hoho+repack.orig/0000755000175000017500000000000011324166541013252 5ustar morphmorphhoho+repack.orig/droboview.80000644000175000017500000000104311265217256015345 0ustar morphmorph.TH DROBOVIEW "8" "October 2008" "droboview " "System Administration Utilities" .SH NAME droboview \- GUI for managing drobo units .SH SYNOPSIS .B droboview \fR[ \fI \fR] .SH DESCRIPTION Starts the graphical management utility for Drobos. See drobom for detailed usage. (this is the same as the 'drobom view') .TP .I device raw block device of a drobo. If not given, it will be searched for. .SH SEE ALSO drobom(8) .SH AUTHOR This manual page was written by Chris AtLee for the Debian project (but may be used by others). hoho+repack.orig/COPYING0000644000175000017500000010437411265217256014322 0ustar morphmorph GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, 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 them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If 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 convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU 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 Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . hoho+repack.orig/droboview.html0000644000175000017500000000466311265220317016145 0ustar morphmorph DROBOVIEW

DROBOVIEW

NAME
SYNOPSIS
DESCRIPTION
SEE ALSO
AUTHOR

NAME

droboview − GUI for managing drobo units

SYNOPSIS

droboview [ <device> ]

DESCRIPTION

Starts the graphical management utility for Drobos. See drobom for detailed usage. (this is the same as the ’drobom view’)

device

raw block device of a drobo. If not given, it will be searched for.

SEE ALSO

drobom(8)

AUTHOR

This manual page was written by Chris AtLee <chris@atlee.ca> for the Debian project (but may be used by others).


hoho+repack.orig/Dunno.txt0000644000175000017500000000123211265217256015100 0ustar morphmorph need partitions? If you are going to use your Drobo as a single file system, can't you just mke2fs on the device file for the whole disk and skip partitioning altogether? Can you mix and match file systems ? answer from DRI person: Yes, you can have multiple partitions per LUN. If the host is not telling us the capacity it sees, then the Drobo firmware uses its own capacity calculation, which is roughly number of used clusters divided by the total possible clusters (calculated by excluding metadata space from the calculation), so it should be FS agnostic. We can scavenge from different FSes, but only those we understand: NTFS, FAT, HFS(+) and Ext3/2. hoho+repack.orig/Drobo-Front-0000.gif0000644000175000017500000015331311265217256016463 0ustar morphmorphGIF89a  ee\<<>89:.04,-.nnj<>DDFJ-./mv8:@@@B57<249)*,!$%)CC<00268>:=C:@E %79?:<@@CH>>@BDI668::@DH?AG()+w>@D446SSM;=B:CY;;=67?A=?F023+138+,1<@EUUP026;>C6BFJ::3>?B27:?666LLFT_uACG<=@+3I344DGK@ADENd 67:014//023788;:;?9:;358/05348<>?]]V-.34>T47>78?=?/TZi46747<;AF79>770bm8;C43112/:=B,,/;;;!&6555++(""#;?E89?:;@==BAEIBB?+++.6LGG@>AE7;@PPO11159?&)CCD!,   Hp >w BbE2-?f rȓ7:%,-C͘1й > 6e.>l.YP61z$H-xdQI*YZȲI ;tɭU.ܒ܇L0>TS=jP\<ؔ),cV3ϠQ@B45uIJ}huCWf  r;ݿ7pwU|rK/;`H!I5pm\<_]GIHf%۷8SMGa-?TR؃L1T=(A.)D ~DxG 0rB6"\0͎A*zD9M8#=($+ T*Tf9%Dv)_Ny+D 9i}BCt` goAz1g 4d 0Mf3c ;~tb t0pi(qVit425Xq4aa X0x B?@` $.6 `,cB#n*|~8b4j[̺캁ܚ(~4HD(Ǽ~HG#;F#( pn;Gӎ 2n\ NXm6&C-`-Ѩr VH?TXr B%ְq% IVXAm/&@VVecQY+5f;%FɳgAYZ-f= ( l/tk[U"YvvY*㱩 ':MӰ R' }4רL#&MH`*t܁Pk Uּa.,*Íp7fI 9⃊RZF,0V&u>Z[4@Wc 2V(lhpuT\KT Lc"c ЋΒc1*Pc &Pb\A*q APk `A@`;+-iG5jdt>iԙ֟:3jVsZ^tS?FOZu# ZԘ݊PS@  !+ZBO +@I1n -U!anzod[Ն|c \Gbm 6n?V5X0&C {"1NSX 5N'| 9p@t8D*\C &P?Mm0Aɗr D XRb荾 >\lf'ЁJ$,a1Ā9֚ᑒǫ Q1 p&IIoTD Kw0*fCcH4 ^Bϥ!{E+](ɘn TZkrҢ^`lTl86 X5|HJ<`Fn%ƭƢֱ+ҲeF˛ A#cΑ%gny>sP P5J E9c$$-#d652GvdP;t H'3J:U3(=K::P QU 233'(J+:b3:򀰀 C` p `M uS :,ŀ,@Bv&8WvòNòpU b,&P-9c|R`}@MK jpgrnEEG|-߃-rQ: 8 .`2x>nhc8 :#Pc03&@JK.9ӂHH;PPg 0`4 P-HI8G6p cGz#DcO(b"2:0*g&0)D  hT-n$!4fg|,r0?xp x0'@'x]wI'a2/- . ("c"!8n P-$P$0(*Pn y-H#;t;ٙH!"9">H&i&z;b35S :" W @ r K 04ɂ5: VHZ !* P  P ,@ z|@h6 az g&t2: zʗhF &|2'\E 1iUJ 5 U<J@ZgF@Z` pPVjST^dJ@ F9z47AK: xc/V7&QH |ЍT4?m`A~:PP]p:eq :J*jaڪdq Iǐ acz,To͢b6-Y&:@  Fm6,e`PI,A:ڮ*纮0^Bbvc"*pT g!4ǐ _H @hvwF!HPp.PdZ݀y0?0fA  *@+0D+8cJhdäbt|MIPrNp Et"OwSOy8&ǷQ&M^aii8-Np 0+E{Kܳ֍HL6K8-=\$PElW$ Wp:lɊ\ΝpH C{bb-;\K;;@ 'k!:,xL5S33"}pF@p`pVs} o RaKPPAA '=^ 0P߻6{F]Ĭv~6N <,}n\ нg]`gp}WF? BlΟN Yо6[ i K׫^@ PšEU 4096 6 nPhl)G.I0k & @ ``~ip̭i0=d 0+0sOdQ `  ? (?/  +0[]I=\ Q (ŝ`軽} | p`bЎICdHhz O@1 P` rp z.\JX Z;PŸk)+. 9%0[?'$Q (&O!15?(/Z]/78_2_N pμOo;p г@ǰA p ~h 2dP7{34&gU2|y*XύBw$N8[)P0  C :E?~(Rc4 0`g='Ĝ )C(1E%PDeWZQQ /ƅkjIVp{mf TCpڣ͜9q $'@8 #M;Hvݎ>}PX!(ǦDLW%+偉JɁ? @tc :&H\%T `w2^@Ƚ{nݹt%K*XBHÒn@e `5 fZ- Yd4:G:!F 1H 8p8SJ B1,`J*m,nNŨ*+ȒHB +*!*d',BKg8ȩMa4q9<00-AfC j)䐫9{9{.OT R0&i,r)onŃ%p`!Zgu*U Ȩ֑ˆ`4vXn0veJ! _(i 1NECP ddln ]na1n za]ª%}xw2,8],3w@Ȋ&G4wwLdѧn Ni!l0{p)B949(D&ytGnB(z`!hLGo%ZX_ *X=Felћ;$裥04,0D$0q nqN3ɲb1w{0w *!* nҊV?lm=!Q8 ax71FPOžvZH#'9!i!?TjֹMjMM|Q@rB4-*l*~`>6 ?#@E`"?!D^P:1Y؁ I7 <ԁIB׍ l & q@qN<̨;E +JtyA%#! +P+ V IGRX4:FA @"ml Y;@iZ 9EC -q{ nS3QB4R@6 dю}A  V,[  1Ƞ( Y"o8 )xa s> ! \:aax"ΌB:At" B$;BpH"d]rvpVbE+XJ8aW`q;/`] !Im R} Bp8"<րlc8 Z!e*F >u,S@LZ`!r@-ь2l (S gne bjP D%3-f!8X"(^Ⱥ2'rXaOH 13D`= EXJlBĐ/}F)I;p!a uDhJQR6+mJҺriȊv؉PfH`*`ZP; 6#p 21WX&M8&pN1.5TxXjYp9%<8C ;6.|\a.,LE|MENDb;e9#$8y!0x\8hAAF\"KPQ^XR +zaK*h^4\Qʙ,hY2 )ƪ1*gbQDXnP^lXYȘ ]Cld+X^7P L艁bD'20vA&vE]T`$+[I)> E1HfK0H$Ƌ9bjѪ#akĎ@+  E4HK8{ݐI ( :gPP`&FaBk3h[>'C6 Xb6a%28cFEo" F>uk6'X@zg2я2 ] 85wK$WPєvyJr#.s0$F0Fر#.7W`8B98ZQG3p`Ai_A:,T|Z(;ZЄM(R&(:H*H;k6>] T mc;s;'(2Ńtk؅'ȁqHv@ @G.'xBM"Qz(`nS3x(.Iـ&1(IH&!B~"(xSwz8!zk/5'hnX?"?nȲN@Ȇ0?X[9@@5(kH@F67 MJ"|jX>aKl[,Q "pr;Ah,,͂83xcyjH`n " =Pnh83ጌ dR:KcX h(n@ |.N &T3 Ю)H?qr.CwH屇فK4 ȆAPZG@!؄T,@V,o8; DZ HZ HOЅ3 ABF6ȁe, sHς'H2|(lF ؁AоAsDHGAh8sj Pl#A .~ਕ T)x`; ,qTa,( @/ DB*? H  N @uȿ\ XDJUMhxPEZ|l`2h_L*TKx8X7,t$F0 qPNN !n! G[,)R2)vŠQ2GxQ .6"#XҽH;(&%6L1QPɢI,8 EjGR ZDH^%8٪k&T5`x6耎z;_t7%OB0Y$6SKrsFRPk<-#A &* {H C@0 r{/ 7.P3$nJjDp._N@sR(jع)a>1;nhvЍAa*(BىU2v<@\u\ȺP!TTEVM6O>)%x 4=8?T YyQHqUgT"k#{('؃:Gw) 8@p/j[Cxڳ38(6Z6@8чEPpMM)GHp+q8-Qɕ()*O{Iq8Pn>(@ S |%Br8s("))ʋ%%__VD`j% 'ǯPֹ#Ity, HpC+%CHl5EYHDƝ/Hw,.4֚C 5,`b!I[6+8H hH87pL9!8262Ĩ.u> Gr @/i4xc ʆH@h%:)P{M`Z:?݄W0{@;<;aZ;&5eFhņ$g# e rmpAȆxVh.G{XL[ϙ[BB Μj(j(jѵƨZH 6aKLdT>l> bCX{*}5o}E*Z4TŶf%<>8lH@b ` CPV>ށh "]Eʹ(r4HɬHw8B,|R0#&  &@V.عC،R+nhȾBx }A R{*IMH3~o֍> .ݯ fklcB0]0PE(XUh]>BW`iH^ X!%XC _qBgoD_ƀG@xvqB Q'C2w2X؄ 3RT .لpW iM8yW B  >"=@B= Y)HxpZ;\VlJ bX7F]uV V(?XX?Lj^qϥ%`gЃ0=Rqt_^ y4pv 1j؊9Cww2RR@!X#U:#)׌ҵ sRJ|_R2‹&/^%?H!eNhDԬx_`Qf)@JH ]fC;WpCk@@0Z+JvOe( ,`} `>H @BHqz9u0z PAhG 3"pz$ "0tkЮݺ M7[4hᎄq82n\"DH bd"a#˙3AMPJRx/JEz?u $!<%BAtѣO@X MDW%*m2U 0YcF_%t(V,@~M&4AY*E)Э;obj("%)TLÒ%&(@4~ =P <*p`/K0ѣDzHXhG}- v! LA tC8b %Ӏ cOip`aN`NΆ- $t0RDE E30B X݉#d HDFv ͒ TF Ǥ &QCdp 3&c }ZhK:G* P h|SH(1n,(wrB5E5`gw ɍ*@B!PB=pS@`!$6tR$0gw00α0, 0 {CmB% pJ 8BCNr3CBpo̐3PǎCG7qBY`nRBG}HM "xEa<tf0N<@TRwgJ |R`g612U=`B!p> q,S2PaLG ;bH6 3| Wn0;XG-H!F!T޶C %TC¶n^B=UOB3lMЎ,I` Q`D:C6^'-سCz"?"%6(5LEf#+`JL1:i'g1~`Jh4MP@ 1b#@&@rL `,7e 70Hm;npXJP-ɽ!xZ?Hbu,oRzp +ARhH(T2ʕ +hS\=@Uaw"$FҢ` <0 " DFԇ! $T`)T( 䀦+& * &:,`3x0Dvɕ ] y^371LB`zT\C?@g0c`:qfX Ch%.slzX |ՉNSX֎vH IAe;HI4 *m@@`W@x|KTU@P:jL&T$*\b1&@  B0så( pI_uykk@@eW@ &%8Ё(JLU6"SD ;Ew"*@ B%*IJ]X*x /@ J "w>_K0Bcq/(>+Y40 >F$]Oy6mBBx2:aNL1U 4-+j!L b t@ aVx@.f?;Ӯn;~ߡKHGN?,6hA31A{nKF'hE1%rDN苁R j$ S2nA̽~=;\m 1 X&ϙ^3^TM3*j4Ay$\@ 0,__*t{z] H5q.CoxtpLP:d<`  Pq!_dj!=2YʥLʁ%Q o̠ ݠ R >_:>LʤxZ.H=h13dDC(_Q9_A!lL 奀 UXX.@U=i0G,T@ B,x"d$I')@t}'[tK,8b-#R#.%[% [,8)[2V3:-L[5>cM5v1Vp^$!:q !dM|, `AI!D]aRӘaD6l (@^!Z%_9r ߦTT䇊ػ->"tWY^X(CX;ell('$%7 7@=lUaB#t-۵A/8^b0蚘,g|XLa \C(4 \>H_MQ^ۿA'H@"(_eRֈqvn=4a!&8^%X^Hpgun8l{CbxXXgaݧt*8D>wn@TN6ilO $1T%`%Odg8AġPH 3NA$h#&h҉h U¨u^a|aҞs!θa&??<]Qْgq(Yǹ5#=HSDa|H=hr|㐘 |H~:''wrXVXw(b[*&*4=,B%dFM%  | lȁZ"9ϽqO%\`T!1|?¦ˀ@fc ᤱئ<+T~ոNBWdPW})[*`auC:whX~g}ػj *TU(H<>{n$k\~>,K$E4Xj҄),T@H\vClrF"vx "B+=RA!Ía#^Z-JLå@(&,ї&?!FbZL@X@\},yJEt,H);ÈQ>λ#9gB0,Tj'02\^.RNX%crL%Jhh,2*n''XgH\G@=4陎@;xl;, ߞX&D%-`"S0H:L:Vjb?V?zFM@t/AFlX?;\ c/!{5۹tf,",th"tFfn)t:N͂Tlz.tBe_jLD%zj*z*'|tBvEBtqa4҉BpϮ ("ӰFNqo7v^;**6`fq]d]bIjҚ_!u,/ X aLrkH> 88fLΑMvĪ:aMgH_J˽8Qε,$40Ex,b} +<=ǮMAVגFݢ$Z dL O L f.a˴~!v "Aج4M$"Di6Ȇrm̩=HyI)6ag,3_.d-wb,o}NKAzĈDa:"и/+#׮LA24g6SVGPIk aGÔRZWCw! !P=đqCA'QCC%F@?' #(BB|Bvн{POclbqB /v 7ݘ1Bڴ\:lVnݱ}7K=@! x8$T ^ˆz@=z[ ow(^P ,YBpcȐ6UQ̧:͗,?R'k)I xPJB**qal 9#q@2'hwfXhc0 u K3ʎ41ƚ MbH!e*BK<YBX؍N6`a(@@c~a$Eo Iq0{,EDTK=PxjW٪>f->YuX⓯ T]]/VMza,ȉ(SF覛!?h&vh<{z,H`ɌDII'1Pz14bʤP.=C8P4Ӄ;.1cPPv` FvpN0" 84f6qZtg bnBBkVaoNInYagKZ5>[k/Uxr,\jC@q FaBp"vpH&g=? -ߎĘ 6*=IȚ J& gLA NFx(D/c &8=c?VNO9tdf`GK#nv@4d_ėN~ dj10bQ8|m=gB!|=:6(hmϺUP/?zV,n- `06[j=aqBH-r׍|P׍~/^9D0) H]hy  f-)U@Fc[PPW\l#aN1!-6;Π51 <=٣h:)$B=T  5x]ܮh. RĀ(d#A)3&F/5xjT#$y$"8 /`#M p?Cdd:p' T Ӆt©^;QM̀"6Gsz҄pٟ\NXHY`(xAJ'Z򟜔dlCli\C$0n$dV9 VE^l4D# 4@@(dJDIȱF@`Fqq ؍9,^ԥЮzWI`@T&XaOxЊ<h;6.HoXĢr DAl@p~BX&l*+KR! %`& HJ6 R+ U^-dE,@.g\8YO5 mHNǸ:a=~N!TM! !kҰ@?QZbIf Bn&2z $\@yL1:Q׺]dO[^ \p$ 8# B0l̀pٲ$vz$ף,BSW@!' B@fS6=h`BJ 5t R\! \' F `+ i.Uh `\x& ǘ e}܂pDb|@ci.x<)Vn" c` {,l,EgBM. pD$D.y?DZЍ@Sa`]ޠ(:B)[27nB!Ñ ĭ#@7.dh8Vpd @oў`okN``jhB*j6r?ޡ##DNsJFFrPAzda@Q n /2'T4NBT@J|ena oFs4`.``=b3% " |nkB`(ڴ=V -҂=Q Vc*ز ~( ~||;}Ԃ"p '"d'b%z i. HD,BBb+)-l HFs*o#!Ah/Q/0hb؈102`0 (2G3od)4! -oH4H"jaȯEAԪ~@lflzUnY>0 *"@^}EB<F(BP1L*gB(RB*NH fXl^Sf~@@G@Ht!/B1t4T3!DHT!3OK2!cZ(@F)GwZUH Ad :r h 0@4!fo 2Wf -f`jDЖz@VUnv @[% |l*( ((b'`aVR_.J!+ơKfa\B$  qŴ8Fl ` VMb5Cj 1D?A4 DA4. 81 Yocax!!G`bЪ5 " .jh! ~./hI ղdd aTΖ?̓?:Cjm&z`& ":A"!"`m=sD>bDs4-e;:jeglijD\~`7VF8 A/AeS0WD`$j16BA $ v*`cvCl`GY4{О @@s8Q0 WNa& ΃jBq#Y,D+(D%r< z~!Ә0,Ԫ?,m1Vf ~/aN\Fl/ ` bVa]JQj$/tDD,;O:C_G-: b% O" NBdڠp &aP&V"=$Zf`TH?6 jZ 㝻ܧa&i!Q @4`0  @fճӑwJ FC}1NLx € dX` dZAdqC*m^A(pƌ=^ bE(F 9yM7q(lxa^!(hЭ3G>]p[A|(ȴ Pi:ut+O7i upʐZU*V:>״&*ixt( yij>T 6;0!K zG1HDC7$ 0B7 UO=kUO/}PSq#5L͸d ?AtӣM1ݴ@ YGbЍM4~D -$$d(Al?Ĉ&`aFzhCL}PR=C PЂ 3tp\ `(WJ-j@t*H7]:# 5H1DCuP%w-x ,Q ](ZmdS ARPrpW=t(UmpF#k08$p@2BH4z|0xl&a :]aC[/Wmr , "%C!7,P`2 U V ֿ$=D0@ <DA⦃^L X \SO@XPkK +H0 hl6P eWQыz +kC`䝫CXiCT`v[|G %1 \E17|XH;7Ð6hvlD;S$Ї@H`-G\> "z(5F=J(-!i `p QxѠ tp&# ~PA4BM#( 7nA "1hAA6 @"~ /w6!1/)YSnpC8{ xǤh,vQ#^ TdHH U*&.MiJl`Sb3Tn8]ԇNL+ lv0_L@ riBtx:N4XUC7Q*(`X(FwB*@.R ($YF`A*\A'"9{C A<֣SI5 4#Of]YhȺx.wAA^FsQ#:40^{ y%cKx+c!aBی ժȵ p)A`)&j`>`*ap95QU:U4)eg~Ё  PA( W~VrC1 /=64 iUN pDLg4?SH2`m^=&G{!fNAy` ;ڂ C+e ,& ``PJ6zy8*[0 *07w` 8;,ix6 *,hF < ^hڨ|0n:lb F -'bm   }1 @(!H@P%&0tj#tqjj P<4 ޱD7{yx.`tbHD,OQO^P&jydl"3w@nhѲ I>f-8-:PWl jB NnCa\h`fmX}f_9P4A0.o(+~w0|_ 򔏼{+!0 ,xuX<闑KXQ[ j:,&\1e:a>.M@G6!:8 CC8)\0M(`>5^j@ 90xxwx7y y xhȁZG |P B RPjP *{ q~j 1MP*6qs}:}~mHpBzxG  '"Q_H c\ȅ q9ԆӅn9׆Qg9O "ZxWxGzH|oxdP5pPZnW,@,r 3aX 4 2h+~PbB}u*fw3D@zM+@mc8~@ P nJ "zE_pa1 PgюtewA 0p_^>1p@\ef"N `"] ] " a ]y ' ]]]?  6  E\OsHЅ@Qd7c& BM X 0FR7XYWe*2MPC #J@ 1)fi._P_rbTP陞IY0__ әpRs_ip`#09hf300N`e40Lc% Q0&s> C9!`0"x at{PtS~@*b*WMfNl7616mYWcU*19"P 1^F !y1pə?#e p1PuR&E3r0Eg63&E Щ@302# _b00)01uju_6pRe# PrA@X~97v BM`e! r7 R:%~M!z&9p!,0a 1PRy0 㰦ٙQ*p4cf'EhE\9e#BIէ4c_p 1H>hZ/NPjWff4] B1}x"|U7X7glq3kvUp:PC7|Ќ:wus#G8f 59Qw1 ((y#0"fI0zz_ʙ%Q6IJ];Qw !CUji:.Ba.3:Qh63ښ~3r* Fby "i"$''Z^Kp|PӁ#'[wuנ YNC6 rc4 Y:v'OOQ8! e[!`ݠ8aOZԊ Fuu &ŦN 1 9J3DzR9H4c31>1{ äTe sR#0Sj7Qp#>Kz:'2a! W 7aWg nJU@zlA7}hI[* KL6*ʔUV˽#jIgfD 㠚dL<;Q 0^Xs|Ψ,&pi~01c2M!vRܠxTtV+x[j GnCP Z"/dN-$ E+w|H`Mp+x WѲ Q'9z U (Ea,x0SF4#2. ٥#6Bv0-D~pbY8)}JgHK8'Y9kּϲnɴ(":'bIf="ۛboIhۣk Iv^{>M>>N ,2v0Sq>N:.`#`3]z_'bIU*(|z+g Z~uܷ n߆;+~p @q'gI8xx OZŇ, ]4?PZt|Y# Wk9qZϨy y_ >I@gHD1oAߨ@&Yp1AQ1܀?AJ/@py<"HoE+$Y—ƻwK ̠*0c 4ԇ:n J]5k~̂ڊ/ؼ: n2=/\t$fZ&#6N2fȺ蜣̶'|Rl:i4Z$h~!P*~r?iJڌjf7cp"t+^*@Y&*mMp7pC^|bۺA;k Q( " (#U.^JP/p@ƅj/ǵ/ 4jBR!UR2-C:A +fi8fs=ͰdG"5#j 0 R'U!I.(] #m5ӭ}40Fx0 p9p7=B7^xU(wdpb N@Wi1hu^_g8E|1d@QyH~]迎^s$XpAQFAQQC" Q+8p8iР]4#0،C (Pr ɺC ѢC~6iI&6IO(xz] hPI?)zYC@|O Ah"(-BIP"HEk-B45w;'ii(b6 `'An܆xQCx\A`Çs$8gsȐQ 2L (7N +؀NNa.c) 0anȦ=(B\$@*0UCiAq I!h n2H!/A;$ .1|ldr꩏N~xDA0Pĉq`6 p!;a߆ O"j62z6;8Ћ:)RcΣr 0҈;A9GA{sJ0iv a'%L?juHH a>QG$9)$ B "Se,Rc, eE'4F e@*p!Y`az(oA`Cvi- i ': ' Z$VD`?|3,<_7n-O>#/(蘁sЈ2 :C#H!PГ6i9pG7vbYD>?& .(jY PrhH!q?P e E&>h->>H!C< 1%XeNg 9ƚBD@$0 xG .( !F@&{sN18c?J!)kRƓ!/,U p~Pa" B=X0$[-jm `;t}\]*Kx mGhr: VX0$pJڻEn8N`,"^1!0O ,AEJ9yz"$QZ!=' NC`g`І(k(2E2?6Sƙ$4w hA ACh>> r88atV J\L9 +9(\ņ) L̗:<xCͰ" c'p 8a&w=t@°16݁znriX0L `.¨90G"Àd$d8R7<sT@@WX67$;r&X"!!X4@mpq Nd  7^І4 B 5!Ub 1Psl"\[(3f43 P$_y9X"'o"=,=B7Q3p~ܰ ؠA8`5U jō{8a! CNz[+q vJ{n{H@(<<`1dTVXQмQ\w\7G pЁVPȅiX> ܃8KP.#`6=K+9K>+`6'8', ` 1hWsDPuԷ Jy|I*<8JlB+>>͑C˳d8]= hAD. D/hXZj0;vКA,"H<   4y@K6Ip%JxlwHHw Kh?xHҋsK1J`7@`P<4sLb\( s&@*Ǽ`sT-ă@BY̏d@<R8p"0E +N@(zpXWZI W6@ Ќ _.@M^`8Hpz+0¥ݨJQ JNZ'Y{0 jb(Qk ͳ QHg7Goss}GP0<Y-;`]踐s%M538HM3Hc8Fw؀]1ȍH@4ȂSGWCѓL1+zC0/ 1Kx*(ʂqG5B,) A  _q<`jXƃ Q4Gl^ ( 0x@;BιG0jK5]8Vp4LC8PF@q{hApv @,,;MRk;L6 J/_@D(TM%hn`N=I?CЫv+{d rEăp={x fi MH)-;wzx![XG ǚBk1ۋ{[o[-d(p#0ܘh.hy#H] @{%1R8wpPL(CF#r^# 聕0ܚ{1CяYw qHmk18q10=V s+7Ȁ< aV [Ps܄p_} 0=wJ5XV(="1dh[2#m(m7ۻuѽm>K8ȁ#h %Z/= $ @A a$Y@ J G:,ލY|0谎SӵKI1Dٵ]DSgf ȯI0L\J 11,qY7pC 4iKv@&s @ #V0W<\=mĤ2(JTh} BԚ#Yք|{n-[?3o 3dX.AMIA\/=l@w1a386ɋW?q7;z S&!06Q݉RAj#Ȇ0XX&`#p3 @ a 4@?@/x%ٹ raz/vHI MA98l ZdbN%z {Xȏ,}QHig0KcA7$#0[P=v)H6B "2hEV<؋J3ܮ PvVh#`oh;[P P ]G/Aٶ-I9sG0a3f"ğEG!5b0[#jG_t=YLP\hpgk;w4Qii2AE8gau= b(P= c?0lvƴh>I}BmG0dGY! ( r01%0""o:oB3gR>j- -v^muH5Hs*sB(&R m- @!@OPdLP(AaeK* C0a~t 'P;"DؑF q6H9"D,GnzhEQii9+:g+p{Q5AUMnJ sZJ6UXѮ3vkSi3M1YG?w #" u"Kn vC@OAQB 됬- @alr.ԄJ"T~BMP-6> hP!?Sa APb\C&` ʡH4,8ѡC A DA ㈁ 6 0Q3I 6ЍgN`4=WH$B 3"; #B@!p 0;0 =X8R1Lx .ݴB `#i@t8 A-ѡo6F;%r`#~tC7Y 1=&'t@xtr`X# A" jz\B "NkH q5S@3RjrL.Ѥr2vEH*ڤ) +y vґAwB6Jfg#=$ !q0,> `_ER8 <)90pC = QBRm@|R _¹FQbpsփa3Y Ȏ,B{%0C;4zf ;#$xLV@tPb C fsa Be&8'a.>@}h'oQ@.<\-zq !_MaЂ4<2)C $0qK!R0r;"8!QfP )3c=`,iY@=%%)cҒ>`|g BpSpzQtnF8 3W~0.xeE)w`n "4C3A(S[5D @3A0t@T(P 6q>BRE40Ā} ך`PԠDjl$Ԕd%xȟBp@ 6Ǎ63ؑH`?,eGMl2yC*!=) P? BB xL%LḎIGj,|n ٌ AH@bE, ٢n%YK2G4+0h^jPHE VLCoN PB@`Y}IAwR`dY@nInɴA)jF=H@:5Th@H"D 6aѤ/P^;L)bJ%xtN—:tHRDn(QǫwbFڿy][ِ@gU.vbUZmc>|Ryp'&w!Vf.7x)C6XSOZxBK'~^([b ĝ~eTzHaN$>:!]-QJT9 +P>J#UJ(X$4K*^rFA)BO$rcI]x3܄F=R sI74!Վde V   *F/JH ?9i©ME^@ـ& _#D4~T?<`xRuBqCz\ SgGv(nq:AE@ēdL̛\ W 2Y)%Cz/&Ezp Q|;pw :ꉝϐhPNX&?hbP` /i (,Al`*5sgXh@k Bh+(6g9uD.R UL4_ vP gd} 1b̽w{nwb(Q W_̒&B1V6tZ:C#Ph~J_9 2@0`:B`JR`Zb`jN40 `& ~x/E)@*K5<L ,Au#]ЀC + Z  \@*, -\G`xpa!aaa r`ڡbP BA14LcmC(@.B M VCZ6Z~Js ץ+h$4!x P@;/""XT8H@H8FlF`F-fH/H^Q"/(#PX/PB,h6jĂ}cމ)8۩*;Q@d1̝P(cdc;<B*j \APBDAzBP ރ,@ @L1x*< s ,B6L !lHZ3- _ڤ42IMbB5z PptOb7d8L(",>Х>8 8\ -&إ]@cA@VF"C^f"f c1f!% P/@ec9ڝ9k/B!C4dF AwZU4 zФ68]@ 7sܠ860Qh(]QZ5"P'h爎=pfvB$.jF$(B܎\Vdd>KХl4b@cb@ṼFČ=(h_ʥ%c6(Ng;`^cb6&eb(8[#Tgf8蝐* X.m`dC1H' P)_-M,_~`M'V@)N}hch%_hbF˃'TƄV@&|z(DfcDU᧌"Jr 1((B % kqf 7VΞ"@, *KܮE%&[e tJ0Ñ!IEHÐVۄp gpRh*IEiqIlCcFFqf-Cy/ip5 d l(@"G&+&4q}$1(A5khF~(僾 sInһĻܥ"@\.$`0 I8Ec4 Cs]>"Z=%|>j $jlfD9 Vd%P+Ω3cmVmL)ik9+AzEC.@4`4\9_Bs,kb1<g>heGL\ h|M'"L(P( ؀Q/h-2)gd9T1n`AQo5 6 @6 :5ڨUGeO? x"g(4]HhiÀv>O(gL._^.Es&hi(&OLaKa;JYce6eL ]zeRjJVRILk+Iͣ/5)iQ3UQ_#H\5A=/"vMGO^Jk5/X*(].¬( p8|.'jp:.h䷀, nJÝar~h8eJ V",w;(hĨ(#0.jI@(:Tm:PF6(3Q[FP;BZ.7QڐXM3+ LC-D6:gRDc bۃ26E`"fR^^D&5#䭻/+hN㟌4*cWߺ7chhYkW_מ kJY6@;IA7<8:K_o:FZ/֚@(@jCo2 ޸M.(GBH6 :$@{B/CoϏ0bP dwH$@(ExQۍ[YTDeA#ɒNQT~!4̈KHԈl HݮēHtz.^.$0Rm Stu"8D2/1<֞|@f%4sti*<&eP$1("H<C؀D @ ;`$@B}KݏK=HO= THu@x% ( &L CcHQ(1Fz܆lM Q2j,sV1^F8%ʊ!9.ę,g΄u 1D^{QG-U*t "'b:q!x(GM0@I&; (*Z&)HA H vBCPR04pgI+8lJn 84n "Kbƹ-͍{g\, p1]/zБb /N}Ny 3|Q/D{=*Bz!$z ' a.('T:Ęn0av*u+Fr x Kx$+I! Ћ>H@Q ?C@& FL|( K. 4# DX~"5{FH `sGP5H9nĀh@BqI? c>@?!N6:0 )]I Ψ.W IJS^ͮFtBEvX66к,x۔?# f`D(R)F&P_zp2aVh%&#)P@;8[.Ń6=(yd6|ӳ5Yf3 fEJ}AD.@v  lfnh5O~w LM{9.l@i#; ٴyu^a`ȎZ뻸R ^QDB I9q6 v:N M[h{9]Tǃ ߁|],i+K/.ұTƱ 4430LMF MByNE 0l %؁n|0T͢' ے4uCS$*8 3@ a~yV5ЇW-Xn`]o%zzhH +6ϩ4;9#uHW9!x`e!ؿr(KA.򑗽\a 9R x-< ؋Q04%zF"x! 6$! `@ ј( a.Q0@HwaTڴ BPz#8ʽqo{ @y@.Br& A&0np*S)P9[i|Ωz7HhȪ" *P>a`Bca9)}zL?*V9砪?PQ(thJII]G0`*J|%& :@*0k*ZZ@?Q!V"F(ڐGEɑH ;0!8V܁ET#paLK>rFP9 J؀ ځ˩a^e]Y? `Ug_ +9⬭򈫎Ҫc"hyJ ?!HqT%\(CpB p3`٭3@~@LK0鸢 p2( )cJP>##c(rq[8JX*1 G` m"TЫ85XCLr,m y E,q?Aq((ΫfPH%y{cA;Uwnu[8VA4<@@ $yF'E? UP':`C@l-F !0` R 4K!JЀy="f3a`3a{LDwBsFFuah@zBC0:1EF7%QDz@'#C8@mj"~h\Ňt(FC# b­ r?lID :"`\Pfa}&l_%XTOF `-``x&@r rN J .!i n`\/Hn`0 0 :! ! nmJ Q tkFڡp# @& C6DS5xMB"$  *^Śp, 6?fX`HIo`8`o&>ca[LiTDQ! . p14> FFA:` ʴ-vDG&JBnw@*|/ǸK0 4< `r0B:‡ a2-p^`J )26B RkAdTt%lV|A*|! ܁HC ;> h9ZiR\&&%98rjj *' `'6oc ` G;.Lk& xG pRaR`ab"/$) ,TnZp7C $@@Rc%` *Asf#\JDl7[)s%ڀ~(!  @`H9F+ p&.rÃ>f$ TprvR yUQ3Y8, U?:#zL TuC kE'i(5MTxp3 tU :(`Z *F R a¢ n2.2hza5,) OJ]  x 4lR!- "`v@<`j18>9H tED)|an܁@`UeQɡ f!EA;,N֚:S"kh:8ǡ 7jsrpaDt6(XG \aF+sVAğbXa.$aȬ[OadB! !UzX9vjjơDz !q(T` fj}ÀRg q@ Xvj]4rT-,Q $a̸U DfA, qU1 xl ,RvqΆ1À"``iݤVz]$jhlk@Gx'G 9fx90G\2%|cʛ0ُl@|I`R#,eDy{G'|UDY hX`Kllkp1C-i`x%#A[4 ႩKp t7rЮr֫jlcw@|!~r>:tps;qzLBv$yjBGĪ2lDPf@y& cSɎO*9&!:>G `!SaVVmp"AC{ZbU$*4Ez nklvl@16k-*Xa ,AX&@soc<^sA"p ]W#_E @ @ `F] `2;>:-~@:WvmGBF5R,IEC RD.AH3Z[@{8kjFPiЀ;V! ..O1w-%{ [G]h`l Y!C&H" ? &`*x(zR`Ad.cP7`Nl7ȁD!tU!|AgL9S Djjnt# xevdf΀M U#U; Ȉn86`0>ƮRW>%7= at`2<@=@X%9@Yx^F 4;Y$fw! @HޗdZaD@N e@Zsuph;,%7!ơIJkW|e`= `<{b;1 ]T#c?vU@' \7  mcbb uǻG`WSH9`Ci*Dmح3}x0iPv 8nF7gfCB x(AgT]>>)Ž:gPAv$aPݺ0H |i BDn},z`Ʌhњ1pLZ:Uر&)B5ir*Pc#GL`QTj%/ .ڔ L(s1(,l٭(!#JU'>3Ä]J6 7?# (DPys xcA;:iI@>];B;+ w9ǁ Hpd#P;R itC$ vEd3 r;`GwJC I!@R KPETUMZr ,+<:M Ab9LK.\_HZ@|vC 1A6)|h%AQ1JVEz$]x'J#;xxbSwHRz/z^P%vW "Ƞ3yͭ~tON5Nv  эIᦞK}˫adIa,兤a^Tߒ˰HHVPX:)[M$WUĠE 4D}uN.)di@(P-w|6Pw1,g0s~SˤɊ(j!A6E &=SGuw"+*zASFN-UPbVe^fu,^O@M&=v?E/n .^aD'50 6\L[O@-;2A/>ģc 5QC/LVZ4G*҄ĠG"%~BLPE(w%QiA0]tԨw*1A 4+?ax(vaR^iSS4[}*.vC_lC4ŊM`F'P^6XhPyaB%j|d Ӹ&N*C(t`!_2 !RG/R Pb>w%/*R0(p$P"@<~AMkQ_ǪҀ-1ȓV9oxT)PA-4w9|hj8@ Hkh:bAHj75ڈ:A (S]*P ]ɋ%"$i>C϶'H1vyLeDUQs_AZѹխm+aA îձtc#+WII iWTjbF9Hs$F /Э%Ht >k IE(eBSH.(й㹧hE)&KS!!V0j,^ݪ֪"w!{UVV'H*R t7\)=Iw/xڱs10xj7.b8"ZP`hAP1$)HjQD(1HE*RT sD.̇iI K=Ĺvbw@X#ힵݮDPWf5KY};e-S%ͯ4 ^0Z;Y9 F<G NI7͂vQ@ A.1 C k1N3-BJq}@|6d UyLʔnVKAnuq$ NT,w^׺Nrb+YM)&Tbh89S޵m@ߦJnπDe|K6tApQ Hi0(;I 2l)| B/&p\$ 02fu*Zq)LPp]][HN9We#>UNscN6w~>yk|f60@ !BB@0A/TLw=GTC.Є*C+;(4 P\<|ڸ1cVOcR -u\,cUUU,~eUdZh VeO^jWUg:USSJejVu^"զz2c;1`U%v6q ;Kpգ *p4;Sb@C26c?: `BPŐ&` :DZSJ$J Xa:6dL'&Ί54Lka:=%$):>$:n1¤C3$bcWbb/ِ tÆ/:[ِii9 Swabv 1ʆj/:CkHxb ;RbPV<ʇ8dZT7LtڰhrBr ::6d@kC:$:jSl1:XaCmjL8$0T:8$CY:ĊzZ[:IRLʚ$DIZkLPXQL_KL:#FqqLZ*PJR:W[KE$j%Fچ rГXb w%KK %vZ[|(c}2j(ck ygت (?4 Y+Ty'cCÕrÇzM\\1@ ҤOc[41dJ%8v//t1z 7o7 j vc1 d{q< p0 R wVq L®q0RpWÀ7 wz"G~- ;,pB\æ̪Spm|ԟ A)Z|)wTb&Bl($Z 1`w[9;IRɕT±dԨrTAhu.H)rRr`L + PCR>Rn"G̑TYbE)3W}:Vh֔C:琤G+~RRdE.Pc\2JŇp1f #V&-r|z垴QLQJU609/|JFZ"M<3D"&SPGrکY(S 6>K9F1ۄIC7sǼTUDT+V.{,L `UaK@FmF iuIEĎ&鲋,m@T %, 'GrI!>m`:P(R"mRKn)Mb*+,O I>:qѣh7.kiAki@ =?")@ (>I$@B2&3V "=Ru%`:n'щ;N>(Ɏ  姝A/={1!UJ4J}T*ba&w|W|{|W 䑧  _!޷a~) {A :c@cy{Xc7aWF0YeQ`g%Wj(i9n&βVRBpJR<ӑ49 B;9ڮTH+O)T2` A j  g{pGbq~)jvqfp™ 3I%_g 4X'%'ArYW ' ~V=G9# N5$D,&E6ĝSco,%wgaz?~ fLeW `X%4^1"zK1zeЁꘂ5h/zM ԗ %0&,G u!|^|' S"Q:d$1yS*&H=x*|#r7mZJ%ѓ3h[>@ +&Ed D J]a1IC5 b#Hh})/g> R5Xh9QyHĆ WŮ0o; t3Em "VHֳEbr hRh8X쪤˥4 ( ]< MK_Wҗ 5&0xL:*'q谿b7bӤ-qH) J`.-(!!]QDH-lƇ_QqV%U` z#҃6bpCauqЄ,S#.OnS>]D?a񴘸COIcJM` +1$Ѝ@gh N)1GĮ)QF u)L@g=.@Gr65AtaM(CT (|HP6 !zP5,`2$q:pR!mCpzө.0bh.{ ip^f] } (@jЁ oPQA@Y F?XF L?9T ǘF2vu 3BҘ90P4~죡DB XD4jh@`4@p>&w@ h/&BxC.6|C<`kxhh(B0bЮ\H@@m X;4hef_e~P`ְggi.j.\灾b&eλi>j~`Fio>g Ҟ1Y[@`8Ȅ,%\ kY B!9} yJޠ2 >cF2.cxTb cxtl1l˦˶l㈤ j Ŷ2ц }[ aMWn%FkHT@[I$P PhM-Pŗ1|MH~md[>VYAn ci=Yi[?mmf֘]S ͥW:J>@;reNxf!"Jy4 pɟej5\ \5e_ Fn|ۖ).ؑqcQ^% . o(o}A-\9ZڥM!cZ%FU@"eH1r{>/&wzT rI u }ێeӅ F ɗǃ`tI:n"7F\zlVK[O_m^P;>&U)`0%\j9Wyyceu g`q 낉cFS!qlї&oog1w Y-\%pGr.i,g-frHxlt{ ;؇\/(؇}xpaw ɍ;; (drM  rJop'q;`atMG kKo6^qz!|!V,r̋s$eX%`߇%ب_ zvau]]mF{%p{ZtPԱ]~c0_G|E0FeMV9e ~;]^i]ad.FP e FCY].S~}w{}'y0xa[{uF_;hoho+repack.orig/index.html0000644000175000017500000000355211265217256015260 0ustar morphmorph Drobo-Utils: Drobo: API, CLI, & Dashboard for linux

Drobo-Utils: Drobo: API, CLI, & Dashboard for linux

[ Image Gallery ] [ Download]

Links & Help!

If you have questions, you can try the google groups or just post to drobo-utils-devel@sourceforge.net, but for now, it's just me... my email works too... Peter.A.Silva@gmail.com (help welcome!)

About This Page

$LastChangedDate$
$Rev$

copyright:

Drobo Utils Copyright (C) 2008,2009  Peter Silva (Peter.A.Silva@gmail.com)
Drobo Utils comes with ABSOLUTELY NO WARRANTY; For details type see the file
named COPYING in the root of the source directory tree.

hoho+repack.orig/.git/0000755000175000017500000000000011265223361014111 5ustar morphmorphhoho+repack.orig/.git/ORIG_HEAD0000644000175000017500000000005111265223361015351 0ustar morphmorphca052dd436eaaec759454a72a859caa9a8ede9c4 hoho+repack.orig/.git/objects/0000755000175000017500000000000011265223111015533 5ustar morphmorphhoho+repack.orig/.git/objects/44/0000755000175000017500000000000011265223111015762 5ustar morphmorphhoho+repack.orig/.git/objects/44/49a6e5cc960623f7349cb42e2e59e9cb59046d0000444000175000017500000000060011265223111023055 0ustar morphmorphx+)JMU014a040031QrutusIMLc~ ׺=WL7KTEɩ efִ4ΞUq{ļԜt03I3 s(KL(? {g*TOFV&\E^IQ~fG{kWQs{r~AeQfzF !É/۽~菫NAPsR2, b5'v΋Ԇ'떖d&$3[iJ=K41];T4͢Qv+ύ⊔ = B''$&gg0(U]cyzߕE/28ށ]XPSw</Tjhoho+repack.orig/.git/objects/pack/0000755000175000017500000000000011265217256016466 5ustar morphmorphhoho+repack.orig/.git/objects/pack/pack-5b161b6f03af0d6c5d2ea2211edc20e730dd29eb.pack0000444000175000017500000135735411265217256026103 0ustar morphmorphPACKxi1m F+0V쭝o| #LE1ercT%F@UDVફ bvQamM r gb'jF qw>Uj*cY*P yA{Smz7YBxN0 E 4FBx푛:3t*̈'e\3F(mBQZ8G*i`um@Tia Vw:oI:JT)+U1gu+Vޱ wKFiHk1OZB,iFs0Sg]#l7c69JT:keul5"FsΰKkVrd/\Q2"y>QB9(}+տJէ6vfߔxKN0D>EX4Bdi3I㜁ڽRՓ c4j+9kaR>b8GWU^Cpl<ȩTaeycѡhQ{U,˒Ǣ_^7ܩA^t T@Jwj_1P`x[ 0Eـ%&q 43тiJvkp9N̐ J'e{1c>*,js VZ:# Gܱ#&r*a DakR+<ຜZOeSnvxt""v<+Բs>B:mP#xi1U6c5 `tO!.WaftثEڄ&W5g!4$ʵ7$Y)gx8htY[ȦlgN߷߿B.uٺ-WL#Y C>3]w.S,ckQ!LxAj0E> ,Y6UĒ }mꮺϼmT1&ЎJ Zi#bbͼU}m{L)j`ΨڴF]r1 3\1ml%c  j.ezZ80Xe<{TD> ix0N !0!]' P@f/֖xqDk)?7(KJ16!Z{r@.cqY?H<7"%x 0EѽGB(M ,m<!9 8ÅK)^R4Sǘ B׎۶㼭Q֊ ݂v"cCp=;6t^ksn{E5yHw3TlOŗx[j!]@D@@ W=3v֟58ԡeb'] ^kLɂuX}v.'716f ^pśTc8Smu0޷~>q̌:&B8R*ЋJ<N?/YR;m=֠4[Wbx;2Xx 0 @{TqS"!H ǡ R8~ ^r.ag)P-\-]`gVjR@D؄jS =WJ*} LB.:. 6Ӻl˻ԥC8Đ,|N\L۔tiSXIyy`QdxAN0 E=/@IJX!!INDTˈۓX>\tjzVR?Q S眳A~ٰPbRn[gJNz!RT#턯=ŒυjtAH!5yqy%P\чH;pv T mK!{c!'y<"9CY%e^"CᴇϞ (_ b0/`rw|n}xAj0E>vYŖ5.%BPF6V䞿6}w)YjdѪuAk8zR"hUvCdi!8i YH׃{ck2$>p_((9#+h`{%|\,KI\;~19]ne~zKٛb,iw/L}TxMKj0@li9  =@4ĐDA{ڋ鶻2 NJKkC E`06,)qxʏ.,[|BMϛCf@~Hm E+4nh5{CXT\nA x48I#7Sv=OӱJrZrke㟩ij)}:xmwxAK0sT%Mm " A\2m&@dMWxJf{yHi;kiUh+B+F Za_Vu5NV(0")‡6|mxJ!Ǒlt'~Je#ò8qƐ5D.JΟưdYJ<.M[ 3abfS8 <ـO/9pb9y!p1'Y|nئ1s!s&LnJ.I~9qcq ~aiIpq33|rzK~3Yt5YU(ۖcDUW!plT2B{fkQ+S]A]xQn EV1TUQ֐ T2P2tz;2 %B9L*o34[r& -!IcU!{Yx{.{mJ_vpSec!yNk(*\7m0H|UJ`V0'fuPxAj0z| ,Yk B-@`FFy~CPݴvf%U(aq|PkJR"E2&bE‘xΑ-ϵNgr8pH/Vpk_MN\?Ŏynz(17Ům |Ji Eh3M8l7:5?j^xAj0 E>.JJEQKE79Co1R*<1#0.Y,=v7v+,Cg >].fr&8 vۣ)D> ^޷+Ki:e{byv!qU7 `lǏLY :)Ym X[xxMN0 90TI !!X1ȏIɏp6OO~5#;Rx*ri$3wDJl7cg2Pq\hRA4-0%eرb[{8YK0CbԂ/3q9siB)tNWXBM0[xrδ@!o_3Ҿ"kko9>Zk[O!w 1U((<qxMn @= ˜Gna,[|=Bo&aZE6` ;.&fɔmP<*hɹDŽ&"Mc!U4W*!S?c){2n0>Zq9}qo{Ck/^7MxMj0F>K%M4P.Dņ:2q}~{*P%LEDD',Z-Q"RC+:=TCt&P$DO켡;tl,p_k$smrb2Ӱm'=DNyUٲni'<R u[Bxj0E$(Vm <ıг;{JbHwfᲬ|1jH\[REPiMY&ֺaIBBYvn82CG c1Bt!B%R ;>VW?y2'u/@` xOKj0o_(5]󳜙Et:#Th!VdΎ}l9X``C]`odY+,K` ާ8N1x~8M!sp)uIb[㓾kA^_(gRWg腬~[`l].0 {VWL/' -6OjykŬqmɪd x] 0s}$4? xٍlST<o`>Ufj򈤤t8&'b$Pyn24%bP ɦPw"lU*\q[~l5r*ǙP AX)}D*qr!/G!~NvxAj0 E>ElC)t_-8؞3=x R(SQfc,eEv3Cwf %D%R g=Qǭ6ҡ .qO?{KZjx\,!G/궭?qb̺?逭A:|~|2M1dOxLKn! s +U6GDĘ)Fΐy?i3śPeF] |2{)`YR(9 Y֟P %g7iuJOs~Nl֯~YȝEQu1be\nUYRamiC?KTexM0}O1+7&-1z`eDp{{91KztSȤV˦uneVLxPkoHFֲ4BIAkj-$hɯ™ܻCp6< 9.sXXD`_>C'B\ϰL37w?;LxAj0E:f,1E!dZ.4 $rsg_x 346"qh-`mzn8S{Ox3'6H>=Ps]+*) ܸ׼:x-;;y1˝ x61]GDO^ح 'xucIu+%K=@'\p)@N˜&^ʱ\xOKN0 T5L$HHelVu=)Wgfl|{nk4[**P<}v0{g.@te/&:J7V.>ͷ>9Kne}.AYI?LyྴI'YaZ"7>3/sHDLr*8BWlẞ|CcOzp4lM&v-mxxQj0C}/,x8P(Xn88Ξ3T_z *@ Gkeog dVxj0D$k# JiO!BɹUk#!s{0o`0Eu@|%ٔlNqP2:S3 :D(pJ%x$Hc#FtQ&ɝV\ ukޢr#J}H؅u龝k:M:WHxMj0: Ag( i4J uȣv6CLht}naku!ܪMmK zihlYdZ|5p#/vc?{ё']^$_`Q[#|# y]97F2N2E ΅mrtlV$xj0z/C=v +J?3d."E%0g'(6LbMHRu萨D[4M'/#Gu8ːvv=Ki}* fm/Z1D, 5-kFu;1 S"xˊ1EH*<Qĝ(xAj0E:Id(%G(EbC1^DK 6M8TY D˘1fMj6S f]atl",2;G_tiޞ>C~C.>Kvs ΣD z#b"  )~TMLR)xAj0E: adI#J=@HYAϐ{>ч8͙Jxągq敆 d\\-`.ㄒ}5P5iGp?/q*z;f"k ߘ[[?1!'.}MZORxQj!D=E,: ,!A j8q WūDy ^E٩u.HeQ)k`<N˲ZUFigop]1FI%\GiIL VO}(faͪEPrN|1""!6|E 7zO9NeG}{&pZKgiL1i9h]xK0 D9P>TU=B2$ ( o< "7y[{lP9߇( {cAWRʓ mvK`MR.\ELE| G>KHFZA[oZ&눘uQs3AX˘ 96B[.SxMj0:FȲ hFP[FKW}x(⣙0 HN[w=R@t`lz2h8;ؐd4ɠGDHT< |I7}y\y䳰L|KIynIq^ץ^(5-/I2:!)S.yZ VƟx=j0{bCcA)Sr+}3ؖ?234T`\ddA$`kaKV7FgrtA.֣[?kOt4Z^-6㱣']Juۖ~(9#+<^?AX u~( VxQn D9RT7Twq,}{&@;̞:a&֙[8 蝧hoDdMSLfކ=77Y;uvVL|->XgGs𦏨?N"b}:>a3;u?lB/|(t*-e*f[xQj0 D} -kJ x9 DWi_ F;3`zfrS]KܚqJ0yWP[ s=E/4ĩ2rtxg 9z&}ig}H.ex#ʶz1M:ª,Əҿi?SlxLA R` 6PߗgIffwJ&`U^ .;n%JW Zh)P;-ag cz$!ʐ2ܨP8-<\״eG!'5Z!R4cal/'a3P1TzYRޒxOKj0o2n(ʋIu0 $!D%eMB+TPD>S8]iņ2CO* ]r8 ^O9QSCLpNc/G J钉U{eM6Pu3B1ReO_໌9B3.mhݸqx Z5\YawxJ0DyoB4?MSѕĵgbmrI*3800@&uQkks>Ng3Y\}CaьCY{m2ht .(qA Tm^=_ONx"rmIe}$vGD:yDe.՗/q; ;SSK"/r8x^(x]j F]}/c@f k*MbP3)]}ΩJ4GŭQ;T=֎&Vah JMC/R*^OIq9WJqy/x %QHynz^e+"|6Һz0 gPo ,T 3 lv"X/xQj0 D} -5G(,+@9C1cZUxGƛ{&a!ԃw1;Ufv58jRLk] SVu8zgKڴf_s\uNtش=(FHYץ]HEε__-mz ?RxMj0F> Frg(A!(ѨVGܾ=1%ʖ8:C[ ^U+˗4=.VkN@Ҥ juQ&,*v,ZO ? G8z1;ojlmENiJ 0{H4t{ԷqdF!9@n( y?a_6xN0 E k !v 1ba"q3'/ݑ}oI̠șBã[8bcfKum7₺o'gQ$8r'.^ɲMIVOQV՗{>y hʓ$ F+%bK W_&{ɍ:Aډa )ā_$>V_n+}&nf("pLb~ߟxKj0:E/3}0G-3bn#}vEJTJʡ?l/| 9w`uQ-h)ɻ:}bLvy?qTɝ|Pޖn+o훮3;`R^1UxDj`mi{Ta⁠;?~YИz9:?ԇ_XxQj0 D} ۱JzbB`1ClǹVOS [L%­*ZBÌ1BO\2M2j1pA _ Ģ4>O,q!1 u4~l|A,VT=xA 0E9\%Mfj " n\)zI&-Fm=,Z\n1H[8t3aq.X@ꈺZcMΰ%o@ƍܧAj5<L{B4amP"耕j X} %>4.VTy+ 쩓a l r1JQ/N:H :ÇfL7>^xv^R+xKN1D>EExb   NF8ӑq{_Agu#*DX{SaI .^VCp: [B&xPۮ0|W爣*i\ 絽n,7-{_gHbFWvu雺jC;5nhaث %`kv?4CS{WNH; μ ,P]}U2q-EwΌ m,; 3/lHƢ%rRO 7$=cVKX2[U.NS; 7L ΟK# M mx'OW2 ܛ1n~8~hRE+%xݦWaYsP1"|KA/%y=1`bŲj~?Q.HN'oo)-O͓+^?xQj0 D} Bu\JiBȎ섲vPҽ}M H 3`uH&Z'7:0YCQ$\h '4~5F"ˑSi'㬢U,wϔ|C84h0Qn[k]j~5s;ΰSf?7EM6(uYt{pfe믶+үoӷWbљxAN1 yHƛlB$>'\S i2 ,yDL7KcXR ~Ziv{Q- %Sk@)$)78P\{(vO?\ֻE+Е<|La863qدO6:X928n}uTxA 0E9EB$sdvѦLSx?o_HBV<1*hlj:I9`[X\eYio|ɓΠ2#,^}N|ryKr[ƑrរU`=fL*ښDŽG 哄 rD>J gc吨dB1[W_,Dx] !+6Ϡj]PR,UF}y}3_DޠvZamܧS$xQn0[@aWF RȥDD=>/@aCr;3ˑHP[4 9]UΠ-˾CT;"l+Ղy*iں]}κ\?*L-G>S8~^ѐ8RH^PUvә$xQn0+2dSe#K{-Kel})EӒ̃#"$ݡm(]9wQ;IAkn֨YW9Zw(` r{"-!Cg|Ԯ FKqBaF'3RѤ ]VޓxQj0Du/xPBPJZ zZg=yLoi,YS25d$NwFhtnO#LA- jbd#G >k{y ?|>zU/X7 ϘXcrC6KGTdK!ilhVTx[j ]^KT(K(tĠ&?[0VX*a\uHH@W이Bzx'!u)?OJ~nYROL;B*Í !ʶ~1˜RAjeϔ& G=O**m[xA " L|.DKC}sL"z!bp& x|ltKɲZ4h`N3!DL2*ګT}&U?e9r[VYRG1vCgQL(E9O35Y1JLKxMj0: Ac)J=@HXXFзGg9M(dB a6*8AYܜF {bɲbKp_bx۳g[iv&xC&ǣQLj1\%miͲLeGuUxMj0O1B X?$(G(2CdI {=xLi XK59hXXtbӝ+NZI',^Ah+ $ᡈZ*}v{2ޏݎʣR/8o$RFfqtMcd-RrNcEk%`(#Cw Cz^QxN0D{HWb ]!* $<^۲7H= |hp%?֑JTq4LR#4QZEFQRb{t>`xhG=ֽ\ᅘ*n/rviu._WZҺ/$s$ncQ{]S)xn0E{}t*# :CXnap=w86};`5" z8FeʱVmNm1f(uSue}fiO?U2y`#O0Q@\m\6=|)eeʯe~o4l8Y7eWEW)γѢˁ=syb&gyO0 (iG4_E|3a #.K vc8ff8D{xDgH%|ɸ" xK) [] 2dzuP;p!)9)'Bfti /SQJ3M߁o49euWr/)dr7,tWX},لxA1E9ERI`fp%I4t z{soE:H2`xY')>d5.U!ẍ8o4[Z0,LI| '1z[)Uwodk,*[FVTS˳3kwȲZ Ck*RNLYdtvלOгv>snʡjKβ.J0mxM 0}NPD<dтmJǷ=Y|oDH,2R,3ZHl {@aNBpɘ"A&aWFre'u31<}"iq#",ynKL#xA D}!?(~@:7 *BB( Dg\t!!Ћ*OMA"v?5h$3Ak*ܸH^^5p**@ <]"v^š21ϵl|K?Qx] 0s %6  F ֔z~[<3,ѠU1m!) sA(lH:e8 fVJ}JF wn:=?(w]qËIj`w>ȃ$#BJ_o$oh*C:M:j{/{qCH>[e?3-K1, ʾ|Шm[0[SvxM 09,AMIfRmRbg>Z Qz2 LLɚ- SAŃ'C8Ӆ;'k{!R% $fb:Á"[NL@%[);VxQj0 wBYN,; (,57 fDži) FKH1bXrlt3x"S]X0gڵeg\~DKmotҏ#ȍY!/<֖^O RqRxKj0D:E>OC9B`r{"Ȧ >Cj(^QCEe Lyr<#Ʃ`̉]Ki lMl/At6[Rj ?ת!Cu;s?}_ZeY&. !bm?F'qu`hOx]J0߻y"I".Ap2M&׀͔tzۮqD܂Ƅ$Vu5Yd-Rӆ%Wm /:@|ZYjp/NB>esmcdJ~gyP0 {]Lx[ 0EyMSq dRAۮw[}`z, j"S6鮉 l"u{FYJ:t&D,1J].u~4A3hc7͆ys(5a!~ҐRzNԓxQ Ds0KkD`לa룠UQ05ځTZQo:'Fg۩V&۰a<(c&C &%10n B*% p7u>kW#]y@rJ׻| |okVrx]J1s~wY7#" @NzdH:s~3g>{3GiV6Yt DݒLrvIGb6:gS&ɈZ'BLDM7fAT$ y9'Z5ҭ;]7WP-4{x#"u|7{2tZA8WJ*b8(3F Rn9/ 8,KѿGkxO[0){K#,k$f88N_ Շ@U" ڌF`}rhN(PimT$&F&4HKhcs GK_jT_g22?{9j$.uJJsV—,KnW!A l!)̜jv3Iue WxQ N& @b@B5PmdfZe8pHL)h>R&DsƣM&JrăW1`IziPZAk{ Wn\| ecq^Z#\N4RF9 E@@xN)-ULjR_0v1ޠ_ QIZ!v`]nJȶ?Re3xKJ@E絊7B}R?FD' :Pyi]3^Rqt8.2YsIQ`[BǙ tfzkp48X؏'BsL >rUxɱ$.ol3puᮭa&Nє^Wcw̏34S f 3b$@S.k%[śW̴.ЬR&q(fTP1AX_Oo[^cJ xJ@ Wʴ(x",^/iv&4ީ>7Cr맡F"K]G.>>WߑxQj0Du֒JPdbAlIn_ y0ZChгpԚ!c'K. v_dk@Ls!{(v@9Zrq4kThK.#M <}^]Q&<ۤ}2ܓnv?( <̾.^dWiKڞ*ֳv]w.TS@x[ 0D$sc.3B5믮w0S #y?Xt0(.pTW1()tΓX`292G JI[vbx["(9~wz}[1F3ޤ6քXR򢎈>OX'BԜi=LxKj1 D>!cOr@KƟ>Uv%TE AKIΣ `֚p!+&=xuʹTDΚ=N< Tx@hxme;/ (mjʾ~x"Dg (coc)pFn@?T1K8JʽA/::e pux1n {^]N6=(E)].^ {7d)f1C)> }:G Fh\qZ_@H%=^y8!ʲ1ㄱ3fheAh}'MxAj0E:CH##z"G!,w{MH]#9NBO=[C>V508-d&uvw&e4AXŽMCT_ %:m ڐ H\zQ*5٠)Ap*,\&SɗxMj0: A,( xHзx?<̐M .]^DlFԎ7H&#mzviLtfO y 7/vW+G%Υ\XgSsp]kIlMAҟI$]-}e֙_]uir?x_<xAj0 E>d Ȗ<5Ml79CAғ 1XCwӄ&PDMLnWǫOŪmbLާ@+i1fKy5ɱ!ߵ w]u\~# Lyosu߳\5Ah'qcp6 8fHRO~eQr-ZkigxAN0 D9HUJ` RTI'=L+"^)j"v18I>-r uP.ShY8ԈcF>ztDTt{.)M |ۃ`|% I hcGףּKq]QKQIQBNPov>ۺAqj ,g?m2 .Pint@̕) lxJ0y+MEi-}{s7p`sN)=yeZLct-&퍯}-vej(3H9 АhZ0t#!#-8O|DjCFReeu]!|D/u ^myW-ݟ1#S\'g7r6 حȄ--\"ASW|$rux]j!=E2jB9BZm g<[A}UTo"y6%Oj0MMlGrhMjL4 1&)?7 -{vK Xѓ%8OT\JyQT +8 T tUxJ0DI4E}4m༝PAĥ#0y6yfƚ%Ĥt2&9?{đAO,pEYŽFh"]'|n'nuo R ;XvG}DK?8QZF(RQ*@FեSx]j0u}/ZPB (EW ,2Mo@N*DDp64k1)z7.Z#% e*EO*ir;7_~n{=ZTʗ H3Yi1X-SDrYG!0ϼ{j;_ XHx] 0"Bn~@#@fW ڔ4gp>ވ$x˅0&,$ 699yIbɍ.sB,].AUuLc =WmFOoc=p]Fڞfi>BZ1g!NE)IxKj0D:Ef0-C& %G# AzWMգdDPzgڏ{/ ƆQq9 4YuX`4.ςAwRy45ܢ7JF^)p 絉ϭ-SX^Tr9.\kb ZAxKj0D:E3 j{LƖ>Rzzc>j)e68W舎$XS㥃ޓ#d` jNn0kd%h(own9'|o'muoCm#?/_AFF O:S?J֒a0\ף֡9\8#\a湶9L[Ex ˱ 0 @)&""X؅陶\Pm4R(U#r2棝_ RHCۇ (WUqoxj0Dl(JV-JJJd$94_:9sZ!p+D.3R~X(5pDq]|OJL=P-f" xW&xMN!Wn^4 0Ņ[`Gd0e`**UA0W٠V (Pd^ԕU(w+rm z ue૴\svujӯzG-V7=e7R .| ec?0>Rid8FgV##5MPgȱgPR$sN8h^x @ @c}^6p1PPE4r-۱W4JXMH[!#ʌѧ=D\Ȏ;;xj0 D z),l(=RXz.-oL(,60R"ck+9{ݶzu*7mc,V(d hLףM׾;OM})Ie=w:[M,yʯPkSW6UUeyC>Q;Ahe @b`1B ){ \`gy(OEa@Ϻ R 58"vq/5 x Ź 0@\JXc1 2 AwhO2l}I;Z(1#zH0&13KOWQͨU(eX={ixKN0D>EA$[B$6@`O{H?gWk&֋+# >͖T8jaO)1[d+fkFRħS\-Y?:fϔF2>mpp.JjQHBNB|>IscKkQX?9mxF q((T׶x$#ݧ-LiF=6Ÿ/hφ{(-b@8Qh=lXqvbwxx ʻ 0 @At&')B,~{w>M<<m| R$jB].lԪZU2a`!غu\?AxA 0E9$ x2I&ZQgZބ54Ss%8;-Uq,0j_r19t8%:)OTJ q0^; uy$ew9ΠE ;nSiy>ǶD%C \4 TW9n Qx]j0u}/,J 9Yiǭrg}@RƹSjlCVȒlpıqڐ˜2\6:N `У ȳl躬B}{yk߸?Ⱥ}iGLnHU(U_$OL +dxSlxK0:EFdAs9@hIGFn\3jQœ 1XNFcw9T¤g DLjdJ׫-! ѥZCpLȦZW:|pKp[Oxl'|mmkO,w0i ES-,AD}-$\o Os jo  _L+yU=xKj0EZś~dK(tI qdv3;s\kfj2XzgbBT6x UN9}ʵ +fT|:}Bky0ݶSS>v r'cEQ"g"3?Yv?hxw(tW$xA0zabBei%2o[[( y4C1ĤgMVXŬ"b@gVd"27o9w{J74Tu+K㸠]ySťzm1✚m. }_lr?:uPxM 0F9셒ɟ xHԂ&%M=vo|1dRIZ>GFi6sF;JyƥCRG+);ѧ]E6spYxֺĹ 48$T?!"ԥϵb4^dOҗxQ 0DslD<$l` aEx-%{h%-Rk(T Q<)Q\ڥ _֬x&N'rT\]VkWH.0,N#y|7([˺c3ZQx[ 0D/HM".AphmJ~58 `,9"*k5#Ӝi# i|hT$$-)ɋ5Gp;SizlíJR)'qpbGej]cd+Aڔ !%c^_QxIj0D:'M$!GAC }gH+^n" ,\6F!SV.m=CIl\Bo*)b̚KQ`a[J?yo૕QRwx-JobxcN A79me^{k=Hfd贗 gm:uB-cOx @ @c[ ?Qh$ 0s/]'V1/꣣ nE&H4 KS9L< ${^6xJ0EN$d<Qt+*yI^fmSTmν1y)z;(ISbOI,x`JEU,Qfykmɝ e!x\^x^".0sҠB^NS'Bo22k VKa˵CN?eWCx 0 P)!N r޻y_:r)O 8% ;(zۿ~s*ieXSA]sESK2MxIj0E:E-F-!dh*$h4TY>C=d"hu[Ɉ; q,.\ȫnY*48)U$Kmn+Ò ezy=y]|jJײ6r4rHNrGHB-q7]i~[Px @ @gwaEF<˳U7C\.R 0u&i'_ւ zо58#Mhp3·xKj1:Egm0_!ܚ#isoSWAYWT ߒ[ ,7d7Tb1ɜA4"⠹u"azE8<7^79m T\`]r{<*mDKc*tZqpc { |? SِxMJ1F9Eo` (@* 銈 ~|xO:3دM%N`猓6sAM6՝:cB?̈́Y)| .eR֚/ŧEjcUsIԆeDL-K=xA 0}N1{Q4 L3-TSm=>*!p<{ɑ " .{Yp#5SwI YӽӔ!igX:ӞETӗ8o/K$ԇN`l]DvzJ6D)b DU?JJӕxA 0}N1{QN:I@#[L'*T[g[Ur]v>I B])8s\ՠTG!ŀDj D1!YgS6p~⺬8.ӻtvס:KG[DaȷdIxK 0yVq$i $76%M]op*.7$kNZUD`3^Duv2FO: <{%nS*c$#|Ӑ޲wF+iO\UԤew Yba~?:Y3l/P^r;JxA 0E9Œd& neT=o*3=h6N0{LFhCT`2H"&١XO8 :t-^*qcޛ>>eԉ#څh ;Ry>mqWn ? KxA 0E9dւG<@N&mIS۞{|+Y]EUDґ6( !9XŐ$g%4tk)!rBkyLnZ4}xu,qrtd`^cXWe[9PҔx[ 0EdN@%.L-i*{5x{ gmV$sHYY˜QB G99te3ikzQ j?s&,4uJ<+H 4P!T.lLs?*Ox[j0E/B]@Ic[HFk%8JgK2C0Ƣ%zR*#ǘF2'GRQC>Ep]xڣ'[TY"GLu ۳ .X"O.2Cm9Ҧ{]tCx̱ A)e`002dv\!sXG5-&92Z$@*WΛGē#{{/f(lN7%|jx] 0s}$_(@j#yf+dv z)m,IGBDػZL**ĤfA'EU*܈cNl5PHDž Qk,dx1"DD8N3pV^[;Ox[ 0E$  dR mSҩ]p9+DS-y*rD|sV,Xif;t d f3D]N S*4 |DD\yPdxQ 0Ds/hB)=Bd5cx03dz(`2G{s;AQy `u۹1Ah؆^вeJR$k^ ~ǞdL-USmSpU*g.RY]3a:=C~OsxN[ 0)_&M( ږ4gp~aLɪ`ɺ6 ) l; :"#'jV:Z :FtV* F"˴dk pYom˞K~yrOzo}&-ϫ?FV$&aONHxKj@Ds4RC09B ,MkTmZQ#xqJ̓C<ަ$Mkqvބ4Cl9uA|tȫ݊7~ǟvUK3WV39l.@v\1ĘߢeRYITЦ%nPxA0 E9#41F# %r] xL1fE7턷m,m7+XrǏ'gy}C_3!N@SHJk=g2xUp./LH@S?R4N#t5fHy?g?kߎY6s^: ۭ9lj1r諮3<.{uNx[ 0Ef 7*Fk8 0dVrz`YTӐ h^Z4bI]*!Me ,ZqcK3*]Ϗu䴖wMȥ-hGsN\O;aRG3 Jw]nX#c`LxA 0E9 aLbI2j篞o_kבּ#@ȉeľܤdZR)ţp=v{!ytbrA^\!U <ߟ/u=嵝r^ 7hEg .xbw=(5"'^Fٴ֠LxA " ] 1'ˢMli(789,ѐ).m0 Ԧg b.%-JhL$ `NLH"_wn>?QC!׭dpX 8<#c"ľ9+`mJxM 0F9EBZdF ڔ4gm>{IqG՘qchR@a@˄4@f _ 3D} K `:5y_zu[Cڞfi<q#"ĶTRB#KyxAN0 E9Fim\!X!9r)JQ"OVEв' 8Qގ]<,e^br3'm/<GRW[9iiP5׺g pEQ)% 0exz}|{y>d$R_gax @ģUX b<03xlXl ޻q_UW94#L C9u k:=D59uY`$Z2X? [ۅ>mKȻ`nrX{NWY|gqx$khwZ[mb_O;|vfő<$RPcm)r$%J#g$LTP.IX2uxg/z{O G!ƒg6ϓ?"=-W_jɘ?`R(xAj0D:PJwz")T4$ׯ}HBdVDS$;AƝ %Aĝqd ɔb%ea:}bW>"xڽg/+Ydžev^Q-K>0F]/Tj_ zod5hlWk7_UFxMj0 >XNlC)u[+S&obf!O)L>-QL暇l _j.Ղg*%b ?;O&xz~oqY7'xC6=(1MTv8N]%>~\TxK 0EYś b>Mq ׾Inv 3:skȳci1A]lc}0G1Z`칵A )>ҵl{}RC.tCE0].5KBژ 6FM6iqu!OJS xMj0:eA=B!(ާP[F>Cg7E˥XHB;'fc[jX;Ystc:'X;$ aAt6BGNt./2Jm/|RZ7uY~E}b}.-fQxKj0:E%!s HݭClI6$}]DLH&tMI>`,-V^;h?HΪ)#jB&rV:<TZETs m]^sV0^" ,2KGD|Ta^rH ~Qf,[?o܆S\.Fx@X=f2 {IWyYe/`zl!|pJ .Nr56iN ~Jt ўFwzx[j0E/@)]B (cUbH$# tאaZ k tv2 >t8X|crEnk1ڸ hk\ax xoR ~ۃs=o;{+{JѾHhbp1Qsߗv!QE VoƲl#Px[j!E]EߎBezF3ۏܿ:kQȢMDnCLqg JN# xkrlBY)JQC&IBx?.|~H wXgKG1m¬2Dhڎ0) ! WmޖY9=x ʱ 0 @)6I C<!",.NWbŴ{4P3!@ pIi &|ǽ5Q`g4h ~?xMn +Y R57hT>RKG=~3tv 18Sb ✌f?'h[lXsΆW +혵 ٱ*ØrEOmF_};Jm7L+ƙ;Zћ|!R}1=n7OȁpzRxOA 0{J6 &n`SoOpN303"Bw 1Š{(ِE dKV{6S4@4g"[>sT)p^㺋{wJ1t,j$827ӫ('qRFO>v8Lhs!%bHJlϥ‡tp̗eK+DK=f nM*k'ƜC E.,=3}_-}KV@x @ģUX3-3l{wy27F}p4tfN~ސpS E.lBטG؞xNQ 0Ǝ0S k-֎ GH HzB]P70B 1ʒŊ*i 8Qv.hm#EިRAy^s^"q.Okm^D<գLj)}nױNy<}iZPx[ 0D %Mr۔4o 3ôH` rZK`QdkɁ~N&tN{D+:Y8ګTzÆ x{9jĹ'N+ Bh/XeYr?FI%K-NxKj0D:EeBB[*ψ%#'G>CzE%ӓ';KfhҎ<.r-Qh+C7jm [ayM*>2}Bˇ~rl|E!碌͠^zʦmr(_88WE8b2+ԇ2?)Bup"$7<( "gԒ"GB?)KSg)yPqx 0 @eL,Y䓻aTb!wr/uVc cI(8sC64i9&m+9Adx] =ž?PJP5)=~:0 L-D0@RrE} Bp 7+Ԋ(-\E=HIK'-EB Zc|sG}T`Lu;ṟpQ<\fV7RV!* ob>ߩ?NkZBu]~TNx[ 0EJ;y4 I&3MQ\92C%XDN[tV l{BH}ҒB}580d֩nR+\ p\wv8ʻKwn'6Em(umyA7/wHL-0Pʞx[j0E/HJ ]@QGI "ywۛ*Pv %cΑ01G\sDqӵ K \Nc!$L%% 2;qdx{m]>;vuv˪ &9Y<0.ˣtŸʸA}r7NdxQ 0s/H^D<$y٪` B:gkK<ZX$h'rj s%x`=ER?hmcI酃PW.tCE:/<\BlL;3pG$Oӻ?N* JIե P=xMj0F:Ke؂RzBPFQ* }3۽{Ic-u|r)R064hmꁍ!pbZ=60zѰYEbE|8᧟hĹ_,م#i4M}/r(Zy2d,h  m7|]RCY?x ű 0@)O6I6"f-ގkE<dB)k+k HS:7aSInC.x[ D]z5PJPkhb0믮9q~ S$ɫDcc NJ#*) J0i-*0A+%sgsTs|^G(&QqPL@~-,u]j!a[=um?LYxA D}!|1PJPѱ 417li<=aT ^aTz:z(8\ZmEX6d5uldhpGRd?_'[^ᾧ#{ĔhVT]ְR$/Ӳ̥QygGTW4LxKj0D:EfԖ09@h-m=0}J3HxLZ'3'LјؓS6j 1yvDHh\wC!ۨ-):Y|p2> ~ {=ZT[neF5: q;b]"'JR˚A*d(RVSSUxQj0Du/YJ =@YFcyk3 )b(sxs)b9V%뤟md7(sr >ēj/(}G2.+:0Л=bE?Nٵ, i{5VPX~9|QVxQj!D=E,ګr@zv3Gq>RWn e lcrU."h}@>F9ߵÇ < n턯%& ju=SljR@)IB4z.h;.>g{-Ց4zYAx 0 @'UP8ptB4B r̻y_U@j==eDQ4#%a߸soNҧM5E3b1gP?ٖxQN0 Ds VI8G@pNm*7Ӟ{ҼfTcl}"Sa_}H^"YIe20b"^-!jSNlh?]C(|ۃu={;}]g,2y&0!<#SLj1h[[fX,vcX]vRrX Yec΁]A/ y7]3^S413#Õ=-eIxKNFOc< :su)s>LXuZ3e|BE aTFYYBT*/JG5(∼DIٷy,Ox 0 P(9CF09Ȳ|,%d)޳=y_UGĨ*-L0ũ46DXo\cu ˁY;Cq_%7xKn bQ,0S#Dggp`"}-"KX5:{7u'6:P,4h ֯!xjU+l |PO~ㆯz{ͭxl%7Ӭ᥿|wx?J>)@ 6M&ANZT*H<3(*MU'A@A js~-ә= ]goEcx ģS80J!,nU=˳sy:Q'a ha ҸzX/8XTԫ`+T= ֻ͖x]j F]%2WTh&o~osf'>&1P| h[ 6;)cFr^Gwx_J.?iR_D=n|DJF]jV/Hmu?"Bm|RkgWMn4WH:x 0 @eOԇ0.h Ë..wl}Ia\!HͲb Z ZfdU̡(פxA 0E=L4 x-ئz|ۅ',ٹAߵ-ZHmYtFoElЖCPŀޠ6^)Dаx),E2\0mp78iQ4G)G@R`gT1 C_;d $^2ݸk 0W5x 0 @)X_a(Q"X qN.RJj%UV]v&1!0q/0-a TsA5]WzxM Z#zbkз ZQEզZ&+1*ix lK% &&B$@+p>zͅ(m=Ὕ^R.t ꝄsKB籞V0-Oͤڎt5QxA 0E9i2 xI҉l#im߽{[cLtq>,Q&' HY}BF&qYgI'Θ4 *nҤ}zoΟu-ߚ$"d8>E`ն~a?ŦTxM 09E6  W-۞b@лТCM:,b66T0Up0CD!r$\E?7rs=[sy<^an'OAhG-"A =358\##ߙm}7@#"y`>.:M\]T |Lu=RV |. dm1\ eCGĘ\u~kn4Ϲ<`eMT8#pU]+dW]Cx 0 @eHQ0.e^$wn{g;+s?`:-"l>} BijeՄײ #xAn b,/R h!F2!}CW{%9YkZJ}+FI2Z T:IFM*g"圏$WN@x;.n|4>kBRQIxGD=#EHϝ1B̕B m<  vPȸCFܨBr Ww̥Aaomrobx @ @*(zR !D#G/oڟjqg$ҹBHxl! cp,բRSR7>xAN0E>qFB[$lgL#j<.$g=}"Xby)irkУ-/䂋% gM%ζ9dqn,NKuՊO %r?yHM8|'TV=Dy_u(۳0+N! z! /VO\(Fx 0P)N,%K{l}rN6DLj#spGS {gPkN\J4{xN_n ~}bE YaT(JO~+O+W"鍞dLvLD54ҹQz(XigDtV94*襙t:';1UHKq#Sun'~^)5iOH|qDR~@BLWH{㋡Gc3=&+2|k>gY*?CߩnRstB"bl_x ʻ @ @𪠄ۯO'D#WC0\˵jT2+2@ -e^sQ[dvyh]R2 ZxKj0:EFaa0 VlȌ$3 h"t5s)`09*6y `cJK sfy=r># w{=>~~dzcCSTm\?N+ӂޡU:OtZoRUYx[ 0E$y4   I*.v ޿^!R(eB"Yoܨ4)QàOOO1yHCLv#}nܹ}~}eGZSO>_@i1Vz8m}8b-;G,(?s^4q47ҦTx[N0EE(Q⤩#!@bȏqb5+?JqpF8sgR B0ݵtae#+RrQJu:@.AnƆ \Ju &ihh3$(9>,t%D"D1602<4Ej ǒ26x1J,*/"Y`b]8 un=Vq!mByݦ+;urݡDEJ+X]?g<\̟^QUPCY,xDi<:|-VֿӢTiG^U߃?/x 0 DQm8d&'Z! "Y$4fHf#kT,zwSÃ}.iton-Y?!Vx[j0E/J Y@@YU8Ir@ʛҫ!z@ ^&,_8+8W~P֯Tz{ᕟOx[ 0EJ3yL".Ap4ZMHo߹pN-Ia? F&o&?X6XڻA Xx 1R4dZ Y.0Y#J1N\s|G^ =2qLenz;( IKLLi]zDH)طRծ8MPxAj0E: A,%_!,w{$H 9YU1J 5"[YbiQCo;4Ή: !uOtGC| }'|m'ܶWE.Js]p{{hyv_l =Y&z hp;R]xM b2 #z2 Ɣ } dŠq Qt7=7wb©k1(A(V"%Gl` ܹr4.ۖ9sz՝6 e! jRyJ Fm"RxMn FbvY xGTu 0Ėi_ vkF lIZP9C8iqبpjh'(7aDW^M0YFXPos.ɍ |-vQs/c.wwJITg}2>?K;DHj3yIw am7 ]Oi)zeaA]dJx Ż P P2S?`{ R[ K%9LusV8wZQڮ&?5G..KY.0HjPc!=xPAn E%KU L5N}Ym_Pfь R-ҡnJ釹g孺C"1j2FOvZzMVk8pøL oټ-FZQ,TV# H876¦}_?pdp~*"Klltš"up>QI[=rN!ʄ|[|9怯}MВnIɉo*5XVLh}d}x Ȼ 0 @2 DiXm,z,7; Lrd¾e ki]D8@ȩKuq(|#tki6&1t]y;nmx ), 1܇aߎ;^k'$텝Qz&sgH2TQ{Z{27Ɉ@AxA 0E9Ÿ$qD<$N6%M= [dh u tQwmK+ aVkȲ !k12ytLHzp8–!OVNRpOZUniQ,R.~GM4cҺ`0EzM('mR&xMj0F:t]0 #z2S2:C[|^"&PJ6MHƆcdE-3ɋFShFŐe1^lȇ܄J45/׽~R2ln`h݈>u[!QA$Ai)3 ReRxQN0 D{ `&i[G@i64tۓH3o%jσne7Q$^eo 6&d?3 Z7EK(4&ys, %x#5&rf HZᡭL@t”&#he|-`|;]s$)g`7 ;eHV1_#D޲W/I=~KXEl\0sZd /~30xMj0: F_(E[qCn_W}<OX49XݏC٣;sh>N-f=5C4!:5=br*rjU;|!ugm2!5Αf$3❋V.ዅ;|82mKW6 DvW9/(렸2PJ<Hۨpa 2DK9,(Řx1n {^}`EiE,XrL7 w"P'|`R)E7{h7֚|Ilة2̓ZŔ]@+sNr>h'vFηᓘ:|=Nymr ]*(: /@v>LtZv0x>ZI:4eX(oQ"1\ԋi?Yx 0P)Nﱪ,ҭKh۽ X{hu7QB, Slk'F7\㿰Q\Xpm'=!3>xQj =ž$ ޠͺBl~o_s.2+bJ.hE3L!eHhxtL"u`] ѐG7LqW7;l^[|p=^|y?ՈSm?w70,fƌ2STKrQ#F 0H=6\wೇ( }7|BDO+]wWkIa<Jx 0P)N0 ϱ,QK{l}4xy1Hgi&dY= {:GH)&JXռ4Zx[J0E3/"Ap-۔T{;߂RXxaGlHh-c!Z)! lJ9;h2/,-N#ϒo.'SNޠ޾ =|OLw,Go>0^}t(XAnɘ?oQx] 0b߅M@#@F )V۞y`f2CmKFKa;t6E2nsTs< xU"1Q&CN&Fso\U\Y*\YmN㲔RL,g0j8-5>D͵H̰NeeaivKSx]j0u}/ՏJ 9@YIߦ:2>CmfFHRq)s!rk=dzb癃٤1HmV̩&糸.X>V[ 7\|#Ck+[MK}\_@"ԎHeq""23dR#MJ)O/xKj0D:EF-YC9@hI`,Y\?RUjtfN% Eq)F+?.uبs9SN;%ZeftgŃ;Mp+SxQ D]&W(BP:^b0~:fL-{B)#Kc;N *H93z}PTwC`hGEPQ=n'<~|Ɯ݊z,E˒9B"D3K;kʫ״5u]k|LTx] 0s &MA#@6ZMISozaHr`#5Pt֥hs:*g+Z$dMpIIA`8ۖ +yJE>e=p^8 իF;<&yz8aQ`NxQ D=ɪ(G(e5 m479C aZe`JIG )6a"*&CG5204Ce#ZƎW΍|L/rs=ඖN|ܮRwe{yR{D(t n\B,l8&jl qfyk&cdu@Nj-i\DRA,i`zĎ6Z7ȣ#e hh;7k9;U1]oeeυ)r>~VZu d9n~M:։gҒFQa͍D@̜`-^q‰gi,-g|;Z/d >N~;/4[}x ʱ0 e a(lY.slĆɫ߽~+(lӄD#*]QL&6p!`l6yxQJ0E- f&6`Stk.XUW7yQIz]S!$8T5{Y&OeB5: ɂg^tm«VxK_ Vn5q{woNaxQ!{KBɼՒ/Y*@=U!4ս{t5uccKx ЄS0B@z4ư #f]YRd4+n?g\Zhx%Sr0`bQ"g~YxJ0Fy %M.]$M&m6)ۛ*j0g*"Xn7QKcFQ؇6LJG>D%,\Lh."zg4>ŵQrtF2wR*ܐ[t]_𼗣ze'Eov[1_5ѥc;<-VPT R;ccmq1@Lu=[vF~qyxNK] @oSbx ű 0 @)!N8ޅ&!"L04p=3 , NV՜` )@Sy'kI1Ц5md-BD.p$kI[{}?'xAj0 E98# E!#=~3TÓfjE E흙xB", `Exh *hCs(D;YaW.di}#< ~ \ qe jPփ|m:ۖno&\|J"U* ^{\L( >-Kr~1r7Z7]Fx 0P)Nl8FUE:DvXg{2.1S)$Ac=&>LW~y0DJ̄AV5 xIj0D>_&O M9@J-YGR*꽜RΌn)/(x8ɣ0pkvN;nГ5U-K^bOd$ZO~*G,4 $MU3m[C4[L Sf%%Dv0Q^@7P\HG!5OK]Ѷk5\fCUx 0ħS8JaЧ1E]Ļwy27V"G3;Yn:xg7Q"ne:ܸ*m!Tx/;xN F(|kHnE|FwqT;v|WVfI.ͫ!jف)vaLcPxYmTlx[j0E/=lYRBP$L"-3R.?r 8L1{g&Gl3pCGì%fC-fm# y;S9*> P'KEm|ZJk[&C*u-Q" uji^UxKj0EZś@ -d.rO#RMq_) 7E.a0C":G,w RCÚ:yW8L <\%dZ 9e}ס~\n;p#AO#1ᅣ;!Ozvx 0 @eVpJ0.H*be:ZCNvV. 5eMU s"%v2zU9pw|&!nP{' (rKruJ>{Yĵe8k7ej>RbٺvgVx ʱ 0 P`8N0]"Xfb(^Y"W1irzFBH #³9^o5hotiĀ ~xMN0 F9w,@Uv#!Ă qL%.>ғ\4cT='cd%YxJCat2,$!NKHgV*|Szx}NxoeRW67PꗝgGIJ?$B\ף?GL>j e}o+Bm{b8J._Nx@)xt2{IKyYe5ij%#f>qy*&3I?$xxOAj0s`^ga)=, }@=4{|IP$$ĕT |A톨tRbڇ{V)1zF}1)X>94O1U_l5R*u$ӝWꀈeY2kchSa {͜R~\p"ŽP[rZ{gQJ e/{jCax @ @gbxEF<˳E:;r`Y֝6BAٌ3BrZKa.(V;"|?{  QExQ 0Ds ҍ۴ "Alj6%M=x0cU"O WbjT#QO>RGb.:WѡhpM@|HQxagx\C?_z}[M z,8v=5{i1qJxLQ 0)޿ mD<9ut;@ ]QY1؊a@NtR+V^(H.XkCOQrbpoR΍+<涕KnW0Nc,tq3n;w8ۣKg~_y F>Zoz,u #JIvZKK>l?!W8x @ģUX3 0slxn{w9 تF v kb.D dL/|:2\aRPqWB 8r&"+mq@po4vgsl4{kSK6^i5%LhKXjn!h8b;1&zAFi8z8m}i* ?T6LyDgf0]w Ќ\Zii}x@8Yf6Z9bu`*"wn<_}xAj0 E>Sۉ3#z&44u/$g#nFMl,7'鼱`[V& 4:qZ%ws}gU)&x" i;{>K{"c&HycMwNus9T^qYO@&0i-m1F\) !0aIΗ09LP&<%A=G=]1ɐ"C İ|p#FLMSR?Og x PoVa /n0c?`;?w mf%9Z=4e X|V[H{E# $IͰxAN0 D9HU&鯄F(qZhq']qkތ-L!Dbh~G9kw9#0ejBm{7F ,ፄ'qzZNFJ?$/z2zԷQX} GR倒 ?+)ul; .TA3&.ҵA.NoHJWliC:3V]srLex 0 @)2?x ;%BŘUWάbѶ>6`8\]GX/|*hW6BbN'i^1xPAN0 #UMmB HM(q=)<<xlID8pԃ26]jԓ=΃C(MUDA@5j S~Շ&M?ʌnr/$+m{}-9-T;PتnRuuaRUOkL|% S-_A(P`)R NcK Z; `8HbTW~sY&9MK3$yDse'xr/yD:P%ECYUPw?wc>$\: d&U}^D xMj0: FJ 9@F<)co =G@`@A5)2)".yJ-KY#(>S+zuRKM+ܧ?vm+*KfQB8o RrRy3ӮZfX6)f7#azo UQxQj0Du/i%Y#z֮RCmY k!`Lo"Z=33 8kQ5Y;PDѳLSft!1Sq1Eъ6I_s;{?GRj˰JAcu>QmJ {_)U^q2KTxN0~'~(4@8iR;rօ=N/ovd ȉFvEYuU۶([6.rFjީ;չn U7US6ok4צmʢ.E}^H}^`aϙcGQզ[(A!Jm(t:L` 8RH awzlrxr=9 8GE`Q18$+>Nv<@3(ā\$<Y)EAљ~i`Y>e =O۷_lPegN@ [jڡ' ayN`ΛjLa,IQ`q#Xg): jLjҸi΃`~O%xK }!/(m5cz:oUD ]d: qV u@F[lh94O:D0Id8gEޥ;6|}u/GLpZ](i`ĺ6r+p~ݷt[-_>RxQ 0Ds [5?<dh6%M{~38oUK$Oi"1w1Pc L\t9@frJ1"xuEXoS /}hbwe{vx;є[֫pn`< }sϲ u}m?L%qK}RxM 09mA4R =@dVFbׯox?9coEГ mfd5B,i'F3s, W~.Yp[⚂1$_Ck*8T8#GRQ\ aE;?Prx[ 0DBiMn@@pǍlSnv ߙL-Dj(1Vi+"\ڄm F MdD$jW"(Is_.xk娎B +ofOs%//HJ}ڱ,:yW\Qj T#+^(==:ҁbNÙ2h:Yx 0 P.$E8=3qe.1 w:jxIpM6Wc!$xjB"cxKj0D:EFaUJ ed9 U+rjˡ0g+h'/i2W؉=6l.X#KVI *O90F-k/t4z_Q(`4* IWucD2zׅn0!ޒPxK E /%gHb0o{{#1uRhPa0Vj`+6Z:(ׄ4H `Rhs Z26xPq"\S^)-QM|~DP:p,y12u'Xi 1&P(xAj0E: a$KcJ9@3,r؋ת9%< mt9~$T4k4lvzb7XJ5!ZsQR*M*ܦs=ᾝ𽕽h?rY}ux]t>xL1&\!ꞼRt1$po\ƍ [Oy/C.3wT/G‡<&|^NS1P S rZQ!6\A}kw-vB?dERx 0ģS8B 0qwq{w+ba]aE3TJ(Pn!O⸗b" kVGOV}? wxJ1y>K&?; x,37NooݾUWń(Śդe ͤ6i4j?R%Ơf3>&(lry1%z5ʣak%xAF\+4 ܠ0p\7[' ceֽpncx/ [%ra gl_x 0 @e"_"a\ԫ Ëd4rlv-+枎Yu5)gΐb,VT_5"4 m _޾1xA EbIJioPDThb0o_5my/c.W@%ڡ<&|TGD{ $7haZ 0`R}xA 0E9IL@L4`Iמ{MR')PvxAn0~ܣ!(OcҧC">sѴ<ѵwwmhr*c$1Ivr3gQ[BAU.CB~B;i&|zv7}Ny޶U.|$LfUƍppy±)|#Lu } #,|ЋJsVh Vx 0 P#S0I< UXإw{2B!M pe/Ѹ #ZWdep cz+Y)EQDx] =žPJPn6h0or *3 04کe4gmb sK䔒kI 0?(Qh)ܸs VJJ}s{<:\AeYv0ڗhS@3"Qx[ 0D/HIA%.@D )1ukp7:G`U1 چ;dcY,0wFk2x@I&>Jൿj+:ppԵ%ڞ8gRZAE 4}b kZ?Δy][W4QxMN!w.411.<0̛< ˸0]UJQCh QZeQȋBZ)h'$wH/'@Ɣ\.7`N2е6@~ףL +H%$8j@k#/_|X~,޷Xmu`4ƞ`F7qtdx 0P5R/"#` cEY+e,ϲW V5U*)X5]E3ޫdThmee%Lo* ;x] 0s}J4 x&ZMI  #n s}Fa4ՂfcFk"{]OQ MfpWp# E8/<kj".ILrobޣRQ*Kڦ?Xf؅ E4^N{TxQ 0DsJbd"Aibn=7 -3tR֥ lO&Xj‹NJ[4!*<%lkm,\1}((-! 1 Iר>$R}Hd L"26MSjSxQ0Ds_$F2Cj_=W*"@Eq̘0r,'Rl 8XZ/E11tSnG7 – (l? X8?x @ģUXg slx-n{w9jL:"#1cxAj0E>ɲ!G_Mп{ (X73`3Vc쭏#5yؤtJs45XKL,:y5ov~^_MkXodx ]cOȼARjuhG"8?SǞx[ 0/4i^  7ɩ-hRm83S*0䍴MAi%XVt+WFᣈ!JgiLN\*P龼Lvu+1D.4HF5q~/t{mBP(E~ TxM 0}N1{dLG]{i$P)LjJe%l~ߵ\fH-k'PxA D}!RzBP M FK_s-1qcP[zX+04ZURZ+DpB %=+7Pbt|\*~O~uϭ \4T/,`'0/K [r!25m>0~P3xQj0 D} q#z"+&t79C1*@U2iCJL1bh}t;n g:FA"\]? %S|-_zhۦ+4:n[c Rz)sZٔ0DL*86SpYxnܶ:RE^h ðr1c|uCgx 3L-" qMiDhKLjQ9*N$VU'ǔ@DRẗ́V_]x,Oۑ[a\Ip<vԳc\R.y~QxAj0zfFd Be<dž2SסE]˜G'8ē>j`.WԺ Y8و14∳t4nu~jys+s.Z,Fr'b$oZo0eiuw83ƼQؑx[ D]3Q(K(tB1Y: L\Hn;H!i|04"=&HQ')-8BťqcD!zІH#O )?a=_^ 5"avR 'bNr`} /RxM }5@)]<_Pc0&oOxk94I.#]GK~cRٶTBG!j݆YK,KH`kzmu-;t FXU x[ 0EJyksH2jP497nm Wjp_ӧ}pYƉ4jgPO,s!X4?x[ 0EJL^  dbE M]<2^tvM(ei/bSO^>*2[d/L=jCMƠ 6nܸC!uj2'w ^z- '#Cj(^Qd1$#X<,dYG ptF/Ɖ!2.{"e2JGF?ht_> {=ZF4a0cК>3*ecD6|,ұIRWRQ͔xJ1y Kf&7&gdHzw] aZwQQ /$~& d49C֢S FGG-m\~e\Y;nmh@ooƘ?X]]xJ1y+K~v 7a,tGv!f7n_UP2򉥗JOZ9Wjg t"/V`L2`cp8A%s3U*q pJS|Ai&4p'D,2!0SA+zqj_zm. ϵrXocf_xJ0yb$Maą %&%=|{ەJ6^ BRT i[[LD0h&;8%y;02Si^5޾ >kayBVa׼].7,Oе޺P+ܫCU4GIU^0kmZ y ="dw>YVyu/a(ۊcfX ͗cKhxA 0E9Ŭ%& xL-XS&=oBSbkH0 &v#2 FsjIBN2 c~c@^EF;\kY%P=n" JF'7^)t>J17؎r50):Z T sV)5!mgG wT=_%Vh.u!S!3K.P-mOypɥfR?ްF:+ \:T3{6_zc(xKj0:EB$CBKj{ cɴ sϐ+xUDs>ɡ~4)ce[u S >81Y "3' 1|m~Go'gZ+ 3}0k*}Qϭ VHO|uh,0QH}w*5֪Z)g^xN0 y 6%m4B;4qFnⲈ5lޞ{|-%68a˥RЊj+H5deQ쀉B˥1v5v67hɵ Dz 6T(OχS1YcU⺑\H |,f02aG\BG3Α\]}D3]:@ICF[FN xy/;@p><=oa?Y]Yއb[0ѣ̌?HxKj0нNhK>!ʘ-#rgHޢ3XTgS`?UmE.=B5VuP] oZ0!Z2<- y)qroY!x=.| o={`1gTn۶ULja}GB˃J?JR{xQj!D=EgYztvgr@Zmw$*NOBn Q%Da8u\lA:6l8 DD^][fO:Csx"jF#+6N8s[v&PUHIMLc}宕wCgS7T4@ k ǿS^C~šfm5/jDb4Gρ<Γ|hUU)e [(~JuvukflF6h), k3V),3/%B/$7A>B]hCk+jc.0Ksr3"Z(KMWgª%PSKJ @`o&\+Rs5BRI?x} 0E7;G>1 $ML*ՈnsŝK޶ VawanU2V҅MQ95:zƒXN#ڀQX+ gW()YF*iWcq^oy6x ^CxXao8_1I8mw/pM"&)t.(H-I{3l%a ll̛7ouԩ?"=__'Lqi#KQEQ ԸHZT醈E*Z瞌mHEZmTk*U4k]D+绗{Vx1zK51D@PPmS'J`Aڛ7:o_fcNJds\hXS6L *le5t_#SkT}rGϭ_RGVojq}{On5/r]l],oR̓F='%(I!r)u?+kM^5ZrztԘZ/ $Վ܊jRCQޜ,VpՖJZ[jMIȁr0ftRiMbv_k=c ?} 붴u)!mځ]`vϥn_nojcg6VY 3yM={AfEEnߜ1XM. #!fc^tA r<zVuz럿8UOqF5օh*4s0uaC|RNA+>`DP۵ I2!},^Gء"M7oMLtE7}Zz3.QW:q6bAsNDBE#kE*j;,R fQ\Q p]ɘ/vI׷_sL5do:-ƗU C0t-SZNu-KO5) wE@)A@ A@kv^f 2Xk-2e$x"2i(ޤPI--sǘ*Y"c(qse8q@ 3 ޠ"ܩw gD򄩤 V @q@:b^ ;IWRAdlzھZJnyɘmX l<0@Ѳpn\ZQ#a.sk⚪(|9yqQ,fF "e= Tz/LJ4!;[I4F.ŕ9^~D(Qi*Ǽxekd o84)Sh&dk]cYLҚz!rrND%Ne@(Hں 0ksM;TQ "@xij#~([]&eBMuܔ'v%+/|Dts?whŕoY˥gTBu@mw BxTp?0{uZVbrtζlZv/f$<Mod@DFu"Fs}dw5,?|*hժ`y<&W]0R,TNp; Wg2TN΀W{J96(VoC-'xvB{%nX귓5 `o $^qT8m9 Ipp&0Xm!p$Rh(e]>)pr=-+/<76=1 췱0 Eq1:w78kOjM8옑5F,.*k/j= Ч`#/(|*r$lMITBZ?/m% %t,m{ׄt 9Fa\Z$,и0»,1l&b, pyOj+׆G""0}  7KGke8ЋtCO2xagҌc^GϠdCepea<0NZccF5}Τ=n!mk(&E{eLGs@ኇŒ- } {Kyu\ڡndǝ/x.^ɖ4F~ M'>^r<2AcLm"*k̫q9_ k9@:#z#Ric}}``PGR g3nƓY9LOPS(ZsT| K2v^;.d2u453A@Eq y_*8I.$K@6 l4Zsb~+_t?tㄐ{bNg noF>C{I᧮IW ŏ2A0x4t8'XjGw8WnoZ#3==XV狳|t qTqq6qGul!yf]_MVa ӏ%#B Ox}[sG֯ώ5,H.IYm Dؾ_f֥ؗ8'"~kof~l_fWť?y7״E]W3^ֻ}SFǩl5-mO4n8fHѵoi% a2zOPNP~Ƿ%J",ڹqm}j=Cݦfֽ]e߰ cK)Us7 x k5 Ș08ͮ3ў7Pmi6ٓHBB gG!Zak5E9- +WY=`|\H4 F>|#"td+ uYPKA,WG${/ߏPJʶ෮5` jbHBX3 J+Q==>{{ys~񰸹Ǯ_[L2o͏sNݲPp'bbo]FuYY%ѴЛ2LUѹm3B}Ep[ܑǸMY6XWR/hyF# 9rZNHN詉 $1mHLpVEeMD "`lr†ʳs˚_1%DYEbB{mVn!o% w:w_J` wY x& IPxW @ɒ]*<ӧ3;Yմ=MP^vP2W^3Vu0Lt ȍhdmajsDCg , *de= NT MVF;1A '^^&;VWжkh iI{?.EY"aHn\ %XzَWIzB_(*f#,-ea)X5x(^HK#}Tg|xWRDDd@"w, ql?V0NЇ^i Lo.1`oަWw#"G?orCZ–)SA),˱`n/ =Ӭ#- RQrGZ+0*z3fH: /XL=*WaV,:$fU_f!J2J3{mME͒Uŋ_"={4DP&PvTѠ>T[)y.uϲs ۹GBECrA[(BS_KWu?T&mq9i cKZ` _GExVuR{P(%1j< Hc&#(&J6`6RR%c /o䘺"I*!4^V䒱Y2؟C#Ep\v*v /JxO@=爋" {XӇiB/FB{9A3'pM&*ERYQ,,! Zge1}΀at3>*$Yc_p.ˋv]09֌ٕ:+#\  GۨU #&I۲\b;®grКBX4OY)(]>!_0.|a|F@J1pCFh:˔$#rM$LGB]-KEٷKtŐd!H2ZBU9J(էI'#L+؉SG.[M!jQEW9 [m@.Q%Q&%n7Ib;aC2eFI44qoe/12II ;D9> 4+6NTɴzZ_ͪ?bFi Mk\[b#~P1V'on ہPq`.rħ:>KC;a@όK_zx].Hd =Mn>,&UXmLȷ8sq/IL7tG}aoxeq{|Z3'cn{BvIO/\*zQ|$Р69TJI>g@iJ4(6YL P/fU0H>Cr6cUUNu3,Vdq`fO, &? ҕH0SmQ2WL=YE·K HowTU;0iDC"ք=lE2hM/u$wBX/@vjGTF U6Ɓsj)^؋TE3DWcy.i6Ud?DflJ~E'AƣD {ULqȸf UU] ];~gW߼^!ǎ4LC 3уcYaYEk'D!blEqÉ/u/bltAD4ǑBh#TxfzPC3-dotW5yRR<j@>XK&^1B#YkS\".d\:\乯a.ksT[7YB0JgI~*'/o/ x'=PLk%۝]Dg|`LJmqؑ8 0~s5U30+I4(5:,߇+`K 눹Ef$Dp"5TVI!"ot7se&#yCQć$KUBn|UL3VRE `WZlDPѯWW*vَ]gŘ*%!R!>b)թd:@sB%GA02Q$TIBoKIO,FFMEJ'QaQ0 r{H۰ ;eX+xN8BS*|\IP_X+Fg~uYP4Iz+L̙{%VԲk0\]H6yD4gNU#UՂȔ5QȜ@z9 u2WխF)dr \B0_ۊO/'PBv8=A>Cʖjm-5"kJ N$/4Ԟѯ`3U 9V{|d :Z]h)='u]WɅңE>i( ^ؼ(ZT@qZe-[f"  RT rZ~|ѡy)''@iToYH/3H*>Ŵ (ur/^zTd9S 5 v:.?Cw#8ATr!Q/9NO0T {!$2$9s^ 6-J"߉.R!^0JAxUAWH$v w7-#=LS @냛bl eL M6ʈy,vM5$9׼_) %ü /*H"qQH&|JX t"m׬04[k$"hF}DLJڅ( >&O@" {C89wq!)0)CB0~tAI44V ~;:tSӵ# o3Iti%;EЦ}gCʛsk7Iqz&+sTAlN+Y -vj_vz6fjIΞj.[d#{ 6iohk+=S; jPWmmZ舼B6>o܇vV qGE,=j⡔+r#Ϛy';KʎCQ0#}d $ &PykZP(r@+^mrE@5㠦͜0z pBvA^A)%[:VSH LK+7+^Iw^:nz@&;x_@i{*dcWT=A_U7,AtQCD HH%9\:v Pe.LDA:i( }Ҫ6Њb7%־4ko3U‰Z1NχmmE+L;ڹ/}Kx\rv49eH"Kؙ*L=o{r(qR׈oO{M ᘎ!RņjI'v q$`SѤY=8r4jtAw7CR G:a^fFKx.K.=lG.G#&~Fhy6MCEo)TI'PsGBQ(3'Ps?wy޸ Au(I1k+1u,oD<uɽw|=n۬Wn\2Uu٪6]HK4^ '[KGG:[ ͏Qa3.Sߕw# igL"m4WHpJ-~PO ;y1vƥ7q>o3ЬHGqaq^Ŕۅ9iJsMlBrb>f$I&aLf4Ӥi kPڿ%$'Tˎn$ڐϦȦ|'/$kKpG$Ҿ`CP<'  NHXi iE!񹭵\6>uڢ1$mg'DfnWEA1<*/cC,*;ָ{LÜ԰Ӈ~{}ݴn5r'/}3x| 8 sd|X#[.520t'+,LЯ(%^L7XT4ǎc)(Ns^y-ȅs-ҫN(`&:Lp&J0Aagߎ[i1Ï6jirDƕ %s)W.AER~U+ri)%gYOqL&K&:| XJa^pt0z(-@ Rs>jtډ- Ixn#0`\#ө] +eܐRyͧ1~&b"4_/p yNZ *Tep&ڈ; ւDVd `k!/@Ғ͢$}cmBX226Q<8O13?#2*%&`>sJ-Ppkry_,NѱècU[=m!9jɇS`4:&?r,6>+5SV'%tҽaqj>=1MQf&jœXz-mr\ZJ{J>{NI u}8 A.n" 1R~6ǪF+ƨX ^*]j'SSs <u/:Ö$k3kMF-AIsr"L&AY 9b n U |aV(\(ZR"LmO0arُai*̟Hea$6mm Ql. ͤ,1頕 Jz-euE%R7Ԑۢ'8c >صL0\ؼ0!ytOWG脿!(-ĬA+-P8p5YgcVL i V*ucC$S'tIԆO̗vuƱ^q(%! RO!CkUa5:PMubvQڃ0[<@`l F2xOs:ou]D}W9z n4ON*gCv=φFbAF`ϭֱ!/V0oq,P7DN{ PV4C%:7Ŷ/Fjfs ~HC_SrO@ >\O"/ZŬﯓV%CT'FPh 6O³ mͨSTu hoJ,'S L,Jm>3zjOSC/}U LJ$ 8Pxm4VƋ[m(qk:~a 9^L0KuB݁5W[tSRo?rE5R~Wp V_% { \Qh:Bmd_B1->B3$t8/8$PaFҮhϫu! 2BMx%#$ɓp#Qx5tt܋1Z0~P^U E°k+3Dhq1GZj%QQۗTyMP>1SB D9, 6 ;MBl}/9_B^\ Q{"7e|/Y /,헻W^׏;ڝ_px?Oa==_o>?Z_w{^|"{ej 7jA'n~uC]~-/|Yᚶ`W;s~~a!nqOK'PYXKk|]_αWrfCׄگ7"WHa|'iϟZ̮}lq,]ak!.<<|ݲHkP7+`n鬠;?nΈNh|Y`@Vcʯ0O7p-J87׿Ϳޛ+Hw7@;d}Bgv~DDW{:+1Vq= kO87{>$J{us 4g35!ylvy O 3qZne_ܽ7ɘn?WƄoX 0 y|jpv񁶺f~x7f[0;>BqBB}TR^倐c~!3~b5H g7LII%cbJٳȴ*kEk l<:YSQ&$6X,%tւ!"bó@ ,p~q(ogcCj|WhkKu6IG|_ IiM(ȏؒ5ҷFҩANJoPI3Oc/dwѸ l L~R}R 9G'i^>xie2p8W%lfQoL2_P WT-PݒjwH^6[#]ID EGy~x">X}\ryO $t<}AWB{NSDbф {K  ;r#SFކ&Z|3%YS66ֽ+rlx~DR)]2au\2x,Rb lCei:Sj?/P03Ngo>?̯N[SN@".7:XH r޼psAvW) |6"ᓃ>!F5mZ{f#d[-_Vx*_?/cfsXN6"XֿOB̅]uG'\s\peIpȷ8qG2˓K4&1gfcJLJ@2|9c:ЁembRL*A$MHY[:Dz?2&l;hƈD.gkj,~ku2㗛8 \F$ f-MqG uq>t%| E*@jS<,?nA0^^U6YnyMh~]>ʋM-q;mxZ]w۶}.VZk$:_m}{:xMN pMhEHQNY3/X$pp>/ίg,_*\LIe7+wѭQpͶUP]]Vz+53FFԥZʨkUi<ˮu]YtӒ;SƴTV ƫzMP\{k͆-G܋W)BZvKa{k4%'64ڭjZwgKo!-wkrC 99>Ω/yAU[UZZ;%PZjy\ ṫbQŊ$Zխv`tO= +lヵjXQh>^ZW¤V@CC _tY[S ΀_ oZSʦWUn=uAΎ Edd@pв"i{WP2Zhk{q:uW.|ΒYT]fe$y? ,z1#[i_IB JK`r[O\DC >}(Hjuo%E!0`=1Z\*QX`#5 ?Q) oam^Ei!)Cr̤Kuv O(JSs#Umi@#AΏxum3PL陚3ڽ\7jG2o~oz{8@>l%5]yxr>c3otDiA5kԆ,D2y` |dԴ ; )RaL艷4RZxLRC5-?jrmtMr`B(y#mv ,/ Tnm?DHF^.n5ݙ%o؋b6w pKiYsTw*ELsÂ6 LЦ5w!ӹTj..MĻQ<cޭIr>] KV.ʓ̭1%&Jg$y\Hv'ȍM?D .c #ɲ;}*C$K&Jæ8R134bDb8`QHYldnM#3nYŰW/Sڝ-J ~m η~6+6H2A?2Mc7Mqx!(XXXAP"8nTRy,ѿRѰVy (%ԙRV`7'։߄SYҋ[dw.eօ|GFo1d}%Nĸa+Fƺ:h(HMc`fQvk&{Wո cVc!#)ɮ+6:t 1b; >PR~h QwN9z f)s<ΪN߾<p8*Hj!BمNn<=.rm?u lZ!B6'NӒ3K+=Y-we^ u උsT1 =V Bľ'i#|!vA#u0Ey0v=CmU\ȘmWFfXz~h$ma_lN< 'g?lJW"aW\.rr?EQK[ ^i_dIc@gwQ3)shȓ' 1m`2 j~,)}thz]*5U\|h\;L<>](Tzd`a4H"}ͻ:t*9s*)lƨ(Mcj݅M%8,{TCm8g!SubjZ[_-'P[/ISڎu]kT6j][cnZW/evc>çKYz*)oN`14kh\f,dFb2b\7peN=?LZE墣y?>zo|-gw <4zYFt" 6@+(#(<~ ?̿>>YNfqs7jv`sƫLuvQiJw8~W,Lxcjfd' >72q߈!aTdM75K#Mb{3|4v>pң]gsȍB+ݼsm BlFZNO? ?{d:}oFft[S>SC卞2mHz"b:UDrΞpgJ'=8 9ݟ?kp.| 0[v:KnB^NȄhaبa&LhS] FTh oP[Ts^+B Ţl2N:YK# ]ӷ@3`;`{hmcLѦqp#A_DGѣRMLSw? $8@>'qK"h?8SdO^: ~vZl̥Tkdd|R <s0Ty..ȷBO熻b\&Lcr|`t,bƎ+p'GrT .d:՗\5I\MkC>Ym=B8,y7#K $"% g* + &[E%}0z!<TG +~r[*  _OI+o%'xsr%+/m2$`ݠ[ė>o^i];/],͡8/j3b&Kgx?KO變~0Ozi~D^>fC#(T։nX$R#jR~ $o&cr2nXm;j8}?m-Q!C NWJ4egzoNrIC}{ Ca.2UJ/Br=A<- X`464Q:h߂OID?T߅Y>xCˏ{ﮭֽuZ:ֺid I !wt!+E%DY%+I(O{z=_gpH# ~[yy<<>}Z/P;{]{h OWw/'kF)++3bnVWrrr a,=|= o3 ͍ "<}$1X~dk} Fۚ5toܧ6n^2LL-\n̠POOg>'wO_77{c3{e (l ܢwsR]DWǝF{}=<ή4 M[wӦuzFv.>.>4_o_.n.^t/ݎ f*UPڑpv3üަf9 1~Aklḽɺ FHuqpp,?su}`Kk*ɗں{Sn~~O)vnζzzFcr++koovffnn.]#o::V!g:<<,IxҒL&{SwitgGG'Oo&@M,\]]mmD"LO߀HvL&-<8Ng٫]=|uU6XYY1 @ ` X$"kR #1K@[N/T|t3{޽Q,|{1T6mkrT Un*~Tdo^}9fC`\Iҍ8zЕ[v0}_t~}H s$`nM}qgLUX$C;x$j\`V1=aJݙhz]-̽#ﴍ__w 60UI9IHaO]W~"YU{SGO5OCX,'^ܪ{72NXM(y'E#+cxJoxFDͬdݮ36>,{,[90 @yD.6+E6m&o*m$E'yXZfQjdDDzj}o5yG&ww#Lrr_Cի)朤DP9">P^LNX|{qMVإ 31⢊YA%$4`L 5v;aU\_%t_oqTbOpf)ڪIL`R1K ޴!+i.wlX^3]EvE7ְfT|Ofv-]!yd#N)=Lt4ȿ_?8ɏv]c upu138FA-Ӣc><)Q!Zh)PIyTM͗{D m9\,BYhs0.x rY7.GX{G~Ew83jlo9W%:0폙J}:s?a9M/TdbǷ}TZSa]׻{3G;7inձCMճS F ^DKLFy藇 ,xM+,&<1 !*:ru@cAl-ʪ-6|z[鯃LX@]0Q/&BJ!^{E~ VZQ6 Ƌ~dOdVt|-Gmi;q1 `1~*H"drdoo'\mb>& ojvmL,R:&!kƗ*:j7cW޸'Hb |d]8Aҡnfz˚w$@k'ᄑPx!]w(k~QT3ӯ(U4-GҊs: YMFv9ТH{p1mb-p[|:Υ;8LVݚjߠU4WNT~1STc7kFOP4TjĖ ׍mdUG0ʈV\ qLW ,=|aux90-e%Orj;~#?ta|+uPt?c?>>hXYO ier5WBQtƴ,g?Wɒ m@k:U 1Q.􉃥nrC͵( }PcɪcՎ[-*- BFBv+a˝s*nQmIzF: T+y7U? `lBQI?ꇖcwfsRQףnrGL_U0벊((ԫט)͢ZJ~d˹a"gqJ~hPMVO?( W7F=Ҥɯ4NmqC>v ޻;Y$Hs'q3(yPſho0Oʓ]?E"ִZz*ЊB>(q90qr'rDҞ5"rM2{Xmm\`Q#ќ0p)`Z:߃{~i{C׻'-L&t %sy}4.3Y:Y[5g yjkBBbCCac%cw+JʁAQ#bI a#[zfڗoK9DW|$JDnw/s9Oe4g#'MHI*kE˞e|$PHud i(n?1QPŢ:)v2Du kv,tZ[A:,M >`p$iY;𣩓'jCH"KwI*Q1&)vi&' Z\%IUpdi|:O37IB 8h'۷ 7dJ$ӥ&? qP>3g.jSӧ#smUGDmĪ*v7X' ZNa&ZSrВpXґ5{=HPz;Pd>QW V(ߢ\D!W2-d,\d Z$M>^jQ-8[$ ( 1327XD)A,:@$Zf9a=k ܁"tJVPSTY8aj+qՁXGHPs r<TÈP dH-|Pjavԯ;Ooe<\tQuy撪juYS,Gz*.pTlM-jʪƪ3[3<υj4i-6hJX$}tWXr-!B|BJn76X =HHi-Bt.U)U([ 㜥ohckQj~j5Mן_BgwW.WjMP1'KǓ$6hR3!٤"oQ*of!sERFF}\ ;_~ FnEJVZ&>IWSk4*jZm{JE Zm} \fHo[#C*P);4ErvfΛ.('v@fvP`n/n-Х*EEX8X!'t%)~@|నF( p^#2|)'в`EH LHH&A9sG`ETЌV$,Zf"H/DI]XA&[: [D%T ߃pe^ކt%ee:O6e]nbpw!9Q[z]}uj' GfP4 ~cH]90DWE!Ću0_2rxhbukF}6Uas[cl4dcb*$@awx%@iBۂ{dBg_ `j㯦gÝe;D) ةj@B-HT0$ԜXR=2 DY`YnPs p랆B+GO6!j\>է{FoaJ`*`TxdĀSYc6wpzSq.p?=xQ3RJ[wb㲤ʏٸI$Cä/{{h&xmDɠ=x6 ؤ<1 ^7XIG,gQ :pF܃KTĒp}9s2:ApB#7:Fc@}Eydd&p"T[~?G^z{SG߿PyGx ,bYkWJ|BlKlʉA3#O 4d$,0 0}Zoͪ| =/bee`i42 q<{PQLhuz'k? |,up205-(߆{0n6Tvosdc`V*ȝ z|w]\l:O2 ]ɖ`w0nh 'a[0*rǯ݅/Ⱥ hj_F~]&w+{SF+GM]BNoCgi\:w@Bo'zL=Y9#nv=}E|Nz:>x-2_ZKh)p\p)lzIRDUR&R#YC|o1*BXdyw&189S'?m+zH0Bn! B@AERU({ xq Pr_|ѸdE5E,aĝlW~%>JUw&0W58 * p5i,U#d޷{w:<$SsUTo9se6-R[a GP[4FXgyq7C11Fʱe5)Hg7i=ζa4QrOɍKZ5?j@(HZZl_er_dOܿK[ 7/9m?~9]>zjw{OJWk>Iʀ^;,I;]r~1gZx2Vv;FW 61UrͣR<"x c]#.aSB{BugZqDarT[OH|o꾳%cx A|F5?8xɂzyf6]ޓ:%rqJ$;;;4FB#zrSz z,LeVϟ1x):wA1wiP;&^bB_ _oѝc[:m$1Z#Y$RӲvQ%8-y)+cY-l bc%i PQځx^*4TZA8G=586}Q@Bm vQikm-r6&ζYjcbs3jbULaJt ƆzsE =. z[WR~AZ[+yAC&8hn;ζ[Nɴލ6N}oSKpx&dlGO6kJ =)1~KX܊]2)o&otuT_<Hg+lIŤ6gWq z>9~P:t2htLl+O#i9 Pzo)0fA4}q2p5O8 ni,kJoN7):yu$T WJPS)ܚ*mwC;gnGIEf^S-mYe3_)AƲIOf6 /㯝kU#;)֗Ø\˯jG14HG{Wntv zG;ߐν1n%:;ګNվ0 k'H@D%2 IWdjW%0aR B H,)c{ oPٍqiH??0)t c " xz|L\큄0U@UWJ˃՚Nl*Wn߄{h#%KWH`=~,hQ7qmo("OL9(QinD|j̆ʖRY7.Is}(Jb nF#lZC7"F^OX!Z\C`i]KEvدto ќ}kR#k[K{1Źw5MI(WWa|W >uc[6CHMalw~ˠ"g2{tUËnuڀR?kX~[`TLIj "ڭ@ Z#gU qH@6'p쨓& Gm"Ih>1 zywbyaoЕqB̾?x\ *ҼMU=bfDTw3G3y4UP,auʅtǴ_U n.$EOKI)%"4J"edqmXn>&h EUҝw[Y;DHc*j[H/p2@` QVpM9؈fB߬>u@~Ba8gKAXH3Ts$7< X&pMȍ:٧(N)/8wL xŝ?\`V)i1L.[#Fx0*+yt阍@dȕ b麹"P@iUzG Ԑ ԍդn}2MfR(H)!C9$~5,:MLAL'nHKt9%%Xʨ.0(ZܖrUMi XM)#ySʖίq+mb-էtY !w&/G4W k?޴Kq5UH]Hz` X ЯǞKr j}`7B"W+.˰*k5 Xw$d6 A,=/ /09 95>k7ro_r@lwNR䱤} {')#o_Y5#8eO>ꍃ!W% ;P +#wך )S@~P o~?\lF ȭ 2t2o0-a d_2et0F\]UcNÖ 6^V0ʸ&Rن+S9wղ @I7 >"'bYX WGO%< ;޼Rc?>$ S;8e{6[qMN@2օ]{mw! y(eRSYZZ 2PpU״DyGE':s{K&Bi< 57z}4>{c:ZjҲ\@Yi`^gaT sT-:m7o4UvyVO_AW'A('vA^HDu 0\G3Mg)1܆)UH0M M {*M7*> {'U_,9Y R̙&B5cEL? 7Wf0wWl{3@8ARպq[Nr+ꄿӾF` s%稫eE%o@c۫/F֫N43rl 8!ctYbLo 2,ך].E8;RC^bkf)mB/+?##|01Z v\@g}T\XIFR>U^><׉d9.GuIo[丣wß/STTkcֹӒ7mhN(bKCE/ nu9rj>90fsCf^3("EotI-tfЄNiqU, T`6|CT]8dk j%p2c_p ʋKi܂9[piMFc V4{לxXoa3طiZ<5nCRf Yr: P=KYcj B=2OP1A60P{YhZ.*0Ni›M򲹞.8uQ?.@ubSH{_19Gi*(0Q(} ῷ'nO$p#9HAh]BHHX94k *@=P$0#S:^;!q0.[4%`鹑D%l]&я,@\IPI7/ߺ>d}_Ys vezE~"S;Ovߗz̏*S#e%<`޳.F[M]7>1#L-ndWmfm9l(z7vsˎ8+m"=zh (1*.l#,`R9вdd0Y}=Th]ާGr>-]cM e uLy/(ʋnڨ\> FW8]}pd{{r֚8oFk>Of4^˙Uy-=,LB#j˃5L9u\:MCU1|L2:=WrDGr cP X0WFL)->;.{NwV?IK^jW:R3Qd|E+efE[6Ʒ ̺u[䪮'Bȸdgf%Y[+:NʟCW įӉ9Om; )#}l5,D6{5'sn( ޡc7u+n^?!ޙw * p&@tq?b] RɌm17)-4UjÁi'51 ɲ#J!~Ž17[\ר"w1xX1. CcY@OrJ ْOamյ^c-ܡ) Y>&AGK 2 ;z7TC0K"i _칶k{dpg`-EW4)B$!C!7Ӧ5$P30p]gL (tH-V~=L_O'p,ZS@TS5)<{eֶrSAŁj>AM ܪ]23 Tɜ<j"[ io \ 0 -0,NHX:rsa/o\v>=v}Ud+8@MpK(ӎ~‚~4*[.´SdL#X \sE,u`n`kw~#ێV|zgCo;=nV0 P)|tz>bw~||1>FDpĦaEq }je6`Y/6),+:;2Ӛl&"yxX,e КC-"z8I.oxPk8e&ZipDM_QgD(%8CY׫-?^;b{>5"svܒ7OۼkcsuIQ8daj.罩THEkߜ]}%ZP _o칷vLfl閳+ϚwC' <4ny1;g%ȳg{`q=WjIFqm~8`x>Z3:{vg̢xfgZ-6^Z6Rhg[otZ'qԿn'fD3 0]oOʌ6K["*s a9~rl'D=$Hqw[FaJd?:IJ+Lb-7{dbѺ.FC:%"hNЭ$Vεj ?'m 0Slu Ze ?X~WsљfmA>%|;#@| F7z9|C|ђ=2OCW-蘭کT$[[+K]Q GC|ThdB0D%fY\c/n:&RUW9(17Ÿ$ƽ'/滍qU7<1bfbuqU0z !uŽ\?+CoZA(ɂ ho"I0A-e'IhA|qbǻ11d(aRUlz04XgFl_#:m$1(r<>ڂb 9y/jYgL/er~.e0 '_Ӱ'QxN?&ğC+\P2 kgdTJ0pu ୸*NN7 Qr 4=V 9e| KWWXڗy)Fo]|_ O6X%ؠ] o SEغ . Se#MbĠǣΌUD`!Dh6:@HH_0 1%ϫF#u-hҗ=O#■o,kӞx{C'6Lkp$ {=J)= +x|ԝ;(܍_[F.|rG``>/;\TCMj ti)_.qy\P`Mi}86:qn+^Z9|9Q.4c`_ Z{SJ\g Q`(D^*+xo:Ӕc D_=zm{s2Q}hA`KcT/rb'51 ݺ`.$ Hr:agy~/^=sc<=Q䤭Nj2Q#>DF-˷Z;/"nX%t?Q>dH@rH?yʀH~2%F#H>hqP L{^6THQQXm,OMƧLݶ!=dlcF;-h>h$cHfR0Ѣj+^݉+(Ј/|!*;")+m<<Bl"FOֆ>F&U_0.}ߟ.cгSܫs 17Ezvk¯g#w]  bVnPRD̍+k8$@Uv0pOۍY)'\ʠiٖf}&3#[ߣRk7Lf1<޼-gj0kӖM3FF!;ڌ@P u/A5($(FᏖ:3wtXW>͈w]4'ĶrC݈;{<jG$?fJ6wVOޘ#5\yu@L7R(9D1 :{jOʂfjsgfӜ7r3msE9$$M I6jIJZ5åÕ?6l4ofDQ.3:`/O0G1$!Իń3˹W%Se?$e17P{')Tw`iT5ܛR,/"st)?g>)>=oG >>tVsC\82$?nqTKA_>`h$?7D&|; OX{k mwY;5u.IoEN&)g慮;\Hگ|YH#{۬]#iz .`B(`.^r# S\*b6hkDL&{-Yih.*70 ﷮Yi[cDU^uǪ,ݗD}uSD@W4or sV[*#տGfKp?f- UW uj.mFn54YbAЦ:<EWt}Ir>Oz:2t/Z)XTd('/ɒ/  -&ҝM ʍ07iv"){AH+xx"b߿#8Rޭɏ<]=}cl:=P}cM1k wL<@T"O+ G r; c-7.qTBEVSP~aD/: ~w6BȎ2Wv!!ƥb_~i߹Ѓ.6Ɗ+I[ol2܎PDX/cG'TJ*gcugYU*"Z@ٻA{UNTrIK޳&JV[Ȑ/½7q8~Ug%n :U:P‡ 6X8LWMkJߠJ-AeKs-7*=a0`ܯq|w}u*xă/@{"?G̖p7e/aBB.@jׅ2Ӈ~ى}z`T0Jt?#|pg2>d!#Հieg@{I՛T_{xL"YOi_ufV<} %@1vt҂F@(ÓLc8/MVtݮ ;٨:crOƪ Ӵ`2kLWU5IHx(QC;ǰ~jxQ;l)Wׄ S6NV1OKATnѭe^g^g4Ư)FUaFbZm'ƍ~7~){a@=\i -LM+)BhT /|-`Q!^ʘW~m%㡫^~ LLazTSZkNDfi4UD [{z0C˫T7G'eee>6G}8u$Q51(M;>kM^.8 i" 4 {eE7-'m}]~dw_?a.C01q()hXbg)I{p+H{=/!3Tr.c+f s`WOsb@wծ ?(2|? B[aLp ľ{EmԟSL0/Pϱ0r\m9P1~q.&`8B3?BFo3yJUr8x5RU&|j `E7`J:<` hPqTw>x G{)Q 'P-0c7j5hlefyOzT-6ةtPs_Mu,~-O;03FO6QM0lc :aL% 2ho,6ȜCgM3T ے7^5O}]A.IWԄrWQNiW"Fͩ^C'oxGb r -MQOwQɅ2_*1_\^/l|jp$Agum[nA}PfVF#uӟ_$H2Ԏa'|kI&$}RQ lVK'i2  s 8)_]pdDs [FuI::]j8)xWFȌsnrڇ{i֠LCF/ \6[pbBtHQ!9%0Gn&N*fR _jʙ@ii>d;e7`_W*h~Fʲu/G(%̒Llܩ䊘S9P6/fI=v6P%#oSǧ4LgFT1O#@;+6PSx~a3ʈLL <|Ojae2pچ ּpSo7kS'IJ-5Ċnw)M^d jx(+B|AA|js%BQr6}tׁjvIH$yk<{U&Th|W9ѽpJ5|CR/MPoK Qw>$'LjLؠWx$Vp 2鴋!{/ >>mxI9bd?^=UF;:NES %G2aGgw n0 4A@ϵYiL`=сClukh;?[߲^o W r!ZZ ᱎvuۑN"oLxmī@ %N|ap.*)dot#%lv fMI'RxZ]ɹ)&{ 2@Tu1E] 96ev?73G<*q?J}Qjb`+(CȘ uI@Q{v<1 H'_U0"L.W,x(s#G9H&g"_XdReb񐒎Ĭ Q eLN\8:@eB_Yg=1JӞuKWmDc:s\h#Y2 1~lK<3Θ-gZkYÞ?+HKڒ{wki~Z_5)-|}&h*|Ki9'/ÕC{Q`(~u3S!zL&Z*O!) h;QjM$ CXJ&ے '$t 11X :oe5H>R7/(W96I#٦xӧ(S6C|X"ֆ_f+E}?9=}9) igھL1]Fz'kyt Yq?UX‚vcH7$c~޺ ״bn 6g*z {?>N.*kze'pb{J3 l&+<dښZAj>IhvT{{۹u/~s#Y=,V}M=zWT^A!)Dz:@~$zۉpE)M\G]Effp\ %FV6MW1'nвޱ7S58~L{K`̜`;Yzj=R8w';a+?nqeQʸfgΚyU$ mU ;L3JJxIccy2@p4rxgP,+=>bjCU/z{Z|>&/Ѕ 2%aH \3nv6jf2v_εqo%fFM\2NAp|X0U(QA$Gs# 2 EZsE~q53C}a>6 )ߨ4 Q0/M:0e杰XPj\  qW. *G5ϳmqKU C+M}Zj8;XHGߣj5<~6,:=Dùv9a$=2UjlH6pp6VI׺!i#dnW* 3;%5/LNb9 Lptc .HcgFx̅:m:B[6htFF/&z?"z(Q3M"v!\ -< adY+.Ϻ;2gz҄h RGJк!.ȇKyE,V.XCuWg€Z2t/{gYҚhXMU$qZQw ^SGYn2 LK OT}=Br-k hG&r1.|Uon6&X ߚd\p0yOO>ryEڐ.=H 8酑a{oh+`τw D͹^䫀KH:qdPc$hM` 2&F(d# "+!YJe=5 /nkq{:›E/]swrNra[/I:oL!օX7s{'+Zo|58, wf~%AϜ1/e \0R 6}M m^M8M),n7~|)ݏ %YbA;+SCr3fK6R?>pe/tRziK4{EjKb0m+:_i]jH8UUdG^XA11=G27 $L`ʄ?D;%38D^Vr%vۤ+Eo@}&< "e6oo9(N*q+1\j[f0<_)6/ (^c*tojRtn^\D2u}xhN>8_jČݒb*(%!''51Aب&>c.:c 8.yDA߈q֌~AG{p}{(rQP_kvY7-J?n Gi`tS|d~懷˖\Aqa44x=/y6H)xL9nNQ#)#9edǏVi/&:|K u-c$*x_pS_<H,L7~*Ӝ~ mou4HrwP95Gn nq]6b_(M4 [u1gʀoOQv* X R[8aOջ'Z+8=4[Ժf0|rÖod~W >\gG~o'tq_<#4au[($<ҽ/^=Cm ͩtcNί|6fS>z[E}?cDB s>#y[uHg:}rճ߇,] K9ăFߕZwPB~ʼn ˥Oÿl qܷ ~r~WV7MJR=?ڙlЃ{ϛuܾys>>$~Lȿ @nE~^>2x m~Pƻ`[ ˃iAnT>*잼8^,|ė(q̱,An.Fpܺ`ĮMm:枍.^lAڸSrhΊ߶G{/(K#GOoVOn{bjXiFXtª&!jV_3 /m{ŔDyS>nk4p`˹kK=2*# "ᜁ%#+`pH"CF?/O2cz^^ocl%+ -E x/tEȥ'Q~754^ XkkgxA K(u1Ֆ=>q";\Y-6|zb?+=5Iߜ}#؊?/{Vl ?Ԯ%|]xUł /ϙA@1@}jt*h#atrs.FS"H=c(QݜSw7K! %Nd&*lbN,EX7w.B f-E,aq+qTFSV}2I0O ͶFn ol薦;[0/}XR\-*ƚο'W9!En݊ǙHc#$RȸOSR+75Tbz&F0jPknI)s4Dme7]l)w\R K4}c?PT0zˢ-RV'b?T2!Ci6Z X34TCOZ]ۨYT[XMr,U&2sIެ gjaIvN9򰛯D^4@k y$sy.BcslksՏ&# cJc~@O6Uͤ2/@sj|J7I:蚯Ԫw[ΟDF0.)W/T [ӡYf I9"2 3bT'Nn5FRetѸ0QJtT{Zw"]Wiax/dNRbbn7²725 "wLV „YҰ/|T- TqHT.a~J8)RӨ9cm]Mm%|j]a ֪&Y{.[Kg^Y@O540%M?|TZv"K _ ƨqS,p>T&J^qԯ\dZS?8tlRU(#jXWDINBצC abs64q+cNj֙5{GwflXxv&O?*{![g4[v8 ҶLYڝ)M[v[uctf-AtY;. y +[MӺ wª ;mQJ\t*wB]~1Si %EkS}y0Mg>Q Q)7i ^SĝR[%n)2J ;΀@q~e&?2Byv0!I7)ީ2u0-Kh;z'7}/ ^Aɯ![0e fm )h ij(m^S&T6:piD`='um=ι x%Q3aUM}|p`S+-vsKnƔص<ҶNW3\g9D]+=B<&O$%޸"5_Lrb c~[Z (@Y-|$NxZ;j <@}`lPhtrQ7y`⊰Dye"jȜF";3gi@d, uDw[@4"8'.x}$aN*t(bMO&0$VRVLt^/ۯI" L_G雟Ð&s-Nxb· #V{ &2A{WoU}k:Ok֮ӒpR"Q }UZDBAd fEQ`EJ(bW6Eն3^^s]_dʭ4GeJ(۠P BXaw>IM)u8.T0HIr8vN1QZ#C GP m^(m`Ry##7 zG$D.nWBZ% PҐfI2Ro6yN 3zt@-|{kf YD -Dm?E&/[ ǎ^zkOEW&a}xfsTޢ GuG&Rgg&Sy8DIE.bnpEP&xܰ`@+r3 2ڀlQ7\)*Ѿ[{՝n8J4̀K Mk9%&QbctV=rT,P!PF0H;pvQۜSY ǒ4HoNF~e R-A_e?L ;;a O P8F5d:rtnu^Ü3W5NEϕCr^םoZLĜ vU6Wx m]C"&dC%W~N)wA栗v_`=~fA4/&ax*`[ 2z$3# TJ+J{ { Znm :Cs#… `Ij|ȠÜPBW<̬D_m/tIF"RvTPj ЏA[GeD:( j=_L-&J 9E[\ďw!P^6pFhA?zޓ77+- Y5ҍKnPqHI 5<sBS<"\}?PxzX|p$u]I}8jOaW#://V|W,Y%WUQJz ($uc%,9Vk!ӣ7D$L@zaeDtX5t c Z" xН 5ʟ&DqnW$yo$ҍ(gAӆ1Lѧvs-jGJymN}iZȅ `Hf&g[ʆO1tX?,.=[k Y~?$2˛/ç Ӵ %iI!GA "7,o@t1 \G4nw|RaЩy^/6]KPݝ=P 9{^XpjLeN /7wMˇ sEkW tv7@(qrI#zD2x w4'fL5p0ѹTA-mNnYNR ;e:y#%swMuP޹. h$ҡNɆV,Y ӷ_>{puۈ"UȄ /1jK3,jYfi$Gk3q@ˊ裂Ɯr k0N"م8?5)XhlX{|{6թdgԆnCwǝIik(!@YcQ-#qX$}]:0 W\z,ؐZ)c,R>i/@:<_V^G"Ӧ^?Ψ]r$Y*` h wx9U›#V(TOH kyx%h HE(rؔ!H(YIJd.80tbs m՟ e&Mt \ڜ]'n}lcsG߻ߩۮz+$9?<09y|>mNslIh·$$$6s $՜ϒNNYcI9J==y?pz\n뢇tf4">RCY8 { #X!$/ p`ء\}~l(. v*u\Q?MUbO n+xÎ~?zͥ_@KK{AKI40Ϧ )y_ʼ0LΉ,+] mk?<F g7$C:B̢p(=V7KiXۙfgh} ԌO#C/ƦE-Hoá)3EdT1ҬgJ_:?5?8M ex>Z`Mr.cr5빁o_-UW}'sS{D&RѸBi[y[';"n]r@Wj_ oQ~'2l=oeb6V렄t3xO:Ga&4IfI*'|uOR:ޥ TK>HgKÖ\s$wJp-i"q~$ Cy+e"tv)-BB6d#2n!$*l_Rqav4b_kkeg}bgMnw;?\GN.?v6mM4J> ڨ ipkH!B j[9Ia&3iK>XJ)w̓z \\UDx&* v/Z739q.RŸѹ:6 (R p5 &R2!bmIъ|yDdE]["*6LiǤ/@B=3}F HB8⼱`!& P-B 0FLq+$%̟KᨒdA>J<'|,z$-?S;=7;\ޏ1ָ3- DvҢpt6P;G7hN8#~c_keL4rw,! 6\)o ӫَ#ߊQ^1z#+"\p\90h6M2B5YyvMu{X=oO K3&UbHsL~S=Y!~´J'Z"sIl kLK(4K!*Vx+}TTM(A{8BLZ *1K5i{`i.hR;Y-N6Jo_ih*W9mb93@Oa$#rSEՔa(7SVL59GDBU ˳ k3e2 }y m* 1yZӢڏz=G; y8ȍ6>µimW*o3JSpΒj4Tdt $eam!ys$^7k.ڐ81AֵȘ X왟I[c)~$( *^ Ui-j &W \xhO̶j)+MyG{PwFmbjjSu6=Heje|ژGqq\a$Ah.C\Q᡽s9"e)KqhecI!"ply>LsوDxs0 6\g䉴7,We zK 7 ibbUsV07*dinEhHƸt@6[aLa1!^\%rTqpZɠV]ͱ9bN1C/㈯0bދ{]&:we0t\3(dGNEU`3: @|]J堶'J܅ z<: 9~Dx2ne~ [<'G(9ōܧioU\tد0B{+J1,"И"3vhӎB3 Z뺪"cJ}[jϝmao]mړ4$c#5z 5ͤCzj矞y]H|S e!nGnP&us+-9%FCG[]D(ɳ}e@R 6KƹͪAxґLsY2i/x)@G Brm.ï98`?Uc-AKW(TIŃ'$:TH}bu9df<#tlHXFxƇBP\ ȡAwrmYά0_)9k1o͑e؃fqY5Sdcقa1KTV)*}mZCWIcr SvU ZdQ$ɗ_^| (]o,@nt ?=69٧vKޖ{9 ^Z< *j!~$%c~oYO_ ~^oD] =k6-F3 u@=0,y}"̀U-׳h.ý&+SH;~r'3d /+0vڻw4AYuQer A|TTdY,X1оH &/B Dƞ|$CR ;5סVy6(Fyl$*-7PR[p%[Pc =y(~5v(l]JJ]y"i"6Qmjj#?=7\ήԙM9 1{Qi.ÿD51`LUJB V}jl8.5 X19B !2֐95APS^/~[T m;c? aH# T_xWDFߒZY5>C3# i4sQt+]GguEz"V.P6HQQ[/YT~Nݞ!ϬvQ%S޹FO>>w 1[Q${\ݗkU=v)p=oYG} )X%dgEZFj,Gd`TI삭OXqL.=3acˎ^ƱoHt2J8Z.OzD췘S W2~٥@OGu3c_S/xy}c%tLK譨t؆05.x%jU[Q4FMs@V>Vs1v!Qkǯ([sloHD/8$9al0 o9QU{+qhO ۝UM9Ն}"Ts0ojo !_l0j§I7ub:땍;篆oo}mYUh.9vdMVڶRּ9m.JV+`U鉯kۺ|κZD|:U}6n+'>B؅> w֯z FK;qlZV;AC68źQyDb%c@א>峨h8!cV{7)4~Ky {NS[s!,fkԊ GJ›1I#m}EJ2NF? |ԭk_F</M9}ϊF&ݕ*tZe+P=M]I0/ {@"*;S$1(s]W3aN"?:űw[j]謩RVyDW8؂#QN{lO.UN ^55o}rU L_ 3M  3GT, 6APk{=:7ܦ%Oz~ Z@z~3=&ߜ5ռ,FL||e^n#5(ιNTbͪĭsQC5{7)3HQMaޟkcȷ$K:Idq,!uānE ]x{oqsϭ}WNg;*JO]hDɐ7 Mm}X0PY &*+-z{UE/`.Ш'?;vWc_2?9<2%[q'tbf1ڻi:->zBO˻z/$nvc5E;M0˝:7]#nL K*o7=WCxȰئIR{伹vuvE5w|9q۴X. 4H(nx>VӤӸ2T/]c[TH LSI<9GI}rS L򿬮YMTػȣsl9Wwk/>3ZtØ/bdom-H+HBC;3t`/ /&f0D^K(sdpy!bWe!=rd;3,)҄X)U %ixwOX8q;"kUXCTaNѾ;D[ eg.SUv;)'`6lZ/ J(2lIh:+L=oqc1TwZKIC#jvg-- (2uv!!tE6sL|'sT*܋+MP[]Dug;U;3Y7:.\7y+p?jׯj2Lti)8M"!̰[R yj:dCG n07jXMB把&(Nΰ2|n@~0L##Pj.]ك>Xu>KY).6wAY)QtzDvT`ӹ%gDd-t7Œ޸b%K|}%zΠ֖埻;<0=Р7v#N CS"9<v$j1[]W8]m(c{:-]~E3u׻qbN)lxgtME},u"Ow~lrŌK{?h#NK*ܹX1ӸuBԞl91(?CZ?t7 :|MV'AӲ?W'!5ixM( r "'gi[ŋ[ f0+iE=)|:W{֝Frn]{ .[xR:BsyƼjrKi8T%1dbu\y1I㊳s>g+`rɅrɷpHk8RL#4Ÿ.B!]H~9)B-KVx"Vciኲ, N nT|E^=5Yמqꜝ}ſbFh;!,FHPnpСѿF 6rXEHEyiU~>^M8q^N(j!R\ݱ/ԥD_ -SG_r^b9yt#ѷҰf(p2ZW>3TdAhcosͫg'Ҳ ]+xx`A@Hzʓ; No2wZbԺw1d~汵 _YO.ɀXPb +R?+L0v~gu/v [I"{JL wo/=:uuyHl)@=a:KnK1,T!29^xk 4cgsQ̾ R断PQy;(DeH,x1x׷x"oOcf]a.[:*3w j4B'鬋6E*򟆡*Ą7Gg x~Z+~q~x!UxsS׋:So+5k49q7? $d͗:i隀IpZTpY#)hUɇ cLHswϿlRb(D4~aFC˚/ >0u 7?"nk/%xGv%8Mt7Tm\%FaZA}SKNU!3}e ~b\9m])^G,*}ZơUd` -$BZc2kt&еJ5161'e$<<͂SF0MQi4Dzȼf=3 wإPE'(D o o8\2S K[UW*xʐǡsQكI]U1(":&Xy tbGYV+3ܬ "M=Y<$"o vr~,q?*dB-C'`̃Xu26B(q&:]%i z Ip.C:oc$[]}>Oupbb8%LNqg4)瘃|,^C_R'*|6} kYbFUn3G7Z5__ k >?7ҜNd16'[y6塢 oF`Z3 6m @aɐPe{c:vXb^Q#6 ,仞WF{LPW#ba$܍)Gi@wq] ; d|!4*8.*XQc{ط:W#*/ =a%a©N@5q?lY.23ƀ;DLJעLlgdJ79v8b5OA癲82Jiaܢ$F $ i1j쓪auT}'ƫ?f'6eHi_U%*.4$a[=h!S,;7MǓ76SPLMne J?%Y#ﱦ݉2{x݃|u"e=!|pćڃ]Q\0T_n긮wߍl6JĬW<8`WI@ o6@ۉާl vS Ƶh( g5B'/b ,_ !a Suϡ @y6Jm"g˕JDD7%vUJWY.9=ƒ6luvP rdd<ќEvO,Qx(c8(WVUb_6ĆSȸt.HR`m%?JR#1U0̎7FKͥb] ٻ zG qPk U+YV8pE%/`Dqѷ˟pQ6FḽOSWB2q b_$V L錂rE`[ EAF>y"Tc- :)9F(W܉~*Pڳ_"Tx,g@ բu% )=G[vmjOI:ޮHw0{j;g7ۢ=p1 -arc?żqˁ^U.z9.d [K*aAݽ:A~ANY!j?E3(F^eJŶ'G2rZ$^fSt+BE%țbf2Oz 30Ly: 1Ev]q"@;c.%T- '5΄+m>U|DV_6Es;~![6W7٨I RE \% `LXO^_鮩aSKACxü Ո2ޣa%A[w ïO+D{%K@vdw\bc2tcOOGDYX[wo[)9؏C/g}bu@ Jl V =0M4A35`nq[U8`~HkMՇ۰&ć c$T'UCtÃr~wڟw.6߷B_J֒wñ `wƲz#IN]$GKNChw ua6BVCx#!\S~#ud"hJ gxA=LJWs-rF#RgS{я&o] 9HEFll$n.HB#ǽ/ɿɝK[fNNGүQ`:ۮi`vL4*f1z#QePxWlV|繻=hXn:Zذ\e{w~W<ҽ̗H?F.2' H,BT>2j QW{[1t-.dvZ]&+T>K ),D;1ɥ6l?,+}nlNRVbq0xfO跭Oﶪ+J ?}{hŨwLq~mKtR${BKXEDv+ϚZqP [^vѝA*JȒ -N[.(A(Dj\^bE#PIșէbU/HBO;^)+3ziAt1Zqu8Qyk<\RA& OB;~)ܝ4X{⳦i'`jGAދgmnmW>%g>`W|h.Ef\"i~o(EˀrUcݭ'C0}{$>kݺu/]qc+*8n ꓉+Jd.c##ChMW]RyLS[ߧJ,Z~(8DpbO6d_S)_[dlj_^4î@{WϙTH0`W05ͿKyMK5ӏYcmb4(y{Fu2^{:GjGckCZv[ZG ;ikUd+Qi0G"rUivg8N;us~{ǡ\;8pLaɀYPbJ`h"d$&.:?2!&ψgg2o.qTN 4>#g);ľ}n3uo"ʇ9g*tͧtܦa3ݫ# zV*5S/ qey&b Q4eUGh<:pJ$ ' "Ϝ?~^[}ϡbLbRrAOTH V~¼R9 l"gͻYaŵ_ig.jVS;R[:8=4 y 8Fߣm{|x5xUK.X C9n'ѮK[ҷ?G! $PPCuGw"/fY_2NasݼbmsVgw\× 2ac2{y8PSk2,Ht_qTg4\<}VqwԱoG7>®`F ɬ_eNbgu2*)*;ir9)xE&u(?PXS8A>2;tњ*6 yJoީ]UޙYʿ\J+wQziW>qǜBl\GljSh+{^րIro3+!+quX.p~W3Y0PZC ,c̳B ZYS+U? +W504 /@;4^ 97_ ?AZTσZ,.J׀sxLoGݩ:ڴyMj7`/j|gLRIgPaVB?m MCHHY0 i.2Pؤl 45@7ߝr.VuC[j&Ʈǂ-TiZZU- նUF?U *y($B̯?IzG^FGdQ6M404gY#YUe{Im "ZyB+Xfþ˴]6uJڞo{0 J&PWX]J>fkjS$k`l{|jiR4/Q=lٟ.K'O2~\y<\NZ8l=|KJHp5o֢8{Zjj>Rg[5WpOf>op{ ~2!)<ZrTHݟtRY&):<&}:\#} 4qξnYDNUǟOk6Ȼw%ܗݐYpà10 1U}`e;ƸYOÞ(8߻0OhN2Hi "~U^iy C5K"%B 4&H[csxraDȣvn DW>!aO:i)/wA7|.̳tS')7Gd;q,ydk;{eO>]<[*Lکx,%#nC2tE2rȊoߛۖwEwoYO Lii )#4vc z# FjwjԚS^1 RRzZ 9nƖ%s+sMǀt0BC?x^뷭S]BmON¸nut]PZ< DP1}jd 7y|aoGc &1}dӝu#bs2HӸ͔f9"#.3ev,/H>y#s񷶹]hE,6IuE_o?]nNĜY5h[Fd?!D! t3}4s|эw$4SqC"9mV}]X2yOQBϔ0YL0J |E4.ą[XY'+L.rMHm/\T[0YcaXR. |^%o|ګ,ф=-7nа%fb#;x`جvw`-cID xἧ+cO첧xdI3mMY}G|~QP`cPbڐv=Đ15@^wKMk}N;Yvc8|c7ƫ k)`f[sHFD@ ɩ۪nq"`M.5 Jn׀K~"\UN靎`GVw k `C;P#0\2mڇiHఢÉ58GEa*m>dԨrTAhu.H)rRr`L + PCR>Rn"G̑TYbE)3W}:Vh֔C:琤G+~RRdE.Pc\2JŇp1f #V&-r|z垴QLQJU609/|JFZ"M<3D"&SPGrکY(S 6>K9F1ۄIC7sǼTUDT+V.{,L `UaK@FmF iuIEĎ&鲋,m@T %, 'GrI!>m`:P(R"mRKn)Mb*+,O I>:qѣh7.kiAki@ =?")@ (>I$@B2&3V "=Ru%`:n'щ;N>(Ɏ  姝A/={1!UJ4J}T*ba&w|W|{|W 䑧  _!޷a~) {A :c@cy{Xc7aWF0YeQ`g%Wj(i9n&βVRBpJR<ӑ49 B;9ڮTH+O)T2` A j  g{pGbq~)jvqfp™ 3I%_g 4X'%'ArYW ' ~V=G9# N5$D,&E6ĝSco,%wgaz?~ fLeW `X%4^1"zK1zeЁꘂ5h/zM ԗ %0&,G u!|^|' S"Q:d$1yS*&H=x*|#r7mZJ%ѓ3h[>@ +&Ed D J]a1IC5 b#Hh})/g> R5Xh9QyHĆ WŮ0o; t3Em "VHֳEbr hRh8X쪤˥4 ( ]< MK_Wҗ 5&0xL:*'q谿b7bӤ-qH) J`.-(!!]QDH-lƇ_QqV%U` z#҃6bpCauqЄ,S#.OnS>]D?a񴘸COIcJM` +1$Ѝ@gh N)1GĮ)QF u)L@g=.@Gr65AtaM(CT (|HP6 !zP5,`2$q:pR!mCpzө.0bh.{ ip^f] } (@jЁ oPQA@Y F?XF L?9T ǘF2vu 3BҘ90P4~죡DB XD4jh@`4@p>&w@ h/&BxC.6|C<`kxhh(B0bЮ\H@@m X;4hef_e~P`ְggi.j.\灾b&eλi>j~`Fio>g Ҟ1Y[@`8Ȅ,%\ kY B!9} yJޠ2 >cF2.cxTb cxtl1l˦˶l㈤ j Ŷ2ц }[ aMWn%FkHT@[I$P PhM-Pŗ1|MH~md[>VYAn ci=Yi[?mmf֘]S ͥW:J>@;reNxf!"Jy4 pɟej5\ \5e_ Fn|ۖ).ؑqcQ^% . o(o}A-\9ZڥM!cZ%FU@"eH1r{>/&wzT rI u }ێeӅ F ɗǃ`tI:n"7F\zlVK[O_m^P;>&U)`0%\j9Wyyceu g`q 낉cFS!qlї&oog1w Y-\%pGr.i,g-frHxlt{ ;؇\/(؇}xpaw ɍ;; (drM  rJop'q;`atMG kKo6^qz!|!V,r̋s$eX%`߇%ب_ zvau]]mF{%p{ZtPԱ]~c0_G|E0FeMV9e ~;]^i]ad.FP e FCY].S~}w{}'y0xa[{uF_;u͸x}ywF֧Ǐ $X&O댷Hr2EW$@0(9Wh̹#@յwuRrj8Ti*Ruj&vE&* _QqNN<E4Y2iF*/̿ <ՠg8ͦ$̸A1 ?~ 0 B}"h𾣎:]y=Lpf5Dj>f  A~e*OوUD6ᒡGzSq="=!-: S6bΖYt;)T뤭EpsiZy݇iqQ۩ŝQ:mbhy_S?׬ C?M-zy~~ty1ɗ5gN4" z eӅvv*I9QrK迭-;-"su m /޽WѼ]_, ŋ匦$XfalBhf$0;1:#nG&dr"PG&Y*[qeE <*XOFSy;[/?Dv4hE0<-cH/A"W*ZQQOBnNhPw<)~ȏ[yggI^Ij]~zN3BAd.MdduOaf~̏]1IG+@`2*? ha@y$LhB:Ӗ1-ӹʮL~GLk,)5E&rvAͥgalLs7Γb&~,aБzVZ<%:q?mG^MmP?J1. 0lCki&hBѤ~/A$$VL/ 3ۙ8T*JܱېMFa ‹N@hD OVֶ DH &"榕e4Klb0,"fz9= ?QC%|̴hA@q2FnjXР+#t7r2TVڮJډ3Zf(- @$r,ŽtIcY w4`eKޜG BA` TQ -T9Rs8reU~1 BY 414GܹmۗLQfD (7z\re`Ɔ?C}nG-xf%JDIv~8{`2@A)\2vgax$@&1tc/<jIa? >q?ʼמYz%u픖յ'$QTb:Mgxo笋bH4Tbkѳ!+Io QӞ;4fr8_%4zK1АTLlzKQ,iGt\Dޤo BԜd&BT8@BMfֽCf)G*$ y;hF\Rs~2Z6-V[:-i z$gDy}NliKZ"giW5`O΄U̜'Y=NU5 c7?QrK4N;,3te$2&$Gmޒ(hzT{b6F"a[Si+Xk5ݾj[wH %$E4}]_KcW5ebm^w}%jP2M ɒ`-~w74Eu56ל2N ꮩn kx-xjʆHeC,ίr\rR$+ZG|@`JżIhbk[ 6sv=ÙuL'IhlX&ZC&NSZEF#RHxo+Nd^7JӦby?|x~I?iU6k:IX%J&9Sr9?@ڈ#{_#أGLD}|siJUyl&m% o^{ņ66g.xUw'}yˣӗ_%Ҟ=>o~˯h9J77g|yӻd ~#n nݥwGobgSo||m"7r՜d1~ A=OnCK\s`4^"588#0$Fq:#w0i8l]s}*uHLxơ//}L"lb szͦ,./c딡Q` g\rFxD4hcT $SBqzT͹$ɃrX.0r{CT+, 1O=sg#;UB ݜr F`dퟞOx{40.h8ltDQ,X"W&";WJ:掞bFO_%sB Uvy:ksIؖ"#x#xcO8o}ع"s<N3;o9*DKkxQX C!3[45~\{V%jLV5uuLHo`"~mpս^S*wJ8`~7r?=:g0wFyX[5-aRk:]x ;qZu0mto? y˽XM$@v-$MXbMUw`g G\&v<&j9t#Xj$Lq`nIf͖3kcs:>Ta)Vx\>AHpap_ (ER;oRTݒ+kRG+RqZ?\<3TZhIw_aaڣ@-밤zKK(Y=@, L•)">T״Υ5 iqf"fO۩Ez' !7./T$E8/Ɉ&к_H89t%QďoӌpQ9P?dߝhxOȅYUTcz.~t~{DfFJ33sU%C?$a6qk62-.i;Ɗ$K]'|-WW2UeϋxZ. *e=\4ۦ@gATwχQ<4l!!Sh^"dei <\-Aoځ}jh6`z k=vaO{ѧ,5 CG_؏;NsfBs6BeUml*M9ZI>Qe"9Rpu@eJmY]s4)Q?b4>@F:GzcN5Q"L#3t˱쁯Dܩ?Ҭ Xu0/ZMːO3Ɓ pIZ&Ӑy&Šf:7UT9ۈtneD Dh41܅8Q0y`>5ciªw Ir n؋L4uOȦ\c7i-GER5,v~#mAOI>ø]X:_a{[BIXT@uBvWۉAʹDF' |HVv,j[iKFIsu5^}Z~٢mE3ofYyCUx|7 \fs ھ&h ?*Ii%|iR&[; D01@9B̅lmcYF[KB5ϙKDBDO46Q;A(f X}}ֈ8=\#>< lp3'T(m?4yv ϏFiDAȵ_B*>D쳊9ĵ;3VJ릩jZC2rE"p1{- "i>2uTOi{b" c,9`]r=ܹv{ᵝqKۯ,s8 P3d/,&A5b\0Eb*wXZTQtX/SwkËGz{!V'bNBLT3!O+.a5|У rjl`pR>{UmU"nFm0_&IgmmY 'nA]2YUL*E7dS)IkpI'!2E iMsI#Wr {19< O|GB)c@uBAFN%6|< my'o\єz ߇Y4>bHzO^NI¤[*1Is>Ά3zA95NAMsD> *-T4K"_$e}GMR/i3@i9F39*t؂Q>@"nc$a"Åȋ|R#p2n9Knt1#r6_"sN_>ͳu~%ug %N{۵9M 0z:8!J7R:9=1_LAHp9(+}pV`6w@mk h`tX'sbXYٲ xFXiCvqޅwh D udEh)ax`1zbv1/ZnƲk@"5w-Uc1d:s*.KBad% 9&G;ʿ;,Yo_$@cmD!`dݳ'P-8ҸٜC҇ gtMzj "}ɼ@Nyfc7 :j0HfT O UPi"+B6ު4'\|a1z>-aC0"0jE* tHH\D>;,*2jU} egoWS1#0au)`XtD 7b~]SQDisyU#SrGpeE\qA. n`XA/GrVH_W6Td:iGd )= K@H@hQiYUv]:8H'r?ޟc{rzЧ&2lEAH}Lt>E uZΝZmR-vTmdؽQXQ9I9q X.Mm8j?5r5Z9u-A[c"u`Z@ړi=Hsn9oP!)D p3  ,8dqdХ7+nU$)i)O@I(>`!v*b< ƈ4-7O'~!}]&x, h ÅlCwM%n(3چ'!s.%I,gpsו&l!-nq1;|\R !9Q'Nbh6s=GҺYΆ1WxX;t1G]IY0ol}T~Nt@Q_ )|nĽ"nrbJbqb"W%! t>?+bkfM[]ր_U O]ov]IlUsfdA+tkj{krM_ "FH*W8kI+k8* ]a pͺjciT㾴wB-So<4mֶ&Ki=-|:+Mm6É.e!2I1xnpݥ8BTQ}e*S־9T^gIH#=IuM G~3@#*&/@S k/<?N'Zy㼨*(ϩ 0@'ZŎPo4w?)gܥYZ%9{n&i;HA_/r%?q$}WF\p7tE'q\U& L})(!#&}Żaf@Og&I*g)>٣+VE@IZ2Z En\ C }Ǫӓ,_U[-3vnM$҅ק?[2%m2;:Jv7sVEMoU60\{>s`gghIYoͳ<j~K:dlPL46~|ROi-Ah`5m+H q_}Q?"I' S|v˦qE;.{)Þ9|[/Ҵc*r =g)1puǜӳd"M$ѝ-'gnBdA-v^ECǗ< }Ձ9PJZtBbsĨCO<$JoRx Qli+:.VVP&ߘo2p[BQfنڃ iYZV6#ClGįMO["\x|ɱk<|9DP!lF* ]x:,9R~fv 'M4J݁6r;-Lm-$5%e$ʵf\]]Ӏ>g1:~\)2bmg^V{_w0I9%Ѡ:{=48+ фFױ!9Ykt$dZWҹ9T)(,r4qh{]%=dK5'&a* JfBoV^Ƅ;Yljt|ڑ5T2w_% +kk`gLw$2gM\ьF\%j^sLSJc2j=T{qBE4 -/ IQTC\% V&W }hA "j/⒀%aff24scsFKsȹĤKИ!'dvNb)_ N8STa, ˒J+,LlOI/&Q'dhx a2 ͧ{G1Y'銯Hb7/rpXJqIjm3'ч.ץwr,]<$8?-2^Pc򏓍'-jI2E ?19l3e"<5)ؚLJޑ[:iva~oJNo $4 x7{}yY pPWY^<2eMn>(`\ǣ& ݯQ:gws&L--d 8={\%{+ݦ_ 2d9֙3[I@.a+Ufby+lcl>ֺ9t[%Ϥʤ-F_ֈ0,~rW htn`u#Ў U8IC*/ +RV+cb=bB_tDl\[ E!ijtER<)SLgme !(3A̧5 #p=:!o@OÂOL32!_ T#9YHUv2/tV;zK x1z`=đi*[5yCJF" IĶ8HMj=YgҥmtU;iKDHDJy|(̷8JKoMJra@!Utœt|ܕBZLY2;)ȴXh.*KjFP:xHTF0=kӐFCRun +]0JDZq*LpϦ@Ϭn2Z6&k}<[zb]}X7\=6keyRNcb,:~ۊAUTCEnrz(f+G5ϵUlCQ >k.NmUe??{Sv\lYC=5O,H5őMHUc<A%&*M@. GAD)OT<ݜ<:}橸Km:\x'JZ49 @YC 2.Ns _4rVvۭ( t'lzHE/[$/?taȕ8mR.鯹#;X"Nq0wMU4W߮Iݚn6:qNx CK[\םiл a:sb@^Hà 1h3H=| ZŒo]Ztd?!+}U:&/Ѷ``Fe YԲ7&oq#^#홮`wё1B&Y g#{Ru[Er/ZSBLK,ݽq.U؊Q{]]񲆝i:$ 2ɰs9]yTY/ kw:+{H$,K<%`Vc ozo3?QMM0,ݬzL"o"Bؚ-YZH~N5WQKW֫yuk;iޱyz<9.˧ \m_y[s_2sToSw;f'_:lIMefay=_/?\#wsn?WeHE_,ʕ:༵ͥ>P{HAo3XzѶ^]>zݽ%Uj?Os)l~^ o, 'g4eNe|b,:ʏcH%,~g37Bk^Qсj^5Z4SC. rϩai&}ڨ")풷~WE -^`]n=]Կ/==QR/V߄r:WŮ`~61u"Gf'L!h|};}J% t6Il󑐢w ].=akPdW3:wGݽ@Q;vDC߻>.;R`u(fCDn{JiZTF׆V$-DYu;60ەJ.4se:/]r6Al 89}-, 7ly`/ꚚDۗcoTDj}G~3q T8YdJ^[ZF`WVsSDa FTY^y1'C!A1A݂}'#{*&!WI҅2߹ ڲf]RՊIfpj#HWNDɠ9/WuDsok2[7{UIA!,k=LV |W7$تr2W=L:$NSʦ4w '=P|A}Wc$Nt2q` h(B;g2?Sy[V0S?8P1ٴqM yS"6`|hs-Cvz|drݽ})H'%_> ^ 0{_2so[:])9<r76q΋{HBZ5&{ $r}ǖ#Oh۵TR%59W\h;isp3UQ.>vv_O%ʋ8KQS3ܬ a0D W|U5mҩfّ+̅O #;8'0hi  9fq_BB?I\Cq< Gܢ\ "!4Q]!b8"[ڍ Y{֚ub Ry@qv־[09 GQR!Cɨd1WB5?yq5X(mL;>f+`/YKt0/qU]CԺ2Bs~E"D(#q3_;0'gkW֠Ľ8A|8 vMKPx Hx`o^;ӇE(77>g[o[oݴʕޚd z}6]m[I>ݙXcsǥ༡_kvK&!n^{*s*jwHk=*eMm߾{5Cns/kIS zkL=j֥U;BnŒ&C*q8.of#QM]U75_-Cۦ1'ekU͍HÍWkthi>@g=0sx|׼B(=? ENJk=kX?< RBwBs Cm~ !GaV\NhM@yEH)xN+rƞ^+R:ƑNdew4$6 |٣o=#>Gem1PYۯD{Mb ƓJokЧr?p8$þ/u&F~P\)>8.:hDS'Hˊ6NUaˉ 3$gK jr XQ>ݤz`jX"UJYIYIq^MTMLz'..D!.t tU%r瑾$Dž*XUSl,G~bS'NS8BϻP_79Nw{.$)􋚣W[>l s_MHl,op\!aec!H_k$;é=l#9FrvSбW AT%+wC9_lzݾv4mZ72~OZv%7T9 ˬnof UMb)_Φ2 N|f(G}s/,6v2c:=9kgu3WZKRKٵlgr kc-ŕ|),o3;p#~ͱNcc\˂?8"۶8C:Woio{.{IABѩhB'u(p؊oG1cD}s!*JCTM#0ʳ ᐽf5dj&n%n*:%ebE#5*$9Mؚso|)Wx6РM8 Z1+̀V|WHz CA’Bq9Ytd3ܝ_2lT5MSQ!8[z`PIC3eMQ0uX؁ ` ͌¿,ʢn?I.Fa"╿fdȎ -j$E%,|xP5MBR#.G9R4p1Ta@Aj:ͱ2)bg;2B?@*i(M->umKeYm}kT[Niz*I|)a}=ʖ'g׺d z banƈlsK_W9X5>a>gXܢ - nhfňJS 1IFI0T%[YO"Z#>FJ㉌xrXMUv$CX ekHzm*Tڡ툯# y3icx?m))2Ttڠ=Rec4U#zNųM;D9lvz/+J|kbBo([w4a4+aO~x;u^_&emȇTU -f1JƏ7ΰ?y}8~U{-;X9 ]G(?T}iidТ܁0X\9d}0Njoj\DDDm$,jѓ( ;VUb?yq[N{;Niz *$rdXU3xդ 6L;15(a/l4|{Tck$ 1G=lwĠ#b!LdQ@t/r@c#A_: Bٿ5F普zg}!_x*0Wm Zaj-RXy)×+{ảc/=[n9'n G|:I悃96ta# (?%xpc̗̓}3>bqg<kӷozʹæ`TS\ Vz-=!2u.!DYPX?YHw~t%~%äښHEm%E@K1o}>8V}Y >PXޱe6)}@cڂc%عDx!JRB.(B dUa[?t&m=\!ⳚY@ !AK 0ԖvW*V) pDW`,CnzN"O0 OrObql*\RA;)m֋vDX/q_3 aK'Ah)S‚L"N" EAfmeP]hch3vM,Kz ,Fz |/0d"> 4=i_{w{~ YF A{y(!=-̠`"mlw2ڋjUCjAM>Sz/M+ŬdӛKϾt5bdμ{ybmE<+K{'-;|vtxmUM6zVI7dt>q`Rvvz b&eԕzEq #Uتρc}EgQ(Jsj-϶aϖ3'DoHUT-G?#8^K}$6VgVّ&N%se6Ppi8\RsLw~q/щ;b%32(<hUUUdݍߞse'@ v>;ehlFV.%qg7$qұy^ K4Ou (t4(MAyJW39Cز86ޮnB9*_ƖUdL;N<٠P$ <̃Y†-P" ?qdǣmE @P6EuAwb^VR"=fsUW$]F 9Ìi1~a 6/#K%SLxC`)LCQ̸ìҗⴽxwE P[Oh16>=VO%Pf r롹×Lai h9^\IXbl"PMUM,w`խ@M%/kjqq;hB%kV,S# Ԗes:KȾ:YiCg[Lw? } jps\>):"u(2ʑqd"&4ewd2+9ɿ1V3q646m+(䵇i ع x=ks8_ȕ#ezγqKIn+JQ$$qLZ\n$$9sl~w*1 2n>qYW3ߝC2:%Dp5|f$]6wq9 #@o$S1K5#?j񑰪)M>Q 4<ҡ*ƨ3x.iH "B#C2j^0R~h0[ JΘS#F 8Ja?PKQ(('\V|2kedO U]nN{GJɹo1 yv: '̞cb\'aȟрѬ|oŨ- 1рBgrtȠErY8q' 4+9`h=RB,A_h;sTU"Ut6Q`d MM،(N)(8 s2d2|j2L4LoBmmlvwƧ=wk·wj~4vK\N7, Itpu)#ЦITPAPDG i&d;C-]FCst~/9!py0N<)()Fd!߈8rb%A}k,0i8MipZdBB | `MwWw7YhFKO`Or s:@F1L!6=B~̜%F3䌾KH&f3f؛"T@2K_GW'7igZ07=VOhpF[U: Z% =eUiuzn&o =k2gO::0/ ;SNKLDt<6 i̢XN9O4u;#wȀD*ļ x>\'8`3ā^䂽}*{]OSǛca63'hab#ЩuQStY}qiaqe_TT>~X5ozѬ[ bTk\H4 ?cF=tȍ&y ӊqƛb!]u;Br00}a*ݹ+@*u6=2ۥX%i4Co܀%xUtpWa, G **ѱt `9L"p+Bg?d\#0kR E̝$OpU|B=Y-Eҏ瘗)_("eZ=1;tIE < )]kL@ O*}WvFC}ܼk% ūըǪ†yN6Qd ȩ6<9l³@Ѭ9¨Z vצph#UV0P-"lYA6ůvo30zh)_l<2O[&H(ܜ]Iח*+FVr#X}yŃzĎ;v؋-컚gčnlј~L]'e7N8qI>eSvSPt-ũ,bG&0!b훺AwTu'}BNR TeW֓kjYE= ȬߣjzP3̟A#FqNNTZ.'{)l"cVCvrJj }[%ʵt6Tw .ݷ$,fѱ+*lO$;wP7,X "I/HTKbRB;{(iߗz~Hlǃ)͢4ƒ8R-2|u)oS%̹VyPwS4jxVK'`3 XB_Np3J*9Y( 84ٵxKGw0Z׊;r@) 5VV\]҂CޮTz`UxeH{(K=;姥'.y5%\.[hf,fz^ 50DTZ NaBfF0flsYD=4@7cMB8~\]Zr{wK9ČYWΨɉ}'LRϹMX6-VCWfl}(NѴGݶU>oz\E.]iggR "f sx~$_pt/#ωz&?`)+;.vũ#=L1anOtsלKD*')O,`$$ _E{ɷp ?-n:+ 2̉^{ԍ<5pZL=N&`G~l71|s7/78/o<7dAЗ,L)ZA;{ҡ>[-]\ճϏ">l28OE<#Qv(Db{!7#I[]Cy}!? Yo/p?Q?ICW)zȽ: PgnK4YW² v8q1ixEF+XF ӈ 1deԇ)_&5 d ?D{'{R AVǍKCރNl3Ux:ߡbSx7:BbfW^̜x5q RA.m'mؓġ6)B(kq#?&&^ ͨ#"ggQֳ(f ^IB.m: ^MιP5s.md̷ dA 1Nx(;x-1/ c*h¶/|Uc&F%h QA'R*/'R&\#dPתv(XE9#OK=G[V(iB,ϫL(.*FwMmS:oC46ruK%( +`Ìٔ[+ C"#kK`1 &nJm(wQTěDO;tz%o-iPAyM߯lY]Jy);ID.,;ܭfȩ8uo!ۤJ_~ť .0rL[]y1 1,]bB ŽU}A+?&c<歍rJSk'Eɦ|~tU=6!kps*tEQ2+8:rّ|2:^^&8/(L(koOuo'J7;~E8Eg\|-A妉i%q 7:8ʋ 3$SgF9ky?Bso ڞ6~hP:[CU}M3z?lBif4XB b]ɏ:B Ģ8j+)͒yF\d ,xIZ?ą_8Ƿuٍկ?^CO7.ȐiD޾1J(U=x=G1 &bdoG  1?D%MXnD,w"ɲ$lD}UYOr )~?ؤ(9B[O^ؿ35𞵔s*({ƕ m[X,`T.wvJ[ @ taUX&1wU['6@ Ҟgo,š74]%:]/8u4ъT2k <ƷS/t&L*~+ԺvN/4HL;)|xkss+.("GmLd*53"Y=;M}޾AVI꧒ V%jfIQxRcV97?D]5I=4#K69̓4 [Y&ޮ Sa2^ C=>N^|> HBdH-Z-P|j`D,"ƣeZME 䆔+ V,/hɂb ~u}ִℎ8 Hd$|#O+IH;ђ 47B_G|~\F_ *%K3ZE)hR3^v=YQN?մ]Y=FbeD oZ%Sf'WJ Nq;7eMjN` hԉbkk2|<^Mp'Z88QT՗)nDcqOh:܍ǪgmE\;=lGQΊW{*.0@ċK~[n9 *+Vpt,&{9[B痭"JZ.3"cKZP0V`8HhdnFd+߉tq^r?$#cҥ.B+xMH,d|TBV`NѬBUr/7VtX @N.:H\pa)-j=]ŵ2,pJ0^Q<7|@B}"^2 "ꗿz[Fh!zr, %d*kj`Mū__@aM{Q_K_U=lU9rM]hO=s'>j%(αO7T^|(hSJ!x嵻ש>C @J\dM^:ֵ=ưMTB|ha8 +.ҸŇUOḓ{&vX%ǼwN UusOǏ) |'zN-cJD3B5GA/5]?mOZ iy -c}ؾ6 )uppĒyO_4fg_v@WX1@IL̾F6KrȈDSWfI}ohE>D]-mOMG!B_dbE$sqB9QW<9OG:Y"j $6 -e\VlPr)kg'%K1ꌥHb]e JOPqAX9eH *9]ׁ&lnhBkJ'ڍFsAi[1 ^u3|ѹx౞[b^9ew%,h!bPf`Ph;Wag=xZڞE'&/AXu Q((Qtܮ WVä1|r4R?;,TUfaY}s!1jsUBgY)/.o4lF60RR"O5UA\,wՍ;,$Ƨa ŕUD imVT14q ˘YdoY|3N!5v8ϡڝSC"LwjG? Zլv޸^a`ԹZ ݷS cTd{ {K=jJXB;ܠR~7\U۟R ASai1rݚ%9>ON;S<(A1(6 Ol^ \X!+aJ50z ޢ<rd>хڛt 8/z|c]Zv9Y qH!K3:vw? IgpHo~{ݖDs4Xps$ŗߓ䥦P"֜fﱋ& .E2gxP1ATq]2T#Sep=wKnX> z`8BW;c2m@YIbq55;ʜ)gEt ҥlMc9[k\9^׼Bh j | C,$-GMizSv**HfZxo >@ڟe˼(>2b|EOr$ !!c4Q@bP±Rhhq'>+y#uRmWУZ|dD낉EOW)(/+aɏd`Mv]=#98gVEڳ\sOcQ,ddq3e~'¤ -?J"^O+ᅚ"s6&mU ޑ=^6=*mX|dFϪit>1RlEOS_@Yz;Cۉ ]1|9W@p6gWg8OqL$9 ~iM}Вx8}ɧ$DZzDx_& '&ts-&"h3hU92-+h4dN$depc:Zm ّ֑*%S2W@9-nn}'ՊIY#&Qǘ0j RSmB񱚥~Tn|7~<81o=[,K;#֜-QW.K49`X<-VdAڔN hUn(KYwW@SpPUTw8~}Re]Vwc}h:ܜwt{z;Cݛ]VuuڝcF/~޷~Dv~˻4ӹ8~|ovUtйܶW? jOwTӧCݽzh]??,_@ߴwO%#8dB:Ȓ }DNa$\&*6nHSx,l̦O$F,;%5"4\ßV%g@N>|Hh573LjY HN/@6)XkEa|VV!}uXC!keHU P伻G~PyrSh\az$$G !+|) GQ?P,@[.=p z8Ot|/|ס{l_I-OTvhJ"'CaFSy~DM/p%tu uNxy"C!i_4~: aax~c: 1q<`†ΔȦ˥QDQLkF0~:x*8 R&bD,h#7w۝+:CU])$ò塅0`ĴYZFQx`$E<cb4fOrpSvAF2S)o3xEOंT7'1Ib!F%eJb9)r"A#0$cc OnPla+@!/XDzH$q0p` {6 ji{)M.Z72ɚo~E.KhR ȼ6N:9mB].j<Z6tln$$݋t p 5צYL7ܐSLQC  r5Y)mmF.?xZ)(FUNT RӍf15Y6yB,~FVHvnfpVCQJq)%k4G8t#Ae57pbO|܂nΥjM8SFô(GT P,nO2AF@>R4OZYk "1`Cx\ft wЗs"n״( ʹ nJ>b@lD33Bs"^{^pƄHxfsrm@loya _kJ[_H|AU:"ŢL)7cvH/`#r0۹H?EAmZ5*,5)<ږl%Hc\+x?2 ӈ>RKɷB2fߟ ^]4+(%&q\A=A4&3-Γ ED1Cn"Gԝ\jqCl bgT!p1::ϤZ%% #c'!!f€9]qK6F,@{w> Gfyn4mU8 YJps}D~\6^hU4ϔƢd] EKqRBm`k[GPêN~lhk (YU1/Eú~"Q_P?<]N~$$(!MpHl8E54p8BM?Ѡxԏrڊr|:*,Pͅ8mjº@u xKCE}3'-.2oM`WSqUT *lC3t *VTSj~A^[N50WzC].oh+rP_Yq*iFcq, ׏<dhcA”Ǜ/!zn-Y 6}{:̫!s! Cy)H[Suu2?C⁦7н0l =G(8Tq"bD<' fak! 81TReZwOEGl)ZIۋgJCF!ZI:l"dF:|ATZg`6M8)A}+~^ ~ d`|VRsɆMTRx18Q(j_g݄y2͸ä~L p#+e!?gIԪx\⹄W<U \@>,:6+#dJSQU1\ڎ"G)(8~.;gNZojvS%TYI ZA uTf :ո1sRx茩X]E lp HQ?w3V}s`QئmI^ȩr]/a,F,U>K]^YS(U ԛaW7Rv?˷ a9rjꊪב^tfg93CtRm/g6~{LSM4֋*n͇-IE߯'nrܻ\-5[nֶLmr3 Jȕ^ |\EX/%K5&sy??/ėn˷[8nqNٔSL#+T}LM5EEX&T[$˻* WEVR+:ʆAˉWJ9WTh+8۞pz!)5LkZZY1h᫭P; qkϻVE|DSa} _Yl ٥ EY* [)b45bQHе D]B@UM.*2,հ篡nRVaM,a*wm+5,Q+\g N$ٮs?(C'E69mm,:͋yPӅ/D9%ǓT=SKEgmQ,B."5}^ O')鐅B EǾ7G˔*6g+  : n1;-ᫌ۵j^oD}jL-UoS)zKV=Obţ[<#O3z"6"CR.K#闳h a9IR]8>qqb&*p-  6vxXYl-JVuQ.k$"i%)r"K-,RQw)mDrݥd)(PwFQRą@'6HڢZE/I|Kg柙ow׿{7~ }EDF(K eiß$⪣暋jjFt7rUaS`baF]`V;|$o~At`cc3t:SsZV^s5IFF@j?'bMn|.1Mǿ'8:Wi>F2 24V^s6ᩅf|?\h-gùřûEx1>o.7/yȪ:n\3le'E5=Pw_u⺢0i!16 q˦ K7Uk(--m5ÚNb| WSMiء,ݢw))U~~`l 00c}B'F@[RJzDygl QTrZDl }Np,]X"@Z7yL;}?;~(ʰvG]bpϫFz6ey Q!H~)(D/zz2UH`j/QMGzʂ圜ԬBY4DA) 0rskSK^ī<ySUh e*=U̳=zRJ ғz6Tä*k/ho/kײyO]) sS~1+|XTI FB p-!Ϭ){n.3 DVqY7=$4 cW xć2/bO΄DŽV-LًO6uv/\NJ뱖z1DF$\Zyl+&%f=ǪftQ{ c>{\6x'h;%z>k" ld2ӰIoDm UngFW Wa$>>v~o{3/¼~Ƿ8nj҂&W*~O}{/5nxj H1‹R$,Dwdt>ǿÉ)&Ӟ)yϞ!kdi,ݩkv }]):U!,3z'guNJ&M6*GcsH":zC#<9tXQ8.hGpfy &-[nBnc ϴ;9*0, m$,8)w^WQ-u*x'BLvY(;ÜlX>sc~ɽ (=lD[L$6-{3K5Ql`0,O5q.ᫍt}6ZGxRﵱՋR$C᷎\sӽ͆2 ^ƃ#¯h,\@Kȷ %Hq,VKC2&_7Slaxg9͗YV3*ȿ x|VHvoSL8; $3 EU㦀&,2L(lI e?<O4Rݸ*gXA}c̻,'-_ Mпhq@EH>˖K GjZJe貲< ]H|8cm8kE]r< L7{D!vmS݉,/med+d<+2x:ȱ̢|gl!ᱲSRd ~/ SҲ08Wv֏{m]ݷw=,k?91jr7]\_vɀu2.g#=|YrI)J— k;( ?1yunX~}nZ"-h-kH4{fώӍ-bC' a\yf)xh6֓ВSK#i6lȖQ@YIƀk-[6} *=PuA[Xn7u5f` 93&ɑb`Y9.Tع/[NpnAg42>j t,\wv%wyQk9E}!&/dC4x'1.3Y_%_Bs͓^n쀧  c4~r$g R|JW:(SJ۠Z ZۣO+dAg~+1' =e߶,N*'{4tڐ g;f¢V]!ʼn{-9=Gト-gJ & qdΎ?a5t\99bw:I! r>Q 񈠖V<ω_^zm{-24;(56O+dDL Uq;84͹S,L\C !be-YrQ7w$w \j~rJaTr+6RKăbH<|Br ?.8+Z@}*;IX@2%_ݽpo&ߍ3Q݃i`0J)药c>#cc7Q$jbr^vlwZ3f\"ٰc ɘB*u,(Me9 xQأ;BavI=k2# IJ8fK׿ %A,HxQOVčq?oܞػu.~ɹlߎt}k^^1u^iO~㫟&|a&@iH-55=ߞߞ6;;NϮJ[Җ}ǓN)&S{:>-8=w}{-8k 0)+jl6LB R j]qkM0|\(f'0[.WJY #xl]^9\#6l%p;m-(ZvA8K57%Fj_*o}oqJg'ү:TEA]!Ѐv=xQú+.E)L\Osqf}Ѣe=qIP:$mIo I6$՗x)`n6j; HQai2q6DJZ3z 4mX(+7EŸGyў7:A*Ot106P|l?1~A>̳SOρ`/?L~7^(eƿwrÀ_IާmC{xZT0b$N;=c{g#۶^оa &ټ.ΰ;"پp[̙zDbQ ؛4g38` z*$I![E?pp+G5/};8Ks (^A$ *n|zqyq; ٭{38ڛۛyGQ}w;I*d/YT2މ]Ⱦ?m/Ao48,a'\ [2GãᱝmoG$Ewx`=j4 FmOڒxUs@_ye;^gdwAކdfY}0zf/\a9śa&̀C$ ?n?FVC=?NnUK.gPlOJ.q?5ŨÑE=7^a]f鄓S0!f uڧ[xta=xA};]p@?zV= cۣCmzr*0QpAFGLJz􇐾žaLT2h8_$mRy7C aӂ :Q48ehe.3U/bh"qwRki>CCbZ(&A|TlF} QYZ!/ē5Aw2Z>*eO y܎/{FF@| _J3g IjxnA)f HX.*D),xQI`\v}//K30w B"6i@EG8*~W&Q^ɑ`M,qU;oU p#sRh!]F<9PgH;Oj5RtQAF/XUNn"$6{pp?ʫcflnd¸SJ ,_y̤-}B(ORS·*\ sŬ^fobbW ZV:?tEwBK*sN;3(@C32a܅h䡏)l ՝Q?Z%g!FH򘰺<4߽S؆vgI:%ʨ YdQQ7$  71.wG"p)t>WJ5ylYmYB5YnSogüޝp=B#̦ċԧht YDy R')HYr#X 0H)!1Wvgai/'z :TtIQXqU UM2 sK)FR,^L~aDu¸h 'zSySSo*lkuc1oHQ1;~U WAX IiywKYyENdBwY05e=eM0Rb_\@8C.;B07 4ȲCNpt+{< s(~̗~HZ~ߝmtŹ@V-K7+>פ5Ni[Nj ,KmٗʇTP>q(ÎQʓ!th9< R˜{&ݦȜ|XD,tDoRt$b2pz^MA&%v$amy"Gq*pMw'frZ!tJ"qRdF#} .F.`|Lې{6ND!`vYms-#0j¾`ϱκ]T/^a]*vԍh)O@j%SX)h@PN$c:!|-=>{RmH^ct S%55j41b 'Uv™cuL} 0Ud7&a]kHS@|w>#WKiK)2e2Rд57/ͩ297Pp9 b1*/Bv 3*mz O~2KPLJS*`;ô\#tN/wia#ƢK[7#%nkաs2;n!_ 32c`KcvQ1uaEW0qF6H epj4-cZ!Qi EAx^]$*NW$ 4 ;$V*5y<{5ּ [یs4>h(D hޚ7%A#gsG"fD=j tJ2dj(%M2%5K~V\1["UT.niB CkeIx$r9Lt勇DTᠬ}%uUhsoX QۅA#=Jת(/0*2FT5XSʗzѮgo#*cJN?zrDD  C ar8"F*57gb0Y$uRXʱ%%xeje7fKk 1qcG4_gR4ֺù:ȌQb=-xT=o\y8p1,9ظ&񹤈@Sz˺)X[gɜiUm4"T߬!˭Tb$7űy"՜q+_5wLusqnaU|HaC5`47͘8|O8^M/-uq4oE9i}.zsѯSZn  1yq#dcLMo~f+ݷF|x].P7D\IVk@ч0Şҡ6+>ai6Qes/U[6h2n2歫E <hlY=;5 ע5-tMua2qrr_qiC0EbGuw9 4L̠_! ՖK1r@L xʟ[/eGq0\{V}yjXمIƒR(̼F r;>鿏YC)M /+#P:iH[[8ذ#+omnEIuo/Z@0ѸS Z6:+Y47˛ʈu"ɷ{|Sip/iC"L%C4_48O g d]L$mVS4k[zǛiyj\caxOG\u*4*JO.fXP˰$ڪ-לj8/&S&_[ZSWZo*,PĿwuzsSS6G٭<7+Ru/Tx UPZ[ZW`Wu~W'cxjwybIrCVOJܕxP^59 x]10  |@Cb[QͭnވPXeMy$#1i"Eb.oGD땎 v$yѱf2 X7KZNO@J@\%X#5=F6%wCӅܼDz~n_Pu xMA0y@i#l {JhG~,b%3QX c ѶFYbTiꛝ crEL>xH~. OO.Vn!`Oi-bji6LAxVr6 }WO;^eNm2M$o'SBRl8L;'ZPyt>j`^<-Zz_-7όVe_V ;ۨWTQ;K ~6l/T$˃ِg*MAo\o+rSV٪Hc8=ͣtn$}RY"E8c߃}pY1ZyRk$q4Ο :D܊*^D2nL)yZ 80[2zI^bĵUKmt܈gU-;:So9PUh`yA 48H_LRwIK*5 GtZ/P(׺U@9ѭG4?2|-'OO?ld>۫c-=]7@a̳֩j; ܨ5rVЮI&һkԤ뜏Jj ,uPyJR xw>|phTgq唌ڸ;>DF|[$.oy"R uciTDyx\ %Pl (pUܱQF8+$}O}D! BaVMk@ãY)eYq '(e!BSLF-~.y$$! `jk4Eqԫ"`z`d^إ0j OE4$'UztZpHڶBbè=.!yŇ ^rV<jǺs3ԣUoGVRH :6T5 Hyӌ5gQ#jP5(\I-{h11{jR;'Hh$aK-H,{ihIe-W=gB%Me_'/Gb$` ::$uGٌuy4*HJ6Eݶ}N@%)Y0T(63:P|L:1v(Aֈ%qNSS yjg*4^f&Dur*f#·3k}WOa VP}eܰr  "jFB>/gQ%ŹK2VsR?y,HʻZ)2$:MWJC2Qb@W G-凷VFH#KytvNtW2[C,-(-f3t%VnlLdvI5)9=jiC^U[ۤ%G(f+,+>*-3ox˭$qB)^fVڦ'dotPC7^nrH F82x3v@NxmSmk0_q}h!q {a4m+lvE:ǢIrld9i6<ծf[i&3:+Avm (@|Tj^;Ԧ8T ۠#w"8rU/U.ȓUhՒ\ |<&ivשr ?4޻TgէQ' ;ddL|sy\*mJ~vzz NTYJ⡞.K}4F%!ǡ [X>P%+t=DjWNzM1yD~b/ѻ?r6_&l(n1N(- D/sСe*0!d6I1)@3Xъ"d:i>Z%kX,2aIG,`pU(O!Z7lҸȲFH-&Z-w 6ιFUzxp;YL~$hskݝu(Zz+C#n3+.Zf8b ŠFmL̳+\V7 iRT~ΖQZ yG7/aic1sp}ky#}QVdfWX%&1@~o)e Lq2WOaUXf;mL4pVu-v$hw\J ?Cxo0+m@lҚUUYִHi*o3p5c#54u~O ''ϋ왪:)ˉZhUCem3\T[˅ju%c5VJ-ZŽ#[gf\h%JQ~`{0N~ưa/ 2UT-gkHȡbG&gȏ$AF9 J.Qz}% ʎ5lDu~)[ g HPB֕pyXzt;?&q:R~сhڤZz6}_`ݳx rutu+(r)ˇ2rR33R!a>A`n#aܵxK)OճJ12SˁlT$5SxTmO0A#҈RTi/1M44&"-AT'm|q3jgTYAX Ybc0ݪ\W*_[Zڹv8a#|6z89{vztvOa:a\cWw".'r>1cZb :+Stof B|"뼀}G(q}m&fj "(<:/][=lEAǢD^^AEGݔl+! W=]=j Ƥje9}uN]"]SQ[Z+9>E41םv7#nO\3sUF,Cۭ"Xɜ?%㦈 ԣ"o) nq|VDJW">gI/P@*av&Ihiqwq<ЃQUJۀ y{[Ё%z`kt6>.|fj\"Ni؊3]AIֹmEN f %FQaJsu׎du`(cˋ^C_R{VrY[d\u[xMPJ1ekA"K$bhYA,WAd Mdս^"Ood-\0yGoqs!y8OE5xvy.,jgZh؁MI B WNxIW~w~ I13\?V2jW5ˍZhp1lDpXZD9f&^gML8HOdZ-PLZ:n F|KJʨ)~}FaL?c9iSZ8&3ge, șBU) gͳ,H6N;oV" Gg!}(5 r#pNU {ǁǿ*:lQ3W|4`mhZ`wauuccѻ,v}Mq#@/W_?ʥ4Vqlz eFSrk_n F#%B9b/]]R.}[`Ϥ,@#hw|O߼:o+aΦgPEG7 Re-') 𑇺>$S-'i5H-SX|T@%Vb ] F OB7xnҧ7./v0O>PR>V@2"jы-.SET+6جhq(c,4{a668ȊgN-mY1yɧVfjd{}47{wd;nk#$m0liTT>&ZtN WAXa?w;}b=H6hTmsǕS6yK';Etf 5N Q_=SYw=/=s S3ŋ- jO BU_hV&^$xV,pno~_𩟦H)dDg.yGFN+1k "D:a=XG4?*g%&n~\0DLe6;=nH)n)gk^ dW(^gKzl9(2ŮrvrBwxdVOn]9`:jGO{Ȣ>ЖC7E#EQ\k}*=@lY yv;y3Ӄ!=(AT2m$ NZBT> )E7#GTpiÏ@g ;suRtk ͔d=9Ji/SP{Wb%Y6b"[a1z W+Q}vMg9r{50wpz͓O aAqCVf+x$e|&94a!X\1јcQsjs>?u0jI5'X y"UOqIi8X6h;( mf¥CzA M*ԫL^#5Eъb_m.LFWVqRՋj/Eol9T>4W˅!s,巢ƱR{/zgkmSҧJ|#l j鹖)/ `tP UZ(t)qcT`jo e.9aw6-/M;nޫH}(|+rM O/~exu7^KQw}ʤLlz.gy ^ʬK=݇갂%݉ğ_&ߺλgja#$o]21Ҝ YfQյYqE"؂I.19֧-l}7/qγv+q8Qqx*wl#;?rR"3UQ5etB5=9>]h&aҵBrB>ƴ9%g{(.8n9~w<>>g`GQF$dAۘqd=v-* D{wSEbGG$\o /: uLsrZtߍ&/7{qU`r-!|0gvoeꜚ/1C{=u^ }%ۡea!l7}R(d!6.vj̯@c̯M>W_{!C3P (g(}66 Xh:y'=HZfȠbx8V=[ئ}Mp iDcՄ-qn<,;uMf?b av# g^@%>r!<^۲FQvY<DkQk=^ @@BoC=]$ZȮ1F2݋7ޭsJ{x 26p;9qE8Q 7H^OՍ'Xjd;".tU#Ajbñ:[lK`;T4c;h (dh`6i8f<$[^M;ZcO6lUH׹yY/3nL8RY;q\HXxP}]yxt;򫷊>Km,i&>^~R"&p<z4c?<]kt`^B匨KM}A8FFjK8 gLںP1 ݸdI3Ϧ6Yq= 7Y 0 ;Rtk]GG5rusٲp*|ĚS3;a? -nL3ޭN&Ojnz~98zc D,FJ> Jv"J2\e8;suUP^v2$'uVTNN_Ϟ>3rlZy&6q_=rh/N屳جśآ|+gTϐAu-l;65s ,ZsIB3)*3j/2:?oZ-|LEķ0ŋ|=6/j,k[;X̵9Ǚ*>>W|mCuT~n|w lviN{e9Nix}U]o6|ׯ>%l5I Cc)PV2TI:ݯ,)_EKrwfvi遮 `GWT9[XE|nNSA[CA:hYۇY%}PmuʨF&E!o{|znY!ezc{9_oJjKP:6Ab\Ry{%]>i:zP n] gZWJի2vhlESyXQk>G\T2;ւ#!I&{>{ADe*71p17#,xSVO/JHMVH)OUPR(L-h \"xEAo@+|-$F5Rj,8-Z}7YGaUZ-TΖiD(gս6ڳSuY_ ﰏߎ +ڜ1b0,CB>R &y+z }K$݋cn g.Tl cn3v9Ѳ5bA%V{ԫ݇h»YL F|4`eDXY_|fP{Rj@r8F fnGbfB!Zmt ^Z"~ #zN9TjeT16 >Hqx[vȑ=x8$)R$P<#:>9Nh Vu%;볉$UnUw2IwoN/UҧeAsZBL3<1g=8BFXʈ$6)kvÙXǹy"JD I$ʲ3 dJsfX+Zb!1R)G"ƓTĉJeDF&5̓0+`0rD T:Mx HLNlf6rӵ_&Ix C-V* ]LEyrz]`]1V/4.6ՌƖ5Hf*FTbGM*5M\*~|py82#e6؟Nee(.PA|f!C.)6 wܮϟHOOA]$TKZ.ri*f1 e=@aTaX*a7'ۅKp(_N0=d\⤌ڝ< hDE8ڡP42$WN<3OZD9d%22l302[3eQuޟ_i $Q̑eGdbj 8}vĽйw95e̙?{SW+B^c9O4\p4`Dh-t'Sxh<2?Y8/jc/ΑQ8F v`ƹT_.T))15!jhZMRס9);Ϻbj4?)"W-g/`+\{ouSP!#aL"[ai &Γ$N3w#.VCK4FTDpR(Zc'~P;v ʪ@1BV>5,ux2]w y;Ev+*PR4v,ȍ%IV,xEvb 8L\ iaJ&Xc YKW~o)_ k0Yc*1ejOkdC>BI31 cJ"[X38S0? >aYym7-#ZQU-z|)4-z`NI#X)Q1K\VSb5Khi$ oTb_$"XS"MI`A*#1$Dx@iJс&6 yCP7`O*t*0lRL% TzNא"t[m0iXc( 3C9vHR\.ha:s侴;uk=XMnU8#ӊ+x nμֈbV$g>;,uNgu$)hfJfk\`ϊ_lI`JLDΧwly m),9"gu G7zo 6^ W8~}L֎Gys|Rz^;p⾛~_oh3;BR\()y9C6d BQEq▗eH㵨ldk}Yhu?<a#iøj mץkꅤ>G-yi^(oz#koMBT}T>75rq܉( [R {դadunޓ~ٙ "Ue(=1^ !2AN٪ !#IAÀ) 2L:e[K |(֌npA^ XY܌d†8gǨUAI׺Z"䑗Q蝃rVƹ{2HEjADA4eAX͏jO3t r-,nRQ0UNMBh M9sɮl'"Kӷ_i4h5o,'\C*vjbL2~wTX-w7\O,Z`5F|[#zdiE*om= @gbJTeae_g)[Fl=O,Sblo`Y3P`"5ٰ+Vu>X0vx't"XB0Кa6|J YɈkS_ҏ̂TgF.Kw ÓSYQ4RyPR0nlD.*f Q&MoFg+6t /WOE!Bק =뢖DS\$ ҢݑM1S6Vw7Ӿ܏>N i5pK%πQxSzFv=ސӶR|jl(fޙblN*d]7 aZyV3㋵el\RVtXgjF'% x:%Hʌ 5*))JbL߫ ZS; 匛*5ǝearE`2/(=T0kkzv/ ZѢ@Hfo Ry308r`_̕[TSG38' qmʀ:#6%TA(~|6< ﮏR\noGPû˱x?`2;a .Fg7#܍jb81]`}??^'ݸҖ +*eʄCbp\>Ye2'fCq68ފMk8=\ .@&&B4oϵ]8@L֕IbǑnyF _R588Vimr0im/wlJf 7X.+ "yUahvG*-;˥iw.@ft|*&ٞpL+$R'Sk$tEY=ٜ ~$tSbU{72vBT5xDMGBC%Z}D'" 44qŶѾlt޶ϪӕC .ٳ=*o;Ujprj=Œ?*U?"!<_kpŽyrܖ|‘tߋ MߡWҞXkU7<|;v̪3m[_tΑ5h͞JxSFbvya =jmVlnp*; >0!y0N'b&|/2v/>1wㅑۋ3& Yq.[v$q}V/voP.`i u(dS]UzO;tFq#''V6^vr 53"7fb\]F|,':EM7t~}4+}}|vn_:w2!{,䉝M2886{x~FT~5Fwz&)i/b(9Q鳽NE>BP"v>r^'M旽t~1,5aϬWpL󚁧09Aw]3QYkivkjHۇ>vM[8>݃N5{6Y~HMjzpӘvKn/AzN1^eVm.߅X3?lUEpmvxbUVTf>8'2Ӕ eu2bjir9%v FƩӂ[`X6tTئxG`B"̭J钄MA5*V('0Wd EK,Ð1.mݹj&`ʁ)2lx+¬! JmKǷ944ЦzyB{̸Ef7ўmRg\[4ִK h!Ez}`svxLP8;;Z|l<N.o?d+W|1S|,@Ѕ/_?P)E򲋹滹7_ʃ"A',x}n@!H\2XHHU:Xi*c'Vxir8scI՜vO kPV KE/؂mT# & 1%q1W&뻞9=CR0+3 G&8=tK]7XzFݺ^Dir|6s][S I@7EdT"|Fifڠ*OxKe*..qkt=^\;WyfB-U@Y 665o~{%D#4%PP eE`*/ԢɁ'\Yr%#;%P=gx~>Ξ?$.[ '+Gsuc>+Gxb/3XVi~3|7g#YG%Prgr^tF }RM}F=bS)֫ݮ*4* FQ ݲ]+oqתH64eQi6Um5]$ZE[xkΕX\Z4q׺ Getting an(*@ , just do : (*  J *track changes. If you want & ``*B xkAIM;B`)s6?j(EA)EJ;ٝdfgۤ9⹊xBfOSk1-6mE5}X=`T} \򖈅D ĪNVm&i#!P~9FJVrv#r#=dv/a($ɀ/مJ 3+CEShl\=ѥoSk6ͦ-Qt^}zcpȌD DZhP~S?N6đNM:Gǟ .? \ӢtT306Ca+ V=ֳ_Oޞw8RB-;"eLlZ꤉+qO(+OtF\ j+: !'<}y9уc3&6X,M/0;8"V?&#D>bv14%$̾-\?O4ܫ1^'aڪEUKCo*sŹyjO,*͢cn/~%|F2pƻ**fɩt[v=[e`^tvxM; @ERhci@q "QFbi1<|SqA,]܁A!xsyϟ[6{Gtgtbt"օB!!d;nr͍ܢ'Zr&3LOmLx4i.Ⲽ{"jx[Ŷm!>=]  &ӽ6ٕ)ݎ<x}SMOQMKR 5ʡ&ӑX1 ! 1XL;o#&アH+wF q/Lܰr鎘47j9s?fɗeG&<.KЦDžB(ڙ8RmLFqOPP*vN|%w5]aDX xd e *\00yF Kp6S:$ԣ #욚*E]7 "jik#n4 &$mnGMnuRw4S4Jz.`7=|+ =S .@ngbSmC?@U;=7obTf1qcAs%ۼ(7|e-x#02Wor_wP!pJ={.W9|ub,x&Z:-[=7ޝdZ+4~8H,ѐyT*>_)ng*n6Tֹ^EIo3ĕdĎelh¨W.a-$3W8W|<-o66}ѤRK=Օ#nP42 qEd!ѽMwh&O@GgKO; 'R88Tx{fF-S2 2Jl2sRt |L^~qIfHF$_$%d:R #838pd7 %ifg͗[V,y\*WKy8}?F8Z'׋`Xm, T)f9XuN5Ś > V,X;Dc~bD@p1",.:ԷȪ hto"٠ȁ.Ք($ kޘ \hqHzReƵI& Bm^B!UOIlkDRwaѸB'0c0f0kGVJL{7/ofxo."OF[Kx{wCrAQf^B^Jjr~JKfbz^~qIfrBbQzqafC}nx9&` |i2Jȧͱ]ƑJpm}r:;n7QE=Tn{xk\$bg)<~ s|*x]n@ / a=HHRE<7c8x, ހlK=]+X_b-ƆҰ^*U+I_AK8p8@xE-aG$ɧGȥ%)DUAu'%4"M_?:!F^QTTfҐ xbX>`mz68M3XRĎ<-חLvEϭaDu^xpS}a*6z0Qr볃7&bq`r.ݵI X%%{lPTG֙T+xv3iZY!۞96yQS{+ ըh^Cwly`2un U^WOΟ?dLxeX,C9EI6x |i2JȧͱCdx &` |i2Jȧͱx9&` |i2Jȧ͑'tn|mE·S.H  xVMlEMn&MMNgΏkA -I:4ڞdqvuWB) Jr!U($TD NAV!āe1i >xͼ}y3oVۺvze |e ˙1y} uwG9$w51T9,c54,((B+;hH#h4.FpcԌWW$k.G"HԘ!CpBbtRɔ^Z!FN?&J(# qIKƃp[NEq8 v?*.؞>8\*EI\ΈMs,z%l.70ynUZvrHV+Cy'Kv t;`IsLFՊ 5x d @Vr:`ϵjkʀs#izPqpd%p^n15x-"0)Ñlhښ&`2R5l/ldaQ^ d61r٥M͍Kbàvg28 jG<5h*ILppO"K>y#/vMuz'W EGG19 T7D'g88i _C-")]f+7s$iîf e::˰WR*Inq}yI RQwzcYJ)˘|TޱBz*+x_y [s@7M qMs@W+GS4_\aYѢYs 8Hv= n|_`YFY-.?P~֕{~p@ ߄_+ȸieHL #;.\;cE Tќ JTkr@5@YC(xX[lsg휌 ;ǻkM/hLN=;1}xl%nRZRQY JE UxiO}<4Q9;?uOx4z&C˙SNdљ*iW۳Yrx[ճ#cZEӒU!|jiFfu%/6qLwZ*|=DȲt25&Y\6ji8V BH-'뒬(jJNuaHY3-`J mG;x9x3]m77WB<>9PD&V*l7 J𛖞hT$##2(7Ie+'vu$I"k\n~!;`"^3%6kj+]R--٪`ښhYc#Ͳ7 7T!G7 )fM3ÉӞЮ6NȪoRe&8 5r?& L1w$ X[cwY =z,pS[%!%p{>{ɱՌn*[[1=l;zRԑR Wb-p)3S*`&M ( GzB7i4ӊx.p G:F}HF`Xu|`cO{[Y_KAn/leRܻ~AI0f(kqK׵I|ٿ[)wf*ijԭ[n5QEQ bw@h+Lf-׌M 4t$Qh5.(]-U zY^IXȺELk]U$U!s=Q,9)M͜dgp+9-C{#$M&ZqX5*i޴ BP׳CѠ鎪iD'4;](:[$-1'LK#y*.Z*(#tAwཐ˺NiY7lpxa畻o`#}BoWw&]?T06QXyEh'[9~~3'FҦ8$j$ۄ{O|xZҷL+Lbae ՚fm^#bD \q;{uÑt6d^x,Mac۵])A}6aꥂaPL ecblTpP, Wڐ;r7u4H|LǭQmH<{(mR7*i =.˩ҷ2+WERP[}bA`Kh=Y7ܕ}FL6p&G}t ^k=yuO{;3#^1!:g,z*jbm182ZTxJ,ZϯX[[ecb~0<J%]_-` ax/}gs}LYfngIJ/} 1|^?ZX.Q#pSQ(\X.ǁ\8ё~>A~-؊i#8`dmq/d><}~S0nhV jg݋qrBUTzt|wxgo\ :n)hj֐ *<3~j]:~3D|ZRę@@n]N`^f 9 u$K"8R!L7 5W`s\R o~@xr 7*'ճU@WQ3BO3LǓ eE, S ;8ӿ!2e"ek^ntSV&58uȐeΐTq)lrc= Zf=ñMK=_;.~!Lϫdz]~~2 Mm[F9g/Ky7`̫_[Z0 8{vԂ-2NH1Y mZd;(%Duڜ!&wŠJ?mĚ'I~/y)i[յ\!_.eIfM}lvvx%]{y[U[Ջ{x屌|q!{l'2֚/c/j}CMwg0=? Q[sbJf&& FډC"QxEQAkAe#Bv$PAmd-I Ђ,$YffS/COȂG'OċG?pf휾y7r}y8Д0ebEp*A5U9C",ɤ *Yq%#1ܖE'0E=H)9 %7O]'Fĝƛ.q}wT̈́#sfgt)ܟFwPz]UvK+rjλky&4Ϭs&|aw4Ώ/fX5xUTjAfIc$PaܬAr!' z0&Qzgjv۝g7{Z@7rCx3x"X=ąYzzꫯΟ?`s~qJ33Cf?A Qަȍ{e4;'O0 H3/F8 @a@B ,V(BmM NNJX@_dU-A#!rR]ĴZa4}4u̮PJkf暠> D ra4wur*@I-8C-NZXE15zf/dseFBz~KO1:A\D+#46{*We u%IáI a -xocAa6)Ct Yѓ6i&Ȋw쑉c9zsH n[%H߱q ?E6VT)%)$9dD7-5^]YHXےIP8(ËXQ$,8od̜+__ Е~Pz%nva ri󥿳16xa4Pe.&*l0>JԽ8W&i^\<͇=|4ZzМz߿ڝ +pLSmD;= /[WB] LI,UH-~iǖWLdI.Ůu])aѷ)yMX+Wn8d]<(iJҚq m2{IvT*zx UJc%utr_i&P(7{:OsNBC׉5ŭ=y8<_2_?q;xY}0WHFBJjRfbBqjIi}Lm\JNNeԔԢ<.HYKQ~R>Piz,\) 榦 %T|K3SS\KRUTRT& )N x۬>[} !ļĒT.W xUKs6>b/$SvvW~ģXr[!bEb,~ RnS} /=Ea9O TU|ΊiIsjӖihUODuB,˲(yox-IqFVsH &5䭦  ˨jn>Lw[3%hhցcWg}BF%]yN]SO73 9T4xw+q"Matc- JO)iP&IwrQURTΓi CuEBsFngHUfR b^]-ef cAhdsl!DsM!pA:/SHA%ņnuEXO$}$[dCoSl|ֻA}U pZR9mH)ԩ"ۅKHrکErhier%#H!64h\esI,xsX\pJ맕4Qg|K&V7W;ֻ0g5઩#gkF՛V~žڕSL|D~8--|4~ .0"%cL_&wa&OD\^lanZ,Kb!RnK(L8k]x]G[{98-47u[v"/>hq#;IX93+*\`x)7qC0u 0TKhtnwc3i0 Ǽ`T>BrKV皣GG V*ȧ^,גRx(;Ey hU#k,OE_}ljW}e qL$zN$(W`)Fen\=jIT^zԤԝJl-kT^C}b|b@>~99/EQ9>OXZ.ޜޟ|\4Z(g0 F8A[[Aq",C織9pP8)+N+Z \:ZhV~)_/?,:噵Vgڤf"YʁCo,!נx5uej:n2([p0R!ԙad k)ʡ9)vc-dZ_@ý~& ɀ ~X}j2XQIlm݅2Rҟ` s Ù6ڛX r(@gJjـtNxMkIc2R#YB#↭9F!i ֏clp8<;H*9y!mhMo .hB.Iw)-PdP^U֘g )Ҭ 69q;69O`m=ַ֧j%SZ SX'^|}_Yŋ^ŸRMx4b.N RNj!4k4uB&yHTͽcp}qYm#}k/ƆXyzlX\C6_&ZҬbrdHSd_?JVg_6]߄Ig\PNg#Gy)\)lquNE}#sc{w8xWϏG([ZnlkB6ZdM8b:U;;R׹rCܑ ą ?āWճXɖݿrLp刄4%o΄ڵ>xuf vf֌? w&=\R'qxxl=Iz^{xe_}c1BYhaӪ$. K6y)*,SgK#}"h!=RڶaF{4&FsLi{GTY ۠ @Έ [R!QKBR]L+aZIHvNN ]@H,Pﻶ.dD`NbFNU8 g*]+By0R5LRudTP>xr՗3nab J1:glҮwEvPޏ>Bt8+w#Q목X}Ÿ =G [CPMْ,EZFuR6s$RB#|B5b|H]iHA9#‹ js(w$*f [쫒1B5y` } LzhDmʠ\W0;*D85_{r?Cpj Tr%Ri RS)LEx x}MwILauOTl7".f؂Bue74+, c ;LL%$iul _:HK T*;0%XrY̻֧|#Á tV.#) BeSh,a_Trt"%og*/MɲtAݎAwM$6 3NtD2ߕ.umxc`vx'Au@X%jk{Ƴ+jamRA72KbKΧ4։Q[y Q0cl7VtK_g*o8~օK7~ۍ_|'oye|Rhֱצ@G T%0r gaJ_Pfk*1ijMkI iȠ@P5xqkb#C|cMDnൎ֩NM%/7l<၇nck5}Xa _Spc:,i:0g߱2eo8~[а9[,mZI0;ڞΰHTE#,Gi{Hyv =zw!-T0UtBdP> !v2zx_gZBm3Qšq2p{BX,̺}KsnwcD& ,|ќib`}:7/^$X%%ظa*yex<pTbX 3=//@BqsEOMOg&7V2<ٻ;M28'0^ͫHoqN1Ê|#c6h*2%`Eeh4XaLn^gJt6:cVUOۆtK?li UwU6̈́8Äo.Ou(9va,UX+( 3kahs ׳WK {Wu5Vg,2N +&4Ɔ?iK^1*XST\ y_Y;)AΏ=lDgph*I鰲׈أcM囿 <=5Lb]2QJ-]̟Na |i6<~vrŽ8Di4~42؍2ZM#!6ީ*-A^[Bn?<-bx[%O+3O!/_ $34'H!(%Ȋk⛃0&3*(dUo6eh\WX^lťXU_՜BH|ZCQ* x{˷F`T_bnBr~nnb^BqiAA~QBf{'cNjQIf^BoHBZ~QybQJjSRRPJK2RJ2K2J pq9[OT. SWW8 䞼L[47zʪcd``9Z$7 %x[#@kT[f^KfbN~BfBpF~[fNWPjYfjBZjbIiQBRfIBnfnnbQvjWIjqByfIB~NBZfQnybQcNjQIf^: 48,U!9?/-"ѝq)Ɍ٘o1nf5ab707~Gg4~xb5]61¬By\_M7xuOQƳ j[$4PVpm%mn%i+4]nDF3GjbB 3 `Ɛx1Qыsy7~y3s|Ӵ63f.[.hjhD/kE|1~mt2aE'2(f{YT,*R$,pb˒QA (XpqՅn,;lw6gϰİt-)+ q<"D$dX^a9R#RT"ŻSm.Q|:IArTL(tB3a g5(Yc !^3>ܲ9ɤ()eDbj\fs^}ըT41ӌCPcё* jhD̀LL~voN ]§]vGPMͪ%,d@ L pۏe4ȑgD> Ѝ=J{Gr o\hPH`A/ 4dus$#E^D%r>O x{J\ЧC$VҿZ_`賐Lw@=1kdAt`dR@C@/xC&34Di&։I ]aۏ/n]n {k!\}ŏ'W][;;kްzTPuvCCu|jU'E}>S͑ly6_̖Y-_`xToTWѲuCt[̥M]EXmm| m\:1q|#iR<4b{B{DL^bح׾b)9;/~~x& XG@3M]5j@*$d4&v6eJMȖEXV%-A[K}, TAXwk};З瞧G#'SS8f];J$ih3hUi YnI7(l&yfT HDKL)k d]%[ 7!T#mBTuASd"+rT̕s\1;+xJ.q~VjeFl V3 LT8h2Z,[,,EIn~&X^Z)n-TzV3Rq)²gy. (Qv?  Kɝ83!ϧĸw=Qh>,VWsbZz%Gg? w`3`>V#JFeH J7`Tls# Őz|,ـXv ̲7߼dtTM:,vtDئFP\hn@CPMZ] 5PȦ&e/.Lsm:1r]M;Аj(aSCBGMXQ0QB,b_t=g.ZgIزٯOJ$)h;`Mb5u{-5љIp0/H;멾q& vQ/KIQ޴5ʞ fy9.Uݶ!SZT4&v~~r2 6ekFsa:np򙣦)& A2*TMؒ/UN-}Cϫ( ^i徐1ͯ%>I|H5#]o(U3M۱7' !'{=þ"jK2j2Mt$Ώ$NCNCfBG(yh{ם'C~v>Ix{y}aU_~>0mslHML#t*9 fKԾ!OGDUi(L<\?r>=N0[yh6Iȑ}勆@xG1- q8.xC8W׫ƃ[@@xnQx{uI 757=f[2x340031Qppsw +(aX~E@] RVLb#+? ϝ(DA6nuk5?5b?;%D5cK0EInEy%@P}IJKaQ܂ 7d775+dPRO:0_y7 Y[XYZ vPyW?<ZUlJYfj9օ*Jw_0R{]ڬ2 )gr?w'KLU*KI(aPj:i;fʅژ ĢĜ ,Kes8]wQj`qjIi(bsϦd_fi<#j s:x{uI SY 7dP|G &x?w6 LX447b,ϛȵ7y;A?4'M>,>YN@FV?J5l'r Jfɪj+%i(䗤d&DX**(()$(i5AR D&ʩN-g4rZ9ũV\ '=[>(ԝW:^Nv +؈gD3ꢴ9^q=o^~BZQ~Kf#Wn,xAk@V[ (ݮ(۰z(fmvI$;&af݃W ED@Ճ^lK|a{yzq%0^ V7+εٽ1umVTS 8DcAF|3Wo Ux;-yU (?)_$3XA@lNr}&W3-rr@҆YQas#sQwj%xeb5]61¬By '+Gsu%.\+Y&o]UȶȫJL9reÒ,-GTnB wge9I̷?/1|ppvx?^7?x۪[yX܂Լw$2C=3K2r+KK&UQKLIIMQJKMU(.-(/*Q(iQ+\1&&S$Nx;vqq q 9'kpL>đRϥPYWRTZWVkQYX 8$8zɉ: NE) 99E: 6 c2RsR ssSKSv$(dd%lZo]US ?H%Ld+eSKJ*7r0NVd5wvne[s-'GsO], "Snxxqt F2}Xx[# BqbYBr~^ZF;!ꛧ0&3nfcŸYU8M 8x[¶mHiP͚ ϯe NgxqqA *뭥'<նwsw¹'g~uy',|U %'M|9PfR ɗ&Ҟ"撙2w=T}`|5rx8>BdwɄ(r F~⭨kl=#ͱ1"1Sx}n \6t9y7 K> ox!$QDcq }H%zBx8~Cs6dݜ" Sxz'100644 CHANGES.txtalE@G'T̷gP%!8;<+PdFDSyKH?3U" M^ t9⌓?/5L/xۭܫ =x} 빸]}Js& O13dovC6pcl%2gΞ͓La<^pgs7pL>f79?c} w{sOn jg4,hY=$qr# A(sEFodD@ЋaFmbs KxI'100644 CHANGES.txtгCH5 ]{'YũC]Zokd"joxU~4Aw x*Դ'CEJ0 ? Ha?E= I{&x[¶m6I)8aKd{)Sx[¶m6HѨʢ'2!LO' $xwo*q<ĢbM[["O nZx:tmX(mRF HT.߅f­qcM(di;xǺu/]x9(txsB^8;AN_Eo4iY~CH$x{u1 8l9$@|`# WxW! dRݴT䑼jox{ys֍gX4x[¶ml]̍oe6in݄ 'x{ p]L%,[Ou;{bԧi\?<0o~jߴa$JR1SB=J.n#x[} &!?.n8xze$61N`/cjx7W! dRݴT䑼Z>$‚yxʿp5RLARxȵayL012xľm#fm;1:A/xa'100644 CHANGES.txtl( ł%)L'`"XldȑFw+bHH}"'jxU~8A}CFxysӖНv +tx}ROaGqQLiif#eef?"e,i$Gu`,T5BD4A6 IJ "ho { :D( zx~>X$\$ʐv\BX_KQPSĺ$tZbtX0 *uS~<9gQk DVRM dUm:k-#v dpEgQ~):gO&Fr>-arz)+LKT<"BEִ溢 ZBURp}ZXxw QR 7CA9kXaP`(58ςn_QF+l' I5C3Sr' I)9{8e(m -fOzp `#-r*֓u6nVD+*GLzƗГqQsuZ8W)HzK@)̖,xzeD։$61N`=!G]xYbZf<7PjF";{bԧi\?<0o~jJ.x_/Home page: http://drobo-utils.sourceforge.net Quit  CUpSUV`a#x:7RQtg~?p";{bԧi\?<0o~j:MexSKas5t˦wvsssDtQnu;N]TOA}HK0cDا >ED7p{~<_;}d D tP__ 'EwQ.Т\H#wan$%ÖY01E]t_átnI^FlW{b T&Z 18<3g3è- V8n'X\Ǎjx#p&Xcb]D8"D$͉)aTM'UHBQ h䫄 )1b{Y!{$+saW/hg0(uvv2@Ү:g=w)h^7l7 |T$\֫` ~\nAkV2g8nO(?R_ 8?i/wQ\jC{O _CvԎW\ DGE=?(9A':{7 M00vٮtO{|5ϧ92ү}ĶDc/fT:e< )(CIxc09iHRʕ8cpgfA:,Ke@eE?Zmlߞ&9hrIN%$v] 5D}xH'100644 CHANGES.txtfYo,)^6o#'Ed,+<96Zvkڱ\k7kKxU~0A}sn3x[ui S$7K2Cx[¶m~F,}zfI=3N'ݍ'bNFx%=JA`v1d~6%X Bb`g1ٙ-{+ h!}T /a$=:|[ˍ_EKVpNVb2bNqx]lܡx Rf2v#uFS{B_+mvxjf~li톀 1 qhF8 ni7 98~O#֍Ʃc`du d {OI 1 ,fy!R(r$dei( %$ģd:>r% D!q;lL@ihE܍d< _F]0_ѫ˂VnY!!{aT;A7<:I ,*(w%- ktF@^FchCC8 CݶSJit,S- FK8$Ip`Z\K8)|ck3p#=oEWu%?yҁO*XQ \Qmuan-FqU&Eb 2R0huNe5~a;f {=dQ sUCka6TR8yԛc6uvP3&Av3YTi!C Xx?e6ٮL"I% 9w\/?6_ŧLNC/;m5ՐUjȝ>}fU:br_i\h=cCp5Yl;齱ޘ6VtF5֕W#zJAMA?;8 D,8 ϺuGt-: |-fza^菩B珥°SBz9%{}Gnwj+p5jvKd sc <4h姏\jMLKH_~lPbztf(+!ђbQ13܏D;օi ?t%pߝ$2͈JLrp8;ݸ$JIA3PykROW)T3qe38xěuz \P8M7ynƗ,$5ˮ,,<rˉt^S$' sN2yO, tKIFZ.o%PYO:ڛkKʢT0-Ŭ eQQ /|2KwAԦ g*>rgAͣ 1>+Ŀ1Qrx[¶m6ȳ*u UM[6il qnx7o)qbԒ ME[ͬVx Wx[¶MD5XZˎ;} .I;p-~rx_&x$kxU0A} ƯtRx[¶m9t/ѤM' ]zVj}foƛS Oxd)E!5l7x[¶m9LMisgn[Io2NYތ7 |x:ON  { E z  <!T! not from DRI"'$wx8o%-|y[ c^jViAu$?EZxti~ |*'nVafLNK6Uܯxo-. ((+Q(/Kˏ6&jUqdG!x6*Q\YX^`k`y&>8P,f0A]dCqYbԒ MEfK +~;kDx[¶mFsWeuw>d6\ꆍ'bT6*x[i~ TDRLsr\2R7Se fv|n@x[i~ +68:Ix[¶mvVħ*m˟MPD  sux[¶mr j lGxgؔu&D x[i~ Yj: JyyyJV\ `PR)\0y.6\z6ߺA%Ee I  iE )EI I9 )eɩzPB'?55,ifLWP1%?/U!3#WA#'??[!D!%31(3dmsGݟ!>Sx kI'*Lz F\ x[i~ )y y )EI 9 % )Ey%on>,:,Axi~ MRK2SRK SҊsRrRR2S tSSɒf3x[¶mIV7Fn|<"ീ1L 9,x[¶m9n9{eFjN(xo 5x;AQaVH5LΕVܼKd^ @x[¶m9=bR?֨5MCs7MF (xo6 L6WMLar-" %y%9VF J)Ju$4 %,>-3'ur]F(O>%<ʂW N~ d ˋMޡ=9WkЈ| yȿ|GF<3%$h9W!xKҊs\<6dyA}x[¶m6HB蓃mӧ }^Cd{~ _1x;ATA [:'9x[~0l 6]~I⍙:tTH+\}ds>~H5)o_xU/jggy2/~(9 xQ`e[[K8`VytT5`ԘmVګY>Г}K]C1F.ShݓO&~k+x۬>K}!ɷnsxk:x[_?~ɗ&,i5x{oC=6#V#ɛضaA 4xX'100644 CHANGES.txtH:qƙ ,uӑ'9?u*#݂䖹g$qۑtc( +>j"="xo l},'jW֓cƱXNPgTx0RH֓;fzW(eF~XJ0cxU)jgg8y2<=kx[#\`Czkx~eFUVFFڌL72+Gx:7~kʔտ8`[ z] Y&KVe0Af]hĭ8 lwx;w;ؖ'xxտV*ȝz`ϣK{]nm*s71;5-3'Ɏ"C-vg,ͅ t{zm܋K'rutuJ-m&^}ysCU3<~oCBONԬkPtdKs¶o1^.44R@eXx).-1{j !`z w)=f6@6,3aB;/V\ήntmlu;e%a &*Ae楤Ve0LK>q m L@ J!/$%5)31=F4|zJ%v TZRZ+]3=v+|/0k &xUD5Xjz᱙~Йx]i-EKh51+mz2mۅ*'>5~hi^UgGMf1ݱL•sZi˅wMMRsȅNequةwTCQgs)$>ZU19I^|ԟ)&w_ɿT ^ai+x;βe<#Lx340031QHHKOOgXP٘xMTOvM3*-H,a^ G} WWRgݳo=2j;p%E% r1,i|?dkPE) Gtw~dlLV0|Ғ̜bļb{ 6-P=gɗ2&s@8ߙˬN*j< UPXpWӦ[^le Vx xE%100644 changelogfcIBYOEIK0NoZ `pd˾i 6}Π4t0jJK`ԆYp!DFcArD(#A"= Dz(RP*I t:2L*Y9zZtR)h  zؓItVhR3./bޱ?&x$P{L' V*OJ BLg[Yk vJ5W_Q2xʾqr杌0xke6[AbQIjݙdw xαy[QBpjK8,9(3=DAY,ZZS哙WjRSfPY 7CG!3/-(7,(u~o&2qv.Ʋx rutu+(r)B]\2rR33R~ax+K-*ϳ5())/NK-O)O--)x =mĢ*.~x!7=* ۪N}{'2K.x97=* ۪N}{'2K6 +\>. _^IsBԲlx%Bh,f}nFRxv7=* ۪N}{'2K} -M_mg%7%*.8^YcPH0#H{(xO100644 drobom.8]^h02oi`Bto1'x[_?~C)[Ib^JRdPɗz 4_x;C'oin~i^BZfQq:Nu7oWgC ZxQ`=4̡+AA'IqtT`q 2V'}K̃ma|Ww'dnk>(5U$[$ |xLi噸&_deNK^ZRZWPP\YPYWW0ك-`L6T<\|Tt&L6fTLS/Kʖ)$&g'DrSK2S&ec|ds {5[|6xQBљ0نqô\ 8(\ZV |ML8o_Ol2nOW~_];N-2\ԦDAiP[@oӳ6r Zkp[Od,J#BJHRmfMr0J.GE1+6yT w7l#S§ & Dbo6:DI7v afu `SR4T:@ t ^*yFdcoc:9v]'i1b4GFU=2G2dB[+l#Br./#-vBpp!@Čx^m ERcq!h-: eW%O_'H "f-&Y(tgSmEܦZj~N|۟ӧ^_i7M nLE ֡4zą6vrK0$i;_`bSt?bmn]})Wi]OړN<=aKpx[ȴID!9#1/=5'?i+M[W_d{D?j)\sC3@GsNؘx]-{rutu`J#~ħd[ۡB]e=_rTTƆ͋@DnLM3Y^ªPQ5 N&NvdZfQ1qϬ7gW5ג?~ ԒJWp 5._߰T|ӻs%Ezx}{wFҧǗ $:%9 PD fΞo ܝIwW7MnQ&i0CEfy"Uai2f_DiUeD?AZD\%öjf"P͒hS ,Dw5=(!ӫKu'$L 1KtzQ4V§:jwTgU3Qe$:yz5}MukA8c zW)ܔa~*8W'ˀp!Ѓ0__~t/Ruqw4 ,|/SbTGQn&fsr񗳋xi1@( p43df "vlXg:| 2aL"NyNyR|Ad4* y~eS,A#bvm+&X6 i/*+IƘ4m[G *? OaNG8L d1R>Azt~n #MccE1&(fta70r 0ccIDY{@d ؑ***(/X<,O&vl<;&!aGA` |-؀=,Mq6%L,Xn>#4flDZ] l;ǗVs0Gvk5HΪp|QT4BeQ. Cqq_`NfBQ-ʄV^h5iq[ Zcf>D8iǭxKiJ[%uER -q%"O̿* D>s$CpO xpH{=YY*d~ _#v}D()ܒD"l۪)44|6Z%"G fv4mȱ^x tPΧ2mJ_Mm)N[ +k?g9TYi&U x$ols۶/R͈@Po`* b*ܘ*Z8yxcQ- 'S,|((]d{䶳0cFx2ȟٍ8<4|H'З[JyfnԝSZSwRhH o*dHMLJ=XCE%=!8gGӞ64Rt8&P$c=Z'Y,M$p/K,Q8WW-Kf7f$ 1LHq B@_BdM[VCf)P*$J8E4hAf9K?. O|J?HfjL a:-}I+!M6)@63$~&72i$Ae88}FDIތF-SpnӘ;LED.m6U$ELhf }V7OE$Q'f748r޹͘ԖEQ۟N$hj1I M˵vWҘ+ҚRVVꭩtC* Q]}j9a]QYS7IJՔ ʆZ_naw] Ruϣ\XG45? [f[["[JhbM|tQ-ij0m>c{!JK`D9" Bem? 1锶u ,ͨwM4 !*D_gXk E]T'ʿMƭHS> b\_=\I Twz¶Vl5m`OϮN ]Oɱo/N~xsq۫?%ϞK?}z{uvtퟒf>Jgz{߽)A[mݥYk ={4]V/ޠJ~'_iG ҵmM4>-¤d5a[[SXH3أ~!M8EX/\33)j tH&13ap2 zv'=뀍jZ X*D._'46&أڣ(:8\^D P`L^YN_E;p=0 31q{\AϜȑD¢3ףgDWl68]tsECt֋BZ3tC轍V{ؙq2u|VUۣHri߭@Վ]SȭpLơ֦]e+PSs+왚`Uq1!$.w8M&L$KK"vL(kS9=q"рfBeVʹi𐣧X`p@+1,gNB*i)( TUR]h -ԿѮEL̘jmS0fFIrL G`.?g~mz'BEo{fѴ";!.v.[>+_q3Ӥ-h}HGI;:Ft;68Xd|VfO::TA)ZxzC9&A( ҹk ?jGMaLX ȸ]-vH$HD)Fjx҄Z-mxݬDGsU,z>Pz ނ%h}HI2AЎSh tM9D r+#T:j98=\NZG!a}"+V=G4ӄz lIq ًL4v:ϟ˦\0m}-GAoNޟkYH{]APAI}qu?߻K bD< 2%y= 1'ljN,( U%9 :V̫{häfmn,Y&ͩI8puckocmti64K w6?۫ݏğiM0~TГvKtt|C6̉va,G7*iQVCnJsb QP4 \E鰈w!;B!`ćꗰʊ95ӵ]8f ځ>YB><a~ Zs"\!hY*2Tط*MS! 'X{=ZFr+L>SDs9T Rpb<k b>Tk>T{{;{[ws7hM`6谺Ndk@ M# /l%5Lu%:d.l=5j7\oC_FGtL_\;P{OS75[|e05mō^* b$5|D== C|W1Z`)w5: &m<Yj0jmpiϘtt.sxgZ{ K+Q^u3$blXk&5Lv}[VaJ WX~p"m]acEb|U8JG=,6]V1GGn]g4*a}T| YJ*d%,h˵ (ZwfؗqC#& L:{\^dO=&% (WGN8K74MԞc}Sϱ[Flxr`h#@ij>>zFN%|ʐ~ C.jP#ǚ֐L؟,ad|GLsqn sDD]NaRZ<9GFpcbr3ЕXN`&-?R !$קY&i#?MCmu/tzHkG?ݜȩ09D&Ԧz*#G lXOK !(Ac94=> 'Q]B>aL?-Ͷ8@o|xӓ(l;ׯp=TiyvIZ4As*C1LS1hWzה awIn&:JV 61Aks%F\+|6k_&zՏu( k1Ik+ogm]6hQV6\HlH-.] r9/EglHGPdzG=ҙfrL 䗚M h8bV)1<435e1MD!r̓MYR8 [WSРa0B_ndU?~qZ)߿33F#ؠ!Jڬ|믈0+UP<63PH4wl"*nQ1=|j6 ۖ@XAp-6;(ŭmli3iU mts }Yge(Cs{?ek # Y?/ץL4 $> b#׾6V8͌ '^]j(t)Mb͡v^u{;ۧHIU͈MkT^f<%G<]O<(K4% qEXq}bv"1굧BU ?jdj;΋ް{ 8rę #XkyUXvMT흮r]ڊ뢑NNkFf -ҿ{1&W1P&"SQ#,d"KLqÁk8_`O)eH .2RJ[3"3|nAo"$+"3 腡cf#VO^~9TֶW!lBδ۫ˋ&B'6#],mlE /=I>)t6s*bD]φ2'=Mv[ǍWa> SdLm:G-DkdQ6:" ŧnbA4:$u%!/xЈg4w ދJL=,pdzmSCk61#l7is'걡I#[1YiPN~Б;nIuHh{u7]{N9ˑ! q}|$IR: Ql̎mDlWNk}Mb軭jWVlMͪ -Eϴhmb;-B17ncX6"hlZ:[mT)jSy 37#Iqȓ78Gĉ!AC9ѨďQt[_=O؎!}tI*sb k<|9D ˵Ql ntVis| Ή(i ͔*5nc[[05TʃY(׎>3s{GnSr]~b1s"bg8FCDxLf\є$-YiG^g9RrUW`NDA&wszJNpN!r$8?)F $7|df>4 M!:j"Md|m%eZB)SN9F|z꾥&½e }Kai`%ed2Ig u9^ *_;].A8/d'2A'% EMO^bspGzYyIHxX5rM5alѐNZ%Y1jţF9%yzZƕTI[2=C%l"t{21l տ pWC*tG-A /Wb; "PbH U0Vme)Y\F~ҧPe*^Yv2py慬.Ƿ" I 8ϜMLiںb{Pոi&!RBӈ!5-h"8լź.cpY"⾮xNryy>Ri:<%Q쭱Ƣ%zG41RY*W2Fs.E&1qͲl1XOA 9(ܨ* h:>S(-6|[KU&`]acbMgV7NUU-O 1>XL oz6t mz땶Ĥ*_K ī=QxirDAMq W9LЀ km<l"smZKÆ33ĕުdZVaAR[XhzD 2j}{ Qt>/Q59˥/rzf@po[^EWeL 'MJ"Nv:%΀$}r/FsF \IHђd)(f$D5O5|h(R&ujDY}jd8)hsqzˬǨȻw}y!+gRĄcJ)YVdF:枛|T t9-| Y5Y L в5qq:qe1URS0"y~QrmhWnhBD޷ i{u|%Gwv*eZ׊^z`1.-`Y#B̐K$o&W=lb5U:jVj=S!X(Q|圔:5kIk]{A=wuԭ<#iUtvi4Z8N~ Y`1'c?; V7"ݩWM\vilQ]#G 7rBm40*rDiWNCUkS}O:#5^:tnʌۺdY;{W~ݹCU@R,e8gs!% L &VRjݽ^wIf{]_ NuMbx695紵c6,kf+52a0}ܜj^Vg3SR/aM_8{:5oҶIAeozwq,.=$~}`u7;`st]INtw^.W)zӹ:>zmL \yoQ&*;d_jxo?>h-hh Ik>p3J$#譧eHb|7q`b3~vdB;s?ڣf 4Qv[>.9sKW0^v;9\ޫ OK}mg, qvg-\s8x[j߿j[ye3}Ӗ Fp= !`\ӉA`Wl!b!,|gDCʐթ\}8/4G8~ v&ޡ|I*cgu#Ȕ^K &`7_g: qVpЎI"˰U,-$E&] 5+%ğ Mg&黗,[g݉Kaz\Pl/u~}4mF}T -ȲvҎ!:˥NrkNՇcS=GƁ4x9K;U%90 R1|Y7ZG Zy@+ ԬzʠDåkE3\χN\MBIșp.;X\;5ˊi,oܒz[ }?J/ٰ⛮ڃiL?}'܊bs~ \Hh?ݙ-nh В~`j HWI\6+jøow"ŝ<=v errMt0&nGR:gر$csw:O:)Ϙan%x ;DjHI`OS@sl$:<{wz es}P,P._-筸[so:6o-kޚӼwyd>q[6N($l!:njJ͎ڬnOuF lϮ?j1un_dV Jq{Srmr_b'ʭ e)Mjim}#X^erwtc:Wo!2} ;-9ddQLָ>cWA˫u2ǹIJ>! M\q&`Cgj:YE@R5}A`ٮz~q65GS܊_~37zZm 6%8X+c_^*||h_PE2ZToHq`]?g<뾙 TCREɬkՆ<з =s,x2 4'"ZU^wD}/9ـ!u ֶR0+nƴ tAѬHO:$<%9P_p5nHPJUK;mxc~ѯz_֣26ؔw"i&1H~I$5[9z8P|`}ͷ9K C?gi(ޏLnQ#}=1+}CEH'Hŋ5L0 _J 3chpT3.V:5H{ǢTrKRKo޼ۦةo>SU&EP7]|Mn(Ȣ~@T ˻nDH^',r)aóIkk Jswe}~0Oh0r K6fkxZa,9Ne4JhK95,ܩ ׶ƵFsk2j)& Rin iĢ3AO!NLt=TwwxToEV K )z)zYY/uVN`C4*Mh$MfNR!| ԡpD $+^Pͬۀ@ك=͛}{'mnX鰰-c( _#l2L6v(?N}JJ v{@dWտi4+׵ljR&G $T>ǹ RSbiuk ɳh.*LBQjFM EVw'ǔR.AQGe*h@95Qv v~?lD!"At3'ڇ.Cޙ7<B mykRNBw7Mtnf:cB! Y,o6JM, gօef"^} =Y )Yd Nt]dgԂ^ܽ;2z#v44H#lcS b/}Ҡ-9m )Xx]L㨯Xh)%mX°ͰנBaɆMkhu&7.쮎&9>[RbTW΃eTBMA J18z_+ T'"oy(1u!y^2ݳN86V?7a{XAcwƉbƮ/O՗0k )7ÊV}QVs 3͒sKSwrӉKn|;7___JAZug1On?KƠZMŠ$Ʀ/~NMSg+/.?5{ȴ\g>UOߺ<:ՇK|o6xW]UNJK[Np\eֲQ(ܶә2wfD?5^Ϣ!ĿhOo&B&>"QϝδҺw=|s=+te%iV-%dN$R &F3T.zAnlܞ#{Fw$E]2ݷDHQ9ziwv`L절Lneja-1eDTGңhtR%aCjlJƔ5Gwɖ7Jj_B&E.DZ]ql'HE}h $X1$)n!~'΢M<Ge4F1L%*d5'+G9 +rq9G\^ՕGv;L7s6\8 %3icJ_B=Jr1Տ@x=aT&0 7-0Lm{rڀcE5 $} Fy~!v/ yM*\BDŽG½K _ ȧ5ѝ0.6|4K߳;2Y[C ڍclnN޼t)dA J4|W_;bGv_V9'{k:su8owQ nf9)8wX|K[8J7os]"F:Pea 4a E]jD=!hjdRΏ/.eפXg ̂y;A8`w6s -j Mgw nf*J>'V:D,X}smpm W'{Ʌ]\u:jhT:i|Q[Er[{m4"3B[:N7:sJm>3"lZՂ9eѐu-̋AƜiu}_,Dx :[g_^jU>Kt|-xhbF> ##}J`Z=st:gZ]` 81]![} t:±ܫ+-J*wg]bpVQn̔ 8${׺Rhӑy&"5[|I9!TP=~UٔfF%-eFu$ Uݣg^;L7@@wk|]uK)~6HO5 MȊ }˛ OaaR%C]%]5U.lH[lx}iQ y2s JJ* R7Odi$g$k*dC|2KB,+.-bq:K߅ol`Z~BA~Ij^IfbBfKQ~RrI^ StSʥJ|UAQxSOAO $XF|ZVe)-$J b4Ȳ; ugcxx0pً&z`8zd`bŘ~P 7]xmyi:FtWUt w\[p̔t @#( %9FilDXAwk> ®!@H'I­'0BHkr'ia6nITG. E-!ι&JPE-Rv)% 2ΠS!3J*@8[ W.`l%ܡ j\\ia|ּ޼./&ۣFQ_#Ox;i~ YM 6_ey= PL_qxǺ+9'51jb}VDxVs knj`KE5j.x[ȴiBaqgeJRrW-#|щY *xE%100644 changelogbEQ!*3i%D}ס%1bjvK_g; j5Ncx;-S (?)_$3XA@tN70OqjQFl&x}:;3"@x[ʾAQ4'+(59?775/J $5eru ?xR]k@|ׯXȃlpT}))k -bB(i-nb$}(^N&k#Ao҇wȼkAǟi!dT>\B oeڬr5 & :]," a/svJd9Hb۽4;258xPU 3d_J=9`|)v}XƟ 6^mtBӴlQ0 %R,P9 9)IEouAoYhHIAaaRHi3Cn)cT^ojm6ldQNu5NtKRk%5(R4Ԩv+]95-x˾m2S}JbIb|ZfNjB4^X_YXP"RVWkzi걚:8 /-.҇X$,0LgA9)L- >X.&[?Sx[϶mTT&c~Lwkx[6uC-dfE[9x:?[&_fQPw)OO.QWq- /xc=2dKFC"x9JT 'x6mBD cٺ\+]ĩU̗XX/i}IkrH<\Y]d79B %Ɠ2&k/D'x%1N1EE@կ.RD" H {٬Qֳ8@CQ8  N8ͿͅA-z;3i[a)d#):uD &F4g(l9r98|Ոހk8ᚷvzxNa1hX@T;Ғx%*S%&ԳDb8wIn[*/̕1dFVW`x[~u\630NgJNJL.L.Ӝ [k1xzuDɓ?{xZ7=* ۪N}{'2K8@Q~&w100644 setup.pyԊ̷ Mu1tO \)xV0Cٹm[Zܑj؂x8Q 9Vj䱹c~/̹>GsrWi#}Gxa"Tڂ~GПW$x;~ YM 6_ay3 PY`x8܇k9.N 2>%K˭4.*T/f$ahGx!u8鿍Qbs-C,L}}xY[lYZ'29$l6g3v|tU_wlNbǎ=]OuZWWTrOJ+v#xHE!B@B  ,Z$}@SվeTs{??կvKx6dljzucْ< \5-!x ĶmxWխ{ߘ~_z{{xsc}y}{k18p-;Q˫;>IH72 l.[/* iCIV5OrzY\'iB'v?;Q.[}عJm#VyRHS$ߎBY2m4H~`q- R ߑ=&@"v|?=m'p".(]]\c|8VG=K7:yN"W4Q0nkwpCc7S.d05z2Dkxuc'E 8 (m8,H{lxx '(L+BJ$'JZIœ[RFlR٣;; Ӹ.`HS؁Ea(1(4"DF* (n"a"4'L3{:O1o=w#$`?qLS=5ӶZo[yFe,b1xێH$wDơՒNr>ɓ4XҤLzmNEPK= oKB:͛ƕgDLa'qOz\} z'Qz5 #BNS%)rSB8qTtb$9ˁd>GkzOvB7'FM^>=:V!9ˑ 1#"`w 1wਂ8?x|w\_':Cfj0r|IhmZZ_Z^YV3:%F[oP72e56Wpk&q ~ꊢVHm?^"I ~(bmB߫[4hٙNFKc0l,9lH XioGZWI@!)lFnQѸ=KW 4%IQ71ܥsI8A. Ir5XG#*@QjY `% a틐?Y]0E"[qa!8DaL>B@2*= #)n 2 1\~Uo+k'T8?©+UX ԟ ۗO/~e?k x[*|eR5z{HK?_b[}FzTR_|ռb[{7(zR<:u>U[<hlX}O25~xb4Y7i?/·`kVw֟,.=T;mOR@=6삻9yB&ő9(L*V 9!1xjh;]} 'a ,ӈ!Ý3 qtCeGw͝E msk@,H0M|MB$8]ۺgk"*c\ikf X0߭I =Wa6R^AmsSNѝJiūj 9qP'P~l}[Њ Rpd5M[P*g,t3 L-8 }k/:2s}I#auHujIݸ?=mU6q 1}W/TJ ەR2T9.OOݬ_N*U2/1,0Nvi;sp`8C?(sD0K獤w%}R"j]"3; wͽvZO؞Ιܨ>9U7 "Hjj^̛=ߟ"x@LKh. HPHϴ '$I8*U:¢n"QF&N#a"Hơʻ O{֏̈I5%=D*7훴E}8\iLF7mzx;>Vg=mC[-@f1NI*wqWhu#B$wBJNMiI!bϽ8bFnPPf۬!zd.N 5hiy5ŊΞ(d3i1i[lE쓯T"Ԋ(´y{G7^zɮUnNWۥ~wn S@6g:{8R\C]tbӜqq@~=ܛur@IugKpjRw T$M`k߿4V>%otAIC`Ks0Fs@jʀb&,RX9XZa^ FR&E} X4q7$_\1%  ~k5 ET`2ھK1;?4}2$o*u 卭#Q%H6gÜi،g )ƚA!H.+΋<$=%aH_5CJ]]킋7?.>1*-?+xMS=oAClDL)i@) (!D۱nW%*$J hH .gD4{{7{3Mҗd{K4.(qO.*NMCH+)Gt%b]*MwV.1UkVyOL]YGN.D v>2ڻC_W>6>sƣ '~gO*,A88j ձL਩f:Rho5M* {hF{meA"mC\ed=hVACZp@AEƃpLIZf7f:!Vؑ,xd`RֲlI2w^Yj^(q 4:dT  Hɤ~YTQ Hs^ieqJ!$ף!d VUڗq/\Nwg@|pEӖp$S#::_ϰUjcp4x1sڭW`wƔM1g(!EfUUГHH =8JhanWrVqJ*dD\MNHTND R9rHܸ?rjI:{UYb0f68Q;/*˥Wf?cMxW]l\G&N\4!i֭sb'5ݽ&8i8v\ ww/{ܹlA,T!"UB H x<"DUB xf8 V4ٙ{̙s3F/f3.sӺpܐV+*ƽR>?k%:DtęRêm2ï(h 0)4 $`nғ4YMm?"376Hd#nXha&|DX.jje|kCRO[nӌÌQcMUvgdx-9|-q8N+38P H';1$]gFݐ4J_8(T>ud8iXA\ _)l5U:X{bLD ݍgkLSa@lk1~w LrB9*aPEi.uuݕ{Ro bwDVtU8eKX)(s,L|xpd BCx*䎢oEA-+LV1}֖bc0yͮ򡩼TvP)ϋC 義g0??qLГ/ \3wa 9aI[!)1yR4Qc2/r;xnԝL'KEWz_'U=4UWVw ]W6(Ce-CefK!Q Csl= Zi^~P}|oDg+G6%/ʟ/.eіsyy|ZW)xV;T8__Hwctl)Wv7}4*5SUKvꚎN݆]4R4,6 Q_|f^os`2U⧑zɢm̝8x(oqyq4?Q*YM@fam{ȘV7fN^X,p4"E@ghG zӚnYeuDB@*4/PnxU^&L?ը|Gˆԃ;Xug8PSZotg ^9 =kpM焂;[e*Fʼn^Tl.-d>Vs $qx;Pb MAbQIj*%yE: ť99 y9)@U% % )%E/2Nfق= bF99RKK2s'rzqe(d)(LNt TYR\N<#D2T!/heIBRifNȸԼD&_ `JKQ59KQar+&KȾŵq)n&< EPx: [<9Ro3; *7sp!)$Ub x;Psz,L?Yo`0h^kxb#100644 CHANGES82iXX"dI'9EEƦWa>~Wt-C4kSY︃ICW&)@xuVr7+KNQkr\)lRGJ~p!A"rtUYFMfL~$͉d#c9ÂbմaKkN!ޤ0I9}& c䑝fn(vח9 QZ3y d#qɸh㎬|NcN9;;B-W5݇?y mL*0-k8j`y5@ # 8D0Z(p;g~0zBvN`>U)nߑM92u"]th)Dδ;CI0TN98zEHu*=1֐ !Zdml?!u7%# 2܂BzVbkE|#RacKϐȗ6'ޯkܷ7rfEDH@UeM색'3"WԳ- 8(AXgqsPv~[$O2NW٥Lw.`Ԩ5ZA҂q#6kcCbY `Q'*WwKbD@0Z5oЉ`Dlv`̴A2pxVϓqdctMyj;PaL/ډFCmNLz/Dkd]4Vݟ5X[9ԙzm{{SY]VV?Ew˕-J=Sy75@p=^piY̐o/_[sqF 1gڬ;.LNHWkcM:e:[>9a8F,GNJx/q 8?ڹsjĊ8'4ȊBetz.<6 ѲҊ,X~,J앗LQ(n6X^dv2;_ N(c"ұUߚ^N6c/cu<iٗ5j[!t5em@AGOz\5>YF*%1TXƟ9!}b qSЗCXͯ 0Q|~! IFvC E{ qꦕw6TR"^Qy>y;.g2 `A,.'Y#֊ExvAڦ9? 8kx/U@D@KAAWwf&]Q c gQ L !S]r MY D)؀[5EDcQY\A#*aQY;@*cQv@vuUnVCxA|< N C"V}DQ֜q j6:yDus=ƭ AP_^VPZT {PsdixeTnE$FBB@ Tĸ뵓B)^Di6@Be;zwfX OG qCpT#{;;xsK'͋EZW[ﭏ^EuI5/v 'i_woIN#vF:_y:<|_:o"[;nk灳5W姵>vo=_p__;8yrwɟ7q! 韴U@ySK{t6lNx{$wNvC:߼%3xv#100644 CHANGESfj?8,huzzI0kZ#9Q vw m߹a 3% pPgr`b Durڱ0 Fl(QIʶd#叓H.=~x=OJ@FU䭥 ?pӅu#u?L3d~!3cʂ'%;ѵ+Oiw} ot&1y, 4I)#M I.ep]V דHT220TCQ(+*U|.QSrNU @9OsB~7-硰f5)-팙I-JՈ ¤ FlR/8;c(ۏ]h`ҧ:&y[4{E Mg~x]P1K@&ZġC)(A jG;\rl̅_nswsP:pr8 Ktrx{{_~X=T U:"ugok:)9+($Agz)M s>-8ON͝r2\!nLBχ],`$aXݗwXD}Wrq!ZlA;Бj4FÁ<dv,Q8?UpR=خC WةAboaί.\N65;KFH . lOi01~sx}Vn6}z"9ܡ:$| vZEeHꞫO',%9Iցk]4u.$9)/m k!I?ϯ7WPZ~LyBDV62 )[YR]xeJIY-La[&J<.(ֶU&.Gn6JtC>Q&;% kU3N?yo*Cߐ-PJfM fC':q;^ 1.,ĦWY 1;,.4^46#$z0͡c\2*`8C'c,5rBmr W)xQN[ Q*p8l$F=%u-4X!h\b˓erF;uy/+Ymr']ʸGT [dZMzBBWX}Izq xQօBPjd{jU(KپCRD2bBY\JCm>IJd Jk0TIzXP b2He+}zqs[G-Bqg _X_m /S+:Vij =އ9)4ӏ;fK/5߬an+ifj 4q G||>_׃ n!V>zc}\Q?I7<EhaNHlPF D6dRGT +OO u9øqm\ȱυ^s*zGձY退h34f%6Ȧ(Xn޼鳙DqDǕޑ5]'oܨXd@whVT;u{e@zظHe"!x4Ԣ#{Гz9)nMw,вVոrAb- ^'l߸QmȮuop{o%{-oZ ͠4&\?"d$Hٚܶc}GNA]_%rrqyϢ0+Nb#*==|gG@ڸv9-"uGDuXdĒͬ8YC/tov,h'A懰]x{(<nQjYbnBJ~rinj^IbIf~BZ~BqfnANfZfjD )) Ey)U`:`ļTļʒ̼t'obrqr1lJLs|?.px{wwY̙3Ovf֘l컹)#e Jxh\zpx&/{p@LDXrQ8 MmǑ"(خ4.S 'cz)>dO1H5F'xePJA<.&`ecDIxAm!4Z6ɚqXXv>>>` Yff0mGA̱pٲ ՜@ ? ռD;0b<GʛjM&Jxp*b.Z><mӠ ".;yk(m5F8h" X?>mbsq)` +. >-Ufٶ]|,U3\A}O 14:C4_h{EeW6$) Nywޝ2@rfSB%Pc<Vtځ|̮pWfQ'TvH4>GΑYxEjAljM?ukn,Y4+(BtmLP՝uka«_7!/>٠q˷Gٮa;`8x<->2bZm[7ˍϽG` :'.bS^yB,eS}&6HxoSsBv .X 6dlK"3bA,CoѪ,b89BBmfS=rt֛M601ON#YXP_W_4 F9ngodox۴i~ kݹJrKJ27r ox{uY".o搵g|Vvrt&_RTԜb6;(xb'xuFIse۟~p4?#ۚ[DUxA4IVN Ar\!R100644 TODO(uC~v0t60#xkdƸAyrxk|+1tcnV x cHU%͹3mLہNX#x]᜙"6#2׃0hϵM:E 9>.gz(P[:|?ob@=ە]QhOL">A+ץE 嶣PE Hc3,Զ5f˨]b"jGҐ첢B?I% L̇ɑIQ!D5GExr(x15KsaeY*3A/R}s= a@DvҍC6B^j'f LH% p&z&7Z>-xcrzO!s_x/s/a( OlmZl+&Tt' ×Y8y1;𼚛Y{]UC--וfhӭ{j/eP?x =w^ޣۋ莚jKJx[itɛ\&ݬ/_eJ}Pxu*^-kf6IIھ_zMFv ngxq" ess2,GHxuCHy~|pa3AlxĽsdiF,q,,;Kx85|2QM]3AʩT?C)61pv [+xyiQ U&o3<[Ek~֪u #ox[ikBBfaɛ\&ݬ/_ hx8Gv9.hGHet2{{mAʩT?C)61pv #,Y9;c$ռ)zeEřyet 2J232trR4@\M%ʒbt͆2g':Bx ),$Ӭ(E =2 l*x["Y`i6lL X1x340031Qppsw fc^jYɫ\ Z^ZfUbR" Qk:5\]UWRQ8ӪblnP(?)_׭(?D3/iXi);?[!L@榦z kJV-{^._Vt Kfpc**6} /dUnEE`Ǟ g~xγʃ![ O53դWg{m/lrIH]ROb_|Y"Ҽ|T;GUTQ#XEy~|paPA.`UQW[+fOp`n}TU?*U]7L:t_W|JJfb:0Ȥ".y x ۾A,{P<˰d{z[&'u:̳" = %{V\Q){yFri\M)L-gغPE Wj]5[f3A E@l]GNY`IXßJq=}Pey)z%9 Xԓ>i5]&$_Ǡtw>_(ħ) 58_?ϙ[޶^a+067&xZms53A()Im+V9z3ɋ@{8@RM:gl{lm@G+_Qj2r82azFhѭh4߆cOF@kPm"4#8x};Ꞿ=88zGJC(Gl" H@FXp;9?sVʀsRQzF z*пoGX;gfj/ {Qĝq"(=Pz̫J#hē x!*h\P65#y34&>8>vܕH]=mi;8$dBq'h'#F!8Mi֞42t(0p/i2B3 R!DQ;:Ca@Ъ*nM ^c >Nka-D )Ge"%cU݁ 8\wjp0QS jB, 1BL1켵(EowܘƸѐAڄcZjFVmZNjSgr3eܜ,B,uH}qzg7tٮmͣ` i7xņBKn)qNd{$@D{9FS a|í%1V1ˎSdKx8PU5nEO'8d&K1 Cln%r\^\\ [lA_3W_enK_o5tw!mp2Fr0hݭvPNPrxyoi>3FA |1HA![\4gƙ+]>/wwFkpyv;^W=}SC2;wngݫ bbr{v Lħjn# `uBgϿ`,#L+6 @1b8 KJ暈 3eK#H~ _d˛f.g*ڝ6QšY\ &<6skt2Fo1Tnc/AU4VZif [)Yj%J]jiaU(OEO4kZa"܃;˗mzڃ77'iԣeK^hT"/MΏ0N.Wduonf4.-źB#;\ylR=OrNenS#RdzgCBu%bZr!/Ũ)e@dOlW 0QB@0ʐY}^&0ӘcrSڧ*ju9[O/',NY*;:ZLʰW]~D]?5/net:P[m>LL_Zx! WdbJYo@`/ĥ̞ȐoOq WgWFZZ {[ fP7-,{ ]t,b{{Z ,dlTp|!ɥ?_'achG&uy\=>аԭ1{+m)!=[Fiu{2`#_ קs\`KESVL5=W 6ْr)#ɏhD+-lfCKQ+K'}?;COr!4ˈx yU4/dZս^/"?j^ sW]Tt%@:n q r2jLd{iT*b:1|6'Kȝ庥i0gl@ܺl\e>뻹*eשBvSL?HUDEJ RB ͈6Y«)IJdgfEUߛ|’wK5cG [ioK = ~vD KAŖe:AFGseGt-\C<\DBRʾO`Cz-p/+GHɇejoAߔUDĦT$siyʌ&O*yݟs1uZῊݒ931vE*p#@>bTr5/%#aIzUJlZUh*}]^9̪w:I@TI0+yCYXeژfXۺGA^bbV(/v،Ë%srF.σ%odawJ1O >\B9؞stsK*VnyJ\4I Fdj|6U*NѪf1@HⶭK!L, e0ʧH#n;H4/)ڏƓlr^Qƍ!ARxl}#2#+ 68"⪉A>^Gms+) Ns{_j.M֗Iߥޢ2~]fN( BfF_.I@ݲlŇJ%)|F,'X`lxC0XNEC, ꐯ:zC7lE.&WVL—-WԱ=+g{ jG~ \* )Īx2$X7Kɂ?![Y~r Ȏ~` \R%_"L?;1U跰#AmKH|Q?Us?YyPnY˟?.:;Ot>g^(aA_+|RA뜜\G%ǚCoU3gT3Xf򑸑EZxc9L!8/sBN Y &OPc\&/Je#\j>ܙ%9 : {տ0NnU̬ ^x<5PYF&< z2f+.}f̪T[U #3?>#J$,T_^gYcdLٜ1kAaf eauq<*q8xJP [T-ʭm mR INbTN:z "Bv7]|7WqL=m<|jmβP)&Cgh1TA oRJGR~✏"hEl e`׉Nq,x1M9 س =mD;˱'nD_frblH-xIi[P˧&yZn-L+0Ϥ&D0?uD 1-.,uT;=p/Kd"ŻhCu`:gj!:P(}.D lk W7*jx[/frJjZf^{oAfiLb i )I j0paB1q"E1 LD!ȸ9O9rKDXB'o|h[TͫXUT`&Ja?Hb {*r1)Wދ$PMbU_SPDE60b("!3YB] Utsz AQ꼓kt#i!9f xK#100644 CHANGESbR#_#:=YyDg֮W+/U@eE3100644 DroboDMP.cCNf$xUbO+Ts[NiFTwŌ ;!ڟ ۨŎ_"(=SO"l xk|'a&MW#J61x} ӆwE% .EI. 9KSsRlu 'McUU&':N~l`j5;L:] Fͳtbz/ZE6 ;2O.5yqhGFF7="-'p̿ $]s}&dUfC#%,>-3'uɥV+eX>xB *' 1.2 drobom settime.135+f{1 "Mlxq7͆B,(xUD5xB5lٮ:1̋9Q"UKx340031Qp)Ou++54KVZ l|' HV!(1/9#X71 8͚54/!Ұf3n׷(X})rx31xxC7;^{啈EƮ,&`uEzFz U'nq ٝ?Wb6;^3])77fptPu#<)+07`X,D8dXvɚ6mW6x340031Qpsgp1 a){Ƶ[.s740075Up)O+d$Z=gʏrfN1V׺P߄s΋rl{'Ȱ4dL,+TL|i"԰ WG_Ww*Y_+1h5~lg!q33('m,e:-=mgY'BVQZ`|:U6RV3C)N-)-9rEΎܤަW{N, y) x;qiSbONE. ȴ5iE y %EyV\㸤&Wr)L%'چ`@E%\\)i 9)Kmµe 6Ģ%?JlVKc%ŸNF͇Tc635r2nirf$ Scm}%dͩ6L8yDOG"Oxpq {X&?d``y7:l2͔Y&ǪtqLΞXZLU ƙ.TartrR455'SЯ.Vvy /fO&dp࿚O):C&Ϸ{!ŊU TN6'y$U~wd͵s3e($o̡~qJ lT`j ((O!ZA .Iiz '>-3'ն $5$31' I93MACI(VVA8EI!1/piM&Ne VJf:bJ̙ VYBEnrl\0;VSe2Z--5y0ͺ`͛c5%i1lжV파vr on jrFgh) !\n49xɬ-2g7zUz V ox[iF *]UD4ң bmL4J22 SRKJ"E i9): \OޮʙԮ V5e6ykU&WR@9E&k8i@7KhvJ2"xu?KPűVQA)zm6VkU8;RDKRiR^-uk{+tsstru:G% *wy;{=݄Q^`6ݵ><@4@)H@]bT(+2$&wRaYF=-K#=i;5H%6_FuW"Ē ">7/WSj 5=.7,Mʈxң:qJK `fx). _(VX롢Qcu"b"vK kCKJ폪eq@{Iͨi:fBpx>Ď1 NĭKhű)&8/5cʯ_ѹ[K[daTg:x#­׊/>y\ Vl 8 2x۴cӆɝBv{p$*hhL둓23/NI+JI,LI/+#&ĥE%{eSR&g*1kLUO8WO!'5D]AU$37ו\3 x]KQQO`Mt0`@9(TĠ]9<3ɾŭ'EFx"" ē@w[ā/30'uD.'x?)L%=.4thCR Ҁ!̗͕ .p a(MuCMj l@+%h&@UHs! &Gj;.ٺIOG20*ے]]UZB =;CIp8]-UVڰTn=mZy,XI,Yó kkofTLd)H*O "p"xe2q1?mtnb/>) ~ȿ ~cy&`&qM/uM1)<1!Y,_4bM$xۼB G'?|;aЦۃ&/LSȎ65UU(I-K͉6Uؼ5DqPE\*9ɉ9i PVQjA~qfI~QBZy^bndpSD&Džެadz$^0x;i| ťE% z%)U i9 %z_2)rAQf^BvjNYbNid sRblm2rR@9yٚ v &V !jMjˬ& v٬a.x>k.ӆ<쬁=]uR+S JRKJRRKR2Rl gb|̼tT"vvLbI9y %E%z9?FGOn-NIK+H)64Q25 3MUzØbu-S*q貌1v q tzS Fxvӆ eނT[&,+1yu&3kO^m8G#(3D!#(uZ@*YARʋ2KR5sRS Lc47՘4YG'MSsSҊtt}\ ts &M囼HGjnf=;>6%w'edA Ex{;iGӆ̜.N }Xwlff \{rrd9 Tv1e(+$(+f$&((L~#ǥ095dr " %}48:_jBtNӗWVRo`4:\aJ~qZd ]Y# "[t6[9PeWKg'7d4u iA 04+Q>F@dB>>&Ũ›"n12gM֋c326luCejbBIFBFjbJjssBJB^~BnbIr[~[RUZTT4']!DO}jB?Nmf['(qϼ~ͷγl~Sm[˴Y(f ,Z7^NxqCjn1ʂTĊҼ*ԲJ̊ PPW_[WZ5y4 H~u |] |gxk/CT+] }Ϙ )x/Jɡ“LW4{sbF>A 0x:0to 'tb' terabytes14e)fErratauG;yKHxg --&ԟǥ%)e`vAQf^RqRNjj9Q|Dd] RFw=r Xx;; zy% %%) %z % E 9)EyՌJRlKJK 5윜<|<t *A)4W_Z6C#ɛC'?Ҝl`;@z]) EtrR4 i 6Gs UUP\m/˝[ M>=ՆsP:OQx{[ zN<}&/ԓ̦(J`~CD'JI" ]Biâ<QM2MJ!"u:Pl15H!<n{-O{F2_'4:\z/efWGz\7uJr9_?7i5j>:Lѓ;[ukbnӖa  h!D#9"R4E@D6u`2DN"7B 3a@|n^dViEУj8wz@57;vhiT 9;ҭAE(@ uʖL6VgmR$[/_T\lM}]} gi|xty J7?ǹ6+n,J\ `_V^ ,h%?yd+qnBT;K ҋSR'D{_PWZXY[Xi(3DA94'˚$mY_,k,G6*mޡ~ywuO>cNVAHv`b!e"|-=/vO#~Q+#L3!4 b}$v 15^J1Zdm/5XC,Āa6%ueJrbH\$y%jӎg%7n hnc޻o97s"%IS@E_sl-w8UaaSu z㟙 jx;q< 7a^Ҥ e?7|X( ۓlW20nLM5PS4G\EP$kB%Ĕ!nH@DN%X\+kK]rw Sw_ݎOIkWDuG"v Q<8śDoü\:6LVFZ6!ަ>yeKbSox,^gY"˃9^6B%CgpSM  b ʿ&.  "4982f8e162w9'`+`Aϥ_ݶS+)S|/' .rx+`X]ӊK @85'M/-$(?9X ?'GCSV/?/Udbh*.I/-+JML)D&[PW_Xԗ^hRّoBR5&H  dN#$9^XkY*"&_9H X6UeK{T 1p x;< 8=JKS&oaRPPRRy@mj``0N(`0402B311q)LNaS+I-K,KQp/*͉(0QYAks~^IQfR)HmBZQ~P^vYVk5'[spr日jmQ]8Ax{6< E&#*1y"5Dƨ 4n+x<\ 6+{2x{:, ܓ&6lFɌbM7SgRBOQ>|u0(Om1Wڬ,Ȗ_3Qui&d7g/cS Sr rQ(O,IP,Q(JM/Qw QT䚼AMu rl%:'?7yssK2KR56)a#N҅d$xWKgYGsC`3 Τ>A̲ĊZn,؉Х JE ahLok8-lxKpnNqڡ`ICԯsۜ B]CC]"u{_Щ<y2헓(8Fvo_C7Wq=egaeEƷp!Xo"..DS}\Ql2 `xHpg~Ţ]̤]05=Ah $cK[M']',3޷ T$(Ti DMPPQV@jP,\y;7ɻ-#[Ib^JRfyeFjl)%c'qmaLY;5E',qyes'pAk.'J,x{}"d7;L73oNVg|Q3dګV n7x;r"dC7xr/xZrH{1k{acbܸ@tmu5BҨJf?.U QI,Iĸ;(Uee/<]t0[/Sg?IwY\@et$(E2Rq@0RH2 H7M0hBӇ/s% ^3U2,( g2IqOvƋ[x&B$;mF-hL)<5T*ɣ$YS)cvۄQY%Zv{Ub) <'^PSTe ~oadxY̼بlYbCȱ6^lrK(AC* ;^ B(B]an0AIl(46 Dz,*Ӗo;z8юwi:rڿR\ϼ4f@;Ld+X psc*s3 J}RXxnm,nG,LM@cfeb [L=+YP$A `1`xc]| GHhG)& up0&7>"6KqpG-Zqpf’ZزͩW.qczѕS Zk}#/^ؠZd3hZorX<' ־[䀿UFRDv! tIf{uy"HeP'Q1=$7ҬuƩp ~taU^C,HD 6fA ̩xmXO ҙXѲUvKQU$8rzAE*8 C,bƧOaOX)x p;Lm,IÚ.sm֖p(㌞&pPF3ŭdEK0ɏb:I~o6Dl|7GBOyʣr#噭oC0#.'RW@|2b4;ϔ=S)8 {i;yB~2C:y⡣2C[v!-ɥ UJwqLB߸=zvO.[ qLC1$)؃xݐ;:uv~: 9ܝV7>?D wܶz'n o"g[-o\ PfVJѿq`_^ĮpErZs]WIΨ4Dj)G Pbv]L"A)gex6dj.BE3(c\Gxk,$*vue%[Y*Hj0zjbc w4{"G@:D+ޞհsX%~߿9E:8V{*HCZ4G :p'28;\ojRk@[Y bRc1DBRȁ%83?O [aQxz_ʼntǜ52f c6?,O+`Bo#8X۠MVoN-VUPyQ3%h\1PY1y oN7!,9U N̴ Y<Ʊ@u6f4FR_$ HEdʠAs#͊.mDbrȈؗ~)H N$c;;e8Odlچ{%C{%)CTbjΊZTl%Z8~ҖEmnSZ4%rlE [5Vx 6C"+~Hiz7aZϓ?`za?g#ʶ^l;]uG 7g"<A@p6vϖurqX{H( Q7q6pNHy0Ԓb4W!lSp)s.-Q*1_0y?BtcŦʁY `d> ^կh0C.'aH×dHt;hDdz}_4nhj<4Hp2&LwZ0Ǝ/C~O/T[w7VlT^2&~5v ]n~=lwVL-*bpu fys25xljI&pPq^È5[--<\ݰQ!K[bvځ-W?9vǚ6>$A2 G m vö s4ivQ)ˆ&.%Ì)ňݑB(~0vy &6rjf5/s%=HE81:TSUܫYB~_!uz6mknUIZ}Bm / 5c4ڎsF ,%تf$R5h9pE-",d ~dIb xo-۹ѳn7/mg&G|@~h O#TƄr[7c 6'Uĥ.w2nڗ}Nգ rR^0qƳ7#ݪgv}D'Aq=ozbns>Gу-E%%EF^%i Fh0M9r\{thz]2W|PĪ?4~1Cq,KH giQ8/@LU[61z]Tn.g-ۢ%IJgM(Ep r<ϗNۇ FiOح\ưf-OhdűSg=k`/{Ag T[ { Iwnpبou,YK G8JEeaֱhw)o] ,8kYȁӦY=S(jv޳h8OU6OHoMl(mFLs_r3|yѠ|Ajf.dקKYSp6$>F6Tb Ыh*ߜ X JӀPE|\J^cKIu%ꡕ1:=]7q jʜbcU} R 2ƑlՈI-4ػޗL>]҇).ljzJU^G*exk:L?/U!91O!(5$5E!Q!'1)5G<$ÊK#473/]$#U!%8[!XA?%L8%EsbfVFFon\x;ysOxFbBfBIFfл\yy%VmlxR K3Rs!",v 6 @x;y}C=Bzr2UHTHVH-I-RH/R(,S(W+NUH)-KW(N-)-&⣐_QRXZXS T\d($ /(J-J-,,,I[ &?O7%ls+fN]+8K*xM1kPCnNpf\E+ ]x>bNtl ]_I6OnV| Lhkr#HPd״YNBJ^Ѳm '{#|)Gec28}&OJka*U.S{绵#DL&^:0Zt+nRhYx"Kt..H'8x]RkPj&휳9iJ'AA E< f`iὐ:ăG/*қŝgiGig&]~~ϊG23es < W<Yq27?x^z@š[߄3N ~%Vn9MN)垮M]MP?O?"J=_SJA4$xh^O1z@C`xսhp׍KÎ\;ziE<ö$j +lmW~ :j.f{EHZXb O:^WT8/qۖpD਴k]Ԏ*xRzu9s@DLhg{yCkUm+`1VU_hAxdqbb~D+/0)@AQf^^V~fFuB)zE)ei9ݤţsJx;iowzvlĒ̢ĢT ͺFŞx;x,83ȳ+L Y=Y/ze#:xMN1P5+? t (J"E Eݐdf'8!' cb xvP= $غO/W=WqNp T<> MKHEt Uq˛)e&U#6yyy`j6ycoʄ\ S<^C6Sn! Zk"ҦVF0*:2܎WMb"0X :aɗLfi0Pn򨡔&^^1yd0.9\ڕeC=oUCYP?6ϲSТ/ "vV&x~"j#"nl?r*♊gJ 9{#'|XUɚOٟ)c.n>{]xsBk4|/7?bS(-NLORPPLSHMQPUPH)P * .}ZJx;UsdĢԼb҂|TDĢ"ԲT̜T=Tt=}~qJfC^q bxٯ6bc`d5ݛe2J$$UƔg)'+hl~΢>ُTޚV|ݓsN>ŷ~=ɑEy% IE٩y iE y: Eiũ % E\ ŕz%71o*q?BRE Q'~Gnᅪi<B*Ta@(/bVA,K b Ġ t+Vtj>3jKfKx[++A{"wmʓpsd)$(*(W%+Yq)(L5,.IKIQKQrKJuR2uʓ3RA҂ĔT%ݼJ$ ux !m\66҂Ēk4&RPPH+/InV8% ̔L=x yU|66.ԊԂ+ɇآ+R+2K447k?e|k9;x*\l-KJinD N qJfQf%6dkιorN,QRPP4R&WqCmVz.lQx[.vAtD/#ϳ4xmRj1|#J&P(N|Z$$[}Ww6hn0Yk;8;E1󇠷Ml:’ߴ۝Fn cO)I^(λq۵MaHXVtѽSqzx1 vAҐ-ِa0c DٸzO1CmkBJ5*qRq*#{jѵL]xȬfkw"6gyW>tk$'mbW3Djɔ}8K2uC,QYQp] etvx;/k&)>X:atE<ن-uVNT& ]kwY;T*0 Q#T|JJfb:=~P-+{J(C.& +&e&1lł'cÏ)xxL s7rby?iiH[*2S:O}4{Ǖ;}o P,|CBs.c)UIƚ›T%+6/ZYx/K\#îSRuB ΕLh9u}le|CM<@K=al;*&*UEFBRAd 밑P=;g'oqe:3h#~L > %]xGND%SL# |YQsq=$C:Qgtx1PEE1=` iϰXま{2aL~lL]qӳ"c7w&)U848N;. xkl"Bv4 h[6+%lyjjK6H R ZRMN`b2B![cO@jE5xwUU~A~9*K&P:  /`-C.3U{RTT-rab&w ]4R$fڡ4snlyy.OQ&w;5"Z^fHTX;뒅MVaUQ/s%:b!(7u [Nko{{cIg 2-k'=,[AeLԯ`m.=S)T1/J$<.3ӱNN0!@n#R0l̦bflv~4xg^Wyz=l91A؎b3xGvzM :caTf0Aؔ ~G,jސe?=F!AΩ}{ CN{谘CdlP(>E\r»YY$?I]n]z|ѫ_<OAuf_Ku1쎈vh5ׯF֕(V79^v1.Ko\ibRF6faRtdѷ}spXm$MN칿 fu_7C%ߛId,kv]넱nXY;/eIx;q$lu&?\Hqs Iy: 0rx!} WX\JR*7+X 1%x=mCrL' LN x%JA!j3rl% ANfsuw&ͺ2 kkZݤ\}u{:$7!ʓcĜ$HZA2ºasĂ0M:GQͣ$ RÅّE1`?)uk3[$ SA4aί8t dX%|酲\[p{lAPm~Z/{ԇ=vz,;3ZߟnV׵BiP x{X=hC`[l yɩJHO^y&/r\& iEE E) E y 9y @J"rɡ6Y3q(dVL>nm,TZTRZQbP\ZP_T2gl L's0:7 ax!DltgocBh{ByFjQBJBzjBZfQny"P$(?&#\$_$D<$#D!(39;3/]!R(?)Y1ظ̒ĒTL4XBf=F3OͭL2lx|iBfBIFjBrFb^zj \TYPT?qīY *M'3O7iUxqĢ']Zx340031QrutusIMLcȼ)=,Xֺ+7iQΐ|AGS?#(? {g*TOFV&\E^IQ~K=b핱>iWRPYQ !*C5u,)*KK`0!Qe'kux7X(%TΦeZ?z91L>?ȏej0M]%.~9{Q|Q~R~iIfNnJjZbiN ©.Jr[>^Q@zwhO93hۍR)Bű++.I!AGqiRqIY"З^O_%rx}114- syO˲ƹ ls0rݤT=Cs4慊M<͏Nc(/.y@/%5)#5 aM,_כln [:FEh82Q$(~.&ygXmL xmA 09;.J DOcmD?#MX}ĝ&N>%,L ;qB[pTa!K~zeKŻrGB(E7kxmG".hkRuJ9r xA 0=7*6ՅT-W@m ͗۫%r,*T+$i'O?Yq6Z 8P?V_؀8ç%w9 [[9XF37$Qw&sGczX!mPм{jie_Gr<&,xmJAEFajҼR1`4 vA.yfάofOvN"BW\ryڛT.Šʠ- څuOOI;aU>Nh!탣V,drQYZS*  `|)' F"Rz cND`8y xɶ}4̤d3ݔ2 8$3pWݠԼb+Ģt#;%4%(R bL#PPY[XbbfP&Td)?*xQj1+zHP 5)Bh ueVZ$v9B=͌F3{+ =G:0Δ𫐗 ;:8s,/q'rH\QX#Uˇøq_0{至woc[%w<O92uنx06A&S ߀G3sr$WDz7T)oQ6˾Opt]1l3RO5wjUp1B;in5}B;NWש.mj47ƻ`3Qŷ!2Y\* ~RA7Z'\ p!!_m H#ltR*4Ҷ5 LU{cN[7TA"XxE1 N6'OL(RSu3o}̼BRqJlDacU-E;GLnǩ,7j\&/x+-.O* 9 xM@ @FvL49ȵ E4{-נcsӪ8ʐyQW5CE:T۱7(`N]mf6aos9[YkoD!5SG{VNe[ĔL=[iKԧK{}v<GS8xSvwVx+,ϳ K-*+MU"xAk0 :J`=-ElfI_8h{MiCӐ { oJb슺;|,fQg ٌ+w^0nY$c .5 a.-@X,j7a4Yߚ)JQxQ} pZr4͹})8@a[$LvKf$Z?.,7}!7xeKNch}u5ux1"|qx 0DW,T ffqMkVbA;fƇNd4sh nS6֧YR/G:V]'Hz)6tTa9G) jvn] jA1uj bS`!b!¿)zE\<;Zh ?`$xRMk1=_1 xKu-=z"q3 $Mƪ]- ᱍvǣp!P!׮D5Q5|IUIAiI1a4)]z74Opƥ'Q!^c 6*`:]~,ޞuQZC֧a99A{AYF 89G}U46xՆI`"f,؛Lh3lL}B v[VQз LlE#]ډE(fwg_GɊ5Mƹt߶r5i6O*^B[-mj\Rul}Fhx 7zN66 6Һe͉C$?qYeBHMP )d=h*˻8).w:akrȞӪU],#xgfgl5.I~+kEV?.x+,ϳ K-*+53*Bɩy%E9 v zfz: ), k"llf\9IpSd3rM./ *MxuSN1}WL<@UR"JEEZUM\v[i݄@W3gگ ͕I86R+!=.mUYC2>NҞQ7B@U7wa_nzX`I:gg abKg+#:x8x(!$@_"G )jʌ,L Iy@OBϛqq@'VGudӛvB"=ʠV+ӭfWni!$q h5^=h^2li7XY5qds S8Xx (x<iVڜ¶YL8CBSzYj HI$ @x}?O0wյXA"D ? wn6C'{?rjr{(FP[t hM#bT=ŕxnrޥޡMC{Xp=:餙A~OqHr $lzGbw _O%r<$)r[և3BH9&9YK*;m<cu@}{2Z?a ]"UdpT/ 2S_1%C"J\[)R%v2rə _8.F1m&E GXj3@ RdH4aռ+ZI 0y[--aZp+m1;%H _q¹}\\D9K~ WJi#sTBeUFWr6R OzIOi<2ka1nNFn>|{fNatFw;H4RMȖ e4rʼ}f7gپt6BT)3B!,2\mAB;r~nTyVx%B/99J%wpmT(;) ޱ:Q@"$AKM1ʰZgj+R~47ԊX%Q.n@/Q1P)<n//RѯP8a&zc >)۔t}0O+l[x"pVPxV8wk*MڮN}ȯS@'ɱSikX([q$xQg *Ndښ}OxK)O/-)733540KIMR(/SH()JJMON#xWmS8lyanihszi[IT)@߮$'KebK}yvY͞M3 ka xdhq +"K)iL87Ca%{ S:(ir]$yyJWU5tEs )`$\\ =#nl5Rh4xVT%7T@ &#4ӂkHL!b+'\K&S%­BHO?aj6Zo/q7BG=BKhނ5I ͥ|LX^k oZ~h6, ̒"'^k\}P1Ordd{Qy[|PM>Vm$Y(AD^ Pw١pȰJ; oaKGzXS,$H)J7\ 4oȽ^ΰ{81o}΁ p 65.gئT  ڶ'.`h?\wv0;S7'J %& ֹ- XsFVSwT@Qݳ7f2Ǖ}e`aKPAIk~Sر vSedGG2kM;BM~a`xh9( LLcߟ Aۅa1|LqjS~0sxI'2 Ǘ9$xĆQGT ۘ{ۆWtYg¼xm4K]Ǘmn{%/i@9gS:GY^WTXWW^A s/|H+v\*4 ;liL-7$Hzy.m0xͅf9]`S%F $p{ro+Wec"[06A0(bj`U "l Q[9VHO#!Tr1ml TF-eN82dtZ2eO[n%q,Ш=m[wMޔsARHVil#~k77[ev!T.u.$D^\dFWes:^"0O^4C¨PbXh} ; pU~$[ְ?|̵¬"xhDs3l1暜"7, C_nİ~xZmSFE pU $6u#BcYR4^'{Fld\u/3ƫvjZY(C?xďSGHgq%iGhhEr%-bP@y{:I*TP(fNp3Yb#UWxۙ),5q -75]yX>HK2;o!c')pP<ì~NdXͧDn%|t/NJ]<ܮF=(fxZpyqT<.J (M"/s- j&.ECq;g﬿ BG8鏎_ *<~yv2ulGQAU'aB6ْN{T AH3UXu@va'YhRmK[huR8^FL J(N3q7w*ubTAz3+Jݏ|)Q)d<@ֽ?gRpBYò+aQZm'?8Ah 8GJE{FHr UHC6- ק -I`̢ ci#?<*Cj =G8Ā6w6R-4RxmhAqcwOy@sn/~ړ LѿEN&>KQv.f}AN)Šo/-]Zk*MP./Ր?L|(6Xre)XPIP)OS}T*yS 16+|ņ&*`0:* G{@X>W#vHDJQ~o%J]ArR(Ďs*TO^b2غc0bLv ֤c_g~OS:_}͗y_TY$܍%- sfS"5A\XRm8+"Aq#1ݠqүE9lŹUZHܙ™ uQ *nȎf3^;j/>rԿ 6Yb_Qۣ.oe*CTP >6Rus})M^)ڼZhd:+ikѨބp2իt?j_ g;ĉR!=Zȁ׻5EľRbqmk1Љt Զcšˋ83s" HP1*ltDoW\iWݶXliie "7m@acwjgS]s F7) S 4cLtlhL?NqW{QEe"i@D:|wIrRGT[e8'*uJ-/mc"[G*;8ޗUP@+C\u<Dکp$}R /j[b`Fm ({>nY}@fX"f[T:P<94O}>5֪YqXiՌ՜[ʝFT?vBDvg!4q^I07Ysyb7.k-cL#]iav](v&9+ҬUw[RDq yw]O8$a[Ž9@_R(a}| LF~܎~e>`f@Ijؽr?Qj(rMm$@ٸ&F.Y55h75r-.y\W&L8~ǴF.p1g|ux(%SFq\`)tڪƗ! g㞟.*ιєdu߁MRpA@)#nR^u>1g| q[z`i YE<*ÑE\s(rtO}bo%>vawNEyIP kG1`7vhl/T}pfQ\?Hv M_K[/KfkȳS"o'_/#O2gӬߘU[˩/ie7A)N"?#&s :[.5 |q唧fmR4"f[/Y+̂Xws=Yv52ty{\ MV!-E|zv,4Cg)~]~jʘoC!^WiEy Wċha(qY#jó\ 1IxZ, hz(*eg۞\"39(d]j1oorHl Q\˟e}PJ<^YrvUM_mTBUO@q$W0kt{Ν:@_MlU/u׵ vZ͎JZnxU]o6}ׯ˒U֚ $b 6FIW;JHʞwHٱh Ķs9I#1M?LnK<ߢ)ZaD͎MLӘl;UP$\6SuSj6<=~!es'u2hW9&$Lw\\eFdsy>/Σd@wi5{hۘ޼~n/ tŧCJZ*C7E][ieY(Ԋ '>tNLZFۘJcJ6|@IS-bI QKG_Ygp XT]l쾭e[T ǥ|9"G8b m骹>4.:ړ:-粔3Gi$}6 39,-& 1"QrCǨ(Y#k/آf3aCiz- Z"? ɻgR>/:*b]Xd^,1+:ݎ+Rk80; y)ծiau9XKvޝ&. &"`鄒9$y {iܲC]@C@N v+GXhw7YOg`p'mAwatD\HdzxhP6 j'=|'|VN|sԃgZU7|j_;Ao4~C)JSO\zSx? G*Mx+;efKyRA{){Fő RǶuolz/O7o'gsܠ]uuXD*m/$ ZljO&I*VUy_;Τh`F::w ,J3D{5ExWo8+fC{^j/i=il΢KIū, $eLJovn E7^lBOσTf\?̧w~SEN?,>@%/aF~Ny.nV7R~O0{yܘ2 m ڗ/Va&B%$zd&=T7S2ZɅ(8lɁi9~{хoOOR@Xk)jj+97!:֬؊0SpA|9 ifЦU,84O bE /bgYȷ[t{!֩K(\.8&w@3JD#-BRu뀭AKϻxiúCki!`ߟ|\E[:q(ucfxPA9"ZgH2+83w W(KKǸX H ri2V&%3LF)框Ev6&MK30%E{ XHI Io9F!RY6^d~!RTpO[9¤~4_<^0~uH|w3dR(m,(qU2uEaN,&Gй 76]'@fp jS4ֽll1HF"Fe)Qob ixF\\Gas|(Ee$JL5HſJ]Ѡa >Moϋ< OePSd"k# =ryRRiÅ iL$ {Veݶ enCU '~=ahg繕~jzIJLas]\5qj*7-yLŘ?F],2>XWQ6a'Mړ>*d9+H^yN@KOd@&6N Z)nzMUJjcVX.2 Zkز4ҁ"wuTji7 o^>'UR[Hcǥ+a|[ +-sni2kDP/h xwksbgLj׀g/$ajk>ueJʿi^@OLhDRPNxSo$:^IZKi g2?), *VU 6,͕m n?1a+A0ҤA 0>GxN~֚iz3 # a/c wl4..]{dX G>e~O\k\:)-/:ƙpgdVQIJXvBaJPN]M:[sWsޕiG4]缨{B##bߋ<xWo{ݱvF\ٽ$wwp0 [3/ZUWA+0qu=3a'DD$hV-3=> Bpcel9o9!@C8_oӧWö^~kۍq}&iwͬC0nIIA-8(3/ j]b-35o6;>TﮦlQR1rIu[=6k=W؏ri1 \6.r%4SEbZ[qL=$8c!E 8uoYECC\4xot4.xQMo@Uj*{&EP. BB=NVwwT)W?w סiKvy烋a:HLV?{xd<>~}> 1H ?s"9jp椩DG.Mf93o<`vUNFLō*ZnAMx`?g/9ku2pޣƨwtS8|.c7F4+PRS;fm{n[^IB=.+Y0z;AX)gm6O*Әgrۙۙpw{ri7k/ bӘW╉NTP&H+pz+r$:Wrkj3WV~2V:ak:*7Z :*-WMzB)V#.M}-Dkv&Y;3": 3!IxM10 "CuE``I Y$NT;!&Owsw:g=(i dzSB*.eJ4>(=fM['8Wg75w1ɷMmj٥O5tQ@knw_a5c*!ZZ}iEjd4):2;J^=aɉ^~ 1(yb1Mx;ľ]HYQ?)3O8KY (wHWQBBQjn~Y:P l JEhr9)p҂ĔTɞҊy̜]~b(Jt3KsrPnE6d'&#ÅAJRʋ2KRP@ם,T H@mAj [kPUsu&eB x;ľ_YQ?)3O8KY(u@]^j.W\bsrԁP`]M~Nd?F1iT҂ĔTFOL/*E,T5"5yL LE16@x;MPYQ?)3O8KY((wH>SH(J/KU@M~NnT (1%U}'B^j9\"-13'5E&5ُQL49?/-'3$Hz",Ȉɝ0ى驺Iy麙y%9@s'?aq[ Ԋg$yQ|IdLG,P̺xVo6l78@ۡc8O-H=R-I4_Bݝ=iZ;;])=-dƔPحU!%/+l\).#sO \6} wdʔEUKM-e䖮sĵ UF^HAsXU2U +&GeTJPId7đ3WikjP )mϱ'+* wN::Gh"7.Ds{wi]9|̺ҔjPhDK{X [Y^% [x"9Yq odZ"6c!BVͤw+)Wzpz CW7U _[M&2X4"A˫Kx9S"TlhcÄ-,n kVhLృDͣKBY6¼A! 8alMj:sTQyb)gi({wY)hC41<uN@E>Gq5?IBr}кvmldKQ-iYJ+k/mQeM ڤC}YԄ14ŌE]u ^b˛a=rM#H[:_'|WQj`:erRE=(2; :Am7oc}nְ$u4hctwe=iiKi{Y.smeST]EwV_ 6[#eNS Vy_o#-:y'TGϬʍ(:”>|t2z蠐 &07\Ȓ*[>"+AE؞&wFTFX1!^Wp*,t"'e?i4!Dʨbso?fN;NJ2Wk HQ$Dz mecۧSE8H\'u_!kY2+[JW8R8a4/r!K%q.=\)vmE)"9| Bۄrm}Bu3R7%cyL-X*p/X o 'GE*^,}Cyaa._x @ǾY"Rvw0oA{W˱ddSxDs4)%B~ 7zV^ʁEtڑ.EkZ H`t݇!1HCjQ|k09Wiу+/̂ mÚ\{-~_X\Sz^R]$̅ 쌾wgS= əS;4j?Vӹ';c#)T=,ʇ9:hq$2+,_{V֪MoY'՚R9%We4]K׌xUKA`͇s;7_.ݗssZ 0%)iaҖƘsfwd TOqc/Y!/obedp.';kJeBVЊu,κ gk'TA=ץK*uAj\O/{*K1v>lN$*ݾ]T8:BܽZu:3ţ,vj3?3dDRC ]58">-llɊ"0&V{&2# Bj!J1BH NyN|u&(_Ux;vMPYQH?)3O$#?o>3tDkMx[6udɒ<P*x340031Qppsw fأS/4q^[CnK!{ J"=\BXJ>jqV'ܡJ\\\}\J*JvϚ.v;m\ oSYVWkzi ՗4v-qN&zsSSzJnfGn{zb-7f%3tI>veBUe'gg{/_+:8Ͼ*^l{']}DZ.]'Uxsj;`&Zkܩ|w<ֶ2'\]|]*dia7I{ wgtx_=k)l.zZT>%%31OKs¶o1^.4) G2 =Caᝫ.l / = ɷ8CM)L-gx%y^UӾ^w "Y ߦwg޴uM@1_lb7JƧyg?58Gzf_pño&+i^l\ ix*,,xuRϋ@n/* Y1 tQ'ɗf$23["hOz]W O?IӪx g?E?NDI"K`=B C|F&  rULc$T3*PQ*(HI4vB7VSjeB(BL3R@Rw>+ibdu5ґ(jwsgpRkm(gW݇]wսlx}ܨN^?}/N~,O9i8x֔酪`5[YYsm1֊z:cYKƈZt|l#\*`UN+`\J&[\[N+ o17*JjX5! v1iLr!W7גg1T۶ 8KZVi>_՝:=tkgx.xM`C$]&x<| DK2K<JTbJJL I% y@ļT`b2XIPcJfJ:PQ~QvQjNfbRNBqB^~9ĢҼL% @meřy@\ JJJ@R(3D!4WDNe2QJ+B$J L4Q%ɂ,@} N`|OxC h͢vVQ,xUO1N@ B~>A E"18wE#xhx _HhXm3;ɋ֡tpB䃶OAZ%Y%tq-:v7\o7Eo6J3*ZWY~9O~ v.AŮFS"6lDM@bW.ƣ8y_P&RScdI'ncY(hy^]Ğ %Z:yx[,xq75\K2RrKJ2BE: I% E% iE )%Eyy % 49[oOU, &x5JAIn1XXeja !"[.q,^Vb,|+g=~J^ (x;v]PYQH?)3O$#?o=\ ܂Ԓ̔0gAy V\ 0yBZ~i^BRiBbBBnjQB.ЌJ\ 4-2f2l6*Y=)Ä(ȴ"Na ;:/A{Z (1 %\܋gݢ'E ذ+C\Sgr# 64পnQ^ժ)/x340031Qppsw fP.ӲYKlVxaUbR" Qk:5\]UWRQb=)}ZlκozǙiY SYVWkzi ՗4v-qN&zsSSzJdz/x,swdd3]|'n|/ʡMB?# Y[fQnybQjxfqFj1رgB_1迢e~Ȗz?r3:uڶtẆ\6k r=^[۾ʜ* t`\(q㙩"fmJc|"jkޑ،;?- ~Y0TU?X_CN9ds"))-1'le;KCV.ÿ{n_cTqJ~bmQ"7 = ؟֪ cu^"ٔr Up`Xq:ѵYe6#R4XAuTN#l֛.TYf^Jj^FIng y/}kwʯM@)E!/$%5)31!?'ݲiႊyPSKJ @ug >mrŶ,^x%;KApKr> 0 Pb,S(( ((^{br{F$ ),MaglV:wi~g~zf^ `X#ݒ.: h / ^n?\<:PN)r@8G#D}32 q N  dDiP-G!̓lPN,Uq^cv?PsZZB'mP[F"LE2It':r;zs YWG}Z\HD_ Eb? eRtulq[ ߱bQR.PQw[i2b|fud)*b-*0A9HʜO@Chqm`Fi&U2K4JijOw曋>=pbU*')6-z zst_ƕI!yPuh|. PXG,w ]x(ꉁ]>X1{6 NhkH6$yUGwukC1FtM᪬!6QT:[oYRœ+;yBlpVf=K]܀AQrU ("F^MK=(v\Ɋg:[E O$\D+tVYfCbaQ|Z&z.n__&a^|YzͿro /DKRhB l Dܯ }s1u)աHk͒澨u1 M̨ĔdDqWi.\V <7wU?ilXW@aŨO\mL ܽ A O{6\úte*06TXeˡ)l/[a԰9fXayl')Þ6a_vǷA .Qنa(a6 X!Ua8Wzme fؿV̰LU2/Pp jQfؗ9ZeKU(pQb WFl(<&bktCmTE R[՚iplU585g'hBUmܻU7湞Du!(1oMLu4hCmUcܻ!R1o㨊UǸ9cr1o.v`ugSdu{WU +q<*\]A*]]SqJVUq]W׸`U1OUzƳiຎz{w)33JTիg(vm_UzsUիg(aVUlJ!UnJ'PUizM. + l^}ٔ‡XUƽ9^5PGU$:LUu$Ue$WUΎ=u(sU`$9bVH$QUp#ɅWKc+вLlUUhYG1Uo@lPwDQUE>~o8%-(ټ,YYLO4 qAz1h>1fLo m0]w a:plqͯ34i#GKk4擊|TnVtJ @oxL0~q2ͫ0E}\>GEK64^uˌ؟"a)ϯ%q>MyX%AMD"BJ<*D^R>QQg KuB-}8j6 tPH:':ztCiGnìv4 ²nꀃ zT;u'嫼snBk2 r ,zm?xvx-invΒיpF(,TȌ)ka6ube<k=I9T﬌2bx˄ n]Qq$BEKףΫBN]@oe59Ut$W嶳ϗKCrU6 9$m7]fy:k3{$.4Cj .e2S"T.,;ѝTA'TPPBb' .By bB瓼+ 7h#:t׋>#*(]POD)8D8A#4||q #6!'p 6ߩ6;=3{qk^L8LW$iz4[:PmN-4I(TJ7GL} Ĺ@I((%5P_\%1dJbck$^OJ i u@I((%{5POW%1n5ĝ@I,XjDQ(:0+I:0h0O:0ᨕwTE9ԁIA ԁIt>Ӏ;ĔӁI7J$LbidZLw$Lf\$L@I&t`H&4i;:04:0-:@ME&Mv сITЀ$ ЁI ̵ЁI ĢzQ&t`?B&!4`2A@?BxB^}b@|_"vv:O'i?޼A0N~BŌ/$@jbݲPo m ؎bu צQOKIvHB1!(] vb=7TC_<,Bk_ۖoRm}{;LkE螡k%-Qɪ]ֱڛq cJ|b^/zXGۻ=$~h46Z\LT,E첋̧~UfjWF7,zt6Uޞy]cQ1gwsZJrZ ˊ8\&S=\n|BFzY@2נNXiŴkg 6N/!PQ)XS殒5(.CGeKq/c<&vn i/ ]DVnB}7,/x340031Qppsw fh-c [ub bBDz3?}fڭNb WCT0|=u7[*&o,Ou++54KVZ l|'P)D^A%C<晵Zk4N&.z 7>v@PŦB-(<(5<8#3~̯O_yUy2?dC=A5ܲffJla&Zkܩ|w<ֶ2'*zR(_bn!PA.`UQW[+fOp`n}TU?*U]7L:t_W|JJfb:0$".y x ۾A,{Po'y>٤b !`z :KrS^!RZΰu +^gW76kfd@fٺ܏?mz2RR+2Jrs80'W}Ҵkz4 M@)E!/$%5)31Ak=|.&QOQSjRqjIi(޿ԇc߾MWX+r$^x:0 H"D-P@>Dy<!$ (/ʇ~?#wi>x[q| O61K{9qHzlgx{(@xC< U:x+./re^C3t#Tg34- o,x8 "єA( 2~ &M{l[eXOGxSdD(x+./!_guZ^ r nx]#100644 CHANGESq<1QzQ7.3#zn]h1f_1 ;)AH(DjYx/,>xc7Px+./۠&b⯓C u* (x\hEěOe.x<>8n5)PczF< 100644 drobom.8j8pE9zi:(Bxpq {X&?d``y7:lRr0U#x-<}@oC 7_'[!ȁ=bED**'޼uB ^ɪHVVM;~ڹ*0+.(J-)-SVPOI-/NIR,x#&W=,6hEY.-S)޿'h0x/~Yt\]x;iqbCcn5MDD9P"Ex+./;B52=u Gxe\D?bl]lK^4d){t9yȣVG+hy>WHLMn/1|wimmkJezX\s ge?ܳ. -6.؄AJu (*6$E[oZx{(<_xF9G 9.0x+./2‰\u,b5vx#1HY%cǓx+./4}r)Կ n_+ nxuC95bcm&o]9웻3(xqm¾'b<2FqF~iNBZbfB~dEcv= L~R6x+./2F㿼r2n/ 6x!y@{Uݔ<._X#n x+./άgb5ƕ 4x+./y= ?++IhF ?~xu7k}~DW߷DHxxSVO/JHMVH)OU(L-v5xE#100644 CHANGESkEB\&*e#.؄AJu (*6$|ox vMtBSL5_6Zx340031Qp)Ou++54KVZ l|' HV!(1/9#lݺ OYWsx#sҼl,͛yO])_WLBKDŽ&l-xffP.}W绉Mr=69IyO xu7k}~DW߷DHxx340031Qp)Ou++54KVZ l|' HV!(1/9#y\b^uݳ?yqyS3DIIQi^6C'讔+&c"-ixffP.rgW7HEz NxuC9ORгHznLF_<Fxi¡L!zf )EI iE) i y))z\ z0Eũ%9yřU :F: 9) i9 y ƚeA􀀋 ߣx340031Qp)Ou++54KVZ l|' HV!(1/9#a%gs_f'<-0x8pFgF^fKij؛AnQ_ .=8e|ihx+./eㆮŶ{O{2TI |x8pFgF^fKć=dZsGxߎ'_ 4xu6Ӄes*zzjbL[ x340031Qp)Ou++54KVZ l|' HV!(1/9#!*ѝN&F|QRRTeㆮŶ{O{2TI--MxffP.ǺƥpCg?/x ] 2xuwo=٧z==ExxeaWLyܓ#l7/kc&h3VA x340031Qp)Ou++54KVZ l|' HV!(1/9#WE ξc31ANҼl-7t,}ڣOJ4-JxffP.R~=;Nl܏i>+ ڣx340031Qp)Ou++54KVZ l|' HV!(1/9#!_oQaU?^eYYYoI< QRRTeㆮŶ{O{2TI!-vkxffP.Rr*9ެc)eªwt  xu>N.gj-wY%0s. #xϷqj7g*dX=xu>N.gj-wY%0s. x+./r)*ؕd:>#84 Sxuwo=٧z==mx+./rRr%&5cCR Mx+./]jC)N%B&ql/] UKxE#100644 CHANGESz`OV>@A9 8#Ia[{+x\L{4*x340031Qp)Ou++54KVZ l|' HV!(1/9#A[I;"WˮXso> JJJv ^m07ũD$ݻx(WwxffP.Ro<9{3̜aΖ\ j*xE#100644 CHANGESz`OV>@A9 8# Dә5*D^!JU:tx+./Ro<9{3̜aΖ x340031Qp)Ou++54KVZ l|' HV!(1/9#oGlWQ$ϘM}x4DIIQi^6CT{͜+g3s9[K%*exf̚wxzuBO_Ĺ6i;-u%4͓%/u x.^`BfFkzO|<̼ĜĒ<<ļRPBQjn~Y*HP!-3'X!DDq *,ȇ4$/.4H 1( 4Hks;[27pʡ<;.eD,ptzk)g k 5Խ%f mky_]"^o%0&[$X8l'x*SxVͅL,$nxE%100644 changelog_=֟:r$J%1C/6tel+őj!x+./-Xקҹ5^op~ Aexzuɮ>"l.*95]Xux+./"K?('Ã8V19 Tx E2} u&\ϟq$!xE%100644 changelogT*68v01~!%1C/6tel+őjs,xǺeD&HN6cQ&Od3 Jx+./tSiS~v& ')xzu,&fW2>-=A/Tx+./.pDG V.8! |x^#100644 CHANGES,DV; =1 AT3#ye>Lv̬´s4>{hWn GB$i_&0xO83FTt+L Y=found Drobo LUNS at: ', strfy/lLx+./F27Md/ kYf' rxzu[_Nk_%//D(?)7@/Lℝ1?p(<7;[ Js6 S@s,V& p7 *WO, 7@x+./dcфcU}1xzu+Eq.C~vGx+./R:ߋ336K4~5 xFg56Mȭ#1ofx+./eEVq̚={ kTxĺuC .&!x+./r g]0#m_c 4x${ծ8ub.qlLՓHAzx+./)]-sڰ< pYx8\G 'ٶ ^׵ppzUW3<zfx+./ChMvV%ۚM  x+./->G JylS +x340031Qp)Ou++54KVZ l|' HV!(1/9#ҽsDγ())*fptPu#<)Ĉ*Bd2x x[:oc3ȿU[,?-:pнe%8x+./a2m:+8z * .WxkbmbFdC𞾤װ~x# t x+./iBεi[ ~<׫lWQ^ Qx^#100644 CHANGES[ TEv}捱#.PC `Fe.H9g%Q [ە@z^$&@x*r@XXajeCEjFxμyBƚhF Qx+./y<-m+H_d_9 EHxkbmb(,cΫs6~R{2%x+./2o}n5io~϶5 exP )  `+lVu Pိ+ŸW9 =d`%gALH' x[iZ *U,9'W̢¬09dUSUe&Wқܩa\PW^VPXZTPZ\Wj @i '*M~nWcs/WU(NI+JI,.I,*٬oŨcfgP\PT^ +-Iӛ\4!EIMA5E"TQ\mґV9ɄhY^/ix[q¶Ϭx+./Gף^nЯ ^Gxkbmb&"sQ₥Qv&fVJ޷q F jx+./߳a&.ڋVc[; xS\+ѧRخ>x+./r[jscLn2l zmx2NIF0^ƱZxss_Ŕ!ӿޓ/s` Vxkbmb$#wZpE9˅&&X?9I9 ~x[ȴID!9#1/=5'?LM@Io5WE,ڥob )EI%9zy =Nk_~uR5l=#ilx[q xK0F9GFmZ``86aJIؽs:M)_U;iN2 أI]FO< [t66RAϵ0j/.ѐm3rк*tUT*OQ3~x+./z׽{g jx6Q9arG>X'dxre qfhЁyyBiYix+./!najOM-DO^ mP) +xmQF.4 ?!8dz̑&eh"H40000 notdebianC8/QlsjBb100644 setup.pyȽ#g"N8wإ.ͤƲ:|+ x;̸q+f==w&l`i ux340031QH)Oճ`X|+PΏ_,<\=IMYfj9PYG٬7$n]K|x+./{r{.}z[ 4xβeC ȭ58:u0 6%uCVTKOx+./VΟ?+:aIr v#x340031Qppsw fx*MgQǦ]ggUbR" Qk:5\]URVWkzi ՗4v-qN&zsSSzJ F~]9͠~J܉!̰Q!xO_͇Ul kXx?"r,-O,J ,H-+(a8/Gg_/C=dBCo7v&%}`&Zkܩ|w<ֶ2'\]|]n=ѩQO/ѯbB],y^l0k9iʧd&)q[cN =fw6BJjRfbâޕ:[0o )>3kӭ$R@e`}9cG_mz>Made $O^٫ʾpsWBRZRZ {ӕ:-o,}'~vɱMV0ix*os(;2xsOk#|/7? O?x+./WIB?I KM.?j] ExB6HmIW!@l[Mc100755 drobom ft>̀?5`7 6I x+./2O[{r53/ wx^g 8瀱i+fx9J"0L"O·"8%#w#,Q?<. -cu!'x+./r>"E@ G.100644 ddiag.c4zorT4+&~@-Ocnx@h8x[k+ o2Cx0%100644 changelogf6e UK5ʑ%;B xMj0D\6U(z(?TXE+S{qx̛RZnF+Sc%x%]yvc?U<2) q`n=(,ixlb'V 7ʘ(S+ $Ǵx˅u+WS~cr`n=`Z|7Zc;cJZWPB%x+./Ÿ(]lSǕl?O Xx²euFlԠbU~1rۂ [QxE}bjL[L9dAx+./rmیۥ:EF{:f{o| NxE9SOA*WӶLѮ 100755 droboview 6 ogxK<>mǀ$$4nx٤>bc`f5ܛ7`/r _ 9@x+./4_>m(p %xD#100644 CHANGES*m` bh>]#cK"8FpXfO6JOi^x*c[* X)Nx+./wh.9 3xD#100644 CHANGES"8>_Bh#cK"8FpXfO6Xk3ilx*}T8"\x+./"kjlnϞ= 9x²eBHk/zyO_lZhY}.x+./+#Ni? wRx ^J9I[xR} jL\jEy% 9y ŕzE V: @ Hf7`/r Sxss_Ɛ4 vw Oyx²euFNlpv3zYx׌`xkRisɛm>89uU^MY Xx+./d{Ktоo}l x²eVFfgߥ#ފK4$c6J xVV)Xuݚ/0!xĵkcFԂͯݙ?vx+. -M6ޛw  x sVyQk9xU :GQn1YgN$Q"(N1^E(l|1v{I c<Fy7e*eP%drx;xQ0(?)$3XA@X`&slxK)O/-)733540KIMR(/SH()JJMON$>x+./2h CVWk>~v }"x Q^ ˿:]%bbelx+./,sHu&[._x Ux²eVFGf>8da'x= ^E(l|1v{I c}z!sDkVxsrbxK)O/-)733540KIMR(/SH()JJMON$Mx+./­gE֮-SWQX.& )axq#100644 CHANGES܅Zj88NMfRHcW[#c(kӫ)!PiͶ~&%ljxG:Mi^z} 7Z׭"yY}X]8*er@+ODtu`}\Ik^7Wm5x*}T6͏&3(UlXx{S7nCG].gUBx+./ͭGϞ m}bo ux²eȪlE+̒}͒u(YRRٰ kx;x+./b7c2#O{t txv:w{H襼[\2100644 DroboDMP.cD 2a(#]+lFDw˵.qU/KC7܊н CSp^eB3lx<!AyR&x+./ӣKBXgU3Cn1jBxu#100644 CHANGESqy_qV1G#cDRz/юLClҥۺbMǴ>&plpa$kLL)lp[IV5mOx*rerf/m&%\?x1'c2[Ib^JRfyMMlZxWa=W|,$3{x+./R+\% Owzܽ+ {x E9kԴ~I&Px+./"e k};1Z UxUo0Ʊ##x+./J]tW| g(xp9{_w`vqlV ͦK@eڪw274X Cjje69e100644 TODO\F=l=#O"n2à2lmx{XQar,+ 3x 1@َ~_`ehHm~5^do;?)~R)~{`Dmz#ґsyʺT,y`'h$Yf"xVüQhMKWz ͼz;6MwY>c0{x+./|Ɋ|wSve ] TXx²eBnek֪ylް?qzYt x' --&ԿY tx+./ҥwS⅞,~ɀ Qx7lOi'}&Haee:U n]re̎sx{X}rxwm.X3rx+./r\W~Mknox+./? 9SK Jx&Ñ+Fo8 h&AkhJx+./߯)wj^N` |x340031Qpsgp1 a){Ƶ[.s7(q)Ou++54KVZ l|'P)D^A%Ë)ɡf ^%c۹Ld).X۩>4c_q]100644 DroboDMP.c>bgI1C zx;}:Lsl~.$gU<ʛDD&K;)(8X))hZs)@Z~FBBRiZNjP R5AP1xrdu.~"LMYtdCN) k &3JLR<_Jd.l1yJ)MȩqI- M͍w+JMՀXbP#ylNZDcxk!Fr7'_`*p(l4x PbC'\7%*t xss_JDTҜyôXXHx+./rNy6ReU%$G j8xi0Fe:x+vh \x,&!755 Drobo.py}s]ҳ?|aNwx{t9 >7l^$(\PWPVR4ys0gZ~B^~f. F7)?R[q"%Hx31ļb*uh)YOgޙUx XIIQi^6Õk$ߛ E9Hw8xiKQ~R^A%CNc>g!{ߢ|'3m,gI6hx{t~ 7cc59U{mWu=&H+/,IH+OI,ICb\ @PZ^Y[XTeLu~/Tuˣ-b5A:6ft1x31ļb*uh)YOgޙUx XIIQi^6ŧS>Z\4II6<XMxD&!755 Drobo.py'ALP2w]tvř97 MI1 /x{6 7bN5VPHIMSHK-IΘ7+q1Lx31ļb*uh)YOgޙUx XIIQi^6ê=[-=04')p]JjXPZNx{i|ut%_WbFwyF% WVx{qb 7f1ݬ_[Kx31ļb*uh)YOgޙUx XIIQi^6Ê2X1.ĸHdxN3OxxA {uȌU G_'޼,i8u⑺-Ɩ, h6 ,F kW'xޢ/34(G"  ax~s8J2R+R'4f\%19KL^7%L!'38$3P$#?,QwK`j Fx7_:59AL_RA]O?(?)?W!3/-_k1w^1ddn>hsz0dQR}C}55x31ļb*uh)YOgޙUx XIIQi^6D п&1^pBvxھrpR9^Q]@͑xkC4SAx31ļb*uh)YOgޙUx XIIQi^6CfECg{KxCqa x݀ӝaoee28o.xkC4^x7OȒR[9KȔ8@kfawux31ļb*uh)YOgޙUx XIIQi^6Bξq7M<6n/x\3:CF\d'F9&/100644 DroboDMP.c6+|8-ƛېmz뇒dCbyO kc,pFx$ޢΡH N )x V Gl'53+%5E x{ͻE@ 757ޭ(5U#4--h9ey';*4L;]pFEsed&@'-E? 5OAXGa%ɾ2XLlR8@w3 @P@A FR)EIi)\D7OP fڇ8e.x'yZ. M͍w+JMH*MKK-|QpFvF}@OxukB{=.ە\+RgX>j@xmڍ;2]x31ļb*uh)YOgޙUx XIIQi^6Cd3nL>/ ӯzoQ x`V{o@~+cuSUQĺ100644 TODOȢ$-' 9)40000 debian5O=oRapkӺ*lx[}kcfܣx31ļb*uh)YOgޙUx XIIQi^6/k7=j*q9]wx{iBHߛ O.>uşſlbW, x31ļb*uh)YOgޙUx XIIQi^6CF?g>7yg1Mlkx6Ype(I,__m5N2ZX:)glQn"x;Lksb 3(tx31ļb*uh)YOgޙUx XIIQi^6 >e@b2EwXȥ$omV-Ct"pXU{?Vr܆@VOq+2"O!>Z~CO[2Iiռvs;y1'0{)1Vobcq>&+ݔ?\%A ļԜt=Ԥ<*.Glߠx31ĢTKц.ӟ x2<, " Nx31dE˗-JyXQa? x31Ғ̜bݔd[ .YGzNf?x340031QHHKOOsIMLKb|9-c%*B_^4*/,L(aI\ɚOLߗյ x:QHchangelog.DebianA 0=7*6ՅT-W@m ͗۫%r,*T+$i'O?Yq6Z 8P?V_؀8ç%w9 [[9XF37$Qw&sGczX!mPм{jie_EFsXƯx31W'OG?45ɖwtvlx3F}5&`E ,΅ nWni-J5s> Ю x340031QH+)azةZ[--o͆%)ť ]/>Ţ ,divsSS̼s\c*U5 1%T9OZᵞm\BIQ.ûN wV6jyow|R D2x0 )ѩ`EBb5@imEHKπt}W.@љ( 1u7ϰhf;s+! =ux#=6z$c 1e*xnL)22HQ?e@^zCrpaQa/g5Y%a&yke%xRMk1=_1E+BA[z(CfvId- v=x0#{3a2,H0E26Zw@eBn\Wkj7 3j bhtR*Q/h<:ඍKODC@x[6*`:]/^uQZC5O r eMMۃyMzde9YJcXϴ*!XPO6?,nV_}z{}̂Ʉ8æ1 `udxjrZMM}Rt& #_8ULoIvQx]PYQ?)3O88DA7kmfj=x31ayo!*q/`bT"E ?M/sY,ꯐK`=2v# {kv5uٵsĺ`&k\nyj'~{dF_=}Ʌ{'-3Ilfoޓ+G6"h*rjYlab߶+RvZX[o(^DUR%FꍢNCHhϊd>WHO 9bOwR^䉥xdpWf"6#"Cߋ0%_'K9 9I.!/3KLoX>a:*G ?1߆}iaҌƈ45ֲw?z0Yn_ ZGqp$iy#[M{N_0Mп!=تn@2 _f3.jFoкpD4fZA0XGZҗZjE',_|Nu0–ƺ5nKFf]ش9vPY5#=.SO!AѼ7lb uEpL;L%78sGVA{ ZIFx=#̧MS4uE쾍m-.ϵrev=+9{ϔ,ٛ.q?աN+ 6K!ưó1Wܢ{"ߝ]*S{%IW$UK~HJ>$ G$?)33)_8PN2RtVSwEZpZ:p*p`58@8 4{}#8Tӂl'N-p€G!'  EejK~1m}^=0du{7M7l̿2/g 2/%)r˼] A=6e.c>>.oO2 k~}VsI(b%ufS~zNωzq9qxCmۏݞq o-]`L֜T}4@fTx5qq3;6+j/P/y{dS'?ͣߤYƇ*(`3x"ǻ@b#_CüL#pȁ~}.bp.<9j);"zܔ:E$::s,rTڶ Cλ/Oo $Ϯl x pѲ! N`1-Vz3gv߮;c=W6cߧmWc`~!C5>`̔|%_y֮?eύvFb֪m$ McexVΩO\tV,O?J9Po.|ssk(uuVq) '^%N,L$"''P?۪B-jV~\;j0v'ɶm7CNopweL%d.ݡHLdv':M^$=,m2dM ۍ?Ň]e=˥%?aedܾ쿶r܋;~3u%5]F ֑&O9T8>rufirN&4|$84cQlK\5f:O,-)0{ G@ֲ}@SWeJG)}JiJboUJ T H=}2ϟw7p 8)9\7):sȹZ3S9%EbH!50F7ɖToe08KuM<0 .%x*bxM"DE ~st$-ӛ'~%٬6w^ .By[5pd_x8zlb?\rx؅?oGLq> Í9<,dGV2*  xL˗x䜀Yx1*h6ηK9@|6tosQ5)=}!)!QG&dۈa9a;?ڲzVGFwbq^;c'N˵s#s,m\ W˅NWad1tkdx >_AųPM+i^r`9=Kv%S,ߙ{ݥs۾Xw RSܭ5+HQw)Z4ÿC]kn<^o)+mlZ45(}hݼc Sz-q4>ܲQݤR̐oQº/4[1S w+,bF9?A)K Er}|W9*)Jy J[oͦ.H.J@)א3R:M jfw[ ^ņ1C{,64SYXh:Zw֒S{M")KޣA=٩6x-(|?+߼~B[8X+wnmlQ (ppՕ)F$"z:†itsN *]ZEYKu=rnb 4*ί~M55/?YFX{\SSZ zDЍ.eQ~f +=jN⛿Y;rr\#|sǷD|wze;/\rogJSnq-s+~&Κp3%]["p6>GgtN&~G؟dz3Qi2n%%z C= zgDck~T%=NoWs E9U!2,;vFcސ 1opg%eah#E`'yQz/?:PBgI hD4n_xDI:k# 57) oi ;,-t.?]$}a-qfpVS(hc)r&m6[<d, ;KҮa*s={TX8^-Uh#m>o=9 sv\Ma}Z*=.1jAiv{jU(nîjbpՒ]U}Fv>T^pB+^~<Ȯz8_.;.uI;N,~Wr$1 x] 1D|@D+x jUI6l CS730)QHjb675 b5?nH n@(+ʞ#>rD[љ7o)aO~Z^Bב#%M +Fgx31dzCΌ{Sa ,n,[YXPEzÂf@UTg$$$2l~}b5ʘUm*x31Ғ̜b)?4~_U5C  x340031QrutusIMLcȼ)=,Xֺ+7i0au9,i}bW(şĢwP{4i ?YjB3Ssӡ|9-c%*B_^)/,L(aI\ɚOL- IRxooFHREADMEZrH{1k{dcbܸ@tmu5BҨJf?.U QI,Iĸ;(Uee/<]t0[/Sg?IwY\@etMXy8E)Z$xa]u)&4}M8Y2OkVEaL&I0n)Wَ<xTt^քTH$wzhC<罆j۠А^%yP$kJ3eYx0 ?4D+ڮZyT1EWJbJ0Q3amy\< p2c 4K`u-<7 ^Ls9Ƌ"؝-qC1>{i>8HbPVEd}٫[bE+ &h5A ՞צXBe2mM'WCwPJ3/M/>9*>V1H \t [a}FZɲ_*}+O~ni㈴iJknmhV't?,/L@b'4)ܤڨh岂jx{LE.ѤEɓ޳kyDߧ;ȟ7},[{ŤӾžM䑨7wpPpH$vhPoO cb{@y*bkbi=C[+2l2|_XRP[9"8# *~[#c>caG*Kb;!y|P,$&B)OZ"(w8A6$ 8Fn@27NE9A1HC;zݪhb'8.alB/r*AYmZḅ%l_ȋ9642]뙿B 4-}79,lrcBkhr*] Ol# z)j7! tIf=s<$΁2˨TKbi:Ek?6aU^C,HD 6fA ̩xmXO ҙXѲUvKQU$8rzAE*8 C,bƧOaOX)x p;Lm,IÚ.sm֖p(㌞&pPFidSV٥|hG1f$q+$D8H.qC-qI%[l&9L8}oA&u}kNf+Ĭ cqę V9]4ޚ6 쁏  ͑S-aa>}yf ȺKʼnŕ3:߰ؠc0 R چ Ӣ@tR~Xō2q#Je /ʿ/c{B~ۧtǾ?z 5akvsQ#O^8L2=Gx訌(G]H'}Kr#Cfқ8iLB4z{h.G7:; c? Z`Kj9ܝV7>?Dm?n3O%pӿoE7`Jr1|_@ٚ[*E-yfi"ï^uqWo_!&9Y(F<aC\f:GCe9EL9#,ã4%CPCuڨ,OAF# ':T]g!ag0Tɵ8\C-,RADel|U Փ[ LC{$=DVxf\rx{Vab) }v+T#'[Q'ߏ^ i5 ^|r}Hmf)(Hqu K #Zp<)lFQm} 'V [`sbȰ/[+<٣JAI⸞bm6Xs;\[UBs72gKѸ,bԡ0c/AR&I>vvp^b[J NJ~S3xJR\qe՜KJ%q"-G0HSZ4%rlE [G+mj{?$40ɟn0=밟Xe[/6 .O#|epg"<A@p6n-K%-l"Z)lQnm*lɝj a%.hBrRx17eQ>8$Wv}*][&Ub~a~ƊM J|<_aHw]N/ɐ$v0>g/t2nOiܠ.yOi0Ood:?Mjs  e`,1_&_n:|^'Ûӭِd:L~5v ]n~=lwVL-*bpuR:*ej3؂;ԒL1kbѽ[ZyܻaLCT[Z~s 5u>$A2 G m vö s4ivQ)ˆ&.%Ì)ňݑB(~0vy &6rjf5/s%=HE81:TSUܫYB~_!uz6mknUIZ}Bm / 5c4ڎsF ,%ت5UdpJKDD\*W\N'KW`ƫ}kӌp۽pL\BG#~%@ճ wc 6'Uĥ.w2v[Mukp|sB>Y]H9)/ YžH虳/xzyImGeϛޫ[Q @loII"`}WIZbàb$m0>gS^Oӏ&aMdd۱_n⦃hQ2h>AF&Y\Q PWunC:w.:-I霟cW3DP#<%;@ ̐5ۏڽVD^;N$í;URb"@Ɓ}q=g漢?wfvg! NEdjK_JTjݖۧY5lڰO+vp E u[=:gޒ/$~U$@gE c4:⁎[.kLFˁEK5͸7r]i]Y9\%Y^+ ㋂+rX&rg/, 쟵 Z0EvA%$~Z罳[y7*z,OAL9Seҽ_E;A߻8h[nX]3` h@l]?}EsS6U>tOY%]LK%Fv,HY]FB/7 ϴeNI!$spHzy'Ta3k3[zNL< !RĶrju{Wq \yp]a&LW8{k0|1'%]e sgT|XdIIIT8bx631vր*X U˼G9c(49_x%_ia'x31ļb*uh)YOgޙUx XIIQi^6WK_ E܃M,j96x;tiLB7wF]٪'Ls҉?<* 4x yS|\'82 x31ļb*uh)YOgޙUx XIIQi^6 Zwog'Ix;tij]uUI*[w-~PP3 =x{qB SE'|ITTdx31ļb*uh)YOgޙUx XIIQi^6ó[YhU\S vgxY2ͣ&UM!-Αml (&xeQjA&NEQōuG7;"DkОƙB"{RxI#xP<y| 3؇'kg*{||r `U&U \&#AQh+#dJ`fe:_Z0r[0zgX@f,CUb5Gc4ZF-)OAMjZV+f\&ԲDЉHa, .d Q5VLk0 ]1EWQ3o2yhYRZ%!$KPڨ)ƽSmNx:*Ņis i&"IlLƞ/?w_}ZGpCThmӆ(}gQ'tţ9wo쀛=ߺ{ꖝׁ7רiwnw0v=^n)wU7>.x31ļb*uh)YOgޙUx XIIQi^6mV<[Ҭ0m7Eax;tiBCK|UZ6 WԈ <1 `Ix;y3lY/B6+ Ln4J,a3#wqj^qjRiZZjd=%"*m$8&+H:N6P|Kg Jg3˓mUx&Uyfv#x31ļb*uh)YOgޙUx XIIQi^6õE眹%e4\;$_Qpm!㳋R kxt3:afŭ2!IPwM i100644 DroboDMP.ceQ;q/4C% m5i?M uQF˺.wcpK>I1x31ļb*uh)YOgޙUx XIIQi^6CoøIBՋRe ;-\Mx;ti'W3ۜKmZ-v?YQ҆ x31ļb*uh)YOgޙUx XIIQi^6,w]<m/:)^YJ=Cwx;tiB*ӶQA_xҮ?< x31ļb*uh)YOgޙUx XIIQi^6C\Q5O-%Dx31ļb*uh)YOgޙUx XIIQi^6S[=O[JDȢfcFWgܣx31ļb*uh)YOgޙUx XIIQi^6730rOA"RxS4p y_!|0X3̛100644 TODO->FzѶl030đW9lmb yL'a$mox"Dd%N)x31ļb /G쐙Tɥ7d[&`%%Ey GX^毽G>bx31xxCojgx^,/^#|`rD%5x31ļb /G쐙Tɥ7d[&`%%Ey x}gߝ;Ϛg wvIxS4}xl_j|\4100644 TODOF!qV長IYaW9lmb yL'a%mxmPJ@RXو8bE xLvcvR}3K7ȡN573ox<~9_θpoWfѤ(X_\NNmL2hL 5+{,Ս-ch7 $%i"穷k"IΠ"{nm=U:/*m *,=fTQtȀq?$w.40rΆgOotO;xu* wW>ESE=t'O{Hx"D`f=L8&1?x31ļb rK]L&`%%Ey x}gߝ;Ϛg px31xxCgS3ΝgͳSa:Fx31ļbMw;ԄVi#^8Q&`%%Ey x}gߝ;Ϛg kɨx31xxCI-oJlK |x>4``q琘A100644 TODOڎ oe5:}kEx%1SAUZꪧsnҙ.tL&o|o&{1)F{K_I .|o_<"B=|Yݎs_4oU2P!=*iV&9>$+_"X[z, ͭ@]8j3;D>3F!hm˂X{K]k@ +(nR 7_4 gM+_-p*Xt֤RDH?6fݬ#u+&mR#g+ѣɐ6q:F'q/ب4NJ v۟ݮ[D6p{R\:K`%_}|?KX>x":vs'_c`SPPHKl޲فc ϝ ;x31ļbMw;ԄVi#^8Q&`%%Ey >53Bo[842bf -dLx31xxCI-oJlK5˗eck<_x31ҼlI-oJlK x340031Qpsgp1 a){Ƶ[.s740075Up)O+dpW~seNZL@SoAC1`5.z ,{ M>֙P!PL{OA) rN dOzDYG}IUe3~=͹&AbPSKJ @K$gZ,X llcxۣqI}?d)hdg$+(*l̝ /xk䳁Qp3FsF:txm͊@qoгs̈́UPiLwf:]ٮ,bb_DXaϾx1H_zݣ3_=}};>_fpq*5T*f|wɸxTiY @9MA3jwOknZ,J]נ@{FeGӊ*` :`@~RBDr .ɥ/+Ԟ{b q_U!̑#a+c`JvXO8`2sit -Qdx> Ay)rʰ/Uy>j[ՠ>)hb̔k8V[i RQKkfuFo*sXle=AZo窳ol >ڍf ` 7v{Y+1`Ltc dYZMU~f EvSxF43x[²eKJindn&I*c2x63o߼~fo'oG9.44.}Y6-JYUő gx2ql :7/׵`dL@O&E RKR2SJ22JR2sR+KRsBE y%): y)@i@A.Ay9y@CRB&+M㙬8FOf3JD/xkQp37lii|$L'? fgHo*yyqW)CxX3GU [pFa--GG96gh 89 x ɳs *100644 README+`'14IVNk=x$n3x:ql <:t+1":x3ML2 [0I M< #0$bB.xۦܡ!/KAA4-MS!%?OD!;/\!K"V  .y% )zP̼lbXqjBb^eIFf^*\!I#rx340031Qpsgp1 a){Ƶ[.s740075Up)O+do.O̤{pBq Kf`;_F5VoT#׼;l{'ȰMg3~9Y<$԰ WG_W/<s=wߠ J)-`rE;YkED YQYfj9W3ۜKmZ-v8y?? Mr:zVł}w+oPx>L LZO2f"YJV > _xP(?av&V܂wr\tFpxTM0WLw$* U{@TU~ -{Bl;6N %ћy3c?UZ&femNRAR*%9 bÆ钓%Hs iJf %w RywF>dw6 sȨYL-hBA.r( |7TE Idv?+B0S)rv\g5U%GAatWEUA5px%@js]UVLJ2ShH~'~nOf)᠑L8JC_`RX~~v~rP`:O3ӡ[-+18#PCo iӵ6?~<ř2Mjv{B^\ũ}z'=}i^!8D.4v] .< DU$Ticn.5#r{ޜBكzMugfynl"/᥃# I܄M[^SFA#[rn^Ylfnj@^^s=Lp&~c֘i]YDdu+t,tLdIm,-5kxk8rSNf^&BqIb^JR% hh*pvd&rx6Yfv{1w;2rˑmZÑPwyoqgq4 LZO2f"9YJ|s e x;sgU3@3 x[´i~v_&@;:WNt q sx[@/ CQǛ.TTHoT4MnZrS+)E[ՙ] WAlD8~-2`Q-TTN-=ubYVƖ,nQW7AoG Z0 i)>(_|ʨȳQ\W) g-|?4B<5$<1|Y(O(tJDSX[UN/B6L\mLWKk_]="&$>e2uDJ.K5 /_F`:%v_PjnRɹ2f[ka*6g {RlV]8KiR܀t%. xyzDvr6W&4 $"[OC/<oTUK[ xow=֜e0sCi!F {]{XX؇/|yL8,8<:p1NkmLb.`DŏvQVX(wM8*\jO9,,$,3$!vv]f100644 DroboDMP.cM˹6W뾈amZ@dcx[´i<3;={t㕰wa~x[SfC;&L"+KN x340031Qrutuep'sGroyfaW !xv(s)!b]5gparted failed},It's just the GUI,:, o)?-7RSS grows at aboutv w =T(=D)ydܢrsLhoho+repack.orig/.git/objects/pack/pack-5b161b6f03af0d6c5d2ea2211edc20e730dd29eb.idx0000444000175000017500000011745411265217256025743 0ustar morphmorphtOc #(-49@HLRW\bipsv}  "'/39@EGJNVZacfmt#*15:=DLUZ`ekmu| $(.048@EOU\\djlwz !$-08@GLP\`dipu| "*,2:=CKNV^ijmpr|#3z,!qkُEInt/E# ,d AGO 4d)KL4Dأ(j8pE9ziTs[NiFTL#0JoϳnC;QX0hRL|NuϽ3ٴmOvsQG:IyX i$Ϣ2g6Cs h52Й`^ÑPwyoqg<ܵn)z|WԶ k m,6m׊RT>?涨J>v^4>{hWn GBGbV~VG[50Cٹm[Z\8犱K%^xv3 HVad|4J"%9z2 _é)Cq8MFN*ze6C_s#6+6V+eQ;q/4C% kG쒌'ʱ c؀Hp}RRL8=.ǵr$) /ʂ7Pho0ss=vY}FG7 M:(5U'ALP2SX'qrAfǍ \KlӷW7߾Dmg0ܟ͍a:c,vJ=}Ҷ zӵ].L T[cV̈%% 0OdqN>@+ODtu`}\'W? 2?,Yon=ܭ,h;ˣ`Mpo PbG7a\@ a _1 ;)A y2oJĴ മ'#F yhY 'cz)>dO1 H"D-P@> ? m2}/rK.I Ə 4/ּZ,/֦ \P=_U)6qIr k5\>,WVB {͏HCM^ñ2ا{ UM4ZhտvH{ C 7@m')!׀C "єA( 2~ &M{ .?ռv'$ RU b8t ~[ ft>̀?5`7 6 Uy(&ɸ<>=") _ " ;m ﳿ󄢙׻:rIV.5 ~Pc&;P4 * ,Q/> C[R\u ~N7⺊/|d> >߱AY;^ć@n H|aѽ:Jm -M_mg%7%* Q<FKqYX~ VZ/ *FFh-#پ\)C eo!6"6bIz v!_ B,?T["#}B|`ƗV7RQtg~?p^es򂄐+U%lvf\dAz!A7!\|!o F.$\.9o k*W..]DE'Rd$¢ك7cDd Zl*gSRVB!J2G2hlQ-1f IH`VJEQ_RDS׬fA]t[SOWW! dRݴTБO e,O\52Ρ|3Y fnI&^iMRF58J+~/̹>GsrWNgfXY.bi&Kn7!) # FZ,g,[)4zorT4+&~@-vR&^wgB'!_X%}T)/-4Bf!CnSlߓ iI-_IV㨖Y9?g/P<=7"u\kse5i03d1^032?%@KB+XmJ>s)'F0X^[ODdIߺߞ2>z>Oe!T]^9T=dKގU@87ud{umH ,*Iu`$EMKK.`5V$ɸ4YPk.L|ʡy@{Uݔ<._Xѡ +}7 ˭+%~|izby@z |5NSv?`c9(1C+9ǖ(FDE&`BS J[W־%az8'EW`ld%:|HTr$WUMD[WjWH2.=a!JDsIf<ȫ1[YqEd,+<96ZvkFRQCHXKHVH?Cw+bHH}=5^{*DŜ AiF % L8v_ʌߏ#hC(W*0 g\řET`y1ީg-zNp(rFu&Z;" KEQi;ىsm;cfv\K]Q޵00ѷ~CT<꾬[If.A,4AZF 36xlUwuV ͦK@eڪw2i{9'b3LΐpOWع-&dVyߛI1ha|=cƱXNPgTx0RH92k]ۋ*ЩcC4kSY︃IX4aNaEt͏k;f]yYh8D2bƨd:#Ŕ!ӿޓ/s#cjAK(iR̮~ݎ&9~d;{c D;k,ѷ(\}fu:_u%U#LSpq;'ۙX'O@[E5{?mpnz,Ŏk8,~q8'0ߗ#: ~@4l •2 B49WٖaK"n|H Eʨ$^{{Ft p/ςe׶?YbZf<7PjF$2lZr˒>@|u$cmŠt>Su1%R4)px@1T% \xn,៙kZ5%r[fGR>Ggl%iostCB[+%${&nNDKF&"Z_m6 2#Xxx&73 o]PzWP&A'Fglʓw&K: iiau&rl ؒ< &NJn>$\k8X' zȈh$Oy'"x&/`X{'CĴ]HIi[ak'GOJ uL ]*h)''H/hLҼXV(߯wâd#8&(˔['z3Uh)# [G_KWR)E"w.6"^)PōFuDu{Q)\:I.Z38'C*Dզ[k2'?!Cs*abƻ;sww}*7sp!)*m` bh>]*îvFzѶl030-%Z%ٓML5Pf[8E-*B"昮ֶ-~3-J,м$-Amg z?-_R ,!-qƿҲ9@*FO9-yrFdH![7-kBI@QF♽j-L0/s^k-Y1Dlun-$DzNr..H9g%Q [ە@z.44.}Y6-JYU.QPu1ֿA 'heD's/H}FÍK+/IML"dQ*x҉E/1i D+&j0=p]+X?O^x zA0 {|9˭NԢl=A0{Km =bY=W0|Q'knƠ:W0]W+8 0c-C,hoq,=1ȓ>o }Bq3R1vր*X U˼1.P4Z% 18Z0d;D5Ƽی1[! D)~t1l)HOWX˿X_2. ==r7.Or)2V~O)tA䍏2t#taP58>̰!0 e2)S] YxbCLF2*SmP(Ggs2t__EߎtG$2ͣ&UM!-37&hmv~CjFe3{kPiCu<`:Ai3zn4? 8N`-KA4iHId`{4DY4˅(l-Mp>@ G.46grfG>]~e4mnҸOd5 6w ~]zgD~5Bsb.}ABE5ƚ hW5`ԘmVګY>5cZ{noȔh5O=oRap5Yѡ] gDrf̔5z 1&?kJO6v9~aSp~dxo6? dž4`S&6n?@)[*G;6nVD+*GLzƗ7yf$[gߡ7zN)oKB7qu'.Fl 7ք܎pG'@ms7cHLS}7a$X8*J48#<-X'dxr9ک<>$!vv]f:S5#t1g '=:;wc4~֡rx;{bԧi\?<0o~j;ֈ'f3˜f.kj;Ά$X./<+chv(TL28[ஃK<5F:!v%p}I`<AK`%<DpFErfmy=YyDg֮W+/U@eE3=rb8ϔN`]r;=w~egVE>Z=tl oHʡX={Ͱqo=&KA7!%ϑe=ˆ*6BlFV<(= MCNLT}H>9^?AyD~>\- L>X۩>4c_q]>o4)"?:K&a(?bZaNmr!CT^?u*#݂䖹g$q?zRKuVbOC,?-[t̤y463cB-?jL<MUZ?ˎ&kMpL@6Nlh8 wlrU@;B;T Hp^A+}w&ޙADM^/Epu׼$@+8BsܜQ0*ȺpzBUf8|Bw+Td\aHB<~(NI:O!B%P,79P"43C_QUz¹C/#ylf\PPtKC%Hn $f\/e}`C)'\k>K 4GzACNf$xUC1D Cy.qPS)@CJW}0Ӣ2HDdKny̮_/Dfk~WEtَHraDxEM"#d/WU=I@EɣO߱),yEυٵ;G$@B6JĎF!qV長IYaFQ zt6)ûF/DX{]=WB(eB F@ޙ_VG Gކ漠?3yGQn1YgN$Q"(Gv9.hGHet2{{mG^T:$1E 9uH:qƙ ,uH@D45js]H+\}ds>~HxjyZH6O5pwѓI#b[^_2Ie * \32!CI~d>Ia[{+x\L{IVN Ar\!RJH3 < DOJ8"?+JHhJ ʝ"#oNJJ Anϖm>O$PJq'(y L gJc7GRK5/dJqt p,JכMs7̭[l43KyO`\7V#iKM^3thBKU Kfp| GMC]K k-WZ6ط[Kՠel{M-RAL)hU8@5>f)Loޠ$}üvmLi+(Wp sLDXrQ8 MmL=ضi3RǼ8Pj%4*3HR x e$S {F/zFl7¯xS*EȋpU0uS>d){t9yȣSOA*WӶLѮ SC#,`g[5SВAb#wwSٶSN>߲x=QncT*68v01~!T̷gP%!8;<+PdTMt.Joԫ?e TxFo'H0mH̀U-4aaᴓs,vUmGfN^J<-U.? 64 W@"H%U+E,;m_mHk.Uo0VG+hy>WHLMn/VT+;n4/*WVV)Xuݚ/0Vz'C[-|*ܚZvV.'cG5cnW>5"`M'wsqpW*{qPi>iq>՟ǜaWcizX,'[BW v4uhVWurUwATO:nXT41`$Ms#VP%P2WZWVF$( ȘZ`1ObmY6tr ZnINÿ{RbZ>$‚yxʿp5[m /[`5]*M["6o H˔[ V]ƑJpm}r:;n7Q]tvř97 ^?e}*^S##$ٟzP $'ӟ^S0XxQ"uS%>^gчM/r̸w^u2`|mE^w^ ˿:]%bb^qu`hcp@O_wBH`|5r7^_3Q/cݍP;0_]w޺_ V:_=֟:r$J`q 2V'}K̃m` &t!Ccx6`Q.C`USJ @b@`b]L#]Ne4`4=g4m;w`"Xld``q琘A`pB3Lqngda&\z:7V`aS#L g˺yao3,HZS-aYEIqKascei* 1{a-<9`궩7Ha"Tڂ~GПaZtjfyFĊcjEav 47jJg[b۔f=QdM`/Vr4bOЄ_h#`4zKb<9z:c䨸.L>8WF#@3c"K2t8pi hkcHUj"=d$βeįikᩛrGdBHc(xXɍdUXq) .Ʌdl,tWCOYnP e 5JrL霶l.eM%AĢfmeLeUj()eėN*;Cˋ(Heu}e sjX͔eQ60y:׬G&S:eʧ/9]Q'.f}NA]XDbA 0fS&=3偊Z fv{1w;2rfzW(eF~fj?8,huzzI0kZfuwze(rfɣah -aMߝgL t"C\gh 89 x ɳs *g١ې6]rWh]wgL#/JOwQ`jah.rVJ(9o}̦h30G[o˔X!@Qh6_5saKPt?hO("6UZCzOs@Xm+w޻$yZ"6mh@bQ F6mdkoK0n M>-XiF\*n5)PczF< n\A񛼠Cqn†jɯ!^CVn.pP)vuM|Fn(_L?03E**o.qGj:8;aoH6tɤA GI^(4AoZՄ[ W"fPo~"R7(H^ogbިzlpe(I,__pR:F$tpĄ`7[ipa$kLL)lp[p y_!|0X3̛p2{Ki<7jqZmc{Y Kq K! hf"N+rNDSd]雲r"BuO/5vM^r8ƣy,CK[r/;H5;ƓBrc_+9/I9rڱ0 Fl(QIʶd#rUl(Uʿ ȃrx ^d,;aIrsOaH{trӾs ge?ܳ. -s'̘&3ŻIse!PFhbIi`"dsnWDx>Sy {- Z1Zq6w?$2yڀVcn<d^ly9®C=\1sS_n;ye>Lv̬´sy3/|;%%*aXz&6J1Ƥ.HOdzɕFTo0gNzeZaBVH{L sz*į{ZQo!kr~A{l"ݢ R<`'{W)Lf @}, 'S{(:* OZ X {wWs5EPa јjv{T׶>\M-2S!|d约ou"LT[yF|Z1h:q)?$u|wimmkJezX|CMr+sYQ Z-.b|u+MZ}MR,>2'GMr*}z!sDkVxs~odot|<~N+z,6ƿ,45~ZKۖp4sL)객~ju f5fЅ~kʔտ8`[ z] Y&~k*x$?M>i~B'1=K Zq~;`N} iuY,j_o(kԼ3ׯҀӝ!5|2QM]3c(49_x%_ia'/>M6#*G& #)mwN : >l?:IbXi1l9{)L4N Y,Dnڎ oe5:}b&Zڄ#iM̔r\1*Rʉ؂9ej4z@LlI%-ζIHy.ࠂ2F~e Fs#%f5azȕ؆Tг$7+J fsqB߀Wle5ٲT|jA\I<0^g 8瀱i+n u c2VS8Omvk_x50,׈ %.&q|,ؔ|VjA~hU~ܝ |NpfUEs|UeA\Sj S={<4ZV#ɶ6a8k [sxdRO- 톉 6 ogxK<>mǀ#K̇ Mk0MTA' w~>!ɋf$8<)ysVyQ̎"޸ZEs>(kV<AFW6߇,Yga'T34faS>#+^0OzD86Jg3[ TEv}捇}xl_j|\4 Jc)lX܇Yh<+1`XS EC9t^k 'D(alE@GIZkƢ%$OUQm`_x59u=aRڊf`ꈧ]pG㈶Nȫ@)YHCv]?`08~Ƚ#g"N8wإ.ͤƲ:"BÛbP܄\H1>s}]~/HlEf6e UK5ʉzo 3{Gor2.r})kWM켞.)*ۜ?6}"u0΋|wHs¿'U}S!pʒ^2NyI?w~rh3]>ꊃQg g>HCZ_eTYUl*,-j CC1BhɌU1{JGrIdC˿лV0h[ BRaaоG+T#CF\d'F9&/koB^L Q k{dI 5_:o,n aE\y$(1{YҌgP!a{+'TcX!Vk5ҍy^%{+ 9ɭ.hɚmȧǍ\F=l=#O"n2nz(gQb$ XBpN۟ ytrL:8R<|2Ct?dxQLGjDQ8 D&0p̵ۓ vSp*^&N-Cz>L˨}Jh5y>uP4DvD0MOF_ُ߇dSv%24M 7XU_B܌z$H-k kwh vr}PzX)WKhQ6 +\>. _^Is8rC]^ r[R$wWؗx@XO&A0/3+틤{$ݟPyUC b/Hj*D 2a(#]+lv*r5_Ia3h~(E iĮMDs"lS `~4Nӕ uŖ`:Ģn]h1f$@*3\ta O3$}T\64|_SfYo,)^6o#kM_VX̉lْe1TWipkLb !^(bu<%uB]}qw*KT)f.$ 4+*)-MsqءE3 [v_KEUDctQ{=z`OV>@A9 8u8[zMrs(dt×K\܋[Bn m:Uk !2Pc>8w)}5g0Χ .!rP?;z)E"H?A{K9u8mo|V^`QL3ٸ%qz< ؝+6g28fIȵ7"K#p:?=;ڴydŰgQ~Ncbc]Snu%rȏӪ0 [ݜ^-;+i8Aqfѽb2&487Ԭm =LnI7i-; r)r0ǔDٟK͠ya uǹ>񬎕}VzфϬȹ1\i+̐ ^Yvۏ!!̎ϗPݯNDknC7M 6ӐmqɘHM܅Zj88NMfRHcW[_ȠK*0@R뽇ZYiuYD ^YcPH0#H{(xO]^h02oi`gΝɓ|,P4js*7|@2UG+(C8/QlsjBb ݁43 Ày*0hy5oQ'#,ޟr9 Q(bv6)أv]"L|?D.C_ .=b;NB5j @P]8wd8`>~~& JTBwhۤFiyYS u+6@ɼwMSGDe8Ⱥw:(7~ mf}82iXX"dI@1.?b&c ѤM/z&l@F@ 7n#:buV[եFg56Mȭ#p=&džʯW>@IArԾ("(خ4.So%-|y[ $~߳D9CI珦Pz;JʾFVx^m]Ë"v UNٸFahBz9e[c2С/[_4kG%B+~2rHl) 0Eo)Қ;h$QDcq }mg 7؟q z~⭨kl=#ͱ1jrNnọpP+WiC.y9 6ӣfݨ}ni:}{kR~/uemY.jm,e >fDv ʮ_m0So5({},NV8^O ur8P~ d;lX;¥ulUBQde%Vc6Ar6cM6bֈ ǫ_-v+ݾfy ME>zj7MXU_44#H/ayMO:K#G3u/?b) o*ҽDڶȬ H [:+I3@Sbz` C0)֡Xa$RT7;#״yUiziUa3t`籔p^GB8LJ(OP8C1Kݗ:~"!n;>Jl.]+%M%[S]2~>Ξ?$KxN/  YSG_b9oWhwa%wyVfLWxt-dq&C*t ' v |}K]C1F.ShzlsC@q, -FWZ]\35OnTJ²S0c1YC/6tel+,6hEY.-S)>BdwɄ(r YMN\&g FN%e -fÀuʅhfAÚSB_3 UbV#täU>:W_ɻ_2ۈAvW eT% T`pFgF^fK[eXOGxSd9Zܲ+O}/c,Lj,?go:/7 )jE .xbx[~0l 6]~I⍙:Ō ;!ڟ ۨŎ_"(=ŧ %;s # AqJi8ϣ6o;6q}IwvO+wLpaƃ䮴6zΣ$M< ƉҗW3^`T8Ɩ, h6 ,F ƛ-~W{ xl-ơD8%MC삜KUƨ#Sw٣d L(crI_|s:zñELt/*qE) o$ c-F۱2"p}s]ҳ?|aNǑQSt-l?Mqގ ,a/Q!Leɭ)7޵1Eͨ1~CNPj[6sW\oP/>pʡ<;.eȋIm5 ./Ȣ$-' 9)ȳ|%.fbefs-ɮ'|@6*3U^kEB\&*e?Lܝ}o Lh!cc65/cN-6YEJrYʩ kI'*Lz F *8sYBnS9$f>J;W-:UOϿXlXk_4.15N5[OʃWm@Uڴ[VϨʈ+xXP&oʩT?C)61pv ܊н CSp^b_З:.=hL'$<!$ (/ʇ~?@Qہ yTzEDum_1ʧ5oy>d]s~f1a= -@eI3P<"DMtKӎeiHRhNUOO wSNهϢ7Q5C 8n7d"hqy_qV1G͗qtp-tlaͶ: t!_zFǭyϮO@Q~&w&+"yG|53Dw4yBflΤУ1*!dS6qs2Uग़rQu[C$-m_ԙeg_;A34^TL.>s]$WіxIZgFԯz_sw {uTϝQkбzYx=.V٬4&nsiY$))]2@ ӪZnW(E EاгCH5 ]{к`Hכy~hpzJցͳoSȤD/ACvھrpR9^Q]@k>*Q|d m~@+5 ~o\ڂKH$ ez[߱Baiѝ}Lic|H TvБ>p]L%,[O-*ݢ ə<'ZSEɏ{IWđΙ7[1@DJ0\JG%֊K}^9\2`:S}f iPj3LO\LE͖uήQ#t@ ɼ!-ӆl~\WWgӕz Ҿ.%̯&*E@2+;.-~fFMf.gzڭLo \0a4L4  >`#-r*LS4*k@~ծ8ub.qlLհs Є(l!BNNInD,mԽ\EW,,h֢C Rfbh)ϳ iֶu,r720+AkIsL'D>YW'Ilg׉sM"D`t$Eׯl\ڹ\CTSĞQ߅<ڪtRjozyfWZƱ{o@~+cuSUQĺ >G~YH'ؕf4w:s2^鬮paؿ.:/2x2\ƒ6JKڛ'0C>bgI1-80fdL~Zd=KrX"8>_BhdPb/P!Er}Xt}p>)*[ c)[pi? wek+,^+@Q ^oONn^ڬ߷TAB{4j\x"F.$>=* ۪N}{'2t\'H#{nVƅ5(#0``J!݄*jmc&n=wқb]܇k9.N 2>%K˭ܮdEw6{^UBEp& jKˆ{-5-?ឧs;)WIj8)=(a1`Dj[8AQRpX\fyQQ xݗ$)S[K퓝Eݼbd԰;7uRJ$.߅f­qcMeWdPm]DT߾ Rǒafŭ2!IPwM iޓm`P"9Ydkvޮ퇩G: | [<9Ro3;%s7QT`ຑߏY&~+ N4Cywrq)?Ƿ[5@+f46-l)XdFl<%YY@8eNv3.ᚉ9NjFT!'ѦA83_0O/뇒dCbyO CYDLwkg  ǤL$PnH!(\VWo"5іL!bEQ!*3i%D}ס˜&pl) N%X *C 3đQyr`A*.$LĀpB XVߴa$JR1SB=xo l},'jWҖWmAaltD5[78nm7F;U'tn|mE·S.(?PSs}+pcߑ, `@պ!xr/]AS%ar1/D iM$m@Yd ԢybqNFB9bV^V>bdqerdm 4R&eOk`P{,5 f‘DRz/юLC̓Mf.j|sJ:ܛ.؄AJu (*6m01ޭ-na $ qVUdP3Ւ#)`GӏW"{Jwˡ}b4NDEma?Ll8 qo#og%'?oHmIW!@l[McRU[晲a dj,D!0y"`qEL=vqٕaW"[Xh![QGN!3seebS<Fy7e*ePqQsuZ8W)HzK@)|cD){ഃ}~5.n0WyHo>ǠFs֣/Qڣ-TK )  `+ddD.Mhy[Ee2{cql} ,D1"թm[҂#NevI嶰^bƜu ' {F-HR + ʙ# /J"Ɓ*()2e9`2oO[q5 QljcF֟e,hOHʿd,dSAgr`b Du& @q6̊ 2F>/hO=zbѿժw5Rl("'(^Td+`(txsB^8;0IS]6r,gC]wW}Z&z9STlCrD9*ӹJo߼~fo'o홚T1g[y230#hs`hcLNfGºxŌCe*Vk+ff2pჇ@:t/ h ŖwRl  ަn IyKuchgV_u{d^J9[H4%0W۹G>xr;u643_N S]Qi*6coՠU %"*18NYɮ4>7s- tsVb=Gt=bPqCL9rtwoJFjk$pZD!_3?j_PS {U)MTmߎy)Z$&.lg.Wa+"%Џђ4₍CCgnE"XQx|9PֿҔ 6axj1WalOi'}&Haeuu'9vKKq4#xgw;|DԒ`3 jo'L.j ^FhrNUb12 ibPtnLװDh0RG|UH҉6sgL-Z6gLfjx7yVI: n|hRKD7'&ylFż[OyGJ]`s^j݁]Npw\KQqIQAޱ,\1fK\8-$&C<:b98,᫥rH4!1tCyme M+f]_>C~UyI|)jCtf*5eO%Uer4> ^}~b0o[!) \SZ.>p'w9;ĐsV"AAL+x8\̣|4dž{?Z?=n?\CY0 i==WƠ~F;c;_ֈp)z3m)WV{ &QEs>>c":L0 # %vWR Ѹ=A28#] Ru4|jELX։SphY,5k.P,u$7)~?>Xe7ن @HC" /w1 L|{񑼩i(M9ï,kjU5̮STd q&CdmU׽JCzm01YrںY ^Y>6#g<ɺc3vWG4l'aM:\VBA9C6*^S/5#}ɚ>M *P.$,u's?Xg(  R<07ߵ`3sokA*sbra#DMT ]WW)u;0¼u{+ Y,kFf0vÂ^2x/۲^8a,[1ʹ8v\hfx0yUQk;Pur^M5DX8C)tS |3QKR Q)4" ZhIjX)Qo?&]i`ՆT>g>0ׯf"`myzúuD~oMsW O-{*i*AQG)8^ȍs3UP04ǮfըAK:4#rCIM RCO ŤV* ~`qȴ7LC<Ә`Bn24'ӇG3Gh* *Hh iv'dxڥ=L3{ZV OLe\|RӔ 7 .ͅ4tiw)2VDtlƥW)x.ga?ưvs::.  hE(6D{1q{iKg9OLJM!kaǧL=jڿ%;Ex.Ôȗjqw+fpUO*zUB\OX %\BRjP-۞_j˧<`>xј_C9 IvOAw&#}tFP,ڕwc.mk  %~U// nX`p6<ڎ}{'|Ug6)g!0͚L0 :>NhOAJ/=ZiZ6W׋_ ]QK9 7a׵j\ [H/ tn E D-5Ld[\tcPrQY\ ryL4mf$V dȷxì"eyɐܓ|δѣՎ8X,+ \*'a3kF{@Ǐ2!¡* Յq&*`{8[U~YgK:r qC3y#MpwE_L`1N ׁg~iF4W w_@`y^ +hyO/Ctd풵;q31e]s)7֥r j%ш9/֏?#dlO[4]#8uAEPgNC~6!'[1AIuUƿl߫ni"~qiZFun[` ަTP:C qJ<.lхCՓt6CC~1Y*e+hˎMx~G1/QDr|X:ܹLd=qюgkQ3ժIV!"uHA/ڞ-75C3:ց&x{VKsF+.rPpF[v}:Pd-*`1t^R veOv-ՊC-J x4?;/p;и uc>ESʧT;{caKX(='N/η|.Z oM{TyAEW|s\aZ eq7+Vg^?R#AL݂0_zbA wziEUv8q9GV#PLăv;W0nsxL <<2`iJ67X"f|s٥o GQ]yUFᨸjSX\KTF+Js.ߞ=!y]ʚTwtϯ^8$%9`OoUVT/[lDd,Y_xͪj/PZײ&cpJ*C8E*cWs'5`A?t쉴{%8x,cE^Ieq)yB _nЪ4OW˅d#>:wUnn8=UtAk, %4ԟ5]oX[\GfҭY^:[WXȇ"$[C|m/zj:e@45w'XT[[NcDqWok&E@N}A"C.ݗTj7D=3O/! ^3IS-oѮ}0!ym//|8cGfRi]o^[>}PIYG<@Xx,!]v8 uOOx`/J3?.G> YZ);)tqv85Q䎵 Fd%2wt6X}EC% (Tt7ܡjO;dRyMH ee؅YX}|g~SQZo9]Xv+!դ,HC2=P\i24њV"շ=T'ǭ Yo}݅[;L|=)i鼸ћ` ˮEBm5"G))7oE24'c!%  {Y :|Vh-,|!XƸtdi+O%X xnK2IUbDfǯk[c/nLK"~ j>g{wPN5Kr%8(a^&J~gA qjRyucpHPASyh \o]W_a/ b wF }oH [BNAbHVed^$IzZ\yCHj3mRO]q4ifhCA{Ixwp{&W_DKͶOǼF>lO;L@\2 >*G\ʑMGU#f-Dg+"E^tLF0R~yWA$Y=L|RLJ9x܋jNgs%4lb["a?VЖٺyi[foRFr`gT]ʜ{r\r1pz`Ϛ%U,R? e<;ʈ|nr)@J+:9zQ%KňVzqb=#GgvlbjC܁e5^ '~SUSR$s-m,ҫUi^{=N C]:cJrz.W-Id}t4>We;y~f*= ]nrJo,sK %( izc*>fc_WtaD\-Bb4I4!&IPzR !Xۉ}"R$5Avf LUQLKY8 ]5Zn[dbn5 LZT\k=w9u=?r eFs ZxbM|Otx m6[R*i>dlJpX wDohj{E @OD~&X@cJ.a5U.ɱ@0t#qTeM|Bbl>LBK Gl+]\qv<.'rnbd,;Jt,9TxTEӣx. "Oϔ?N'hgN|afI%HV|`.?z&FLa:>`bT]F QlX8d:k$HBkK]U"vUNg zvmj)fY  sF5B@}1ΑVLD{P"eiAږ Ml\ElelC5^3p1]regyFXLd\GStM {3@-qZ=Zc]>:\=\L4rPH 4?Q& LS?~errP R ao *s[}z2`Y Pn@|q;A*rxXղ[^MmN]bb.hmMC>G(E*D[@̏Wvj,MǤp(/Z[>j@֯1 **i89B̥C^Aa,d<H_EIA.R5hFB]^_=Cju|DxHxVm?@[Xyۈ!ReXeI_lf^BLh~e# [VTȖ^PD;#H87GEAx,vJFkzS b+bM9[NÇQwK/n9v8;A B;s(c\dF: =5,#E&WabUXyH?1BuH^4Kldg̋V?XsfCdWHnS{IEwK8Cb0Ī=cʉnd[֯2UB}ԿZVl(\KC"9d}jmwyWO OqcuGovak=;]KYcQѓcn;įDv17Φt.M,0T{;“=D)ydܢrsL@݋<ndkWhoho+repack.orig/.git/objects/56/0000755000175000017500000000000011265223111015765 5ustar morphmorphhoho+repack.orig/.git/objects/56/361907cc8769a16da020b83e65f224f636224e0000444000175000017500000000316411265223111022623 0ustar morphmorphxWMs6ٿb{ݑINTm2m$㎿&N( tN=YxՓK?byL1_vOtʗ'SkT*hc>QggrS!Z~ҵJTXƹ9==m캠Ww5=m\iEqM,Ε\+ɴ-bOT)|c 97Wb5MP|7>TjMpÏ}ÁMƇ·5hbboD֏Ey3PӠ#kJBN&gDTiI{vKB Tx!@4pIY RR79X9]S? 9޴ExFt݌+_h\V%8S[l3.Ɛcj3„N zvH!d*"u>$Ruy3sno,w?qU gqMV}kAwVUpV\fz97کVOA ozQ۩&>߹٢F5d*؛] ƥ"'"F/Um"nn:RE0&^9}p4bCs&0姪3(\[K V`I隓+*TCR!tZ jV yAf\z7hXWryG!5 2!2G}ڂU1Cu-̊B5 UN;V1ai*=ZH )}xb&=g Ꭿ,h8r} (D$XYJE7uSeP-._0%:,!4Cgi`%z`t{tdjZu j?}~,R@v6 ,(ӲV|]1b (A^tru$Elgŕ9nՠ9{ꙁȩʌ߈/CAR7p!f}c٨t#IU )EӶ,ɳ-$‡-kkum6O7o|<ʼnyDC^`y(ICjH1ڋ77X%7[Ze~+1Lj^Dyt62]YޤX$&-AKŸ~){/@>}L E*4nBwUa <eAAh|Jƪ8iDA|g a?tRC ݐ[86;%3! u+˚W*Pk04FǼBpfV xqtQꯂeFw<՟rMuS!տYhoho+repack.orig/.git/objects/info/0000755000175000017500000000000011265217247016503 5ustar morphmorphhoho+repack.orig/.git/objects/15/0000755000175000017500000000000011265223111015760 5ustar morphmorphhoho+repack.orig/.git/objects/15/1483fb0603b38bd5faf96ccea761fe11c9ba2e0000444000175000017500000000030711265223111023402 0ustar morphmorphx1N0E})`83jk$fYGl+sYץAԫe.^cB7`m%y3:0igb",M& %URCT\m;pne,Ttq΢ U[m=iQe^2)9e lԚDT}}l' ^hoho+repack.orig/.git/objects/c6/0000755000175000017500000000000011265223111016043 5ustar morphmorphhoho+repack.orig/.git/objects/c6/3e1d5fa8364b60dcd868f8530949b5204ef6210000444000175000017500000000127311265223111023052 0ustar morphmorphx+)JMU04`040031QK,L/Je~y-f^mU$3L&Tk^IE EǦW-'zyL@;QKGm6$pu;Tkk0⛩KNiiǬ̅a*u݊Jt 4KVZ l|'P H^A%ߖ˖9ga9d32rR33R~:/Gg_/C6=drh.~+⼮qAK&{'N3k ҶX[YM4//l_+Nk{ѥ.}9U䛘ʐUhyR?=DA:MֱsiƇfm>"jF#+6N8s[v&PUHIMLc}宕wCgS7T4 P2ev޼Ug|iZQgs)$>ZUlJYfj9օ*Jw_0R{]ڬ2 )gr?w'KLU*KI(aPj:i;fʅژ ĢĜ >V%;|RӶj ;ԒPu6؛ +m>Ԡ\wP;\AJhoho+repack.orig/.git/objects/4f/0000755000175000017500000000000011265223111016044 5ustar morphmorphhoho+repack.orig/.git/objects/4f/6e6aef4bf6df9f928d6eaacc624c5203c6dc860000444000175000017500000000754011265223111023603 0ustar morphmorphxZ[sk+Ί" 6 "+` 6JY.j4Ӓf_l-We]왾>[,gt_G)th<ӫu^X2[|W*[dOѐުLQ 0e8xZG_{~瀞@׈u0C?F5|F~-]g ?3e6$ &bk(Ns#[9_ݠ9XL9qT^ ej?p_@ʩ; Cm$ ͺ_̑:Q1{ <' 5ˑ# Jg%TxW8y!(p=zN3ur柜+ k, h펨&r@ordeUc t{'f_kh*r#0L؉ dڻI2zY9;?y%fX~-)|2v+)L])DBA2.[_UtCP\`ܪz!TjT4KUGόam佩]-jDǖ[z8.J0/. ~ AW!Bu__繍RGޔf(ahL d-ԮkHfXR powP"K-~lPsﻦphνo1L>N湩uxuՒZK}o-?Q0+k O݁i=Sʙ 7`IN4~ťJ5uMI_&41d/sTdF4px u\G-~8,äH%vt/#=~Q ׆;!hw"Mu8Inhc)tл-w%ڌh|E nd%.7Uǘnh9sxɶwGg ΐ[O9F `W> 5'#m @Ka%.L̐p܊( mKPuf'S Ku8$YJ|e!65ΊO~YVuFxx gWD4U \z91: >Jh]򗹬=q %j{zN޻#N^v]OmU鄏]kcŸ]^7׀ww^}"y |Ag |]=P`@ O:xZ&ֻe >znnB=(eu&^ws:x׋O''o aUғЙxɋ+ -wS~@7ԤW`}D~ B-C}WfgPȞi;#.*;/W4qzf; +ֹhTQf6. wH.Ee?wM TֲAmE3JW0zvAr¹v6vV ~JmѪ-kc|bRIHqT@#rd[*Xg&\S$0fə%5Ly&ǧ/7!5ysDqh?ՑQ99-yϬ DWPo6ඉcqd=GD?6`%;D蚨PAjVOR8lqib5xǵ0긥~?؛fa*'F+*% }3z|hW{{gRʜTRKJ >_"ݲp%H3}g!:12TEF2:{irCe' 5פ3`Awt!~' _Uœ!\˪K ߆psw!#W5B![ysE^,V88=εu|&Q||JgW5o`ƗNs jN[>ڷv+~ּ!EVi9r-B\k9_Ag)>5pi Znyky;W#tܯE!4Wװ!ii^,T=?ov8Vw`q><7\/.O=\u4Ihoho+repack.orig/.git/objects/59/0000755000175000017500000000000011265223111015770 5ustar morphmorphhoho+repack.orig/.git/objects/59/68a9372d388a181fbab20b4739ce88a7aa39e00000444000175000017500000000025311265223111023127 0ustar morphmorphx 09mh7[B(5D"9Ch޼y C-"@;|)NF2Pd@:sD:j!{,} \*U ܆;ipY筰CI5sG GZ?5~?u˹QQXhoho+repack.orig/.git/objects/1b/0000755000175000017500000000000011265223111016035 5ustar morphmorphhoho+repack.orig/.git/objects/1b/98e6c894d659db773dc0f0d96eda3015ca88ed0000444000175000017500000000127211265223111023362 0ustar morphmorphx+)JMU04`040031QK,L/Je~y-f^mU$3L&Tk^IE {׃W~˶35$IL@;QKGm6$pu;Tkk0⛩KNiiǬ̅a*u݊Jt 4KVZ l|'P H^A%ߖ˖9ga9d32rR33R~:/Gg_/C6=drh.~+⼮qAK&{'N3k ҶX[YM4//l_+Nk{ѥ.}9U䛘ʐUhyR?=DA:MֱsiƇfm>"jF#+6N8s[v&PUHIMLcp\46&sE<ɒ 4)ezIy$1BςA1#@yySI}ٔr Up`Xq:ѵYe6#R4~O5hUZQ .!tNK5vsw.0Ksr3"Z(KMWgª%PSKJ @`o&\+Rs5BR@hoho+repack.orig/.git/objects/3d/0000755000175000017500000000000011265223111016041 5ustar morphmorphhoho+repack.orig/.git/objects/3d/47684ae09b91a9f0916d06ad495d85546227e60000444000175000017500000000520611265223111022723 0ustar morphmorphxX]s۶Ȕ,'i{gn$i1HBj`P]PܼD`ٳ,[_7uԙl8".Fimik]i 6a1ҏ L*6jr}C&ʅnkD[篷TkZнô6xkg4.di ]|LDwhNn?~߼M2{}t(gtW%_"zF*O}r+WI H;~naK~[D7)8D޵m'> |zmwsus}_G?5YRud(w@G$?v(MeK6X<ܽ8:F?3 8c\q)/}}t`Q_ȯ+3Z 悜RiڞZW2ftZ/ F)]ҎSjjǞBmTL\c᧯׼>?e dizIm ίCp}B'ȡ|I5;1D<&ڮ]VzA@H4x4mD&yA]bV Br:aAF)d5'WT<: Y %aVjI< 6ŀ¼-)\i/.~CKIA[kRK.Q5!$fBvQ,V9i dM=uQAP&qd^~۷ l:w=T3="Xpbu9:tS:lPd^ UCQB k ,uSnnCv܊tȪ3O87Z yd GkZap"Z@uEgibX*zjN7PGdf@R G,PIHKVwjXVOS (c[T D$ky8/3Zj̶*YOxbQogAC4Gƈfj+Zŕ9^;`9{ǃi}N^PUʇ fY2I1Ҕ1qr(+щ1*H0FMk?"~0\=r`mk3ғD<щ45 PJq֖ >`\&+Ԕ]e AzAzPql9_,{xP'橲LhY˅ e&A TQ)Se+~’-knΣ8:Ӳ e'H8$L!6^l@DF@R2ɄF]<5; .D:.Q'Ukd6j&ȾPixtf I ٧2 x:9=^vrg*-@#G1ǜ|א;6}bo}gBNlGz(i SwV 5mP8EyNc8.dMxEe̞[둍hYx(lW><|K <O @ X/{j⭴8Ĕcs(F1 8+&f0!1c@q`<2k@M&|ӂXt'$k[Qؠ`ܿz%Ih+Lfx:P+8!}e1 ՇS)f`)+;ȄLc/^ ,>Flf+bn*x:|Vo|ls,jTnM3,e_bcK1ś< дmS sL Y[:X(*t p@{fCX QĮ<| כfip#X2@/_隞dfC C =62A4M6=].F9#rޡDy>Ό5q.$k:{>h\dHY_@p!#?Z4..yX/o`ٷwo]W/»7rxjǺAvlCx.~/HPZī m?钫Иȶ!DU-\&9_1Yi]} =9q8[T搎NDg[:č 9&:]ziH'ɷHP^B,U~`}&i_8JK×'w0x/?6Ʃ[ ?8nB@&Ouv0W|G^?rg,4ީ{+eUĄ,sJWx< /i'2Y{#VǪ譾I@|>VVxBaQl=oH4s̶ lC2 f0_O2Op~PK]wQhoho+repack.orig/.git/info/0000755000175000017500000000000011265217247015052 5ustar morphmorphhoho+repack.orig/.git/info/exclude0000644000175000017500000000036011265217247016425 0ustar morphmorph# git-ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ hoho+repack.orig/.git/branches/0000755000175000017500000000000011265217247015704 5ustar morphmorphhoho+repack.orig/.git/logs/0000755000175000017500000000000011265217256015063 5ustar morphmorphhoho+repack.orig/.git/logs/HEAD0000644000175000017500000000145611265223361015507 0ustar morphmorph0000000000000000000000000000000000000000 3f867a52fd4b9775b1f656fd19ca62a8be4f432c Peter Silva 1255481006 -0400 clone: from ssh://peter_silva@drobo-utils.git.sourceforge.net/gitroot/drobo-utils/drobo-utils 3f867a52fd4b9775b1f656fd19ca62a8be4f432c ca052dd436eaaec759454a72a859caa9a8ede9c4 Peter Silva 1255481031 -0400 checkout: moving from master to origin/r0_6_1 ca052dd436eaaec759454a72a859caa9a8ede9c4 ca052dd436eaaec759454a72a859caa9a8ede9c4 Peter Silva 1255483047 -0400 checkout: moving from ca052dd436eaaec759454a72a859caa9a8ede9c4 to r0_6_1 ca052dd436eaaec759454a72a859caa9a8ede9c4 5968a9372d388a181fbab20b4739ce88a7aa39e0 Peter Silva 1255483121 -0400 pull origin r0_6_1: Fast forward hoho+repack.orig/.git/logs/refs/0000755000175000017500000000000011265217256016022 5ustar morphmorphhoho+repack.orig/.git/logs/refs/heads/0000755000175000017500000000000011265223232017075 5ustar morphmorphhoho+repack.orig/.git/logs/refs/heads/r0_6_10000644000175000017500000000052711265223361020015 0ustar morphmorph0000000000000000000000000000000000000000 ca052dd436eaaec759454a72a859caa9a8ede9c4 Peter Silva 1255483034 -0400 branch: Created from HEAD ca052dd436eaaec759454a72a859caa9a8ede9c4 5968a9372d388a181fbab20b4739ce88a7aa39e0 Peter Silva 1255483121 -0400 pull origin r0_6_1: Fast forward hoho+repack.orig/.git/logs/refs/heads/master0000644000175000017500000000035411265217256020326 0ustar morphmorph0000000000000000000000000000000000000000 3f867a52fd4b9775b1f656fd19ca62a8be4f432c Peter Silva 1255481006 -0400 clone: from ssh://peter_silva@drobo-utils.git.sourceforge.net/gitroot/drobo-utils/drobo-utils hoho+repack.orig/.git/logs/refs/remotes/0000755000175000017500000000000011265217256017500 5ustar morphmorphhoho+repack.orig/.git/logs/refs/remotes/origin/0000755000175000017500000000000011265223111020752 5ustar morphmorphhoho+repack.orig/.git/logs/refs/remotes/origin/r0_6_10000644000175000017500000000024211265223111021661 0ustar morphmorphca052dd436eaaec759454a72a859caa9a8ede9c4 5968a9372d388a181fbab20b4739ce88a7aa39e0 Peter Silva 1255482953 -0400 pull : fast forward hoho+repack.orig/.git/logs/refs/remotes/origin/HEAD0000644000175000017500000000035411265217256021415 0ustar morphmorph0000000000000000000000000000000000000000 3f867a52fd4b9775b1f656fd19ca62a8be4f432c Peter Silva 1255481006 -0400 clone: from ssh://peter_silva@drobo-utils.git.sourceforge.net/gitroot/drobo-utils/drobo-utils hoho+repack.orig/.git/FETCH_HEAD0000644000175000017500000000021711265223361015446 0ustar morphmorph5968a9372d388a181fbab20b4739ce88a7aa39e0 branch 'r0_6_1' of ssh://peter_silva@drobo-utils.git.sourceforge.net/gitroot/drobo-utils/drobo-utils hoho+repack.orig/.git/HEAD0000644000175000017500000000002711265223247014537 0ustar morphmorphref: refs/heads/r0_6_1 hoho+repack.orig/.git/packed-refs0000644000175000017500000000117211265217256016227 0ustar morphmorph# pack-refs with: peeled ca052dd436eaaec759454a72a859caa9a8ede9c4 refs/remotes/origin/r0_6_1 b84ec87b4f15eadaea77f05cecf8f18d38f9ee40 refs/remotes/origin/r0_6_0 e1576fd8ef2235afa0d2dbfc14ebd196ba4cd621 refs/remotes/origin/r0_5_0 dd3d2861baad9131ed60ced844f1fe6aec905b38 refs/remotes/origin/r0_4_0 bb87277a84b6f48cd8532ac706cfb00e5061d375 refs/remotes/origin/r0_3_3 9d02cb18ce3306ff14d9b825b0717ab93c0985d8 refs/remotes/origin/r0.2.1 b8ef39e4093294181f525919e6ea51107e1bef3c refs/remotes/origin/peter 51a50715d0ce4a26a499a8a9114f967bd3569d49 refs/remotes/origin/noC 3f867a52fd4b9775b1f656fd19ca62a8be4f432c refs/remotes/origin/master hoho+repack.orig/.git/description0000644000175000017500000000007211265217247016364 0ustar morphmorphUnnamed repository; edit this file to name it for gitweb. hoho+repack.orig/.git/config0000644000175000017500000000046211265217256015311 0ustar morphmorph[core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true [remote "origin"] url = ssh://peter_silva@drobo-utils.git.sourceforge.net/gitroot/drobo-utils/drobo-utils fetch = +refs/heads/*:refs/remotes/origin/* [branch "master"] remote = origin merge = refs/heads/master hoho+repack.orig/.git/hooks/0000755000175000017500000000000011265217247015242 5ustar morphmorphhoho+repack.orig/.git/hooks/post-receive.sample0000755000175000017500000000105111265217247021052 0ustar morphmorph#!/bin/sh # # An example hook script for the "post-receive" event. # # The "post-receive" script is run after receive-pack has accepted a pack # and the repository has been updated. It is passed arguments in through # stdin in the form # # For example: # aa453216d1b3e49e7f6f98441fa56946ddcd6a20 68f7abf4e6f922807889f52bc043ecd31b79f814 refs/heads/master # # see contrib/hooks/ for an sample, or uncomment the next line and # rename the file to "post-receive". #. /usr/share/doc/git-core/contrib/hooks/post-receive-email hoho+repack.orig/.git/hooks/pre-applypatch.sample0000755000175000017500000000061611265217247021404 0ustar morphmorph#!/bin/sh # # An example hook script to verify what is about to be committed # by applypatch from an e-mail message. # # The hook should exit with non-zero status after issuing an # appropriate message if it wants to stop the commit. # # To enable this hook, rename this file to "pre-applypatch". . git-sh-setup test -x "$GIT_DIR/hooks/pre-commit" && exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"} : hoho+repack.orig/.git/hooks/pre-commit.sample0000755000175000017500000000100711265217247020522 0ustar morphmorph#!/bin/sh # # An example hook script to verify what is about to be committed. # Called by git-commit with no arguments. The hook should # exit with non-zero status after issuing an appropriate message if # it wants to stop the commit. # # To enable this hook, rename this file to "pre-commit". if git-rev-parse --verify HEAD 2>/dev/null then against=HEAD else # Initial commit: diff against an empty tree object against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 fi exec git diff-index --check --cached $against -- hoho+repack.orig/.git/hooks/post-commit.sample0000755000175000017500000000024011265217247020717 0ustar morphmorph#!/bin/sh # # An example hook script that is called after a successful # commit is made. # # To enable this hook, rename this file to "post-commit". : Nothing hoho+repack.orig/.git/hooks/commit-msg.sample0000755000175000017500000000157611265217247020535 0ustar morphmorph#!/bin/sh # # An example hook script to check the commit log message. # Called by git-commit with one argument, the name of the file # that has the commit message. The hook should exit with non-zero # status after issuing an appropriate message if it wants to stop the # commit. The hook is allowed to edit the commit message file. # # To enable this hook, rename this file to "commit-msg". # Uncomment the below to add a Signed-off-by line to the message. # Doing this in a hook is a bad idea in general, but the prepare-commit-msg # hook is more suited to it. # # SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') # grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" # This example catches duplicate Signed-off-by lines. test "" = "$(grep '^Signed-off-by: ' "$1" | sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { echo >&2 Duplicate Signed-off-by lines. exit 1 } hoho+repack.orig/.git/hooks/update.sample0000755000175000017500000000551411265217247017737 0ustar morphmorph#!/bin/sh # # An example hook script to blocks unannotated tags from entering. # Called by git-receive-pack with arguments: refname sha1-old sha1-new # # To enable this hook, rename this file to "update". # # Config # ------ # hooks.allowunannotated # This boolean sets whether unannotated tags will be allowed into the # repository. By default they won't be. # hooks.allowdeletetag # This boolean sets whether deleting tags will be allowed in the # repository. By default they won't be. # hooks.allowdeletebranch # This boolean sets whether deleting branches will be allowed in the # repository. By default they won't be. # # --- Command line refname="$1" oldrev="$2" newrev="$3" # --- Safety check if [ -z "$GIT_DIR" ]; then echo "Don't run this script from the command line." >&2 echo " (if you want, you could supply GIT_DIR then run" >&2 echo " $0 )" >&2 exit 1 fi if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then echo "Usage: $0 " >&2 exit 1 fi # --- Config allowunannotated=$(git config --bool hooks.allowunannotated) allowdeletebranch=$(git config --bool hooks.allowdeletebranch) allowdeletetag=$(git config --bool hooks.allowdeletetag) # check for no description projectdesc=$(sed -e '1q' "$GIT_DIR/description") if [ -z "$projectdesc" -o "$projectdesc" = "Unnamed repository; edit this file to name it for gitweb." ]; then echo "*** Project description file hasn't been set" >&2 exit 1 fi # --- Check types # if $newrev is 0000...0000, it's a commit to delete a ref. if [ "$newrev" = "0000000000000000000000000000000000000000" ]; then newrev_type=delete else newrev_type=$(git-cat-file -t $newrev) fi case "$refname","$newrev_type" in refs/tags/*,commit) # un-annotated tag short_refname=${refname##refs/tags/} if [ "$allowunannotated" != "true" ]; then echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 exit 1 fi ;; refs/tags/*,delete) # delete tag if [ "$allowdeletetag" != "true" ]; then echo "*** Deleting a tag is not allowed in this repository" >&2 exit 1 fi ;; refs/tags/*,tag) # annotated tag ;; refs/heads/*,commit) # branch ;; refs/heads/*,delete) # delete branch if [ "$allowdeletebranch" != "true" ]; then echo "*** Deleting a branch is not allowed in this repository" >&2 exit 1 fi ;; refs/remotes/*,commit) # tracking branch ;; refs/remotes/*,delete) # delete tracking branch if [ "$allowdeletebranch" != "true" ]; then echo "*** Deleting a tracking branch is not allowed in this repository" >&2 exit 1 fi ;; *) # Anything else (is there anything else?) echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 exit 1 ;; esac # --- Finished exit 0 hoho+repack.orig/.git/hooks/post-update.sample0000755000175000017500000000027511265217247020721 0ustar morphmorph#!/bin/sh # # An example hook script to prepare a packed repository for use over # dumb transports. # # To enable this hook, rename this file to "post-update". exec git-update-server-info hoho+repack.orig/.git/hooks/pre-rebase.sample0000755000175000017500000001151611265217247020501 0ustar morphmorph#!/bin/sh # # Copyright (c) 2006, 2008 Junio C Hamano # # The "pre-rebase" hook is run just before "git-rebase" starts doing # its job, and can prevent the command from running by exiting with # non-zero status. # # The hook is called with the following parameters: # # $1 -- the upstream the series was forked from. # $2 -- the branch being rebased (or empty when rebasing the current branch). # # This sample shows how to prevent topic branches that are already # merged to 'next' branch from getting rebased, because allowing it # would result in rebasing already published history. publish=next basebranch="$1" if test "$#" = 2 then topic="refs/heads/$2" else topic=`git symbolic-ref HEAD` || exit 0 ;# we do not interrupt rebasing detached HEAD fi case "$topic" in refs/heads/??/*) ;; *) exit 0 ;# we do not interrupt others. ;; esac # Now we are dealing with a topic branch being rebased # on top of master. Is it OK to rebase it? # Does the topic really exist? git show-ref -q "$topic" || { echo >&2 "No such branch $topic" exit 1 } # Is topic fully merged to master? not_in_master=`git-rev-list --pretty=oneline ^master "$topic"` if test -z "$not_in_master" then echo >&2 "$topic is fully merged to master; better remove it." exit 1 ;# we could allow it, but there is no point. fi # Is topic ever merged to next? If so you should not be rebasing it. only_next_1=`git-rev-list ^master "^$topic" ${publish} | sort` only_next_2=`git-rev-list ^master ${publish} | sort` if test "$only_next_1" = "$only_next_2" then not_in_topic=`git-rev-list "^$topic" master` if test -z "$not_in_topic" then echo >&2 "$topic is already up-to-date with master" exit 1 ;# we could allow it, but there is no point. else exit 0 fi else not_in_next=`git-rev-list --pretty=oneline ^${publish} "$topic"` perl -e ' my $topic = $ARGV[0]; my $msg = "* $topic has commits already merged to public branch:\n"; my (%not_in_next) = map { /^([0-9a-f]+) /; ($1 => 1); } split(/\n/, $ARGV[1]); for my $elem (map { /^([0-9a-f]+) (.*)$/; [$1 => $2]; } split(/\n/, $ARGV[2])) { if (!exists $not_in_next{$elem->[0]}) { if ($msg) { print STDERR $msg; undef $msg; } print STDERR " $elem->[1]\n"; } } ' "$topic" "$not_in_next" "$not_in_master" exit 1 fi exit 0 ################################################################ This sample hook safeguards topic branches that have been published from being rewound. The workflow assumed here is: * Once a topic branch forks from "master", "master" is never merged into it again (either directly or indirectly). * Once a topic branch is fully cooked and merged into "master", it is deleted. If you need to build on top of it to correct earlier mistakes, a new topic branch is created by forking at the tip of the "master". This is not strictly necessary, but it makes it easier to keep your history simple. * Whenever you need to test or publish your changes to topic branches, merge them into "next" branch. The script, being an example, hardcodes the publish branch name to be "next", but it is trivial to make it configurable via $GIT_DIR/config mechanism. With this workflow, you would want to know: (1) ... if a topic branch has ever been merged to "next". Young topic branches can have stupid mistakes you would rather clean up before publishing, and things that have not been merged into other branches can be easily rebased without affecting other people. But once it is published, you would not want to rewind it. (2) ... if a topic branch has been fully merged to "master". Then you can delete it. More importantly, you should not build on top of it -- other people may already want to change things related to the topic as patches against your "master", so if you need further changes, it is better to fork the topic (perhaps with the same name) afresh from the tip of "master". Let's look at this example: o---o---o---o---o---o---o---o---o---o "next" / / / / / a---a---b A / / / / / / / / c---c---c---c B / / / / \ / / / / b---b C \ / / / / / \ / ---o---o---o---o---o---o---o---o---o---o---o "master" A, B and C are topic branches. * A has one fix since it was merged up to "next". * B has finished. It has been fully merged up to "master" and "next", and is ready to be deleted. * C has not merged to "next" at all. We would want to allow C to be rebased, refuse A, and encourage B to be deleted. To compute (1): git-rev-list ^master ^topic next git-rev-list ^master next if these match, topic has not merged in next at all. To compute (2): git-rev-list master..topic if this is empty, it is fully merged to "master". hoho+repack.orig/.git/hooks/applypatch-msg.sample0000755000175000017500000000070411265217247021402 0ustar morphmorph#!/bin/sh # # An example hook script to check the commit log message taken by # applypatch from an e-mail message. # # The hook should exit with non-zero status after issuing an # appropriate message if it wants to stop the commit. The hook is # allowed to edit the commit message file. # # To enable this hook, rename this file to "applypatch-msg". . git-sh-setup test -x "$GIT_DIR/hooks/commit-msg" && exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"} : hoho+repack.orig/.git/hooks/prepare-commit-msg.sample0000755000175000017500000000230311265217247022156 0ustar morphmorph#!/bin/sh # # An example hook script to prepare the commit log message. # Called by git-commit with the name of the file that has the # commit message, followed by the description of the commit # message's source. The hook's purpose is to edit the commit # message file. If the hook fails with a non-zero status, # the commit is aborted. # # To enable this hook, rename this file to "prepare-commit-msg". # This hook includes three examples. The first comments out the # "Conflicts:" part of a merge commit. # # The second includes the output of "git diff --name-status -r" # into the message, just before the "git status" output. It is # commented because it doesn't cope with --amend or with squashed # commits. # # The third example adds a Signed-off-by line to the message, that can # still be edited. This is rarely a good idea. case "$2,$3" in merge,) perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;; # ,|template,) # perl -i.bak -pe ' # print "\n" . `git diff --cached --name-status -r` # if /^#/ && $first++ == 0' "$1" ;; *) ;; esac # SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') # grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" hoho+repack.orig/.git/index0000644000175000017500000000470011265223361015144 0ustar morphmorphDIRCJJ  ﳿ󄢙׻:rIV.5 .gitignoreJ&J& =GhJmI]Tb' CHANGES.txtJJ D2Tt e$6"Ndebian/changelogJJ ~k*x$?M>i debian/compatJJ &"Z_m6 2#Xxxdebian/controlJJ 71ȓ>o }Bq3Rdebian/copyrightJJ C}VzфϬȹ1\i+ debian/docsJJ Loޠ$}üvmdebian/drobo-utils.manpagesJJ  8k [sxdRO- debian/rulesJJ 0 {|9˭NԢl=Adebian/uscan-repack.shJJ t8K_pH". debian/watchJ&J& )OnjKߟnbLR܆drobomJJ  7![]Q7nnzHdrobom.8JJ $" }'2֚ droboviewJJ #N=DYdtV="^ droboview.8JJ jX'O@[E5{?m index.htmlJJ YF+rM~efpmake_tarball.shJJ ҉?6}"u0΋|wsetup.py(-ZwلLs4hoho+repack.orig/.git/refs/0000755000175000017500000000000011265217256015056 5ustar morphmorphhoho+repack.orig/.git/refs/heads/0000755000175000017500000000000011265223361016134 5ustar morphmorphhoho+repack.orig/.git/refs/heads/r0_6_10000644000175000017500000000005111265223361017041 0ustar morphmorph5968a9372d388a181fbab20b4739ce88a7aa39e0 hoho+repack.orig/.git/refs/heads/master0000644000175000017500000000005111265217256017354 0ustar morphmorph3f867a52fd4b9775b1f656fd19ca62a8be4f432c hoho+repack.orig/.git/refs/tags/0000755000175000017500000000000011265217247016014 5ustar morphmorphhoho+repack.orig/.git/refs/remotes/0000755000175000017500000000000011265217256016534 5ustar morphmorphhoho+repack.orig/.git/refs/remotes/origin/0000755000175000017500000000000011265223111020006 5ustar morphmorphhoho+repack.orig/.git/refs/remotes/origin/r0_6_10000644000175000017500000000005111265223111020713 0ustar morphmorph5968a9372d388a181fbab20b4739ce88a7aa39e0 hoho+repack.orig/.git/refs/remotes/origin/HEAD0000644000175000017500000000004011265217256020441 0ustar morphmorphref: refs/remotes/origin/master hoho+repack.orig/Drobo.py0000755000175000017500000013005711265217307014703 0ustar morphmorph""" The Drobo module is used to get configuration data from a Data Robotics Inc. "Drobo" storage unit. The ways of querying the unit are derived mostly from: DROBO Management Protocol Specification Rev. A.0 03/08 referred herein as 'DMP Spec'. Another source of data was the droboprotocoldefs.h file (referred to as dmp.h). The last source of information is what the device actually does. Many inconsistencies were identified. ERRATA is used to identify when a conflict was apparent. tested with firmware: 1.0.3 and later... ( Drobo is a trademark of Data Robotics Inc. ) copyright: Drobo Utils Copyright (C) 2008,2009 Peter Silva (Peter.A.Silva@gmail.com) Drobo Utils comes with ABSOLUTELY NO WARRANTY; For details type see the file named COPYING in the root of the source directory tree. """ import fcntl, struct, socket, array, commands, time import exceptions import os, sys, re import types #only for fw download... import os.path import urllib2 import zipfile,zlib #only for simulation mode... import random # maximum transaction ID before wrapping... MAX_TRANSACTION = 250 # obviously need to update this with every release. VERSION = '0.6.1' # set to non-zero to increase verbosity of library functions. DEBUG = 0 # It's a bit field, DBG_Chatty = 0x01 DBG_HWDialog = 0x02 DBG_Instantiation = 0x04 #DBG_DMP = 0x08 # C-layer... not used here... DBG_Detection = 0x10 DBG_General = 0x20 # This isn't entirely simulation mode. It is to aid development # when no drobo is available. You can format random disks, including # non-drobos. So do not activate unless you read what the code does first. # in simulation mode, can run non-root, best for GUI work. DBG_Simulation = 0x80 #for generic SCSI IO details... import DroboIOctl class DroboException(exceptions.Exception): """ If there is a problem accessing the Drobo, this exception is raised. """ def __init__(self, msg="Unknown"): self.msg = msg def __str__(self): print "Problem accessing a Drobo: " + self.msg def _ledstatus(n): """ return colors decoded, given numeric slot status goal: match what the lights are doing on the unit. STATUS: working with ERRATA: Developer Notes: The spec says: status is high order 3 bits, and starting from 0, goes: green, yellow, Red, ( Green Yellow ) dmp.h says: forget the high order 3 bits, it's the whole byte. off is supposed to be 0, but doesn't match when flashing red green.. off, red, yellow, green, yellow-green, red-green, red-off, red-yellow my drobo says: high order bits always 0. status seems to use whole byte. green is 3, flashing red-green is 4... which dmp.h says is yellow green flashing red-black is 6... agrees with dmp.h 0x80 is indeed an empty slot, as per dmp.h unknown-- yellow-green... matches neither... hmm... """ colourstats=[ 'black', 'red', 'yellow', 'green', ['red', 'green'], [ 'red', 'yellow' ], ['red', 'black'] ] if DEBUG & DBG_General: print 'colourstats, argument n is: ', n if ( n == 0x80 ): # empty return 'gray' return colourstats[n & 0x0f ] def _unitstatus(n): """ return string, given numeric unit status STATUS: working with ERRATA: here is what the spec says should work (integers...): ust = [ 'Normal', 'Red Threshold Exceeded', 'Yellow Threshold Exceeded', 'No Disks', 'Bad Disk', 'Multiple Disks Removed', 'No Redundancy', 'No Magic Hotspare', 'Unit Full', 'Relay Out in Progress', 'Format in Progress' ] return ust[n] the .h files says... no stupid... it's bit fields. I don't much care as long as folks make up their mind. I have a higher regard for the .h so that implementation is active. """ f = [] if ( n & 0x0002 ): f.append( 'Red alert' ) if ( n & 0x0004 ): f.append( 'Yellow alert' ) if ( n & 0x0008 ): f.append( 'No disks' ) if ( n & 0x0010 ): f.append( 'Bad disk' ) if ( n & 0x0020 ): f.append( 'Too many missing disks' ) if ( n & 0x0040 ): f.append( 'No redundancy' ) if ( n & 0x0080 ): f.append( 'No magic hotspare' ) if ( n & 0x0100 ): f.append( 'no space left' ) if ( n & 0x0200 ): f.append( 'Relay out in progress' ) if ( n & 0x0400 ): f.append( 'Format in progress' ) if ( n & 0x0800 ): f.append( 'Mismatched disks' ) if ( n & 0x1000 ): f.append( 'Unknown version' ) if ( n & 0x2000 ): f.append( 'New firmware installed' ) if ( n & 0x4000 ): f.append( 'New LUN available after reboot' ) if ( n & 0x10000000):# was going to say 'Let us pray...', but no need to alarm people. f.append( 'Unknown error' ) return f def _partformat(n): """ return Drobo's idea of what the partition type is STATUS: working with ERRATA: the codes are wonky... dmp.h says 0x08 for EXT3, but my Drobo says, 0x80 says 0x01 is 'no format', but my Drobo says that is NTFS. tried added >>4 but that says only one bit is supposed to be set, but, I dunno if I trust it. returning a tuple for now. """ f = [] if ( n & 0x01 ): f.append( 'NTFS' ) if ( n & 0x02 ): f.append( 'NO FORMAT' ) if ( n & 0x04 ): f.append( 'HFS' ) if ( n & 0x80 ): # on Peter's... f.append( 'EXT3' ) #if ( n & 0x08 ): # on Matthew Mastracci's # f.append( 'EXT3' ) if ( n & 0xFF ) == 0: f.append( 'FAT32' ) if (len(f) != 1): print 'hoho! multiple partition types! Brave are we not?' return f def _partscheme(n): """ return what drobo thinks the partition scheme is STATUS: working, no issues. Have set all of them on my drobo using parted, was detected correctly. """ if (n == 0): return "No Partitions" if (n == 1): return "MBR" if (n == 2): return "APM" if (n == 3): return "GPT" def _unitfeatures(norig): """ return a list of features supported by a unit STATUS: working. this comes straight from dmp.h.. what they mean isn't documented. stuff that looks wrong: -- USED_CAPACITY... should be USE_CAPACITY ... no 'D' -- all the 'SUPPORTS' texts are redundant. every bit is about what is supported. It should be just LUNINFO2 etc... feature x0800 and 0x2000 show up on my Drobo v1 running 1.3.0... of course, do not know what they are... """ n=norig feature_map = [ ( 0x001, 'NO_AUTO_REBOOT' ), ( 0x0002, 'NO_FAT32_FORMAT' ), ( 0x0004, 'USED_CAPACITY_FROM_HOST' ), ( 0x0008, 'DISKPACKSTATUS' ), ( 0x0010, 'ENCRYPT_NOHEADER' ), ( 0x0020, 'CMD_STATUS_QUERIABLE' ), ( 0x0040, 'VARIABLE_LUN_SIZE_1_16' ), ( 0x0080, 'PARTITION_LUN_GPT_MBR' ), ( 0x0100, 'FAT32_FORMAT_VOLNAME' ), ( 0x0200, 'SUPPORTS_DROBOSHARE' ), ( 0x0400, 'SUPPORTS_NEW_LUNINFO2' ), ( 0x0800, 'feature x0800' ), ( 0x1000, 'LUN_MANAGEMENT' ), ( 0x2000, 'feature x2000 ' ), ( 0x4000, 'SUPPORTS_OPTIONS2' ), ( 0x8000, 'SUPPORTS_SHUTDOWN' ), ( 0x80000000, 'SUPPORTS_SINGLE_LUN_FORMAT' ), ( 0x40000000, 'SUPPORTS_VOLUME_RENAME' ) ] f = [] for feature in feature_map: #print "checking for %s %04x in %04x: " % ( feature[1], feature[0], n ) if n & feature[0] : n = n & ~ feature[0] f.append( feature[1] ) if n != 0: f.append( "leftovers (%04x)" % n ) return f class Drobo: """ Drobo the class for data exchange with the storage units. briefly, communicates using SCSI sub_page blocks. There are member functions for each page type... See the DMP Spec for details. All capacity returned are in bytes. the rest of this comment is destined only for Drobo.py developers, not users: DMP Spec ERRATA, by subpage: - in config, last Q is capacity, manual says bytes, sample code says *512, which works better... so actual quantity is 512 byte blocks. - in slotinfo, 'managed capacity' is always 0, is that OK? - in version, seems to want an extra byte. BB fails, but BBB works... returns - in settings, the 32 byte name starts with a null byte before 'TRUSTED DATA', is that normal? """ def __init__(self,chardevs,debugflags=0): """ chardev is /dev/sdX... the character device associated with the drobo unit """ global DEBUG DEBUG=debugflags if DEBUG & DBG_Instantiation : print '__init__ ' self.fd=None if type(chardevs) is types.ListType: self.char_dev_file = chardevs[0] self.char_devs = chardevs else: self.char_dev_file = chardevs self.char_devs = [ chardevs ] self.features = [] self.transactionID=random.randint(1,MAX_TRANSACTION) self.relaystart=0 if DEBUG & DBG_Simulation == 0: self.fd=DroboIOctl.DroboIOctl(self.char_dev_file,0,debugflags) if self.fd == None : raise DroboException # more thorough checks for Drobohood... # for some reason under ubuntu intrepid, start getting responses of all bits set. # need some ways to spot a real drobo. cfg = self.GetSubPageConfig() #Side effect: Config, sets self.slot_count... if DEBUG & DBG_Detection: print "cfg: ", cfg if ( len(cfg) != 3 ): # We ask this page to return three fields... if DEBUG & DBG_Detection: print "%s length of cfg is: %d, should be 3" % (self.char_dev_file, len(cfg)) raise DroboException if ( self.slot_count < 4 ): if DEBUG & DBG_Detection: print "%s cfg[0] = %s, should >= 4. All Drobos have at least 4 slots" % (self.char_dev_file, cfg[0]) raise DroboException # Assert: All Drobo have 4 slots. set=self.GetSubPageSettings() if DEBUG & DBG_Detection: print "settings: ", set fw=self.GetSubPageFirmware() if ( len(fw) < 8 ) and (len(fw[7]) < 5): if DEBUG & DBG_Detection: print "%s length of fw query: is %d, should be < 8." % (self.char_dev_file, len(fw)) print "%s len(fw[7]) query: is %d, should be < 5." % (self.char_dev_file, len(fw[7])) raise DroboException if ( fw[6].lower() != 'armmarvell' ): if DEBUG & DBG_Detection: print "%s fw[6] is not armmarvell." % self.char_dev_file raise DroboException def __del__(self): if DEBUG & DBG_Instantiation : print '__del__ ' if self.fd != None : self.fd.closefd() self.fd=None def format_script(self,fstype='ext3'): """ return a shell script giving the code to commands required to format the single LUN represented by a given drobo... pscheme is one of: mbr, apt, gpt, gpt - >= 2 TB, linux or windows... mbr <= 2 TB good for FAT32 fstype is one of: fat32, ext3, ntfs (HPS+ is not supported on linux) sizes in terabytes not implemented yet... each lun is formatted as a single primary partition. partitions are never marked bootable. need to detect each lun... algorithm: do discoverLUNs() figure out which LUNs belong to the current Drobo... How? -- do not want to partition LUNS on another Drobo! That would be bad! for l in LUN: parted /dev/sd?? mklabel gpt mkpart pri ext2 0 -1 mke2fs -j ... /dev/sd?? """ format_script='/tmp/fmtscript' fd=open(format_script, 'w') fd.write( "#!/bin/sh\n" ) if fstype == 'FAT32' or fstype == 'msdos': ptype='msdos' else: ptype='gpt' for cd in self.char_devs: fd.write( "parted -s %s mklabel %s\n" % (cd, ptype) ) # there is a bit of a race condition creating the partition special file. # the parted print gives a little time before starting the mkfs, to ensure # file is there... if fstype == 'ext3': # -m 0 -- Drobo takes care of complaining when near the size limit. # little point in complaining early, pretending you have less space. # ^resize_inode -- Drobo makes the file system much bigger than the actual space # available ( >= 2TB ) , so it doesn't make sense to allow space for future # inode expansion beyond that. only makes sense in LVM, that's why this # option is 'off' (the '^' at the beginning.) # sparse_super -- there are lots too many superblock copies made by default. # safe enough with fewer. fd.write( "parted -s %s mkpart ext2 0 100%%\n" % cd ) fd.write( "parted -s %s print; sleep 5\n" % cd ) fd.write( 'mke2fs -j -i 262144 -L Drobo01 -m 0 -O sparse_super,^resize_inode %s1\n' % cd ) elif fstype == 'ntfs': fd.write( "parted -s %s mkpart ntfs 0 100%%\n" % cd ) fd.write( "parted -s %s print; sleep 5\n" % cd ) fd.write( 'mkntfs -f -L Drobo01 %s1\n' % cd ) elif fstype == 'FAT32' or fstype == 'msdos': fd.write( "parted -s %s mkpart primary fat32 0 100%%\n" % cd ) fd.write( "parted -s %s print; sleep 5\n" % cd ) fd.write( 'mkdosfs -v -v -F 32 -S 4096 -n Drobo01 %s1\n' % cd ) else: print 'unsupported partition type %s, sorry...' % fstype fd.close() os.chmod(format_script,0700) #if DEBUG & DBG_Simulation !=0: return format_script #fmt_process = subprocess.Popen( format_script, close_fds=True ) #pid, sts = os.waitpid(fmt_process.pid, 0) def __getsubpage(self,sub_page,pack): """Retrieve Sub page from drobo block device. Uses DroboIOctl class to run the raw ioctl. sub_page: selection code from DMP Spec... pack: the pattern of fields in the subpage... returns: a list unpacked according to the structure Each sub_page has a standard header: pack is prepended with a standard header '>BBH' Drobo is bigendian. first byte has some flags and a vendor code. second byte is the sub-page code. following two bytes have the length of the record (max: 65535) """ if DEBUG & DBG_HWDialog: print 'getsubpage' if DEBUG & DBG_Simulation: return () mypack = '>BBH' + pack paklen=struct.calcsize(mypack) modepageblock=struct.pack( ">BBBBBBBHB", 0x5a, 0, 0x3a, sub_page, 0, 0, 0, paklen, 0 ) cmdout = self.fd.get_sub_page(paklen, modepageblock,0, DEBUG) if len(cmdout) != paklen: raise DroboException("cmdout is unexpected length") result = struct.unpack(mypack, cmdout) if DEBUG & DBG_HWDialog : print '4 byte returned sense buffer header: 0x%x, 0x%x, 0x%x' % result[:3] return result[3:] def __transactionNext(self): """ Increment the transaction member for some modeSelect pages. """ if (self.transactionID > MAX_TRANSACTION): self.transactionID=0 self.transactionID=self.transactionID+1 def __issueCommand(self,command): """ issue a command to a Drobo... 0x06 - blink. 0x0d - Standby returns nothing, look at the drobo to see if it worked. note: command is asynchronous, returns before operation is complete. """ if DEBUG & DBG_HWDialog: print 'issuecommand...' if DEBUG & DBG_Simulation: self.__transactionNext() return modepageblock=struct.pack( ">BBBBBBBHB", 0xea, 0x10, 0x00, command, 0x00, self.transactionID, 0x01 <<5, 0x01, 0x00 ) try: cmdout = self.fd.get_sub_page(1, modepageblock,1,DEBUG) except: print 'IF you see, "bad address", it is because you need to be the super user...' print " try sudo or su ... " sys.exit() self.__transactionNext() if ( len(cmdout) != 1 ): raise DroboException # only way to verify success is to look at the Drobo... def Sync(self,NewName=None): """ Set the Drobo's current time to the host's time, and the name to selected value. STATUS: works, maybe... DRI claims Drobos are all in California time. afaict, it ignores TZ completely. I feed it UTC, and when I read the time, normal routines convert to local time. so it looks perfect. but diagnostics might not agree. """ if DEBUG & DBG_Simulation: return now=int(time.time()) payload="LH32s" payloadlen=struct.calcsize(payload) if NewName==None: NewName=self.GetSubPageSettings()[2] buffer=struct.pack( ">BBH" + payload , 0x7a, 0x05, payloadlen, now, 0 , NewName ) sblen=len(buffer) # mode select CDB. modepageblock=struct.pack( ">BBBBBBBHB", 0x55, 0x01, 0x7a, 0x05, 0, 0, 0, sblen, 0) self.fd.put_sub_page( modepageblock, buffer, DEBUG ) def SetOptions(self,options): """ Set Options. accepts a set of options as returned by GetSubPageOptions STATUS: UNTESTED! basic thresholds work on Drobo v1. OPTIONS2 is just a guess, have no Pro, cannot test. """ # v1 Options first... fmt = 'BBBLBB' payloadlen=struct.calcsize(fmt) buffer = struct.pack(">BBH" + fmt, 0x7a, 0x30, payloadlen, options["YellowThreshold"], options["RedThreshold"], 0, 0, 0, 0 ) sblen=len(buffer) modepageblock=struct.pack( ">BBBBBBBHB", 0x55, 0x01, 0x7a, 0x30, 0, 0, 0, sblen, 0) self.fd.put_sub_page( modepageblock, buffer, DEBUG ) # These are for the DroboPro. UNTESTED. if ( 'SUPPORTS_OPTIONS2' in self.features ): fmt = 'QHLL490B' payloadlen=struct.calcsize(fmt) rawip = struct.unpack('I', socket.inet_aton(options['IPAddress'])) rawnm = struct.unpack('I',socket.inet_aton(options['NetMask'])) flags=0 if (d["DualDiskRedundancy"]): flags |= 0x0001 if (d["SpinDownDelay"]): flags |= 0x0002 if (d["UseManualVolumeManagement"]): flags |= 0x0004 if (d["UseStaticIPAddress"]): flags |= 0x0008 buffer = struct.pack(">BBH" + fmt, 0x7a, 0x31, payloadlen, \ flags, options["SpinDownDelayMinutes"], \ rawip, rawnm, "" ) sblen=len(buffer) modepageblock=struct.pack( ">BBBBBBBHB", 0x55, 0x01, 0x7a, \ 0x31, 0, 0, 0, sblen, 0) self.fd.put_sub_page( modepageblock, buffer, DEBUG ) return def SetLunSize(self,tb): """ SetLunSize - Sets the maximum LUN size to 'tb' terabytes status: works with no issues! """ if (DEBUG & DBG_Chatty): print 'set lunsize to %d TiB' % tb if not self.umount(): if (DEBUG & DBG_Chatty): print 'cannot free up Drobo to set lunsize' return buffer=struct.pack( ">l", tb ) sblen=len(buffer) # mode select CDB. modepageblock=struct.pack( ">BBBBBBBHB", 0xea, 0x10, 0x0, 0x0f, 0, self.transactionID, (0x01 <<5)|0x01, sblen, 0x00 ) self.fd.put_sub_page( modepageblock, buffer, DEBUG ) self.__transactionNext() def SlotCount(self): self.GetSubPageConfig() return self.slot_count def Blink(self): """ asks the Drobo nicely to blink it's lights. aka. Identification If you happen to have five in a row (drool), you can know which is which. STATUS: works, no issues. """ self.__issueCommand(6) def Standby(self): """ asks the Drobo nicely to shutdown, flushing all manner of caches. STATUS: command itself works, no issues.... only light tests so far. still testing umount code. """ if self.umount(): self.__issueCommand(0x0d) def GetDiagRecord(self,diagcode,decrypt=0): """ returns diagnostics as a string... diagcodes are either 4 or 7 for the two different Records available. STATUS: works fine. decryption done in drobom (look at diagprint) """ if DEBUG & DBG_Chatty: print "Dumping Diagnostics..." # tried 32000 ... it only returned 5K, so try something small. buflen=4096 modepageblock=struct.pack( ">BBBBBBBHB", 0xea, 0x10, 0x80, diagcode, 0x00, self.transactionID, (0x01 <<5)|0x01, buflen, 0x00 ) todev=0 if DEBUG & DBG_General: print "Page 0..." cmdout = self.fd.get_sub_page( buflen, modepageblock, todev, DEBUG ) diags=cmdout i=0 while len(cmdout) == buflen: modepageblock=struct.pack( ">BBBBBBBHB", 0xea, 0x10, 0x80, diagcode, 0x00, self.transactionID, 0x01, buflen, 0x00 ) cmdout = self.fd.get_sub_page( buflen, modepageblock, todev, DEBUG ) i=i+1 diags=diags+cmdout if DEBUG & DBG_General: print "diags ", i, ", cmdlen=", len(cmdout), " diagslen=", len(diags) return diags def dumpDiagnostics(self): n=time.gmtime() dfname="/tmp/DroboDiag_%d_%02d%02d_%02d%02d%02d.log" % ( n[0:6] ) df=open(dfname, "w") d=self.GetDiagRecord(4) df.write(d) d=self.GetDiagRecord(7) self.__transactionNext() df.write(d) df.close() return dfname def decodeDiagnostics(self,diagfilename): try: f=open( diagfilename ) data = f.read() f.close() except: return '' key = ord(data[0]) ^ 0x2d datam = ''.join(map( lambda x: chr(ord(x)^key), data )) return datam # # constants for use with firmware operations # fwsite="ftp://updates.drobo.com/" localfwrepository= os.path.expanduser("~") + "/.drobo-utils" def localFirmwareRepository(self): return Drobo.localfwrepository def PickFirmware(self,name): """ read in a given firmware from disk. sets self.fwdata """ if (DEBUG & DBG_Chatty): print 'Reading Firmware from = %s' % name if ( name[-1] == 'z' ): # data is zipped... inqw=self.inquire() hwlevel=inqw[10] z=zipfile.ZipFile(name,'r') for f in z.namelist(): if (DEBUG & DBG_General): print f , ' ? ' print 'firmware for hw rev ', f[-5] , ' this drobo is rev ', hwlevel[0] if f[-5] == hwlevel[0]: self.fwdata = z.read(f) else: # old file... f = open(name,'r') self.fwdata = f.read() f.close() good = self.validateFirmware() return good def inquire(self): """ issue a standard SCSI INQUIRY command, return standard response as tuple. STATUS: works. trying to understand how to send an INQUIRY: SCSI version 2 protocol INQUIRY... protocol : T10/1236-D Revision 20 byte: 0 - descriptor code. 0x12 -- INQUIRY 1 - 00 peripheral dev. type code 0x0, 4, 5, 7, e .. 2 - reserved 3 - reserved. 4-27 target descriptor parameters. 0 - target descriptor type code: 0x04 - Identification. 28-31 dev. type params. """ mypack = '>BBBBBBBB8s16s4s20sBB8HH' paklen=struct.calcsize(mypack) modepageblock=struct.pack( "BBBBBB", 0x12 , 0, 0, 0, paklen, 0 ) cmdout = self.fd.get_sub_page(paklen, modepageblock,0, DEBUG) if ( len(cmdout) == paklen ): return struct.unpack(mypack, cmdout) else: raise DroboException def PickLatestFirmware(self): """ fetch firmware from web site. ... should be a .tdf file. validate firmware from header... sets self.fwdata go to fwsite download index.txt figure out which one to download. return arch and version of firmware running, and the download file name. SCSI INQUIRY is supposed to respond with 'VERSION' 1.0 or 2.0 to tell which to use. tdz support: zip file containing two .tdf's. one for rev1, another for rev2. status: works """ if DEBUG & DBG_Simulation: return ('fwarch', 'fwv', 'hwlevel', 'value') inqw=self.inquire() hwlevel=inqw[10] fwi=self.GetSubPageFirmware() fwv= str(fwi[0]) + '.' + str(fwi[1]) + '.' + str(fwi[2]) #FIXME ugly hack to force v1 to get onto the v2 firmware stream # current dri index.txt file says v1's should run 1.1.2, but win/Mac dashboards upgrade # to 1.2.4 anyways... so I guess linux should too. # if a v1 is running 1.1.2, then just claim to be an early v2 firmware, all should work. #if fwv == "1.200.11177": # fwv="1.201.12942" fwarch = fwi[6].lower() if (DEBUG & DBG_Chatty): print 'looking for firmware for:', fwarch, fwv, 'hw version:', hwlevel listing_file=urllib2.urlopen( Drobo.fwsite + "index.txt") list_of_firmware_string=listing_file.read().strip("\t\r") list_of_firmware=list_of_firmware_string.split("|") i=1 p = re.compile('\[(.*)\]') while i < len(list_of_firmware): key=list_of_firmware[i-1].split()[1] value=list_of_firmware[i].split()[1] k=key.split('/') # profits oblige... if k[2] == "licensed" : k = k[0:2] + k[3:] #print k # these If's are now nested for ease of debugging, insert a print to taste... # the algorithm is wrong wrt, other platforms... if k[2] == "firmware" : #print ' match firmware' if k[3] == fwarch : #print ' match k[3] = ', fwarch #if we are on a line that lists the fwversion in [] fixup k[4] m=p.search(list_of_firmware[i-1]) if m : k[4]=m.group(1); if k[4] == fwv: if len(k) > 4: if (DEBUG & DBG_Chatty): print 'This Drobo should be running: ', value return (fwarch, fwv, hwlevel, value) i=i+2 if (DEBUG & DBG_Chatty): print 'no matching firmware found, must be the latest and greatest!' return ( '','','','' ) def downloadFirmware( self, fwname, localfw ): """ download given fw file from network repository. load self.fwdata with the data from it STATUS: works. """ if (DEBUG & DBG_Chatty): print 'downloading firmware ', fwname, '...' self.fwdata=None firmware_url=urllib2.urlopen( Drobo.fwsite + fwname ) filedata = firmware_url.read() f = open(localfw,'w+') f.write(filedata) f.close() if (DEBUG & DBG_Chatty ) : print 'local copy written' if ( fwname[-1] == 'z' ): # data is zipped... self.PickFirmware(localfw) else: self.fwdata=filedata if (DEBUG & DBG_Chatty ) : print 'downloading done ' return self.fwdata def validateFirmware(self): """ requires self.fwdata to be initialized before calling. read in the header of the firmware from self.fwdata. check the information in the header to confirm that it is a valid firmware image. status: works for length, and body CRC. something wrong with header CRC. according to dpd.h: (hdrlength, hdrVersion, magic, imageVersion, targetName, sequenceNum, bootFailureCount, imageFlashAddress, imageLength, imageCrc32, about, hdrCrc32 ) = struct.unpack('llll16slllll256sl', self.fwdata[0:304]) & 0xffffffffL is a kludge to work around CRC32 returning different values on 32 vs. 64 bit platforms. can remove once py3k arrives. (see: http://bugs.python.org/issue1202) STATUS: working. """ if (DEBUG & DBG_Chatty): print 'validateFirmware start...' self.fwhdr = struct.unpack('>ll4sl16slllll256sl', self.fwdata[0:312]) if len(self.fwdata) != ( self.fwhdr[0] + self.fwhdr[8] ) : print 'header corrupt... Length does not validate.' return 0 if (DEBUG & DBG_Chatty): print 'header+body lengths validated. Good.' #print self.fwhdr if self.fwhdr[2] != 'TDIH' : print 'bad Magic, not a valid firmware' return 0 if (DEBUG & DBG_Chatty): print 'Magic number validated. Good.' print '%d + %d = %d length validated. Good.' % ( self.fwhdr[0], self.fwhdr[8], len(self.fwdata) ) # http://bugs.python.org/issue1202 # doesn't work on 64 bit, only on 32bit... weird... blank = struct.pack('i',0) hdrcrc = zlib.crc32( self.fwdata[0:308] + blank + self.fwdata[312:self.fwhdr[0]] ) & 0xffffffffL r = self.fwhdr[11] & 0xffffffffL if (DEBUG & DBG_Chatty): print 'CRC from header: %d, calculated using python zlib crc32: %d ' % ( r, hdrcrc) if r != hdrcrc : print 'file corrupt, header checksum wrong' return 0 bodycrc = zlib.crc32( self.fwdata[self.fwhdr[0]:] ) & 0xffffffffL q = self.fwhdr[9] & 0xffffffffL if (DEBUG & DBG_Chatty): print 'CRC for body from header: %d, calculated: %d ' % ( q, bodycrc) if q != bodycrc : print 'file corrupt, payload checksum wrong' return 0 if (DEBUG & DBG_Chatty): print '32 bit Cyclic Redundancy Check correct. Good.' print 'validateFirmware successful...' return 1 def updateFirmwareRepository(self): """ put the best firmware in self.fwdata. return 1 if successful, 0 if not. determine currently running firmware and most current from web site. check if the most current one has already been downloaded. if not, then download it into a local repository. Compare the current running firmware against the appropriate file in the local repository STATUS: working... """ (fwarch, fwversion, hwlevel, fwpath ) = self.PickLatestFirmware() if fwarch == '' : # already at latest version... return 0 if not os.path.exists(Drobo.localfwrepository) : os.mkdir(Drobo.localfwrepository) fwname = fwpath.split('/') localfw = Drobo.localfwrepository + '/' + fwarch + '_' + hwlevel + '_' + fwname[-1] if (DEBUG & DBG_Chatty): print 'looking for: %s' % localfw if not os.path.exists(localfw): if (DEBUG & DBG_Chatty): print 'not present, fetching from drobo.com' self.fwdata = self.downloadFirmware(fwpath,localfw) good = self.validateFirmware() if not good: print 'downloaded firmware did not validate.' return 0 else: if (DEBUG & DBG_Chatty): print 'local copy already present:', localfw good = self.PickFirmware(localfw) if good: if (DEBUG & DBG_Chatty): print 'correct fw available' return 1 print 'no valid firmware found' return 0 def writeFirmware(self,function): """ given good firmware data, upload it to the Drobo... 1_README_*.txt from the resource kit is followed here. function -- a callback that accepts a single argument, an integer in the range 0-100. indicates % done. the function is called after each write in the loop. STATUS: works. """ totallength = len(self.fwdata) buffer = struct.pack( ">L" , totallength ) + self.fwdata[0:self.fwhdr[0]] modepageblock=struct.pack( ">BBBBBBBHB", 0xea, 0x10, 0x00, 0x70, 0x00, self.transactionID, (0x01<<5)|0x01, len(buffer), 0x00 ) written = self.fd.put_sub_page( modepageblock, buffer, DEBUG ) if DEBUG & DBG_General: print "Page 0..." buflen=32768 written=buflen i=self.fwhdr[0] j=i+buflen moretocome=0x01 if (DEBUG & DBG_General ) : print 'writeFirmware: i=%d, start=%d, last=%d fw length= %d\n' % \ ( i, self.fwhdr[0], totallength, len(buffer) ) while (written == buflen) and ( i < len(self.fwdata)) : if ( i + buflen ) > totallength : # writing the last record. buflen= totallength - i moretocome=0 modepageblock=struct.pack( ">BBBBBBBHB", 0xea, 0x10, 0x00, 0x70, 0x00, self.transactionID, moretocome, buflen, 0x00 ) j=i+buflen written = self.fd.put_sub_page( modepageblock, self.fwdata[i:j], DEBUG ) i=j function(i*100/totallength) if (DEBUG & DBG_General ) : print 'wrote ',written, ' bytes. Cumulative: ', i, ' of', totallength if (DEBUG & DBG_General ) : print 'writeFirmware Done. i=%d, len=%d' % ( i, totallength ) self.__transactionNext() paklen=1 modepageblock=struct.pack( ">BBBBBBBHB", 0xea, 0x10, 0x80, 0x71, 0, self.transactionID, 0x01 << 5 , paklen, 0 ) cmdout = self.fd.get_sub_page(paklen, modepageblock,0, DEBUG) status = struct.unpack( '>B', cmdout ) if DEBUG & DBG_General : print 'Drobo thinks write status is: ', status[0] def GetCharDev(self): return self.char_dev_file def GetSubPageConfig(self): """ returns: ( MaxNumberOfSlots, MaxNumLUNS, MaxLunSize ) """ # SlotCount, Reserved, MaxLuns, MaxLunSz, Reserved, unused, unused if DEBUG & DBG_Simulation: self.slot_count = 8 return (8, 16, 2199023250944) result=self.__getsubpage( 0x01, 'BBBQ' ) self.slot_count = result[0] return ( result[0], result[2], result[3]*512 ) def GetSubPageCapacity(self): """ returns: ( Free, Used, Virtual, Unprotected ) """ if DEBUG & DBG_Simulation: capacity = 495452160000 used = random.randint(0,capacity) return (capacity-used, used, capacity, 125184245760) return self.__getsubpage(0x02, 'QQQQ' ) def GetSubPageSlotInfo(self): """ returns list of slot info, each slot is: ( slotId, PhysicalCapacity, ManagedCapacity, leds, Manufacturer, Model ) ... ) leds - indicates what the lights on the front panel are doing. returns one colour if one colour is constant, set of colours if there is flashing going on. """ if DEBUG & DBG_Simulation: return ( (0, 500107862016, 0, 'green', 'ST3500830AS', 'ST3500830AS'), (1, 750156374016, 0, 'green', 'WDC WD7500AAKS-00RBA0', 'WDC WD7500AAKS-0'), (2, 0, 0, _ledstatus(random.randint(0,6)), '', ''), (3, 0, 0, 'gray', '', ''), (0, 500107862016, 0, 'green', 'ST3500830AS', 'ST3500830AS'), (1, 750156374016, 0, 'green', 'WDC WD7500AAKS-00RBA0', 'WDC WD7500AAKS-0'), (2, 0, 0, _ledstatus(random.randint(0,6)), '', ''), (3, 0, 0, 'gray', '', '') ) slotrec='HBQQB32s16sL' i = 0 pattern='B' while ( i < self.slot_count ): pattern += slotrec i +=1 r = self.__getsubpage( 0x03, pattern ) l=[] j=0 while (j < r[0] ): i=j*8 s = ( r[i+2], r[i+3], r[i+4], _ledstatus( r[i+5] ), r[i+6].strip(" \0"), r[i+7].strip(" \0") ) l.append( s ) j=j+1 return l def GetSubPageLUNs(self): """ returns for each LUN returns detailed info: ( LUNID, LUN total Capacity, LUN Used Capacity, PartitionScheme*, Partition Count*, Format* ) *only returned if firmware: SUPPORTS_NEW_LUNINFO2 (essentially >=1.1.0) N.B. must run getSubPageFirmware before the first time you calling this routine, or it will fail by returning the empty set. STATUS: works, with ERRATA: report from matthew mastracci that this doesn't work for him... should be +6, and the value for ext3 should be 0.0x8, and not 0x80... haven't understood it yet... question: is it correct to mix 'used capacity' from luninfo, with total capacity from luninfo2? for old luninfo, the spec and dmp.h agree... spec says: dmp.h says: len ( 8* H-len, B-id, Q-cap, Q-used ) returns for each LUN returns detailed info: ( LUNID, LUN total Capacity, PartitionScheme, PartitionCount, Format ) for Luninfo2.. works, but 'PartCount' is odd. my guess after much experiments: PartitionCount and format are inverted vs. dmp.h. the count is last(6th), and the format is 5th.. even that doesn't work right, because I get partcount=1 when there are none, and it stays 1 when I add one. now there are 8 when there is only one... unless 8 is ext2 fs. and I guessed wrong about part types... See also ERRATA for _partscheme dmp.h says 8 x H-length, B-LunID, Q-TotalCapacity, B-PartScheme, B-PartCount, B-Format, 5B-rsvd """ if DEBUG & DBG_Simulation: return [(0, 2199023251456, 5092651008, 'GPT', ['EXT3'])] lp="HBQQ" l = self.__getsubpage( 0x04, 'B'+lp+lp+lp+lp+lp+lp+lp+lp ) if ( 'SUPPORTS_NEW_LUNINFO2' in self.features ): li2="HBQBBB5B" l2= self.__getsubpage( 0x07, "B"+ li2+li2+li2+li2+li2+li2+li2+li2 ) i=0 li=[] while ( i < l[0] ): j=i*4 if ( 'SUPPORTS_NEW_LUNINFO2' in self.features ): k=i*7 li.append( (l[j+2], l2[k+3], l[j+4], _partscheme(l2[k+4]), _partformat(l2[k+5]) ) ) else: li.append( (l[j+2], l[j+3], l[j+4]) ) i=i+1 return li def GetSubPageSettings(self): """ returns: ( currentUTCtime, UTCoffset, DroboName ) STATUS: works with... ERRATA: -- dpd.h and other sources say offset is two bytes. -- DMP Spec says it is only one byte. -- other sources say it is always set to 'California Time'... 8. -- California time is UTC - 8... +8 would be China. -- structures returned are supposed to be in network byte order (MSB) when two byte value read in network byte order, result is 2048. they stuff it in LSB order, so the 8 ended up in the higher order byte. -- so I just claim it says 8 and shut up. """ if DEBUG & DBG_Simulation: return (1220112079, 8, 'TRUSTED DATA') ( utc, offset, name ) = self.__getsubpage(0x05, 'LH32s' ) name=name.strip(" \0") offset=8 # offset is screwed up returned by Drobo, just set it to what they claim it should be. return ( utc, offset, name ) def GetSubPageProtocol(self): """ returns ( Major, Minor ) STATUS: working... soupcon: at firmware 1.0.3, seemed to demand an additional byte. might be a confused artifact of dev. at 1.1.1 the additional byte leads to resid > 0 in the C call, so matches docs. """ if DEBUG & DBG_Simulation: return (0, 10) return self.__getsubpage( 0x06, 'BB' ) def GetSubPageFirmware(self): """ STATUS: working with ERRATA: returns ( majorVer, MinorVer, Build, UpgMajorVer, UpgMinorVer, BuildDate, Arch, ) above is what the spec says... dpd.h says byte 128 has a feature agrees on the first four, but says the date is a 32 char string, and is followed by Arch[16], and Extra[256], Drobo has a version string after arch, guessed at 16 chars. I shortened Extra for that. byte 0x80 is supposed to be feature flags, found it a 0x73... """ if DEBUG & DBG_Simulation: return (1, 201, 12942, 12, 6, 'May 13 2008,15:29:32', 'ArmMarvell', '1.1.2', ['NO_AUTO_REBOOT', 'NO_FAT32_FORMAT', 'USED_CAPACITY_FROM_HOST', 'DISKPACKSTATUS', 'ENCRYPT_NOHEADER', 'CMD_STATUS_QUERIABLE', 'VARIABLE_LUN_SIZE_1_16', 'PARTITION_LUN_GPT_MBR', 'FAT32_FORMAT_VOLNAME', 'SUPPORTS_DROBOSHARE', 'SUPPORTS_NEW_LUNINFO2']) raw=self.__getsubpage(0x08, 'BBHBB32s16s16s240s' ) result = struct.unpack('>112sL32sH90s', raw[8]) self.features = _unitfeatures(result[1]) return (raw[0], raw[1], raw[2], raw[3], raw[4], raw[5].strip(" \0"), raw[6].strip(" \0"), raw[7].strip(" \0"), self.features ) def GetSubPageStatus(self): """ return _unitstatus STATUS: works a bit, relayoutcount stuff completely untested... Errata: spec says a single byte. dmp.h says two longs: (Status, RelayOutCount) Drobo always returns 0 for second Long. when I remove a disk, I get [ 'No Redundancy', 'Relay out in progress'], but when I format, it stays empty... """ if DEBUG & DBG_Simulation: return _unitstatus(random.randint(0,16535)) ss=self.__getsubpage(0x09, 'LL' ) s=_unitstatus(ss[0]) if ss[1] > 0 : # relay out in progress if self.relaystart == 0: self.relaystart=time.time() self.relayinitialcount=ss[1] s.append( 'no estimate yet ' ) else: now=time.time() runningtime=(now - self.relaystart)/60.0 amtdone= self.relayinitialcount - ss[1] amtleft= ss[1] pctleft= 100.0 * amtleft / self.relayinitialcount pctdone= 100 - pctleft if amtdone == 0: s.append( 'gathering stats, no estimate yet ' ) else: rate= pctdone / runningtime timeleft = pctleft*rate # timeleft in minutes... s.append( '%d blocks left ' % ss[1] ) else: if self.relaystart > 0: self.relaystart == 0 return ( s, ss[1] ) def GetSubPageOptions(self): """ different fw/hw combinations will return different results. return one of: None - this drobo does not support Options ( fw < 1.11 ) ( YellowThresh, RedThresh, AutoDelSnapshot, LowYel, LowRed ) - drobo supports first version of options ( fw >= 1.11) ( above + FeatureOnOffStates, SpinDownDelay, IPAddress, Subnetmask ) - DroboPro only ? my v1's don't support it. STATUS: untested, seems to agree with dmp.h for Options Options2 (only on Drobo Pro) completely un-tested. DMIP spec says: B-YelThresh, B-RedThresh, 5B-Rsvd, 1bit-AutoDel, B-Rsvd dmp.h (published 2007 and summer 2009) says: B-YelThresh, B-RedThresh, B-Flags, L-DataCheckParam, B-LowYelThresh, B-LowRedThresh. later firmware version and dmp published in 2009 adds OPTIONS2 with hmm... """ if DEBUG & DBG_Simulation: return {"YellowThreshold":85, "RedThreshold":95 } try: # insert try/except for compatibility with firmware <= 1.1.0 #o = self.__getsubpage(0x07, 'BB5BBB' ) #return ( o[0], o[1], o[4] >>7 ) #return ( o[0], o[1], o[2], ) o = self.__getsubpage(0x30, 'BBBLBB' ) d = { "YellowThreshold": o[0], "RedThreshold": o[1] } if ( 'SUPPORTS_OPTIONS2' in self.features ): ( pagelen, flags, d['SpinDownDelayMinutes'], \ rawip, rawnm, reserved ) = \ self.__getsubpage(0x31, 'QHLL490B' ) d["DualDiskRedundancy"] = ( flags & 0x0001 ) > 0 d["SpinDownDelay"] = ( flags & 0x0002 ) > 0 d["UseManualVolumeManagement"] = ( flags & 0x0004 ) > 0 d["UseStaticIPAddress"] = ( flags & 0x0008 ) > 0 d["IPAddress"]=socket.inet_ntoa(struct.pack('I',rawip)) d["NetMask"]=socket.inet_ntoa(struct.pack('I',rawnm)) return d except: return None def umount(self): """ umount all file systems using the given Drobo. return true on success, false on failure. """ if DEBUG & DBG_Simulation: return True toumount = self.DiscoverMounts() if len(toumount) > 0: for i in toumount: if DEBUG & DBG_Chatty: print "unmounting: ", i umresult=os.system("umount " + i ) if umresult != 0: return False return True def DiscoverMounts(self): """ return the list of mounted file systems using the unit. """ if DEBUG & DBG_Simulation: return [ "/drmnt0", "/drmnt2" ] mounts=open("/etc/mtab") dlen=len(self.char_dev_file) filesystems=[] for l in mounts.readlines(): fields=l.split() for i in self.char_devs: if fields[0][0:dlen] == i: filesystems.append(fields[1]) mounts.close() return filesystems def DiscoverLUNs(debugflags=0): """ find all Drobo LUNs accessible to this user on this system. returns a list of list of character device files samples: [ [ "/dev/sdf", "/dev/sdg" ], [ "/dev/sdh" ] ] """ global DEBUG DEBUG=debugflags if DEBUG & DBG_Simulation: return [ [ "/dev/sdb", "/dev/sdc" ], [ "/dev/sdd" ] ] devices=[] for potential in DroboIOctl.drobolunlist(DEBUG): if ( DEBUG & DBG_Detection ): print "trying: ", potential try: d = Drobo( potential, DEBUG ) devices.append(potential) except: pass return devices hoho+repack.orig/DroboGUI.py0000755000175000017500000006465111265217256015261 0ustar morphmorph#!/usr/bin/python #Drobo Utils Copyright (C) 2008,2009 Peter Silva (Peter.A.Silva@gmail.com) #Drobo Utils comes with ABSOLUTELY NO WARRANTY; For details type see the file #named COPYING in the root of the source directory tree. # #------------------------------------------------------------------- # debugging stuff: begin #------------------------------------------------------------------- #import pdb #------------------------------------------------------------------ # debugging stuff: end #------------------------------------------------------------------- import os,sys,math from PyQt4 import QtGui from PyQt4 import QtCore import socket import Drobo import subprocess import commands import string def _toGB(num): g = num*1.0/(1000*1000*1000) return "%6.1f" % g def _toTiB(num): """ convert input number to computerish Terabytes.... (ok... TibiBytes blech...) STATUS: works bizarrely... bug in python 2.5? - a number which is 2 TB -1, + any number < 5000 ends up smaller than 2TiB. so at first I just added 5000 to get the correct answer. did a manual binary search, and even 4096 doesn't work... but when I change OS's, even that didn't workreliably... so now I just round it at each division... """ #print num, num/1024, num/(1024*1024), num/(1024*1024*1024), g = round(round(round(round(num/1024)/1024)/1024)/1024) return int(g) def _setDiskLabel(model,capacity): if (capacity == ''): label = model else: if ( capacity > 0): label = model.rstrip() + ' ' + _toGB(capacity) + 'GB ' else: label = 'empty' return label partitioner="" def _runPartitioner(): """ invoke existing partitioning program... """ print "partitioner = ", partitioner subprocess.Popen( partitioner, shell=True) class DroboAbout(QtGui.QWidget): def __init__(self, parent=None): QtGui.QWidget.__init__(self, parent) self.setMinimumSize(240, 240) al = QtGui.QVBoxLayout(self) self.main = QtGui.QLabel(""" drobo-utils: software to manage a Drobo storage unit from Data Robotics International Corp. Winner of the Data Robotics Incorporated (DRI) Bounty 2008 for a linux dashboard! Thanks tor RI for putting up the Bounty! Copyright 2008 Peter Silva ( Peter.A.Silva@gmail.com ) license: General Public License (GPL) v3 Version: """ + Drobo.VERSION + """ See README for other contributors. """ , self) al.addWidget(self.main) self.quit = QtGui.QPushButton('Dismiss',self) al.addWidget(self.quit) self.connect(self.quit, QtCore.SIGNAL('clicked()'), self.hide) class ShowText(QtGui.QWidget): def __init__(self, manual, isfile=True, parent=None): QtGui.QWidget.__init__(self, parent) self.setMinimumSize(500, 440) al = QtGui.QVBoxLayout(self) # search support... buggy. #self.lastsearch='' #self.lscursor=QtGui.QTextCursor(self) #self.lscursor.setPosition(0) if isfile: dirs=[ "/usr/local/share/drobo-utils-doc", "/usr/share/drobo-utils/share/drobo-utils-doc", "." ] readme="" i=0 while (i < 3 ) and (readme == "") : try: readmefile = open( dirs[i] + "/" + manual ) readme = readmefile.read() readmefile.close() except: pass i=i+1 if i >= 3: readme = "Documentation %s not found" % manual self.main = QtGui.QTextEdit(readme, self ) else: self.main = QtGui.QTextEdit('', self ) self.main.setPlainText(manual) al.addWidget(self.main) self.quit = QtGui.QPushButton('Dismiss',self) al.addWidget(self.quit) self.connect(self.quit, QtCore.SIGNAL('clicked()'), self.hide) #self.findbt = QtGui.QPushButton('Find',self) #al.addWidget(self.findbt) #self.connect(self.findbt, QtCore.SIGNAL('clicked()'), self.__search) def __search(self): """ search is for finding a string in a text document being displayed. STATUS: totally borked. """ text, ok = QtGui.QInputDialog.getText(self, self.tr("Search Text"), self.tr("Look for:"), QtGui.QLineEdit.Normal, self.lastsearch) if ok and not text.isEmpty(): self.lastsearch = QtCore.QString(text) self.lscursor = self.find(self.lastsearch,0) self.lscursor.setPosition(0) class DroboGUI(QtGui.QMainWindow): """ GUI for a single Drobo, start one for each drobo. """ def __Blink(self): self.drobo.Blink() def __StatusBar_space(self): c=self.drobo.GetSubPageCapacity() self.statusmsg = 'used: ' + _toGB(c[1]) + ' free: ' + _toGB(c[0]) + ' Total: ' + _toGB(c[2]) + ' GB, update# ' + str(self.updates) #print self.statusmsg def __updateLEDs(self): """ update LEDS (implement flashing.) """ self.updates = self.updates + 1 i=0 while ( i < self.drobo.SlotCount() ): c=self.s[i][3] if (len(c) == 2 ): colour = c[ self.updates % 2] else: colour = c self.Device.slot[i][1].setStyleSheet( "QWidget { background-color: %s }" % colour ) i=i+1 def __updatewithQueryStatus(self): """ query device to update information """ try: fwv=self.drobo.GetSubPageFirmware() except: self.statusBar().showMessage( 'bad poll: %d.. need to restart' % self.updates ) return settings=self.drobo.GetSubPageSettings() self.Device.id.setText( self.drobo.GetCharDev() + ' ' + settings[2] + ' firmware: ' + fwv[7] ) self.Device.id.setToolTip( "Firmware build: " + str(fwv[0]) + '.' + str(fwv[1]) + '.' + str(fwv[2]) + "\n Features: " + string.join(fwv[8],"\n") ) self.s=self.drobo.GetSubPageSlotInfo() luninfo=self.drobo.GetSubPageLUNs() luntooltip="luns, count: " + str(len(luninfo)) + "\n" for l in luninfo: luntooltip = luntooltip + "lun id: " + str(l[0]) + " used: " + \ _toGB(l[2]) + " total: " + _toGB(l[1]) if 'SUPPORTS_NEW_LUNINFO2' in self.drobo.features : luntooltip = luntooltip + " scheme: " + l[3] + " type: " + str(l[4]) luntooltip = luntooltip + "\n" i=0 mnw=0 while i < self.drobo.SlotCount() : self.Device.slot[i][0].setText(_setDiskLabel(self.s[i][5],self.s[i][1])) w= self.Device.slot[i][0].width() if w > mnw: mnw=w self.Device.slot[i][0].setToolTip(luntooltip) i=i+1 c=self.drobo.GetSubPageConfig() self.Format.lunsize = _toTiB(c[2]) c=self.drobo.GetSubPageCapacity() if c[2] > 0: self.Device.fullbar.setValue( c[1]*100/c[2] ) self.Device.fullbar.setToolTip( string.join(self.drobo.DiscoverMounts(),',') + "\nused: " + _toGB(c[1]) + ' free: ' + _toGB(c[0]) + ' Total: ' + _toGB(c[2]) + ' GB, update# ' + str(self.updates) ) #print self.statusmsg #self.__StatusBar_space() self.statusBar().showMessage( self.statusmsg ) ss = self.drobo.GetSubPageStatus() self.statusmsg = 'Status: ' + str(ss[0]) + ' update: ' + str(self.updates) if self.Format.inProgress and ( self.fmt_process.poll() != None) : # reset to normal state... print 'it took: %d updates to run' % (self.updates - self.Format.startupdate ) self.Format.inProgress=0 normal = self.Tools.Updatebutton.palette().color( QtGui.QPalette.Button ) self.Format.Formatbutton.palette().setColor( QtGui.QPalette.Button, QtCore.Qt.blue ) self.Format.ext3.setChecked(0) self.Format.ntfs.setChecked(0) self.Format.msdos.setChecked(0) self.Format.Formatbutton.setText('Format Done!') self.Format.connect(self.Format.Formatbutton, QtCore.SIGNAL('clicked()'), self.FormatLUN) #pdb.set_trace() def __updateStatus(self): self.__updateLEDs() # only update display... # try not to poll the device too often, so only every 'n' screen updates if (self.updates % 5 == 0 ): # query device for new info... self.__updatewithQueryStatus() def __initDeviceTab(self): self.Device = QtGui.QWidget() self.Device.setObjectName("Device") # Create Device tab... devtablayout=QtGui.QGridLayout(self.Device) devtablayout.setColumnStretch(0,19) devtablayout.setColumnStretch(1,1) devtablayout.setVerticalSpacing(4) self.Device.id = QtGui.QPushButton('Unknown Drobo', self.Device) self.Device.id.setCheckable(False) self.Device.id.setStyleSheet( "QWidget { background-color: white }" ) #self.Device.id.setSizePolicy( QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding ) devtablayout.addWidget(self.Device.id,0,0,1,-1) self.Device.slot = [ [ '', '' ], [ '', '' ], [ '', '' ], [ '', '' ], [ '', '' ], [ '', '' ], [ '', '' ], [ '', '' ] ] i=0 while ( i < self.drobo.SlotCount() ): slotlayout=QtGui.QHBoxLayout() self.Device.slot[i][0] = QtGui.QPushButton('uninitialized - 0000GB', self.Device) self.Device.slot[i][0].setCheckable(False) self.Device.slot[i][0].setStyleSheet( "QWidget { background-color: white }" ) self.Device.slot[i][0].setSizePolicy( QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding ) devtablayout.addWidget(self.Device.slot[i][0],i+1,0,1,1) self.Device.slot[i][1] = QtGui.QWidget(self.Device) self.Device.slot[i][1].setMinimumWidth(10) devtablayout.addWidget(self.Device.slot[i][1],i+1,1,1,1) i=i+1 self.Device.fullbar = QtGui.QProgressBar(self.Device) devtablayout.addWidget(self.Device.fullbar,i+1,0,1,-1) self.connect(self.Device.fullbar, QtCore.SIGNAL('focusInEvent()'), self.__StatusBar_space) self.tab.addTab(self.Device, "Device") def ReallyFormatLUN(self): print 'Really formatting...' self.Format.disconnect(self.Format.Formatbutton, QtCore.SIGNAL('clicked()'), self.ReallyFormatLUN) if self.Format.fstype == 'none': # changing LUN size self.Format.Formatbutton.setText('Done. WAIT 5 min. restart dashboard!') self.drobo.SetLunSize(self.Format.lunszlcd.value()) else: self.Format.Formatbutton.setText('Format in progress, WAIT!') format_script = self.drobo.format_script(self.Format.fstype) self.Format.startupdate = self.updates self.Format.inProgress = 1; #self.fmt_process = subprocess.Popen( format_script, bufsize=0, stdout=subprocess.PIPE ) self.fmt_process = subprocess.Popen( format_script ) p = self.Format.Formatbutton.palette() p.setColor( QtGui.QPalette.Button, QtCore.Qt.red ) def FormatLUN(self): print 'Clicked format...' if self.Format.ntfs.isChecked(): fstype='ntfs' elif self.Format.msdos.isChecked(): fstype='FAT32' elif self.Format.ext3.isChecked(): fstype='ext3' else: fstype='none' if ( self.Format.lunszlcd.value() == self.Format.lunsize ): return self.Format.Formatbutton.palette().setColor( QtGui.QPalette.Button, QtCore.Qt.yellow ) self.Format.Formatbutton.setText( \ "Last Chance, Resize to %d TiB" % self.Format.lunszlcd.value() ) if fstype != 'none': self.Format.Formatbutton.palette().setColor( QtGui.QPalette.Button, QtCore.Qt.yellow ) self.Format.Formatbutton.setText( "Last Chance, Format %s ?" % fstype) self.Format.fstype=fstype self.Format.disconnect(self.Format.Formatbutton, QtCore.SIGNAL('clicked()'), self.FormatLUN) self.Format.connect(self.Format.Formatbutton, QtCore.SIGNAL('clicked()'), self.ReallyFormatLUN) def __adjustlunsize(self,sz): # This crap is here only because of firmware broken for large LUNS # please remove the whole if mess once the firmware gets fixed. if ( sz > 1 ): # force down to 2 TiB newsize=2 self.Format.lunsize = newsize self.Format.lunszlcd.display( newsize ) self.Format.horizontalSlider.setValue( 1 ) self.__adjustlunsize(1) self.Format.Formatbutton.setText( "Sorry, only upto %d TiB on Linux" % newsize ) return newsize=2**sz self.Format.lunszlcd.display(newsize) if ( self.Format.lunsize != newsize ): self.Format.fstype= 'none' self.Format.ext3.setChecked(False) self.Format.ext3.setCheckable(False) self.Format.msdos.setChecked(False) self.Format.msdos.setCheckable(False) self.Format.ntfs.setChecked(False) self.Format.ntfs.setCheckable(False) self.Format.Formatbutton.setText( "Set LUN size to %d TiB" % newsize) else: self.Format.ext3.setCheckable(True) self.Format.msdos.setCheckable(True) self.Format.ntfs.setCheckable(True) self.Format.Formatbutton.setText( "Format (Erases All Data!) " ) def __initFormatTab(self): """ known issues: -- formats only using GPT labels... should be mbr for FAT32. -- should refuse to set lunsize > 2 TB for FAT32. -- should refuse to set lunsize > 8 TB for ext3. """ self.Format = QtGui.QWidget() self.Format.setObjectName("Format") flay = QtGui.QGridLayout(self.Format) self.Format.header = QtGui.QLabel("WARNING: Format erases whole Drobo", self.Format) self.Format.header.setStyleSheet( "QWidget { color: red }" ) flay.addWidget(self.Format.header,0,0,1,2) self.Format.lunsztitle = QtGui.QLabel("Maximum LUN size:", self.Format) flay.addWidget(self.Format.lunsztitle,1,0,1,1) self.Format.lunsztitle.setSizePolicy( QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed ) self.Format.lunszlcd = QtGui.QLCDNumber(2, self.Format) flay.addWidget(self.Format.lunszlcd,1,1,1,1) self.Format.horizontalSlider = QtGui.QSlider(self.Format) flay.addWidget(self.Format.horizontalSlider,2,0,1,2) self.Format.horizontalSlider.setMaximum(4) self.Format.horizontalSlider.setMinimum(0) self.Format.horizontalSlider.setSingleStep(1) self.Format.horizontalSlider.setPageStep(2) self.Format.horizontalSlider.setOrientation(QtCore.Qt.Horizontal) self.Format.horizontalSlider.setTickPosition(QtGui.QSlider.TicksBelow) self.Format.horizontalSlider.setTickInterval(1) self.Format.horizontalSlider.setObjectName("horizontalSlider") self.Format.horizontalSlider.setProperty("value",QtCore.QVariant(2)) c=self.drobo.GetSubPageConfig() self.Format.lunsize = _toTiB(c[2]) self.Format.lunszlcd.display( self.Format.lunsize ) if self.Format.lunsize > 1: self.Format.horizontalSlider.setValue( int(math.log(self.Format.lunsize,2)) ) else: self.Format.horizontalSlider.setValue(0) self.Format.connect(self.Format.horizontalSlider, QtCore.SIGNAL('valueChanged(int)'), self.__adjustlunsize) self.Format.ext3 = QtGui.QRadioButton("Ext3 (journalled ext2)", self.Format) mkfs = commands.getoutput("which mke2fs") if mkfs == "" : self.Format.ext3.setCheckable(0) self.Format.ext3.setStyleSheet( "QWidget { color: gray }" ) self.Format.ext3.setText('Ext3 disabled (missing mke2fs)') flay.addWidget(self.Format.ext3,3,0,1,-1) self.Format.msdos = QtGui.QRadioButton("FAT32 MS - Disk Operating System", self.Format) mkfs = commands.getoutput("which mkdosfs") if ( mkfs == "" ): self.Format.msdos.setCheckable(0) self.Format.msdos.setStyleSheet( "QWidget { color: gray }" ) self.Format.msdos.setText('FAT32 disabled (missing mkdosfs)') flay.addWidget(self.Format.msdos,4,0,1,-1) self.Format.ntfs = QtGui.QRadioButton("NTFS -- Windows NT/XP/Vista", self.Format) flay.addWidget(self.Format.ntfs,5,0,1,-1) mkfs = commands.getoutput("which mkntfs") if ( mkfs == "" ): self.Format.ntfs.setCheckable(0) self.Format.ntfs.setStyleSheet( "QWidget { color: gray }" ) self.Format.ntfs.setText('NTFS disabled (missing mkntfs)') self.Format.Formatbutton = QtGui.QPushButton('Format (Erases All Data!) ', self.Format) self.Format.Formatbutton.setToolTip("Configure a Drobo for use") flay.addWidget(self.Format.Formatbutton,6,0,1,-1) self.tab.addTab(self.Format, "Format") self.Format.connect(self.Format.Formatbutton, QtCore.SIGNAL('clicked()'), self.FormatLUN) # progress flag... self.Format.inProgress = 0 def upgrade(self): self.disconnect(self.Tools.Updatebutton, QtCore.SIGNAL('clicked()'), self.upgrade) self.connect(self.Tools.Updatebutton, QtCore.SIGNAL('clicked()'), self.checkup) if self.drobo.updateFirmwareRepository(): self.drobo.writeFirmware( self.Tools.progress.setValue ) self.Tools.comment.setText( "Written! Reboot Drobo to activate.") def checkup(self): self.drobo.Sync() # convenient side effect: make the host and drobo clocks agree... (fwarch, fwversion, hwlevel, fwpath ) = self.drobo.PickLatestFirmware() print "checkup: this Drobo is a %s hw rev: %s, and needs: %s" % ( fwarch, hwlevel, fwversion ) if fwpath != '' : self.Tools.Updatebutton.setText( "Upgrade" ) self.disconnect(self.Tools.Updatebutton, QtCore.SIGNAL('clicked()'), self.checkup) self.connect(self.Tools.Updatebutton, QtCore.SIGNAL('clicked()'), self.upgrade) self.Tools.comment.setText( "Press 'Upgrade' upgrade to %s" % ( fwversion )) else: self.Tools.comment.setText( "No update available!" ) def __diags(self): self.drobo.Sync() # convenient side effect make the host and drobo clocks agree... fname = self.drobo.dumpDiagnostics() self.last_diagfile = fname self.Tools.comment.setText( fname ) def __printDiagFile(self): fileName = QtGui.QFileDialog.getOpenFileName(self, self.tr("QFileDialog.getOpenFileName()"), self.last_diagfile, self.tr("All Files (*);;Text Files (*.txt)")) if not fileName.isEmpty(): datam =self.drobo.decodeDiagnostics(str(fileName)) self.diagdialog = ShowText(datam,False) self.diagdialog.show() def __loadFirmware(self): fileName = QtGui.QFileDialog.getOpenFileName(self, self.tr("QFileDialog.getOpenFileName()"), self.drobo.localFirmwareRepository(), self.tr("All Files (*);;Text Files (*.txt)")) if not fileName.isEmpty(): if self.drobo.PickFirmware(str(fileName)): self.drobo.writeFirmware( self.Tools.progress.setValue ) def __renameDialog(self): settings=self.drobo.GetSubPageSettings() text, ok = QtGui.QInputDialog.getText(self, self.tr("QInputDialog.getText()"), self.tr("New name:"), QtGui.QLineEdit.Normal, settings[2]) if ok and not text.isEmpty(): self.drobo.Sync(str(text)) # convenient side effect: make the host and drobo clocks agree... def __initToolTab(self): self.Tools = QtGui.QWidget() self.Tools.setObjectName("Tools") tlay = QtGui.QGridLayout(self.Tools) # # Set the tool colors to grey, to indicate non-functional... # self.Tools.Standbybutton = QtGui.QPushButton('Shutdown', self.Tools) self.Tools.Standbybutton.setToolTip( 'Unmount file systems, and turn Drobo off (DRI calls this standby)' ) self.Tools.Standbybutton.setCheckable(False) tlay.addWidget(self.Tools.Standbybutton,0,0,1,1) self.connect(self.Tools.Standbybutton, QtCore.SIGNAL('clicked()'), self.drobo.Standby) w=self.Tools.Standbybutton.width() self.Tools.Blinkybutton = QtGui.QPushButton('Blink Lights', self.Tools) self.Tools.Blinkybutton.setToolTip( 'Make a light show (totally harmless)' ) self.Tools.Blinkybutton.setCheckable(False) tlay.addWidget(self.Tools.Blinkybutton,0,1,1,1) self.connect(self.Tools.Blinkybutton, QtCore.SIGNAL('clicked()'), self.drobo.Blink) self.Tools.Renamebutton = QtGui.QPushButton('Rename', self.Tools) self.Tools.Renamebutton.setToolTip( "Change the Drobo's name (does not affect mount points.)" ) self.Tools.Renamebutton.setCheckable(False) tlay.addWidget(self.Tools.Renamebutton,1,0,1,1) self.connect(self.Tools.Renamebutton, QtCore.SIGNAL('clicked()'), self.__renameDialog) self.Tools.Updatebutton = QtGui.QPushButton('Update', self.Tools) self.Tools.Updatebutton.setToolTip( "See if new firmware is available." ) tlay.addWidget(self.Tools.Updatebutton,1,1,1,1) self.connect(self.Tools.Updatebutton, QtCore.SIGNAL('clicked()'), self.checkup) Registerbutton = QtGui.QPushButton('Register', self.Tools) Registerbutton.setToolTip( "Report for warranty service." ) Registerbutton.setStyleSheet( "QWidget { color: gray }" ) Registerbutton.setCheckable(False) tlay.addWidget(Registerbutton,2,0,1,1) Diagbutton = QtGui.QPushButton('Diagnostics', self.Tools) Diagbutton.setToolTip( "Have Drobo write a diagnostics file to /tmp" ) Diagbutton.setCheckable(False) tlay.addWidget(Diagbutton,2,1,1,1) self.connect(Diagbutton, QtCore.SIGNAL('clicked()'), self.__diags) DiagShowbutton = QtGui.QPushButton('Show Diag', self.Tools) DiagShowbutton.setToolTip( "Show a decoded diagnostics file" ) DiagShowbutton.setCheckable(False) tlay.addWidget(DiagShowbutton,3,0,1,1) self.connect(DiagShowbutton, QtCore.SIGNAL('clicked()'), self.__printDiagFile) FwLdbutton = QtGui.QPushButton('Load Firmware', self.Tools) FwLdbutton.setToolTip( "Pick your own firmware (use Update normally)" ) FwLdbutton.setCheckable(False) tlay.addWidget(FwLdbutton,3,1,1,1) self.connect(FwLdbutton, QtCore.SIGNAL('clicked()'), self.__loadFirmware) self.Tools.progress = QtGui.QProgressBar(self.Tools) #self.Tools.progress.setMinimumWidth(2*w) tlay.addWidget(self.Tools.progress,4,0,1,2) #self.Tools.progress.setSizePolicy( QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed ) self.Tools.progress.setValue( 0 ) self.Tools.comment = QtGui.QLabel("Press 'Update' to look for updates", self.Tools) tlay.addWidget(self.Tools.comment,5,0,1,2) normal = self.Tools.Updatebutton.palette().color( QtGui.QPalette.Button ) self.tab.addTab(self.Tools, "Tools") def __init__(self, d, parent=None): QtGui.QMainWindow.__init__(self) #QtGui.QWidget.__init__(self, parent) global partitioner self.drobo = d self.updates = 0 self.last_diagfile='/tmp' self.statusmsg='Ready' self.color = QtGui.QColor(0, 0, 0) QtGui.QApplication.setStyle(QtGui.QStyleFactory.create('MacStyle')) self.setMinimumSize(300, 350) self.setSizePolicy( QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding ) self.setWindowTitle('DroboView') self.setWindowIcon(QtGui.QIcon(':Drobo-Front-0000.gif')) exit = QtGui.QAction(QtGui.QIcon('icons/exit.png'), 'Exit', self) exit.setShortcut('Ctrl+Q') exit.setStatusTip('Exit application') self.connect(exit, QtCore.SIGNAL('triggered()'), QtCore.SLOT('close()')) menubar = self.menuBar() file = menubar.addMenu('&File') file.addAction(exit) help = menubar.addMenu('&Help') manual = QtGui.QAction(QtGui.QIcon('icons/exit.png'), 'Read Me', self) self.manualdialog = ShowText("README.html") help.addAction(manual) self.connect(manual, QtCore.SIGNAL('triggered()'), self.manualdialog.show) devmanual = QtGui.QAction(QtGui.QIcon('icons/exit.png'), 'For Developers', self) self.devmanualdialog = ShowText("DEVELOPERS.html") help.addAction(devmanual) self.connect(devmanual, QtCore.SIGNAL('triggered()'), self.devmanualdialog.show) dmmanpage = QtGui.QAction(QtGui.QIcon('icons/exit.png'), 'Drobom man-page', self) self.dmmanpagedialog = ShowText("drobom.html") help.addAction(dmmanpage) self.connect(dmmanpage, QtCore.SIGNAL('triggered()'), self.dmmanpagedialog.show) dvmanpage = QtGui.QAction(QtGui.QIcon('icons/exit.png'), 'Droboview man-page', self) self.dvmanpagedialog = ShowText("droboview.html") help.addAction(dvmanpage) self.connect(dvmanpage, QtCore.SIGNAL('triggered()'), self.dvmanpagedialog.show) chgmanual = QtGui.QAction(QtGui.QIcon('icons/exit.png'), 'Change log', self) self.chgmanualdialog = ShowText("CHANGES.html") help.addAction(chgmanual) self.connect(chgmanual, QtCore.SIGNAL('triggered()'), self.chgmanualdialog.show) about = QtGui.QAction(QtGui.QIcon('icons/exit.png'), 'About DroboView', self) self.aboutdialog = DroboAbout() help.addAction(about) self.connect(about, QtCore.SIGNAL('triggered()'), self.aboutdialog.show) self.tab = QtGui.QTabWidget(self) self.setCentralWidget(self.tab) self.tab.setMinimumWidth(300) self.tab.setMinimumHeight(300) self.__initDeviceTab() self.__initToolTab() self.__initFormatTab() self.__updatewithQueryStatus() self.updateTimer = QtCore.QTimer(self) self.connect(self.updateTimer, QtCore.SIGNAL("timeout()"), self.__updateStatus ) self.updateTimer.setInterval(1000) self.updateTimer.start() partitioner= " gparted" hoho+repack.orig/DroboIOctl.py0000644000175000017500000002372311265217256015637 0ustar morphmorph from ctypes import * from fcntl import ioctl import Drobo import struct def hexdump(label,data): i=0 print "%s %03x:" % (label, i), for bb in data: print "%02x" % ord(bb), i=i+1 if (i % 16) == 0: print print "%s %03x:" % (label,i), print class sg_io_hdr(Structure): """ do ioctl's using Linux generic SCSI interface. all of this comes from /usr/include/scsi/sg.h """ SG_DXFER_TO_DEV=-2 SG_DXFER_FROM_DEV=-3 SG_IO = 0x2285 SG_GET_VERSION_NUM = 0x2282 # see include/scsi/scsi.h for more values SAM_STAT_GOOD = 0x00 SAM_STAT_CHECK_CONDITION = 0x02 _fields_ = [ ("interface_id", c_int ), ("dxfer_direction", c_int), ("cmd_len", c_ubyte), ("mx_sb_len", c_ubyte), ("iovec_count", c_ushort), ("dxfer_len", c_int), ("dxferp", c_char_p), # ought to be void... ("cmdp", c_char_p), ("sbp", c_char_p), ("timeout", c_uint), ("flags", c_uint), ("pack_id", c_int), ("usr_ptr", c_char_p), # ought to be void... ("status", c_ubyte), ("masked_status", c_ubyte), ("msg_status", c_ubyte), ("sb_len_wr", c_ubyte), ("host_status", c_ushort), ("driver_status", c_ushort), ("resid", c_int), ("duration", c_uint), ("info", c_uint) ] def __init__(self): self.interface_id=ord('S') self.dxfer_direction=0 self.cmd_len=0 self.mx_sb_len=0 self.iovec_count=0 self.dxfer_len=0 self.dxferp=None self.cmdp=None self.timeout=20000 # milliseconds #self.timeout=4000 # milliseconds self.flags=0 self.pack_id=0 self.usr_ptr=None self.status=0 self.masked_status=0 self.msg_status=0 self.sb_len_wr=0 self.host_status=0 self.driver_status=0 self.resid=0 self.duration=0 self.info=0 class DroboIOctl: def __init__(self,char_dev_file,readwrite=1,debugflags=1): self.char_dev_file=char_dev_file self.sg_fd=open(char_dev_file,'w') self.debug=debugflags def version(self): """ """ k=create_string_buffer(8) if ioctl(self.sg_fd, sg_io_hdr.SG_GET_VERSION_NUM, k) < 0 : print "%s is not an sg device, or old sg driver\n" % char_dev_file num=struct.unpack("l",k) return num def closefd(self): if self.sg_fd > 0: self.sg_fd.close() self.sg_fd=-1 pass def identifyLUN(self): """ printf("%s: scsi%d channel=%d id=%d lun=%d", file_namep, host_no, (my_idlun.dev_id >> 16) & 0xff, my_idlun.dev_id & 0xff, (my_idlun.dev_id >> 8) & 0xff); """ SCSI_IOCTL_GET_IDLUN = 0x5382 SCSI_IOCTL_GET_BUS_NUMBER = 0x5386 fmt=">bbbbl" idlun = create_string_buffer(struct.calcsize(fmt)) i= ioctl( self.sg_fd, SCSI_IOCTL_GET_IDLUN, idlun) if i < 0: print "Drobo get_mode_page SG_IO ioctl error" return None (channel, lun, id, host, host_unique_id ) = struct.unpack(fmt, idlun) #print "%s: scsi%d channel=%d id=%d lun=%d" % ( self.char_dev_file, host, \ # channel, id, lun ) #bog standard inquiry mcb fmt="8s8s16s" hoholen=struct.calcsize(fmt) mcb=struct.pack("6B", 0x12, 0, 0, 0, hoholen, 0 ) # len ought to be 96 hoho=self.get_sub_page(hoholen,mcb,0,self.debug) (dunno1,vendor,product) = struct.unpack(fmt,hoho) return ( host, channel, id, lun, vendor ) def get_sub_page(self, sz, mcb, out, DEBUG): """ ioctl to retrieve a sub-page from the Drobo. required arguments: sz : length of buffer to be returned. if the ioctl indicates a residual amount control_block : some scsi control block thingum... pass transparently through to ioctl/SG out : choose direction of xfer. out= to device. debug : if 1,then print debugging output (lots of it.) """ io_hdr=sg_io_hdr() if out: io_hdr.dxfer_direction=sg_io_hdr.SG_DXFER_TO_DEV else: io_hdr.dxfer_direction=sg_io_hdr.SG_DXFER_FROM_DEV if self.debug & Drobo.DBG_HWDialog: hexdump("mcb", mcb) io_hdr.cmd_len = len(mcb) io_hdr.cmdp = mcb sense_buffer = create_string_buffer(64) self.mx_sb_len = len(sense_buffer) #io_hdr.sbp=addressof(sense_buffer) io_hdr.sbp=cast(sense_buffer,c_char_p) io_hdr.sb_len_wr = 0 # initialize just in case... page_buffer=create_string_buffer(sz) io_hdr.dxfer_len = sz #io_hdr.dxferp = addressof(page_buffer) io_hdr.dxferp = cast(page_buffer,c_char_p) if self.debug & Drobo.DBG_HWDialog: print "4 before ioctl, sense_buffer_len=", io_hdr.mx_sb_len i=ioctl(self.sg_fd, sg_io_hdr.SG_IO, io_hdr) if self.debug & Drobo.DBG_HWDialog: print "5 after ioctl, result=", i print "status: ", io_hdr.status print "driver_status: ", io_hdr.driver_status print "host_status: ", io_hdr.host_status print "sb_len_wr: ", io_hdr.sb_len_wr print "resid: ", io_hdr.resid if i < 0: raise IOError("Drobo get_mode_page SG_IO ioctl error") if io_hdr.status != io_hdr.SAM_STAT_GOOD: raise IOError("io_hdr status is: %x" % io_hdr.status) if io_hdr.resid > 0: retsz = sz - io_hdr.resid else: retsz = sz if self.debug & Drobo.DBG_HWDialog: hexdump("page_buffer", page_buffer) print "the length is: ", retsz return page_buffer[0:retsz] def put_sub_page(self, mcb, buffer, DEBUG ): """ ioctl to write using a sub-page to the Drobo. required arguments: modepageblock - buffer DEBUG return the number of bytes written. """ io_hdr=sg_io_hdr() io_hdr.dxfer_direction=sg_io_hdr.SG_DXFER_TO_DEV io_hdr.status=99; io_hdr.cmd_len = len(mcb) io_hdr.cmdp = mcb sense_buffer = create_string_buffer(32) io_hdr.mx_sb_len = len(sense_buffer) #io_hdr.sbp=addressof(sense_buffer) io_hdr.sbp=cast(sense_buffer,c_char_p) size = len(buffer) data2write = create_string_buffer(buffer,size) io_hdr.dxfer_len = size #io_hdr.dxferp = addressof(data2write) io_hdr.dxferp = cast(data2write,c_char_p) #these are set by ioctl... initializing just in case. io_hdr.sb_len_wr=0; io_hdr.resid=0; io_hdr.status=0; #iohp = cast(pointer(io_hdr), c_void_ptr).value i=ioctl(self.sg_fd, sg_io_hdr.SG_IO, io_hdr) if self.debug & Drobo.DBG_HWDialog: print "put_sub_page, 5 after ioctl, result=", i print "status: ", io_hdr.status print "driver_status: ", io_hdr.driver_status print "host_status: ", io_hdr.host_status print "sb_len_wr: ", io_hdr.sb_len_wr print "resid: ", io_hdr.resid if (i< 0) : print " get_mode_page SG_IO ioctl error" return None if (io_hdr.status != 0 ) and (io_hdr != 2) : print "oh no! io_hdr status is: %x\n" % io_hdr.status return None if io_hdr.resid > 0: size = size - io_hdr.resid return size import os def drobolunlist(debugflags=0): """ return a list of attached Drobo devices, like so [ [lun0, lun1, lun2], [lun0, lun1, lun2] ] inspired by sg_scan.c (part of sg3_utils), sample output line: /dev/sdh: scsi41 channel=0 id=0 lun=0 [em] TRUSTED Mass Storage 1.00 [rmb=0 cmdq=0 pqual=0 pdev=0x0] whose logic is encapsulated in the idenfityLUN call. """ devdir="/dev" devices=[] lundevs=[] previousdev="" p=os.listdir(devdir) p.sort() # to ensure luns in ascending order. for potential in p: if potential.startswith("sd") and len(potential) == 3: dev_file = devdir + '/' + potential try: if debugflags & Drobo.DBG_Detection: print "examining: ", dev_file pdio = DroboIOctl( dev_file ) except: if debugflags & Drobo.DBG_Detection: print "rejected: failed to construct LUN pdio" continue try: id = pdio.identifyLUN() except: if debugflags & Drobo.DBG_Detection: print "rejected: failed to identify LUN" pdio.closefd() continue if debugflags & Drobo.DBG_Detection: print "id: ", id thisdev="%02d%02d%02d" % (id[0], id[1], id[2]) if ( id[4].startswith("TRUSTED") or id[4].startswith("DROBO") ): # you have a Drobo! if debugflags & Drobo.DBG_Detection: print "found a Drobo" if thisdev == previousdev : # multi-lun drobo... if debugflags & Drobo.DBG_Detection: print "appending to lundevs..." lundevs.append( dev_file ) else: if lundevs != []: devices.append(lundevs) if debugflags & Drobo.DBG_Detection: print "appending new lundevs to devices:", devices lundevs=[dev_file] else: if debugflags & Drobo.DBG_Detection: print "rejected: vendor is %s (not from DRI)" % id[4] previousdev=thisdev pdio.closefd() if lundevs != []: devices.append(lundevs) if debugflags & Drobo.DBG_Detection: print "returning list: ", devices return devices # unit testing... if __name__ == "__main__": import struct # only for unit testing... valid_device="/dev/sdg" #valid mcb: 5a 00 3a 01 00 00 00 00 14 00 valid_mcb=struct.pack(">BBBBBBBBBB", 0x5a, 0, 0x3a, 1, 0, 0, 0, 0, 0x14, 0 ) dmp = DroboIOctl(valid_device) print "version", dmp.version() print "identifyLUN", dmp.identifyLUN() print "doing a sub_page" hoho=dmp.get_sub_page(20,valid_mcb,0,4) # the 4 byte header on the returned sense buffer: (122, 1, 20) # cfg: (4, 16, 1099511557632) #hexdump("hoho", hoho) fmt=">BBHBBBQBHH" print struct.calcsize(fmt) print struct.unpack(fmt,hoho) dmp.closefd() print 'hunt...' print drobolunlist() hoho+repack.orig/Makefile0000644000175000017500000000127611265217256014724 0ustar morphmorph#!/usr/bin/make -f build: doc python setup.py build clean: -python setup.py clean -find . -name "*\.pyc" -delete -rm CHANGES.html DEVELOPERS.html README.html drobom.html droboview.html -rm -rf build* doc: groff -Thtml -man drobom.8 >drobom.html groff -Thtml -man droboview.8 >droboview.html rst2html README.txt >README.html rst2html DEVELOPERS.txt >DEVELOPERS.html rst2html CHANGES.txt >CHANGES.html # Uncomment this to turn on verbose mode. PKGNAME := drobo-utils install: build python setup.py install_lib -d /usr/lib/python/site-packages; python setup.py install_data -d /usr/share/$(PKGNAME) python setup.py install_scripts -d /usr/sbin release: ./make_tarball.sh debuild -i hoho+repack.orig/setup.py0000644000175000017500000000172211265217256014772 0ustar morphmorph# Drobo Utils Copyright (C) 2008,2009 Peter Silva (Peter.A.Silva@gmail.com) # Drobo Utils comes with ABSOLUTELY NO WARRANTY; For details type see the file # named COPYING in the root of the source directory tree. from distutils.core import setup setup (name = 'Drobo-utils', version = '0.6.1', description = 'Drobo Management Protocol io package', py_modules=['Drobo','DroboGUI', 'DroboIOctl' ], scripts=['drobom', 'droboview'], data_files = [ ('share/pixmaps', ['Drobo-Front-0000.gif']), ('share/drobo-utils-doc', ['README.html']), ('share/drobo-utils-doc', ['DEVELOPERS.html']), ('share/drobo-utils-doc', ['drobom.html']), ('share/drobo-utils-doc', ['droboview.html']), ('share/drobo-utils-doc', ['CHANGES.html']) ] ) hoho+repack.orig/DroboFirmwareWishes.txt0000644000175000017500000000350411265217256017746 0ustar morphmorph Hi Data Robotics! Here are a bunch of wishes people have for firmware improvements. relay out progress report: when there is a status "relay out in progress" would be very helpful to get a "% complete" number reportable somehow. Dashboard or other tools can figure out when it will be complete. Alternatively, drobo could do all the work, and just report relay out start and predicted end times. --psilva cpu utilisation report: Drobo often gets slow/busy. It would be nice to have a means of reporting how busy it is. --psilva "hardware" encryption: a scsi command that accepts a key from the host, used to encrypt/decrypt on the fly transparently to the host OS. --psilva "Release disk" command: Sometimes, one wants to remove a disk from drobo, even though it is working fine, for use elsewhere. Currently, the way to do that is to remove the disk, and then there is an interval when there is no redundancy, until the relay out process is complete. It would be useful to be able to ask the Drobo to perform the disk relay out process while the disk is still present, so window of lack of redundancy is 0. A scsi command to ask Drobo to start the relayout to free up a specified disk for removal. At the end of the process, the disk freed should be powered down, and a flashing green LED should indicate that it is ready for removal. --psilva "allocate/deallocate" block: a scsi command to allow for host based instructions about which blocks contain real data and which are free (for which relay out processing is not needed.) - Jkrahn "SCSI compliance": Even a cheap USB-key storage has proper SCSI support. Some of the existing mode-page data should be moved to SCSI VPD pages, and the diagnostic logs should be transferred by the log-transfer mechanism built in to the SCSI protocol. -- jkrahn hoho+repack.orig/drobom.html0000644000175000017500000002602011265220316015415 0ustar morphmorph DROBOM

DROBOM

NAME
SYNOPSIS
DESCRIPTION
AUTHOR

NAME

drobom − CLI for managing drobo units

SYNOPSIS

drobom [ options ] <command> [ arguments... ]

DESCRIPTION

options is one of:

−c, −−command

the command to execute.

−d, −−device

the device to operate on (default searches all devices and picks first one found.)

−h, −−help

print a usage message

−v, −−verbose

verbosity, a bit-field to trigger increased output as needed, mostly for debugging. 1 - General, 2 - Hardware Dialog, 4 - Initiation, 8 - DMP layer, 16- Detection 64 will print everything... (default: 0, as terse as possible.) 128 enables simulation mode (for testing when no Drobo is available. Dangerous!)

−V, −−version

print the version id.

command is one of:

blink

identify the drobo by making the lights blink

diag

dump diagnostics file into /tmp directory

diagprint <diagdumpfile>

print diagnostics file to standard output

<diagdumpfile> the diagnostic dump file to print.

fwcheck query drobo.com for updates to firmware for the given Drobo

fwload load a specific firmware for the given Drobo. Arguments:

<fwimage> the firmware file to load.

fwupgrade

upgrade the firmware to the latest and greatest, recommended by DRI

help

print this text

info <toprint>

print information on a Drobo. The <toprint> argument is a comma separated list of the values below (default is to print all of them): config, capacity, protocol, settings, slots, firmware, status, options, luns

list

show device files for all Drobos found.

name <newname>

Set the name of the Drobo to the given value ( only firmware > 1.3.0 supports this command )

settime sync Drobo’s clock to UTC

setlunsize Set the size of LUNS on device. Arguments:

<sz> integer number of TiB to set the lunsize to

<confirmation> Specify ’PleaseEraseMyData’ if you really mean it

Note: After execution, Drobo reboots, wait a few minutes before accessing again

shutdown

shutdown drobo (DRI calls this ’standby’)

status

report how is the Drobo doing

device

raw block device of a drobo (i.e. /dev/sdz) . If not given, assumes all attached drobos.

AUTHOR

This manual page was written by Chris AtLee <chris@atlee.ca> for the Debian project (but may be used by others).


hoho+repack.orig/DEVELOPERS.txt0000644000175000017500000002463211265217256015476 0ustar morphmorph---------------- DEVELOPERS NOTES ---------------- .. contents:: This software is copyright under GPL. See near end file for details... Random useful bits for developers. (aka notes to myself ;-) Working With Source ------------------- Project Source code is managed using a git repository provided by sourceforge.net. Git ( http://git-scm.com/ ) provides a fully distributed development model, so one can exchange patches arbitrarily among developers. On the sf.net repository, the 'master' branch is the final integration target for future releases. Getting a Source Tree --------------------- the following checks out the master branch of the source code tree and puts it in the drobo-utils subdirectory of the current tree. git clone ssh://peter_silva@drobo-utils.git.sourceforge.net/gitroot/drobo-utils/drobo-utils drobo-utils Before doing Any commits, ensure that the author fields are appropriately set. One can obtain patches applied to the branch with git pull, and commit patches for distribution with git push. GIT Configure Patch Author -------------------------- To ensure the correct author on patches created, make sure to set your author settings. Something like the following is appropriate if you use a single identity for all your code contributions. boule% git config --global user.name "firstname lastname" boule% git config --global user.email "developer@sourceforge.net" boule% Others may wish for the identity to be associated with each project. Using a Source Snapshot ----------------------- Sometimes, when there are issues, the correction gets checked in, but there hasn't been time to do a full release process. If you really need the fix, then your only option is to get it from the developers' git repository. If you are told 'it is in git', that refers to the git source code management system, and the server for that is at sourceforge.net. How to get it:: # git clone ssh://developer@drobo-utils.git.sourceforge.net/gitroot/drobo-utils/drobo-utils mine # cd mine # go into the source directory you downloaded # ./drobom status # try it out... # python setup.py install # install it in system places... # drobom status # try it out... # git pull # get any changes made since the git clone was done. # python setup.py install # install the changes in system places. Sample checkout of a stable version. To view available branches:: % git branch -r origin/HEAD -> origin/master origin/master origin/noC origin/peter origin/r0.2.1 origin/r0_3_3 origin/r0_4_0 origin/r0_5_0 origin/r0_6_0 Where a version is something like r0_4_0. then you can pick anyone to work with:: % git branch r0_4_0 -r origin/r0_4_0 Branch r0_4_0 set up to track remote branch r0_4_0 from origin. % git checkout r0_4_0 Switched to branch 'r0_4_0' % When you use git to get a tree, it keeps copies of metadata to be able to track changes. If you want a copy that is contains no git cruft, rm -rf .git in the root of the source tree. If you are mixing downloaded packages and source installs, check out the next section for gotchas. Dpkg vs. Python Install ----------------------- The 'setup.py' script, mentioned in the previous section, is a convention from the distutils python packaging system. distutils installation is slightly different from installation from debian packages. There doesn't seem to be a distutils way to remove a package. touch all the files, do an installation, then manually remove the files it installed. drobo-utils has been picked up for inclusion in debian. The "real" packaging for debian packages is kept in a separate tree, and maintained by debian developers. The debian/ setup puts stuff in /usr/sbin while setup.py puts things in /usr/bin. Python install does not install man pages either, which the dpkg takes care of. The libs are placed differently too. haven't reviewed for other conflicts, least confusing to use one or the other method on a system. (if you do distutils install, then remove the debian package via: dpkg --purge drobo-utils) Making a Release ---------------- 1 - make a branch # assuming you have a local repository... git branch # creates the branch, from the cwd (ought to be master) git checkout # switches current dir to the branch. 2 - Stamp the branch with version vi CHANGES.txt # complete change manifest for release vi debian/changelog # copy manifest from txt, add signature. vi setup.py # edit version vi Drobo.py # edit VERSION 3 - Build packages for testing & Install them. (see separate recipe.) 4 - Run QA. Record results of release tests in the branch (QA.txt) As new tests are created, modify QA.txt on trunk for to keep references for the next release. Quality Assurance (QA.txt) ========================== QA.txt is a quality assurance log. The version on the trunk of the releases indicates the QA procedure to be applied to the next version during the release process. Since a branch is created for each release, the version of QA.txt acts as a quality log for that release. so one can do an git checkout, or git export to get the quality log for any release (QA.txt introduce in version 0.4.0) Building Debian & Ubuntu Packages ================================= Assumes you have installed the Build dependencies:: # obtain a fresh tree % git clone ssh://peter_silva@drobo-utils.git.sourceforge.net/gitroot/drobo-utils/ drobo-utils- % cd drobo-utils- % rm -rf .git # get rid of Git cruft, yielding a raw source tree. % chmod 755 debian/rules # I dunno why the permissions are wrong... # this debian/ config is just for non-distro packages. # builds for debian and Ubuntu. % dpkg-buildpackage -rfakeroot % cd .. # rename it for whatever distro is appropriate... % mv drobo_utils_0.3.3-1_i386 --> droboutils_0.3.3-1_i386_ubunutuIntrepid.deb # rebuild the source tar because it will have the 'debian' link in it. % cd drobo-utils-0.99.9 % rm debian % cd .. % tar -czvf drobo-utils-0.3.3-1.tgz drobo-utils-0.99.9 apply QA tests. as per QA.txt recording results there. Updating Documentation ---------------------- use the restructured text tools (from the python-docutils package.) to build things using: % make doc Have a look at Makefile for how that works. update the web site: % scp README.html ,drobo-utils@web.sourceforge.net:htdocs Droboshare ---------- Droboshare is not directly supported by drobo utils running on a linux host. However, the droboshare itself is a linux host, and it is possible to run drobo-utils un-modified on the droboshare itself. There is download called the Droboshare Augmented Root File system (DARFS), which includes a python interpreter and drobo-utils. Open Task: Reverse Engineer Dashboard <-> Droboshare Protocol ============================================================= Why isn't there full support in host based drobo-utils itself? Digital Robotics hasn't released details of the protocol used by the proprietary dashboard to communicate with a droboshare, so it would be a lot of work to reverse engineer that. So support of a droboshare from a linux GUI on a host system is not likely in the near future. If someone wants to figure that out, it might be a good thing (tm) After that is figured out, the next step would be to understand how to flash the firmware remotely. That would eliminate the last function that cannot be done with open source. Building DARFS ============== DARFS - Droboshare Augmented Root File System. A pile of stuff that can be run on a droboshare. Have a look here: http://groups.google.com/group/drobo-talk/web/building-droboshare-apps-on-debianish-os?hl=en TODO ---- Tasks which would be cool to get done, in no particular order: Option setting... especially for DroboPro IP Address & netmask. CentOS support. Fedora is likely fine, but should build a VM with CentOS on it, and build an rpm. RHEL has an ancient python (2.4?) with no ctypes by default, so could be interesting. GUI - handle when Drobo disappears... Refuse known non-working feature bits... firmware (review 2009 SDK release) Review feature bits, mis-marked? 28 Add Alerting to GUI & CLI -- save config... .. SMTP forwarder: .. address .. authentication.? u+p .. Droboshare bugs -- don't dump diags to /tmp, they don't fit. -- don't BUGS: when running two fw uploads, the second one will not run easily. need to wait for transaction to timeout... perhaps randomize id? did randomization, did not change anything... STANDARD menu entries for droboview... partition types do not appear to be correctly displayed... some confusion between NTFS vs. EXT3 no obvious ill effect. partition type should pre-select in Format dialog... memory consumption on the GUI. still chews up 4 MB per hour... gnats: man page does not document output. -- what is the meaning of the output? provide a sample... review print statements: should they write to stderr? STANDARD menu entries for droboview... Better STATUS progress reporting: -- the block count is there, but heuristics for determining timing suck. -- some sort of indicator of how long 'relay out' will be in progress. -- when it is busy, it should say so... like when I emptied an ntfs it took hours for the led indicators to drop from 70% to 0. It should say something about what is going on. LIVELIER GUI: -- have status queries proceed asynchronously from the GUI. right now, if the drobo is slow, the GUI makes it slower, and gets very slow too. should run as a daemon, async. from the GUI. Re-design the whole darn thing. -- there should be some sort of service integrated with dbus-hal -- not sure that a GUI is needed at all. but if it is, it should be a DBUS client. -- how does authentication work in DBUS? of interest: -- python bindings for parted... http://dcantrel.fedorapeople.org/pyparted/ Revision date: 2009/05/19 copyright: Drobo Utils Copyright (C) 2008,2009 Peter Silva (Peter.A.Silva@gmail.com) Drobo Utils comes with ABSOLUTELY NO WARRANTY; For details type see the file named COPYING in the root of the source directory tree. Administrivia ------------- version 0.6.1, October 6th 2009. copyright: Drobo Utils Copyright (C) 2008 Peter Silva (Peter.A.Silva@gmail.com) Drobo Utils comes with ABSOLUTELY NO WARRANTY; For details type see the file named COPYING in the root of the source directory tree. hoho+repack.orig/CHANGES.html0000644000175000017500000003202511265220321015201 0ustar morphmorph
master
  • TODO: Fix the weird prompt in parted... you got a letter about that.
  • TODO: looking at firmware based LUN creation/deletion & format.
  • TODO: alerts.
  • TODO: review unitstatus vs. diskpack status.
  • TODO: review format queries (NTFS/GPT/MBR, etc...)
0.6.1: October 7th, 2009
  • misc. bug-fixes. DroboPro identification fix by spobole
  • Looked at newly released DMIP. Found option2 command.
  • Options2 query/set implemented (but cannot test for Drobo)
  • migrated source code managers from subversion to git
  • minor: consistency of default location to look for fw between lib and gui.
  • fixed that inability to read lun size on old firmwares crashed GUI. GUI now works all the way back to the beginning.
0.6.0
  • Major: GUI heavily re-vamped. Behaves better.
  • Major: DroboPRO support added (thanks to lemonizer on the google group!)
  • Major: GUI gets online documentation.
  • GUI: layouts replaced fixed dimensions.
  • GUI: added Rename support
  • GUI: added Load firmware button
  • GUI: Show Diagnostics (equiv. to diagprint.)
  • GUI: Name display to main display. Easier to tell which Drobo is which.
  • GUI: added mount point display to space used tool tip.
  • api: added ability to detect un-documented feature bit settings.
  • ddiag.c becomes drobom diagprint
  • catlee fixes the packaging again.
0.5.0 2009/01/30
  • replaced DroboDMP C extension by DroboIOctl python class. no need for architecture dependent packages. this also means you can just try it out straight after download, no need to install anything. much easier. fewer build dependencies as well.
  • device detection completely re-written. It works better now.
  • Now displays mount points where it makes sense to do so.
  • status command output better/different. shows all devices and mount points for each drobo.
  • full Multiple LUN support. should do what is expected.
  • full multiple Drobo support. should do what is expected.
  • added modular info printing with csv list of outputs.
  • firmware 1.3.0, has enabled formerly broken functionality which name makes the sync command rename every drobo to 'hi there'. fixed.
  • added 'name' command, to name Drobo. (functionality of Sync)
  • corrected detection logic, which depended on formerly immutable name. (affects fw >= 1.3.0) now use same mechanisms as sg_scan from sg3_utils.
  • documentation moved into restructured text. now shows up on the web. web site and documntation now consistent.
0.4.0 Release: 2008/12/28
  • IMPORTANT: firmware 1.3.0 support added. Earlier drobo-utils

    versions will not recognize a drobo running 1.3.0 or later.

  • CLI is more normal... use getopts (got rid of device as fixed place arg.)

    now allows command to be an option as well.

  • Changed DEBUG from a flag requiring code modification, to a bitmap

    honored as a command-line argument (--verbose)

  • misc. improvements in documentation.

  • droboview now only launches for first drobo found in list, and stays foreground

    always.

  • drobom list returns a list that is easier to parse (suitable for use in backticks.)

  • droboview is now just a stub for drobom view. reduced overhead.

  • now reports VERSION id in usage. There is a -V option too.

0.3.3 release: 2008/11/05
  • lunsize display bug fixed.
  • Chris's man pages & help improvements.
  • more messaging fixups for when you don't invoke as root.
  • fix for ubuntu Intrepid deciding all disks are Drobos. !!
  • fixed all the firmware info parsing issues.
  • firmware load issues should all be gone.
  • Brad's fix for ddiag.c, done properly this time (my bad!)

0.3.2 release 2008/10/25

  • for v1, still don't understand index.txt file.

  • after testing, some more fixes, v2 downloads now work.

  • fixes received from Brad Guillory for v2/tdz firmware downloading.

    they don't do any harm afaict, don't have a v2 to test with.

  • added fwload directive to drobom.

  • added root user check to give a bigger hint.

0.3.1 release 2008/10/01

  • OK I know checking for firmware updates doesn't work

    right now, but I need to find out why. code seems correct. there is a bugfix for getting rid of the 'licensed' part.

  • fixes for firmware validation:
    • header CRC on 32bit was broken on 64bit.
    • 32 vs. 64 bit kludge needed.
0.3.0 release 2008/09/04
  • added ability to format Drobo

  • added ability to set lun sizes

  • bugfix for firmware:
    • CRC32 on 32bit intel. (use signed, instead of unsigned.)
    • fixed header CRC not validating.
  • added ability to set time on Drobo.

  • added simulation mode to Drobo.py, development aid.

  • some work done towards lunsize setting, but incomplete.

  • some work towards indicating relay out progress, not tested...

0.2.2 Released 2008/08/08
  • firmware uploads work with .tdz as well

  • tested with older firmwares, contains a few fixes to improve compatibility.

    works well enought upgrade old firmwares.

0.2.1 Released: 2008/08/06
  • uploaded to drobospace & sourceforge.
  • firmware upload works for .tdf's
0.1.1 Initial version uploaded april 2008
  • to drobospace.com and sf.net
  • confirmed to work with firmware 1.1.1
  • shows status, disk slots filled, model, etc..
  • shows fw version loaded.
  • blink & standby commands work.
hoho+repack.orig/CHANGES.txt0000644000175000017500000001243711265223361015070 0ustar morphmorph master * TODO: Fix the weird prompt in parted... you got a letter about that. * TODO: looking at firmware based LUN creation/deletion & format. * TODO: alerts. * TODO: review unitstatus vs. diskpack status. * TODO: review format queries (NTFS/GPT/MBR, etc...) 0.6.1: October 7th, 2009 * DroboPro identification fix by spobole, * parted fix from Patrick Bills * Looked at newly released DMIP. Found option2 commands for settings. * Option query/set implemented (but cannot test for DroboPRO) * migrated source code managers from subversion to git * minor: consistency of default location to look for fw between lib and gui. * fixed that inability to read lun size on old firmwares crashed GUI. GUI now works all the way back to the beginning. 0.6.0 * Major: GUI heavily re-vamped. Behaves better. * Major: DroboPRO support added (thanks to lemonizer on the google group!) * Major: GUI gets online documentation. * GUI: layouts replaced fixed dimensions. * GUI: added Rename support * GUI: added Load firmware button * GUI: Show Diagnostics (equiv. to diagprint.) * GUI: Name display to main display. Easier to tell which Drobo is which. * GUI: added mount point display to space used tool tip. * api: added ability to detect un-documented feature bit settings. * ddiag.c becomes drobom diagprint * catlee fixes the packaging again. 0.5.0 2009/01/30 * replaced DroboDMP C extension by DroboIOctl python class. no need for architecture dependent packages. this also means you can just try it out straight after download, no need to install anything. much easier. fewer build dependencies as well. * device detection completely re-written. It works better now. * Now displays mount points where it makes sense to do so. * status command output better/different. shows all devices and mount points for each drobo. * full Multiple LUN support. should do what is expected. * full multiple Drobo support. should do what is expected. * added modular info printing with csv list of outputs. * firmware 1.3.0, has enabled formerly broken functionality which name makes the sync command rename every drobo to 'hi there'. fixed. * added 'name' command, to name Drobo. (functionality of Sync) * corrected detection logic, which depended on formerly immutable name. (affects fw >= 1.3.0) now use same mechanisms as sg_scan from sg3_utils. * documentation moved into restructured text. now shows up on the web. web site and documntation now consistent. 0.4.0 Release: 2008/12/28 * IMPORTANT: firmware 1.3.0 support added. Earlier drobo-utils versions will not recognize a drobo running 1.3.0 or later. * CLI is more normal... use getopts (got rid of device as fixed place arg.) now allows command to be an option as well. * Changed DEBUG from a flag requiring code modification, to a bitmap honored as a command-line argument (--verbose) * misc. improvements in documentation. * droboview now only launches for first drobo found in list, and stays foreground always. * drobom list returns a list that is easier to parse (suitable for use in backticks.) * droboview is now just a stub for drobom view. reduced overhead. * now reports VERSION id in usage. There is a -V option too. 0.3.3 release: 2008/11/05 * lunsize display bug fixed. * Chris's man pages & help improvements. * more messaging fixups for when you don't invoke as root. * fix for ubuntu Intrepid deciding all disks are Drobos. !! * fixed all the firmware info parsing issues. * firmware load issues should all be gone. * Brad's fix for ddiag.c, done properly this time (my bad!) 0.3.2 release 2008/10/25 * for v1, still don't understand index.txt file. * after testing, some more fixes, v2 downloads now work. * fixes received from Brad Guillory for v2/tdz firmware downloading. they don't do any harm afaict, don't have a v2 to test with. * added fwload directive to drobom. * added root user check to give a bigger hint. 0.3.1 release 2008/10/01 * OK I know checking for firmware updates doesn't work right now, but I need to find out why. code seems correct. there is a bugfix for getting rid of the 'licensed' part. * fixes for firmware validation: * header CRC on 32bit was broken on 64bit. * 32 vs. 64 bit kludge needed. 0.3.0 release 2008/09/04 * added ability to format Drobo * added ability to set lun sizes * bugfix for firmware: * CRC32 on 32bit intel. (use signed, instead of unsigned.) * fixed header CRC not validating. * added ability to set time on Drobo. * added simulation mode to Drobo.py, development aid. * some work done towards lunsize setting, but incomplete. * some work towards indicating relay out progress, not tested... 0.2.2 Released 2008/08/08 * firmware uploads work with .tdz as well * tested with older firmwares, contains a few fixes to improve compatibility. works well enought upgrade old firmwares. 0.2.1 Released: 2008/08/06 * uploaded to drobospace & sourceforge. * firmware upload works for .tdf's 0.1.1 Initial version uploaded april 2008 * to drobospace.com and sf.net * confirmed to work with firmware 1.1.1 * shows status, disk slots filled, model, etc.. * shows fw version loaded. * blink & standby commands work. hoho+repack.orig/README.txt0000644000175000017500000005146511265217256014767 0ustar morphmorph================== Drobo Utils README ================== Drobo-utils is a set of linux tools to query and manage Data Robotics Drobo storage systems. If you fire up droboview, it should look pretty familiar to those who have seen the dashboard on other operating systems. Droboview is built on a little programmer interface which can be installed on the system and used by other applications as well. For experienced Linux hands, there is a command line interface, drobom, which offers the same functionality as droboview. For real hackers, fire up a python interpreter, 'import Drobo', help(Drobo), and you are off to the races... Command-line access is also bundled into a set of improvements to a standards droboshare called 'Droboshare Augmented Root File System' (DARFS) .. contents:: INSTALLATION ------------ Drobo utils installation. REQUIREMENTS ============ Drobo-utils was developed on pre-release version of Kubuntu (Hardy, Intrepid, and now Jaunty) Any similarly recent distro ought to do. To get drobo-utils running, you need packages something like (these are ubuntu packages, names may vary on other distros): essential:: python -- interpreter for python language parted -- partitioner, usually included with the distro. if using RHEL, which has python 2.4... python-ctypes -- module for C-interface for the GUI: python-qt4 -- the python bindings for version 4 of the QT toolkit To get a complete list, it is best to use a shell window to grep in the Debian package control file (which defines what the dependencies are for the build system):: peter@pepino% grep Depend debian/control Build-Depends: debhelper (>= 5), python2.5-dev, python-docutils Depends: ${shlibs:Depends}, ${misc:Depends}, parted peter@pepino% INSTALLING pre-requisites ========================= On ubuntu, it would typically look like so: Open a shell window. Enter the following package installation commands:: % sudo aptitude install python-qt4 parted % sudo aptitude install debhelper python2.5-dev % sudo aptitude install python-docutils If you have received a pre-built binary package,then you only need the first line. If you want to build from source, then you need the second line. The third line install what you need to build documentation. On redhat/fedora distros, it would more likely be 'yum' instead of 'aptitude' and some of the package names will change. A typical difference is that packages for developers have the -devel suffix on Redhat derived distributions, instead of the -dev favoured by debian derived ones. here is an example from fedora 7 (courtesy of help4death on the google group):: % yum install python % yum install PyQt4 % yum install python-devel NOTE: if X or QT is missing, it will only disable the GUI. Line mode will work without issues. the package should work fine on headless servers using only the command line. Install From Package ==================== Point your browser at: http://sourceforge.net/project/showfiles.php?group_id=222830 where current packages are available. after downloading a .deb, it is simply a matter of: dpkg -i drobo-utils-.deb done! Install from Source =================== See DEVELOPER.txt Try Out the CLI =============== Assuming you have all of the above parts, in the directory where you downloaded the source, you should be able to invoke the command line interface as follows:: drobom status see if something sensible happens... on my system with a drobo the following happens:: % sudo drobom status /dev/sdz /drobo01 100% full ( ['Red alert', 'Bad disk', 'No redundancy'], 0 ) % Note: drive changed to sdz to avoid copy/paste errors. very scary, but my drobo is in bad shape right now... you should just get [] as a status, which means there is nothing wrong. To get all kinds of information on your drobo, try 'drobom info.' You can then invoke it with no arguments at all which will cause it to print out a list of the commands available through the command line interface. Try Out the GUI =============== Once the command line stuff that is working, and assuming you have python-qt4 installed, try:: % droboview which should start a GUI for each drobo attached to your machine, that you have permission to access (depends on the setup, usually USB devices on desktops are accessible to users, so you can see them. Try Out the Python API ====================== See DEVELOPERS.txt Building debian & ubuntu packages ================================= See DEVELOPERS.txt Setup Drobo with Linux ---------------------- One can use the Format tab of the GUI to partition the device and create a single file system for a given LUN. NOTE: mke2fs takes a very long time to run, on the order of ten minutes per Terabyte. the display format button just turns red while the format is in progress,and you have to wait until it finishes. Have not determined a method to monitor progress yet. other file systems are much more quickly created, so less of an issue. I actually prefer to use the system tools manually, as described below: Drobos with firmware 1.1.1 or later work well under linux with ext3. You can, of course set up an NTFS or HPS+ or FAT32 if you really want, but it seems actively counter-intuitive on Linux. Have not tested HPS, but ntfs-3g worked fine initially. However, unless you are going to physically move the disk to between systems, the native (ext3) format has many advantages. The ´coffee is hot´ disclaimer is necessary at this point:: WARNING: THE FOLLOWING 4 LINES WILL ERASE ALL DATA ON YOUR DROBO! WARNING: NO, IT WILL NOT ASK ANY QUESTIONS! WARNING: ASK YOURSELF, before you start: ARE YOU SURE? WARNING: AFTER THE SECOND LINE, YOU ARE TOAST. WARNING: BEST TO BACKUP YOUR DATA BEFOREHAND... If you didn't use the GUI, Here is what you have to type:: # drobom -d /dev/sdz format ext3 PleaseEraseMyData You asked nicely, so I will format ext3 as you requested if you are really sure, go ahead and do: sh /tmp/fmtscript # cat /tmp/fmtscript #!/bin/sh parted /dev/sdz mklabel gpt parted /dev/sdz mkpart ext2 0 100% parted /dev/sdz print; sleep 5 mke2fs -j -i 262144 -L Drobo01 -m 0 -O sparse_super,^resize_inode /dev/sdz1 The above sets up the drobo as one big partition, with a label that says it ought to contain an ext2 file system. If you want an NTFS file system, then write ´ntfs´ in place of ext2. The next step is to add the file system into the partition. while parted's are instantaneous, the mke2fs takes a while, just have a little patience, it´ll be fine. sh -x /tmp/fmtscript (If you want an ntfs file system, then mkntfs -f -L Drobo01 /dev/sdz1 ought to work too... ) On my system the process looked like this:: root@alu:~# parted -i /dev/sdz GNU Parted 1.7.1 Using /dev/sdz Welcome to GNU Parted! Type 'help' to view a list of commands. (parted) mklabel gpt (parted) mkpart ext2 0 100% (parted) quit root@alu:~# fdisk /dev/sdz GNU Fdisk 1.0 Copyright (C) 1998 - 2006 Free Software Foundation, Inc. This program is free software, covered by the GNU General Public License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. Using /dev/sdz Command (m for help): p Disk /dev/sdz: 2199 GB, 2199020382720 bytes 255 heads, 63 sectors/track, 267349 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Device Boot Start End Blocks Id System /dev/sdz1 1 267350 2147488843 83 Linux Command (m for help): q root@alu:~# mke2fs -j -i 262144 -L Drobo01 -m 0 -O sparse_super,^resize_inode /dev/sdz1 mke2fs 1.40.8 (13-Mar-2008) Filesystem label=Drobo01 OS type: Linux Block size=4096 (log=2) Fragment size=4096 (log=2) 8388608 inodes, 536870886 blocks 0 blocks (0.00%) reserved for the super user First data block=0 16384 block groups 32768 blocks per group, 32768 fragments per group 512 inodes per group Superblock backups stored on blocks: 32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, 4096000, 7962624, 11239424, 20480000, 23887872, 71663616, 78675968, 102400000, 214990848, 512000000 Writing inode tables: done Creating journal (32768 blocks): done Writing superblocks and filesystem accounting information: done This filesystem will be automatically checked every 26 mounts or 180 days, whichever comes first. Use tune2fs -c or -i to override. root@alu:~# root@alu:~# mount /dev/sdz1 /mnt Getting Source ============== See DEVELOPERS.txt Multiple LUNS ============= LUN is an abbreviation of 'Logical UNit'. The origin of the term is SCSI terminology. When RAID units became too large for support in the past, and were sub-divided to present smaller units the operating system. The default LUNSIZE on Drobos is 2 TiB (adjustable using the tools.) If more disk space (after allowing for parity/redundancy) than LUNSIZE is installed in a unit, Drobo will show a second (or even third) LUN. Each LUN shows up in Linux as a separate disk (examples if the first LUN shows up as /dev/sde, the next will be /dev/sdf, then /dev/sdg.) If you think you should see multiple LUNS and you don't, you might have a look at some kernel settings: make sure that scsi_mod kernel module is loaded, make sure /sys/module/scsi_mod/parameters/max_luns is > 1. Droboview will start up one GUI per drobo, regardless of the number of LUNS. If asked to format, all LUNS for the device will be formatted. ON LUNSIZES >= 2TB: -- On older distributions, there are a couple of gotchas related to linux tools which aren't 2TB ready... to exceed 2 TB, you need to: -- use GPT partitions, which aren´t supported by older fdisk versions. Tools based on libparted work fine, mostly. -- gparted fails, and seems to have a 1 TB limit on devices. (bug #524948 reported to bugzilla.gnome.org) It's just the GUI, as libparted is fine, and other tools based on it still work. -- on linux kernel < 2.6.24 supposedly, the USB layer won't let one address LUNs/offsets > 2 TB. For example, Ubuntu hardy (8.04) released in Spring 2008 has a 2.6.24, and so is OK. I've never been able to test this problem. -- ext3 with 4K blocks is supposed to allow file system capacity of 8 TiB. 4K blocks seem to be assigned by default. So I think a good max. It would be fun to set the LunSIZE to 8 TiB and test it out... Drobo Pro ========= Drobo-utils depends on the linux generic scsi layer. I suspect that there is just a basic ethernet connection now, and you a few additional driver layers set up before it will work. You need to configure the iscsi driver to recognize the device. Lemonizer on the Google Group 2009/05/16 reported good luck with: I had to manually configure the ip of the dbpro from the Drobo Dashboard on my macbook to do this as I'm not sure how to get the portal ip for iscsiadm. In my case it was 192.168.2.80 port 3260 and I'll use that ip in the example below 1. Configure iscsi ip address via drobo dashboard on win/osx 2. Install open-iscsi (http://www.open-iscsi.org/): sudo apt-get install open-iscsi 3. Connect the dbpro to host machine via iscsi 4. Query dbpro's id: sudo iscsiadm --mode discovery --type sendtargets --portal 192.168.2.80 5. Copy the id string returned by iscsiadm, something like "iqn.2005-06.com.datarobotics:drobopro.tdb091840080.node0" 6. Connect to the dbpro: sudo iscsiadm --mode node --targetname iqn.2005-06.com.datarobotics:drobopro.tdb091840080.node0 --portal 192.168.2.80:3260 --login If everything went well, your dbpro should show up under /dev. Also check /var/log/messages to confirm that the iscsi device connected successfully. After that, drobo-utils should be able to detect the Drobo and manage it over ethernet. (source: http://groups.google.com/group/drobo-talk/browse_frm/thread/453e02e105e9b41?hl=en ) Some people reported data corruption. This link claims to fix one such issue: http://www.drobospace.com/forum/thread/13951/Dropped-iSCSI-connections/?page=2#24792 Drobo Firmware -------------- Upgrading firmware is pretty self-explanatory in the GUI. the first time you press the Update button, it checks to see if a new firmware is available. If it there is newer firmware, it offer to upgrade, with suitable prompts. Similarly, the line mode interface has two commands to deal with firmware, fwcheck will tell you if an upgrade is required. the fwupgrade will do the job. It takes a few minutes, and prints a status you you can see how it is progressing. Have patience:: root@pepino:/home/peter/drobo/drobo-utils/trunk# drobom fwupgrade validateFirmware start... Magic number validated. Good. 484 + 2937552 = 2938036 length validated. Good. CRC from header: 4260378881, calculated using python zlib crc32: 398201869 yeah, the header CRCs do not match. For now they never do ... ignoring it. CRC for body from header: 1852877921, calculated: 1852877921 32 bit Cyclic Redundancy Check correct. Good. validateFirmware successful... writeFirmware: i=484, start=484, last=2938036 fw length= 488 . wrote 32768 bytes... total: 33252 wrote 32768 bytes... total: 66020 . . . wrote 32768 bytes... total: 2720228 wrote 32768 bytes... total: 2752996 wrote 32768 bytes... total: 2785764 wrote 32768 bytes... total: 2818532 wrote 32768 bytes... total: 2851300 wrote 32768 bytes... total: 2884068 wrote 32768 bytes... total: 2916836 wrote 21200 bytes... total: 2938036 writeFirmware Done. i=2938036, len=2938036 root@pepino:/home/peter/drobo/drobo-utils/trunk# when it's done, you can check if it worked using:: root@pepino# drobom status /dev/sdf - 00% full - (['New firmware installed'], 0) If the status is like that, then do:: root@pepino:/home/peter/drobo/drobo-utils/trunk# drobom shutdown lights will flash etc... wait until Drobo goes dark. Wait another five seconds, then un-plug the USB / connector. Plug it back in, and wait 10 seconds. it should start up with the latest firmware available for your drobo. The drobom commands, like DRI's dashboard, will normally get the latest and greatest firmware and upgrade. If you have the need, you can load arbitrary firmware from the CLI with fwload command. SAFETY ====== Those worried about safety of using this software should know: it was developed with assistance from the vendor (Data Robotics Inc.), and in every case, based on vendor documentation, and with at least encouragement, if not outright support. For each release, a QA.txt file is built, demonstrating the functionality tests run. There are multiple checksum verifications built into the firmware upgrade process, so it is next to impossible to brick a drobo using the tools. Drobo-utils verifies firmware checksums before attempting to upload the image to the device, and the device checks the firmware against the checksums as well. New firmware is loaded into an alternate location from the currently active one, and if activation of the new firmware fails, the drobo will simply boot the old one. On the other hand, common sense rules do apply. Setting the LUN size, or re-formatting a Drobo will erase all your data whether you do it on Linux or any other operating system. These are power tools, and they can do some damage to your data if used without proper care. For example, the reliability of any storage unit does not reduce the need for backups it only makes doing them easier. A Drobo is an excellent place to put backups, but not a substitute for them. Backups are the only way to address error 18 (the number of inches in front of the keyboard the source of the issue lies.) and no storage unit can protect against fire or flood. Compatibility ============= Drobo has been tested with every old firmware version. Any Drobo should be upgradable to modern firmware using the dashboard. NOTE: really need at least 1.1.1 to use Linux & ext3. just use the tools to upgrade your firmware ASAP. 1.01 - very old... bad idea to install this, need to write a script to get out, because it isn't in the revision table. not much works except firmware upgrade. 1.0.2 - works ok in CLI And GUI to view, and upgrade firmware. 1.0.3 - GUI and CLI work OK, can upgrade firmware. Used ntfs3g for a few months under ubuntu 7.10 Linux. Used 2 TB LUN, with 1.5 TB of physical space available. 1.1.0 - dashboard works no issues. - from this point, you don't seem to need to unplug the USB connector to complete the upgrade. - firmware prior to here deals badly with ext3. 1.1.1 - 1.2.4 works without issues. ('name' not supported by firmware) 1.3.0 - works without issues. KNOWN BUGS ---------- droboview isn't suited to run continuously for long periods, as it has a memory leak... total foot print starts out at 32M with a 15 MB resident set size, of which 10 MB are shared, so only about 4M of real memory consumed. but the RSS grows at about 2MB/hour. 29m 11m S 1 2.9 9:44.50 droboview best to restart it daily, or use it when necessary, but not leave it on for days. After you resize luns, droboview gets confused, you need to exit and restart. We have a report that dumping diagnostics does not work over firewire. Work-around: connect via USB. Droboshare Support ------------------ Droboshare is not directly supported by drobo utils running on a linux host. However, the droboshare itself is a linux host, and it is possible to run drobo-utils un-modified on the droboshare itself. In order to do run drobo-utils, you need to build a python interpreter. A python interpreter has, itself, a bunch of dependencies. So you need to install a whack of packages on the droboshare in order to get a working drobo-utils. This is where DARFS comes in. DARFS ===== The Droboshare Augmented Root File System (darfs) is a 60 MB or so download you can get from drobo-utils.sf.net. There isn't any source code, because, well, nothing from any of the packages has been modified. there are instructions on how to build DARFS in DEVELOPERS.html DARFS is a standard droboshare root file system, with some packages added: openssl, openssh, berkeleydb, bzip2, a fairly complete Python 2.6.2. drobo- utils is a python app. and it works in line and API mode, natively, on the droboshare. for example, I've used it to replace the firmware. no problem at all. People un-afraid of the command line can upgrade drobo firmware, query status, and take diagnositc dumps, from the command line on the droboshare itself, just as they would on any linux host computer. But a full GUI would be too much for the little processor and more importantly the limited memory in the droboshare, so that is not provided. DARFS Installation ================== Download it from drobo-utils.sf.net: steps: 1. copy the tar file onto somewhere on your share. 2. log in via DropBear ssh as a root user on the droboshare. 3. cd /mnt/DroboShares/YourDrobo (root of drobo file system, for example) 4. tar -xzf darfs.tgz (root of drobo file system, for example) 5. the root directory of the tar is 'slash'.. it will be under YourDrobo 6. export PATH="/mnt/DroboShares/YourDrobo/slash/usr/bin:${PATH}" (which is where python and drobom are.) 7. drobom status you're done! Enable SFTP Support =================== all you need to do is: ln -s /usr/libexec /mnt/Droboshares/YourDrobo/slash/usr/libexec Try an sftp from another machine (as root...) and it ought to work. (explanation: when one tries to sftp to a droboshare, it gives an error about trying to exec '/usr/libexec/sftp-server'. Openssh builds the right binary, but Dropbear doesn't know where to look for it. the libexec directory isn't there on the droboshare, so there is no harm in creating it and linking into DARFS.) Building Droboshare applications ================================ See DEVELOPERS.txt Droboshare Firmware =================== With DARFS, and the third party software you can get from drobospace and drobo.com, the droboshare is very open and hackable. However, there remains one remaining limitation: There is no open source way to upgrade or modify droboshare firmware. If you want to re-flash to a factory original state, you need the vendor dashboard. Credits ------- who did what:: Peter Silva: wrote most all of it. Chris Atlee: the proper debian packaging. Brad Guillory: some help with diagnostics and patches. Joe Krahn: lots of inspiration. Andy Grover: some elegance cleanups. Administrivia ------------- version 0.6.1, October 6th 2009. copyright: Drobo Utils Copyright (C) 2008,2009 Peter Silva (Peter.A.Silva@gmail.com) Drobo Utils comes with ABSOLUTELY NO WARRANTY; For details type see the file named COPYING in the root of the source directory tree. hoho+repack.orig/drobom.80000644000175000017500000000446711265217256014644 0ustar morphmorph.TH DROBOM 8 October 2008 droboa System Administration Utilities .SH NAME drobom \- CLI for managing drobo units .SH SYNOPSIS .B drobom [ \fIoptions\fR ] \fI \fR[ \fIarguments\fR... ] .SH DESCRIPTION .SS options is one of: .TP \-c, \-\-command the command to execute. .TP \-d, \-\-device the device to operate on (default searches all devices and picks first one found.) .TP \-h, \-\-help print a usage message .TP \-v, \-\-verbose verbosity, a bit-field to trigger increased output as needed, mostly for debugging. 1 - General, 2 - Hardware Dialog, 4 - Initiation, 8 - DMP layer, 16- Detection 64 will print everything... (default: 0, as terse as possible.) 128 enables simulation mode (for testing when no Drobo is available. Dangerous!) .TP \-V, \-\-version print the version id. .SS command is one of: .TP blink identify the drobo by making the lights blink .TP diag dump diagnostics file into /tmp directory .TP diagprint print diagnostics file to standard output .sp .br the diagnostic dump file to print. .TP fwcheck query drobo.com for updates to firmware for the given Drobo fwload load a specific firmware for the given Drobo. Arguments: .sp .br the firmware file to load. .TP fwupgrade upgrade the firmware to the latest and greatest, recommended by DRI .TP help print this text .TP info print information on a Drobo. The argument is a comma separated list of the values below (default is to print all of them): config, capacity, protocol, settings, slots, firmware, status, options, luns .TP list show device files for all Drobos found. .TP name Set the name of the Drobo to the given value ( only firmware > 1.3.0 supports this command ) .TP settime sync Drobo's clock to UTC .TP setlunsize Set the size of LUNS on device. Arguments: .sp integer number of TiB to set the lunsize to .sp Specify 'PleaseEraseMyData' if you really mean it .sp Note: After execution, Drobo reboots, wait a few minutes before accessing again .TP shutdown shutdown drobo (DRI calls this 'standby') .TP status report how is the Drobo doing .SS device raw block device of a drobo (i.e. /dev/sdz) . If not given, assumes all attached drobos. .SH AUTHOR This manual page was written by Chris AtLee for the Debian project (but may be used by others). hoho+repack.orig/droboview0000755000175000017500000000003611265217256015203 0ustar morphmorph#!/bin/sh exec drobom $* view hoho+repack.orig/README.html0000644000175000017500000010170611265220320015070 0ustar morphmorph Drobo Utils README

Drobo Utils README

Drobo-utils is a set of linux tools to query and manage Data Robotics Drobo storage systems. If you fire up droboview, it should look pretty familiar to those who have seen the dashboard on other operating systems. Droboview is built on a little programmer interface which can be installed on the system and used by other applications as well.

For experienced Linux hands, there is a command line interface, drobom, which offers the same functionality as droboview. For real hackers, fire up a python interpreter, 'import Drobo', help(Drobo), and you are off to the races... Command-line access is also bundled into a set of improvements to a standards droboshare called 'Droboshare Augmented Root File System' (DARFS)

INSTALLATION

Drobo utils installation.

REQUIREMENTS

Drobo-utils was developed on pre-release version of Kubuntu (Hardy, Intrepid, and now Jaunty) Any similarly recent distro ought to do.

To get drobo-utils running, you need packages something like (these are ubuntu packages, names may vary on other distros):

essential::

python -- interpreter for python language parted -- partitioner, usually included with the distro.

if using RHEL, which has python 2.4...
python-ctypes -- module for C-interface
for the GUI:
python-qt4 -- the python bindings for version 4 of the QT toolkit

To get a complete list, it is best to use a shell window to grep in the Debian package control file (which defines what the dependencies are for the build system):

peter@pepino% grep Depend debian/control
Build-Depends: debhelper (>= 5), python2.5-dev, python-docutils
Depends: ${shlibs:Depends}, ${misc:Depends}, parted
peter@pepino%

INSTALLING pre-requisites

On ubuntu, it would typically look like so: Open a shell window. Enter the following package installation commands:

% sudo aptitude install python-qt4 parted
% sudo aptitude install debhelper python2.5-dev
% sudo aptitude install python-docutils

If you have received a pre-built binary package,then you only need the first line. If you want to build from source, then you need the second line. The third line install what you need to build documentation.

On redhat/fedora distros, it would more likely be 'yum' instead of 'aptitude' and some of the package names will change. A typical difference is that packages for developers have the -devel suffix on Redhat derived distributions, instead of the -dev favoured by debian derived ones.

here is an example from fedora 7 (courtesy of help4death on the google group):

% yum install python
% yum install PyQt4
% yum install python-devel

NOTE: if X or QT is missing, it will only disable the GUI. Line mode will work without issues. the package should work fine on headless servers using only the command line.

Install From Package

Point your browser at: http://sourceforge.net/project/showfiles.php?group_id=222830 where current packages are available. after downloading a .deb, it is simply a matter of:

dpkg -i drobo-utils-<version>.deb

done!

Install from Source

See DEVELOPER.txt

Try Out the CLI

Assuming you have all of the above parts, in the directory where you downloaded the source, you should be able to invoke the command line interface as follows:

drobom status

see if something sensible happens... on my system with a drobo the following happens:

% sudo drobom status
/dev/sdz /drobo01 100% full ( ['Red alert', 'Bad disk', 'No redundancy'], 0 )
%

Note: drive changed to sdz to avoid copy/paste errors.

very scary, but my drobo is in bad shape right now... you should just get [] as a status, which means there is nothing wrong. To get all kinds of information on your drobo, try 'drobom info.' You can then invoke it with no arguments at all which will cause it to print out a list of the commands available through the command line interface.

Try Out the GUI

Once the command line stuff that is working, and assuming you have python-qt4 installed, try:

% droboview

which should start a GUI for each drobo attached to your machine, that you have permission to access (depends on the setup, usually USB devices on desktops are accessible to users, so you can see them.

Try Out the Python API

See DEVELOPERS.txt

Setup Drobo with Linux

One can use the Format tab of the GUI to partition the device and create a single file system for a given LUN.

NOTE: mke2fs takes a very long time to run, on the order of ten minutes per Terabyte. the display format button just turns red while the format is in progress,and you have to wait until it finishes. Have not determined a method to monitor progress yet. other file systems are much more quickly created, so less of an issue.

I actually prefer to use the system tools manually, as described below:

Drobos with firmware 1.1.1 or later work well under linux with ext3. You can, of course set up an NTFS or HPS+ or FAT32 if you really want, but it seems actively counter-intuitive on Linux. Have not tested HPS, but ntfs-3g worked fine initially. However, unless you are going to physically move the disk to between systems, the native (ext3) format has many advantages. The ´coffee is hot´ disclaimer is necessary at this point:

WARNING: THE FOLLOWING 4 LINES WILL ERASE ALL DATA ON YOUR DROBO!
WARNING: NO, IT WILL NOT ASK ANY QUESTIONS!
WARNING: ASK YOURSELF, before you start: ARE YOU SURE?
WARNING: AFTER THE SECOND LINE, YOU ARE TOAST.
WARNING: BEST TO BACKUP YOUR DATA BEFOREHAND...

If you didn't use the GUI, Here is what you have to type:

# drobom -d /dev/sdz format ext3 PleaseEraseMyData
You asked nicely, so I will format ext3 as you requested
if you are really sure, go ahead and do: sh /tmp/fmtscript

# cat /tmp/fmtscript
#!/bin/sh
parted /dev/sdz mklabel gpt
parted /dev/sdz mkpart ext2 0 100%
parted /dev/sdz print; sleep 5
mke2fs -j -i 262144 -L Drobo01 -m 0 -O sparse_super,^resize_inode /dev/sdz1

The above sets up the drobo as one big partition, with a label that says it ought to contain an ext2 file system. If you want an NTFS file system, then write ´ntfs´ in place of ext2. The next step is to add the file system into the partition. while parted's are instantaneous, the mke2fs takes a while, just have a little patience, it´ll be fine.

sh -x /tmp/fmtscript

(If you want an ntfs file system, then mkntfs -f -L Drobo01 /dev/sdz1 ought to work too... )

On my system the process looked like this:

root@alu:~# parted -i /dev/sdz
GNU Parted 1.7.1
Using /dev/sdz
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) mklabel gpt
(parted) mkpart ext2 0 100%
(parted) quit
root@alu:~# fdisk /dev/sdz
GNU Fdisk 1.0
Copyright (C) 1998 - 2006 Free Software Foundation, Inc.
This program is free software, covered by the GNU General Public License.

This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.  See the GNU General Public License for more details.

Using /dev/sdz
Command (m for help): p

Disk /dev/sdz: 2199 GB, 2199020382720 bytes
255 heads, 63 sectors/track, 267349 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

   Device Boot      Start         End      Blocks   Id  System
/dev/sdz1               1      267350  2147488843   83  Linux
Command (m for help): q
root@alu:~# mke2fs -j -i 262144 -L Drobo01 -m 0 -O sparse_super,^resize_inode /dev/sdz1
mke2fs 1.40.8 (13-Mar-2008)
Filesystem label=Drobo01
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
8388608 inodes, 536870886 blocks
0 blocks (0.00%) reserved for the super user
First data block=0
16384 block groups
32768 blocks per group, 32768 fragments per group
512 inodes per group
Superblock backups stored on blocks:
        32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
        4096000, 7962624, 11239424, 20480000, 23887872, 71663616, 78675968,
        102400000, 214990848, 512000000

Writing inode tables: done
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done

This filesystem will be automatically checked every 26 mounts or
180 days, whichever comes first.  Use tune2fs -c or -i to override.
root@alu:~#
root@alu:~# mount /dev/sdz1 /mnt

Getting Source

See DEVELOPERS.txt

Multiple LUNS

LUN is an abbreviation of 'Logical UNit'. The origin of the term is SCSI terminology. When RAID units became too large for support in the past, and were sub-divided to present smaller units the operating system. The default LUNSIZE on Drobos is 2 TiB (adjustable using the tools.) If more disk space (after allowing for parity/redundancy) than LUNSIZE is installed in a unit, Drobo will show a second (or even third) LUN. Each LUN shows up in Linux as a separate disk (examples if the first LUN shows up as /dev/sde, the next will be /dev/sdf, then /dev/sdg.)

If you think you should see multiple LUNS and you don't, you might have a look at some kernel settings: make sure that scsi_mod kernel module is loaded, make sure /sys/module/scsi_mod/parameters/max_luns is > 1.

Droboview will start up one GUI per drobo, regardless of the number of LUNS. If asked to format, all LUNS for the device will be formatted.

ON LUNSIZES >= 2TB:
-- On older distributions, there are a couple of gotchas related to
linux tools which aren't 2TB ready... to exceed 2 TB, you need to:
-- use GPT partitions, which aren´t supported by older fdisk
versions. Tools based on libparted work fine, mostly.
-- gparted fails, and seems to have a 1 TB limit on devices.
(bug #524948 reported to bugzilla.gnome.org) It's just the GUI, as libparted is fine, and other tools based on it still work.
-- on linux kernel < 2.6.24 supposedly, the USB layer won't let one address
LUNs/offsets > 2 TB. For example, Ubuntu hardy (8.04) released in Spring 2008 has a 2.6.24, and so is OK. I've never been able to test this problem.
-- ext3 with 4K blocks is supposed to allow file system capacity of 8 TiB.
4K blocks seem to be assigned by default. So I think a good max. It would be fun to set the LunSIZE to 8 TiB and test it out...

Drobo Pro

Drobo-utils depends on the linux generic scsi layer. I suspect that there is just a basic ethernet connection now, and you a few additional driver layers set up before it will work. You need to configure the iscsi driver to recognize the device. Lemonizer on the Google Group 2009/05/16 reported good luck with:

I had to manually configure the ip of the dbpro from the Drobo Dashboard on my macbook to do this as I'm not sure how to get the portal ip for iscsiadm. In my case it was 192.168.2.80 port 3260 and I'll use that ip in the example below

  1. Configure iscsi ip address via drobo dashboard on win/osx
  2. Install open-iscsi (http://www.open-iscsi.org/): sudo apt-get install open-iscsi
  3. Connect the dbpro to host machine via iscsi
  4. Query dbpro's id: sudo iscsiadm --mode discovery --type sendtargets --portal 192.168.2.80
  5. Copy the id string returned by iscsiadm, something like "iqn.2005-06.com.datarobotics:drobopro.tdb091840080.node0"
  6. Connect to the dbpro: sudo iscsiadm --mode node --targetname iqn.2005-06.com.datarobotics:drobopro.tdb091840080.node0 --portal 192.168.2.80:3260 --login

If everything went well, your dbpro should show up under /dev. Also check /var/log/messages to confirm that the iscsi device connected successfully.

After that, drobo-utils should be able to detect the Drobo and manage it over ethernet.

(source: http://groups.google.com/group/drobo-talk/browse_frm/thread/453e02e105e9b41?hl=en )

Some people reported data corruption. This link claims to fix one such issue: http://www.drobospace.com/forum/thread/13951/Dropped-iSCSI-connections/?page=2#24792

Drobo Firmware

Upgrading firmware is pretty self-explanatory in the GUI. the first time you press the Update button, it checks to see if a new firmware is available. If it there is newer firmware, it offer to upgrade, with suitable prompts. Similarly, the line mode interface has two commands to deal with firmware, fwcheck will tell you if an upgrade is required. the fwupgrade will do the job. It takes a few minutes, and prints a status you you can see how it is progressing. Have patience:

root@pepino:/home/peter/drobo/drobo-utils/trunk# drobom fwupgrade

validateFirmware start...
Magic number validated. Good.
484 + 2937552 = 2938036 length validated. Good.
CRC from header: 4260378881, calculated using python zlib crc32: 398201869
yeah, the header CRCs do not match. For now they never do ... ignoring it.
CRC for body from header: 1852877921, calculated: 1852877921
32 bit Cyclic Redundancy Check correct. Good.
validateFirmware successful...
writeFirmware: i=484, start=484, last=2938036 fw length= 488
.
wrote  32768  bytes... total: 33252
wrote  32768  bytes... total: 66020
.
.
.
wrote  32768  bytes... total: 2720228
wrote  32768  bytes... total: 2752996
wrote  32768  bytes... total: 2785764
wrote  32768  bytes... total: 2818532
wrote  32768  bytes... total: 2851300
wrote  32768  bytes... total: 2884068
wrote  32768  bytes... total: 2916836
wrote  21200  bytes... total: 2938036
writeFirmware Done.  i=2938036, len=2938036
root@pepino:/home/peter/drobo/drobo-utils/trunk#

when it's done, you can check if it worked using:

root@pepino# drobom status
/dev/sdf - 00% full - (['New firmware installed'], 0)

If the status is like that, then do:

root@pepino:/home/peter/drobo/drobo-utils/trunk# drobom shutdown

lights will flash etc... wait until Drobo goes dark. Wait another five seconds, then un-plug the USB / connector.

Plug it back in, and wait 10 seconds. it should start up with the latest firmware available for your drobo.

The drobom commands, like DRI's dashboard, will normally get the latest and greatest firmware and upgrade. If you have the need, you can load arbitrary firmware from the CLI with fwload command.

SAFETY

Those worried about safety of using this software should know: it was developed with assistance from the vendor (Data Robotics Inc.), and in every case, based on vendor documentation, and with at least encouragement, if not outright support. For each release, a QA.txt file is built, demonstrating the functionality tests run. There are multiple checksum verifications built into the firmware upgrade process, so it is next to impossible to brick a drobo using the tools. Drobo-utils verifies firmware checksums before attempting to upload the image to the device, and the device checks the firmware against the checksums as well. New firmware is loaded into an alternate location from the currently active one, and if activation of the new firmware fails, the drobo will simply boot the old one.

On the other hand, common sense rules do apply. Setting the LUN size, or re-formatting a Drobo will erase all your data whether you do it on Linux or any other operating system. These are power tools, and they can do some damage to your data if used without proper care. For example, the reliability of any storage unit does not reduce the need for backups it only makes doing them easier. A Drobo is an excellent place to put backups, but not a substitute for them. Backups are the only way to address error 18 (the number of inches in front of the keyboard the source of the issue lies.) and no storage unit can protect against fire or flood.

Compatibility

Drobo has been tested with every old firmware version. Any Drobo should be upgradable to modern firmware using the dashboard.

NOTE: really need at least 1.1.1 to use Linux & ext3.
just use the tools to upgrade your firmware ASAP.
1.01 - very old... bad idea to install this, need to write
a script to get out, because it isn't in the revision table. not much works except firmware upgrade.

1.0.2 - works ok in CLI And GUI to view, and upgrade firmware.

1.0.3 - GUI and CLI work OK, can upgrade firmware.
Used ntfs3g for a few months under ubuntu 7.10 Linux. Used 2 TB LUN, with 1.5 TB of physical space available.
1.1.0 - dashboard works no issues.
  • from this point, you don't seem to need to unplug the USB connector to complete the upgrade.
  • firmware prior to here deals badly with ext3.
1.1.1 - 1.2.4 works without issues.
('name' not supported by firmware)

1.3.0 - works without issues.

KNOWN BUGS

droboview isn't suited to run continuously for long periods, as it has a memory leak... total foot print starts out at 32M with a 15 MB resident set size, of which 10 MB are shared, so only about 4M of real memory consumed. but the RSS grows at about 2MB/hour.

29m 11m S 1 2.9 9:44.50 droboview

best to restart it daily, or use it when necessary, but not leave it on for days.

After you resize luns, droboview gets confused, you need to exit and restart.

We have a report that dumping diagnostics does not work over firewire. Work-around: connect via USB.

Droboshare Support

Droboshare is not directly supported by drobo utils running on a linux host. However, the droboshare itself is a linux host, and it is possible to run drobo-utils un-modified on the droboshare itself. In order to do run drobo-utils, you need to build a python interpreter. A python interpreter has, itself, a bunch of dependencies. So you need to install a whack of packages on the droboshare in order to get a working drobo-utils. This is where DARFS comes in.

DARFS

The Droboshare Augmented Root File System (darfs) is a 60 MB or so download you can get from drobo-utils.sf.net. There isn't any source code, because, well, nothing from any of the packages has been modified. there are instructions on how to build DARFS in DEVELOPERS.html

DARFS is a standard droboshare root file system, with some packages added: openssl, openssh, berkeleydb, bzip2, a fairly complete Python 2.6.2. drobo- utils is a python app. and it works in line and API mode, natively, on the droboshare. for example, I've used it to replace the firmware. no problem at all.

People un-afraid of the command line can upgrade drobo firmware, query status, and take diagnositc dumps, from the command line on the droboshare itself, just as they would on any linux host computer. But a full GUI would be too much for the little processor and more importantly the limited memory in the droboshare, so that is not provided.

DARFS Installation

Download it from drobo-utils.sf.net: steps:

  1. copy the tar file onto somewhere on your share.
  2. log in via DropBear ssh as a root user on the droboshare.
  3. cd /mnt/DroboShares/YourDrobo (root of drobo file system, for example)
  4. tar -xzf darfs.tgz (root of drobo file system, for example)
  5. the root directory of the tar is 'slash'.. it will be under YourDrobo
  6. export PATH="/mnt/DroboShares/YourDrobo/slash/usr/bin:${PATH}" (which is where python and drobom are.)
  7. drobom status

you're done!

Enable SFTP Support

all you need to do is:

ln -s /usr/libexec /mnt/Droboshares/YourDrobo/slash/usr/libexec

Try an sftp from another machine (as root...) and it ought to work.

(explanation: when one tries to sftp to a droboshare, it gives an error about trying to exec '/usr/libexec/sftp-server'. Openssh builds the right binary, but Dropbear doesn't know where to look for it. the libexec directory isn't there on the droboshare, so there is no harm in creating it and linking into DARFS.)

Droboshare Firmware

With DARFS, and the third party software you can get from drobospace and drobo.com, the droboshare is very open and hackable. However, there remains one remaining limitation: There is no open source way to upgrade or modify droboshare firmware. If you want to re-flash to a factory original state, you need the vendor dashboard.

Credits

who did what:

Peter Silva:    wrote most all of it.
Chris Atlee:    the proper debian packaging.
Brad Guillory:  some help with diagnostics and patches.
Joe Krahn:      lots of inspiration.
Andy Grover:    some elegance cleanups.

Administrivia

version 0.6.1, October 6th 2009.

copyright:

Drobo Utils Copyright (C) 2008,2009 Peter Silva (Peter.A.Silva@gmail.com) Drobo Utils comes with ABSOLUTELY NO WARRANTY; For details type see the file named COPYING in the root of the source directory tree.

hoho+repack.orig/make_tarball.sh0000755000175000017500000000042011265217256016227 0ustar morphmorph#!/bin/bash version=$(python setup.py --version) mkdir ../drobo-utils-$version cp -a * ../drobo-utils-$version cd .. tar zcf drobo-utils_$version.orig.tar.gz --exclude debian --exclude .git --exclude *.pyc --exclude build* drobo-utils-$version rm -rf drobo-utils-$version hoho+repack.orig/QA.txt0000644000175000017500000000317111265217256014322 0ustar morphmorphQA Test checklist prior to release: 1.0 Review Documentation -- Revision dates in index.html, README.txt, TODO.txt -- Set version to pre-release one. -- build packages with pre-release version id. 1.1 drobom status... check for accuracy. sudo drobom status /dev/sdf - Drobo disk pack 00% full - ([], 0) peter@pepino:~/drobo/drobo-utils/drobo-utils-0.6.1$ 1.2 drobom settime yup. 1.3 drobom status... check for accuracy. yup. 1.4 drobom fwload (something really old) 1.03 yup. 1.4.1 drobom shutdown -- to run the firmware. yup. 1.4.2 restart (unplug and replug usb) yup. 1.4.3 run drobom status etc.. (make sure it is running 1.0.3) should say disk pack is un-readable or some such. yup. 1.4.4 hard reset to factory default after downgrade, disk pack will no longer be recognized. need to reset to make Drobo look at the disks. (with the pin in the back and all that.) http://www.drobospace.com/article/10207/Resetting-the-Drobo/?highlight=reset+drobo yup. 1.4.3 place a file on the Drobo. make sure it works. 1.4.4 drobom status -- have a look. 1.5 drobom fwupgrade 1.5.1 drobom shutdown - to run the firmware. 1.5.2 drobom status -- have a look. 1.5.3 repeat 1.5 perhaps a second time (as needed to get to current) 1.7 drobom setlunsize 3 (should fail),1,2 1.8 drobom create file systems, each type. msdos ntfs ext3 .... 1.9 drobom diags # verify that dumping diagnostics still works... 2.0 with fw >= 1.30 drobom name drobom info... 3.0 Re-build packages with final release id. hoho+repack.orig/drobom0000755000175000017500000002465511265223407014475 0ustar morphmorph#!/usr/bin/python import sys import Drobo import time import getopt import string import os import types import textwrap toprint = ("config", "capacity", "protocol", "settings", "slots", "firmware", "status", "options", "luns") def usage(): print "\nUsage: drobom [options] [ arguments... ] \n" print " drobo management interface, version: %s\n" % Drobo.VERSION print "options may be one of: " print " -c, --command \tcommand to run." print " -d, --device \tpick a specific disk, rather than scan" print " -h, --help \t\tprint this help text" print " -v, --verbose \t bit-field, default is 0 (off) " print "\t1 - General" print "\t2 - Hardware Dialog" print "\t4 - Initiation" print "\t8 - DMP layer" print "\t16 - Detection" print "\t63 - All of the above" print "\t128- Simulate presence of Drobo for testing\n" print " -V, --version\treport version of drobo-utils." print "\ncommand is one of: " print "\tblink\tidentify the drobo by making the lights blink" print "\tdiag \tdump diagnostics file into /tmp directory" print "\tdiagprint - print diagnostic file to stdout" print "\tformat\tPrepares a script to format LUNS from a device. Arguments:" print "\t\t\tfile system type. One of: ext3, ntfs, FAT32" print "\t\t\tSpecify 'PleaseEraseMyData' if you" print "\t\t\t\treally mean it" print "\t\tNote: This places a script in /tmp, which you must run." print "\tfwcheck\tquery drobo.com for updates to firmware for the given Drobo" print "\tfwload\tload a specific firmware for the given Drobo. Arguments:" print "\t\t\tthe firmware file to load." print "\tfwupgrade\tupgrade the firmware to the latest and greatest," print "\t\t\trecommended by DRI" print "\tinfo \tprint information on a Drobo" print "\t\t\tcomma separated list of:" opt_str = ', '.join(toprint) for line in textwrap.wrap(opt_str, 40): print "\t\t\t\t" + line print "\tlist \tshow device files for all Drobos found." print "\tname \tSet Drobo name" print "\tsettime\tsync Drobo's clock to UTC" print "\tsetlunsize\tSet the size of LUNS on device. Arguments:" print "\t\t\tinteger number of TiB to set the lunsize to" print "\t\t\tSpecify 'PleaseEraseMyData' if you" print "\t\t\t\treally mean it" print "\t\tNote: After execution, Drobo reboots, wait a few minutes" print "\t\t\tbefore accessing again" print "\tshutdown\tShutdown drobo" print "\t\t\t(DRI calls this 'standby'. Shutdown also umounts.)" print "\tstatus\treport how is the Drobo doing" print "\tview\tstart up a management dashboard GUI" def printconfig(d): config=d.GetSubPageConfig() if Drobo.DEBUG & Drobo.DBG_Chatty: print 'query config result: ' print config print 'max lun size is: ', config[2] print else: print config def printcapacity(d): c=d.GetSubPageCapacity() if Drobo.DEBUG & Drobo.DBG_Chatty: print 'query capacity result:' print c print 'Physical space... used: ', c[1] , ' free: ' , c[0], ' Total: ', c[2] print else: print c def printprotocol(d): protocol=d.GetSubPageProtocol() if Drobo.DEBUG & Drobo.DBG_Chatty: print 'query protocol version result: ' print protocol print else: print protocol def printsettings(d): settings=d.GetSubPageSettings() if Drobo.DEBUG & Drobo.DBG_Chatty: print 'query settings result:' print settings print 'Drobo time is', time.ctime(settings[0]) print else: print settings def printslots(d): slotinfo=d.GetSubPageSlotInfo() if Drobo.DEBUG & Drobo.DBG_Chatty: print 'query slotinfo result: number of slots:', d.slot_count print slotinfo def printfirmware(d): firmware=d.GetSubPageFirmware() if Drobo.DEBUG & Drobo.DBG_Chatty: print 'query firmware result:' print firmware print 'drobo says firmware revision: ', str(firmware[0]), '.', str(firmware[1]), '(', str(firmware[2]), ') was built: ', firmware[5] print else: print firmware def printstatus(d): status=d.GetSubPageStatus() if Drobo.DEBUG & Drobo.DBG_Chatty: print 'query status result:' print status print else: print status def printoptions(d): options=d.GetSubPageOptions() if Drobo.DEBUG & Drobo.DBG_Chatty: print 'query options result:' print options else: print options def printluns(d): luninfo=d.GetSubPageLUNs() if Drobo.DEBUG & Drobo.DBG_Chatty: print 'query luninfo result:' for i in luninfo: print i print else: for i in luninfo: print i def info(d,choices): if debug & Drobo.DBG_Chatty: print '---------------------------------------------------------' print 'Info about Drobo ' , print ' Name:', d.GetSubPageSettings()[2], print ' Devices:', ':'.join(d.char_devs) print '---------------------------------------------------------' for c in choices: eval( "print" + c + "(d)" ) if debug & Drobo.DBG_Chatty: print '---------------------------------------------------------' def update(pct): print "write is %2d%% done." % ( pct ) # Mainline... if ( len(sys.argv) == 1 ) or (sys.argv[1] == 'help'): usage() sys.exit() device=None cmd=None #default is chatty debug=1 try: opts, args = getopt.getopt(sys.argv[1:], "c:d:hv:V", \ ["command=", "device=", "help", "verbosity=", "version"]) except getopt.GetoptError, err: usage() sys.exit(2) for o, a in opts: if o in ("-c", "--command"): cmd = a elif o in ("-d", "--device"): device=a elif o in ("-h", "--help"): usage() sys.exit() elif o in ("-v", "--verbosity", "--verbose") : debug = int(a) elif o in ("-V", "--version" ): print Drobo.VERSION sys.exit() else: assert False, "unhandled option" if cmd==None : if (len(args) == 0): usage() sys.exit() cmd=args[0] if (os.geteuid() != 0) and (debug & Drobo.DBG_Simulation == 0): print "Please try again as root." sys.exit() l = Drobo.DiscoverLUNs(debug) if not l: print "No Drobos discovered" sys.exit() # find the requested Drobo... match=False if device != None: for i in l: if type(i) == types.ListType: for j in i: if device in j: l=[i] match=True elif device in i: l=[i] match=True if device != None and not match: print "given device: %s, is not a Drobo" % d sys.exit() if cmd == 'list': print ' '.join(map(lambda x: ':'.join(x) , l )) sys.exit() if debug & Drobo.DBG_Detection: print "found ", l for u in l: d=Drobo.Drobo(u,debug) #assert d is a valid drobo object... if cmd == "blink": d.Blink() elif cmd == "diag": f=d.dumpDiagnostics() print "diagnostics in ", f elif cmd == "diagprint": print d.decodeDiagnostics( args[1] ) elif cmd == "format": if len(args) < 3 : print 'This is guaranteed to erase your disk, so you must say: PleaseEraseMyData' sys.exit() if args[2] != 'PleaseEraseMyData': print 'This is guaranteed to erase your disk, so you must say: PleaseEraseMyData' sys.exit() print 'You asked nicely, so I will format %s as you requested' % args[1] d.format_script(args[1]) print 'OK, I built the script but nothing is erased yet...' print 'If you are really sure, go ahead and do: sh /tmp/fmtscript' elif cmd == 'fwcheck': tuple=d.PickLatestFirmware() print tuple[3] elif cmd == 'fwload': if d.PickFirmware(args[1]): d.writeFirmware(update) d.Sync() elif cmd == 'fwupgrade': if d.updateFirmwareRepository(): d.writeFirmware(update) d.Sync() elif cmd == 'info': if len(args) > 1: toprint=args[1].split(',') info(d,toprint) elif cmd == "name": d.Sync(args[1]) elif cmd == "setlunsize": lunsize=int(args[1]) if lunsize not in (1, 2, 4, 8, 16): print 'lun size needs to be 1, 2, 4, 8, or 16 TiB; %d is invalid' % lunsize sys.exit() if lunsize > 2: print 'WARNING: lun size > 2 TiB known not work in many cases under Linux' if len(args) < 3 : print 'This is guaranteed to erase your disk, so you must say: PleaseEraseMyData' sys.exit() if args[2] != 'PleaseEraseMyData': print 'This is guaranteed to erase your disk, so you must say: PleaseEraseMyData' sys.exit() print 'You asked nicely, so I will set the lunsize to %d as you requested' % lunsize d.SetLunSize(lunsize) print 'Done... Drobo is likely now rebooting. In a few minutes, it will come back with the new LUN size.' elif cmd == "set": what = args[1] if what == "time" : d.Sync() else: options=d.GetSubPageOptions() if args[1] in options.keys(): # TODO: are all options integers? no.. if args[2] == 'True': value=True elif args[2] == 'False': value=False elif args[1] == 'IPAddress' or args[1] == 'NetMask': value=args[2] else: value=int(args[2]) options[args[1]]=value else: print 'option not present: ', args[1] d.SetOptions( options ) elif cmd == "settime": d.Sync() elif cmd == "shutdown": d.Standby() elif cmd == "status": c=d.GetSubPageCapacity() n=d.GetSubPageSettings() if c[2] > 0 : pfull = 100 * ((c[1]+1.0)/c[2]) else: print "firmware too old to report capacity properly... or the drobo is empty..." pfull = -1 m=':'.join(d.DiscoverMounts()) if m == "": m="-" if n[2] == "": n[2] = "-" print "%s %s %s %02d%% full - %s" % ( ':'.join(d.char_devs), m, n[2], \ pfull, d.GetSubPageStatus() ) elif cmd == "time": settings=d.GetSubPageSettings() print "Drobo says it is:", time.ctime(settings[0]) elif cmd == "view": import sys,subprocess try: from PyQt4 import QtGui from PyQt4 import QtCore from DroboGUI import DroboGUI except: print "QT support missing, no GUI possible" # fire up a GUI for the given LUN, stays foreground... app = QtGui.QApplication(sys.argv) tb = DroboGUI(d) tb.show() app.exec_() else: usage() print "Unknown Command: ", cmd hoho+repack.orig/.gitignore0000644000175000017500000000040511265217256015245 0ustar morphmorph*.pyc CHANGES.html DEVELOPERS.html README.html build-stamp build/ debian/drobo-utils.debhelper.log debian/drobo-utils.postinst.debhelper debian/drobo-utils.prerm.debhelper debian/drobo-utils.substvars debian/drobo-utils/ debian/files drobom.html droboview.html hoho+repack.orig/DEVELOPERS.html0000644000175000017500000005075611265220320015613 0ustar morphmorph DEVELOPERS NOTES

DEVELOPERS NOTES

This software is copyright under GPL. See near end file for details...

Random useful bits for developers. (aka notes to myself ;-)

Working With Source

Project Source code is managed using a git repository provided by sourceforge.net. Git ( http://git-scm.com/ ) provides a fully distributed development model, so one can exchange patches arbitrarily among developers. On the sf.net repository, the 'master' branch is the final integration target for future releases.

Getting a Source Tree

the following checks out the master branch of the source code tree and puts it in the drobo-utils subdirectory of the current tree.

git clone ssh://peter_silva@drobo-utils.git.sourceforge.net/gitroot/drobo-utils/drobo-utils drobo-utils

Before doing Any commits, ensure that the author fields are appropriately set.

One can obtain patches applied to the branch with git pull, and commit patches for distribution with git push.

GIT Configure Patch Author

To ensure the correct author on patches created, make sure to set your author settings. Something like the following is appropriate if you use a single identity for all your code contributions.

boule% git config --global user.name "firstname lastname" boule% git config --global user.email "developer@sourceforge.net" boule%

Others may wish for the identity to be associated with each project.

Using a Source Snapshot

Sometimes, when there are issues, the correction gets checked in, but there hasn't been time to do a full release process. If you really need the fix, then your only option is to get it from the developers' git repository. If you are told 'it is in git', that refers to the git source code management system, and the server for that is at sourceforge.net. How to get it:

# git clone ssh://developer@drobo-utils.git.sourceforge.net/gitroot/drobo-utils/drobo-utils mine
# cd mine                 # go into the source directory you downloaded
# ./drobom status         # try it out...
# python setup.py install # install it in system places...
# drobom status           # try it out...
# git pull # get any changes made since the git clone was done.
# python setup.py install # install the changes in system places.

Sample checkout of a stable version. To view available branches:

% git branch -r
origin/HEAD -> origin/master
origin/master
origin/noC
origin/peter
origin/r0.2.1
origin/r0_3_3
origin/r0_4_0
origin/r0_5_0
origin/r0_6_0

Where a version is something like r0_4_0. then you can pick anyone to work with:

% git branch r0_4_0 -r origin/r0_4_0
Branch r0_4_0 set up to track remote branch r0_4_0 from origin.
% git checkout r0_4_0
Switched to branch 'r0_4_0'
%

When you use git to get a tree, it keeps copies of metadata to be able to track changes. If you want a copy that is contains no git cruft, rm -rf .git in the root of the source tree.

If you are mixing downloaded packages and source installs, check out the next section for gotchas.

Dpkg vs. Python Install

The 'setup.py' script, mentioned in the previous section, is a convention from the distutils python packaging system. distutils installation is slightly different from installation from debian packages. There doesn't seem to be a distutils way to remove a package. touch all the files, do an installation, then manually remove the files it installed.

drobo-utils has been picked up for inclusion in debian. The "real" packaging for debian packages is kept in a separate tree, and maintained by debian developers.

The debian/ setup puts stuff in /usr/sbin while setup.py puts things in /usr/bin. Python install does not install man pages either, which the dpkg takes care of. The libs are placed differently too. haven't reviewed for other conflicts, least confusing to use one or the other method on a system.

(if you do distutils install, then remove the debian package via: dpkg --purge drobo-utils)

Making a Release

1 - make a branch
# assuming you have a local repository... git branch <branch> # creates the branch, from the cwd (ought to be master) git checkout <branch> # switches current dir to the branch.
2 - Stamp the branch with version
vi CHANGES.txt # complete change manifest for release vi debian/changelog # copy manifest from txt, add signature. vi setup.py # edit version vi Drobo.py # edit VERSION

3 - Build packages for testing & Install them. (see separate recipe.)

4 - Run QA.
Record results of release tests in the branch (QA.txt) As new tests are created, modify QA.txt on trunk for to keep references for the next release.

Quality Assurance (QA.txt)

QA.txt is a quality assurance log. The version on the trunk of the releases indicates the QA procedure to be applied to the next version during the release process. Since a branch is created for each release, the version of QA.txt acts as a quality log for that release. so one can do an git checkout, or git export to get the quality log for any release (QA.txt introduce in version 0.4.0)

Building Debian & Ubuntu Packages

Assumes you have installed the Build dependencies:

# obtain a fresh tree
% git clone ssh://peter_silva@drobo-utils.git.sourceforge.net/gitroot/drobo-utils/<version> drobo-utils-<version>
% cd drobo-utils-<version>
% rm -rf .git  # get rid of Git cruft, yielding a raw source tree.
% chmod 755 debian/rules  # I dunno why the permissions are wrong...

# this debian/ config is just for non-distro packages.
# builds for debian and Ubuntu.

% dpkg-buildpackage -rfakeroot
% cd ..
# rename it for whatever distro is appropriate...
% mv drobo_utils_0.3.3-1_i386 --> droboutils_0.3.3-1_i386_ubunutuIntrepid.deb

# rebuild the source tar because it will have the 'debian' link in it.
% cd drobo-utils-0.99.9
% rm debian
% cd ..
% tar -czvf drobo-utils-0.3.3-1.tgz drobo-utils-0.99.9

apply QA tests. as per QA.txt recording results there.

Updating Documentation

use the restructured text tools (from the python-docutils package.) to build things using:

% make doc

Have a look at Makefile for how that works. update the web site:

% scp README.html <user>,drobo-utils@web.sourceforge.net:htdocs

Droboshare

Droboshare is not directly supported by drobo utils running on a linux host. However, the droboshare itself is a linux host, and it is possible to run drobo-utils un-modified on the droboshare itself. There is download called the Droboshare Augmented Root File system (DARFS), which includes a python interpreter and drobo-utils.

Open Task: Reverse Engineer Dashboard <-> Droboshare Protocol

Why isn't there full support in host based drobo-utils itself? Digital Robotics hasn't released details of the protocol used by the proprietary dashboard to communicate with a droboshare, so it would be a lot of work to reverse engineer that. So support of a droboshare from a linux GUI on a host system is not likely in the near future.

If someone wants to figure that out, it might be a good thing (tm) After that is figured out, the next step would be to understand how to flash the firmware remotely. That would eliminate the last function that cannot be done with open source.

Building DARFS

DARFS - Droboshare Augmented Root File System. A pile of stuff that can be run on a droboshare.

Have a look here:

http://groups.google.com/group/drobo-talk/web/building-droboshare-apps-on-debianish-os?hl=en

TODO

Tasks which would be cool to get done, in no particular order:

Option setting... especially for DroboPro IP Address & netmask.

CentOS support. Fedora is likely fine, but should build a VM with CentOS on it, and build an rpm. RHEL has an ancient python (2.4?) with no ctypes by default, so could be interesting.

GUI - handle when Drobo disappears...

Refuse known non-working feature bits... firmware (review 2009 SDK release)
Review feature bits, mis-marked? 28
Add Alerting to GUI & CLI
-- save config... .. SMTP forwarder: .. address .. authentication.? u+p ..
Droboshare bugs
-- don't dump diags to /tmp, they don't fit. -- don't
BUGS:
when running two fw uploads, the second one will not run easily. need to wait for transaction to timeout... perhaps randomize id? did randomization, did not change anything...
STANDARD menu entries for droboview...
partition types do not appear to be correctly displayed...
some confusion between NTFS vs. EXT3 no obvious ill effect.

partition type should pre-select in Format dialog...

memory consumption on the GUI. still chews up 4 MB per hour...

gnats:
man page does not document output. -- what is the meaning of the output? provide a sample...
review print statements:
should they write to stderr?

STANDARD menu entries for droboview...

Better STATUS progress reporting:
-- the block count is there, but heuristics for determining timing suck. -- some sort of indicator of how long 'relay out' will be in progress. -- when it is busy, it should say so... like when I emptied an ntfs it took hours for the led indicators to drop from 70% to 0. It should say something about what is going on.
LIVELIER GUI:
-- have status queries proceed asynchronously from the GUI.
right now, if the drobo is slow, the GUI makes it slower, and gets very slow too. should run as a daemon, async. from the GUI.
Re-design the whole darn thing.

-- there should be some sort of service integrated with dbus-hal -- not sure that a GUI is needed at all. but if it is, it should be a DBUS client. -- how does authentication work in DBUS?

of interest: -- python bindings for parted... http://dcantrel.fedorapeople.org/pyparted/

Revision date: 2009/05/19

copyright:

Drobo Utils Copyright (C) 2008,2009 Peter Silva (Peter.A.Silva@gmail.com) Drobo Utils comes with ABSOLUTELY NO WARRANTY; For details type see the file named COPYING in the root of the source directory tree.

Administrivia

version 0.6.1, October 6th 2009.

copyright:

Drobo Utils Copyright (C) 2008 Peter Silva (Peter.A.Silva@gmail.com) Drobo Utils comes with ABSOLUTELY NO WARRANTY; For details type see the file named COPYING in the root of the source directory tree.