From: Ian Jackson Date: Sat, 16 Sep 2023 10:51:52 +0000 (+0100) Subject: Add 'diziet-utils/' from commit 'd070a0324f10f76f9c97d8f56f864f0cafa88cf1' X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=381c986cf1e86167177d22cef626bc027ab39ab0;hp=d070a0324f10f76f9c97d8f56f864f0cafa88cf1;p=reprap-play.git Add 'diziet-utils/' from commit 'd070a0324f10f76f9c97d8f56f864f0cafa88cf1' git-subtree-dir: diziet-utils git-subtree-mainline: 3d11c1da2508c1a2bd4a1d1272f92b732444b361 git-subtree-split: d070a0324f10f76f9c97d8f56f864f0cafa88cf1 --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f328663 --- /dev/null +++ b/.gitignore @@ -0,0 +1,40 @@ +*~ +*.gcode +light-bracket.stl +*.aside +*.stl +*,*.auto.scad +.*.d +*.tmp +*.fig.bak +funcs.scad +nutbox.scad +powerbank-anker-10000.dxf* +knifeblock-knives-*.dxf* +pandemic-counter-l*.dxf +pandemic-counter-l*.eps +pandemic-quarantine-l*.dxf +pandemic-quarantine-l*.eps +screw-recess-test-number-s*.* +question-question.dxf +question-question.eps +lemon-stand.scad +electron-token.scad +commitid.scad +commitid-best-test.scad +filamentspool-number-n*.dxf +filamentspool-number-n*.eps +sealing-box.scad +sewing-table.scad +maglite-holder-torch-curve.dxf +maglite-holder-torch-curve.eps +sewing-table-rear-profile.dxf +sewing-table-rear-profile.eps +sewing-table-front-profile.dxf +sewing-table-front-profile.eps +sewing-table-end-profile.dxf +sewing-table-end-profile.eps +sewing-table,Demo-flat.png +poster-tube-lid-parametric.scad +treefoil.scad +quacks-L*.auto.ini diff --git a/35mmjack-dummy.scad b/35mmjack-dummy.scad new file mode 100644 index 0000000..1a675a5 --- /dev/null +++ b/35mmjack-dummy.scad @@ -0,0 +1,32 @@ +// -*- C -*- + +p2 = [ 0, 3.0 /2 ]; +p1 = p2 + [ -1.0, -1.0 ]; +p3 = [ 3.0, 2.5 /2 ]; +p4 = [ p3[0] + (3.2-2.5)/2 , 3.2 /2 ]; +p8 = [ 13.0, 8.0 /2 ]; +p5 = [ p8[0] - 8.5, 3.2 /2 ]; +p6 = [ p5[0] + (3.5-3.2)/2, 3.5 /2]; +p7 = [ p8[0], p6[1] ]; +p9 = p8 + [ 10, 0 ]; + +$fa = 1; +$fs = 0.1; + +module Plan(){ + polygon([[ p1[0], 0.1 ], + p1, p2, p3, p4, p5, p6, p7, p8, p9, + [ p9[0], 0.1 ]]); +} + +module Dummy(){ + rotate_extrude() + rotate([0,0,-90]) + Plan(); + translate([0,0, -p1[0]]) + mirror([0,0,1]) + cylinder(r= 0.2, h= p9[0] - p1[0]); +} + +//Plan(); +Dummy(); diff --git a/GPL-3 b/GPL-3 new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/GPL-3 @@ -0,0 +1,674 @@ + 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 +. diff --git a/Huxley-INSTRUCTIONS b/Huxley-INSTRUCTIONS new file mode 100644 index 0000000..c5efa32 --- /dev/null +++ b/Huxley-INSTRUCTIONS @@ -0,0 +1,79 @@ +To prepare file: + + * Make stl file. + openscad -o test-object.tmp.stl test-object.scad + or equivalent. + + * Slice the file. On appropriate OS run Slic3r. + I was using 0.9.7. + Download from here: + http://slic3r.org/download + + Then + + /home/reprap/Slic3r/bin/slic3r --load /home/reprap/play/slic3r-config.ini test-object.stl + + Produces test-object.gcoce. + +To print: + + * Turn on printer and connect computer. + * Start pronterface + cd /home/reprap/reprappro-software.git/ + ./pronterface/pronterface.py + * Select "connect" (make sure it's ttyUSB0 115200), + wait for printer to connect + * Tick "watch" + * Turn on the hotend and bed heaters + * Remove MicroSD card from printer and copy the file to it + (give it an 8.3 filename ending in .G) + * Insert MicroSD card back into printer + * Wait for bed (and hotend) to get up to temperature + * If there's lots of ooze, pick off nozzle with fine-nosed pliers + * "SD" / "Print", select the file you uploaded earlier + * Watch while it starts and make sure that the skirt sticks to + printbed and nothing gets tangled + * Check that filament feed path from feedstock coil looks good. + +After printing: + + * You can right away unclip the bed plate. + * Wait for the object and bed plate to cool before removing it. + +*** DO NOT TURN PRINTER OFF WHILE HOT END IS HOT *** + +Levelling (occasionally, or after transport): + + * Home in pronterface + * Set level: + Use FL/FR to move to front left / right + Use Home Z to make it go up and down + Observe motion of bed - should be just none + Turn RH thread with fingers to adjust so above is true + (Levelling screws front/back are at RH of bed plate.) + +Bed cleaning: use isopropanol + +------------------------------------------------------------ + +make these symlinks +~/.pronsolerc -> /home/reprap/play/pronsolerc (adjust to taste) + +Slic3r - is from slic3r-linux-x86-0-9-7.tar.gz + /home/reprap/Slic3r/bin/slic3r --load /home/reprap/play/slic3r-config.ini --ignore-nonexistent-config + +repsnapper - only used this so far for its gcode viewer + +------------------------------------------------------------ + +firmware upgrade: + + firmware is in marlin.git#iwj and works with make + various other firmwares for comparison only + sprinter-reprappro.git sprinter.git + produces Marlin.hex + depends on stuff in arduino-0022 (doesn't work with other arduino + versions, incompatible) + program with + avrdude -b 38400 -v -P /dev/ttyUSB0 -p atmega644P -c arduino -U flash:w:Marlin.hex + needs the reset jumper (which is right next to the mcu) fitted diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..2821dee --- /dev/null +++ b/Makefile @@ -0,0 +1,150 @@ +# reprap-objects Makefile +# +# Build scripts for various 3D designs +# Copyright 2012-2016 Ian Jackson +# +# This work 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 work 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 work. If not, see . + +FILAMENTSPOOL_AUTOS = filamentspool filamentspool-lt filamentspool-sm +FILAMENTSPOOL_AUTOS += filamentspool-storarm3 + +QUACKSES = $(addprefix quacks-ingredients-L, 1 2 3 4 5) +QUACKS_SCADS = $(addsuffix .scad, $(QUACKSES)) + +USING_AUTOS ?= $(FILAMENTSPOOL_AUTOS) xeno-drivebay-bracket dungeonquest-cone anke-gps-bracket cable-hole-trunking-cover anglepoise-neck crossbar-computer-led-mount wardrobe-hook knifeblock pandemic-counter pattress-boxes-3-cover bike-lipo-box earring-stand bike-stalk-led-mount sewing-table sewing-table-test sewing-table-jig maglite-holder poster-tube-lid poster-tube-lid-coarse fairphone-case fairphone-battery-case fairphone4-case fairphone4-case-coarse lock-inframe-bracket ksafe-base $(QUACKSES) quacks-ingredients-demos mic-table-clamp nook-case nook-case-test scaffold-clamp-common scaffold-clamp-tensioner scaffold-clamp-linear-bracket scaffold-clamp-straphook powerbank-bike-clamp topeak-mtx-tortec-expeditionrack-adapter lipo-flat-mount laptop-sound-cable-hooks $(foreach x,500 1000,adafruit-powerboost-$x) + +AUTO_INCS += sealing-box.scad sewing-table.scad nutbox.scad \ + powerbank-anker-10000.dxf \ + poster-tube-lid-parametric.scad \ + $(QUACKS_SCADS) + +AUTO_STLS_INCS += poster-tube-lid,CatchPostDistort-fa3.stl +AUTO_STLS_INCS += poster-tube-lid,CatchPostDistort-fa20.stl + +include reprap-objects.make + +dovecliptest.stl: doveclip.scad $(AUTO_INCS) + +KNIFEBLOCK_KNIVES= 0 1 2 +KNIFEBLOCK_TEMPLATES= bl hl +KNIFEBLOCK_TEMPLATE_FILES=\ + $(foreach k,$(KNIFEBLOCK_KNIVES), \ + $(foreach t,$(KNIFEBLOCK_TEMPLATES), \ + knifeblock-knives-t$k$t.dxf)) + +knifeblock-knives-templates knifeblock.stl: $(KNIFEBLOCK_TEMPLATE_FILES) + +.PRECIOUS: knifeblock-knives-t%.dxf +knifeblock-knives-t%.dxf: knifeblock-knives-filter knifeblock-knives-trace.fig + ./$< $(notdir $*) <$(filter %.fig, $^) >$@.tmp.fig + fig2dev -D -30 -L eps <$@.tmp.fig >$@.tmp.eps + pstoedit -dt -f "dxf: -polyaslines -mm" $@.tmp.eps $@ + +PANDEMICCOUNTER_LETTERS=30 31 32 33 34 35 +PANDEMICCOUNTER_DXFS=$(foreach l,$(PANDEMICCOUNTER_LETTERS), \ + pandemic-counter-l$l.dxf) + +pandemic-counter-letters: $(PANDEMICCOUNTER_DXFS) +pandemic-counter%.stl: $(PANDEMICCOUNTER_DXFS) + +.PRECIOUS: pandemic-counter-l%.eps +pandemic-counter-l%.eps: pandemic-counter-letters.fig + fig2dev -D +$(notdir $*) -L eps <$< >$@.tmp + @mv -f $@.tmp $@ + +.PRECIOUS: maglite-holder-torch-curve.eps +maglite-holder-torch-curve.eps: maglite-holder-torch.fig + fig2dev -D +1:70 -L eps <$< >$@.tmp + @mv -f $@.tmp $@ + +maglite-holder-torch-curve.dxf: maglite-holder-torch-curve.eps + pstoedit -dt -flat 0.05 -f "dxf: -polyaslines -mm" $< $@ + +powerbank-anker-10000.dxf: powerbank-anker-10000.eps + pstoedit -dt -f "dxf: -polyaslines -mm" $< $@ + +PANDEMICQUARANTINES_NUMBERS=1 2 +PANDEMICQUARANTINES_DXFS=$(foreach l,$(PANDEMICQUARANTINES_NUMBERS), \ + pandemic-quarantine-l$l.dxf) + +pandemic-quarantine-numbers: $(PANDEMICQUARANTINES_DXFS) +pandemic-quarantine%.stl: $(PANDEMICQUARANTINES_DXFS) + +.PRECIOUS: pandemic-quarantine-l%.eps +pandemic-quarantine-l%.eps: pandemic-quarantine-numbers.fig + fig2dev -D +$(notdir $*) -L eps <$< >$@.tmp + @mv -f $@.tmp $@ + +FILAMENTSPOOL_NUMBERS=$(shell seq 300 100 1500) +filamentspool-number-n%.eps: filamentspool-number.eps.pl + ./$< $* >$@.tmp && mv -f $@.tmp $@ + +FILAMENTSPOOL_DXFS=$(foreach n,$(FILAMENTSPOOL_NUMBERS), \ + filamentspool-number-n$n.dxf) + +$(addsuffix .auto.stl, $(foreach f,$(FILAMENTSPOOL_AUTOS),$(shell \ + $(PLAY)/toplevel-find $(PLAY)/$f))): $(FILAMENTSPOOL_DXFS) + +filamentspool-numbers filamentspool.stl: $(FILAMENTSPOOL_DXFS) + +SCREWRECESSTEST_SIZES= 2 3 4 5 6 +SCREWRECESSTEST_DXFS=$(foreach s,$(SCREWRECESSTEST_SIZES), \ + screw-recess-test-number-s$s.dxf) + +screw-recess-test-number-s%.fig: screw-recess-test-number.fig.pl + ./$< $* >$@.tmp && mv -f $@.tmp $@ + +screw-recess-test-number-s%.eps: screw-recess-test-number-s%.fig + fig2dev -L eps <$< >$@.tmp + @mv -f $@.tmp $@ + +screw-recess-test-numbers screw-recess-test.stl: $(SCREWRECESSTEST_DXFS) + +question-question.eps: question-question.fig + fig2dev -L eps <$< >$@.tmp + @mv -f $@.tmp $@ + +sewing-table%.stl: sewing-table-rear-profile.dxf +sewing-table%.stl: sewing-table-front-profile.dxf +sewing-table%.stl: sewing-table-end-profile.dxf + +sewing-table-%-profile.eps: sewing-table-%-profile.fig + fig2dev -L eps -D +40 <$< >$@.tmp + @mv -f $@.tmp $@ + +question-token.stl: question-question.dxf + +lemon-stand.stl: lemon-stand.scad + +electron-token.stl: electron-token.scad + +quacks-scads: $(addsuffix .auto.scads, $(QUACKSES)) +quacks-scads: quacks-ingredients-demos.auto.scads + +quacks-stls: $(addsuffix .auto.stls, $(QUACKSES)) + +.PRECIOUS: $(SCREWRECESSTEST_DXFS) $(SCREWRECESSTEST_DXFS) \ + $(foreach s,$(SCREWRECESSTEST_SIZES), \ + screw-recess-test-number-s$s.fig \ + screw-recess-test-number-s$s.eps) + +poster-tube-lid,CatchAssembly.auto.stl: poster-tube-lid,CatchPostDistort-fa3.stl +poster-tube-lid-coarse,CatchAssembly.auto.stl: poster-tube-lid,CatchPostDistort-fa20.stl + +poster-tube-lid,CatchPostDistort-fa%.stl: \ + distort-stl poster-tube-lid,CatchPreDistort.auto.stl + ./distort-stl $@.tmp + mv -f $@.tmp $@ + diff --git a/Marlin.hex b/Marlin.hex new file mode 100644 index 0000000..30cf7e0 --- /dev/null +++ b/Marlin.hex @@ -0,0 +1,3895 @@ +:100000000C94DD090C94050A0C94050A0C94050A5D +:100010000C94050A0C94050A0C94050A0C94050A24 +:100020000C94050A0C94050A0C94050A0C94050A14 +:100030000C94050A0C944F510C94050A0C94050A73 +:100040000C94050A0C94CB610C94B32A0C94050A09 +:100050000C94752C0C94050A0C94050A0C94050A52 +:100060000C94050A0C94050A0C94050A0C94050AD4 +:100070000C94050A0C94050A0C94050A084AD73B0F +:100080003BCE016E84BCBFFDC12F3D6C74319ABD67 +:1000900056833DDA3D00C77F11BED9E4BB4C3E918B +:1000A0006BAAAABE000000803F05A84CCDB2D44E7A +:1000B000B93836A9020C50B9918688083CA6AAAA7C +:1000C0002ABE000000803F6563686F3A00656E716C +:1000D0007565696E67202200220073746172740076 +:1000E000506F7765725570002045787465726E6147 +:1000F0006C205265736574002042726F776E206FBA +:100100007574205265736574002057617463686468 +:100110006F672052657365740020536F6674776152 +:100120007265205265736574004D61726C696E2052 +:1001300000312E302E302052433200204C61737437 +:1001400020557064617465643A2000323031322D7C +:1001500030372D323900207C20417574686F723A37 +:10016000200069776A002046726565204D656D6FD5 +:1001700072793A20002020506C616E6E6572427573 +:100180006666657242797465733A200053746F72C3 +:1001900065642073657474696E6773207265747228 +:1001A00065697665643A006F6B00446F6E65207315 +:1001B0006176696E672066696C652E004572726FA4 +:1001C000723A004C696E65204E756D6265722069E9 +:1001D00073206E6F74204C617374204C696E6520BF +:1001E0004E756D6265722B312C204C617374204CFE +:1001F000696E653A00636865636B73756D206D6940 +:10020000736D617463682C204C617374204C696E4B +:10021000653A004E6F20436865636B73756D207798 +:10022000697468206C696E65206E756D6265722CEC +:10023000204C617374204C696E653A004E6F204CFF +:10024000696E65204E756D626572207769746820ED +:10025000636865636B73756D2C204C617374204CFF +:10026000696E653A006F6B005072696E746572203A +:1002700073746F707065642064657520746F206599 +:1002800072726F72732E20466978207468652065DB +:1002900072726F7220616E6420757365204D3939FA +:1002A0003920746F2072657374617274212E202856 +:1002B00054656D7065726174757265206973207222 +:1002C000657365742E2053657420697420626566B9 +:1002D0006F72652072657374617274696E6729004C +:1002E000446F6E65207072696E74696E672066690E +:1002F0006C6500426567696E2066696C65206C6993 +:10030000737400456E642066696C65206C69737453 +:10031000006F6B20543A00202F0020423A00202F1B +:100320000020403A00543A0020453A0020573A0055 +:10033000543A0020453A0020423A004649524D576F +:100340004152455F4E414D453A4D61726C696E2098 +:1003500056313B20537072696E7465722F677262FA +:100360006C206D617368757020666F722067656EB2 +:1003700036204649524D574152455F55524C3A68D6 +:100380007474703A2F2F7777772E6D656E64656C75 +:100390002D70617274732E636F6D2050524F544FE5 +:1003A000434F4C5F56455253494F4E3A312E302001 +:1003B0004D414348494E455F545950453A4D656E4D +:1003C00064656C2045585452554445525F434F551F +:1003D0004E543A310A00583A00593A005A3A004508 +:1003E0003A0020436F756E7420583A00593A005A0B +:1003F0003A00785F6D696E3A00795F6D696E3A0018 +:100400007A5F6D696E3A00556E6B6E6F776E206322 +:100410006F6D6D616E643A22002200FFFFFF0000E5 +:1004200000000000000000000000000000000000CC +:100430000000000080BF00001B43000016430000C6 +:10044000B4420000A0400000A0400000803F000037 +:100450001B43000016430000B64253657474696E76 +:1004600067732053746F72656400537465707320F2 +:1004700070657220756E69743A0020204D39322003 +:100480005800205900205A002045004D6178696DC0 +:10049000756D2066656564726174657320286D6D85 +:1004A0002F73293A0020204D323033205800205934 +:1004B00000205A002045004D6178696D756D20411E +:1004C0006363656C65726174696F6E20286D6D2F52 +:1004D0007332293A0020204D323031205800205903 +:1004E00000205A00204500416363656C65726174A9 +:1004F000696F6E3A20533D616363656C6572617428 +:10050000696F6E2C20543D72657472616374206152 +:100510006363656C65726174696F6E0020204D3293 +:100520003034205300205400416476616E6365646A +:10053000207661726961626C65733A20533D4D6942 +:100540006E20666565647261746520286D6D2F7319 +:10055000292C20543D4D696E2074726176656C20A3 +:10056000666565647261746520286D6D2F73292C32 +:1005700020423D6D696E696D756D207365676D65AF +:100580006E742074696D6520286D73292C20583D88 +:100590006D6178696D756D207859206A65726B2080 +:1005A000286D6D2F73292C20205A3D6D6178696D5F +:1005B000756D205A206A65726B20286D6D2F732926 +:1005C0000020204D323035205300205400204200BE +:1005D000205800205A00204500486F6D65206F6646 +:1005E0006673657420286D6D293A0020204D3230E5 +:1005F00036205800205900205A0050494420736585 +:100600007474696E67733A002020204D33303120B6 +:100610005000204900204400526573656E643A0022 +:100620006F6B005072696E7465722068616C7465DE +:10063000642E206B696C6C28292063616C6C656486 +:10064000202121005072696E7465722073746F707E +:100650007065642064657520746F206572726F72B6 +:10066000732E2046697820746865206572726F72F7 +:1006700020616E6420757365204D39393920746F9F +:100680002072657374617274212E202854656D7018 +:100690006572617475726520697320726573657423 +:1006A0002E20536574206974206265666F72652020 +:1006B00072657374617274696E6729007C3C3E5E7A +:1006C0002B3D3F2F5B5D3B2C2A225C006563686FEE +:1006D0003A0020636F6C6420657874727573696F7B +:1006E0006E2070726576656E7465640020746F6F3D +:1006F000206C6F6E6720657874727573696F6E20F9 +:1007000070726576656E746564006563686F3A0043 +:10071000656E6473746F7073206869743A2000208A +:10072000583A0020593A00205A3A0024F404D920BB +:100730001BC40C5C0E9804C4095F0265077101F4C8 +:1007400005F900FB04B30048048700C103690058A1 +:1007500003550003034500BE023A008402310053F2 +:10076000022A002902250004022000E4011C00C81E +:10077000011900AF011700980114008401130071E2 +:100780000110006101100051010E0043010D0036FF +:10079000010B002B010B0020010B00150109000CBF +:1007A00001090003010800FB000800F3000800EB4A +:1007B000000700E4000600DE000600D8000600D2B4 +:1007C000000600CC000500C7000500C2000500BD02 +:1007D000000400B9000400B5000400B1000400AD3D +:1007E000000400A9000400A5000300A20003009F6C +:1007F0000004009B00030098000300950002009392 +:10080000000300900003008D0002008B00030088AD +:100810000002008600020084000300810002007FC5 +:100820000002007D0002007B0002007900020077D8 +:1008300000010076000200740002007200010071E5 +:100840000002006F0002006D0001006C0002006AEF +:1008500000010069000200670001006600010065F8 +:1008600000010064000200620001006100010060FC +:100870000001005F0002005D0001005C0001005B00 +:100880000001005A00010059000100580001005702 +:100890000001005600010055000100540001005302 +:1008A00000000053000100520001005100010050FF +:1008B0000001004F0001004E0000004E0001004DFD +:1008C0000001004C0001004B0000004B0001004AF9 +:1008D00000010049000100480000004800010047F5 +:1008E00000010046000000460001004500000045F0 +:1008F00000010044000100430000004300010042E9 +:1009000000000042000100410000004100010040E1 +:100910000001003F0000003F0001003E0000003EDB +:100920000001003D0000003D0001003C0000003CD3 +:100930000000003C0001003B0000003B0001003AC9 +:100940000000003A000100390000003900010038C1 +:1009500000000038000000380001003700000037B8 +:1009600000010036000000360000003600010035AE +:1009700000000035000000350001003400000034A4 +:100980000000003400010033000000330000003399 +:10099000000100320000003200000032000100318E +:1009A0000000003100000031000100300000003084 +:1009B000000000300001002F0000002F0000002F79 +:1009C0000000002F0001002E0000002E0000002E6D +:1009D0000001002D0000002D0000002D0000002D62 +:1009E0000001002C0000002C0000002C0000002C56 +:1009F0000001002B0000002B0000002B0000002B4A +:100A00000001002A0000002A0000002A0000002A3D +:100A10000001002900000029000000290000002931 +:100A20000000002900010028000000280000002824 +:100A30000000002800000028000100270000002717 +:100A4000000000270000002700000027000100260A +:100A500000000026000000260000002600000026FE +:100A600000010025000000250000002500000025F1 +:100A700000000025000000250001002400000024E3 +:100A800000000024000000240000002400010023D6 +:100A900000000023000000230000002300000023CA +:100AA00000000023000000230001002200000022BB +:100AB00000000022000000220000002200000022AE +:100AC00000010021000000210000002100000021A1 +:100AD0000000002100000021000000210001002092 +:100AE0000000002000000020000000200000002086 +:100AF0000000002000000020000000200001001F76 +:100B00000000001F0000001F0000001F0000001F69 +:100B10000000001F0000001F0001001E0000001E5A +:100B20000000001E0000001E00000024F4D430501D +:100B3000C38E20C2A24017828B7011127A910D8150 +:100B40006CD90AA861E108C7586607615143061EBF +:100B50004B5D05C145A7041A411104093D98037175 +:100B60003931034036DB0265339102D430540280C0 +:100B70002E1D02632CEE01752AC501B028A00110BC +:100B80002781018F2564012B244B01E0223401AC25 +:100B9000211F018D200D01801FFC00841EED009798 +:100BA0001DDF00B81CD200E61BC600201BBC006481 +:100BB0001AB200B219A8000A19A0006A189900D147 +:100BC00017910040178B00B516840031167E00B3D4 +:100BD0001579003A157300C7146F0058146A00EEB7 +:100BE0001366008813630025135E00C7125B006C58 +:100BF00012570015125400C111510070114F0021FD +:100C0000114B00D61049008D1047004610440002D9 +:100C1000104200C00F4000800F3E00420F3C000613 +:100C20000F3B00CB0E3800930E37005C0E350027CB +:100C30000E3400F30D3200C10D3100900D30006014 +:100C40000D2E00320D2D00050D2C00D90C2B00AE01 +:100C50000C2900850C29005C0C2700350C27000EA0 +:100C60000C2600E80B2400C40B2400A00B23007DFD +:100C70000B23005A0B2100390B2100180B2000F820 +:100C80000A1F00D90A1E00BB0A1E009D0A1D008013 +:100C90000A1D00630A1C00470A1B002C0A1B0011D6 +:100CA0000A1A00F7091A00DD091900C4091900AB76 +:100CB000091900920917007B091800630917004CF5 +:100CC00009160036091600200916000A091500F554 +:100CD000081500E0081400CC081400B8081400A49B +:100CE000081400900813007D0812006B08130058C8 +:100CF00008120046081200340811002308110012DF +:100D000008110001081100F0071000E0071000D0E2 +:100D1000071000C0071000B0070F00A107100091D6 +:100D2000070E0083070F0074070F0065070E0057BA +:100D3000070E0049070E003B070D002E070E00208E +:100D4000070D0013070D0006070D00F9060C00ED56 +:100D5000060D00E0060C00D4060C00C8060C00BC12 +:100D6000060C00B0060C00A4060B0099060C008DC2 +:100D7000060B0082060B0077060B006C060B006169 +:100D8000060A0057060B004C060A0042060A003805 +:100D9000060A002E060A0024060A001A060A001097 +:100DA00006090007060A00FD050900F4050900EB25 +:100DB000050900E2050900D9050900D0050900C7A9 +:100DC000050900BE050900B5050800AD050800A528 +:100DD0000509009C050800940508008C050800849E +:100DE0000508007C050800740508006C050700650F +:100DF0000508005D050700560508004E0507004779 +:100E00000507004005080038050700310507002ADE +:100E1000050700230507001C050600160507000F3F +:100E20000507000805060002050700FB040600F59B +:100E3000040700EE040600E8040600E2040700DBF5 +:100E4000040600D5040600CF040600C9040600C34A +:100E5000040600BD040600B7040600B1040500AC9A +:100E6000040600A6040600A00405009B04060095E5 +:100E7000040500900406008A04050085040500802E +:100E80000406007A04050075040500700405006B73 +:100E900004050066040500610405005C04050057B4 +:100EA000040500520405004D0405004804050043F4 +:100EB0000405003E0404003A040500350405003032 +:100EC0000404002C04050027040400230405001E6C +:100ED0000404001A04040016040500110404000DA3 +:100EE000040400090405000404040000040400FCD8 +:100EF000030400F8030400F4030400F0030400EC0E +:100F0000030400E8030400E4030400E0030400DC3D +:100F1000030400D8030400D4030400D0030400CC6D +:100F2000030400C8030300C5030300206269617362 +:100F30003A200020643A2000206D696E3A2000209B +:100F40006D61783A2000204B753A20002054753AA4 +:100F5000200020436C6173696320504944200020C5 +:100F60004B703A2000204B693A2000204B643A2015 +:100F700000504944204175746F74756E6520666138 +:100F8000696C6564212054656D7065726174757259 +:100F90006520746F2068696768006F6B20543A00A1 +:100FA00020403A00504944204175746F74756E6555 +:100FB000206661696C6564212074696D656F757464 +:100FC00000504944204175746F74756E65206669E0 +:100FD0006E6973686564202120506C6163652074BC +:100FE0006865204B702C204B6920616E64204B6437 +:100FF00020636F6E7374616E747320696E20746801 +:101000006520636F6E66696775726174696F6E2EB5 +:1010100068004572726F723A00202D20496E766129 +:101020006C6964206578747275646572206E756D84 +:10103000626572210070012C0190012701B001222C +:1010400001C0011D01F00118011002130130020E50 +:10105000016002090190020401C002FF000003FACE +:10106000004003F5008003F000D003EB002004E60D +:10107000007004E100E004DC004005D700C005D2A8 +:10108000004006CD00D006C8008007C3003008BE6F +:1010900000F008B900C009B400B00AAF00B00BAA54 +:1010A00000D00CA500000EA000500F9B00C01096B1 +:1010B000005012910000148C00C0158700B01782F8 +:1010C00000B0197D00D01B7800001E730040206E18 +:1010D0000090226900F024640040275F0090295AA4 +:1010E00000E02B5500102E500020304B00103246EF +:1010F00000E033410090353C001037370070383243 +:1011000000A0392D00B03A2800A03B2300603C1E0F +:1011100000103D1900903D1400103E0F00703E0A73 +:1011200000C03E0500003F0000202D20496E766182 +:101130006C6964206578747275646572206E756D73 +:101140006265722021003A20457874727564657278 +:10115000207377697463686564206F66662E204D1E +:10116000415854454D5020747269676765726564D3 +:101170002021003A20457874727564657220737777 +:10118000697463686564206F66662E204D494E540D +:10119000454D50207472696767657265642021004F +:1011A00054656D70657261747572652068656174EF +:1011B0006564206265642073776974636865642080 +:1011C0006F66662E204D415854454D50207472690B +:1011D000676765726564202121006563686F3A0066 +:1011E000534420696E6974206661696C00457272AF +:1011F0006F723A00766F6C756D652E696E6974203A +:101200006661696C6564006F70656E526F6F742003 +:101210006661696C65640053442063617264206F89 +:101220006B006F70656E206661696C65642C20468A +:10123000696C653A20002E0046696C65206F706508 +:101240006E65643A002053697A653A0046696C65B8 +:101250002073656C6563746564006F70656E2066ED +:1012600061696C65642C2046696C653A20002E002B +:101270006F70656E206661696C65642C2046696CD0 +:10128000653A20002E0057726974696E6720746F8A +:101290002066696C653A20006F70656E2066616932 +:1012A0006C65642C2046696C653A20002E00466906 +:1012B0006C652064656C657465643A0044656C65B2 +:1012C00074696F6E206661696C65642C2046696C78 +:1012D000653A20002E005344207072696E74696E66 +:1012E00067206279746520002F004E6F742053448C +:1012F000207072696E74696E67006572726F722019 +:1013000077726974696E6720746F2066696C650016 +:1013100000000001020000000000000004030706B6 +:1013200000000000000000000000000000000000BD +:1013300001020408102040800102040810204080AF +:10134000010204081020408080402010080402019F +:10135000020202020202020204040404040404045D +:10136000030303030303030301010101010101015D +:10137000002225282B002124272A494E46494E4980 +:1013800054594E414E000020410000C84200401C0C +:101390004620BCBE4CCA1B0E5AAEC59D74CDCCCCEB +:1013A0003D0AD7233C17B7D13877CC2B329595E639 +:1013B000241FB14F0A00AB2AAF2A11241FBECFEF62 +:1013C000D0E1DEBFCDBF12E0A0E0B1E0ECE6F1EF8E +:1013D00002C005900D92A63EB107D9F71EE0A6EE19 +:1013E000B2E001C01D92A534B107E1F713E1C8EBEB +:1013F000D3E104C02297FE010E94B472C63BD1071C +:10140000C9F70E947D2A0C94A9780C940000FC0175 +:101410004591559165917491E52F362F272F642FB3 +:101420007E2F832F922F08952F923F924F925F929B +:101430006F927F928F929F92AF92BF92CF92DF92E4 +:10144000EF92FF920F931F93CF93DF9300D000D0C2 +:1014500000D0CDB7DEB78C019C01220F331F220FC5 +:10146000331F3E832D832B503D4F3A832983F9014F +:10147000108211821282138221E033E04DEF52E09C +:1014800069EF72E085EF92E00E94F74F8D819E81B7 +:10149000825B9B4F0E94070AF801E55EFB4F0491B7 +:1014A0002EE8222E25E0322E2D813E81220E331E83 +:1014B00020E030E040EC5FE30E9457712B013C01DB +:1014C000602F772767FD7095872F972F0E94246FD5 +:1014D0004B015C019B01AC01C301B2010E94577139 +:1014E000F10160837183828393832D813E81245E29 +:1014F0003E4F3C832B83F90160817181828193810E +:1015000060932C0170932D0180932E0190932F01F5 +:1015100020E030E040E752E40E94896E38EEC32EAE +:1015200032E0D32E7B018C012AE935E046E955E013 +:1015300062E975E08EE895E00E9468450E94AC572C +:10154000E981FA81108211821282138221E033E054 +:101550004DEF52E069EF72E085EF92E00E94F74FA5 +:101560008D819E818E5B9B4F0E94070A2B013C015F +:101570009058A50194010E945771F1016083718315 +:101580008283938320E030E040E752E460912C01B5 +:1015900070912D0180912E0190912F010E94896EF2 +:1015A0007B018C012AE935E046E955E062E975E006 +:1015B0008EE895E00E9468450E94AC57A301920115 +:1015C000C301B2010E94A96DA50194010E94577147 +:1015D000F101608371838283938320E030E040E0F7 +:1015E0005FE3EB81FC8160817181828193810E9444 +:1015F0005771FB01462F5F2F682F792F40932C01E5 +:1016000050932D0160932E0170932F0120E030E064 +:1016100040E752E4BF010E94896E7B018C012AE9F8 +:1016200035E046E955E062E975E08EE895E00E9414 +:1016300068450E94AC578D819E81825E9B4F0E94BF +:10164000070AED81FE81E751FD4F80809180A280E5 +:10165000B380A50194010E94A96D2B013C01982F34 +:10166000442D552D692F772DE981FA8140835183CF +:10167000628373838D819E81865D9B4F0E94070AE2 +:101680000D811E81045F1E4FA50194010E94A96D6A +:10169000F80160837183828393838D819E818A5C4C +:1016A0009B4F0E94070A0D811E8100501F4FA5010C +:1016B00094010E94A96DF8016083718382839383F2 +:1016C000842D952DA62DB72DF10180839183A283C2 +:1016D000B38310922C0110922D0110922E011092C2 +:1016E0002F0126960FB6F894DEBF0FBECDBFDF9157 +:1016F000CF911F910F91FF90EF90DF90CF90BF900F +:10170000AF909F908F907F906F905F904F903F90A1 +:101710002F900C943F5107C03091C00035FFFCCF93 +:101720002093C6000196FC0124912111F5CF22E0FF +:1017300030E081EC95E00C94B92E07C03091C000E8 +:1017400035FFFCCF2093C6000196FC0124912111A6 +:10175000F5CF22E030E081EC95E00C94B92E07C083 +:101760003091C00035FFFCCF2093C6000196FC01EC +:1017700024912111F5CF2AE030E081EC95E00C9422 +:101780009C2DCF93DF93C7ECD0E0FE0107C0909172 +:10179000C00095FFFCCF8093C600319684918111E3 +:1017A000F6CFEAE6F4E007C09091C00095FFFCCFC9 +:1017B0008093C600319684918111F6CF8091C0004C +:1017C00085FFFCCF8AE08093C600FE018491E7ECA0 +:1017D000F0E008C09091C00095FFFCCF8093C60058 +:1017E000319684918111F6CF4091730D5091740D13 +:1017F0006091750D7091760D8AE794E00E948B0BD5 +:101800004091770D5091780D6091790D70917A0D1E +:1018100082E894E00E948B0B40917B0D50917C0DEF +:1018200060917D0D70917E0D85E894E00E948B0B98 +:1018300040917F0D5091800D6091810D7091820DCE +:1018400088E894E00E948B0B8091C00085FFFCCF5C +:101850008AE08093C600FE018491E7ECF0E008C0C6 +:101860009091C00095FFFCCF8093C6003196849183 +:101870008111F6CFEBE8F4E007C09091C00095FF2E +:10188000FCCF8093C600319684918111F6CF809170 +:10189000C00085FFFCCF8AE08093C600FE018491E2 +:1018A000E7ECF0E008C09091C00095FFFCCF80937A +:1018B000C600319684918111F6CF4091830D5091ED +:1018C000840D6091850D7091860D85EA94E00E94EB +:1018D0008B0B4091870D5091880D6091890D70910F +:1018E0008A0D8EEA94E00E948B0B40918B0D5091F3 +:1018F0008C0D60918D0D70918E0D81EB94E00E94A6 +:101900008B0B40918F0D5091900D6091910D7091C6 +:10191000920D84EB94E00E948B0B8091C00085FFB8 +:10192000FCCF8AE08093C600FE018491E7ECF0E0F2 +:1019300008C09091C00095FFFCCF8093C6003196FF +:1019400084918111F6CFE7EBF4E007C09091C000DD +:1019500095FFFCCF8093C600319684918111F6CF1C +:101960008091C00085FFFCCF8AE08093C600FE0115 +:101970008491E7ECF0E008C09091C00095FFFCCFA7 +:101980008093C600319684918111F6CF4091630D0A +:101990005091640D6091650D7091660D85ED94E038 +:1019A0000E94AF0B4091670D5091680D6091690DD9 +:1019B00070916A0D8EED94E00E94AF0B40916B0D1B +:1019C00050916C0D60916D0D70916E0D81EE94E0F3 +:1019D0000E94AF0B40916F0D5091700D6091710D91 +:1019E0007091720D84EE94E00E94AF0B8091C00064 +:1019F00085FFFCCF8AE08093C600FE018491E7EC6E +:101A0000F0E008C09091C00095FFFCCF8093C60025 +:101A1000319684918111F6CFE7EEF4E007C0909102 +:101A2000C00095FFFCCF8093C60031968491811150 +:101A3000F6CF8091C00085FFFCCF8AE08093C6007E +:101A4000FE018491E7ECF0E008C09091C00095FFA2 +:101A5000FCCF8093C600319684918111F6CF4091DE +:101A60005B0D50915C0D60915D0D70915E0D8CE190 +:101A700095E00E948B0B4091570D5091580D60914D +:101A8000590D70915A0D85E295E00E948B0B809163 +:101A9000C00085FFFCCF8AE08093C600FE018491E0 +:101AA000E7ECF0E008C09091C00095FFFCCF809378 +:101AB000C600319684918111F6CFE8E2F5E007C0C7 +:101AC0009091C00095FFFCCF8093C6003196849121 +:101AD0008111F6CF8091C00085FFFCCF8AE0809312 +:101AE000C600FE018491E7ECF0E008C09091C000D0 +:101AF00095FFFCCF8093C600319684918111F6CF7B +:101B000040915F0D5091600D6091610D7091620D7B +:101B100081EC95E00E948B0B4091470D5091480D50 +:101B20006091490D70914A0D8AEC95E00E948B0BF3 +:101B30004091930D5091940D6091950D7091960D7B +:101B40008DEC95E00E94AF0B4091530D5091540DD8 +:101B50006091550D7091560D80ED95E00E948B0BB4 +:101B600040914F0D5091500D6091510D7091520D5B +:101B700083ED95E00E948B0B40914B0D50914C0DE5 +:101B800060914D0D70914E0D86ED95E00E948B0B8E +:101B90008091C00085FFFCCF8AE08093C600FE01E3 +:101BA0008491E7ECF0E008C09091C00095FFFCCF75 +:101BB0008093C600319684918111F6CFE9EDF5E06E +:101BC00007C09091C00095FFFCCF8093C60031966E +:101BD00084918111F6CF8091C00085FFFCCF8AE00F +:101BE0008093C600FE018491E7ECF0E008C090917C +:101BF000C00095FFFCCF8093C6003196849181117F +:101C0000F6CF4091E9025091EA026091EB027091A7 +:101C1000EC028BEE95E00E948B0B4091ED0250910F +:101C2000EE026091EF027091F00284EF95E00E9465 +:101C30008B0B4091F1025091F2026091F30270918E +:101C4000F40287EF95E00E948B0B8091C00085FF26 +:101C5000FCCF8AE08093C600FE018491E7ECF0E0BF +:101C600008C09091C00095FFFCCF8093C6003196CC +:101C700084918111F6CFEAEFF5E007C09091C000A2 +:101C800095FFFCCF8093C600319684918111F6CFE9 +:101C90008091C00085FFFCCF8AE08093C600FE01E2 +:101CA000C491E7ECF0E008C08091C00085FFFCCF54 +:101CB000C093C6003196C491C111F6CF4091520134 +:101CC00050915301609154017091550188E096E064 +:101CD0000E948B0B2DEB37E346E05EE360914E01F3 +:101CE00070914F0180915001909151010E94896E35 +:101CF000AB01BC0182E196E00E949D0B2DEB37E326 +:101D000046E05EE360914A0170914B0180914C0185 +:101D100090914D010E945771AB01BC0185E196E0A5 +:101D20000E949D0B8091C00085FFFCCF8AE08093CC +:101D3000C600DF91CF910895CF93DF9300D0CDB748 +:101D4000DEB780913F0E9091400E9E012F5F3F4F76 +:101D5000009719F425543E4002C0281B390B3A83E2 +:101D6000298389819A810F900F90DF91CF910895F7 +:101D70002091E6033091E703243031050CF06AC06E +:101D80004091E8035091E90360E6649F9001659FEC +:101D9000300D1124BC01C90186519C4F0E947A75F7 +:101DA000E7ECF0E007C09091C00095FFFCCF809376 +:101DB000C600319684918111F6CFEDECF0E007C0BA +:101DC0009091C00095FFFCCF8093C600319684911E +:101DD0008111F6CF8091E8039091E90320E6289FD6 +:101DE000F001299FF00D1124E651FC4F06C090919F +:101DF000C00095FFFCCF8093C60081918111F7CF81 +:101E0000E8EDF0E007C09091C00095FFFCCF809313 +:101E1000C600319684918111F6CF8091C00085FF74 +:101E2000FCCF8AE08093C6008091E8039091E9039B +:101E3000019664E070E00E9440729093E903809301 +:101E4000E8038091E6039091E70301969093E703FE +:101E50008093E6030895809174059091750560E084 +:101E600070E001960C94B87280917405909175059C +:101E70004AE050E060E070E001960C940F744091ED +:101E80006E0550916F0590E6949F9001959F300DDF +:101E90001124682F70E0C90186519C4F0E946F7514 +:101EA000909375058093740521E0892B09F420E057 +:101EB000822F08950E94FD2A6093860570938705FE +:101EC0008093880590938905E0916E05F0916F05E8 +:101ED000E659FA4F8081811114C0E0E2F6E007C0B4 +:101EE0009091C00095FFFCCF8093C60031968491FD +:101EF0008111F6CF8091C00085FFFCCF8AE08093EE +:101F0000C600089581EC95E00E94FE2CE8E1F6E021 +:101F100007C09091C00095FFFCCF8093C60031961A +:101F200084918111F6CF40917A0550917B056091A3 +:101F30007C0570917D054F5F5F4F6F4F7F4F2AE0AB +:101F400030E081EC95E00E94AF2D8091C00085FFCC +:101F5000FCCF8AE08093C6000C945A0F2F923F92D8 +:101F60004F925F926F927F928F929F92AF92BF92A9 +:101F7000CF92DF92EF92FF920F931F93CF93DF9355 +:101F8000CDB7DEB76F970FB6F894DEBF0FBECDBFEB +:101F9000A0E67A2EB4E04B2E512CE8E6F2E08490D5 +:101FA0001AE0B12EE5E6F2E0A49099249394809192 +:101FB0004206909143062091440630914506821BCB +:101FC000930B8F779927892B09F004C234C38D3086 +:101FD00051F08A3321F490917105992321F02F3526 +:101FE00031050CF4DAC12115310509F49FC2809145 +:101FF000E8039091E903789E7001799EF00C11241A +:10200000F701E20FF31FE651FC4F1082209171059A +:102010002111BEC110927105FC01E659FA4F1082E0 +:10202000870106511C4F6EE470E0C8010E946F7575 +:10203000009709F404C19093750580937405801B83 +:10204000910B8E0D9F1D4AE050E060E070E08551DD +:102050009C4F0E940F746093760570937705809370 +:10206000780590937905C0907A05D0907B05E09033 +:102070007C05F0907D05970186010F5F1F4F2F4F64 +:102080003F4F6017710782079307C1F12091E80362 +:102090003091E903729EC001739E900D11246BE88C +:1020A00071E086519C4F0E949E75892B39F5ECEBAF +:1020B000F1E007C09091C00095FFFCCF8093C6006F +:1020C000319684918111F6CFE3ECF1E007C0909155 +:1020D000C00095FFFCCF8093C6003196849181119A +:1020E000F6CF2AE030E0B701A60181EC95E00E942E +:1020F000AF2D8091C00085FFFCCF8AC08091E8039E +:102100009091E903789E1001799E300C1124810191 +:1021100006511C4F6AE270E0C8010E946F7500977B +:1021200021F450C0F3262F5F02C020E0F12CF10112 +:10213000E20FF11DE651FC4F30813A3299F790934E +:10214000750580937405801B910B820D931D60E0D3 +:1021500070E085519C4F0E94B8720E94F16E2F2D45 +:1021600030E02617370709F459C0ECEBF1E007C05F +:102170009091C00095FFFCCF8093C600319684916A +:102180008111F6CFE5EFF1E007C09091C00095FF17 +:10219000FCCF8093C600319684918111F6CF409197 +:1021A0007A0550917B0560917C0570917D052AE050 +:1021B00030E081EC95E00E94AF2D8091C00085FF5A +:1021C000FCCF26C0ECEBF1E007C09091C00095FF7A +:1021D000FCCF8093C600319684918111F6CFE3E164 +:1021E000F2E007C09091C00095FFFCCF8093C6003D +:1021F000319684918111F6CF2AE030E0B701A60133 +:1022000081EC95E00E94AF2D8091C00085FFFCCF4E +:102210008AE08093C6000E94820F47C080917605B5 +:1022200090917705A0917805B091790580937A0512 +:1022300090937B05A0937C05B0937D053BC06AE23B +:1022400070E0C8010E946F75892BA1F1ECEBF1E001 +:1022500007C09091C00095FFFCCF8093C6003196D7 +:1022600084918111F6CFECE3F2E007C09091C000B9 +:1022700095FFFCCF8093C600319684918111F6CFF3 +:1022800040917A0550917B0560917C0570917D05A8 +:102290002AE030E081EC95E00E94AF2D8091C000F3 +:1022A00085FFFCCF8AE08093C600109273051092E0 +:1022B0007205EFC18091E8039091E903789E800157 +:1022C000799E100D1124FAEEEF2EF3E0FF2EE00EB2 +:1022D000F11E67E470E0C7010E946F75009709F472 +:1022E00042C090937505809374058E199F09800FE5 +:1022F000911F60E070E085519C4F0E94B8720E946F +:10230000F16E6430710578F58091E602811117C095 +:1023100080910C03811127C08A2DE5E6F2E008C008 +:102320009091C00095FFFCCF8093C60031968491B8 +:102330008111F6CF8091C00085FFFCCF12C0882D9F +:10234000E8E6F2E008C09091C00095FFFCCF8093D2 +:10235000C600319684918111F6CF8091C00085FF2F +:10236000FCCFB092C6008091E8039091E9030196FA +:10237000B2010E9440729093E9038093E803809138 +:10238000E6039091E70301969093E7038093E603B9 +:1023900010927305109272050ACE8B3311F490924D +:1023A000710590917105911102CE4091E803509111 +:1023B000E903749ED001759EB00D1124A20FB31FC6 +:1023C000A651BC4F8C932F5F3F4F309373052093E2 +:1023D0007205EDCD8091E6039091E70304970CF42C +:1023E0002FC129C18091720590917305892B09F441 +:1023F000E8C04FC14D3081F04A3321F4209171057E +:10240000222351F020917205309173052F3531054B +:102410001CF4019609F0B8C04091DC035091DD0333 +:102420006091DE037091DF038091D4039091D50316 +:10243000A091D603B091D703481759076A077B07C5 +:1024400008F46DC08F8DE0EEF2E008C09091C000FE +:1024500095FFFCCF8093C600319684918111F6CF11 +:102460008091C00085FFFCCF7092C6000E94FD2ABB +:1024700060937E0570937F0580938005909381051E +:102480002091820530918305409184055091850506 +:10249000621B730B840B950BA70196010E9454726B +:1024A000CA01B901A50194010E9454727F936F93F0 +:1024B0003F932F9380E991E09F938F933F922F92C8 +:1024C0000E94B875862D0FB6F894DEBF0FBECDBF43 +:1024D000E7ECF0E008C09091C00095FFFCCF80933E +:1024E000C600319684918111F6CFF10106C090911A +:1024F000C00095FFFCCF8093C60081918111F7CF7A +:102500008091C00085FFFCCF7092C6008CE093E004 +:102510000E94D56A61E08CE093E00E94CC69209132 +:102520007205309173052115310519F4109271056A +:10253000B0C08091E8039091E903189FF001199FC2 +:10254000F00D1124E20FF31FE651FC4F1082FC0145 +:10255000E659FA4F00832091E6033091E7032F5F9D +:102560003F4F3093E7032093E6030196B2010E94A8 +:1025700040729093E9038093E803109271051092E2 +:102580007305109272053BC04B3311F40093710533 +:1025900080917105811133C08091E8039091E90326 +:1025A000189FF001199FF00D1124E20FF31FE6515F +:1025B000FC4F40832F5F3F4F30937305209372058C +:1025C0001EC010E601E044E0442E512CE0EEF2E0A3 +:1025D00034913F8F5AE0752E68EEC62E63E0D62EFA +:1025E000E12CF12C7CE3872E912CA12CB12C222400 +:1025F0002394312C2C0E3D1EE7ECF0E064904091CA +:10260000DC035091DD036091DE037091DF03809164 +:10261000D4039091D503A091D603B091D703481766 +:1026200059076A077B07A8F58091E6039091E703B5 +:102630000497A4F02EC080910D038111D3CE29C040 +:1026400081EC95E00E94E22C809370052091720548 +:10265000309173058A3009F0BACCC5CC8091C103A2 +:102660009091C203A091C303B091C4038093DC0393 +:102670009093DD03A093DE03B093DF0389EB93E037 +:102680000E944631482F809370058A3009F0B2CEFF +:10269000C3CE6F960FB6F894DEBF0FBECDBFDF91ED +:1026A000CF911F910F91FF90EF90DF90CF90BF904F +:1026B000AF909F908F907F906F905F904F903F90E2 +:1026C0002F9008958F929F92AF92BF92CF92DF92F8 +:1026D000EF92FF920F931F93CF93DF9300E4A02E0E +:1026E00002E0B02E05EF12E0CEE8D5E088E0882EBB +:1026F00083E0982EF50181915F010E943F0F8823AE +:1027000019F10E942B0F6B017C01F4018081811172 +:1027100003C060919E0501C061E070E080E090E040 +:102720000E94246FF80120813181428153810E94EF +:1027300057719B01AC01C701B6010E94A96D688366 +:1027400079838A839B8309C0F80180819181A2816A +:10275000B38188839983AA83BB830C5F1F4F249620 +:10276000FFEF8F1A9F0A84E4A81682E0B80611F6DC +:1027700086E40E943F0F8823D9F00E942B0F6B0143 +:102780007C016093A8057093A9058093AA05909396 +:10279000AB0520E030E0A9010E948570181644F4D2 +:1027A000C0922C01D0922D01E0922E01F0922F01C7 +:1027B000DF91CF911F910F91FF90EF90DF90CF901D +:1027C000BF90AF909F908F9008950E94621389E40C +:1027D0000E943F0F882359F00E942B0F6093AC0595 +:1027E0007093AD058093AE059093AF0508C010922D +:1027F000AC051092AD051092AE051092AF058AE4BB +:102800000E943F0F882359F00E942B0F6093B00560 +:102810007093B1058093B2059093B305089510921B +:10282000B0051092B1051092B2051092B30508954B +:10283000CF92DF92EF92FF92CF93DF93EC01C090A3 +:102840000C01D0900D01E0900E01F0900F01A70156 +:102850009601688179818A819B810E94826E87FFBF +:1028600004C0C882D982EA82FB82C0901001D09055 +:102870001101E0901201F0901301A70196016C8103 +:102880007D818E819F810E94826E87FF04C0CC82F1 +:10289000DD82EE82FF82C0901401D0901501E0909D +:1028A0001601F0901701A7019601688579858A8540 +:1028B0009B850E94826E87FF04C0C886D986EA86FF +:1028C000FB86C0900001D0900101E0900201F090E1 +:1028D0000301A7019601688179818A819B810E9409 +:1028E0008570181624F4C882D982EA82FB82C090CF +:1028F0000401D0900501E0900601F0900701A701C6 +:1029000096016C817D818E819F810E948570181651 +:1029100024F4CC82DD82EE82FF82C0900801D09048 +:102920000901E0900A01F0900B01A701960168856A +:1029300079858A859B850E948570181624F4C8863F +:10294000D986EA86FB86DF91CF91FF90EF90DF90EA +:10295000CF900895CF92DF92EF92FF920F931F9343 +:102960008EE895E00E9418140E94FD2A6093860567 +:1029700070938705809388059093890560911A016B +:1029800070911B01882777FD8095982F0E94246FF6 +:1029900020912C0130912D0140912E0150912F0159 +:1029A0000E94577120E030E040E752E40E94896EB7 +:1029B00020E030E048EC52E40E94896E28EEC22EFE +:1029C00022E0D22E7B018C012AE935E046E955E070 +:1029D00062E975E08EE895E00E94684580918E0579 +:1029E00090918F05A0919005B09191058093F5028B +:1029F0009093F602A093F702B093F80280919205AB +:102A000090919305A0919405B09195058093F9025A +:102A10009093FA02A093FB02B093FC02809196057A +:102A200090919705A0919805B09199058093FD022A +:102A30009093FE02A093FF02B093000380919A0549 +:102A400090919B05A0919C05B0919D0580930103F9 +:102A500090930203A0930303B09304031F910F917B +:102A6000FF90EF90DF90CF900895AF92BF92CF92FA +:102A7000DF92EF92FF920F931F93CF93DF93182F64 +:102A80002091B0053091B1054091B2055091B30548 +:102A90006091AC057091AD058091AE059091AF0548 +:102AA0000E949270EB01082FF92E60911A0170912B +:102AB0001B01882777FD8095982F0E94246F209115 +:102AC0002C0130912D0140912E0150912F010E9437 +:102AD000577120E030E040E752E40E94896E20E028 +:102AE00030E048EC52E40E94896E2091E8022F9376 +:102AF0001F93FF920F93DF93CF935B016C0132E042 +:102B0000E32E01E020E04CEA55E06EE875E085EF49 +:102B100092E00E94263C80918E0590918F05A091B5 +:102B20009005B09191058093F5029093F602A093E1 +:102B3000F702B093F8028091920590919305A091CD +:102B40009405B09195058093F9029093FA02A093B1 +:102B5000FB02B093FC028091960590919705A0919D +:102B60009805B09199058093FD029093FE02A09381 +:102B7000FF02B093000380919A0590919B05A0916C +:102B80009C05B0919D058093010390930203A0934F +:102B90000303B09304030E94FD2A6093860570939B +:102BA000870580938805909389050F900F900F906B +:102BB0000F900F900F90DF91CF911F910F91FF9089 +:102BC000EF90DF90CF90BF90AF900895F8940E945F +:102BD000DF5C5E9A5E9A159A5E9AECEBF1E007C0B4 +:102BE0009091C00095FFFCCF8093C60031968491F0 +:102BF0008111F6CFE3E2F6E007C09091C00095FFA7 +:102C0000FCCF8093C600319684918111F6CF8091DC +:102C1000C00085FFFCCF8AE08093C600FFCFCF9233 +:102C2000DF92EF92FF920F931F930E94FD2A009173 +:102C3000A0051091A1052091A2053091A305C09097 +:102C40008605D0908705E0908805F09089056C197D +:102C50007D098E099F09061717072807390730F4E1 +:102C6000012B022B032B11F00E94E61580913101FC +:102C700090913201A0913301B0913401892B8A2BBC +:102C80008B2B09F10E94FD2A009186051091870582 +:102C90002091880530918905601B710B820B930B85 +:102CA00000913101109132012091330130913401B2 +:102CB000061717072807390730F4909155088091B7 +:102CC0005408981741F01F910F91FF90EF90DF90FB +:102CD000CF900C9444455E9A5E9A159A5E9AF3CF13 +:102CE0000E94DF5C8091E602811134C081E0809314 +:102CF000E60280917A0590917B05A0917C05B091C8 +:102D00007D058093A4059093A505A093A605B09397 +:102D1000A705ECEBF1E007C09091C00095FFFCCF58 +:102D20008093C600319684918111F6CFE4E4F6E0F9 +:102D300007C09091C00095FFFCCF8093C6003196EC +:102D400084918111F6CF8091C00085FFFCCF8AE08D +:102D50008093C60008958091E6020895EF92FF9255 +:102D60000F931F93CF93DF938C017B0184E0E80ED8 +:102D7000F11CEB016991F801808191819C012F5F29 +:102D80003F4F318320830E94C177CE15DF0591F735 +:102D900084E090E0DF91CF911F910F91FF90EF9031 +:102DA0000895EF92FF920F931F93CF93DF938C01BF +:102DB0007B0180E1E80EF11CEB016991F801808153 +:102DC00091819C012F5F3F4F318320830E94C17707 +:102DD000CE15DF0591F780E190E0DF91CF911F9153 +:102DE0000F91FF90EF900895EF92FF920F931F9332 +:102DF000CF93DF938C017B0184E0E80EF11CEB01A3 +:102E00006991F801808191819C012F5F3F4F31834F +:102E100020830E94C177CE15DF0591F784E090E012 +:102E2000DF91CF911F910F91FF90EF9008950F9335 +:102E30001F93CF93DF93CDB7DEB72A970FB6F894E1 +:102E4000DEBF0FBECDBF80E390E3A0E3B0E08D8393 +:102E50009E83AF83B88784E690E09A878987BE0116 +:102E60006B5F7F4FCE0109960E94AE1663E77DE04F +:102E7000CE0109960E94D11663E87DE0CE01099645 +:102E80000E94D11603E61DE0F80161918F0189854A +:102E90009A859C012F5F3F4F3A8729870E94C1770F +:102EA000FDE003371F0781F76BE57DE0CE01099652 +:102EB0000E94F41667E57DE0CE0109960E94F416A3 +:102EC0006FE57DE0CE0109960E94F41667E47DE08F +:102ED000CE0109960E94F41603E91DE0F801619104 +:102EE0008F0189859A859C012F5F3F4F3A872987FB +:102EF0000E94C177FDE007391F0781F763E57DE098 +:102F0000CE0109960E94F4166FE47DE0CE01099689 +:102F10000E94F4166BE47DE0CE0109960E94F4163F +:102F200009EE12E0F80161918F0189859A859C0173 +:102F30002F5F3F4F3A8729870E94C177F2E0053F14 +:102F40001F0781F762E571E0CE0109960E94F41631 +:102F50006EE471E0CE0109960E94F4166AE471E015 +:102F6000CE0109960E94F41686E590E3A6E3B0E050 +:102F700089839A83AB83BC8384E690E09A878987B0 +:102F8000BE016F5F7F4FCE0109960E94AE16E7EC3F +:102F9000F0E007C09091C00095FFFCCF8093C60081 +:102FA000319684918111F6CFEAE5F4E007C0909163 +:102FB000C00095FFFCCF8093C600319684918111AB +:102FC000F6CF8091C00085FFFCCF8AE08093C600D9 +:102FD0002A960FB6F894DEBF0FBECDBFDF91CF911A +:102FE0001F910F910895EF92FF920F931F93CF932C +:102FF000DF938C017B0180E1E80EF11CEB01F8010D +:10300000808191819C012F5F3F4F318320830E94FB +:10301000B9778993CE15DF0591F780E190E0DF91D4 +:10302000CF911F910F91FF90EF900895EF92FF9233 +:103030000F931F93CF93DF938C017B0184E0E80E05 +:10304000F11CEB01F801808191819C012F5F3F4FC2 +:10305000318320830E94B9778993CE15DF0591F7DC +:1030600084E090E0DF91CF911F910F91FF90EF905E +:103070000895AF92BF92CF92DF92EF92FF920F939B +:103080001F93CF93DF93CDB7DEB7EC970FB6F894CD +:10309000DEBF0FBECDBFD82E24E630E03AAF29AF59 +:1030A00046E550E366E370E049AB5AAB6BAB7CABF3 +:1030B0008E010B5C1F4FB8017E0189E3E80EF11C05 +:1030C00089AD9AAD9C012F5F3F4F3AAF29AF6BAFEF +:1030D0007CAF0E94B977F80181938F016BAD7CAD15 +:1030E000EE15FF0569F7D110A4C043E050E0CE0112 +:1030F000C1960E948175009709F09BC063E77DE04F +:10310000C8010E94F31763E87DE0C8010E94F3172D +:1031100003E61DE089AD9AAD9C012F5F3F4F3AAFAA +:1031200029AF0E94B977F80181938F01FDE0033741 +:103130001F0781F76BE57DE0CE01C9960E94161846 +:1031400067E57DE0CE01C9960E9416186FE57DE027 +:10315000CE01C9960E94161867E47DE0CE01C9969B +:103160000E94161803E91DE089AD9AAD9C012F5FFE +:103170003F4F3AAF29AF0E94B977F80181938F0191 +:10318000FDE007391F0781F763E57DE0CE01C996B1 +:103190000E9416186FE47DE0CE01C9960E941618B1 +:1031A0006BE47DE0CE01C9960E94161809EE12E08C +:1031B00089AD9AAD9C012F5F3F4F3AAF29AF0E9476 +:1031C000B977F80181938F01F2E0053F1F0781F77E +:1031D00062E571E0CE01C9960E9416186EE471E0B6 +:1031E000CE01C9960E9416186AE471E0CE01C99614 +:1031F0000E941618E7ECF0E007C09091C00095FF20 +:10320000FCCF8093C600319684918111F6CFECE813 +:10321000F1E007C09091C00095FFFCCF8093C600FD +:10322000319684918111F6CF8091C00085FFFCCF4B +:10323000DDC080E1EBE5F1E0DE01919601900D92B9 +:103240008A95E1F780E1EBE6F1E0DE01519601902D +:103250000D928A95E1F780E1EBE7F1E0DE0111964E +:1032600001900D928A95E1F76E0181E2C80ED11CA2 +:1032700043E7E42E4DE0F42E8E010F5E1F4F63E80E +:103280007DE0AE014F5F5F4FE3E6AE2EEDE0BE2E78 +:1032900024E030E0F60181919191A191B1916F010B +:1032A000F70181939193A193B1937F01F8018191EB +:1032B0009191A191B1918F01FB0181939193A19380 +:1032C000B193BF01FA0181919191A191B191AF01A7 +:1032D000F50181939193A193B1935F01215031093D +:1032E000C9F680E090E0AAE7B4E480935B0D909388 +:1032F0005C0DA0935D0DB0935E0D8093570D909380 +:10330000580DA093590DB0935A0D10925F0D109265 +:10331000600D1092610D1092620D80E29EE4A0E0BB +:10332000B0E08093930D9093940DA093950DB0937E +:10333000960D1092470D1092480D1092490D109263 +:103340004A0D80E090E0A0E7B1E48093530D9093A4 +:10335000540DA093550DB093560D4DEC5CEC6CECF8 +:103360007EE340934F0D5093500D6093510D709339 +:10337000520D80934B0D90934C0DA0934D0DB09337 +:103380004E0D1092F1021092F2021092F30210927E +:10339000F4021092ED021092EE021092EF021092DF +:1033A000F0021092E9021092EA021092EB021092DF +:1033B000EC02E7ECF0E007C09091C00095FFFCCF75 +:1033C0008093C600319684918111F6CFEFE9F1E048 +:1033D00006C09091C00095FFFCCF8093C6008191FC +:1033E0008111F7CF8091C00085FFFCCF8AE08093E8 +:1033F000C600EC960FB6F894DEBF0FBECDBFDF91CE +:10340000CF911F910F91FF90EF90DF90CF90BF90E1 +:10341000AF9008952F923F924F925F926F927F925A +:103420008F929F92AF92BF92CF92DF92EF92FF92D4 +:103430000F931F93CF93DF93CDB7DEB7A6970FB649 +:10344000F894DEBF0FBECDBF87E40E943F0F8823F4 +:1034500009F40EC20E942B0F0E94F16E64307105B8 +:10346000D9F144F46230710521F15CF577FF17C0A2 +:103470000C94B7276A35710509F4A6C134F46C3190 +:10348000710511F00C94B7276AC06B35710509F40A +:103490009FC16C35710511F00C94B7279EC18091C6 +:1034A000E602811106C00E9462130E94AA140C94C5 +:1034B00047288091E602811104C00E94E51381E053 +:1034C00007C08091E602811107C00E94E51380E0E9 +:1034D0000E9435150C94472880E50E943F0F8823F1 +:1034E00039F00E942B0F0E94F66E6B017C0103C025 +:1034F000C12CD12C760183E50E943F0F882361F017 +:103500000E942B0F20E030E04AE754E40E945771FC +:103510000E94F66E6B017C010E94AC570E94FD2A4E +:103520004B015C018C0C9D1CAE1CBF1C0E94FD2A33 +:10353000609386057093870580938805909389052D +:1035400005C00E94FD5981E00E940F160E94FD2ACD +:10355000681579058A059B05A0F30C94B72780911F +:103560002C0190912D01A0912E01B0912F018093FB +:103570008A0590938B05A0938C05B0938D0580915F +:103580001A0190911B01909307038093060384E630 +:1035900090E090931B0180931A010E94FD2A609392 +:1035A000860570938705809388059093890581E04F +:1035B0000E9446518091F5029091F602A091F70287 +:1035C000B091F80280938E0590938F05A09390059B +:1035D000B09391058091F9029091FA02A091FB02BB +:1035E000B091FC028093920590939305A09394056B +:1035F000B09395058091FD029091FE02A091FF028B +:10360000B09100038093960590939705A093980539 +:10361000B09399058091010390910203A091030357 +:10362000B091040380939A0590939B05A0939C0509 +:10363000B0939D0510922C0110922D0110922E0135 +:1036400010922F0188E50E943F0F882311F090E02F +:103650000AC089E50E943F0F8111F9CF8AE50E94D7 +:103660003F0F91E098279093300191110C94BA2765 +:1036700088E50E943F0F81110C94BA278091300198 +:1036800081110C94C02789E50E943F0F81110C9491 +:10369000C0278091300181110C94C6278AE50E94D1 +:1036A0003F0F81110C94C62788E50E943F0F8823A5 +:1036B000D1F00E94340F672B682B692BA1F00E9478 +:1036C0002B0F2091E9023091EA024091EB025091D8 +:1036D000EC020E94A96D6093F5027093F60280934C +:1036E000F7029093F80289E50E943F0F8823D1F0FA +:1036F0000E94340F672B682B692BA1F00E942B0FBF +:103700002091ED023091EE024091EF025091F002D3 +:103710000E94A96D6093F9027093FA028093FB02F4 +:103720009093FC028AE50E943F0F8823D1F00E940B +:10373000340F672B682B692BA1F00E942B0F20916F +:10374000F1023091F2024091F3025091F4020E9492 +:10375000A96D6093FD027093FE028093FF02909327 +:10376000000321E033E04DEF52E069EF72E085EFB6 +:1037700092E00E94F74F80E00E94465180918A05B6 +:1037800090918B05A0918C05B0918D0580932C01B3 +:1037900090932D01A0932E01B0932F0180910603E9 +:1037A0009091070390931B0180931A010E94FD2AB8 +:1037B00060938605709387058093880590938905AB +:1037C0000E943F510C94B72710929E050C94B72786 +:1037D00081E080939E050C94B72785E40E943F0FFB +:1037E000811102C00E94AC5750E4C52E52E0D52E84 +:1037F00069EEE62E62E0F62E05EF12E0B12CF6013E +:1038000081916F010E943F0F882339F1F3E0BF12CD +:103810000CC00E942B0FF801608371838283938315 +:1038200081E093E00E94935018C00E942B0FF70193 +:1038300020813181428153810E94A96DF80160830A +:1038400071838283938321E033E04DEF52E069EF8F +:1038500072E085EF92E00E94F74FB394F4E0EF0E30 +:10386000F11C0C5F1F4F24E0B212C9CF0C94B72794 +:103870008DE40E943F0F882311F40C940A270E94C4 +:103880002B0F0E94F16E6237710509F45FC70CF0CF +:103890006FC06C31710509F46DC19CF5663171051D +:1038A00009F425C1ACF46231710509F45EC634F443 +:1038B0006131710511F00C94B727E2C064317105D4 +:1038C00009F4E4C06531710511F00C94B72709C102 +:1038D0006931710509F434C154F46731710509F493 +:1038E0000CC16831710511F00C94B72719C16A3108 +:1038F000710509F42BC16B31710511F00C94B727D8 +:1039000033C16435710509F430C6CCF46A327105EF +:1039100009F43BC254F46E31710509F460C16F3192 +:10392000710511F00C94B72798C16235710509F43F +:1039300015C66335710511F00C94B72712C66836A9 +:10394000710509F45FC254F46535710509F448C680 +:103950006C35710511F00C94B72758C6693671059E +:1039600009F4C6C26D36710511F00C94B72792C3E5 +:103970006E3C710511F40C94BB25D4F56C387105BF +:1039800009F4A2C2C4F46737710511F40C948824B9 +:1039900034F46337710511F00C94B727C9C6683742 +:1039A000710511F40C9482246937710511F00C949F +:1039B000B7270C9484246B3C710511F40C942125D9 +:1039C0005CF46E3B710509F42DC5693C710511F07D +:1039D0000C94B7270C94E7246C3C710511F40C94FB +:1039E0003D256D3C710511F00C94B7270C945D25B5 +:1039F000603931E0730711F40C94E62604F56D325A +:103A000091E0790711F40C94F82564F46C3D71058C +:103A100011F40C94D7256D3D710511F00C94B72766 +:103A20000C94E9256E32F1E07F0711F40C94D32653 +:103A30006F32714011F00C94B7270C94D726663F73 +:103A400031E0730711F40C94EE266CF4643F91E0BE +:103A5000790711F40C94E926653F714011F00C943C +:103A6000B7270C94EC26673FF1E07F0711F40C9424 +:103A7000F226673E734011F00C94B7270C94F5269C +:103A80005E985E9815985E980C94B727E3EFF2E085 +:103A900007C09091C00095FFFCCF8093C60031967F +:103AA00084918111F6CF8091C00085FFFCCF8AE020 +:103AB0008093C6008CE093E00E94C664E3E0F3E0EC +:103AC00007C09091C00095FFFCCF8093C60031964F +:103AD00084918111F6CF8091C00085FFFCCF0C94BA +:103AE000B4278CE093E00E9408650C94B7278CE023 +:103AF00093E00E94CE650C94B72700917405109155 +:103B000075050C5F1F4F6AE270E0C8010E946F7577 +:103B1000009719F0FC013197108241E0B80159C0BB +:103B20008CE093E00E94D2650E94FD2A609382059A +:103B30007093830580938405909385050C94B72733 +:103B40008CE093E00E94D9650C94B72780910E0316 +:103B5000882311F40C94B72783E50E943F0F81114D +:103B60000C94CC270C94B7278CE093E00E94096951 +:103B70000C94B72780917405909175056AE270E006 +:103B800004960E946F758C010097E1F020916E05FC +:103B900030916F0540E6429FC001439F900D112474 +:103BA0006EE470E086519C4F0E946F7560E270E099 +:103BB0000E946F7501969093750580937405F801C6 +:103BC0003197108260917405709175056C5F7F4F1D +:103BD00040E08CE093E00E94DE650C94B727809172 +:103BE0000E03882311F40C94B7278CE093E00E9415 +:103BF000C06A80917405909175056AE270E0049640 +:103C00000E946F758C010097E1F020916E05309154 +:103C10006F0540E6429FC001439F900D11246EE462 +:103C200070E086519C4F0E946F7560E270E00E94C8 +:103C30006F7501969093750580937405F80131971F +:103C4000108260917405709175056C5F7F4F8CE0F8 +:103C500093E00E94CD670C94B7270E94FD2A6093E1 +:103C60007E0570937F058093800590938105009178 +:103C70008205109183052091840530918505601B94 +:103C8000710B820B930B28EE33E040E050E00E9472 +:103C90005472CA01B9012CE330E040E050E00E94C8 +:103CA00054727F936F933F932F9380E991E09F939A +:103CB0008F93CE0101969F938F930E94B875E7EC86 +:103CC000F0E084910FB6F894DEBF0FBECDBFE7ECF5 +:103CD000F0E008C09091C00095FFFCCF8093C60033 +:103CE000319684918111F6CFFE01319606C09091F4 +:103CF000C00095FFFCCF8093C60081918111F7CF62 +:103D00008091C00085FFFCCF8AE08093C60080913F +:103D1000260D882311F40C94B7271092260D60917C +:103D2000E802E62FF0E0EE0FFF1FE050F24F808137 +:103D300091810E9431592091390130913A0140918D +:103D40003B0150913C010E948570181614F00C94B0 +:103D5000B7276091E802062F10E080E090E00E9413 +:103D60006158F801EE0FFF1FE050F24F91838083FE +:103D7000F801EE0FFF1FEE0FFF1FEA50F24F108207 +:103D80001182128213820C94B72783E50E943F0FA1 +:103D9000882311F40C94B7270E942B0F0E94F16E18 +:103DA0007B0180E50E943F0F882311F40C94B72714 +:103DB000F7FE02C00C94B727FFEFEF16F10409F0ED +:103DC00014F40C94DD270C94B727819191918017FE +:103DD000910711F40C94B72722E0E83BF207A9F70A +:103DE00017FF02C00C94B72761E0802F0E94252C9A +:103DF0006E2D802F0E94412CB701802F0E949A2B9C +:103E00000C94B7278091E80280939F0584E50E9477 +:103E10003F0F882379F10E942B0F0E94F66E60936A +:103E20009F05662339F1E7ECF0E007C09091C000F0 +:103E300095FFFCCF8093C600319684918111F6CF17 +:103E4000EDEBF1E006C09091C00095FFFCCF8093B0 +:103E5000C60081918111F7CF40E050E060919F054D +:103E600081EC95E00E94A82D8091C00085FFFCCFD9 +:103E70000C94B42783E50E943F0F882309F1B0908A +:103E80009F050E942B0F6B017C010B2D10E00E94FF +:103E9000F16EDC01CB016B2D0E946158F801EE0F31 +:103EA000FF1FE050F24F91838083F801EE0FFF1F58 +:103EB000EE0FFF1FEA50F24FC082D182E282F382FE +:103EC0000E94DE5C0C94B72783E50E943F0F882395 +:103ED00011F40C94B7270E942B0F0E94F16ECB01B6 +:103EE0000E94E5589093FF0D8093FE0D0C94B72728 +:103EF0008091E80280939F0584E50E943F0F88230C +:103F000079F10E942B0F0E94F66E60939F05662345 +:103F100039F1E7ECF0E007C09091C00095FFFCCFCD +:103F20008093C600319684918111F6CFE4EDF1E0E3 +:103F300006C09091C00095FFFCCF8093C600819190 +:103F40008111F7CF40E050E060919F0581EC95E052 +:103F50000E94A82D8091C00085FFFCCF0C94B4274F +:103F6000E1E1F3E007C09091C00095FFFCCF8093A2 +:103F7000C600319684918111F6CF60919F05E62F9E +:103F8000F0E0EE0FFF1FE450F24F808191810E941C +:103F90003159AB01BC0121E030E081EC95E00E9499 +:103FA000B92EE7E1F3E007C09091C00095FFFCCF88 +:103FB0008093C600319684918111F6CF60919F0560 +:103FC000E62FF0E0EE0FFF1FE050F24F808191816D +:103FD0000E943159AB01BC0121E030E081EC95E059 +:103FE0000E94B92EEAE1F3E007C09091C00095FF6E +:103FF000FCCF8093C600319684918111F6CF8091D9 +:10400000FA0D9091FB0D0E94EB5BAB01BC0121E02E +:1040100030E081EC95E00E94B92EEEE1F3E007C0BC +:104020009091C00095FFFCCF8093C600319684919B +:104030008111F6CF8091FE0D9091FF0D0E94EB5BF8 +:10404000AB01BC0121E030E081EC95E00E94B92E8B +:10405000E1E2F3E007C09091C00095FFFCCF8093B0 +:10406000C600319684918111F6CF80919F0590E032 +:104070000E945B584AE050E0BC0181EC95E00E9450 +:10408000C02D8091C00085FFFCCF8AE08093C600E0 +:104090000C9447288091E80280939F0584E50E9454 +:1040A0003F0F882371F10E942B0F0E94F66E6093E0 +:1040B0009F05662331F1E7ECF0E007C09091C00066 +:1040C00095FFFCCF8093C600319684918111F6CF85 +:1040D000EBEEF1E006C09091C00095FFFCCF80931D +:1040E000C60081918111F7CF40E050E060919F05BB +:1040F00081EC95E00E94A82D8091C00085FFFCCF47 +:1041000033C71092260D83E50E943F0F882309F1E3 +:10411000B0909F050E942B0F6B017C010B2D10E0CE +:104120000E94F16EDC01CB016B2D0E946158F801F9 +:10413000EE0FFF1FE050F24F91838083F801EE0FE6 +:10414000FF1FEE0FFF1FEA50F24FC082D182E282C2 +:10415000F38283E50E943F0F882351F00E942B0FCA +:104160006093390170933A0180933B0190933C0135 +:1041700082E40E943F0F882351F00E942B0F60932E +:104180003D0170933E0180933F019093400186E48E +:104190000E943F0F882369F00E942B0F6093350126 +:1041A00070933601809337019093380181E08093BA +:1041B000260D0E94DE5C0E94FD2A4B015C0180916D +:1041C0009F0590E0880F991FFC01E050F24F20817D +:1041D000318138A32F8FFC01E450F24F808191810F +:1041E0009EA38DA3CC24CA94DC2C7601E5E2F3E0F7 +:1041F0002490E8E2F3E03490ECE2F3E0049148EE3E +:10420000442E43E0542E612C712C1AE0F9C6822D05 +:10421000E5E2F3E008C09091C00095FFFCCF8093E9 +:10422000C600319684918111F6CF60919F05E62FEB +:10423000F0E0EE0FFF1FE450F24F808191810E9469 +:104240003159AB01BC0121E030E081EC95E00E94E6 +:10425000B92E832DE8E2F3E008C09091C00095FFED +:10426000FCCF8093C600319684918111F6CF609186 +:104270009F054AE050E070E081EC95E00E94C02D7F +:10428000802FECE2F3E008C09091C00095FFFCCFD6 +:104290008093C600319684918111F6CFF7FE03C05A +:1042A000E2E0F2E027C00E94FD2A4B015C01C70159 +:1042B000B601605F784D8F4F9F4F681979098A0961 +:1042C0009B09A30192010E94547249015A012AE0FC +:1042D00030E0B501A40181EC95E00E949C2D809115 +:1042E000C00085FFFCCF0DC09091C00095FFFCCFB2 +:1042F0008093C60081918111F7CF8091C00085FF26 +:10430000FCCF1093C6000E94FD2A4B015C010E9465 +:10431000FD5981E00E940F169FEFC916D906E906E4 +:10432000F906A9F560919F05EF8DF8A12DA13EA199 +:104330002E173F070CF07FC6E62FF0E0EE0FFF1FB1 +:10434000E450F24F808191810E94315969A37AA390 +:104350008BA39CA360919F05E62FF0E0EE0FFF1F5B +:10436000E050F24F808191810E94315920E030E08D +:1043700040E85FE30E94A86D9B01AC0169A17AA1AE +:104380008BA19CA10E94857087FF20C639C0F7FCD5 +:1043900037C060919F05E62FF0E0EE0FFF1FE4505D +:1043A000F24F808191810E94315969A37AA38BA336 +:1043B0009CA360919F05E62FF0E0EE0FFF1FE050F9 +:1043C000F24F808191810E9431599B01AC0169A11A +:1043D0007AA18BA19CA10E94A86D0E94F16EAB01F5 +:1043E000BC0177FF07C070956095509541955F4F70 +:1043F0006F4F7F4F44305105610571050CF0E6C5E4 +:104400003FEFC316D306E306F30609F4F9C5F7FC3C +:10441000E2C50E94FD2A6C197D096031774208F4DB +:10442000EFC5D9C583E50E943F0F882359F00E944C +:104430002B0F0E94F16ECB010E94E5589093FF0D67 +:104440008093FE0D0E94FD2A6B017C01E0E3F3E006 +:10445000A490E3E3F3E0B490E7E3F3E014910AE01F +:1044600070C00E94FD2A6C197D098E099F09693E62 +:1044700073408105910508F45FC06091E802A62FA2 +:10448000B0E0AA0FBB1FA450B24F8D919C910E9427 +:104490003159AB01BC018A2DE0E3F3E008C09091F3 +:1044A000C00095FFFCCF8093C600319684918111A6 +:1044B000F6CF22E030E081EC95E00E94B92E8B2D02 +:1044C000E3E3F3E008C09091C00095FFFCCF809338 +:1044D000C600319684918111F6CF6091E8024AE0DE +:1044E00050E070E081EC95E00E94C02D812FE7E361 +:1044F000F3E008C09091C00095FFFCCF8093C60008 +:10450000319684918111F6CF8091FA0D9091FB0D37 +:104510000E94EB5BAB01BC0121E030E081EC95E057 +:104520000E94B92E8091C00085FFFCCF0093C60089 +:104530000E94FD2A6B017C010E94FD5981E00E94CE +:104540000F162091FE0D3091FF0D8091FA0D909184 +:10455000FB0D821793070CF484CF47C510920B0311 +:1045600006C581E080930B0302C583E50E943F0FDF +:10457000882399F00E942B0F20E030E04AE754E4B2 +:104580000E9457710E94F66E609331017093320160 +:104590008093330190933401EAC488E50E943F0F71 +:1045A000811141C589E50E943F0F81113CC58AE513 +:1045B0000E943F0F811137C585E40E943F0F811192 +:1045C00032C52BC55E9A89E50E943F0F81115E9A24 +:1045D0008AE50E943F0F882309F4C9C4159AC7C40D +:1045E00083E50E943F0F0E942B0F20E030E04AE756 +:1045F00054E40E9457710E94F66E6093A005709378 +:10460000A1058093A2059093A305B1C420E432E0F4 +:104610003EA32DA353E7252E5DE0352E83E89DE0D4 +:1046200098A38F8F67E3862E6DE0962E10E0EDA1A4 +:10463000FEA18191FEA3EDA30E943F0F882309F400 +:1046400066C0133009F05CC00E942B0F6B017C0127 +:1046500020E030E040EA51E40E94826E87FF4AC0C9 +:10466000A7019601F10160817181828193810E948D +:10467000896E762EA72EB82E092F762F272F3A2D4A +:104680004B2D502F60914B0D70914C0D80914D0D25 +:1046900090914E0D0E94577160934B0D70934C0D8D +:1046A00080934D0D90934E0D272D3A2D4B2D502F6D +:1046B000EF8DF8A160817181828193810E94577191 +:1046C000EF8DF8A16083718382839383F40160810D +:1046D0007181828193810E94226F272D3A2D4B2D6B +:1046E000502F0E9457710E94F66EF401608371830F +:1046F00082839383F101C082D182E282F38207C078 +:104700000E942B0FF10160837183828393831F5F6B +:10471000F4E02F0E311C2F8D38A12C5F3F4F38A3B2 +:104720002F8F34E0830E911C143009F080CF1FC40A +:10473000EBE3F3E007C09091C00095FFFCCF8093BE +:10474000C600319684918111F6CF11C4E6EDF3E0F5 +:1047500007C09091C00095FFFCCF8093C6003196B2 +:1047600084918111F6CF4091F5025091F60260914B +:10477000F7027091F80222E030E081EC95E00E94AF +:10478000B92EE9EDF3E007C09091C00095FFFCCF92 +:104790008093C600319684918111F6CF4091F90241 +:1047A0005091FA026091FB027091FC0222E030E02D +:1047B00081EC95E00E94B92EECEDF3E007C09091FA +:1047C000C00095FFFCCF8093C60031968491811183 +:1047D000F6CF4091FD025091FE026091FF02709170 +:1047E000000322E030E081EC95E00E94B92EEFED6D +:1047F000F3E007C09091C00095FFFCCF8093C60006 +:10480000319684918111F6CF4091010350910203BA +:10481000609103037091040322E030E081EC95E0A5 +:104820000E94B92EE2EEF3E007C09091C00095FF20 +:10483000FCCF8093C600319684918111F6CF0E94FF +:1048400006580E94246F2091730D3091740D409191 +:10485000750D5091760D0E94896EAB01BC0122E06E +:1048600030E081EC95E00E94B92EECEEF3E007C059 +:104870009091C00095FFFCCF8093C6003196849143 +:104880008111F6CF81E00E9406580E94246F20918A +:10489000770D3091780D4091790D50917A0D0E94ED +:1048A000896EAB01BC0122E030E081EC95E00E9412 +:1048B000B92EEFEEF3E007C09091C00095FFFCCF5A +:1048C0008093C600319684918111F6CF82E00E94D8 +:1048D00006580E94246F20917B0D30917C0D4091F1 +:1048E0007D0D50917E0D0E94896EAB01BC0122E0CE +:1048F00030E081EC95E00E94B92E8091C00085FFE8 +:10490000FCCF32C380E001C081E00E9446512FC33A +:10491000E2EFF3E007C09091C00095FFFCCF8093D9 +:10492000C600319684918111F6CF329B03C0E7EB2C +:10493000F1E009C0EAEBF1E006C09091C00095FFFC +:10494000FCCF8093C60081918111F7CFE9EFF3E0AE +:1049500007C09091C00095FFFCCF8093C6003196B0 +:1049600084918111F6CF339B03C0E7EBF1E009C0DE +:10497000EAEBF1E006C09091C00095FFFCCF809378 +:10498000C60081918111F7CFE0E0F4E007C090917B +:10499000C00095FFFCCF8093C600319684918111B1 +:1049A000F6CF349B03C0E7EBF1E009C0EAEBF1E09E +:1049B00006C09091C00095FFFCCF8093C600819106 +:1049C0008111F7CF8091C00085FFFCCFCDC240E4BC +:1049D000E42E42E0F42E00E010E0F70181917F0127 +:1049E0000E943F0F882339F10E942B0F23E6C22E2D +:1049F0002DE0D22EC00ED11E0E94F66EF60160830D +:104A00007183828393830E942B0F37E3C32E3DE093 +:104A1000D32EC00ED11EF801ED58F24F2081318106 +:104A2000428153810E9457710E94F66EF6016083A5 +:104A30007183828393830C5F1F4F0031110569F6E8 +:104A400096C200E412E093E8E92E9DE0F92EF80109 +:104A500081918F010E943F0F882339F00E942B0F14 +:104A6000F7016083718382839383F4E0EF0EF11C7E +:104A700022E00434120759F77AC283E50E943F0FFF +:104A8000882351F00E942B0F60935B0D70935C0D97 +:104A900080935D0D90935E0D84E50E943F0F882307 +:104AA00009F465C20E942B0F6093570D7093580D47 +:104AB0008093590D90935A0D5AC283E50E943F0F7F +:104AC000882351F00E942B0F60935F0D7093600D4F +:104AD0008093610D9093620D84E50E943F0F8823BF +:104AE00051F00E942B0F6093470D7093480D8093F7 +:104AF000490D90934A0D82E40E943F0F882361F094 +:104B00000E942B0F0E94F66E6093930D7093940D8C +:104B10008093950D9093960D88E50E943F0F882312 +:104B200051F00E942B0F6093530D7093540D80939E +:104B3000550D9093560D8AE50E943F0F882351F042 +:104B40000E942B0F60934F0D7093500D8093510D69 +:104B50009093520D85E40E943F0F882309F407C209 +:104B60000E942B0F60934B0D70934C0D80934D0D55 +:104B700090934E0DFCC100E412E089EEE82E82E035 +:104B8000F82EF80181918F010E943F0F882339F0A0 +:104B90000E942B0FF7016083718382839383F4E07B +:104BA000EF0EF11C22E00334120759F7E0C183E550 +:104BB0000E943F0F882309F4DAC10E942B0F0E9444 +:104BC000F16E70931B0160931A0181E080930503DD +:104BD000CEC183E50E943F0F882309F4C8C10E941B +:104BE0002B0F0E94F16E7093190160931801BFC1E1 +:104BF00080E50E943F0F882351F00E942B0F6093A5 +:104C0000520170935301809354019093550189E4AC +:104C10000E943F0F882381F00E942B0F2DEB37E37A +:104C200046E05EE30E94577160934E0170934F011E +:104C3000809350019093510184E40E943F0F882398 +:104C400081F00E942B0F2DEB37E346E05EE30E94DC +:104C5000896E60934A0170934B0180934C0190934D +:104C60004D0183E40E943F0F882351F00E942B0FD7 +:104C700060934601709347018093480190934901E6 +:104C80000E944458E4E0F2E006C09091C00095FF15 +:104C9000FCCF8093C60081918111F7CFE7E0F2E06D +:104CA00006C09091C00095FFFCCF8093C600819113 +:104CB0008111F7CF409152015091530160915401FD +:104CC0007091550122E030E081EC95E00E94B92E10 +:104CD000EBE0F2E006C09091C00095FFFCCF80931E +:104CE000C60081918111F7CF2DEB37E346E05EE3FB +:104CF00060914E0170914F0180915001909151014E +:104D00000E94896EAB01BC0122E030E081EC95E0AD +:104D10000E94B92EEFE0F2E006C09091C00095FF2E +:104D2000FCCF8093C60081918111F7CF2DEB37E343 +:104D300046E05EE360914A0170914B0180914C0125 +:104D400090914D010E945771AB01BC0122E030E00F +:104D500081EC95E00E94B92EE3E1F2E006C090916B +:104D6000C00095FFFCCF8093C60081918111F7CFE1 +:104D70002DEB37E346E05EE3609146017091470119 +:104D800080914801909149010E945771AB01BC018B +:104D900022E030E081EC95E00E94B92E8091C000C5 +:104DA00085FFFCCFE1C081E00E94AD50E0C083E50B +:104DB0000E943F0F882319F00E942B0F04C060E06F +:104DC00070E086E193E40E94015DD1C00E94AC577F +:104DD000CEC00E941717CBC080E001C081E00E94C6 +:104DE0003918C5C00E94C10BC2C01092E602809162 +:104DF000A4059091A505A091A605B091A705809363 +:104E00007A0590937B05A0937C05B0937D050E9465 +:104E1000820FADC084E50E943F0F882309F463C070 +:104E20000E942B0F0E94F66E60939F05662391F1FE +:104E3000E7ECF0E007C09091C00095FFFCCF8093B5 +:104E4000C600319684918111F6CFE7E1F2E006C009 +:104E50009091C00095FFFCCF8093C6008191811195 +:104E6000F7CF40E050E060919F0581EC95E00E9413 +:104E7000A82DE9E1F2E006C09091C00095FFFCCFBB +:104E80008093C60081918111F7CF8091C00085FF8A +:104E9000FCCF6AC01092E802E7ECF0E007C0909106 +:104EA000C00095FFFCCF8093C6003196849181119C +:104EB000F6CFEAE2F2E006C09091C00095FFFCCF89 +:104EC0008093C60081918111F7CF6091E8024AE09A +:104ED00050E070E081EC95E00E94C02D8091C00010 +:104EE00085FFFCCF41C0E7ECF0E007C09091C00027 +:104EF00095FFFCCF8093C600319684918111F6CF47 +:104F0000E7E0F4E007C09091C00095FFFCCF8093EC +:104F1000C600319684918111F6CF80916E059091F3 +:104F20006F0520E6289FF001299FF00D1124E6511E +:104F3000FC4F06C09091C00095FFFCCF8093C60047 +:104F400081918111F7CFE9E1F4E007C09091C000B1 +:104F500095FFFCCF8093C600319684918111F6CFE6 +:104F60008091C00085FFFCCF8AE08093C6000E943C +:104F70005A0F8DC080E090E00E94140A0C943E1BF2 +:104F800081E090E00E94140A0C94491B82E090E0BA +:104F90000E94140A0C94541B0E94340FAB016093BE +:104FA000DC035093DD038093DE039093DF03BC01A9 +:104FB00089EB93E00E94D131DACF0E942B0F0E943F +:104FC000F16E8B01E4E4F2E00C94E51E0E94FD2AF0 +:104FD0006B017C0115CA0E94FD2A609382057093C3 +:104FE000830580938405909385050E94FD2A609334 +:104FF0008605709387058093880590938905B7CFC0 +:105000000E94FD2A681979098A099B09693E734043 +:105010008105910508F0FBC87AC90E94AC575E9AD9 +:105020000E941A58A4CF0E94AC5788E50E943F0FF7 +:105030008111C8CAC8CAE62FF0E0EE0FFF1FE45086 +:10504000F24F808191810E94315969A37AA38BA389 +:105050009CA360919F05E62FF0E0EE0FFF1FE0504C +:10506000F24F808191810E94315920E030E040E888 +:105070005FE30E94A96D9B01AC0169A17AA18BA19C +:105080009CA10E94826E18160CF0A0CFB9C9A696FA +:105090000FB6F894DEBF0FBECDBFDF91CF911F9149 +:1050A0000F91FF90EF90DF90CF90BF90AF909F90C7 +:1050B0008F907F906F905F904F903F902F900895CA +:1050C000CF93DF938091E6039091E703039714F465 +:1050D0000E94AE0F60E08CE093E00E94CC6980916A +:1050E000E6039091E703892B09F460C080910C03DB +:1050F000882309F443C080916E0590916F0520E6E6 +:10510000289FE001299FD00D1124C651DC4F6CE38C +:1051100072E0CE010E949E75892BB9F4BE018CE02D +:1051200093E00E945E69E7EAF1E007C09091C00059 +:1051300095FFFCCF8093C600319684918111F6CF04 +:105140008091C00085FFFCCF15C08CE093E00E94E9 +:10515000C06AEAEAF1E007C09091C00095FFFCCF79 +:105160008093C600319684918111F6CF8091C00062 +:1051700085FFFCCF8AE08093C60002C00E940A1A15 +:105180008091E6039091E70301979093E703809362 +:10519000E60380916E0590916F05019664E070E0E2 +:1051A0000E94407290936F0580936E050E94FD5996 +:1051B00081E00E940F16DF91CF910C94B050CF92F6 +:1051C000DF92EF92FF920F931F93CF93DF9300D064 +:1051D00000D0CDB7DEB740E052EC61E070E081EC8A +:1051E00095E00E94AA2CEAEDF0E007C09091C00083 +:1051F00095FFFCCF8093C600319684918111F6CF44 +:105200008091C00085FFFCCF8AE08093C60087ECC8 +:1052100090E0FC0107C03091C00035FFFCCF209327 +:10522000C600319624912111F6CF24B720FF14C077 +:10523000E0EEF0E007C04091C00045FFFCCF3093A6 +:10524000C600319634913111F6CF3091C00035FF50 +:10525000FCCF3AE03093C60021FF14C0E8EEF0E046 +:1052600007C04091C00045FFFCCF3093C600319687 +:1052700034913111F6CF3091C00035FFFCCF3AE0C8 +:105280003093C60022FF14C0E8EFF0E007C0409161 +:10529000C00045FFFCCF3093C600319634913111E8 +:1052A000F6CF3091C00035FFFCCF3AE03093C60016 +:1052B00023FF14C0E9E0F1E007C04091C00045FFC2 +:1052C000FCCF3093C600319634913111F6CF309136 +:1052D000C00035FFFCCF3AE03093C60025FF14C074 +:1052E000E9E1F1E007C03091C00035FFFCCF209329 +:1052F000C600319624912111F6CF2091C00025FFE0 +:10530000FCCF2AE02093C60014BEE9E2F1E007C01A +:105310003091C00035FFFCCF2093C6003196249118 +:105320002111F6CFE1E3F1E007C03091C00035FF75 +:10533000FCCF2093C600319624912111F6CF209105 +:10534000C00025FFFCCF2AE02093C600FC01249179 +:10535000E7ECF0E008C03091C00035FFFCCF2093AF +:10536000C600319624912111F6CFEBE3F1E007C09E +:105370003091C00035FFFCCF2093C60031962491B8 +:105380002111F6CFEBE4F1E007C03091C00035FF0A +:10539000FCCF2093C600319624912111F6CFE6E58B +:1053A000F1E007C03091C00035FFFCCF2093C6006C +:1053B000319624912111F6CFE2E6F1E007C0309159 +:1053C000C00035FFFCCF2093C600319624912111F7 +:1053D000F6CF2091C00025FFFCCF2AE02093C60025 +:1053E000FC018491E7ECF0E008C09091C00095FFCB +:1053F000FCCF8093C600319684918111F6CFE6E60A +:10540000F1E007C09091C00095FFFCCF8093C600EB +:10541000319684918111F6CF0E949C0E4AE050E0B3 +:10542000BC0181EC95E00E94C02DE5E7F1E007C0EA +:105430009091C00095FFFCCF8093C6003196849177 +:105440008111F6CF4AE050E060ED74E081EC95E028 +:105450000E94C02D8091C00085FFFCCF8AE0809320 +:10546000C60010926A0510926B0510926C0510929E +:105470006D0580E00E94391873E6C72E7DE0D72EB7 +:10548000E3E7EE2EEDE0FE2E07E31DE0F60161916D +:105490007191819191916F01F70121913191419128 +:1054A00051917F0129833A834B835C830E94226F51 +:1054B00029813A814B815C810E9457710E94F66E6E +:1054C000F80161937193819391938F01F3E7CF1664 +:1054D000FDE0DF06D9F60E94825C0E94CB430F906C +:1054E0000F900F900F90DF91CF911F910F91FF9030 +:1054F000EF90DF90CF900C9460570E945F2B0E943A +:10550000DF280E946028FDCF24E832E0FC013183CF +:1055100020832581222319F002960C94B832089535 +:10552000CF93DF93EC0185559F4F0E94842ACE01D3 +:1055300085599F4F0E94842ACE01825B9F4F0E9413 +:10554000842ACE01C1960E94842ACE014296DF9120 +:10555000CF910C94842A8CE093E00C94EA628CE066 +:1055600093E00C94902A1F920F920FB60F92112481 +:105570002F933F938F939F93AF93BF938091B805E1 +:105580009091B905A091BA05B091BB053091C005C5 +:10559000232F2D5F2D3720F40196A11DB11D05C0CD +:1055A000232F2A570296A11DB11D2093C005809379 +:1055B000B8059093B905A093BA05B093BB05809147 +:1055C000BC059091BD05A091BE05B091BF050196A7 +:1055D000A11DB11D8093BC059093BD05A093BE0590 +:1055E000B093BF05BF91AF919F918F913F912F9144 +:1055F0000F900FBE0F901F9018950F931F938FB7AA +:10560000F8940091B8051091B9052091BA05309130 +:10561000BB058FBFB801C9011F910F9108950F936A +:105620001F939FB7F8940091BC051091BD05209180 +:10563000BE053091BF0586B5A89B06C08F3F21F0FF +:105640000F5F1F4F2F4F3F4F9FBF322F212F102F24 +:105650000027080F111D211D311D42E0000F111FF1 +:10566000221F331F4A95D1F7B801C9011F910F912D +:105670000895CF92DF92EF92FF92CF93DF936B0169 +:105680007C010E940F2BEB010EC00E940F2B6C1BA4 +:105690007D0B683E734038F081E0C81AD108E108FC +:1056A000F108C851DC4FC114D104E104F10469F7D9 +:1056B000DF91CF91FF90EF90DF90CF900895789495 +:1056C00084B5826084BD84B5816084BD85B5826007 +:1056D00085BD85B5816085BDEEE6F0E080818160A5 +:1056E0008083E1E8F0E010828081826080838081A5 +:1056F00081608083E0E8F0E0808181608083E1EB7D +:10570000F0E0808184608083E0EBF0E08081816064 +:105710008083EAE7F0E0808184608083808182601A +:105720008083808181608083808180688083109203 +:10573000C10008951F93CF93DF93182FEB0161E011 +:105740000E94252C209711F460E004C0CF3FD105C2 +:1057500039F461E0812FDF91CF911F910C94412C9E +:10576000E12FF0E0E05FFC4EE491E330B9F028F483 +:10577000E13051F0E230B1F50CC0E63019F1E7301C +:1057800049F1E43079F514C084B5806884BDC7BDA3 +:105790002EC084B5806284BDC8BD29C080918000C0 +:1057A000806880938000D0938900C09388001FC0D8 +:1057B00080918000806280938000D0938B00C093A2 +:1057C0008A0015C08091B00080688093B000C093BB +:1057D000B3000DC08091B00080628093B000C09390 +:1057E000B40005C0C038D1050CF0B3CFADCFDF9108 +:1057F000CF911F910895833069F028F48130A1F092 +:10580000823011F514C08630B1F08730C1F0843099 +:10581000D9F404C0809180008F7703C0809180000C +:105820008F7D80938000089584B58F7702C084B502 +:105830008F7D84BD08958091B0008F7703C08091E3 +:10584000B0008F7D8093B000089590E0FC01E05D92 +:10585000FC4E2491FC01E05BFC4EE491EE2381F0D0 +:10586000F0E0EB58FC4EA491B0E09FB7F8948C9117 +:10587000611103C02095822301C0822B8C939FBFAE +:1058800008950F931F93CF93DF931F92CDB7DEB789 +:10589000A82FB0E0FD01E05FFC4E8491FD01E05DCA +:1058A000FC4E1491FD01E05BFC4E04910023B9F025 +:1058B000882321F069830E94FB2B6981E02FF0E0AF +:1058C000E059FC4EA491B0E09FB7F8948C9161111F +:1058D00003C01095812301C0812B8C939FBF0F9033 +:1058E000DF91CF911F910F9108951F920F920FB6E4 +:1058F0000F9211242F933F934F935F936F938F9346 +:105900009F93EF93FF936091C600209142063091E0 +:105910004306C90101968F7799274091440650911B +:1059200045068417950741F0F901EE53FA4F60835D +:105930009093430680934206FF91EF919F918F9140 +:105940006F915F914F913F912F910F900FBE0F90EC +:105950001F9018959A01AB01211581EE380741057A +:105960005105A9F42AC03093C5002093C40080914A +:10597000C10080618093C1008091C10088608093E4 +:10598000C1008091C10080688093C100089582E0C9 +:105990008093C00060E079E08DE390E00E94767231 +:1059A0002150310941095109CA01B90122E030E011 +:1059B00040E050E00E947672D6CF1092C00020E105 +:1059C00030E0D1CF80914406909145062091420667 +:1059D000309143062817390769F0FC01EE53FA4F5E +:1059E000208101968F7799279093450680934406EE +:1059F00030E002C02FEF3FEFC901089580914406C7 +:105A000090914506909343068093420608956F92C5 +:105A10007F928F929F92AF92BF92CF92DF92EF923E +:105A2000FF920F931F93CF93DF93CDB7DEB7A0976D +:105A30000FB6F894DEBF0FBECDBF8C0141155105E6 +:105A400061057105E1F420E030E040E350E060E002 +:105A500070E0A0960FB6F894DEBF0FBECDBFDF9109 +:105A6000CF911F910F91FF90EF90DF90CF90BF905B +:105A7000AF909F908F907F906F900C94AF2D662485 +:105A80006394712C6C0E7D1EC12CD12C7601822E5C +:105A9000912CA12CB12CCB01BA01A50194010E943B +:105AA0005472FA01D3016D933D01BFEFCB1ADB0AAB +:105AB000EB0AFB0AA901BF014115510561057105FA +:105AC00051F781E0C81AD108E108F1081AC0E1E0F5 +:105AD000F0E0EC0FFD1FEC0DFD1D8081482F8A309A +:105AE00010F4405D01C0495C50E060E070E020E0EF +:105AF00030E0C8010E94AF2DA1E0CA1AD108E10828 +:105B0000F108BFEFCB16DB06EB06FB0601F7A0960C +:105B10000FB6F894DEBF0FBECDBFDF91CF911F91BE +:105B20000F91FF90EF90DF90CF90BF90AF909F903C +:105B30008F907F906F9008952115310539F48091F1 +:105B4000C00085FFFCCF4093C60008950C94072D3C +:105B50009A01462F50E060E070E00C949C2D2115D6 +:105B6000310539F48091C00085FFFCCF4093C60019 +:105B700008952A30310511F40C94EC2D0C94072D66 +:105B80009A01AB01662757FD6095762F0C94AF2DD7 +:105B9000CF93DF93EC0120E030E04DE050E060E097 +:105BA00070E00E94AF2D20E030E04AE050E060E07D +:105BB00070E0CE01DF91CF910C94AF2DCF93DF93A6 +:105BC000EC019A01AB0160E070E00E949C2DCE01D7 +:105BD000DF91CF910C94C82DCF92DF92EF92FF927C +:105BE000CF93DF93EC016A017B0177FF10C020E0C7 +:105BF00030E04DE250E060E070E00E94AF2DF094A4 +:105C0000E094D094C094C11CD11CE11CF11C2AE08A +:105C1000B701A601CE01DF91CF91FF90EF90DF9009 +:105C2000CF900C94072D8F929F92AF92BF92CF92FC +:105C3000DF92EF92FF920F931F93CF93DF938C012C +:105C40004A015B01C22F20E030E0A901C501B40187 +:105C50000E94826E87FF0DC020E030E04DE250E0F0 +:105C600060E070E0C8010E94AF2DB7FAB094B7F8B9 +:105C7000B094D0E060E070E080E09FE307C020E0F7 +:105C800030E040E251E40E94896EDF5FDC13F7CF21 +:105C9000262F372F482F592FC501B4010E94A96D17 +:105CA000D62EE72EF82ED92F0E94F66E962EA72E0E +:105CB000B82EC92E0E94226F9B01AC016D2D7E2D46 +:105CC0008F2D9D2F0E94A86DD62FF72EE82ED92E4E +:105CD0002AE0492D5A2D6B2D7C2DC8010E94072DDD +:105CE000CC23C1F1EEE7F2E006C09091C00095FF31 +:105CF000FCCF8093C60081918111F7CF2BC020E0AB +:105D000030E040E251E46D2F7F2D8E2D9D2D0E94BD +:105D100057714B015C01792D9B2D0E94F16E6B0137 +:105D2000EE24D7FCE094FE2CB701A601C8010E9426 +:105D3000EC2DC701B6010E94246F9B01AC01682DB8 +:105D4000792D8A2D9B2D0E94A86DD62FF72EE82E37 +:105D5000D92EC150C111D3CFDF91CF911F910F9197 +:105D6000FF90EF90DF90CF90BF90AF909F908F907B +:105D700008950C94132ECF93DF93EC019C012C5FBC +:105D80003F4F41E050E060E070E0898D9A8D0E94C5 +:105D900084398823A1F04D895E896F89788D452BE0 +:105DA000462B472B71F44C815D816E817F814D8B39 +:105DB0005E8B6F8B788F89818068898302C080E0D9 +:105DC00001C081E0DF91CF910895CF92DF92EF92F1 +:105DD000FF921F93CF93DF93EC0149895A896B8916 +:105DE0007C89403E5F4F6F41710508F06DC00E9495 +:105DF000BB2E882309F468C00E948F37882309F4DA +:105E000063C0E98DFA8DCC80DD80EE80FF8032E0CA +:105E1000C31AD108E108F108058404C0CC0CDD1CCC +:105E2000EE1CFF1C0A94D2F746855785608971895C +:105E3000C40ED51EE61EF71E81E080934C06C0926C +:105E40004F08D0925008E0925108F092520880E03A +:105E500092E0EFE4F6E0DF019C011D92215030401A +:105E6000E1F711E011C0B701A601410F511D611DFD +:105E7000711D2FE436E080914D0690914E060E94F0 +:105E80005E6D882309F11F5FE98DFA8D84811817F3 +:105E900050F3C12C82E0D82EE12CF12C058404C0F3 +:105EA000CC0CDD1CEE1CFF1C0A94D2F749895A89E0 +:105EB0006B897C894C0D5D1D6E1D7F1D498B5A8B36 +:105EC0006B8B7C8B81E001C080E0DF91CF911F91D3 +:105ED000FF90EF90DF90CF900895CF93DF93EC0188 +:105EE00041E0611101C040E06C857D858E859F8514 +:105EF0000E94CA37882341F0288980E2289F9001B8 +:105F00001124215B394F02C020E030E0C901DF914C +:105F1000CF910895CF93FB0120E030E231932F5FC2 +:105F20002B30E1F7DC0130E0C7E01CC0CA3051F192 +:105F300038E0CAE017C0E21729F1FC010196E491AC +:105F4000E111F9CFC317F0F02132E0F02F37D0F490 +:105F5000FB01E30FF11D822F81568A3108F4205294 +:105F600020833F5FCD012D91211109C0FA0180836B +:105F7000918381E0FB019081903259F403C02F326C +:105F800019F4F4CF80E005C02E3281F28CEB96E05C +:105F9000D4CFCF9108950F931F93CF93DF93EC014C +:105FA0008B018B81882311F080E044C0FB0187893D +:105FB000803131F528C083E08B83F801428D538D09 +:105FC000648D758D4D8B5E8B6F8B788F9E012F5EF0 +:105FD0003F4FC8010E948438882331F31A8F098FFC +:105FE00081E089831C821D821E821F821886198689 +:105FF0001A861B861C861D861E861F86188A1AC056 +:10600000803291F6D8CF82E08B831D8A1E8A1F8A48 +:10601000188EFB01408D518D60E070E095E0440FDB +:10602000551F661F771F9A95D1F7498B5A8B6B8B3B +:106030007C8BD4CFDF91CF911F910F9108952F9238 +:106040003F924F925F926F927F928F929F92AF9208 +:10605000BF92CF92DF92EF92FF920F931F93CF9355 +:10606000DF9300D000D0CDB7DEB79C838B831A01BD +:10607000DC0113968C91811103C02FEF3FEFEEC02E +:10608000EB81FC81818180FFF8CFBCC01601201A12 +:10609000310A21015B018B819C8104969A8389835B +:1060A000ABC0AB81BC8118960D911D912D913C9197 +:1060B0001B97D901C8019170AA27BB273C01EB812E +:1060C000FC8143816801790159E0F694E794D79403 +:1060D000C7945A95D1F7818D928D423061F4DC01DD +:1060E0005A966D917D918D919C915D976C0D7D1D62 +:1060F0008E1D9F1D4BC0FC0194809A949C206114BE +:10610000710401F591101EC0012B022B032B59F4D1 +:10611000EB81FC8185899689A789B08D84839583DD +:10612000A683B7830FC0AB81BC8114964D915D915E +:106130006D917C91179729813A810E9403388823B9 +:1061400009F49BCFAB81BC815996ED91FC915A9794 +:1061500014966D917D918D919C9117976250710964 +:1061600081099109058404C0660F771F881F991F54 +:106170000A94D2F70685178520893189600F711F2F +:10618000821F931F690D711D811D911D20E032E05A +:106190002619370972012415350508F47901E1142F +:1061A000B2E0FB0609F054C000914F08109150086E +:1061B00020915108309152086017710782079307A8 +:1061C000D9F546C0C301815B994FA701BC01C50148 +:1061D0000E945B75AE0CBF1CEB81FC8100851185B4 +:1061E000228533850E0D1F1D211D311D008711874E +:1061F000228733874E185F084114510409F051CFAC +:1062000091012CC0EB81FC81C188D288E388F4889D +:1062100000851185228533852A01612C712C460168 +:106220005701801A910AA20AB30A481459046A0451 +:106230007B0408F02BCF2DCF9501AB01BC018091E1 +:106240004D0690914E060E943B6C8111C3CF15CF35 +:1062500040E00E94CA378111B5CF0FCFC9010F901E +:106260000F900F900F90DF91CF911F910F91FF90A2 +:10627000EF90DF90CF90BF90AF909F908F907F90E6 +:106280006F905F904F903F902F900895CF93DF9342 +:106290001F92CDB7DEB741E050E0BE016F5F7F4F88 +:1062A0000E941F30019719F4298130E002C02FEFBE +:1062B0003FEFC9010F90DF91CF9108950F931F9386 +:1062C000CF93DF938C01EB01FC018381823028F1B5 +:1062D00040855185628573854F71552766277727DD +:1062E000452B462B472BC9F440E250E0BE01C801C4 +:1062F0000E941F308032910521F0892B71F480E0DB +:106300000DC088818823D9F3853E71F38E3261F305 +:106310008B8583FDE9CF80E201C08FEFDF91CF91C4 +:106320001F910F910895CF92DF92EF92FF92CF933A +:10633000DF93EC018B81823018F420E030E029C03B +:10634000C884D984EA84FB8475E0F694E794D794F2 +:10635000C7947A95D1F78FE0C822DD24EE24FF247C +:10636000CE010E94463197FDE8CF488559856A8560 +:106370007B85415E5F4F6F4F7F4F488759876A87A4 +:106380007B87960165E0220F331F6A95E1F7215B59 +:10639000394FC901DF91CF91FF90EF90DF90CF90FF +:1063A00008958F929F92AF92BF92CF92DF92EF9219 +:1063B000FF920F931F93CF93DF93EC014A015B0190 +:1063C0002B81222309F475C089899A89AB89BC89FC +:1063D00084179507A607B70708F46BC06CC0811433 +:1063E0009104A104B10449F41C821D821E821F8203 +:1063F000188619861A861B865AC0088519852A852B +:106400003B85E98DFA8D858590E00996B901A80153 +:106410004150510961097109082E04C076956795AC +:10642000579547950A94D2F7CC24CA94DC2C760170 +:10643000C80CD91CEA1CFB1C04C0F694E794D79442 +:10644000C7948A95D2F7C416D506E606F70620F05B +:10645000012B022B032B49F44D895E896F89788DBE +:106460004C835D836E837F8316C0C41AD50AE60A07 +:10647000F70A11C04C815D816E817F819801898D01 +:106480009A8D0E94033891E0C91AD108E108F108F9 +:10649000811104C014C08E010C5F1F4FC114D104C0 +:1064A000E104F10439F788869986AA86BB8681E0E3 +:1064B00006C080E004C0223009F091CFF4CFDF9114 +:1064C000CF911F910F91FF90EF90DF90CF90BF90F1 +:1064D000AF909F908F9008950F931F93CF93DF936A +:1064E000EC018B818823E1F1898187FF33C061E072 +:1064F000CE010E946D2F8C01009791F1FC018081EB +:10650000853E71F18B81823040F449895A896B89CB +:106510007C89448F558F668F778F4D895E896F890F +:10652000788DF801538F428F758B648BE09146060E +:10653000F0914706309759F0B8016A5E7F4FC80165 +:1065400048960995F801808D918D938B828B898176 +:106550008F778983DF91CF911F910F910C948F37A3 +:1065600081E0888380E0DF91CF911F910F910895A2 +:10657000CF93DF93EC010E946C321B82DF91CF91AD +:106580000895FC01238121110C94B83208956F9273 +:106590007F928F929F92AF92BF92CF92DF92EF92B3 +:1065A000FF920F931F93CF93DF9300D000D0CDB70E +:1065B000DEB73C016A017B01FC018381813009F077 +:1065C00083C0818181FF80C081C0452B462B472B32 +:1065D00009F478C0F30180849184A284B384B70164 +:1065E000A601C3010E94D131811101C06DC0F30128 +:1065F000818D928DC114D104E104F10479F44589AF +:1066000056896789708D0E94953A882309F45CC089 +:10661000F301158A168A178A108E3AC0F301448155 +:106620005581668177819E012F5F3F4F0E9403381D +:10663000882309F449C049815A816B817C81F30127 +:10664000818D928DFC012789203139F4483FFFEF7D +:106650005F0761057105E0F407C0483F2FEF52075F +:1066600062072FE07207A0F40E94953A882361F137 +:10667000F30144815581668177810FEF1FEF2FEF82 +:106680003FE0818D928D0E94EC38811101C01CC0C9 +:10669000F301C18AD28AE38AF48A81818068818386 +:1066A000C3010E946C32882379F0B701A6018C14D3 +:1066B0009D04AE04BF0410F4B501A401C3010E94FF +:1066C000D13110C081E00EC080E00CC0F3014189DF +:1066D0005289638974894C155D056E057F0508F044 +:1066E00074CFF2CF0F900F900F900F90DF91CF915A +:1066F0001F910F91FF90EF90DF90CF90BF90AF90E0 +:106700009F908F907F906F900895CF93DF93EC01CF +:1067100040E050E0BA010E94C732882371F061E086 +:10672000CE010E946D2F009741F025EEFC012083E1 +:106730001B82DF91CF910C948F3780E0DF91CF9156 +:106740000895FF920F931F93CF93DF93EC01F42EE4 +:1067500080E2689FF0011124E15BF94F838581712C +:1067600021F0842F827109F05CC000914F081091D4 +:10677000500820915108309152080C871D872E87B0 +:106780003F87688B4489558960E070E0BA015527DE +:106790004427028D138D20E030E0402B512B622BDB +:1067A000732B4D8B5E8B6F8B788F8385887151F443 +:1067B000048D158D268D378D098B1A8B2B8B3C8B79 +:1067C00081E00CC0803169F59E012F5E3F4F898DBD +:1067D0009A8D0E948438882321F184E08B838F2D49 +:1067E0008F7089831C821D821E821F8218861986E3 +:1067F0001A861B86F4FE18C040E050E0BA01CE01B4 +:106800000E94C732811110C012C049895A896B8910 +:106810007C89CE01DF91CF911F910F91FF900C9455 +:10682000D1311B8280E003C0F5FCEFCF81E0DF9126 +:10683000CF911F910F91FF9008956F927F928F9249 +:106840009F92AF92BF92CF92DF92EF92FF920F93FF +:106850001F93CF93DF935C01EB014A01722E898D68 +:106860009A8DF501928F818F40E050E0BA01CE0100 +:106870000E94D131612C33C045E03695279517959C +:1068800007954A95D1F70F70CE010E949331DC0134 +:10689000009709F495C08C91882311F0853EB1F4DE +:1068A000611010C0C0904F08D0905008E09051087F +:1068B000F0905208F501C486D586E686F786008BEF +:1068C000662463948C9181110AC075C04BE050E03E +:1068D000BD01C4010E944E75009709F46FC0088580 +:1068E00019852A853B85C988DA88EB88FC880C15D0 +:1068F0001D052E053F0508F4BFCF5DC071FE60C0C9 +:10690000662051F0F501008961E0C5010E946D2FFC +:10691000EC01009771F454C08B81823009F450C0AF +:10692000CE010E94E52E882309F44AC0CFE4D6E0C8 +:1069300000E080E2FE0111928A95E9F78BE0F40114 +:10694000DE0101900D928A95E1F7E0914606F09103 +:106950004706309739F0BE01625F7F4FCE01409607 +:10696000099508C081E298E2998B888B80E098E0D5 +:106970009F878E87888999899B8B8A8B998F888F2F +:106980008E859F859F8B8E8B0E948F378823C1F0C9 +:10699000472D602FC501DF91CF911F910F91FF907F +:1069A000EF90DF90CF90BF90AF909F908F907F90AF +:1069B0006F900C94A13376FCA1CF02C077FEE8CF94 +:1069C00080E0DF91CF911F910F91FF90EF90DF90CA +:1069D000CF90BF90AF909F908F907F906F900895D1 +:1069E0005F926F927F928F929F92AF92BF92CF925F +:1069F000DF92EF92FF920F931F93CF93DF93CDB768 +:106A0000DEB7C354D1090FB6F894DEBF0FBECDBFB9 +:106A10005C016B0124965FAF4EAF2497522E1C8E03 +:106A20001F8E19821C826115710511F410E075C06A +:106A3000FC0183818111FACF2496EEADFFAD24973E +:106A400080818F3239F0760117C031962496FFAFDE +:106A5000EEAF24972496EEADFFAD249780818F3260 +:106A6000A1F3F60183818250823060F4ECCFEE24F2 +:106A7000E394F12CEC0EFD1E8E01045E1F4F4801C5 +:106A800038010CC0F601618D728DCE0101960E9415 +:106A9000CB2F8111ECCFCACF78018301AE014E5BC1 +:106AA0005F4FBE01695C7F4F24968EAD9FAD2497EA +:106AB0000E948A2F811106C0B9CF31962496FFAF6C +:106AC000EEAF24972496EEADFFAD249780818F32F0 +:106AD000A1F38823C9F021E0AE01495C5F4FB70103 +:106AE000C8010E941D34882309F4A0CFEC14FD04D2 +:106AF00019F0C7010E94B8320815190569F68E0110 +:106B00000F5F1F4F7301CACF252DAE01495C5F4F48 +:106B1000B701C5010E941D34182FCE0101960E94B5 +:106B2000C132CE014C960E94C132812FCD5BDF4F26 +:106B30000FB6F894DEBF0FBECDBFDF91CF911F918E +:106B40000F91FF90EF90DF90CF90BF90AF909F900C +:106B50008F907F906F905F9008951F93CF93DF93F6 +:106B6000CDB7DEB76B970FB6F894DEBF0FBECDBFC3 +:106B7000AB0119821C8222E0BC01CE0101960E9469 +:106B8000F034882331F0CE0101960E948533182F0E +:106B900001C010E0CE0101960E94C132812F6B9698 +:106BA0000FB6F894DEBF0FBECDBFDF91CF911F911E +:106BB00008952F923F924F925F927F928F929F9271 +:106BC000AF92BF92CF92DF92EF92FF920F931F93FB +:106BD000CF93DF9300D000D000D0CDB7DEB71C013B +:106BE000162F072F5E834D83DC0113968C9113972C +:106BF000813009F054C111968C9181FF50C155C16B +:106C0000F101418952896389748980859185A285C2 +:106C1000B38584179507A607B70729F4AD80BE8012 +:106C2000812E902E07C1C1010E94D1318111F6CF72 +:106C300036C1D10159968D919C915A97FC0174806F +:106C40007A94B701A601E9E076956795579547953F +:106C5000EA95D1F77422F1E0DF22EE24FF24260129 +:106C600071104AC0C114D10409F046C014964D9168 +:106C70005D916D917C9117974115510561057105E5 +:106C800061F455960D911D912D913C9158970115E8 +:106C900011052105310549F522C09E012F5F3F4FA7 +:106CA0000E940338882309F4FAC009811A812B81D4 +:106CB0003C81D1015996ED91FC915A978789803199 +:106CC00039F4083FBFEF1B072105310540F40DC023 +:106CD000083FEFEF1E072E07EFE03E0730F0C1013F +:106CE0000E94BB2E811108C0DAC0D10114960D9309 +:106CF0001D932D933C93179780E092E0841995099A +:106D000085018A159B0508F48C01D1015996ED91F6 +:106D1000FC915A971496CD90DD90ED90FC901797CA +:106D2000B2E0CB1AD108E108F108058404C0CC0C0C +:106D3000DD1CEE1CFF1C0A94D2F786859785A0897E +:106D4000B189C80ED91EEA1EFB1EC70CD11CE11C5E +:106D5000F11C0115E2E01E0731F580914F0890917A +:106D60005008A0915108B09152088C159D05AE05B0 +:106D7000BF0569F410924C068FEF9FEFDC01809302 +:106D80004F0890935008A0935108B0935208940173 +:106D9000B701A60180914D0690914E060E945E6D4E +:106DA000811137C07CC04114510419F5D1011896E6 +:106DB0004D915D916D917C911B9751968D919D9117 +:106DC0000D90BC91A02D481759076A077B0788F0E2 +:106DD0000E948F37882309F462C081E080934C06BB +:106DE000C0924F08D0925008E0925108F092520899 +:106DF00008C041E0C701B6010E94CA37882309F4E0 +:106E00004EC09201215B394FA801B401C9010E9413 +:106E10005B75F101C084D184E284F384C00ED11E7D +:106E2000E11CF11CC086D186E286F386800E911E9D +:106E3000A01AB10AF101C084D184E284F384A114C0 +:106E4000B10409F0F6CE01891289238934890C1521 +:106E50001D052E053F0530F4D101C18AD28AE38A8F +:106E6000F48A0BC08091460690914706892B59F011 +:106E7000ED81FE81EF2B39F0D10111968C911197A4 +:106E8000806811968C93F101818183FD03C02D816F +:106E90003E810EC0C1010E946C328111F8CF81E0A9 +:106EA000D1018C932FEF3FEF03C082FDA9CEB6CE68 +:106EB000C90126960FB6F894DEBF0FBECDBFDF9195 +:106EC000CF911F910F91FF90EF90DF90CF90BF90E7 +:106ED000AF909F908F907F905F904F903F902F90BA +:106EE0000895DB010D900020E9F7AD0141505109F3 +:106EF000461B570B02960C94D935CF93DF931F9204 +:106F0000CDB7DEB7698341E050E0BE016F5F7F4FD0 +:106F100002960E94D9350F90DF91CF91089580910C +:106F20004C068823A9F140914F0850915008609178 +:106F30005108709152082FE436E080914D069091EF +:106F40004E060E945E6D811102C080E0089540915E +:106F500048065091490660914A0670914B064115CA +:106F600051056105710591F02FE436E080914D06E1 +:106F700090914E060E945E6D882339F31092480668 +:106F80001092490610924A0610924B0610924C0637 +:106F900081E00895CF92DF92EF92FF92CF936B0141 +:106FA0007C01C42F80914F0890915008A091510806 +:106FB000B09152088C159D05AE05BF05D1F00E9419 +:106FC0008F37811102C080E018C02FE436E0B7018E +:106FD000A60180914D0690914E060E943B6C88233D +:106FE00091F3C0924F08D0925008E0925108F0926D +:106FF000520881E0C11180934C06CF91FF90EF9031 +:10700000DF90CF900895AF92BF92CF92DF92EF9230 +:10701000FF920F931F93CF93DF935C016A017B0173 +:10702000E901FC0141855285638574854F5F5F4F9F +:107030006F4F7F4F4C155D056E057F0510F480E0A6 +:1070400058C0FC018789803129F499278F2D7E2D26 +:107050006D2D0CC0803299F7C701B60127E09695D7 +:107060008795779567952A95D1F7F5010389148956 +:1070700025893689600F711F821F931F00914F0869 +:1070800010915008209151083091520860177107F3 +:107090008207930729F4F50187898031A1F406C09E +:1070A00040E00E94CA378111F6CFC9CFDD24EE241B +:1070B000FF24F601EE0FFF1FE15BF94F8081918104 +:1070C000A0E0B0E011C0E894C7F8DD24EE24FF246E +:1070D000F601EE0FFF1FEE0FFF1FE15BF94F8081FE +:1070E0009181A281B381BF7088839983AA83BB8376 +:1070F00081E0DF91CF911F910F91FF90EF90DF9092 +:10710000CF90BF90AF9008956F927F928F929F9291 +:10711000AF92BF92CF92DF92EF92FF920F931F93A5 +:10712000CF93DF9300D000D0CDB7DEB78C01498379 +:107130005A836B837C833901C12CD12C7601812C3D +:1071400042E0942EA12CB12C49815A816B817C8123 +:107150009E012F5F3F4FC8010E940338882341F1F1 +:10716000D501C401F801058404C0880F991FAA1F26 +:10717000BB1F0A94D2F7C80ED91EEA1EFB1E498116 +:107180005A816B817C818789803131F4483F5F4F20 +:107190006105710530F4D8CF483F5F4F6F4F7F4096 +:1071A00098F2F301C082D182E282F38281E001C0D1 +:1071B00080E00F900F900F900F90DF91CF911F9173 +:1071C0000F91FF90EF90DF90CF90BF90AF909F9086 +:1071D0008F907F906F9008956F927F928F929F9281 +:1071E000AF92BF92CF92DF92EF92FF920F931F93D5 +:1071F000CF93DF9300D0CDB7DEB73C014A015B01EE +:10720000423051056105710508F46CC0F3014185F8 +:107210005285638574854F5F5F4F6F4F7F4F481571 +:1072200059056A057B0508F45DC08789803129F41A +:10723000FF24EB2CDA2CC92C0DC0803209F052C08F +:107240007501640177E0F694E794D794C7947A9532 +:10725000D1F7F30183899489A589B689C80ED91E0F +:10726000EA1EFB1E41E0C701B60129833A830E9452 +:10727000CA3729813A818823A9F1F30187898031AE +:1072800059F49924AA24BB24F401EE0FFF1FE15BFB +:10729000F94F1183008310C0E89487F89924AA2439 +:1072A000BB24F401EE0FFF1FEE0FFF1FE15BF94F50 +:1072B0000083118322833383F3018289823080F03B +:1072C00085819681A781B0858C0D9D1DAE1DBF1D4A +:1072D0008093480690934906A0934A06B0934B06C4 +:1072E00081E001C080E00F900F90DF91CF911F915E +:1072F0000F91FF90EF90DF90CF90BF90AF909F9055 +:107300008F907F906F9008952F923F924F925F924F +:107310006F927F928F929F92AF92BF92CF92DF92A5 +:10732000EF92FF920F931F93CF93DF93CDB7DEB70A +:107330002F970FB6F894DEBF0FBECDBF1C014C8750 +:107340005D876E877F873B872A87DC0119964D9082 +:107350005D906D907C901C97BFEF4B1A5B0A6B0A97 +:107360007B0AF90180809180A280B380811491040E +:10737000A104B10431F0FFEF8F1A9F0AAF0ABF0AD0 +:1073800010C0DC018D909D90AD90BC90B1E0BD83AC +:107390002C853D854E855F852130310541055105A0 +:1073A00009F01D82750164011E821F8218861986EC +:1073B000F10181859285A385B4852E813F81488521 +:1073C0005985281739074A075B0708F052C04C1443 +:1073D0005D046E047F0450F4B2E0CB2ED12CE12C7E +:1073E000F12C12E0812E912CA12CB12C9E012F5F4B +:1073F0003F4FB701A601C1010E9403388823C9F19C +:1074000049815A816B817C81D701C6010196A11DFA +:10741000B11D452B462B472B19F04C015D010DC0CA +:1074200088199909AA09BB092C853D854E855F8578 +:1074300082179307A407B50789F08E819F81A885DD +:10744000B9850196A11DB11D8E839F83A887B98739 +:107450009FEFC91AD90AE90AF90AAACF0FEF1FEF5D +:107460002FEF3FE0A601B701C1010E94EC38811166 +:1074700015C080E041C044244A94542C32014C0C85 +:107480005D1C6E1C7F1C97018601B301A201C10126 +:107490000E94EC38882369F3730162018C149D0407 +:1074A000AE04BF0440F3AA85BB854D915D916D91FB +:1074B0007C91411551056105710551F4EA85FB8503 +:1074C00080829182A282B382FD81F11109C013C032 +:1074D00095018401C1010E94EC388111EFCFC9CF21 +:1074E0002FEF821A920AA20AB20AD1018D929D92BE +:1074F000AD92BC92139781E02F960FB6F894DEBF41 +:107500000FBECDBFDF91CF911F910F91FF90EF90F4 +:10751000DF90CF90BF90AF909F908F907F906F90B3 +:107520005F904F903F902F900895AF92BF92CF926F +:10753000DF92EF92FF920F931F93CF93DF9300D0D0 +:1075400000D0CDB7DEB75C016A017B0142E050E0BC +:1075500060E070E0FC0140835183628373839E018D +:107560002F5F3F4FB701A601C5010E94033881116B +:1075700002C080E023C000E010E09801B701A6013E +:10758000C5010E94EC388823A1F3C980DA80EB8022 +:10759000FC80F5018789803141F4F8EFCF16FFEFC9 +:1075A000DF06E104F10448F4DACF88EFC8168FEF64 +:1075B000D806E8068FE0F80690F281E00F900F9071 +:1075C0000F900F90DF91CF911F910F91FF90EF904F +:1075D000DF90CF90BF90AF9008958F929F92AF921F +:1075E000BF92CF92DF92EF92FF920F931F93CF93B0 +:1075F000DF93EC01142F70934E0660934D061F8AA3 +:1076000052E0C52ED12CE12CF12CC882D982EA821D +:10761000FB8210924C061092480610924906109276 +:107620004A0610924B06CC24CA94DC2C7601C092F8 +:107630004F08D0925008E0925108F092520844232B +:1076400059F1453008F0DDC040E060E070E0CB016A +:107650000E94CA37882309F4D4C020E1129FF001A8 +:107660001124E350F84F80818F7709F0CAC0C48499 +:10767000D584E684F78434E6C316D104E104F1042A +:1076800008F4BFC0C084D184E284F384C114D1045F +:10769000E104F10421F4B5C0C12CD12C760140E005 +:1076A000C701B6010E94CA37882309F4AAC0809195 +:1076B0005A0690915B068115924009F0A2C0209174 +:1076C0005F06222309F49DC080915D0690915E06BD +:1076D000009709F496C040915C06442309F491C0D8 +:1076E0002A8B4C831D8650E061E070E006C02E2F8F +:1076F0002F5F2D87E83008F084C0ED859B010E2EAA +:1077000002C0220F331F0A94E2F74217530779F79A +:1077100020916506309166062115310519F040E08B +:1077200050E008C0209173063091740640917506B0 +:10773000509176062D833E834F835887460157012B +:10774000880E991EA11CB11C8B8A9C8AAD8ABE8AA8 +:107750000091600610916106198F088FA0915F0655 +:10776000B0E00E941D72680D791D8A1D9B1D6A8FF5 +:107770007B8F8C8F9D8F980105E0220F331F0A9518 +:10778000E1F721503E4F232F33272695DC01CB0113 +:10779000820F931FA11DB11D8E879F87A88BB98B68 +:1077A00080906206909063068114910419F0A12CD8 +:1077B000B12C08C080906F0690907006A090710662 +:1077C000B0907206A7019601281B390B4A0B5B0B80 +:1077D000DA01C901880D991DAA1DBB1D04C0B6950B +:1077E000A79597958795EA95D2F789879A87AB876A +:1077F000BC87853F3FE09307A105B10520F48CE0ED +:107800008F8B80E016C0853F9F4FA105B10510F416 +:1078100080E10DC040917B0650917C0660917D0611 +:1078200070917E064A8F5B8F6C8F7D8F80E28F8B8D +:1078300081E0DF91CF911F910F91FF90EF90DF904A +:10784000CF90BF90AF909F908F9008952F923F92CE +:107850004F925F926F927F928F929F92AF92BF9260 +:10786000CF92DF92EF92FF920F931F93CF93DF930C +:10787000CDB7DEB7CA54D1090FB6F894DEBF0FBE3C +:10788000CDBF1C017E8B6D8B3A012BA30EA3E8A606 +:10789000AEAABFAAC8AED9AE34E0239F800111249E +:1078A000400F511F5BAB4AABDA018D909D90AD90BC +:1078B000BC90FC01E00FF11F208131814281538196 +:1078C000C501B4010E94A96D6AAF7BAF8CAF9DAFBB +:1078D000EEA1B4E0EB9F7001112493012E0D3F1D2A +:1078E0003DAB2CABD9014D905D906D907C90F1013A +:1078F000EE0DFF1D2081318142815381C301B20110 +:107900000E94A96D6EAF7FAF21968FAF219722960F +:107910009FAF2297E8A5B4E0EB9FC0011124F101CD +:10792000E80FF91F20813181428153812B8F3C8FD9 +:107930004D8F5E8FED89FE89E80FF91F608171819F +:10794000828193810E94A86D462F572F682F792F2F +:10795000498B5A8B6B8B7C8BAD89BE891C968D9124 +:107960009D910D90BC91A02D8AA79BA7ACA7BDA708 +:10797000D1011C962D913D914D915C911F972F8FB8 +:1079800038A349A35AA3B7FAB094B7F8B09477FADA +:10799000709477F87094ED89FE89E00FF11F7AAD4D +:1079A0006BAD9CAD8DAD272F362F492F582F6081A1 +:1079B0007181828193810E94A86D6F8B788F898FEE +:1079C0009DA3ED89FE89EE0DFF1D7EAD6FAD219665 +:1079D0009FAD219722968FAD2297272F362F492FC3 +:1079E000582F60817181828193810E94A86D162F2A +:1079F000072F382E292E7F89688D998D8DA1272FED +:107A0000362F492F582FC501B4010E9457716B01C1 +:107A10007C01B801C101272F362F492F582FC301F0 +:107A2000B2010E9457719B01AC01C701B6010E94CF +:107A3000A96D6B017C01B801C101272F362F492F99 +:107A4000582FC501B4010E9457716EA77FA788AB5C +:107A500099AB7F89688D998D8DA1272F362F492F5E +:107A6000582FC301B2010E9457719B01AC016EA552 +:107A70007FA588A999A90E94A86DA70196010E94D7 +:107A80001C6E362E272E182F092F20E030E0A9017A +:107A9000D101F8016B2F7A2F8F2F9E2F0E94826EBB +:107AA00087FF10C02BED3FE049EC50E4D101F80115 +:107AB0006B2F7A2F8F2F9E2F0E94A96D362E272E87 +:107AC000182F092FA4968FADA497882381F02BED52 +:107AD0003FE049EC50E4D101F8016B2F722D8F2F5C +:107AE000902F0E94A86D362E272E182F092FC98897 +:107AF000DA88EB88FC88E894F7F8A3962CAD3DADC6 +:107B00004EAD5FADA397D101F8016B2F722D8F2F72 +:107B1000902F0E945771A70196010E9492706B01ED +:107B20007C012FE632E143E85AE30E94826E87FD32 +:107B300016C2C701B6010E945F6F0E94F66E7A8F6F +:107B4000698FFB01EF2B21F421E030E03A8F298F80 +:107B5000498D5A8DBA0180E090E00E94226F6B013E +:107B60007C019B01AC01D101F8016B2F722D8F2F8D +:107B7000902F0E94896E6F8B788F1C01A701960150 +:107B800069897A898B899C890E94896E24966FAF56 +:107B9000249725967FAF259726968FAF2697279611 +:107BA0009FAF27972F8D38A149A15AA16AA57BA520 +:107BB0008CA59DA50E94A86DA70196010E94896EC3 +:107BC00028966FAF289729967FAF29972A968FAF6F +:107BD0002A972B969FAF2B9720E030E040E05FE3A1 +:107BE000BF89A88D6B2F7A2F822D932D0E945771FC +:107BF000BF89A88D2B2F3A2F422D532D0E945771EC +:107C00009B01AC0160E070E080E89FE30E94A86DFA +:107C10006DA37AA78EA723969FAF2397CE010196D7 +:107C2000FC01A8A554E0A59FE00DF11D11242B8DAA +:107C30003C8D4D8D5E8D20833183428353832F8D08 +:107C400038A149A15AA12D873E874F87588B198AA1 +:107C500041E050E05C8F4B8F81E090E08C0F9D1FE6 +:107C6000BBA1A4E0BA9F800D911D112499A788A7FC +:107C700021E030E02C0F3D1F5EA144E0549F200D19 +:107C8000311D11243FA32EA3FCA3EBA347C1898977 +:107C900089310CF050C07F89688D272F362F422DF7 +:107CA000532DC501B4010E9457716B017C017DA168 +:107CB0006AA59EA523968FAD2397272F362F492F90 +:107CC000582FC301B2010E9457719B01AC01C7013B +:107CD000B6010E94A96D7B018C017DA16AA59EA5BC +:107CE00023968FAD2397272F362F492F582FC50165 +:107CF000B4010E9457715B016C017F89688D272F49 +:107D0000362F422D532DC301B2010E9457719B01A2 +:107D1000AC016A2D7B2D8C2D9D2D0E94A86D862E89 +:107D2000972EA82EB92E99899F5F998B4E2C5F2C88 +:107D3000602E712E72C0AB8DBC8DBD0180E090E0D5 +:107D40000E94226FBF89A88D2B2F3A2F422D532DD1 +:107D50000E9457717B018C017F2D802F912F0E94F3 +:107D6000866E2B013C016E2D7F2D802F912F0E945E +:107D7000BA71698B7A8B8B8B9C8BEAA9FBA980816A +:107D80009181A281B3819C01AD0150582F8F38A3FE +:107D900049A35AA3ACA9BDA9CD90DD90ED90FC906C +:107DA000A30192016F8D78A189A19AA10E945771B8 +:107DB0004B015C0129893A894B895C89C701B6016D +:107DC0000E9457719B01AC01C501B4010E94A96DCD +:107DD000862E972EA82EB92E29893A894B895C893F +:107DE0006F8D78A189A19AA10E945771698B7A8BB6 +:107DF0008B8B9C8BA3019201C701B6010E94577126 +:107E00009B01AC0169897A898B899C890E94A86D44 +:107E1000462E572E682E792E198AA5019401BAADE7 +:107E2000ABADFCADEDAD6B2F7A2F8F2F9E2F0E9447 +:107E3000A96DE8A5F9A56083718382839383A3016B +:107E40009201BEADAFAD2196FFAD21972296EFAD69 +:107E500022976B2F7A2F8F2F9E2F0E94A96DAEA194 +:107E6000BFA16D937D938D939C93139724967FADC3 +:107E7000249725966FAD259726969FAD2697279632 +:107E80008FAD2797272F362F492F582FEBA1FCA115 +:107E900060817181828193810E94A96DABA1BCA197 +:107EA0006D937D938D939C93139728967FAD289720 +:107EB00029966FAD29972A969FAD2A972B968FAD5D +:107EC0002B97272F362F492F582F6D857E858F852D +:107ED00098890E94A96D6D877E878F87988BCE01C8 +:107EE00001960E94181494E6C92ED12CCC0EDD1EEA +:107EF000EEA8FFA808AD19AD9E01235F3F4FAE016C +:107F0000475F5F4FBE016B5F7F4FCE0101960E94BE +:107F10006845EB8DFC8D3196FC8FEB8F2B8D3C8D66 +:107F2000498D5A8D2417350708F4B1CE2D893E8925 +:107F3000245F3F4F4D895E89485F5F4F6D897E8921 +:107F40006C5F7F4F84E6C82ED12CCC0EDD1EEEA8D0 +:107F5000FFA808AD19AD8D899E890E946845C65B52 +:107F6000DF4F0FB6F894DEBF0FBECDBFDF91CF91CC +:107F70001F910F91FF90EF90DF90CF90BF90AF9047 +:107F80009F908F907F906F905F904F903F902F9039 +:107F900008952F923F924F925F926F927F928F92AD +:107FA0009F92AF92BF92CF92DF92EF92FF920F9388 +:107FB0001F93CF93DF93CDB7DEB768970FB6F894D2 +:107FC000DEBF0FBECDBF1C014A015B016801790114 +:107FD000DC01D8966D917D918D919C91DB970E94EB +:107FE000226F69837A838B839C83A50194010E940D +:107FF00057710E946F6E0E94F66E6D837E838F8331 +:108000009887A701960169817A818B819C810E9462 +:1080100057710E946F6E0E94F66E69877A878B8710 +:108020009C872D813E814F81588528373105410538 +:10803000510540F488E790E0A0E0B0E08D839E8396 +:10804000AF83B88729853A854B855C85283731050C +:108050004105510540F488E790E0A0E0B0E0898751 +:108060009A87AB87BC87F101EC5BFF4F4080518062 +:1080700062807380C301B2010E94246F6B017C0196 +:10808000D101DC966D917D918D919C91DF970E943D +:10809000226F6D877E878F87988B20E030E0A90163 +:1080A000C701B6010E94826E882339F129813A8185 +:1080B0004B815C81CA01B9010E9457714B015C017F +:1080C0002D853E854F855889CA01B9010E94577197 +:1080D0009B01AC01C501B4010E94A86D4B015C017C +:1080E000A7019601C701B6010E94A96D9B01AC01D1 +:1080F000C501B4010E94896E04C060E070E080E0B8 +:1081000090E00E946F6E0E94F16E4B015C01662749 +:108110007727CB0164197509860997090E94246F96 +:108120002B013C01F101E05CFF4F60817181828194 +:1081300093810E94226F698B7A8B8B8B9C8B20E0C2 +:1081400030E0A901C301B2010E94826E882379F157 +:1081500029893A894B895C89CA01B9010E94577102 +:108160006D8B7E8B8F8B988F29813A814B815C81BF +:10817000CA01B9010E9457719B01AC016D897E89CA +:108180008F89988D0E94A86D69837A838B839C83E5 +:10819000A3019201C301B2010E94A96D9B01AC0130 +:1081A00069817A818B819C810E94896E04C060E024 +:1081B00070E080E090E00E945F6FD10150962D91B9 +:1081C0003D914D915C91539729833A834B835C8316 +:1081D00029013A01481859086A087B080E94F16E83 +:1081E000461A570A680A790A77FE6CC020E030E028 +:1081F000A901C701B6010E94826E882309F445C017 +:10820000A7019601C701B6010E94A96D2B013C018F +:1082100069817A818B819C810E94226F9B01AC01D4 +:10822000C301B2010E9457712B013C012D853E858F +:108230004F855889CA01B9010E9457719B01AC0151 +:10824000C301B2010E94A86D2B013C0129893A8922 +:108250004B895C89CA01B9010E9457719B01AC012D +:10826000C301B2010E94A96D4B015C0120E030E026 +:1082700040E850E4C701B6010E9457719B01AC0170 +:10828000C501B4010E94896E04C060E070E080E026 +:1082900090E00E946F6E0E94F16E4B015C01B7FE90 +:1082A00003C0812C912C540129813A814B815C813E +:1082B00082169306A406B50610F049015A01412C16 +:1082C000512C32018FB7F894F101E45BFF4F90819C +:1082D000911125C0D10154968D929D92AD92BC9280 +:1082E0005797480C591C6A1C7B1CF101408E518E1B +:1082F000628E738E2D813E814F815885DC962D9341 +:108300003D934D935C93DF97A05CBF4F29853A85E1 +:108310004B855C852D933D934D935C9313978FBF55 +:1083200068960FB6F894DEBF0FBECDBFDF91CF9138 +:108330001F910F91FF90EF90DF90CF90BF90AF9083 +:108340009F908F907F906F905F904F903F902F9075 +:108350000895AF92BF92CF92DF92EF92FF920F9368 +:108360001F93CF93DF935B017A016115710509F4C7 +:1083700075C04115510509F471C0FB0102A513A593 +:10838000D4A5C5A5CE01202F312F492F582F66A186 +:1083900077A180A591A50E94826E882309F45EC012 +:1083A000F50187A981114BC0F701C6A0D7A0E0A4B1 +:1083B000F1A4A7019601DE01602F712F8B2F9A2F58 +:1083C0000E9485701816DCF5A7019601C701B60159 +:1083D0000E9457716B017C01F50182A993A9A4A9A0 +:1083E000B5A9BC01CD0190589B01AC010E94A96DBB +:1083F000F50126A537A540A951A90E9457719B01F7 +:10840000AC01C701B6010E94A86D0E94C4716B0146 +:108410007C01762F272F3D2D4E2D5F2DFE01602FE5 +:10842000712F8F2F9E2F0E94826E87FF03C06801DD +:10843000ED2EFC2E5C2D4D2D3E2D2F2D03C0502FEB +:10844000412F9E01852F942FA32FB22FF50186A3D4 +:1084500097A3A0A7B1A781E0F50186ABDF91CF91EB +:108460001F910F91FF90EF90DF90CF90BF90AF9052 +:108470000895CF92DF92EF92FF920F931F93CF93C5 +:10848000DF931F92CDB7DEB7809155088FB7F89470 +:10849000F09054088FBF8091550890E08F19910992 +:1084A0008F709927049704F12091550823502F705D +:1084B00040E050E000E010E08DE4E82E13C0211110 +:1084C00001C020E12150E29E6001112486E598E080 +:1084D000C80ED91EB801C60129830E94A941A8016E +:1084E000860129812F11EBCF0F90DF91CF911F9142 +:1084F0000F91FF90EF90DF90CF9008952F923F92D1 +:108500004F925F926F927F928F929F92AF92BF92A3 +:10851000CF92DF92EF92FF920F931F93CF93DF934F +:10852000EC011B01009709F464C08FA9811161C09F +:108530008EA09FA0A8A4B9A4FB01C6A0D7A0E0A4C8 +:10854000F1A42C2D3D2D4E2D5F2DC501B4010E94AF +:10855000826E87FF4EC0A5019401C501B4010E943F +:1085600057712B013C018AA89BA8ACA8BDA8C501E6 +:10857000B40190589B01AC010E94A96D2EA53FA5A6 +:1085800048A959A90E9457719B01AC01C301B201CE +:108590000E94A86D0E94C4718B01D82FC92F762F1D +:1085A000CE01272F312F492F582F6C2D7D2D8E2D49 +:1085B0009F2D0E94826E87FF03C08601DE2DCF2D86 +:1085C000CE01202F312F492F5C2F6C2D7D2D8E2D2C +:1085D0009F2D0E94826E882361F09E01802F912F33 +:1085E000A32FBC2FF10186A397A3A0A7B1A781E079 +:1085F00086ABDF91CF911F910F91FF90EF90DF90AD +:10860000CF90BF90AF909F908F907F906F905F9032 +:108610004F903F902F900895EF92FF920F931F93EA +:10862000CF93DF93F0905408C0E0D0E080E090E07A +:108630002DE4E22E11C0EF9C800111240A5A174F3D +:10864000A801BE010E947E428F2D8F5F803109F408 +:1086500080E0F82ECE01E80120915508F212EBCF10 +:1086600040E050E0BE01DF91CF911F910F91FF904C +:10867000EF900C947E424F925F926F927F928F9216 +:108680009F92AF92BF92CF92DF92EF92FF920F93A1 +:108690001F93CF93DF9350905408C0E0D0E03DE4A7 +:1086A000432E37C0489E3001499E700C112486E548 +:1086B00098E0680E791E209731F18EA9811104C0CF +:1086C000F30186A98823F9F0CAA0DBA0ECA0FDA0E5 +:1086D000A7019601F30166A177A180A591A50E944B +:1086E000896E4B015C01A70196016EA17FA188A54F +:1086F00099A50E94896EAB01BC0195018401CE0150 +:108700000E94C93F1EAA5394F0E15F1201C0512C90 +:10871000E301852D992787FD90952091550830E03C +:108720008217930709F0BECF2097F1F0CAA0DBA013 +:10873000ECA0FDA0A70196016DEC7CEC8CE49DE320 +:108740000E94896E4B015C01A70196016EA17FA179 +:1087500088A599A50E94896EAB01BC019501840191 +:10876000CE010E94C93F1EAADF91CF911F910F91A8 +:10877000FF90EF90DF90CF90BF90AF909F908F9041 +:108780007F906F905F904F9008950E9439420E94B1 +:108790000C430C943B43109255081092540880E10E +:1087A000E7E2FDE0DF011D928A95E9F71092970D4F +:1087B0001092980D1092990D10929A0D10929B0D97 +:1087C00010929C0D10929D0D10929E0D10929F0D77 +:1087D0001092A00D1092A10D1092A20D1092A30D57 +:1087E0001092A40D1092A50D1092A60D1092A70D37 +:1087F0001092A80D1092A90D1092AA0D08954F92F3 +:108800005F926F927F928F929F92AF92BF92CF9220 +:10881000DF92EF92FF920F931F93CF93DF9380919C +:10882000260D882309F41FC160E08091000E90910D +:10883000010E0E9431590091390110913A01D091F5 +:108840003B01C0913C0120E030E040E050E40E9458 +:10885000A96DFE01202F312F4F2F5E2F0E94826EB7 +:1088600087FD01C1F0905408B12CC12CD12CE12C12 +:108870004DE4A42E5CC02F2D30E0A29EF001A39EFB +:10888000F00D1124EA5AF74F80819181A281B381C2 +:10889000892B8A2B8B2B81F484819581A681B781CA +:1088A000892B8A2B8B2B41F480859185A285B385FA +:1088B000892B8A2B8B2BC1F1A29E4001A39E900C89 +:1088C000112486E598E0880E991EF401648575856B +:1088D000868597850E94246F2B013C01F4016089F5 +:1088E0007189828993890E94226F9B01AC01C30127 +:1088F000B2010E94896EF40122A133A144A155A1C5 +:108900000E9457713B014C012B2D3C2D4D2D5E2DAE +:10891000662D772D882D992D0E948570181624F4C8 +:10892000B62CC72CD82CE92CF394FFE0FF228091C1 +:108930005508F812A0CF20913501309136014091B1 +:108940003701509138016B2D7C2D8D2D9E2D0E946D +:1089500057719B01AC01FE01602F712F8F2F9C2F4F +:108960000E94A96D6B017C01CE01202F312F492F70 +:108970005C2F6C2D7D2D8E2D9F2D0E94826E87FD8C +:1089800003C08601DE2DCF2DC0903D01D0903E0169 +:10899000E0903F01F09040012C2D3D2D4E2D5F2D9C +:1089A000FE01602F712F8F2F9C2F0E94857018164B +:1089B0001CF06801ED2EFC2E8090AB0D9090AC0D5C +:1089C000A090AD0DB090AE0D2C2D3D2D4E2D5F2DF8 +:1089D000C501B4010E9485701816F4F420E037ED4B +:1089E00043EA5CE36C2D7D2D8E2D9F2D0E945771E7 +:1089F0008B01D82FC92F28E431EE4AE75FE3C50188 +:108A0000B4010E945771FE01202F312F4F2F5E2F8E +:108A10000E94A96D6B017C018C2D9D2DAE2DBF2D6B +:108A20008093AB0D9093AC0DA093AD0DB093AE0DB4 +:108A30006C2D7D2D8E2D9F2D0E94F16EDC01CB01C2 +:108A400060E00E9461589093010E8093000E8C2D7F +:108A50009D2DAE2DBF2D8093F60D9093F70DA09315 +:108A6000F80DB093F90DDF91CF911F910F91FF9009 +:108A7000EF90DF90CF90BF90AF909F908F907F90BE +:108A80006F905F904F900895909154088091550891 +:108A90009817D9F02091540830E04DE410C0429F5F +:108AA000F0011124EA5AF74F80859185A285B3859C +:108AB000892B8A2B8B2B09F03F5F2F5F2F708091C2 +:108AC00055082813ECCF311101C0159A0C94FF43BF +:108AD0002F923F924F925F926F927F928F929F92CE +:108AE000AF92BF92CF92DF92EF92FF920F931F93BC +:108AF000CF93DF93CDB7DEB7C357D1090FB6F89444 +:108B0000DEBF0FBECDBF2C013B014A0159013E2CF7 +:108B1000F9AA0AAB212EDDAACCAA209155082F5F15 +:108B200063962FAF6397203119F463961FAE639756 +:108B300063963FAD6397032F112707FD109505C07E +:108B40000E94FD5981E00E940F168091540890E028 +:108B500080179107A9F32091730D3091740D409106 +:108B6000750D5091760DD2016D917D918D919C91F5 +:108B70000E9457710E94277123966FAF2397249606 +:108B80007FAF249725968FAF259726969FAF269780 +:108B90002091770D3091780D4091790D50917A0D9B +:108BA000F30160817181828193810E9457710E94DB +:108BB000277127966FAF279728967FAF289729961A +:108BC0008FAF29972A969FAF2A9720917B0D3091DE +:108BD0007C0D40917D0D50917E0DD4016D917D9164 +:108BE0008D919C910E9457710E9427712B966FAFB7 +:108BF0002B972C967FAF2C972D968FAF2D972E9677 +:108C00009FAF2E9720917F0D3091800D4091810D67 +:108C10005091820DF50160817181828193810E9462 +:108C200057710E9427716AAF7BAF8CAF9DAF809167 +:108C3000330D9091340DA091350DB091360D2AADC4 +:108C40003BAD4CAD5DAD281739074A075B07C1F155 +:108C50006091E802E62FF0E0EE0FFF1FE450F24FC4 +:108C6000808191810E94315920E030E04AE253E452 +:108C70000E94826E87FF24C080915308811120C01A +:108C80000C94CD4F9091C00095FFFCCF8093C6000F +:108C9000319684918111F6CFE2EDF6E007C0909114 +:108CA000C00095FFFCCF8093C6003196849181115E +:108CB000F6CF8091C00085FFFCCF8AE08093C6008C +:108CC0008091330D9091340DA091350DB091360DFA +:108CD0002AAD3BAD4CAD5DAD281B390B4A0B5B0B90 +:108CE000CA01B90157FF07C09095809570956195AD +:108CF0007F4F8F4F9F4F0E94246F4B015C0120E0FC +:108D000030E848E953E460917F0D7091800D8091C7 +:108D1000810D9091820D0E9457719B01AC01C5019C +:108D2000B4010E94857018166CF58AAD9BADACAD90 +:108D3000BDAD8093330D9093340DA093350DB0935A +:108D4000360DECECF6E007C09091C00095FFFCCF2B +:108D50008093C600319684918111F6CFECEEF6E057 +:108D600007C09091C00095FFFCCF8093C60031965C +:108D700084918111F6CF8091C00085FFFCCF8AE0FD +:108D80008093C60080915508EDE48E9FD001112498 +:108D9000AA5AB74FBCA3ABA3FD01E45BFF4F1082FF +:108DA0002091270D3091280D4091290D50912A0DC9 +:108DB0002DA33EA34FA358A726964CAC5DAC6EAC3A +:108DC0007FAC2697421A530A640A750A77FE08C0D8 +:108DD0007094609450944094411C511C611C711C0F +:108DE000ABA1BCA14D925D926D927C9213972091A4 +:108DF0002B0D30912C0D40912D0D50912E0D29A74A +:108E00003AA74BA75CA72A968CAC9DACAEACBFAC86 +:108E10002A97821A930AA40AB50AB7FE08C0B0942A +:108E2000A09490948094811C911CA11CB11CABA1B6 +:108E3000BCA114968D929D92AD92BC9217972091F1 +:108E40002F0D3091300D4091310D5091320D2DA7E5 +:108E50003EA74FA758AB2E964CAD5DAD6EAD7FAD26 +:108E60002E978DA59EA5AFA5B8A9481B590B6A0BD7 +:108E70007B0B77FF07C070956095509541955F4FCC +:108E80006F4F7F4F142F052F6EAB78AFABA1BCA1F6 +:108E900018964C93189719965C9319971A966C9399 +:108EA0001A971B967C93C090330DD090340DE090B0 +:108EB000350DF090360DA0911801B09119012AAD31 +:108EC0003BAD4CAD5DAD2C193D094E095F0957FF17 +:108ED00007C050954095309521953F4F4F4F5F4FBC +:108EE0000E94287224E630E040E050E00E94767252 +:108EF000EBA1FCA12487358746875787812F902FC8 +:108F0000AEA9B8AD88159905AA05BB0514F4D5011D +:108F1000C40182179307A407B50714F4DA01C90145 +:108F200093018201481659066A067B0614F48C01E7 +:108F30009D01ABA1BCA150960D931D932D933C9325 +:108F40005397063011052105310510F40C94DD4FBF +:108F5000FD01E85BFF4F8091E70290E0A0E0B0E008 +:108F600080839183A283B38326962CAD3DAD4EAD15 +:108F70005FAD26978DA19EA1AFA1B8A5281739078F +:108F80004A075B072CF0ABA1BCA190961C9204C0D1 +:108F900081E0EBA1FCA180A32A962CAD3DAD4EADA6 +:108FA0005FAD2A9789A59AA5ABA5BCA52817390757 +:108FB0004A075B0744F4ABA1BCA190968C919097B3 +:108FC000826090968C932E962CAD3DAD4EAD5FADEC +:108FD0002E978DA59EA5AFA5B8A9281739074A07D2 +:108FE0005B0744F4ABA1BCA190968C9190978460F0 +:108FF00090968C932AAD3BAD4CAD5DAD2C153D05E7 +:109000004E055F0544F4ABA1BCA190968C9190975E +:10901000886090968C93ECA9FDA98081ABA1BCA13E +:1090200091968C9345284628472809F05E98EBA135 +:10903000FCA184819581A681B781892B8A2B8B2BFA +:1090400009F05E98EBA1FCA180859185A285B3858E +:10905000892B8A2B8B2B09F01598EBA1FCA1848519 +:109060009585A685B785892B8A2B8B2B09F05E9871 +:10907000ABA1BCA11C962D913D914D915C911F9788 +:1090800022962CAF3DAF4EAF5FAF2297232B242B00 +:10909000252BD9F44090470D5090480D6090490D14 +:1090A00070904A0D242D352D462D572DA9A9FAA9CA +:1090B000632D7A2F8F2F922D0E94826E87FD0EC016 +:1090C000432C59A86AA8722C09C040905F0D50909B +:1090D000600D6090610D7090620DE4CF26966CADCE +:1090E0007DAD8EAD9FAD26972DA13EA14FA158A578 +:1090F000621B730B840B950B0E94246F2091730DE0 +:109100003091740D4091750D5091760D0E94896ECD +:109110006DA379AB8AAB9CAB362F272F982F8CA9E8 +:10912000432F522F692F782F498B5A8B6B8B7C8B57 +:109130002A966CAD7DAD8EAD9FAD2A9729A53AA537 +:109140004BA55CA5621B730B840B950B0E94246FCF +:109150002091770D3091780D4091790D50917A0DD5 +:109160000E94896E162F072F89A79EAB9801982F12 +:109170008EA9432F522F692F782F4D8B5E8B6F8BCB +:10918000788F2E966CAD7DAD8EAD9FAD2E972DA5B3 +:109190003EA54FA558A9621B730B840B950B0E942B +:1091A000246F20917B0D30917C0D40917D0D50916D +:1091B0007E0D0E94896E6DA778AF382E292E362F2E +:1091C000272FC101432F522F692F782F498F5A8F94 +:1091D0006B8F7C8FA0901801B09019016AAD7BADA8 +:1091E0008CAD9DAD6C197D098E099F090E94246F7D +:1091F00020917F0D3091800D4091810D5091820D15 +:109200000E94896E6B017C01B501882777FD8095EE +:10921000982F0E94246F9B01AC01C701B6010E94E8 +:10922000577120E030E048EC52E40E94896E462FEE +:10923000572F682F792FDB01CA014D8F5E8F6F8FFB +:1092400078A3EBA1FCA180809180A280B380F6E09E +:109250008F169104A104B104E4F4EBA1FCA14481B4 +:1092600055816681778146305105610571058CF421 +:1092700040855185628573854630510561057105CC +:1092800044F4AC01BD017F7746A757A760AB71AB33 +:109290003AC05DA149A93AA92CA9652F742F832F43 +:1092A000922F0E9402726B017C01A80139A52EA9A0 +:1092B000652F702F832F922F0E9402729B01AC01A9 +:1092C000C701B6010E94A96D162F072FF82EE92EAF +:1092D0005DA548AD9101652F742F832F922D0E94BB +:1092E00002729B01AC01D801F7016B2F7A2F8F2FEF +:1092F0009E2F0E94A96D0E94C471EBA1FCA166A7DC +:1093000077A780AB91ABABA1BCA19E962D913D916F +:109310004D915C91D197AA962CAF3DAF4EAF5FAF08 +:10932000AA9760E070E080E89FE30E94896E9B014D +:10933000AC01642D752D862D972D0E94577169A75C +:109340007DA789AB9CAB9091550880915408E92F7B +:10935000F0E0E81BF109EF70FF27FBABEAAB762FDB +:109360006DA599A98CA9272F362F492F582F60E07A +:1093700074E284E799E40E94896E0E9427711B01C0 +:109380008C012AA93BA9223031050CF44AC069019D +:10939000EE24D7FCE094FE2CC701B6010E94246F96 +:1093A00020E030E040E051E40E94826E87FF39C047 +:1093B000210138018091930D9091940DA091950D0C +:1093C000B091960D481659066A067B0650F5BC0109 +:1093D000CD016419750986099709660F771F881FE3 +:1093E000991FA70196010E945472CA01B9010E94F7 +:1093F000226F0E942771AB01BC01CB01BA01640D41 +:10940000751D861D971D0E94226F9B01AC0160E0B7 +:1094100074E284E799E40E94896E69A77DA789AB0D +:109420009CAB79A56DA599A98CA9272F362F492F1B +:10943000582FAA966CAD7DAD8EAD9FADAA970E94B8 +:1094400057716E966FAF6E97A2967FAFA2972F96C9 +:109450008FAF2F97A6969FAFA697362F272F982FBF +:10946000A6968FADA697432F522F692F782FABA1C9 +:10947000BCA192964D935D936D937C939597509676 +:109480006D917D918D919C9153970E94226F6B01FC +:109490007C0179A56DA599A98CA9272F362F492F75 +:1094A000582FC701B6010E9457710E946F6E0E942B +:1094B000F66E67966CAF7DAF8EAF9FAF6797EBA1EF +:1094C000FCA160AF71AF82AF93AF9E012F5E3F4FA3 +:1094D0003FAB2EABAE014F5F5F4F5EA34DA383E862 +:1094E0009DE06D969FAF8EAF6D97DE019196BAA30A +:1094F000A9A359AF48AF212C312C00E81FE3EEA9F6 +:10950000FFA96191719181919191FFABEEABB9A5EA +:10951000ADA5F9A9ECA92B2F3A2F4F2F5E2F0E9452 +:109520005771AB01BC01A8ADB9AD4D935D936D937F +:109530007D93B9AFA8AFDB01CA01BF776B968CAF43 +:109540009DAFAEAFBFAF6B976D96AEADBFAD6D9734 +:109550004D905D906D907D906D96BFAFAEAF6D9765 +:10956000A30192016B966CAD7DAD8EAD9FAD6B97F7 +:109570000E9485701816F4F46B962CAD3DAD4EAD7F +:109580005FAD6B97C301B2010E94896E2B01782EEB +:10959000692E762FC301272F352D492F582F622D85 +:1095A000732D802F912F0E94826E87FD03C01201C0 +:1095B000072D162DEEA9FFA929A13AA1E217F3075D +:1095C00009F09DCF20E030E040E85FE3622D732D8D +:1095D000802F912F0E94826E87FF4FC03E0131E1A4 +:1095E000630E711C222D332D402F512FADA1BEA132 +:1095F0006D917D918D919C910E945771EDA1FEA17D +:109600006193719381939193FEA3EDA3E615F70502 +:1096100049F7222D332D402F512F6E96BFAD6E97F7 +:10962000A296AFADA2972F96FFAD2F97A696EFAD5E +:10963000A6976B2F7A2F8F2F9E2F0E945771ABA169 +:10964000BCA192966D937D938D939C93959767960D +:109650006CAD7DAD8EAD9FAD67970E94226F222DC0 +:10966000332D402F512F0E9457710E94F66EEBA1AF +:10967000FCA160AF71AF82AF93AFAA962CAD3DADA8 +:109680004EAD5FADAA97C701B6010E94896E162F35 +:10969000072F382E292E81149104A104B10491F5CD +:1096A000EBA1FCA184819581A681B781892B8A2BAE +:1096B0008B2B41F580859185A285B385892B8A2BDB +:1096C0008B2B01F52091570D3091580D4091590D7C +:1096D00050915A0DD801F1016B2F7A2F8F2F9E2FA9 +:1096E0000E9457710E946F6EEBA0FCA0F4E4EF0E95 +:1096F000F11C0E94F66ED7016D937D938D939C9320 +:10970000139700C120915B0D30915C0D40915D0D70 +:1097100050915E0DD801F1016B2F702F8F2F922D7C +:109720000E9457710E946F6E0E94F66EEBA1FCA121 +:10973000EC5BFF4FFEA3EDA3608371838283938371 +:109740004090370D5090380D6090390D70903A0D63 +:109750000E94226F69A77AA78BA79CA7C501B401B5 +:109760000E94246F9B01AC0169A57AA58BA59CA5DD +:109770000E945771A70196010E94896E4B015C01FE +:10978000C301B2010E94226F9B01AC01C501B4016B +:109790000E948570181634F4EDA1FEA1408251821A +:1097A0006282738240903B0D50903C0D60903D0D65 +:1097B00070903E0DADA1BEA16D917D918D919C915A +:1097C0000E94226F4B015C01EBA1FCA164817581B9 +:1097D000868197810E94246F9B01AC01C501B40171 +:1097E0000E945771A70196010E94896E4B015C018E +:1097F000C301B2010E94226F9B01AC01C501B401FB +:109800000E94857018163CF4ADA1BEA14D925D92E8 +:109810006D927C9213974090430D5090440D609050 +:10982000450D7090460DEBA1FCA1EC5BFF4FFEA334 +:10983000EDA360817181828193810E94226F4B012F +:109840005C0122966CAD7DAD8EAD9FAD22970E94DE +:10985000246F9B01AC01C501B4010E945771A7019F +:1098600096010E94896E4B015C01C301B2010E9406 +:10987000226F9B01AC01C501B4010E9485701816CE +:109880003CF4ADA1BEA14D925D926D927C92139776 +:1098900040903F0D5090400D6090410D7090420DF2 +:1098A000EDA1FEA160817181828193810E94226F6E +:1098B0004B015C01ABA1BCA118966D917D918D917E +:1098C0009C911B970E94246F9B01AC01C501B401C0 +:1098D0000E945771A70196010E94896E6B017C015D +:1098E000C301B2010E94226F9B01AC01C701B60106 +:1098F0000E948570181634F4EDA1FEA140825182B9 +:1099000062827382EBA1FCA1EC5BFF4F60817181ED +:10991000828193810E94226F6B017C01B801C10199 +:10992000272F302F492F522DC701B6010E94896E73 +:10993000462F572F682F792FE0964CAF5DAF6EAF53 +:109940007FAFE097ABA1BCA1D2964D935D936D9391 +:109950007C93D5972DEB37E346E051E4C701B60180 +:109960000E9457710E94F16EEBA1FCA1648F758F6C +:10997000868F978F4090530D5090540D6090550DE9 +:109980007090560D20E030E040E05FE3C301B2018B +:109990000E9457716DA379A78DA799AB29853A8548 +:1099A0004B855C85A1962CAF3DAF4EAF5FAFA197C5 +:1099B00080904F0D9090500DA090510DB090520D91 +:1099C00020E030E040E05FE3C501B4010E94577140 +:1099D000162F072FF82EE92EA1966CAD7DAD8EAD1A +:1099E0009FADA1979F77D801F7012B2F3A2F4F2FCB +:1099F0005E2F0E9485701816B4F4B801C701272F96 +:109A0000362F492F582FBDA1A9A5FDA5E9A96B2F78 +:109A10007A2F8F2F9E2F0E94826E87FD04C01DA378 +:109A200009A7FDA6E9AA8D859E85AF85B889A5966B +:109A30008CAF9DAFAEAFBFAFA597C0904B0DD09090 +:109A40004C0DE0904D0DF0904E0D20E030E040E0E8 +:109A50005FE3C701B6010E945771162F072F382EFA +:109A6000292EA5966CAD7DAD8EAD9FADA5979F7748 +:109A7000D801F1012B2F3A2F4F2F5E2F0E948570B6 +:109A80001816B4F4B801C101272F362F492F582FCB +:109A9000BDA1A9A5FDA5E9A96B2F7A2F8F2F9E2F18 +:109AA0000E94826E87FD04C01DA309A73DA629AAB6 +:109AB000ABA1BCA19296BC91BCABEBA1FCA1F3A164 +:109AC000FEABABA1BCA19496BC91B8AFEBA1FCA13D +:109AD000F5A1FEAF7CA96EA9272F362F4B2F5F2F44 +:109AE000BDA1A9A5FDA5E9A96B2F7A2F8F2F9E2FC8 +:109AF0000E94826E87FD08C02CA92DA33EA939A71C +:109B000048AD4DA75EAD59AB8AA99BA902970CF44D +:109B100043C19091A70D9AABA091A80D6496AFAFE9 +:109B20006497B091A90D6896BFAF6897E091AA0DB0 +:109B30006C96EFAF6C9727E137EB41ED58E36896F1 +:109B4000FFAD6897692F7A2F8F2F9E2F0E94857007 +:109B500018160CF021C12091970D3091980D40916D +:109B6000990D50919A0D69817A818B819C810E9417 +:109B7000A86D162F072F382E292E20919B0D30917E +:109B80009C0D40919D0D50919E0D6D817E818F8128 +:109B900098850E94A86D2F966FAF2F97A6967FAFDE +:109BA000A697AB968FAFAB97AC969FAFAC97B8012B +:109BB000C101272F362F492F582FD801F1016B2FC4 +:109BC0007A2F8F2F9E2F0E945771E4966CAF7DAF36 +:109BD0008EAF9FAFE4972F967FAD2F97A6966FAD70 +:109BE000A697AB969FADAB97AC968FADAC97272F52 +:109BF000362F492F582FDB01FC016B2F7A2F8F2F27 +:109C00009E2F0E9457719B01AC01E4966CAD7DAD17 +:109C10008EAD9FADE4970E94A96D0E94C4716296BB +:109C20006CAF7DAF8EAF9FAF6297A30192010E9490 +:109C3000857018166CF462962CAD3DAD4EAD5FADDF +:109C40006297C301B2010E94896E8B011C0106C09C +:109C500000E010E050E8252E6FE3362E20919F0D96 +:109C60003091A00D4091A10D5091A20DA1966CAD27 +:109C70007DAD8EAD9FADA1970E94A86D2B013C01DB +:109C8000E89477F8A5019401C301B2010E948570A0 +:109C90001816D4F4A3019201C501B4010E94896E83 +:109CA0004B01B82EA92E762FC501272F392D492F0C +:109CB000582F602F712F822D932D0E94826E87FD69 +:109CC00003C084012B2C3A2C2091A30D3091A40DBC +:109CD0004091A50D5091A60DA5966CAD7DAD8EADB4 +:109CE0009FADA5970E94A86D4B015C01E894B7F861 +:109CF000A7019601C501B4010E9485701816D4F41D +:109D0000A5019401C701B6010E94896E6B01F82E6E +:109D1000E92E762FC701272F3D2D492F582F602F71 +:109D2000712F822D932D0E94826E87FD03C08601C4 +:109D30002F2C3E2C202F312F422D532DBCA9AEA904 +:109D4000F8ADEEAD6B2F7A2F8F2F9E2F0E9457719B +:109D50004B015C01762F272F392D4A2D5B2DBAA997 +:109D60006496AFAD64976896FFAD68976C96EFAD5B +:109D70006C976B2F7A2F8F2F9E2F0E94826E87FFFA +:109D80000FC08AA864969FAC64976896AFAC68973A +:109D90006C96BFAC6C9704C08DA099A4ADA4B9A873 +:109DA000482D592D6A2D7B2DABA1BCA19A964D93C0 +:109DB0005D936D937C939D97E0966CAD7DAD8EAD7C +:109DC0009FADE09790589B01AC010E94A96DAA96A7 +:109DD0002CAD3DAD4EAD5FADAA970E9457719B0172 +:109DE000AC016BE077ED83E29BE30E94A86D0E94DB +:109DF000C4718B01F82EE92E762FC701272F312F42 +:109E0000492F582F682D792D8A2D9B2D0E94826E07 +:109E100087FD03C04801AF2CBE2C482D592D6A2D5B +:109E20007B2DEBA1FCA146A357A360A771A7C70197 +:109E3000202F312F492F5E2DBCA9AEA9F8ADEEAD74 +:109E40006B2F7A2F8F2F9E2F0E94826E181634F060 +:109E500081E0ABA1BCA1D7968C9303C0EBA1FCA180 +:109E600017AA81E0ABA1BCA1D6968C9380E1FE013C +:109E70003196A7E9BDE001900D928A95E1F73CA9E2 +:109E80002EA998AD8EAD432F522F692F782F409376 +:109E9000A70D5093A80D6093A90D7093AA0D232FC1 +:109EA000352F492F582FBDA1A9A5FDA5E9A96B2FD5 +:109EB0007A2F8F2F9E2F0E94896E6B017C017CA9C7 +:109EC0006EA998AD8EAD272F362F492F582F682DAC +:109ED000792D8A2D9B2D0E94896EAB01BC019701C3 +:109EE00086018BA19CA10E94C93F6396BFAD639779 +:109EF000B093550826962CAD3DAD4EAD5FAD26977F +:109F00002093270D3093280D4093290D50932A0D4F +:109F10002A968CAD9DADAEADBFAD2A9780932B0D2B +:109F200090932C0DA0932D0DB0932E0D2E962CAD4D +:109F30003DAD4EAD5FAD2E9720932F0D3093300D7C +:109F40004093310D5093320D8AAD9BADACADBDAD9C +:109F50008093330D9093340DA093350DB093360D4F +:109F60000E94C543CD58DF4F0FB6F894DEBF0FBE39 +:109F7000CDBFDF91CF911F910F91FF90EF90DF90B8 +:109F8000CF90BF90AF909F908F907F906F905F9099 +:109F90004F903F902F900C9449512AAD3BAD4CAD62 +:109FA0005DAD2093330D3093340D4093350D5093B8 +:109FB000360DECECF6E00C944946CD58DF4F0FB669 +:109FC000F894DEBF0FBECDBFDF91CF911F910F91EF +:109FD000FF90EF90DF90CF90BF90AF909F908F90C9 +:109FE0007F906F905F904F903F902F900895EF92E9 +:109FF000FF920F931F93CF93DF937B018A01E901B7 +:10A000002091730D3091740D4091750D5091760D26 +:10A01000FC0160817181828193810E9457710E944D +:10A020002771E7E2FDE0608371838283938320914F +:10A03000770D3091780D4091790D50917A0DF7019F +:10A0400060817181828193810E9457710E94277182 +:10A05000EBE2FDE0608371838283938320917B0D2B +:10A0600030917C0D40917D0D50917E0DF801608105 +:10A070007181828193810E9457710E942771EFE262 +:10A08000FDE0608371838283938320917F0D309103 +:10A09000800D4091810D5091820D688179818A8176 +:10A0A0009B810E9457710E942771E3E3FDE060836A +:10A0B0007183828393839F014FE25DE06BE27DE0D9 +:10A0C00087E29DE00E94B9571092A70D1092A80D4B +:10A0D0001092A90D1092AA0D1092970D1092980D42 +:10A0E0001092990D10929A0D10929B0D10929C0D4A +:10A0F00010929D0D10929E0D10929F0D1092A00D2A +:10A100001092A10D1092A20D1092A30D1092A40D09 +:10A110001092A50D1092A60DDF91CF911F910F9176 +:10A12000FF90EF90089520917F0D3091800D409128 +:10A13000810D5091820DFC0160817181828193813A +:10A140000E9457710E942771E3E3FDE060837183F1 +:10A1500082839383CF010C94F5578093530808951D +:10A160008091C10D811188C08091C00D811184C082 +:10A170008091BF0D811180C008959091C00095FF1E +:10A18000FCCF8093C600319684918111F6CFE0E137 +:10A19000F7E007C09091C00095FFFCCF8093C60008 +:10A1A000319684918111F6CF8091C10D8823D1F031 +:10A1B0006091C20D7091C30D8091C40D9091C50D39 +:10A1C0000E94246F2091730D3091740D4091750D94 +:10A1D0005091760D0E94896EAB01BC018FE197E032 +:10A1E0000E948B0B8091C00D8823D1F06091C60D29 +:10A1F0007091C70D8091C80D9091C90D0E94246F78 +:10A200002091770D3091780D4091790D50917A0D14 +:10A210000E94896EAB01BC0183E297E00E948B0B28 +:10A220008091BF0D8823D1F06091CA0D7091CB0D44 +:10A230008091CC0D9091CD0D0E94246F20917B0DCB +:10A2400030917C0D40917D0D50917E0D0E94896E64 +:10A25000AB01BC0187E297E00E948B0B8091C000AC +:10A2600085FFFCCF8AE08093C6001092C10D10924A +:10A27000C00D1092BF0D0895EAE0F7E085CF10926F +:10A28000C10D1092C00D1092BF0D0895809345012D +:10A290000895EFE6F0E080818260808308951F9248 +:10A2A0000F920FB60F9211240F931F932F933F938A +:10A2B0004F935F936F937F938F939F93AF93BF93CE +:10A2C000EF93FF938091D20D9091D30D892B09F0DC +:10A2D0007DC19091550880915408981771F0E091D4 +:10A2E00054088DE4E89FF0011124EA5AF74FDF018A +:10A2F000A45BBF4F81E08C9302C0E0E0F0E0F093FC +:10A30000D30DE093D20D309709F45AC1DF01A45B5D +:10A31000BF4F81E08C931092D40D1092D50D109206 +:10A32000D60D1092D70D60AD71AD61349CE97907FF +:10A3300028F461329EE4790748F002C060E47CE9C9 +:10A34000769567957695679584E007C0613197E2C9 +:10A35000790730F07695679582E08093D80D07C035 +:10A360008093D80D6032710510F460E270E06052A5 +:10A370007109611588E07807D0F0872F9927880F39 +:10A38000991F880F991F855D984FFC013296459162 +:10A390005491AA27659F9001649F210D3A1F06944E +:10A3A0002A1F3A1F1124FC01859194911DC09B0125 +:10A3B000369527952C7F255D344FF9018591949131 +:10A3C0002E5F3F4FF90145915491FB01E770FF2744 +:10A3D0004E9F90014F9F300D5E9F300D112413E072 +:10A3E000369527951A95E1F7821B930B84369105D4 +:10A3F000A0F4EAE8F2E006C09091C00095FFFCCF1F +:10A400008093C60081918111F7CF4AE050E081EC42 +:10A4100095E00E94DE2D84E690E09093DA0D809323 +:10A42000D90DE091D20DF091D30D64AD75AD70935F +:10A43000DC0D6093DB0D61349CE9790728F461320F +:10A440008EE4780748F002C060E47CE97695679571 +:10A450007695679584E007C0613197E2790730F01F +:10A460007695679582E08093D80D08C081E080934F +:10A47000D80D6032710510F460E270E0605271092D +:10A48000611588E07807E0F0872F9927880F991FDA +:10A49000880F991F855D984FFC0132962591349164 +:10A4A000AA27639FA001629F410D5A1F06944A1F6D +:10A4B0005A1F1124FC0125913491241B350B1EC019 +:10A4C000CB01969587958C7F855D944FFC012591F6 +:10A4D00034910296FC0145915491FB01E770FF27EE +:10A4E0004E9FC0014F9F900D5E9F900D112443E041 +:10A4F000969587954A95E1F7281B390B2436310547 +:10A50000A0F4EAE8F2E006C09091C00095FFFCCF0D +:10A510008093C60081918111F7CF4AE050E081EC31 +:10A5200095E00E94DE2D24E630E0C901A0E0B0E015 +:10A530008093DD0D9093DE0DA093DF0DB093E00DC1 +:10A540003093890020938800E091D20DF091D30DD3 +:10A5500080899189A289B389B695A79597958795A2 +:10A56000B095A095909581959F4FAF4FBF4F809329 +:10A57000E10D9093E20DA093E30DB093E40D809371 +:10A58000E50D9093E60DA093E70DB093E80D809351 +:10A59000E90D9093EA0DA093EB0DB093EC0D809331 +:10A5A000ED0D9093EE0DA093EF0DB093F00D109282 +:10A5B000CE0D1092CF0D1092D00D1092D10D06C07D +:10A5C00080ED97E09093890080938800E091D20D10 +:10A5D000F091D30D309709F460C480A18093F10D00 +:10A5E00080FF38C0459A8FEF8093410180914501EB +:10A5F0008823A1F1329942C480E029C080819181F1 +:10A60000A281B381181619061A061B06FCF4809164 +:10A61000AF0D9091B00DA091B10DB091B20D80939E +:10A62000C20D9093C30DA093C40DB093C50D81E0EE +:10A630008093C10D80899189A289B3898093CE0DC1 +:10A640009093CF0DA093D00DB093D10D81E0809366 +:10A65000F20D04C0459881E0809341018091F10D95 +:10A6600081FF3CC047988FEF809342018091450164 +:10A670008823C1F1339907C480E02DC0E091D20D49 +:10A68000F091D30D84819581A681B78118161906A2 +:10A690001A061B06FCF48091B30D9091B40DA091A5 +:10A6A000B50DB091B60D8093C60D9093C70DA093D4 +:10A6B000C80DB093C90D81E08093C00D8089918948 +:10A6C000A289B3898093CE0D9093CF0DA093D00D26 +:10A6D000B093D10D81E08093F30D04C0479A81E0DF +:10A6E000809342018091F10D82FF3CC02A988FEF48 +:10A6F00080934301809145018823C1F13499C8C3F7 +:10A7000080E02DC0E091D20DF091D30D8085918530 +:10A71000A285B385181619061A061B06FCF480914B +:10A72000B70D9091B80DA091B90DB091BA0D80936D +:10A73000CA0D9093CB0DA093CC0DB093CD0D81E0BD +:10A740008093BF0D80899189A289B3898093CE0DB2 +:10A750009093CF0DA093D00DB093D10D81E0809355 +:10A76000F40D04C02A9A81E0809343018091F10D99 +:10A7700083FF03C0289A8FEF02C0289881E080935E +:10A78000440120E030E081C18091C00087FF19C002 +:10A79000E091C6004091420650914306CA010196DD +:10A7A0008F77992760914406709145068617970721 +:10A7B00041F0DA01AE53BA4FEC9390934306809385 +:10A7C0004206E091D20DF091D30D8091E10D909170 +:10A7D000E20DA091E30DB091E40D408151816281C1 +:10A7E0007381840F951FA61FB71F8093E10D90936F +:10A7F000E20DA093E30DB093E40D181619061A06A6 +:10A800001B0644F55F9A4089518962897389841BCC +:10A81000950BA60BB70B8093E10D9093E20DA093DF +:10A82000E30DB093E40D409141018091AF0D909103 +:10A83000B00DA091B10DB091B20D840F911DA11D6D +:10A84000B11D8093AF0D9093B00DA093B10DB09357 +:10A85000B20D5F98E091D20DF091D30D8091E50D8E +:10A860009091E60DA091E70DB091E80D44815581DE +:10A8700066817781840F951FA61FB71F8093E50D12 +:10A880009093E60DA093E70DB093E80D1816190606 +:10A890001A061B0644F5469A4089518962897389D4 +:10A8A000841B950BA60BB70B8093E50D9093E60DDB +:10A8B000A093E70DB093E80D409142018091B30D54 +:10A8C0009091B40DA091B50DB091B60D840F911D6E +:10A8D000A11DB11D8093B30D9093B40DA093B50D40 +:10A8E000B093B60D4698E091D20DF091D30D8091C2 +:10A8F000E90D9091EA0DA091EB0DB091EC0D408522 +:10A90000518562857385840F951FA61FB71F80939D +:10A91000E90D9093EA0DA093EB0DB093EC0D181692 +:10A9200019061A061B0644F52B9A4089518962893B +:10A930007389841B950BA60BB70B8093E90D90933D +:10A94000EA0DA093EB0DB093EC0D40914301809183 +:10A95000B70D9091B80DA091B90DB091BA0D840FBB +:10A96000911DA11DB11D8093B70D9093B80DA093BB +:10A97000B90DB093BA0D2B98E091D20DF091D30D93 +:10A980008091ED0D9091EE0DA091EF0DB091F00D35 +:10A990004485558566857785840F951FA61FB71F4B +:10A9A0008093ED0D9093EE0DA093EF0DB093F00D0D +:10A9B000181619061A061B0644F5299A408951896A +:10A9C00062897389841B950BA60BB70B8093ED0DE1 +:10A9D0009093EE0DA093EF0DB093F00D40914401D4 +:10A9E0008091BB0D9091BC0DA091BD0DB091BE0D9D +:10A9F000840F911DA11DB11D8093BB0D9093BC0DC3 +:10AA0000A093BD0DB093BE0D29988091CE0D90916D +:10AA1000CF0DA091D00DB091D10D0196A11DB11D0A +:10AA20008093CE0D9093CF0DA093D00DB093D10D08 +:10AA30004091CE0D5091CF0D6091D00D7091D10D00 +:10AA40002F5F3F4FE091D20DF091D30D8089918916 +:10AA5000A289B389481759076A077B07B0F040916C +:10AA6000CE0D5091CF0D6091D00D7091D10DE09130 +:10AA7000D20DF091D30D84899589A689B789841761 +:10AA80009507A607B70748F4E0C08091D80D90E07D +:10AA9000281739070CF478CEE2CF4091DD0D5091A4 +:10AAA000DE0D6091DF0D7091E00D048D158D268D0A +:10AAB000378DAA27419FB12D529FC001629F900DF3 +:10AAC000619F800D911D429FB00D811D9A1F519F66 +:10AAD000B00D811D9A1F609FB00D811D9A1F509F60 +:10AAE000B10D8A1F9A1FB6958A1F9A1F112444AD73 +:10AAF00055AD480F591F5093DC0D4093DB0D80ADD1 +:10AB000091ADA2ADB3AD60E070E084179507A607E4 +:10AB1000B70720F49093DC0D8093DB0D6091DB0D83 +:10AB20007091DC0D61349CE9790728F461328EE480 +:10AB3000780748F002C060E47CE9769567957695E1 +:10AB4000679584E007C0613197E2790730F0769528 +:10AB5000679582E08093D80D08C081E08093D80D7E +:10AB60006032710510F460E270E0605271096115A5 +:10AB700088E07807E0F0872F9927880F991F880FC2 +:10AB8000991F855D984FFC01329625913491AA2733 +:10AB9000639FA001629F410D5A1F06944A1F5A1FCE +:10ABA0001124FC0125913491241B350B1EC0CB01CF +:10ABB000969587958C7F855D944FFC012591349106 +:10ABC0000296FC0145915491FB01E770FF274E9FCF +:10ABD000C0014F9F900D5E9F900D1124F3E096955C +:10ABE0008795FA95E1F7281B390B24363105A0F437 +:10ABF000EAE8F2E006C09091C00095FFFCCF809398 +:10AC0000C60081918111F7CF4AE050E081EC95E0D8 +:10AC10000E94DE2D24E630E03093890020938800E6 +:10AC20008091DD0D9091DE0DA091DF0DB091E00DD2 +:10AC3000820F931FA11DB11D8093DD0D9093DE0D3A +:10AC4000A093DF0DB093E00DF3C04091CE0D509175 +:10AC5000CF0D6091D00D7091D10D808D918DA28D11 +:10AC6000B38D84179507A607B70708F0D9C04091A0 +:10AC7000D40D5091D50D6091D60D7091D70D048DE6 +:10AC8000158D268D378DAA27419FB12D529FC0016A +:10AC9000629F900D619F800D911D429FB00D811D9F +:10ACA0009A1F519FB00D811D9A1F609FB00D811D8D +:10ACB0009A1F509FB10D8A1F9A1FB6958A1F9A1F1F +:10ACC00011242091DB0D3091DC0DE05CFF4F281743 +:10ACD000390718F42081318102C0281B390B80818B +:10ACE0009181A281B381A90160E070E04817590702 +:10ACF0006A077B0708F49C0121349CE9390728F492 +:10AD000021328EE4380748F002C020E43CE9369551 +:10AD100027953695279584E007C0213197E23907BA +:10AD200030F03695279582E08093D80D08C081E0F9 +:10AD30008093D80D2032310510F420E230E0B901C3 +:10AD400060527109611588E07807E0F0872F992734 +:10AD5000880F991F880F991F855D984FFC013296C7 +:10AD600045915491AA27659F9001649F210D3A1F38 +:10AD700006942A1F3A1F1124FC0145915491421B4D +:10AD8000530B1EC0CB01969587958C7F855D944FA4 +:10AD9000FC01459154910296FC0125913491FB01EF +:10ADA000E770FF272E9FC0012F9F900D3E9F900DB3 +:10ADB000112433E0969587953A95E1F7481B590B96 +:10ADC00044365105A0F4EAE8F2E006C09091C000D4 +:10ADD00095FFFCCF8093C60081918111F7CF4AE0A7 +:10ADE00050E081EC95E00E94DE2D44E650E0509367 +:10ADF0008900409388008091D40D9091D50DA09149 +:10AE0000D60DB091D70D840F951FA11DB11D809354 +:10AE1000D40D9093D50DA093D60DB093D70D08C047 +:10AE20008091D90D9091DA0D9093890080938800DC +:10AE30004091CE0D5091CF0D6091D00D7091D10DFC +:10AE4000E091D20DF091D30D80899189A289B389C7 +:10AE5000481759076A077B0700F11092D30D10922B +:10AE6000D20D90915508809154089817B1F08091B7 +:10AE700054088F5F8F70809354080FC08091F20D3B +:10AE80008111BCCBE3CB8091F30D8111F7CB22CCA8 +:10AE90008091F40D811136CC61CCFF91EF91BF917F +:10AEA000AF919F918F917F916F915F914F913F9162 +:10AEB0002F911F910F910F900FBE0F901F9018951B +:10AEC0003D9A3F9A229A209A569A5E9A569A5E9A8C +:10AED0000D9A159A569A5E9A3A98429A3B98439AD6 +:10AEE0003C98449A579A5F985E9A3E9A46985E9A22 +:10AEF000239A2B98159A219A29985E9AA1E8B0E096 +:10AF00008C918F7E8C938C9188608C93E0E8F0E03C +:10AF100080818D7F808380818E7F808380818F730D +:10AF2000808380818F7C80838C91887F82608C93EA +:10AF300080E090E4909389008093880010928500CF +:10AF400010928400EFE6F0E080818260808381E0EF +:10AF50008093450178940895909155088091540804 +:10AF6000981731F00E94FD5981E00E940F16F4CF2E +:10AF70000895CF93DF93EFB7F894EC01888199811E +:10AF8000AA81BB818093AF0D9093B00DA093B10DBA +:10AF9000B093B20DEB0188819981AA81BB81809326 +:10AFA000B30D9093B40DA093B50DB093B60DEA0117 +:10AFB00088819981AA81BB818093B70D9093B80D48 +:10AFC000A093B90DB093BA0DE90188819981AA8146 +:10AFD000BB818093BB0D9093BC0DA093BD0DB0932E +:10AFE000BE0DEFBFDF91CF9108952FB7F894FC010C +:10AFF00080819181A281B3818093BB0D9093BC0D20 +:10B00000A093BD0DB093BE0D2FBF08950F931F9356 +:10B010009FB7F89424E0829FF0011124E155F24F8C +:10B0200000811181228133819FBFB801C9011F9125 +:10B030000F9108950E94AC575E9A5E9A159A5E9A97 +:10B04000089580916F008D7F80936F0006C080917E +:10B0500054088F5F8F7080935408909155088091A9 +:10B06000540898130AC01092D30D1092D20D8091FB +:10B070006F00826080936F000895909155088091D1 +:10B080005408981751F3E3CF20914E0130914F01AE +:10B09000409150015091510160E070E08FE793E4DE +:10B0A0000E94896E6093030E7093040E8093050EC8 +:10B0B0009093060E08958E5F914FFC01808190E081 +:10B0C00008950F931F93CF93DF93EC01662309F448 +:10B0D00061C0E2E1F0E107C09091C00095FFFCCFB4 +:10B0E0008093C600319684918111F6CF4AE050E0FA +:10B0F00070E081EC95E00E94C02DE9E1F0E107C02D +:10B100009091C00095FFFCCF8093C600319684914A +:10B110008111F6CF8091C00085FFFCCF8AE080933B +:10B12000C6000E94E61536C0C901880F991F880F16 +:10B13000991FFC01E95CFF4E659174916C177D07C6 +:10B140003CF521503109220F331F220F331FF90123 +:10B15000EB5CFF4E05911491295C3F4EF90145913E +:10B160005491FC01EB5CFF4E25913491C41BD50B2F +:10B17000201B310BC29FC001C39F900DD29F900D29 +:10B180001124641B750B0E944072600F711F13C065 +:10B190004F5F01C041E0242F30E04D3309F0C4CFB0 +:10B1A0002D33310531F4E5E2F1E185919491BC0153 +:10B1B00002C060E070E020EF3FE3261B370BC901BF +:10B1C000DF91CF911F910F910895CF93DF9321E0ED +:10B1D00030E0D901AA0FBB1FAA0FBB1FFD01E95C1C +:10B1E000FF4E659174916817790744F52150310934 +:10B1F000220F331F220F331FF901EB5CFF4EC59165 +:10B20000D491295C3F4EF90145915491FD01EB5CCD +:10B21000FF4E25913491FC01E41BF50B2C1B3D0BDB +:10B22000E29FC001E39F900DF29F900D1124641BDB +:10B23000750B0E9440726C0F7D1F0BC02F5F3F4F3C +:10B240002D33310509F0C5CFE5E2F1E18591949107 +:10B25000BC0120EF3FE3261B370BC901DF91CF91E3 +:10B2600008952F923F924F925F926F927F928F92AA +:10B270009F92AF92BF92CF92DF92EF92FF920F9385 +:10B280001F93CF93DF938C01662351F1E2E1F0E14C +:10B2900007C09091C00095FFFCCF8093C600319607 +:10B2A00084918111F6CF4AE050E070E081EC95E0A6 +:10B2B0000E94C02DE9E2F1E107C09091C00095FF26 +:10B2C000FCCF8093C600319684918111F6CF809196 +:10B2D000C00085FFFCCF8AE08093C6000E94E6157F +:10B2E000C0EFDFE3C01BD10B41E05EC09C01220F29 +:10B2F000331F220F331FF901EB5CFF4E65907490F2 +:10B30000C615D7050CF04FC00197880F991F880FFD +:10B31000991FFC01E95CFF4E259034908B5C9F4E99 +:10B32000FC0105911491F901E95CFF4E45905490A0 +:10B33000B101882777FD8095982F0E94246F6B01BB +:10B340007C01BE01601B710B882777FD8095982FCB +:10B350000E94246F4B015C01B201621973098827B6 +:10B3600077FD8095982F0E94246F9B01AC01C50149 +:10B37000B4010E9457714B015C01B301601B710B5A +:10B38000882777FD8095982F0E94246F9B01AC0140 +:10B39000C501B4010E94896E9B01AC01C701B601D1 +:10B3A0000E94A96D17C04F5F842F90E04D3309F0C4 +:10B3B0009DCFCD9759F4E7E2F1E16591749188272B +:10B3C00077FD8095982F0E94246F04C060E070E0A4 +:10B3D00080E090E0DF91CF911F910F91FF90EF906F +:10B3E000DF90CF90BF90AF909F908F907F906F90A5 +:10B3F0005F904F903F902F9008952F923F924F92E1 +:10B400005F926F927F928F929F92AF92BF92CF92F4 +:10B41000DF92EF92FF920F931F93CF93DF9300D0B1 +:10B42000CDB7DEB78091F50D882309F4BFC18FB782 +:10B43000F8941092F50D8FBF60E08091FC0D909113 +:10B44000FD0D0E9431596B017C019B01AC016091A3 +:10B45000F60D7091F70D8091F80D9091F90D0E9405 +:10B46000A86DB62EA72E182F092FA5019801852F9C +:10B47000942FA32FB22F8093070E9093080EA093C2 +:10B48000090EB0930A0E20E030E040E251E4D5010D +:10B49000F8016B2F7A2F8F2F9E2F0E948570181620 +:10B4A0000CF41DC120E030E040E251ECD501F80180 +:10B4B0006B2F7A2F8F2F9E2F0E94826E87FD0BC1DC +:10B4C00080910B0E8111FCC02091520130915301EB +:10B4D0004091540150915501D501F8016B2F7A2DFF +:10B4E0008F2F902F0E945771762E672E89839A8313 +:10B4F000A301382F292F852F942FA32FB22F8093AC +:10B50000100E9093110EA093120EB093130E209173 +:10B510000C0E30910D0E40910E0E50910F0ED50174 +:10B52000F8016B2F7A2D8F2F902F0E94A96D8B0120 +:10B530002C018090140E9090150EA090160EB090D5 +:10B54000170E282D392D4A2D5B2D602F712F842D3C +:10B55000952D0E94826E87FF9DC084012501802F5A +:10B56000912FA42DB52D80930C0E90930D0EA093CA +:10B570000E0EB0930F0E20914E0130914F0140916D +:10B58000500150915101602F712F842D952D0E94F3 +:10B5900057714B015C01862F992DAA2DBB2D8093ED +:10B5A000180E9093190EA0931A0EB0931B0E2091B3 +:10B5B0001C0E30911D0E40911E0E50911F0EC701A2 +:10B5C000B6010E94A86D20914A0130914B01409133 +:10B5D0004C0150914D010E94577120ED3CEC4CE420 +:10B5E0005DE30E9457711B012C0123E333E343E722 +:10B5F0005FE36091200E7091210E8091220E909158 +:10B60000230E0E9457719B01AC01C201B1010E943F +:10B61000A96D8B012C01862F912FA42DB52D809320 +:10B62000200E9093210EA093220EB093230EC09271 +:10B630001C0ED0921D0EE0921E0EF0921F0E282DB1 +:10B64000392D4A2D5B2DD301F980EA806B2F762DA1 +:10B650008F2D9E2D0E94A96D202F312F442D552D09 +:10B660000E94A86D8B017C0120E030E0A901712FC0 +:10B670009F2D0E94826E87FD3CC020E030E04FE7A6 +:10B6800053E4602F712F8E2D9F2D0E948570181608 +:10B69000A4F528C08090030E9090040EA090050E93 +:10B6A000B090060E282D392D4A2D5B2D602F712F5D +:10B6B000842D952D0E94857018160CF050CF4DCF1B +:10B6C00010920C0E10920D0E10920E0E10920F0E84 +:10B6D00010920B0EF9CE81E080930B0E0AC081E030 +:10B6E00080930B0E00E010E08FE7E82E93E4F92E34 +:10B6F00004C000E010E0E12CF12C2091FC0D309111 +:10B70000FD0D4091240E5091250E421753071CF059 +:10B710001092020E11C0409156015091570124170A +:10B720003507B4F7602F712F8E2D9F2D0E94F16E7B +:10B73000759567956093020E0E94FD2A0091260E72 +:10B740001091270E2091280E3091290E601B710B4D +:10B75000820B930B683873418105910538F10E9483 +:10B76000FD2A6093260E7093270E8093280E9093E7 +:10B77000290E8091FA0D9091FB0D20912A0E3091A7 +:10B780002B0E281739078CF420915801309159015C +:10B790008217930754F42091FE0D3091FF0D82170C +:10B7A00093070CF002C05A9A01C05A980F900F905C +:10B7B000DF91CF911F910F91FF90EF90DF90CF908D +:10B7C000BF90AF909F908F907F906F905F904F90C1 +:10B7D0003F902F9008952F923F924F925F926F92D9 +:10B7E0007F928F929F92AF92BF92CF92DF92EF9211 +:10B7F000FF920F931F93CF93DF93C0EFDFE3C81B3C +:10B80000D90B81E090E09C01220F331F220F331FE0 +:10B81000F901EB5CFF4E65907490C615D7050CF0EE +:10B820004FC00197880F991F880F991FFC01E95C91 +:10B83000FF4E259034908B5C9F4EFC010591149136 +:10B84000F901E95CFF4E45905490B101882777FDDE +:10B850008095982F0E94246F6B017C01BE01601BB4 +:10B86000710B882777FD8095982F0E94246F4B01DC +:10B870005C01B20162197309882777FD8095982FC2 +:10B880000E94246F9B01AC01C501B4010E94577155 +:10B890004B015C01B301601B710B882777FD80951C +:10B8A000982F0E94246F9B01AC01C501B4010E9436 +:10B8B000896E9B01AC01C701B6010E94A96D0FC042 +:10B8C00001968D33910509F09ECFE7E2F1E1659194 +:10B8D0007491882777FD8095982F0E94246FDF91BF +:10B8E000CF911F910F91FF90EF90DF90CF90BF907D +:10B8F000AF909F908F907F906F905F904F903F9010 +:10B900002F9008951092140E1092150E1092160E8C +:10B910001092170E20914E0130914F01409150012D +:10B920005091510160E070E08FE793E40E94896ECE +:10B930006093030E7093040E8093050E9093060E91 +:10B94000559A529A87ED80937A00EEE7F0E01082E4 +:10B9500080818068808380818064808380E888BD66 +:10B96000EEE6F0E08081846080836AEF70E080E042 +:10B9700090E00E94392B60E085E090E00E946158E1 +:10B980009093250E8093240E60E083E191E00E9465 +:10B990006158909357018093560185E090E00E9492 +:10B9A000E55890932B0E80932A0E86E990E00E9432 +:10B9B000E55890935901809358010895089560E0E7 +:10B9C00080E090E00E9461581092F60D1092F70D01 +:10B9D0001092F80D1092F90D80E090E00E94E55869 +:10B9E0009093FF0D8093FE0D1092010E1092000EA9 +:10B9F0001092020E5D981092FF0D1092FE0D5A9853 +:10BA000008952F923F924F925F926F927F928F9202 +:10BA10009F92AF92BF92CF92DF92EF92FF920F93DD +:10BA20001F93CF93DF93CDB7DEB7E1970FB6F894AE +:10BA3000DEBF0FBECDBF688B798B8A8B9B8B0E943C +:10BA4000FD2A6C8B7D8B8E8B9F8BEEE9F2E006C01E +:10BA50009091C00095FFFCCF8093C6008191811129 +:10BA6000F7CF8091C00085FFFCCF8AE08093C600AD +:10BA70000E94DF5C8FE78093020E4C885D886E88A1 +:10BA80007F884C865D866E867F86AFE7CA2ED12C76 +:10BA9000E12CF12CBFE78B2E912CA12CB12C8EA682 +:10BAA0009FA6A8AAB9AA11E01B861A86EBE2FFE0BE +:10BAB00094909FA2E3E3FFE0A490A8A6E8E3FFE050 +:10BAC000B490B9A6EFE3FFE084908AA6E6E4FFE035 +:10BAD00094909BA6ECE4FFE0A490ACA68091F50DB9 +:10BAE000882309F4BBC28FB7F8941092F50D8FBF6D +:10BAF00060E08091FC0D9091FD0D0E9431596E83A4 +:10BB00007F8388879987762F6F81982F8985272F44 +:10BB1000362F492F582FB88DA98DEA8DFB8D6B2FAD +:10BB20007A2FCF010E948570181644F0BE80B88E1F +:10BB30008F80898E98849A8EA984AB8E7E816F8146 +:10BB400098858985272F362F492F582FECA1602FF4 +:10BB5000722D832D9E2F0E94826E87FD05C00E815F +:10BB60002F803884B984BCA2112309F43FC378899B +:10BB700069899A898B89272F362F492F582FBE81A3 +:10BB8000AF81E885F9856B2F7A2FCF010E948570F0 +:10BB900018160CF063C20E94FD2A64197509860903 +:10BBA0009709693873418105910508F457C28EA53C +:10BBB0009FA5A8A9B9A98C199D09AE09BF09B5957A +:10BBC000A795979587958093020E0E94FD2A6C8712 +:10BBD0007D878E879F874B015C0184189508A60896 +:10BBE000B70888A299A2AAA2BBA29888988EA98811 +:10BBF000A98EBA88BA8E8B888B8EF8C20E94FD2AD5 +:10BC00008C849D84AE84BF84681979098A099B0954 +:10BC1000693873418105910508F41FC20E94FD2A0D +:10BC20002B013C018A849B84892809F4FCC1DC0136 +:10BC3000CB018C849D84AE84BF8488199909AA099C +:10BC4000BB0988A099A0AAA0BBA0880E991EAA1E15 +:10BC5000BB1E28A139A14AA15BA1281B390B4A0BA5 +:10BC60005B0BCA01B901A70196010E943072A501C0 +:10BC700094010E9476728EA59FA5A8A9B9A9280F44 +:10BC8000391F4A1F5B1F243131054105510524F13D +:10BC90002EA73FA748AB59AB2C3E310541055105B6 +:10BCA00044F02BEE30E040E050E02EA73FA748AB39 +:10BCB00059AB8EA59FA5A8A9B9A980389105A10562 +:10BCC000B105C4F0EEEFCE2ED12CE12CF12CC81A28 +:10BCD000D90AEA0AFB0A12C024E130E040E050E051 +:10BCE0002EA73FA748AB59AB74E1C72ED12CE12C4E +:10BCF000F12C04C0CEA4DFA4E8A8F9A88FA1EBE240 +:10BD0000FFE008C09091C00095FFFCCF8093C60073 +:10BD1000319684918111F6CF2AE030E04EA55FA5DF +:10BD200068A979A981EC95E00E94AF2D88A5E3E38D +:10BD3000FFE008C09091C00095FFFCCF8093C60043 +:10BD4000319684918111F6CF2AE030E0B701A60147 +:10BD500081EC95E00E94AF2D89A5E8E3FFE008C0E3 +:10BD60009091C00095FFFCCF8093C60031968491DE +:10BD70008111F6CF22E030E08CA1402F522D632DAF +:10BD8000782F81EC95E00E94B92E8AA5EFE3FFE0C1 +:10BD900008C09091C00095FFFCCF8093C6003196FB +:10BDA00084918111F6CF22E030E0F88DE98D9A8DF3 +:10BDB0008B8D4F2F5E2F692F782F81EC95E00E949D +:10BDC000B92E8091C00085FFFCCF8AE08093C60029 +:10BDD0004A855B85433051050CF425C1C701B60186 +:10BDE0000E94246F20E030E040E850E40E94577148 +:10BDF0006C8F7D8F8E8F9F8F8CA1202F322D432DA6 +:10BE0000582FB88DA98DEA8D1B8D6B2F7A2F8E2F11 +:10BE1000912F0E94A86D20ED3FE049E450E40E947C +:10BE2000577120E030E040E05FE30E9457719B01D2 +:10BE3000AC016C8D7D8D8E8D9F8D0E94896E362E0E +:10BE4000072F182F9C8FC501B4010E94246F20E09A +:10BE500030E04AE754E40E94896EA62E972E282EE1 +:10BE6000892E8BA5E6E4FFE008C09091C00095FF05 +:10BE7000FCCF8093C600319684918111F6CF22E0E9 +:10BE800030E08C8D432D502F612F782F81EC95E081 +:10BE90000E94B92E8CA5ECE4FFE008C09091C00090 +:10BEA00095FFFCCF8093C600319684918111F6CF27 +:10BEB00022E030E04A2D592D622D782D81EC95E05D +:10BEC0000E94B92E8091C00085FFFCCF8AE080934C +:10BED000C6002AE939E949E15FE3EC8D632D702F53 +:10BEE000812F9E2F0E945771362E072F182FB92EA3 +:10BEF000762F272F302F412F5B2D632D702F812F11 +:10BF00009B2D0E94A96D2A2D392D422D582D0E945E +:10BF1000896E6C8F7CA38DA39EA32A2D392D422D73 +:10BF2000582D632D702F812F9B2D0E94577120E07B +:10BF300030E040E05EE30E945771A62E972E282E37 +:10BF4000892EE2E5FFE007C09091C00095FFFCCF8D +:10BF50008093C600319684918111F6CF8091C00004 +:10BF600085FFFCCF8AE08093C600EFE5FFE007C0C5 +:10BF70009091C00095FFFCCF8093C60031968491CC +:10BF80008111F6CF22E030E0432D502F612F7B2D21 +:10BF900081EC95E00E94B92E8091C00085FFFCCF16 +:10BFA0008AE08093C600E5E6FFE007C09091C000FC +:10BFB00095FFFCCF8093C600319684918111F6CF16 +:10BFC00022E030E0FC8DECA19DA18EA14F2F5E2FD1 +:10BFD000692F782F81EC95E00E94B92E8091C000E6 +:10BFE00085FFFCCF8AE08093C600EBE6FFE007C048 +:10BFF0009091C00095FFFCCF8093C600319684914C +:10C000008111F6CF22E030E04A2D592D622D782D96 +:10C0100081EC95E00E94B92E8091C00085FFFCCF95 +:10C020008AE08093C6008EA59FA5A8A9B9A98C0D0A +:10C030009D1DAE1DBF1DB595A795979587958093BE +:10C04000020E8A859B8501969B878A8708892988A5 +:10C050003A888B888CA211E001C010E020E030E02B +:10C0600040EA51E4B889A989EA89FB896B2F7A2FC4 +:10C07000CF010E94A96D9B01AC01BE81AF81E88513 +:10C08000F9856B2F7A2FCF010E948570181694F4D2 +:10C09000E1E7FFE007C09091C00095FFFCCF8093DF +:10C0A000C600319684918111F6CF8091C00085FF42 +:10C0B000FCCF98C00E94FD2A8C889D88AE88BF88DE +:10C0C000681979098A099B09613D774081059105C5 +:10C0D00008F43FC00E94FD2A6C8B7D8B8E8B9F8B5A +:10C0E000EAE9FFE007C09091C00095FFFCCF809384 +:10C0F000C600319684918111F6CF60E08091FC0DED +:10C100009091FD0D0E943159AB01BC0122E030E05D +:10C1100081EC95E00E94B92EE0EAFFE007C0909123 +:10C12000C00095FFFCCF8093C600319684918111A9 +:10C13000F6CF6091020E4AE050E070E081EC95E0AD +:10C140000E94C02D8091C00085FFFCCF8AE08093C3 +:10C15000C6000E94FD2A6A837B838C839D830E9494 +:10C16000FD2A8C849D84AE84BF84840C951CA61CFF +:10C17000B71C2A813B814C815D81281939094A0904 +:10C180005B09260F371F481F591F21383F44424182 +:10C19000510590F0E4EAFFE007C09091C00095FFE0 +:10C1A000FCCF8093C600319684918111F6CF8091A7 +:10C1B000C00085FFFCCF16C0AA85BB8516970CF47E +:10C1C0008DCCE1ECFFE007C09091C00095FFFCCF63 +:10C1D0008093C600319684918111F6CF8091C00082 +:10C1E00085FFFCCF8AE08093C60015C078896989F5 +:10C1F0009A898B89272F362F492F582FBE81AF81DF +:10C200001885F9856B2F7A2F812F9F2F0E94826EC0 +:10C2100087FDF4CC22CFE1960FB6F894DEBF0FBEB7 +:10C22000CDBFDF91CF911F910F91FF90EF90DF90E5 +:10C23000CF90BF90AF909F908F907F906F905F90C6 +:10C240004F903F902F900895CF93DF931F92CDB7DB +:10C25000DEB789830E94DF5C0E94AB166981811181 +:10C260002FC0E2E1F0E107C08091C00085FFFCCF64 +:10C270009093C600319694919111F6CF4AE050E028 +:10C2800070E081EC95E00E94C02D8091C00085FF98 +:10C29000FCCF8AE08093C600E6E4F1E107C090910C +:10C2A000C00095FFFCCF8093C60031968491811128 +:10C2B000F6CF8091C00085FFFCCF8AE08093C60056 +:10C2C0000F90DF91CF910895CF93DF931F92CDB759 +:10C2D000DEB789830E94DF5C0E94AB166981811101 +:10C2E0002FC0E2E1F0E107C08091C00085FFFCCFE4 +:10C2F0009093C600319694919111F6CF4AE050E0A8 +:10C3000070E081EC95E00E94C02D8091C00085FF17 +:10C31000FCCF8AE08093C600E3E7F1E107C090918B +:10C32000C00095FFFCCF8093C600319684918111A7 +:10C33000F6CF8091C00085FFFCCF8AE08093C600D5 +:10C340000F90DF91CF9108955A980E94AB168111FA +:10C3500021C0E2E1F0E107C09091C00095FFFCCF61 +:10C360008093C600319684918111F6CFE0EAF1E125 +:10C3700007C09091C00095FFFCCF8093C600319616 +:10C3800084918111F6CF8091C00085FFFCCF8AE0B7 +:10C390008093C60008951F920F920FB60F9211243A +:10C3A0002F933F934F935F936F937F938F939F93BD +:10C3B000AF93BF93EF93FF9380915A01811106C011 +:10C3C0008091020E80932C0E81115D9A90912C0E1B +:10C3D00080915A01891708F05D988F5F8F7780935D +:10C3E0005A0180912D0E833009F443C020F481302E +:10C3F000D1F0A8F50CC0853009F457C008F453C03B +:10C40000863009F454C0873009F05AC052C01092E7 +:10C410007B0087E480937C0080917A008064809325 +:10C420007A0081E019C020917800309179008091E4 +:10C430002E0E90912F0EA091300EB091310E820FE2 +:10C44000931FA11DB11D80932E0E90932F0EA093CC +:10C45000300EB093310E82E080932D0E31C086E411 +:10C4600080937C0080917A00806480937A0083E0DE +:10C47000F3CF20917800309179008091320E909125 +:10C48000330EA091340EB091350E820F931FA11D73 +:10C49000B11D8093320E9093330EA093340EB0935F +:10C4A000350E84E0D9CF85E0D7CF86E0D5CF87E0C1 +:10C4B000D3CF10922D0E8091360E8F5F8093360E63 +:10C4C0008091360E803108F474C02FEF3FE38091E5 +:10C4D0002E0E90912F0EA901481B590BCA015093A3 +:10C4E000FD0D4093FC0D4091320E5091330E241BF4 +:10C4F000350B3093FB0D2093FA0D21E02093F50DC1 +:10C500001092360E10922E0E10922F0E1092300EA8 +:10C510001092310E1092370E1092380E1092390E82 +:10C5200010923A0E10923B0E10923C0E10923D0E5D +:10C5300010923E0E1092320E1092330E1092340E64 +:10C540001092350E209156013091570182179307B2 +:10C550004CF01092010E1092000E80E00E942461B7 +:10C560000E9470162091FC0D3091FD0D8091240EDB +:10C570009091250E821793074CF01092010E1092A5 +:10C58000000E80E00E9464610E9470162091FA0DF6 +:10C590003091FB0D8091580190915901281739076E +:10C5A00044F01092FF0D1092FE0D0E94A4610E94B3 +:10C5B0007016FF91EF91BF91AF919F918F917F91F5 +:10C5C0006F915F914F913F912F910F900FBE0F9000 +:10C5D0001F901895CF93DF93FC01148A178A84E883 +:10C5E00092E0938B828B13AA16AA92AB81ABDF01E8 +:10C5F000A05BBF4F1C9213961C92DF01A25BBF4F42 +:10C600008D939C93DF01A359BF4F1C9213961C92EC +:10C61000DF01A559BF4F8D939C93DF01A857BF4FF2 +:10C6200029E111962C93119714961C92DF01A357C0 +:10C63000BF4F57961C92DF01A355BF4F1C92139614 +:10C640001C92DF01A555BF4F8D939C93DF01A8532A +:10C65000BF4F1D921D921D921C921397DF01A05394 +:10C66000BF4F1D921D921D921C9213971182128230 +:10C670001082EF01C453DF4F188219821A821B8285 +:10C68000DF01AC52BF4F81E08C93118A108A0E9467 +:10C69000FD2A68577C4E8F4F9F4F688379838A832A +:10C6A0009B83DF91CF910895DB01FC0120E03EE206 +:10C6B0004C91403229F0283009F431934C91419348 +:10C6C0002F5F11962B30A1F7108208952F923F9281 +:10C6D0004F925F926F927F928F929F92AF92BF9292 +:10C6E000CF92DF92EF92FF920F931F93CF93DF933E +:10C6F000CDB7DEB7C158D1090FB6F894DEBF0FBE73 +:10C70000CDBF8C017B01212C4A0182E0880E911C57 +:10C710006801E5EDCE0ED11C5801F6EDAF0EB11C4F +:10C720008EE3482E512C4C0E5D1E82E0480E511CAB +:10C73000EAEDF1E13490F3C09C85292F2871203176 +:10C7400009F007C1F6018081813009F402C182300D +:10C7500009F0EFC0FEC061EB72E0CE01855A9F4F39 +:10C760000E946475B701CE01855A9F4F0E9464757F +:10C77000BE016B587F4FCE01855A9F4F0E94647552 +:10C7800061EB72E0CE01855A9F4F0E94647521963D +:10C790001FAE219724961FAE249784E892E09FAFA6 +:10C7A0008EAF21E0AE014B585F4FB401C2010E9431 +:10C7B000F034811139C0F6018081811135C0832D9B +:10C7C000EAEDF1E108C09091C00095FFFCCF8093A5 +:10C7D000C600319684918111F6CFA3EBB2E006C07A +:10C7E0009091C00095FFFCCF8093C6008D91811180 +:10C7F000F7CF8091C00085FFFCCF8AE08093C60010 +:10C80000DE01AB58BF4F06C09091C00095FFFCCF32 +:10C810008093C6008D918111F7CF8091C00085FF74 +:10C82000FCCF8AE08093C6008BE1FE01E05CFF4F05 +:10C83000DE01939601900D928A95E1F784E892E0EB +:10C840009AA389A3AE014F5D5F4FBE01655A7F4F2A +:10C85000C8010E946663CE0181960E94842ACE019F +:10C86000CE960E94842A5BC0853E09F458C08E3261 +:10C8700009F455C08F3509F452C093FD50C081E0D2 +:10C88000203109F080E0F8018787811108C089858F +:10C89000873409F044C08A858E3709F440C03801D6 +:10C8A000F3E06F0E711CBE016F5F7F4FC3010E94EA +:10C8B0005463F601808181111EC0D70106C090919A +:10C8C000C00095FFFCCF8093C6008D918111F7CFFA +:10C8D000D30106C09091C00095FFFCCF8093C600A5 +:10C8E0008D918111F7CF8091C00085FFFCCF8AE048 +:10C8F0008093C60014C0813039F4F50180819181A4 +:10C900000196918380830BC0823049F4222D30E060 +:10C91000F5018081918128173907F1F02394BE0138 +:10C920006F5F7F4FC4010E945E3118160CF404CF74 +:10C9300013C0BE016F5F7F4FCE018B589F4F0E9487 +:10C9400054636C961FAE6C97F701808181110ACFFA +:10C9500002CF8981811188CFCF57DF4F0FB6F8946E +:10C96000DEBF0FBECDBFDF91CF911F910F91FF9022 +:10C97000EF90DF90CF90BF90AF909F908F907F907F +:10C980006F905F904F903F902F900895EF92FF929D +:10C990000F931F93CF93DF93CDB7DEB76D970FB68D +:10C9A000F894DEBF0FBECDBF8C01FC01EB52FF4FF0 +:10C9B00010827C0184E1E80EF11C40E050E0BA01F5 +:10C9C000C7010E94D1318BE1F701DE01139601907E +:10C9D0000D928A95E1F784E892E09A838983AE010B +:10C9E0004F5F5F4F6DE972E0C8010E946663CE0140 +:10C9F00001960E94842A6D960FB6F894DEBF0FBE92 +:10CA0000CDBFDF91CF911F910F91FF90EF900895CF +:10CA1000EF92FF920F931F93CF93DF93EC011A8253 +:10CA20008F89882321F0CE0144960E94B8327E017E +:10CA300088E8E80EF11C4FE160E0C7010E94686CD5 +:10CA400081111FC0EAEDF1E107C09091C00095FF90 +:10CA5000FCCF8093C600319684918111F6CFE0EE31 +:10CA6000F1E107C09091C00095FFFCCF8093C60014 +:10CA7000319684918111F6CF8091C00085FFFCCF63 +:10CA800076C08E0103571F4F41E0B701C8010E94D5 +:10CA9000ED3A811126C040E0B701C8010E94ED3A8D +:10CAA00081111FC0EDEEF1E107C09091C00095FF2C +:10CAB000FCCF8093C600319684918111F6CFE4EFCC +:10CAC000F1E107C09091C00095FFFCCF8093C600B4 +:10CAD000319684918111F6CF8091C00085FFFCCF03 +:10CAE00046C0B801CE0144960E94CB2F81111FC0D1 +:10CAF000EDEEF1E107C09091C00095FFFCCF80936F +:10CB0000C600319684918111F6CFE7E0F2E107C0CB +:10CB10009091C00095FFFCCF8093C6003196849120 +:10CB20008111F6CF8091C00085FFFCCF20C081E04D +:10CB30008A83EAEDF1E107C09091C00095FFFCCF38 +:10CB40008093C600319684918111F6CFE7E1F2E13E +:10CB500007C09091C00095FFFCCF8093C60031962E +:10CB600084918111F6CF8091C00085FFFCCF8AE0CF +:10CB70008093C6008BE1FE017496DE01D39601908E +:10CB80000D928A95E1F7CE01429698AB8FA7DF917F +:10CB9000CF911F910F91FF90EF900895FC011182AA +:10CBA00012820895FC012281222311F021E02183C9 +:10CBB0000895FC0121812111118208952F923F9245 +:10CBC0004F925F926F927F928F929F92AF92BF929D +:10CBD000CF92DF92EF92FF920F931F93CF93DF9349 +:10CBE000CDB7DEB7AA970FB6F894DEBF0FBECDBFA4 +:10CBF0007C016B01342EFC018281882309F4B4C1CD +:10CC00004701FDEA8F0E911CC4010E94B832F70162 +:10CC100011821B821E8284E892E09A838983C70175 +:10CC2000429690AB87A7F60180818F3209F08CC0C5 +:10CC30006FE270E0C6010E946F758C010F5F1F4F9D +:10CC40009AE0292E44244394512C4C0E5D1E77C04B +:10CC50006FE270E0C8010E946F755C01009709F4F3 +:10CC60007BC00817190708F077C03C01601A710AE9 +:10CC7000A301B801CE014E960E948F75EEE1F0E05F +:10CC8000EC0FFD1FE60DF71D10828E01025E1F4F97 +:10CC9000F80106C09091C00095FFFCCF8093C600BC +:10CCA00081918111F7CF8091C00085FFFCCF209248 +:10CCB000C600F70167A570A96115710519F06E5FCF +:10CCC0007F4F02C060E070E021E0AE01425E5F4F46 +:10CCD000CE0103960E94F03481112BC0E2E2F2E112 +:10CCE00007C09091C00095FFFCCF8093C60031969D +:10CCF00084918111F6CF06C09091C00095FFFCCFC2 +:10CD00008093C600F80181918F018111F5CFE6E390 +:10CD1000F2E107C09091C00095FFFCCF8093C60060 +:10CD2000319684918111F6CF8091C00085FFFCCFB0 +:10CD300014C1F70150AA47A685010F5F1F4F0115C7 +:10CD4000110509F085CF05C0C701C196F70190AB69 +:10CD500087A7BC2CAD2C02C0B02EA12EF70167A571 +:10CD600070A9332009F49FC06115710519F06E5F39 +:10CD70007F4F02C060E070E021E04B2D5A2DC401CE +:10CD80000E94F034882309F463C0F701E853FF4F91 +:10CD9000D701A355BF4F51960D911D912D913C91F7 +:10CDA00054970083118322833383E8E3F2E107C0C1 +:10CDB0009091C00095FFFCCF8093C600319684917E +:10CDC0008111F6CFEB2DFA2D06C09091C00095FF92 +:10CDD000FCCF8093C60081918111F7CFE5E4F2E1A9 +:10CDE00007C09091C00095FFFCCF8093C60031969C +:10CDF00084918111F6CFF701E853FF4F40815181B3 +:10CE0000628173812AE030E081EC95E00E949C2DE4 +:10CE10008091C00085FFFCCF8AE08093C600F701B7 +:10CE2000E053FF4F1082118212821382ECE4F2E190 +:10CE300007C09091C00095FFFCCF8093C60031964B +:10CE400084918111F6CF8091C00085FFFCCF85C011 +:10CE5000EAE5F2E107C09091C00095FFFCCF809316 +:10CE6000C600319684918111F6CFEB2DFA2D06C0C4 +:10CE70009091C00095FFFCCF8093C60081918111F5 +:10CE8000F7CFEEE6F2E107C09091C00095FFFCCF2E +:10CE90008093C600319684918111F6CF8091C000B5 +:10CEA00085FFFCCF5AC06115710519F06E5F7F4F89 +:10CEB00002C060E070E026E54B2D5A2DC4010E94AF +:10CEC000F03481112BC0E0E7F2E107C09091C0007F +:10CED00095FFFCCF8093C600319684918111F6CFE7 +:10CEE000EB2DFA2D06C09091C00095FFFCCF8093EA +:10CEF000C60081918111F7CFE4E8F2E107C090917B +:10CF0000C00095FFFCCF8093C600319684918111BB +:10CF1000F6CF8091C00085FFFCCF1FC081E0F701F4 +:10CF20008083E6E8F2E107C09091C00095FFFCCF56 +:10CF30008093C600319684918111F6CFF60106C028 +:10CF40009091C00095FFFCCF8093C6008191811124 +:10CF5000F7CF8091C00085FFFCCF8AE08093C600A8 +:10CF6000CE0101960E94842AAA960FB6F894DEBFDD +:10CF70000FBECDBFDF91CF911F910F91FF90EF902A +:10CF8000DF90CF90BF90AF909F908F907F906F90E9 +:10CF90005F904F903F902F9008955F926F927F9295 +:10CFA0008F929F92AF92BF92CF92DF92EF92FF92B9 +:10CFB0000F931F93CF93DF93CDB7DEB7AA970FB62A +:10CFC000F894DEBF0FBECDBF8C016B01FC018281E6 +:10CFD000882309F408C1C80183559F4F0E94B832C5 +:10CFE000F80111821B821E8284E892E09A83898371 +:10CFF000C801429690AB87A7F60180818F3209F075 +:10D000008EC06FE270E0C6010E946F7501967C01D0 +:10D010004AE0542E66246394712C6C0E7D1E7AC0F7 +:10D020006FE270E0C7010E946F755C01009709F420 +:10D030007CC0E816F90608F078C04C018E189F08ED +:10D04000A401B701CE014E960E948F75EEE1F0E08B +:10D05000EC0FFD1FE80DF91D10823EE1E32EF12CCF +:10D06000EC0EFD1EF70106C09091C00095FFFCCFAD +:10D070008093C60081918111F7CF8091C00085FF18 +:10D08000FCCF5092C600F80167A570A96115710523 +:10D0900019F06E5F7F4F02C060E070E021E0AE01EA +:10D0A000425E5F4FCE0103960E94F03481112BC087 +:10D0B000E8E9F2E107C09091C00095FFFCCF8093B2 +:10D0C000C600319684918111F6CF06C09091C000C0 +:10D0D00095FFFCCF8093C600F70181917F018111FC +:10D0E000F5CFECEAF2E107C09091C00095FFFCCFCC +:10D0F0008093C600319684918111F6CF8091C00053 +:10D1000085FFFCCF69C0F80170AA67A67501FFEF23 +:10D11000EF1AFF0AE114F10409F082CF05C0C8013B +:10D12000C196F80190AB87A77601F80187A590A971 +:10D13000009711F0029602C080E090E0B7010E94D3 +:10D14000AD35882301F1EEEAF2E107C09091C0000D +:10D1500095FFFCCF8093C600319684918111F6CF64 +:10D16000F70106C09091C00095FFFCCF8093C600E8 +:10D1700081918111F7CFF801E053FF4F10821182A6 +:10D18000128213822CC0ECEBF2E107C09091C00038 +:10D1900095FFFCCF8093C600319684918111F6CF24 +:10D1A000F70106C09091C00095FFFCCF8093C600A8 +:10D1B00081918111F7CFE4EDF2E107C09091C000B9 +:10D1C00095FFFCCF8093C600319684918111F6CFF4 +:10D1D0008091C00085FFFCCF8AE08093C600CE011D +:10D1E00001960E94842AAA960FB6F894DEBF0FBE5D +:10D1F000CDBFDF91CF911F910F91FF90EF90DF9006 +:10D20000CF90BF90AF909F908F907F906F905F90E6 +:10D210000895CF93DF93EC018A818823C1F1E6ED75 +:10D22000F2E107C09091C00095FFFCCF8093C6004B +:10D23000319684918111F6CFFE01E053FF4F40817A +:10D240005181628173812AE030E081EC95E00E9497 +:10D250009C2DE8EEF2E107C09091C00095FFFCCF55 +:10D260008093C600319684918111F6CFC853DF4F69 +:10D27000488159816A817B812AE030E081EC95E028 +:10D280000E949C2D8091C00085FFFCCF11C0EAEE6A +:10D29000F2E107C09091C00095FFFCCF8093C600DB +:10D2A000319684918111F6CF8091C00085FFFCCF2B +:10D2B0008AE08093C600DF91CF910895CF92DF92EC +:10D2C000EF92FF920F931F93CF93DF937C01EB01BB +:10D2D000EC2FFD2FDF010D900020E9F78D010150AB +:10D2E00011090E1B1F0BF701E355FF4F10826EE46F +:10D2F00070E0CE010E946F756C01009729F4F8016F +:10D300003197EC0FFD1F0DC060E270E00E946F7559 +:10D31000EC0121966AE270E0C6010E946F75FC0183 +:10D3200031978DE081838AE082831382BE01C70139 +:10D3300085559F4F0E947137F701E355FF4F80815C +:10D34000882309F1EDEEF1E107C09091C00095FF4F +:10D35000FCCF8093C600319684918111F6CFEAEF1D +:10D36000F2E107C09091C00095FFFCCF8093C6000A +:10D37000319684918111F6CF8091C00085FFFCCF5A +:10D380008AE08093C600DF91CF911F910F91FF90AB +:10D39000EF90DF90CF9008953F924F925F926F92FF +:10D3A0007F928F929F92AF92BF92CF92DF92EF9235 +:10D3B000FF920F931F93CF93DF93CDB7DEB7CC557A +:10D3C000D1090FB6F894DEBF0FBECDBF8C01662326 +:10D3D00049F0F801EC52FF4F1082F801828181116F +:10D3E00018C030C0FC01EC52FF4F8081882309F443 +:10D3F000AEC0F801E453FF4FC080D180E280F380DB +:10D400000E94FD2AC616D706E806F90608F49FC052 +:10D41000E0CFF80181898F9380898F9386EC92E029 +:10D420009F938F937E01FFE3EF0EF11CFF92EF922B +:10D430000E94B8750F900F900F900F900F900F9063 +:10D44000670110C0C8010E940865F801828181113E +:10D45000E0CF7DC0F701808190E00E942E75F7013A +:10D4600081937F01F60101900020E9F73197EC19D3 +:10D47000FD09C7018C199D098E179F075CF33801C0 +:10D48000F4E16F0E711C40E050E0BA01C3010E944C +:10D49000D131312CEE24E394F12CEC0EFD1E5E0113 +:10D4A0008FE3A80EB11C7FEC472E72E0572E4E0181 +:10D4B000E1E28E0E911C37C0F601808190E00E945F +:10D4C0002E75F60181936F01F70101900020E9F7B5 +:10D4D0003197EE19FF09C6018E199F098E179F0714 +:10D4E0005CF38A858E37F9F045E050E0B501C7015D +:10D4F0000E9481750097B9F4BF92AF925F924F92EC +:10D500009F928F920E94B875C4010E94B80E86ED5A +:10D5100092E00E94B80E0F900F900F900F900F9016 +:10D520000F9033243394B701C3010E945E31181663 +:10D5300014F46701C9CF311004C08FEF9FEFF801D9 +:10D5400004C0F801808991890196918B808BC45A1F +:10D55000DF4F0FB6F894DEBF0FBECDBFDF91CF9186 +:10D560001F910F91FF90EF90DF90CF90BF90AF9001 +:10D570009F908F907F906F905F904F903F90089515 +:10D580000F931F93CF93DF938C01EC01C355DF4FB3 +:10D59000CE010E946C32CE010E94B832F801108296 +:10D5A000DF91CF911F910F910895CF93DF93EC01FD +:10D5B0000E94AC570E94215819828AED92E00E9485 +:10D5C000B80E8091260D8823A1F11092260D60914E +:10D5D000E802E62FF0E0EE0FFF1FE050F24F8081EF +:10D5E00091810E9431592091390130913A01409145 +:10D5F0003B0150913C010E9485701816D4F4609153 +:10D60000E802C62FD0E080E090E00E946158FE0161 +:10D61000EE0FFF1FE050F24F91838083FE01EE0F6B +:10D62000FF1FEE0FFF1FEA50F24F1082118212828D +:10D630001382DF91CF910895EF92FF920F931F9382 +:10D64000CF93DF937C01EB018A01060F171F09C0FE +:10D650006991D701ED91FC910190F081E02DC70116 +:10D660000995C017D107A1F7DF91CF911F910F91B5 +:10D67000FF90EF9008958FEF8EBD0DB407FEFDCFA4 +:10D680008EB508958EBD0DB407FEFDCF089561E0FF +:10D69000FC0180810C94412CFC014281242F30E05C +:10D6A0003595279520652CBD40FD03C021E046300F +:10D6B00009F420E02DBD60E0FC0180810C94412C38 +:10D6C000CF92DF92EF92FF920F931F93CF93DF934E +:10D6D000EC018B017A010E94FD2A6B0109C00E94B6 +:10D6E000FD2A6C197D096D32714010F081E108C08E +:10D6F0000E943B6B8B838F3F91F38E3F19F08FE03D +:10D70000898328C0E114F104E1F081E0E81AF1080E +:10D710008FEF8EBDF8012FEF06C00DB407FEFDCFD1 +:10D720008EB581932EBDCF01801B910B8E159F0569 +:10D73000A0F30DB407FEFDCF8EB5F801EE0DFF1D71 +:10D7400080830E943B6B0E943B6BCE010E94476B23 +:10D7500081E004C0CE010E94476B80E0DF91CF9151 +:10D760001F910F91FF90EF90DF90CF9008950F934E +:10D770001F93CF93DF938B010E94FD2AEB0107C01B +:10D780000E94FD2A6C1B7D0B6017710730F40E940C +:10D790003B6B8F3FA9F781E001C080E0DF91CF9123 +:10D7A0001F910F910895CF92DF92FF920F931F93D5 +:10D7B000CF93DF9300D000D0CDB7DEB78C01F62E2B +:10D7C00029833A834B835C830E944C6B6CE271E04B +:10D7D000C8010E94B76B8F2D80640E94426B68E184 +:10D7E000C62ED12C5C814B813A812981DA01C90195 +:10D7F0000C2C04C0B695A795979587950A94D2F7F7 +:10D8000029833A834B835C830E94426B68E0C61A8B +:10D81000D10829813A814B815C8188EFC8168FEF4E +:10D82000D80621F7FF2029F098E0F91621F08FEFB4 +:10D8300003C085E901C087E80E94426BECE0FE125C +:10D8400002C00E943B6BF12C0E943B6BF80183836A +:10D8500087FF05C0FFEFFF1611F0F394F5CF0F908F +:10D860000F900F900F90DF91CF911F910F91FF902C +:10D87000DF90CF9008950F931F93CF93DF93EC0128 +:10D8800089018C81833039F0B9E0440F551F661F40 +:10D89000771FBA95D1F79A01AB0161E1CE010E94E1 +:10D8A000D36B81110AC040E052E0B801CE01DF9194 +:10D8B000CF911F910F910C94606B84E08983CE010E +:10D8C0000E94476B80E0DF91CF911F910F910895E7 +:10D8D000BF92CF92DF92EF92FF920F931F93CF935D +:10D8E000DF93EC01B62E1C82198248830E94FD2A28 +:10D8F0008B0161E088810E94252CCE010E94476B3C +:10D9000060E086E00E94252C61E085E00E94252CE5 +:10D9100061E087E00E94252C61E084E00E94252CD4 +:10D9200061E084E00E94412C85E08A8382E58CBD21 +:10D930001DBC2AE0F22E8FEF0E94426BFA94D9F7B9 +:10D9400009C00E94FD2A601B710B613D774010F0F9 +:10D9500081E058C020E030E0A90160E0CE010E94E3 +:10D96000D36BF82E8B8381E0F812EBCF2AEA31E0FB +:10D9700040E050E068E0CE010E94D36B82FF02C01D +:10D98000FC820DC094E0F92E0E943B6B8B83FA94CD +:10D99000D9F78A3A11F082E035C082E08C838C811D +:10D9A000823031F4C12CD12CE12C80E4F82E0DC052 +:10D9B000C12CD12C760109C00E94FD2A601B710B7D +:10D9C000613D774010F08AE01DC020E030E0A90101 +:10D9D00067E3CE010E94D36BA701960169E2CE01F5 +:10D9E0000E94D36B8B838111E7CF8C818230C9F485 +:10D9F00020E030E0A9016AE3CE010E94D36B8823C6 +:10DA000019F088E0898319C00E943B6B807C803CC0 +:10DA100011F483E08C830E943B6B0E943B6B0E945D +:10DA20003B6BCE010E94476B86E08B1518F488E1B2 +:10DA3000898306C0BA8281E004C0CE010E94476B90 +:10DA400080E0DF91CF911F910F91FF90EF90DF90D9 +:10DA5000CF90BF900895CF93DF93EC016EBD20E08F +:10DA600030E00DB407FEFDCFFA01E20FF31F808115 +:10DA70008EBD0DB407FEFDCF81818EBD2E5F3F4F61 +:10DA8000211582E0380769F70DB407FEFDCF8FEF4F +:10DA90000E94426B8FEF0E94426B0E943B6B8B8314 +:10DAA0008F71853039F083E18983CE010E94476B05 +:10DAB00080E001C081E0DF91CF9108950F931F9323 +:10DAC000CF93DF93EC0189018C81833039F0E9E059 +:10DAD000440F551F661F771FEA95D1F79A01AB01D6 +:10DAE00068E1CE010E94D36B882311F086E029C043 +:10DAF000A8016EEFCE010E942B6D8823B9F068E576 +:10DB000072E0CE010E94B76B811102C087E119C09B +:10DB100020E030E0A9016DE0CE010E94D36B8111BD +:10DB20000FC00E943B6B81110BC005C0CE010E944B +:10DB3000476B80E008C0CE010E94476B81E003C0C4 +:10DB400086E18983F3CFDF91CF911F910F910895E3 +:10DB50005058BB27AA270ED076C23FD230F044D20D +:10DB600020F031F49F3F11F41EF40FC20EF4E09543 +:10DB7000E7FBDCC1E92F89D280F3BA17620773078C +:10DB80008407950718F071F49EF5B8C20EF4E0957D +:10DB90000B2EBA2FA02D0B01B90190010C01CA0167 +:10DBA000A0011124FF27591B99F0593F50F4503E12 +:10DBB00068F11A16F040A22F232F342F4427585F04 +:10DBC000F3CF469537952795A795F0405395C9F71C +:10DBD0007EF41F16BA0B620B730B840BBAF09150D4 +:10DBE000A1F0FF0FBB1F661F771F881FC2F70EC073 +:10DBF000BA0F621F731F841F48F487957795679546 +:10DC0000B795F7959E3F08F0B3CF9395880F08F02E +:10DC10009927EE0F979587950895DFD158F080E802 +:10DC200091E009F49EEFE0D128F040E851E059F48A +:10DC30005EEF09C0AAC162C2E92FE07826D268F37C +:10DC4000092E052AC1F3261737074807590738F068 +:10DC50000E2E07F8E02569F0E025E0640AC0EF63C6 +:10DC600007F8009407FADB01B9019D01DC01CA0144 +:10DC7000AD01EF935DD0E7D10AD05F91552331F02C +:10DC80002BED3FE049E450FD49EC63CF0895DF936D +:10DC9000DD27B92FBF7740E85FE316161706480760 +:10DCA0005B0710F4D92F96D29F938F937F936F9336 +:10DCB000A9D3ECE7F0E06CD1C6D12F913F914F9101 +:10DCC0005F9101D3DD2349F09058A2EA2AED3FE0AD +:10DCD00049EC5FE3D0785D274DDFDF91B4C1F7D128 +:10DCE00080F09F3740F491110EF409C260E070E0BB +:10DCF00080E89FE3089526F01B16611D711D811DAC +:10DD00001BC135C1EFD008F481E0089575D1E395CA +:10DD1000ABC10CD098C168D140F05FD130F021F494 +:10DD20005F3F19F003C15111EAC12FC1AED198F381 +:10DD30009923C9F35523B1F3951B550BBB27AA278C +:10DD400062177307840738F09F5F5F4F220F331FFE +:10DD5000441FAA1FA9F333D00E2E3AF0E0E830D0CA +:10DD600091505040E695001CCAF729D0FE2F27D0CD +:10DD7000660F771F881FBB1F261737074807AB079B +:10DD8000B0E809F0BB0B802DBF01FF2793585F4F10 +:10DD90002AF09E3F510568F0C9C0B1C15F3FECF366 +:10DDA000983EDCF3869577956795B795F7959F5FD5 +:10DDB000C9F7880F911D9695879597F90895E1E029 +:10DDC000660F771F881FBB1F621773078407BA0788 +:10DDD00020F0621B730B840BBA0BEE1F88F7E095E3 +:10DDE000089504D06894B1118AC1089556D188F07D +:10DDF0009F5790F0B92F9927B751A0F0D1F0660F37 +:10DE0000771F881F991F1AF0BA95C9F712C0B13051 +:10DE100081F074D1B1E0089571C1672F782F882700 +:10DE2000B85F39F0B93FCCF3869577956795B39590 +:10DE3000D9F73EF490958095709561957F4F8F4FFF +:10DE40009F4F0895E89409C097FB3EF49095809504 +:10DE5000709561957F4F8F4F9F4F9923A9F0F92FB0 +:10DE600096E9BB279395F695879577956795B7952E +:10DE7000F111F8CFFAF4BB0F11F460FF1BC06F5F14 +:10DE80007F4F8F4F9F4F16C0882311F096E911C026 +:10DE9000772321F09EE8872F762F05C0662371F047 +:10DEA00096E8862F70E060E02AF09A95660F771F5B +:10DEB000881FDAF7880F9695879597F9089507D107 +:10DEC00080F09F3740F491110EF019C160E070E0CE +:10DED00080E89FEB089526F41B16611D711D811DBE +:10DEE0002BC045C0990F0008550FAA0BE0E8FEEFC4 +:10DEF00016161706E807F907C0F012161306E4070E +:10DF0000F50798F0621B730B840B950B39F40A2606 +:10DF100061F0232B242B252B21F408950A2609F4E4 +:10DF2000A140A6958FEF811D811D089597F99F67E8 +:10DF300080E870E060E00895882371F4772321F091 +:10DF40009850872B762F07C0662311F499270DC0B0 +:10DF50009051862B70E060E02AF09A95660F771F4B +:10DF6000881FDAF7880F9695879597F908959F3F50 +:10DF700031F0915020F4879577956795B795880F84 +:10DF8000911D9695879597F908959FEF80EC0895D8 +:10DF9000DF93CF931F930F93FF92EF92DF927B015A +:10DFA0008C01689405C0DA2EEF018DD1FE01E89452 +:10DFB000A5912591359145915591AEF3EF01DADDAB +:10DFC000FE019701A801DA9479F7DF90EF90FF90B6 +:10DFD0000F911F91CF91DF91089500240A94161696 +:10DFE000170618060906089500240A941216130647 +:10DFF000140605060895C9CF50D0E8F3E894E0E090 +:10E00000BB279F57F0F02AED3FE049EC06C0EE0F2A +:10E01000BB0F661F771F881F28F0B23A620773078D +:10E02000840728F0B25A620B730B840BE3959A9520 +:10E0300072F7803830F49A95BB0F661F771F881FE0 +:10E04000D2F7904896CF092E0394000C11F4882340 +:10E0500052F0BB0F40F4BF2B11F460FF04C06F5FA0 +:10E060007F4F8F4F9F4F0895EF93E0FF06C0A2EAC6 +:10E070002AED3FE049EC5FEB7DDDE5DF0F90039497 +:10E0800001FC9058E9EAF0E0C7C157FD9058440FF1 +:10E09000551F59F05F3F71F04795880F97FB991F07 +:10E0A00061F09F3F79F087950895121613061406C4 +:10E0B000551FF2CF4695F1DF08C016161706180651 +:10E0C000991FF1CF86957105610508940895E5DFE4 +:10E0D000A0F0BEE7B91788F4BB279F3860F4161686 +:10E0E000B11D672F782F8827985FF7CF8695779592 +:10E0F0006795B11D93959639C8F30895E894BB27A9 +:10E1000066277727CB0197F90895ECDE08F48FEFA7 +:10E11000089563DF19F068DF09F037CF07CFB90141 +:10E12000CA0125CF9F775F77B0DF98F39923B9F3C2 +:10E130005523B9F3FF27951758F4E52FE91BED3068 +:10E1400070F75E3B10F0F1E41CC09034E0F40AC0BC +:10E15000E92FE51BED3028F79E3B10F0F1E411C0EC +:10E16000503488F4F9EA88232AF09A95660F771FCD +:10E17000881FDAF744232AF05A95220F331F441FD1 +:10E18000DAF79F1B5F1BFF931F930F93FF92EF9292 +:10E1900079018A01BB27AB2F9B01AC0196D0970177 +:10E1A000A801BF937B018C01AA27BA2FB901CA012C +:10E1B0008CD0AF919701A801EF90FF900F911F9124 +:10E1C000D9DC41DFE1D04F9140FF0895552747FD4D +:10E1D000509509C09B01AC0160E070E080E89FE3CE +:10E1E00098CDA4CEC4CE59DFE8F39923D9F3940F88 +:10E1F000511DBBF39150504094F059F0882332F0F8 +:10E20000660F771F881F91505040C1F79E3F510500 +:10E2100044F7880F911D9695879597F908955F3F6C +:10E22000ACF0983E9CF0BB27869577956795B7959F +:10E2300008F4B1609395C1F7BB0F58F711F460FF74 +:10E24000E8CF6F5F7F4F8F4F9F4FE3CF58CF25DFD2 +:10E2500058F19E5758F19851A0F0E9F0983020F508 +:10E26000092E9927660F771F881F991F0A94D1F7E7 +:10E2700012C0062E672F782F8827985F11F4000CA4 +:10E2800007C0993FB4F38695779567959395D9F72D +:10E29000611D711D811D3EF490958095709561956D +:10E2A0007F4F8F4F9F4F0895689429CF27CF0BD072 +:10E2B000CACE93DE28F098DE18F0952309F036CE0A +:10E2C00064CE11241CCFE1DEA0F3959FD1F3950F0E +:10E2D00050E0551F629FF001729FBB27F00DB11DEA +:10E2E000639FAA27F00DB11DAA1F649F6627B00D7A +:10E2F000A11D661F829F2227B00DA11D621F739F63 +:10E30000B00DA11D621F839FA00D611D221F749F70 +:10E310003327A00D611D231F849F600D211D822FB7 +:10E32000762F6A2F11249F5750408AF0E1F08823FE +:10E330004AF0EE0FFF1FBB1F661F771F881F91500B +:10E340005040A9F79E3F510570F0F0CDD8CE5F3F09 +:10E35000ECF3983EDCF3869577956795B795F7953E +:10E36000E7959F5FC1F7FE2B880F911D96958795C6 +:10E3700097F908959F9340DE0F9007FCEE5F74CEEF +:10E3800011F40EF402CEF3CD88DED0F39923D9F345 +:10E39000CEF39F57550B87FF38D00024A0E640EA04 +:10E3A000900180585695979528F4805C660F771FEA +:10E3B000881F20F026173707480730F4621B730BBD +:10E3C000840B202931294A2BA695179407942025E0 +:10E3D00031254A2758F7660F771F881F20F0261728 +:10E3E0003707480730F4620B730B840B200D311D87 +:10E3F000411DA09581F7B901842F9158880F9695FA +:10E40000879508959B01AC0152CF91505040660F03 +:10E41000771F881FD2F708959F938F937F936F93F1 +:10E42000FF93EF939B01AC0142DFEF91FF91B0DDD1 +:10E430002F913F914F915F913ACF0E949272A59F89 +:10E44000900DB49F900DA49F800D911D11240895EF +:10E45000B7FF0C941D720E941D72821B930B0895CE +:10E46000DB018F939F930E941D72BF91AF91A29F7A +:10E47000800D911DA39F900DB29F900D11240895C2 +:10E4800097FB072E16F4009407D077FD09D00E9461 +:10E490009E7207FC05D03EF4909581959F4F08959C +:10E4A000709561957F4F0895A1E21A2EAA1BBB1BA0 +:10E4B000FD010DC0AA1FBB1FEE1FFF1FA217B30750 +:10E4C000E407F50720F0A21BB30BE40BF50B661F66 +:10E4D000771F881F991F1A9469F76095709580952A +:10E4E00090959B01AC01BD01CF010895052E97FBCE +:10E4F00016F4009407D057FD0DD00E94547207FC0B +:10E5000009D07EF490958095709561957F4F8F4FDF +:10E510009F4F089550954095309521953F4F4F4F0F +:10E520005F4F0895A29FB001B39FC001A39F01D088 +:10E53000B29F700D811D1124911D0895AA1BBB1B54 +:10E5400051E107C0AA1FBB1FA617B70710F0A61BF3 +:10E55000B70B881F991F5A95A9F780959095BC0114 +:10E56000CD010895EE0FFF1F0590F491E02D099461 +:10E57000A0E0B0E0EEEBF2E70C9478788B01611547 +:10E58000710519F0FB01808391837C01F701C19033 +:10E590007F01EF018C2D90E00E942675892BB1F749 +:10E5A000FDE2CF1204C0C990DD24D39405C02BE254 +:10E5B000C21201C0C990D12C7E0141E0E41AF108D9 +:10E5C00043E050E06AE773E1C7010E943675892B8A +:10E5D000E9F47E0182E0E80EF11C45E050E06DE7D1 +:10E5E00073E1C7010E943675892B21F47E01E7E0B3 +:10E5F000EE0EF11C0115110519F0F801F182E0820F +:10E6000010E0D0E0C0E8D110FBC0FFC043E050E014 +:10E6100062E873E1C7010E943675892B49F4011540 +:10E62000110509F4EFC02296F801D183C083EAC036 +:10E6300060E070E0CB01E12CF12CEC2DE053EA30EE +:10E6400048F5FD2DF2602D2D2870D2FE06C0211157 +:10E6500027C02FEFE21AF20A23C0222319F041E06B +:10E66000E41AF108A5E0B0E09B01AC010E941D7224 +:10E67000660F771F881F991F6E0F711D811D911DD9 +:10E680006839E9E97E078E07E9E19E0748F0FD2D2C +:10E69000F66006C0EE3F39F4D3FC3DC0FD2DF860B6 +:10E6A000C990DF2ECACFE53311F0E531A1F5A8817D +:10E6B000AD3219F4F0E1DF2A06C0AB3221F0219629 +:10E6C00021E030E004C0A981229622E030E0A0538E +:10E6D000AA3018F0C21BD30B1EC0FE0120E030E0B0 +:10E6E00020384CE034075CF4A901440F551F440F57 +:10E6F000551F240F351F220F331F2A0F311DA191E3 +:10E70000A053EF01AA3060F3D4FE03C031952195E8 +:10E710003109E20EF31ED1FE07C00115110521F0EB +:10E720002197F801D183C0830E94226F2D2D237081 +:10E73000233029F0162FD72FC82F092F07C0DC014F +:10E74000CB01B058182FD92FCA2F0B2F20E030E063 +:10E75000A901612F7D2F8C2F902F0E94826E88231C +:10E7600009F454C0F7FE08C0F194E194F10831EBCC +:10E77000C32E33E1D32E04C029E9C22E23E1D22EC9 +:10E780004601F8E18F1A910890E2A92EB12C15C02C +:10E79000F6014591559165917491242F352F462F9F +:10E7A000572F612F7D2F8C2F902F0E945771162F7E +:10E7B000D72FC82F092FEA18FB08EA14FB0444F7E7 +:10E7C00024E0C21AD108B594A794C814D904A9F7B3 +:10E7D000612F7D2F8C2F902F282F220F292F221F62 +:10E7E0002F3F39F020E030E0A9010E94826E8111B4 +:10E7F0000DC082E290E09093440E8093430E06C0D9 +:10E800000FEF04C010E0D0E0C0EC0FE7612F7D2FC8 +:10E810008C2F902FCDB7DEB7ECE00C949478A0E06D +:10E82000B0E0E5E1F4E70C9474782B018A016115FE +:10E83000710519F0FB01808391830115110539F0F1 +:10E840009801225031092332310508F0E6C07C01DD +:10E85000F701C1917F013F018C2F90E00E94267546 +:10E86000892BB1F7CD3229F4F701C1913F01D1E0F5 +:10E8700006C0CB3219F4F701C1913F01D0E0011578 +:10E88000110509F4D8C00031110581F4D0C0F3019D +:10E890008081883719F0883509F0C3C0F301C18140 +:10E8A000F2E06F0E711CD26000E110E0083011053B +:10E8B000D9F024F402301105F9F407C00A3011052B +:10E8C00051F000311105C1F425C0C12CD12CE12C2F +:10E8D00030E4F32E24C00AE010E02CECC22EDC2C35 +:10E8E000EC2C2CE0F22E1BC008E010E0C12CD12C47 +:10E8F000E12C90E1F92E13C09801442737FD409593 +:10E90000542F60E070E080E090E80E94547269014A +:10E910007A0105C0C12CD12CE12C88E0F82E40E012 +:10E9200060E070E0CB014801AA2497FCA094BA2CC7 +:10E93000EC2FE053EA3060F02C2F21542A3110F4F0 +:10E94000E75006C02C2F21562A3128F5EC2FE75529 +:10E950002E2F30E020173107F4F447FD18C0C616FB +:10E96000D706E806F90680F09B01AC01C501B401A9 +:10E970000E9430726E0F711D811D911D61307105F5 +:10E98000810520E8920710F04FEF01C041E0F3014C +:10E99000C1913F01CDCF4114510491F0442339F08E +:10E9A000F1E06F1A7108F2017182608209C0D1FF33 +:10E9B0001BC0F2E06F1A7108F2017182608214C00C +:10E9C00047FF12C0D0FF05C060E070E080E090E833 +:10E9D00004C06FEF7FEF8FEF9FE722E230E03093CC +:10E9E000440E2093430E16C0D0FF08C0909580952A +:10E9F000709561957F4F8F4F9F4F0CC097FF0AC056 +:10EA000082E290E09093440E8093430E6FEF7FEF8D +:10EA10008FEF9FE76B017C0112C0C12CD12C7601D6 +:10EA20000EC0C0E30115110509F45ECF3FCFC0331E +:10EA300009F03CCF2CCFC03309F04DCF28CFB60121 +:10EA4000C701CDB7DEB7E0E10C9490789111A7C271 +:10EA5000803219F089508550D0F7089591110895AA +:10EA600081548A5108F4805E855A0895FB01DC01C7 +:10EA70004150504088F08D9181341CF08B350CF45E +:10EA8000805E659161341CF06B350CF4605E861B12 +:10EA9000611171F3990B0895881BFCCFFB01DC0118 +:10EAA00004C08D910190801921F441505040C8F765 +:10EAB000881B990B0895FB01DC0102C001900D92A7 +:10EAC00041505040D8F70895FB01DC010D90002023 +:10EAD000E9F7119701900D920020E1F70895FC01EC +:10EAE0008191861721F08823D9F7992708953197C6 +:10EAF000CF010895FB01DC0101900D920020E1F7A8 +:10EB00000895FB01DC014150504030F08D9101909F +:10EB1000801919F40020B9F7881B990B0895FB019F +:10EB2000DC014150504048F001900D920020C9F79F +:10EB300001C01D9241505040E0F70895FB015191F2 +:10EB40005523A9F0BF01DC014D9145174111E1F7B3 +:10EB500059F4CD010190002049F04D91401541112B +:10EB6000C9F3FB014111EFCF81E090E001970895D7 +:10EB7000A0E1B0E0EEEBF5E70C9480780F89188DFA +:10EB800086E08C831A8309838FEF9FE79E838D83B2 +:10EB9000AE01455E5F4F588B4F87698D7A8DCE01F0 +:10EBA00001960E94DC75EF81F885E00FF11F10825D +:10EBB0006096E4E00C949C78ACE0B0E0E2EEF5E71F +:10EBC0000C9472787C016B018A01FC011782168219 +:10EBD000838181FFC7C188248394912C8C0E9D1E54 +:10EBE000F7019381F60193FD859193FF81916F0168 +:10EBF000882309F4B3C1853239F493FD859193FFDD +:10EC000081916F01853229F4B70190E00E94E87785 +:10EC1000E7CF712C312C20E02032A8F48B3261F048 +:10EC200028F4803251F0833271F40BC08D3239F008 +:10EC3000803349F4216028C02260246025C0286008 +:10EC400023C0206121C027FD27C0382F30533A3020 +:10EC500078F426FF06C0FAE07F9E300D1124732E53 +:10EC600013C08AE0389E300D1124332E20620CC070 +:10EC70008E3221F426FD72C1206406C08C3611F458 +:10EC8000206802C0883641F4F60193FD859193FF18 +:10EC900081916F018111C0CF982F9554933018F056 +:10ECA0009052933028F40C5F1F4FFFE3F9830DC09F +:10ECB000833631F0833771F0833509F05EC023C0AD +:10ECC000F801808189830E5F1F4F66246394712C45 +:10ECD000540115C02801F2E04F0E511CF801A0802C +:10ECE000B18026FF03C0672D70E002C06FEF7FEF99 +:10ECF000C5012C870E94DD773C0182012C856FE7DE +:10ED0000262E222218C02801F2E04F0E511CF801D5 +:10ED1000A080B18026FF03C0672D70E002C06FEFB6 +:10ED20007FEFC5012C870E94D2773C012C8550E8EB +:10ED3000252E222A820123FC1CC006C0B70180E2D6 +:10ED400090E00E94E8773A94832D90E06816790667 +:10ED5000A8F30FC0F50127FC859127FE81915F0183 +:10ED6000B70190E00E94E87731103A94F1E06F1A11 +:10ED700071086114710471F7EEC0843611F08936A0 +:10ED800041F5F80127FF07C060817181828193817D +:10ED90000C5F1F4F08C060817181882777FD8095C7 +:10EDA000982F0E5F1F4F4FE6642E622297FF09C017 +:10EDB00090958095709561957F4F8F4F9F4FF0E8AC +:10EDC0006F2A2AE030E0A4010E941478A82EA81827 +:10EDD00044C0853731F43FEEB32EB2222AE030E052 +:10EDE00024C099EFB92EB2228F36B9F020F48835BD +:10EDF00009F0B4C00DC0803721F0883709F0AEC0EB +:10EE000002C020E1B22AB4FE0BC084E0B82A08C0D8 +:10EE100024FF09C0E6E0BE2A06C028E030E005C0B5 +:10EE200020E130E002C020E132E0F801B7FE07C087 +:10EE300060817181828193810C5F1F4F06C0608168 +:10EE4000718180E090E00E5F1F4FA4010E94147852 +:10EE5000A82EA8188FE7682E6B2066FE0BC0362DF3 +:10EE60003E7FA71450F464FE0AC062FC08C0362D31 +:10EE70003E7E05C0BA2C362D03C0BA2C01C0B72C7B +:10EE800034FF0DC0FE01EA0DF11D8081803311F4C5 +:10EE9000397E09C032FF06C0B394B39404C0832FF7 +:10EEA000867809F0B39433FD14C030FF0FC07A2C7C +:10EEB000B31460F4730C7B18B32C08C0B70180E264 +:10EEC00090E03C870E94E877B3943C85B314B0F39C +:10EED00004C0B31410F43B1801C0312C34FF12C02D +:10EEE000B70180E390E03C870E94E8773C8532FFE1 +:10EEF0001EC031FF03C088E590E002C088E790E0C3 +:10EF0000B7010CC0832F867891F031FD02C080E2FA +:10EF100001C08BE237FD8DE2B70190E00E94E877F7 +:10EF200006C0B70180E390E00E94E8777A94A714C6 +:10EF3000C0F3AA94F401EA0DF11DB701808190E0BD +:10EF40000E94E877A110F5CF06C0B70180E290E0FB +:10EF50000E94E8773A943110F8CF42CEF70126812B +:10EF6000378102C02FEF3FEFC9012C96E2E10C94EC +:10EF70008E78F999FECF92BD81BDF89A992780B518 +:10EF80000895262FF999FECF1FBA92BD81BD20BDED +:10EF90000FB6F894FA9AF99A0FBE01960895992738 +:10EFA00088270895FC010590615070400110D8F742 +:10EFB000809590958E0F9F1F0895FC0161507040C1 +:10EFC00001900110D8F7809590958E0F9F1F08959E +:10EFD0000F931F93CF93DF938C01EB018B8181FD06 +:10EFE00003C00FEF1FEF1AC082FF0DC02E813F81BB +:10EFF0008C819D812817390764F4E881F981019398 +:10F00000F983E88306C0E885F985802F0995892B67 +:10F0100041F78E819F8101969F838E83C801DF9186 +:10F02000CF911F910F910895FA01AA27283051F12D +:10F03000203181F1E8946F936E7F6E5F7F4F8F4F29 +:10F040009F4FAF4FB1E03ED0B4E03CD0670F781F88 +:10F05000891F9A1FA11D680F791F8A1F911DA11D6D +:10F060006A0F711D811D911DA11D20D009F46894A6 +:10F070003F912AE0269F11243019305D3193DEF64E +:10F08000CF010895462F4770405D4193B3E00FD004 +:10F09000C9F7F6CF462F4F70405D4A3318F0495DEF +:10F0A00031FD4052419302D0A9F7EACFB4E0A695D2 +:10F0B0009795879577956795BA95C9F700976105F4 +:10F0C000710508959B01AC010A2E0694579547954A +:10F0D00037952795BA95C9F7620F731F841F951F3F +:10F0E000A01D08952F923F924F925F926F927F9250 +:10F0F0008F929F92AF92BF92CF92DF92EF92FF9248 +:10F100000F931F93CF93DF93CDB7DEB7CA1BDB0BF3 +:10F110000FB6F894DEBF0FBECDBF09942A88398898 +:10F1200048885F846E847D848C849B84AA84B9849F +:10F13000C884DF80EE80FD800C811B81AA81B981AB +:10F14000CE0FD11D0FB6F894DEBF0FBECDBFED01BF +:10F15000089513E1C8EBD3E104C0FE010E94B4722C +:0CF160002296CA3BD107C9F7F894FFCFF4 +:10F16C0000001B43000016430000B44200000000E6 +:10F17C0000000000000080BF6400640000803B457C +:10F18C0000803B4500007043000000000080BB4441 +:10F19C000160EA0000CDCCCC3D0000524300007A67 +:10F1AC004301010101010000803FE7849145AECF8E +:10F1BC001A3D00004041FF3FFF3F0171DBB6427139 +:10F1CC00DBB64200007A4500C05A440000FA430006 +:10F1DC0000FA430000A04000003442E8030000E8BD +:10F1EC0003000032000000FA0000004D3131300005 +:10F1FC002569206D696E2C20256920736563005587 +:10F20C0073696E672044656661756C7420736574F0 +:10F21C0074696E67733A004820004C20004D313001 +:10F22C003420496E76616C696420657874727564FB +:10F23C00657220004D31303520496E76616C696401 +:10F24C0020657874727564657220004D31303920F8 +:10F25C00496E76616C696420657874727564657248 +:10F26C0020003F006F6B0020703A0020693A0020AC +:10F27C00643A0020633A005400496E76616C69640C +:10F28C002065787472756465720041637469766583 +:10F29C002045787472756465723A20004D323900DD +:10F2AC0058595A45000001000F0015000E001200BD +:10F2BC00FFFF160017000E001300FFFF03000200F3 +:10F2CC001A001400FFFFFFFFFFFF0A00FFFF010001 +:10F2DC0000000E000D000700FFFFFFFF06002E00D0 +:10F2EC00000000007D3771371C6B537465707261C0 +:10F2FC00746520746F2068696768203A2000504953 +:10F30C0044204175746F74756E65207374617274EA +:10F31C00002F0043616E6E6F74206F70656E2073EA +:10F32C007562646972006175746F25692E67004D92 +:10F33C003233202573004D3234004D3834205820A0 +:06F34C0059205A20450083 +:00000001FF diff --git a/README b/README new file mode 100644 index 0000000..36ca447 --- /dev/null +++ b/README @@ -0,0 +1,26 @@ +This directory contains source code a number of objects of various +kinds, and a simple build system. + +In general for a simple file FOO.scad you can say `make FOO.stl'. + + +More complicated files contain source code for multiple related parts. +The actual objects which might be printed or previewed are indicated +in the source code with `///toplevel'. For a complicated file +BAR.scad you can generate simple template openscad files, one for each +such object, with `make BAR.auto.scads'. And you can make all the +corresponding .stl files with `make BAR.auto.stls'. + + +Many objects have `slop' in them, which represents an amount by which +holes or gaps are bigger, in order to make things fit well. You will +need to examine the openscad source or play around with previews to +see which slop does what. + + +Unless otherwise noted every object and file here is: + + Copyright Ian Jackson + Licenced under the GNU General Public Licence, version 3, or + (at your option) any later version. There is NO WARRANTY. + diff --git a/adafruit-powerboost-1000.scad b/adafruit-powerboost-1000.scad new file mode 100644 index 0000000..683eb81 --- /dev/null +++ b/adafruit-powerboost-1000.scad @@ -0,0 +1,175 @@ +// -*- C -*- + +psu_sz_nom = [ 11.43*2, 36.20 ]; + +//// toplevels-from: +include + +psu_hole_pos = [ 2.05, // from back edge of psu_sz[0] + 0.55 * 0.5 * 25.4, // from centreline + ]; + +psu_led_low_x = 4; + +psu_led_usbend_y_min = 4.5; +psu_led_chrg_min_x = -1.0; +psu_led_chrg_max_x = 3.0; +psu_led_chrg_both_sz_y = 9.4; + +psu_led_low_sz_x = 4.5; +psu_led_low_min_y = -1.5; +psu_led_low_max_y = 3.25; + +psu_led_baffle_th = 0.8; +psu_led_baffle_ends = 1.5; + +psu_baffle_th = [ 0.8, 3.5 ]; +psu_innerend_led_depth = 7; + +psu_led_legend_line = 0.75; + +psu_led_legend_battery_l = 6.0; +psu_led_legend_battery_w = 4.0; +psu_led_legend_battery_nub_l = 0.75; +psu_led_legend_battery_nub_w = 1.5; + +psu_led_legend_power_dia = 5.0; + +psu_led_legend_gap = 1.25; + +// ----- calculated ----- + +psu_led_legend_battery_edge = psu_led_legend_line; + +psu_led_legend_power_tick_l = + psu_led_legend_power_dia * 0.65; +psu_led_legend_power_tick_dy = psu_led_legend_line; + +psu_led_legend_power_sz_y = + psu_led_legend_power_dia/2 + psu_led_legend_power_tick_l/2 + - psu_led_legend_power_tick_dy; + +psu_innerend_led_x_midder = - psu_hole_pos[1] - psu_hole_dia/2; + +module PsuLedBafflePlan(){ + AtPsuMountCorner(0,0) { + translate([ (psu_led_chrg_min_x + psu_led_chrg_max_x)/2, + psu_led_usbend_y_min + psu_led_chrg_both_sz_y/2 ]) + square(center=true, + [ psu_led_chrg_max_x - psu_led_chrg_min_x + + psu_led_baffle_ends*2, + psu_led_baffle_th ]); + } +} + +module PsuLedWindowsPlanCore(){ + difference(){ + union(){ + // Two LEDs one side of inlet connector + // "Full" (near edge) and "Chrg" (inner) + AtPsuMountCorner(0,0) { + translate([0, psu_led_usbend_y_min ]) + rectfromto([ psu_led_chrg_min_x, 0 ], + [ psu_led_chrg_max_x, + psu_led_chrg_both_sz_y ]); + } + + // One LED, "Low", other side of inlet connector + AtPsuMountCorner(1,0) { + translate([0, psu_led_usbend_y_min ]) + rectfromto([ 0, + psu_led_low_min_y ], + [ psu_led_low_sz_x, + psu_led_low_max_y ]); + } + + // One LED, PWR, near outlet USB pads + AtPsuMountCorner(0,1){ + rectfromto([0,0], + [psu_sz[0]/2 + psu_innerend_led_x_midder, + psu_innerend_led_depth]); + } + } + } +} + +module PsuLedLegendBattery(percent=50){ + e = psu_led_legend_battery_edge; + empty_l = (100-percent)/100 * (psu_led_legend_battery_l - e*2); + difference(){ + union(){ + square([psu_led_legend_battery_l, + psu_led_legend_battery_w], center=true); + translate([psu_led_legend_battery_l/2, 0]) + square([psu_led_legend_battery_nub_l*2, + psu_led_legend_battery_nub_w], center=true); + } + if (empty_l > 0) + translate([-(psu_led_legend_battery_l/2-e), + -(psu_led_legend_battery_w/2-e)]) + square([empty_l, psu_led_legend_battery_w - e*2]); + } +} + +module PsuLedLegendPowerSymbol(){ + $fn=30; + tick_mid = [0, psu_led_legend_power_dia/2 - psu_led_legend_power_tick_dy]; + + cut_slope = ( psu_led_legend_gap + psu_led_legend_line/2 ) / tick_mid[1]; + cut_y = psu_led_legend_power_dia + 1; + + translate(tick_mid) + square([psu_led_legend_line, psu_led_legend_power_tick_l], center=true); + + difference(){ + circle(r= psu_led_legend_power_dia/2); + circle(r= psu_led_legend_power_dia/2 - psu_led_legend_line); + + polygon([[0, 0], + [-cut_y * cut_slope, cut_y], + [ cut_y * cut_slope, cut_y]]); + + if(0) translate(tick_mid) + square([psu_led_legend_line, psu_led_legend_power_tick_l] + + [psu_led_legend_gap*2, 0.1], + center=true); + } +} + +module PsuLedLegendsPlan(){ + translate([psu_led_legend_power_dia/2 + + psu_innerend_led_x_midder + + psu_led_legend_gap, + psu_sz[1]/2 + - psu_innerend_led_depth/2 + ]) + rotate([0,0,180]) + PsuLedLegendPowerSymbol(); + + for (full=[0,1]) { + translate([-psu_sz[0]/2 + + psu_led_legend_battery_l/2 + + psu_led_chrg_max_x + + psu_led_legend_gap, + -psu_sz[1]/2 + + psu_led_usbend_y_min + + psu_led_chrg_both_sz_y * 0.5 + + max( + psu_led_legend_battery_w + psu_led_legend_gap, + psu_led_chrg_both_sz_y * 0.5 + ) * (0.5 - full) + ]) + PsuLedLegendBattery(full ? 100 : 50); + } + + translate([psu_sz[0]/2 + - psu_led_legend_battery_nub_l + - psu_led_legend_battery_l/2, + -psu_sz[1]/2 + + psu_led_legend_gap + + psu_led_usbend_y_min + + psu_led_low_max_y + + psu_led_legend_battery_w/2 + ]) + PsuLedLegendBattery(0); +} diff --git a/adafruit-powerboost-500.scad b/adafruit-powerboost-500.scad new file mode 100644 index 0000000..d10002e --- /dev/null +++ b/adafruit-powerboost-500.scad @@ -0,0 +1,66 @@ +// -*- C -*- + +psu_sz_nom = [ 21.59, 35.56 ]; + +//// toplevels-from: +include + +psu_baffle_cnr_y = 7.45; // from connector end +psu_baffle_th = [ 0.8, 3.5 ]; +psu_usbend_led_x = 4.5; +psu_innerend_led_depth = 10; + +// ----- calculated ----- + +psu_usbend_led_depth = psu_baffle_cnr_y*2 - psu_usbend_led_x; + + +module PsuLedBafflePlan(){ + baffle_tr = [0, psu_baffle_cnr_y] + + 0.5 * [psu_baffle_th[1], psu_baffle_th[0]]; + translate([0, -psu_sz[1]/2]) { + mirror([1,0,0]) { + rectfromto([-psu_baffle_th[1]/2, 0], + baffle_tr); + rectfromto([-psu_sz[0]/2 - psu_board_support_wall *2, + baffle_tr[1] - psu_baffle_th[0]], + baffle_tr); + } + } +} + +module PsuLedLegendsPlan(){ +} + +module PsuLedWindowsPlanCore(){ + difference(){ + union(){ + // Two LEDs incl "Chrg", one side of inlet connector + AtPsuMountCorner(1,0) { + rectfromto([ -(psu_board_support_wall + 0.1), + +psu_usbend_led_x ], + [ psu_sz[0]/2, + +psu_usbend_led_depth ]); + } + + // One LED, "Low", other side of inlet connector + AtPsuMountCorner(0,0) { + sz = psu_baffle_cnr_y - psu_board_support_wall - psu_baffle_th[0]; + translate([0, psu_baffle_cnr_y]) + rectfromto([ -(psu_board_support_wall + 0.1), + -sz/2 ], + [ psu_sz[0]/2, + +sz/2 ]); + } + + // One LED, PWR, near outlet USB pads + AtPsuMountCorner(0,1){ + rectfromto([0,0], + [psu_sz[0]/2 - psu_hole_pos[1] - psu_hole_dia/2, + psu_innerend_led_depth]); + } + } + translate([0, -psu_sz[1]/2]) + square(center=true, [psu_baffle_th[1], psu_sz[1]]);; + } +} diff --git a/adafruit-powerboost-common.scad b/adafruit-powerboost-common.scad new file mode 100644 index 0000000..b62643a --- /dev/null +++ b/adafruit-powerboost-common.scad @@ -0,0 +1,337 @@ +// -*- C -*- + +include +include + +psu_sz = psu_sz_nom + [ 0.11, 0.44 ] + [ 0.25, 0.25 ]; + +psu_hole_pos = [ 2.05, // from back edge of psu_sz[0] + 0.55 * 0.5 * 25.4, // from centreline + ]; + +psu_th = 1.70 + 0.25; +psu_th_for_clamp = 1.50; + +psu_hole_dia = 2.5 - 0.5; +psu_connector_z = 2.9 + 0.1; +psu_connector_z_overlap = 0.15; +psu_connector_depth = 6.25; +psu_connector_w = 8.0 + 0.5; +psu_usb_protr = 0.6; + +psu_clamp_th = 4.0 + 0.75; +psu_clamp_w = 8.0; +psu_clamp_gap = 0.4; + +psu_board_clamp_ovlp = 4.5; +psu_board_nutbox = nutbox_data_M3; + +psu_board_gap = 0.5; +psu_board_support_wall = 2; +psu_board_support_ovlp = 4.5; +psu_board_support_ovlp_ceil = 2; +psu_board_support_z = 2; + +psu_baffle_gap = 1.0 + 0.5; + +psu_y = +psu_sz[1]/2 + psu_usb_protr; + +psu_usba_v_apart = 7.0; +psu_usba_v_from_edge = 4.86; +psu_usba_v_space_below = 1.5; +psu_usba_v_space_w = 1.7; +psu_usba_v_space_l = 3.0; + +psu_test_ceil = 2.5; + +// ----- calculated ----- + +psu_z = NutBox_h_base(psu_board_nutbox); +psu_z_down = psu_z + 0.1; +psu_fix_sz = NutBox_outer_size(psu_board_nutbox); +psu_board_nutbox_y = psu_sz[1]/2 + psu_board_nutbox[0]/2; + +psu_mount_outer_sz_x = psu_sz[0] + psu_board_support_wall * 2; // centred +psu_mount_outer_sz_y = psu_y + max(psu_board_support_wall, // at psu_y + psu_board_nutbox_y + psu_fix_sz/2); + +module PsuBoardRepresentation(){ + linear_extrude(height= psu_th) + square(center=true, [psu_sz[0],psu_sz[1]]); +} + +module PsuRepresentation(){ + PsuBoardRepresentation(); + translate([0, -psu_sz[1]/2, -psu_connector_z]) + linear_extrude(height= psu_connector_z + psu_connector_z_overlap) + rectfromto([ -psu_connector_w/2, -10 ], + [ +psu_connector_w/2, psu_connector_depth ]); +} + +module AtPsuMountCorner(mx,my){ + mirror([mx,0,0]) + mirror([0,my,0]) + translate(-0.5 * [psu_sz[0], psu_sz[1], 0] + -1 * [0,0, psu_z_down]) + children(); +} + +module PsuMountCornerExtrude(mx,my, plus_z=psu_board_support_z){ + AtPsuMountCorner(mx,my){ + linear_extrude(height= psu_z_down + plus_z, convexity=10) { + children(); + } + } +} + +module PsuUsbAVSpacePlan(){ + for (x= [-1,+1] * psu_usba_v_apart/2) { + translate([x, -psu_usba_v_from_edge ]) { + hull(){ + for (y= [-1,+1] * 0.5 * (psu_usba_v_space_l - psu_usba_v_space_w)) { + translate([0,y]) + circle(r= psu_usba_v_space_w); + } + } + } + } +} + +module PsuMountPositiveMain(){ + for (mx=[0,1]) { + for (my=[0,1]) { + PsuMountCornerExtrude(mx,my){ + rectfromto(-[1,1]*psu_board_support_wall, + +[1,1]*psu_board_support_ovlp); + } + } + // mount above at plug end + PsuMountCornerExtrude(mx,0, psu_th + psu_board_support_wall){ + rectfromto(-[1,1]*psu_board_support_wall, + [psu_board_support_ovlp, + psu_board_support_ovlp_ceil]); + } + } + translate([0,0, -psu_z_down]) + linear_extrude(psu_z_down - psu_baffle_gap, convexity=10) + PsuLedBafflePlan(); +} + +module PsuMountNegative(){ + axis = [0, -psu_sz[1]/2, psu_th]; + PsuRepresentation(); + translate(axis) + rotate([atan(2 * psu_board_support_z / psu_sz[1]), + 0,0]) + translate(-axis) + PsuBoardRepresentation(); +} + +module PsuMountPositive(){ + difference(){ + intersection(){ + PsuMountPositiveMain(); + linextr_y_xz(-psu_y, psu_sz[1]*2) square(100, center=true); + } + PsuMountNegative(); + intersection(){ + hull(){ + PsuBoardRepresentation(); + translate([0,0,5]) PsuBoardRepresentation(); + } + translate([-20,0,-20]) cube(40); + } + } + for (mx=[0,1]) { + PsuMountCornerExtrude(mx,1){ + translate([psu_sz[0]/2 - psu_hole_pos[1], + psu_hole_pos[0]] + + psu_board_gap * [1,1] ) + circle(r= psu_hole_dia/2); + } + } + difference(){ + translate([0, psu_board_nutbox_y, 0]) + rotate([0,0,180]) + NutBox(psu_board_nutbox, psu_z_down); + translate([0, psu_sz[1]/2, 0]) + linextr(-psu_usba_v_space_below, +10) + PsuUsbAVSpacePlan(); + } +} + +module PsuClamp(){ ////toplevel + rotate([180,0,0]) difference(){ + linear_extrude(height=psu_clamp_th + psu_th_for_clamp, convexity=5) { + difference(){ + hull(){ + circle(r = psu_fix_sz/2); + translate([ -psu_board_nutbox[0]/2, 0]) + square(center=true, [ psu_board_clamp_ovlp*2, psu_clamp_w ]); + } + circle(r = psu_board_nutbox[0]/2); + } + } + translate([0,0,-1]) linear_extrude(height=psu_th_for_clamp+1) { + translate([ -psu_board_nutbox[0]/2 + psu_clamp_gap, 0 ]) + mirror([1,0]) + translate([0,-20]) square(40); + } + linextr(-10,10) { + rotate(-90) + translate([0, -psu_board_nutbox[0]/2]) + PsuUsbAVSpacePlan(); + } + } +} + +module PsuLedWindowsPlan(){ + difference(){ + PsuLedWindowsPlanCore(); + PsuLedBafflePlan(); + } +} + +module PsuLedWindowsWindows(ceil){ + translate([0,0, -psu_z - ceil]) + linextr(0, psu_initial_layer_thick) + offset(delta=psu_window_ledge) + PsuLedWindowsPlan(); +} + +module PsuFirstLayerNegative(ceil){ + translate([0, 0, -psu_z - ceil]) + linextr(-1, psu_initial_layer_thick) + children(); +} + +module PsuMountWindowsNegative(ceil){ + linextr(-10, 0.1) + PsuLedWindowsPlan(); + PsuFirstLayerNegative(ceil) + offset(delta= psu_window_ledge + psu_multicolour_gap) + PsuLedWindowsPlan(); +} + +module PsuLedLegendsNegative(ceil){ + PsuFirstLayerNegative(ceil) + offset(delta= psu_multicolour_gap) + PsuLedLegendsPlan(); +} + +module PsuMountDemo() { ////toplevel + ceil = psu_test_ceil; + + translate([0, psu_y, psu_z]) { + difference(){ + PsuMountPositive(); + linextr(-20, 0.1) + PsuLedWindowsPlan(); + } + %PsuMountNegative(); + + color("yellow") translate([0,0, -psu_z - ceil]) + linear_extrude(height=0.4, convexity=10) + PsuLedWindowsPlan(); + + color("blue") translate([0,0, -psu_z - ceil]) + linear_extrude(height=0.4, convexity=10) + PsuLedLegendsPlan(); + + translate([0, psu_board_nutbox_y, 10]) + rotate([180,0,0]) + rotate([0,0,-90]) + PsuClamp(); + } +} + +module PsuMountTest() { ////toplevel + ceil = psu_test_ceil; + $fs = 0.1; + $fa = 3; + difference(){ + union(){ + translate([0, psu_y, psu_z]) + PsuMountPositive(); + difference(){ + + // rectangular box with wall + linextr_x_yz(-psu_mount_outer_sz_x/2, + +psu_mount_outer_sz_x/2) { + difference(){ + rectfromto([0, -ceil], + [psu_mount_outer_sz_y, psu_z + 10]); + rectfromto([ceil,0], 400*[1,1]); + } + } + + translate([0, psu_y, psu_z]) { + PsuMountNegative(); + } + } + } + translate([0, psu_y, psu_z]) { + PsuMountWindowsNegative(ceil); + PsuLedLegendsNegative(ceil); + } + } +} + +psu_multicolour_gap = 0.075; +psu_initial_layer_thick = 0.400; +psu_initial_layer_width = 0.750; +psu_window_ledge = 0.50; // each side + +psu_frame_gap = 1.0; + +module PsuMountLayerFrame(bl, tr, ix) { + gap0 = [1,1] * (psu_frame_gap + psu_initial_layer_width*(ix+0)); + gap1 = [1,1] * (psu_frame_gap + psu_initial_layer_width*(ix+1)); + linextr(0, psu_initial_layer_thick) { + difference(){ + rectfromto(bl-gap1, tr+gap1); + rectfromto(bl-gap0, tr+gap0); + } + } +} + +module PsuMountTestFullLayerFrame(ix) { + PsuMountLayerFrame([-0.5 * psu_mount_outer_sz_x, 0], + [+0.5 * psu_mount_outer_sz_x, + psu_mount_outer_sz_y], + ix); +} + +module PsuMountTestFullMain() { ////toplevel + ceil = psu_test_ceil; + + PsuMountTestFullLayerFrame(2); + + difference(){ + translate([0,0, ceil]) + PsuMountTest(); + } +} + +module PsuMountTestFullOneLayer(ix) { + PsuMountTestFullLayerFrame(ix); + linextr(0, psu_initial_layer_thick) { + translate([0, psu_y]) children(); + } +} + +module PsuMountTestFullText() { ////toplevel + PsuMountTestFullOneLayer(0) + PsuLedLegendsPlan(); +} +module PsuMountTestFullWindows() { ////toplevel + PsuMountTestFullLayerFrame(1); + translate([0, psu_y, psu_z + psu_test_ceil]) + PsuLedWindowsWindows(psu_test_ceil); +} + +module PsuMountTestFullDemo() { ////toplevel + color("blue") PsuMountTestFullMain(); + color("yellow") PsuMountTestFullText(); + %PsuMountTestFullWindows(); +} diff --git a/anglepoise-neck.scad b/anglepoise-neck.scad new file mode 100644 index 0000000..aa39ce2 --- /dev/null +++ b/anglepoise-neck.scad @@ -0,0 +1,83 @@ +// -*- C -*- + +arm_depth = 25; +arm_innerwidth = 9.60 - 0.50; +arm_innerheight = 8.90 - 0.50; +arm_pin_depth = 18.50 + 1.0; +arm_pin_dia = 1.5 + 0.7; + +armpart_hex_rad = 15; +armpart_main_thick = 8; + +hingepin_dia = 3 + 1.0; +hingenut_width = 6 + 1.0; +hingenut_depth = 4; +hingenut_clear = 5; + +headpart_main_dia = 15 + 0.3; +headpart_main_len = 16 + 1.1; +headpart_stub_protrude = 2; +headpart_stub_width = 11.7 - 0.6; + +headpart_flatten_angle = 45; + +// computed + +armpart_hinge_height = arm_innerheight + hingenut_width/2 + hingenut_clear; +armpart_main_height = armpart_hinge_height + headpart_stub_width / 2; +armpart_main_width = headpart_stub_width; +armpart_x_unit = armpart_hex_rad * tan(30); +headpart_flatten_z = headpart_main_dia/2 * cos(headpart_flatten_angle); +headpart_stub_support_x = headpart_stub_width * cos(59) / 2; +headpart_stub_len = headpart_stub_protrude + headpart_main_dia/2; +hingenut_depth_y = + sqrt(headpart_main_dia*headpart_main_dia/4 - hingenut_width*hingenut_width/4) + - hingenut_depth; + +module ArmPart(){ ////toplevel + difference(){ + translate([-arm_innerwidth/2, 1, 0]) + mirror([0,-1,0]) + cube([arm_innerwidth, arm_depth+1, arm_innerheight]); + translate([0, -arm_pin_depth, -50]) + cylinder(r=arm_pin_dia/2, h=100, $fn=20); + } + difference(){ + translate([-armpart_main_width/2, 0, 0]) + cube([armpart_main_width, armpart_main_thick, armpart_main_height]); + translate([0,50,armpart_hinge_height]) + rotate([90,0,0]) + cylinder(r=hingepin_dia/2, h=100, $fn=20); + } +} + +module HeadPart(){ ////toplevel + difference(){ + union(){ + translate([-headpart_main_len/2, 0,0]) + rotate([0,90,0]) + cylinder(r=headpart_main_dia/2, h=headpart_main_len, $fn=40); + rotate([90,0,0]) + cylinder(h = headpart_stub_len, + r = headpart_stub_width/2, + $fn = 6); + translate([-headpart_stub_support_x, + -headpart_stub_len, + -headpart_main_dia/2]) + cube([headpart_stub_support_x*2, + headpart_stub_len, + headpart_main_dia/2]); + } + translate([-100,-100,-100]) + cube([200,200, 100 - headpart_flatten_z]); + rotate([90,0,0]) + translate([0,0, -100]) + cylinder(r=hingepin_dia/2, h = 200, $fn=20); + translate([0,hingenut_depth_y,0]) + rotate([90,0,180]) + cylinder(r=hingenut_width/2/cos(30), h=20, $fn=6); + } +} + +//ArmPart(); +//HeadPart(); diff --git a/anglepoise-neck.slic3r b/anglepoise-neck.slic3r new file mode 100644 index 0000000..b5079ea --- /dev/null +++ b/anglepoise-neck.slic3r @@ -0,0 +1 @@ +perimeters = 4 diff --git a/anke-gps-bracket.scad b/anke-gps-bracket.scad new file mode 100644 index 0000000..084eefd --- /dev/null +++ b/anke-gps-bracket.scad @@ -0,0 +1,374 @@ +// -*- C -*- + +include + +// Dimensions of the main GPS body +outerw = 120; +outerh = 75; +outert = 15; +outerbackbevel = 3; + +// Dimensions for the holder +holder_outerw = outerw - 0.0; +holder_outerh = outerh + 0.0; +holder_outert = outert + 0.0; + +// Dimensions for the model +model_outerw = outerw + 2.5; +model_outerh = outerh - 0.2; +model_outert = outert - 1.0; + +// Dimensions of the bezel area round the edges +bezelw = 11 - 0.5; +bezelboth = 11 - 0.5; +bezeltoph = 7 - 0.5; + +// Dimensions of the speaker at the back +spkrdia = 22; +spkr2bot = 19; +spkr2rhs = 25; + +// Dimensions of the plug and wire +plugw = 12; +plugh = 9; +plug2bot = 11; +plug2lhs = 11; +plugtotald = 15; +pluggapd = 5; + +// Dimensions of the hole in the tray +// width and height (vertical) at the top +nestleh = 53; +nestlew = 60.9; +// depths (back to front distance): +nestledl = 40.2; +nestledr = 43.9; +// differences in width, depth, at bottom: +nestledwl = 2.1; +nestledwr = 1.4; +nestleddf = 4.0; +nestleddbl = 5.7; +nestleddbr = 5.2; + +// Adjustment for the GPS attitude and position +gpsazimuth = 45; +gpselevation = 40; +gpsrightwardoffset = 5; +gpsrearwardoffset = 2; +gpsrightwardoffsetonbar = 0; + +// Amount of wire protrusion to allow for +plugwiremoreh = 25; + +// Slops and steps etc. +plugslop = 0.5; +plughstep = 1.5; +bodylhsrhsslop = 0.5; +holderhgap = 5; +holderbezelmore = 2; +nestlebevel = 1; + +// Dimensions for strength only +screent = 1.0; +plugstrutw = 4; +plugstrutt = min(model_outert, 5); +nestledoveclipw = 20; +holderh = model_outerh * 0.5; +holderwallt = 2.5; +holderbackt = 2.8; +holderdccount = 2; +holderdoveclipl = 15; +chassish = 13; +chassist = 13; +nestlefloorh = 4.7; +nestleceilh = 6.0; +nestlewallmin = 10.0; +nestlearchslope = 0.75 * sqrt(0.5); + +// Consequential values +holderdcw = DoveClipPairSane_width(holderdccount); + +module GpsPlugPlug(slop){ + effhslop = slop - plughstep; + effplugw = plugw + slop*2; + effplugh = plugh + effhslop*2; + translate([plug2lhs-slop, plug2bot-effhslop, -1]) + cube([effplugw, effplugh, model_outert+2]); +} + +module GpsBodyOuterBevel(len){ + translate([0,-1,0]) { + rotate([-90,0,0]) { + linear_extrude(height=len+2) { + polygon([[-outerbackbevel, 0], + [ 0, outerbackbevel], + [outerbackbevel, 0], + [ 0, -outerbackbevel]]); + } + } + } +} + +module GpsBody() { ////toplevel + difference(){ + union(){ + difference(){ + cube([model_outerw, model_outerh, model_outert]); + translate([bezelw, bezelboth, screent]) + cube([model_outerw-bezelw*2, + model_outerh-bezelboth-bezeltoph, + model_outert]); + translate([model_outerw-spkr2rhs, spkr2bot, -1]) + cylinder(r=spkrdia/2, h=model_outert+2); + } + translate([plug2lhs+plugw/2, plug2bot+plugh/2, 0]) + cylinder(r=(plugw+plugh)/2, h=model_outert); + for (x=[plug2lhs-plugstrutw, plug2lhs+plugw]) + translate([x, 0.1, 0]) + cube([plugstrutw, model_outerh-0.2, plugstrutt-0.10]); + } + GpsPlugPlug(0); + for (x=[0,model_outerw]) translate([x,0,0]) GpsBodyOuterBevel(model_outerh); + for (y=[0,model_outerh]) translate([0,y,0]) + rotate([0,0,-90]) GpsBodyOuterBevel(model_outerw); + } +} + +module GpsPlug() { + plugwireh = plug2bot + plugwiremoreh; + translate([-plugslop,0,0]) GpsPlugPlug(-plugslop); + mirror([0,0,1]) translate([plug2lhs, plug2bot, 0]) { + cube([plugw, plugh, plugtotald-0.05]); + translate([0, -plugwireh, pluggapd]) + cube([plugw, plugwireh+0.05, plugtotald-pluggapd]); + } +} + +lhsteethu = 2; + +module GpsLHSMask(xslop=0){ + translate([plug2lhs + plugw+plugh+plugstrutw, + 0, + -50]) { + for (iter=[-100/lhsteethu : 100/lhsteethu]) { + translate([0, iter*lhsteethu*2, 0]) { + linear_extrude(height=100) { + polygon([[-300, 0], + [ 0, 0], + [lhsteethu,lhsteethu], + [ 0, lhsteethu*2], + [-300, lhsteethu*2+0.1]]); + } + } + } + } +} + +module GpsAssembled(){ ////toplevel + GpsBody(); + GpsPlug(); +} + +module GpsBodyLT(){ + intersection(){ + GpsBody(); + GpsLHSMask(); + } +} + +module GpsBodyRT(){ + difference(){ + GpsBody(); + GpsLHSMask(bodylhsrhsslop); + } +} + +module GpsPlugT(){ ////toplevel + rotate([0,-90,0]) GpsPlug(); +} + +module NestleCubeCutout(ca,cb,d){ + dist = cb - ca; + cuth = -nestleh + nestlefloorh; + mirror([0,1,0]){ + translate([0,1,0]) + rotate([90,0,0]){ + linear_extrude(height=d+2){ + polygon([[ca+nestlebevel, cuth], + [ca, cuth+nestlebevel*2], + [ca, -dist/2/nestlearchslope-nestleceilh], + [(ca+cb)/2, -nestleceilh], + [cb, -dist/2/nestlearchslope-nestleceilh], + [cb, cuth+nestlebevel*2], + [cb-nestlebevel, cuth]]); + } + } + } +} + +module NestleCube(){ ////toplevel + midw = nestlew/2; + midd = min(nestledl,nestledr); + midddb = max(nestleddbl,nestleddbr); + + based0 = nestleddf; + based1 = midd - midddb; + basew0 = -nestledwr; + basew1 = +nestledwl-nestlew; + + echo("wl,wr=", basew1, basew0); + echo("df,dbl,dbm,dbr", + based0, nestledl-nestleddbl, based1, nestledr-nestleddbr); + + cutd0 = based0 + nestlewallmin; + cutd1 = based1 - nestlewallmin; + cutw0 = basew0 - nestlewallmin; + cutw1 = basew1 + nestlewallmin; + + bevth = -nestleh + nestlebevel*2; + bevw = nestlebevel; + bevd = nestlebevel; + + translate([-(basew0+basew1)/2, -(based0+based1)/2, 0]) { + difference(){ + polyhedron + (points= + [[ +0 , +0, 0], // 0 + [ +0 , +nestledr, 0], // 1 + [ -midw , +midd, 0], // 2 + [ -nestlew, +nestledl, 0], // 3 + [ -nestlew, +0, 0], // 4 + [-nestledwr+0 , +nestleddf +0, bevth], // 5 + [-nestledwr+0 , -nestleddbr+nestledr, bevth], // 6 + [ -midw , -midddb +midd, bevth], // 7 + [+nestledwl-nestlew, -nestleddbl+nestledl, bevth], // 8 + [+nestledwl-nestlew, +nestleddf +0, bevth], // 9 + [-nestledwr+0 -bevw, +nestleddf +0 +bevd, -nestleh], // 10 + [-nestledwr+0 -bevw, -nestleddbr+nestledr-bevd, -nestleh], // 11 + [ -midw , -midddb +midd -bevd, -nestleh], // 12 + [+nestledwl-nestlew+bevw, -nestleddbl+nestledl-bevd, -nestleh], // 13 + [+nestledwl-nestlew+bevw, +nestleddf +0 +bevd, -nestleh]], // 14 + triangles=[// main side panels + [0,1,6],[6,5,0], + [1,2,7],[7,6,1], + [2,3,8],[8,7,2], + [3,4,9],[9,8,3], + [4,0,5],[5,9,4], + // bevels + [6,7,12],[12,11,6], + [7,8,13],[13,12,7], + [8,9,14],[14,13,8], + [9,5,10],[10,14,9], + [5,6,11],[11,10,5], + // top and bottom + [4,3,2],[2,1,0],[0,4,2], + [12,13,14],[10,11,12],[12,14,10]], + convexity=3); + union(){ + #NestleCubeCutout(cutw1, cutw0, max(nestledl,nestledr)); + #rotate([0,0,90]) NestleCubeCutout(cutd0, cutd1, nestlew); + } + } + } + + translate([gpsrightwardoffset,-gpsrearwardoffset,0]) + rotate([0,0,90+gpsazimuth]) + translate([nestledoveclipw/2,0,DoveClip_depth()-0.5]) + rotate([0,-90,0]) + DoveClipPairSane(count=3, h=nestledoveclipw); +} + +module NestleCubeBaseTest(){ ////toplevel + intersection(){ + translate([0,0,nestleh]) NestleCube(); + translate([-100,-100,0]) cube([200,200,nestlebevel*5]); + } + cube([5,5,10]); +} + +module NestleCubeCeilTest(){ ////toplevel + intersection(){ + translate([0,0,3]) NestleCube(); + translate([-100,-100,0]) cube([200,200,5.5]); + } + cube([5,5,10]); +} + +module NestleCubePin(){ ////toplevel + DoveClipPin(nestledoveclipw*0.4); +} + +module HolderSideL(){ ////toplevel + minz = -(bezelw - holderbezelmore) - holderbackt; + holdert = holder_outert + holderwallt*2; + cylr = 0.5*sqrt(holderdcw*holderdcw + holderdoveclipl*holderdoveclipl); + difference(){ + translate([-holderh, + -holderwallt, + minz]) { + cube([holderh + holderhgap + cylr, + holdert, + -minz]); + translate([holderh + holderhgap + cylr, holdert/2, 0]) { + cylinder(r=cylr, h=-minz); + rotate([0,0,gpselevation]) + translate([0, -holderdoveclipl/2, -minz + DoveClip_depth()]) + rotate([0,-90,-90]) + DoveClipPairSane(count=holderdccount, h=holderdoveclipl); + } + } + translate([-holderh-1, + 0, + minz + holderbackt]) + cube([holderh+1, + holder_outert, + bezelw]); + } +} + +module HolderSideR(){ ////toplevel + mirror([0,1,0]) HolderSideL(); +} + +module ChassisBar(){ ////toplevel + dist = holder_outerw - 2*((bezelw - holderbezelmore) + DoveClip_depth()); + cliph = holderdcw; + for (mir=[0,1]) { + mirror([mir,0,0]) { + translate([dist/2, cliph/2, 0]) + DoveClipPairSane(h=holderdoveclipl, count=holderdccount); + translate([-1, 0, 0]) + cube([dist/2 - DoveClip_depth() + 1.1, chassish, chassist]); + } + } + translate([-gpsrightwardoffsetonbar, -DoveClip_depth(), 0]) + rotate([0,0,-90]) + DoveClipPairSane(h=nestledoveclipw, count=3, + baseextend=chassist/2); +} + +module HolderSidePin(){ ////toplevel + DoveClipPin(holderdoveclipl*0.5); +} + +module Pins(){ ///toplevel + for (i=[1:4*holderdccount]) { + translate([i*10, 0, 0]) HolderSidePin(); + } + for (i=[1:6]) { + translate([i*10, 20, 0]) NestleCubePin(); + } +} + +//GpsPlugT(); +//GpsAssembled(); +//GpsBody(); +//NestleCube(); +//NestleCubeBaseTest(); +//NestleCubeCeilTest(); +//NestleCubePin(); +//HolderSideL(); +//HolderSideR(); +//HolderSidePin(); +//ChassisBar(); +//Pins(); diff --git a/atreic-piano-stand.scad b/atreic-piano-stand.scad new file mode 100644 index 0000000..be81606 --- /dev/null +++ b/atreic-piano-stand.scad @@ -0,0 +1,11 @@ +// -*- C -*- +height = 40; +depth = 20; +thick = 3; +width = 40; + +difference(){ + cube([width, depth, height]); + translate([thick, -1, thick]) + cube([width - thick*2, depth+2, height]); +} diff --git a/axlepin.scad b/axlepin.scad new file mode 100644 index 0000000..8b47771 --- /dev/null +++ b/axlepin.scad @@ -0,0 +1,47 @@ +// -*- C -*- +// +// axlepin.scad +// +// 3D designs for for securing things on axles +// Copyright 2012,2016 Ian Jackson +// +// This work 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 work 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 work. If not, see . + + + +function AxlePin_holerad() = 2; +function AxlePin_zoffset(holerad=2, slop=0.5) = (holerad - slop)*0.7; + +module AxlePin(axlerad, pinlen, holerad=2, tabthick=5, slop=0.5){ + pinr = holerad - slop; + intersection(){ + union(){ + translate([0, -pinlen/2, 0]) rotate([-90,0,0]) + cylinder(r=pinr, h=pinlen, $fn=10); + translate([-tabthick, axlerad, -holerad]) + cube([tabthick*2, holerad*2, holerad*2]); + } + translate([-50,-50,-AxlePin_zoffset(holerad,slop)]) + cube([100,100,50]); + } +} + +function Washer_thick() = 1.2; + +module Washer(axlerad, washerrad, thick=1.2, slop=0.5){ + difference(){ + cylinder(h=thick, r=washerrad); + translate([0,0,-1]) cylinder(h=thick+2, r=axlerad+slop); + } +} diff --git a/belt-cut-jig-common.scad b/belt-cut-jig-common.scad new file mode 100644 index 0000000..5464678 --- /dev/null +++ b/belt-cut-jig-common.scad @@ -0,0 +1,95 @@ +// -*- C -*- + +jig_max_len = 160; // print diagonally +//jig_max_len = 30; + +registrationgroove_width = 0.8; +registrationgroove_depth = 1.2; + +registrationprotrusion_poke = 3; +registrationprotrusion_slope = 0.75; + +jig_overlap = 1; + +jig_ends_extra = 2; + +jig_iters = floor((jig_max_len - jig_ends_extra) / jig_interval); +//jig_iters=2; +echo(jig_iters); + +module RegistrationGroove(l){ + // runs along the +ve X axis for length l but at correct z pos + translate([0, 0, jig_main_zsz + 0.1]) { + rotate([90,0,90]) + linear_extrude(height=l) + polygon([[-registrationgroove_width/2, 0], + [ +registrationgroove_width/2, 0], + [ 0, -registrationgroove_depth ]]); + } +} + +module OneJig(){ + difference(){ + translate([-(jig_interval/2 + jig_overlap), + jig_min_y, + -strap_thick]) + cube([jig_interval + 2, + jig_max_y - jig_min_y, + jig_main_zsz + strap_thick]); + OneJigCutout(); + translate([-100, -strap_width/2, -10]) + cube([200, strap_width, 10]); + translate([-100,0,0]) + RegistrationGroove(200); + for (xfrac=[-1/4,0,+1/4]) + translate([jig_interval * xfrac, -100, 0]) + rotate([0,0,90]) + RegistrationGroove(200); + } +} + +module RegistrationProtrusion(){ + // points towards the positive x axis + xsz = registrationprotrusion_poke; + ysz = registrationprotrusion_poke; + diag_sz = xsz * sqrt(2); + zsz = diag_sz / registrationprotrusion_slope; + hull(){ + translate([0, 0, 0.1]){ + linear_extrude(height=0.1) + polygon([[ 0, -ysz ], + [ xsz, 0 ], + [ 0, ysz ]]); + translate([-0.1, 0, zsz ]) + rotate([0,0,45]) + cube(0.1); + } + } +} + +module Jig(){ + for(end=[0,1]){ + for(yfrac=[-1/2, 0, 1/2]){ + translate([ end + ? jig_interval * (jig_iters - 0.5) + : -jig_interval/2, + yfrac * strap_width, + 0]) + rotate([0,0, end ? 0 : 180]) + translate([ jig_overlap, 0, 0 ]) + RegistrationProtrusion(); + } + } + for (i=[0:jig_iters-1]) { + translate([jig_interval * i, 0, 0]) + OneJig(); + } +} + +module JigPrint(){ + rotate([0,0,-45]) + translate([0,0,jig_main_zsz]) + rotate([180,0,0]) + Jig(); +} + diff --git a/belt-hole-cut-jig-simple.scad b/belt-hole-cut-jig-simple.scad new file mode 100644 index 0000000..68ef720 --- /dev/null +++ b/belt-hole-cut-jig-simple.scad @@ -0,0 +1,96 @@ +// -*- C -*- + +strap_thick = 3; +strap_width = 26.75 + 0.7; + +punch_dia = 11.10; + +punch_slop = 0.5; + +jig_interval = 20; + +reg_blocks = 3; + +jig_iters = 7; + +roof_thick = 4; +regblock_thick = 4; +punchtube_thick = 1.8; + +total_h = 33; +punchfree_h = 8; + +reg_prot_width = 4; + +// computed: + +punchhole_r = punch_dia/2 + punch_slop; +mainframe_l = jig_interval * jig_iters; + +mainframe_w = strap_width + reg_prot_width*2; + +echo(mainframe_l); + +module RegBlockOutline(){ + difference(){ + translate([0, -mainframe_w/2]) + mirror([1,0]) + square([total_h, mainframe_w]); + translate([1, -strap_width/2]) + mirror([1,0]) + square([strap_thick+1, strap_width]); + } +} + +module RegBlock(){ + translate([regblock_thick/2,0,total_h]) + rotate([0,-90,0]) + linear_extrude(height=regblock_thick) + RegBlockOutline(); +} + +module MainFrame(){ + translate([jig_interval/2, -mainframe_w/2, 0]) + mirror([1,0,0]) + cube([mainframe_l, mainframe_w, roof_thick]); + for (rbi=[0:reg_blocks-1]) { + translate([0 + + -(mainframe_l-jig_interval)/(reg_blocks-1) * rbi, + 0,0]) + RegBlock(); + } +} + +module PerHole(){ + for (holei=[0:jig_iters-1]) { + translate([-jig_interval * holei, 0, 0]) + child(0); + } +} + +module Shells(){ + PerHole(){ + cylinder(r=punchhole_r+punchtube_thick, h=total_h-punchfree_h, $fn=50); + } +} + +module Punches(){ + PerHole(){ + translate([0,0,-1]){ + cylinder(r=punchhole_r, h=total_h+2, $fn=100); + %cylinder(r=punch_dia/2, h=total_h); + } + } +} + +module Jig(){ + difference(){ + union(){ + MainFrame(); + Shells(); + } + Punches(); + } +} + +Jig(); diff --git a/belt-hole-cut-jig.scad b/belt-hole-cut-jig.scad new file mode 100644 index 0000000..36380a0 --- /dev/null +++ b/belt-hole-cut-jig.scad @@ -0,0 +1,38 @@ +// -*- C -*- + +strap_thick = 3; +strap_width = 26.75 + 0.7; + +jig_interval = 20; + +edgewall_width = 3; + +jig_ywidth = 17; + +jig_min_y = -jig_ywidth; +jig_max_y = +jig_ywidth; + + +jig_main_zsz = 28; +punch_dia = 12.75; + +punch_slop = 0.5; + +// common stuff + +include + +module OneJigCutout(){ + translate([0,0,-10]) + cylinder(r= punch_dia/2 + punch_slop, h=100, $fn=50); +} + +module Demo(){ ////toplevel + Jig(); +} + +module JigT(){ ////toplevel + JigPrint(); +} + +JigT(); diff --git a/belt-slot-cut-jig,JigT.auto.slic3r b/belt-slot-cut-jig,JigT.auto.slic3r new file mode 100644 index 0000000..33b5b29 --- /dev/null +++ b/belt-slot-cut-jig,JigT.auto.slic3r @@ -0,0 +1,2 @@ +fill_angle = 0 +skirt_distance = 1 diff --git a/belt-slot-cut-jig,Kit.auto.slic3r b/belt-slot-cut-jig,Kit.auto.slic3r new file mode 100644 index 0000000..33b5b29 --- /dev/null +++ b/belt-slot-cut-jig,Kit.auto.slic3r @@ -0,0 +1,2 @@ +fill_angle = 0 +skirt_distance = 1 diff --git a/belt-slot-cut-jig.scad b/belt-slot-cut-jig.scad new file mode 100644 index 0000000..543a53f --- /dev/null +++ b/belt-slot-cut-jig.scad @@ -0,0 +1,195 @@ +// -*- C -*- + +// todo +// various registration marks +// protrustions at ends at strap width and middle +// grooves on top face at 1/4,1/2,3/4 length and 1/2 width + +strap_thick = 3; +strap_width = 26.75 + 0.7; + +jig_interval = 25; + +edgewall_width = 3; +crewpunch_slop = 0.3; +main_slop = 0.25; + +holder_min_wall = 2; +holder_attach_near_wall = 5; + +holder_attach_xsz = 5; +holder_ctie_width = 4.0 + 0.5; +holder_ctie_thick = 3.0 + 0.5; +holder_attach_walls = 3; +holder_attach_roof = 2.5; + +holder_corner_round = 2.0; + +punch_travel = 8; + +// from careful measurement + +crewpunch_shape = + [[ 6, [0.6, 6.0], [1.6, 12.3] ], + [ 8, [1.1, 6.2], [1.9, 12.5] ], + [ 10, [1.6, 6.5], [2.1, 12.8] ], + [ 12, [1.8, 6.6], [2.3, 12.7] ], + [ 14, [2.1, 6.8], [2.6, 13.0] ], + [ 16, [2.4, 6.9], [2.7, 13.2] ], + [ 18, [2.5, 7.0], [2.9, 13.3] ], + [ 22, [3.1, 7.1], [3.2, 13.4] ], + [ 26, [3.3, 7.2], [3.5, 13.6] ], + ]; + +crewpunch_shaft_max_y = 7.5; + +crewpunch_systematic_size_error = +0.36; + +crewpunch_smallest_shape = crewpunch_shape[0]; +crewpunch_biggest_shape = crewpunch_shape[len(crewpunch_shape)-1]; + +crewpunch_skew_angle = 3.5; //degrees +crewpunch_skew_yoff = +1.1; //mm + +// computed + +punch_dx = 0.5 * (-crewpunch_biggest_shape[2][0] + +crewpunch_biggest_shape[2][1]); +punch_dy = 0.5 * (+crewpunch_biggest_shape[1][1] + -crewpunch_biggest_shape[1][0]) + crewpunch_skew_yoff; + +attach_ysz = holder_attach_walls*2 + holder_ctie_width; + +holder_block_zsz = crewpunch_biggest_shape[0] - crewpunch_smallest_shape[0]; +holder_xsz = crewpunch_biggest_shape[2][0] + crewpunch_biggest_shape[2][1] + + holder_min_wall*2; + +holder_skewangle_yextra = holder_xsz/2 * sin(abs(crewpunch_skew_angle)); + +holder_max_y = punch_dy + crewpunch_biggest_shape[1][0] + holder_min_wall + + crewpunch_systematic_size_error + holder_skewangle_yextra; + +holder_attach_max_y = punch_dy + - max(crewpunch_biggest_shape[1][1], crewpunch_shaft_max_y) + - crewpunch_systematic_size_error - holder_skewangle_yextra; + +holder_block_min_y = punch_dy + - crewpunch_biggest_shape[1][1] - holder_attach_near_wall + + - crewpunch_systematic_size_error - holder_skewangle_yextra; + +holder_all_min_y = holder_attach_max_y - attach_ysz; + +jig_max_y = max(holder_max_y + main_slop, strap_width/2) + edgewall_width; +jig_min_y = min(holder_all_min_y - main_slop, -strap_width/2) - edgewall_width; + +jig_main_zsz = holder_block_zsz + punch_travel; + +// common stuff + +include + +// objects + +module CrewPunch(){ + ourslop = crewpunch_slop - crewpunch_systematic_size_error; + hull(){ + for(layer=crewpunch_shape){ + translate([0,0, layer[0]]){ + for(xind=[0,1]) //translate([xind?0:1,0,0]) + for(yind=[0,1]) //translate([0,yind?0.5:0,0]) + mirror([xind?1:0,0,0]) mirror([0,yind?0:1,0]){ + translate([-0.1,-0.1,-0.1]) + cube([0.1 + layer[2][xind] + ourslop, + 0.1 + layer[1][1-yind] + ourslop, + 0.2]); + } + } + } + } +} + +module MaybeRoundedCube(sizes, roundedness){ + if (roundedness > 0) { + translate([roundedness, roundedness, 0]){ + minkowski(){ + cube([sizes[0] - roundedness*2, + sizes[1] - roundedness*2, + sizes[2]]); + cylinder(h=0.05, r=roundedness, $fn=20); + } + } + } else { + cube(sizes); + } +} + +module PunchHolder(cutouts=true){ + roundedness = cutouts ? holder_corner_round : 0; + difference(){ + translate([-holder_xsz/2, holder_block_min_y, 0]) + MaybeRoundedCube([holder_xsz, + holder_max_y - holder_block_min_y, + holder_block_zsz], + roundedness); + if (cutouts) + rotate([0,0,-crewpunch_skew_angle]) + translate([punch_dx, + punch_dy, + -crewpunch_smallest_shape[0]]) + CrewPunch(); + } + difference(){ + translate([-holder_attach_xsz/2, holder_all_min_y, 0]) + MaybeRoundedCube([holder_attach_xsz, + attach_ysz, + holder_block_zsz + punch_travel + + holder_ctie_thick + holder_attach_roof + 1], + roundedness); + if (cutouts) + translate([-30, + holder_all_min_y + holder_attach_walls, + holder_block_zsz + punch_travel]) + cube([60, holder_ctie_width, holder_ctie_thick]); + } +} + +module OneJigCutout(){ + minkowski(){ + cube([main_slop*2, main_slop*2, 50], center=true); + PunchHolder(false); + } +} + +module JigT(){ ////toplevel + JigPrint(); +} + +module PunchHolderT(){ ////toplevel + PunchHolder(true); +} + +module Demo(){ ////toplevel + %PunchHolder(); + Jig(); +} + +module Kit(){ ////toplevel + JigT(); + rotate([0,0,-45]){ + translate([(jig_iters-1)*jig_interval/2, + jig_min_y - holder_max_y - 5, + 0]) + PunchHolder(); + } +} + +//CrewPunch(); +//PunchHolder(); +//PunchHolder(false); +//OneJig(); +//Jig(); +Demo(); +//JigT(); +//RegistrationProtrusion(); +//PunchHolderT(); +//Kit(); diff --git a/bike-lipo-box-gland.scad b/bike-lipo-box-gland.scad new file mode 100644 index 0000000..0e9228b --- /dev/null +++ b/bike-lipo-box-gland.scad @@ -0,0 +1,59 @@ +// -*- C -*- + +include + +cable_dias = [6.5, 8.2]; + +cd = cable_dias[1] + 0.5; +wall = 2.5; + +function Gland_xlen(cabledia) = cabledia * 1.5; +function Gland_xdia(cabledia) = cabledia * 2.0; +function Gland_xoutdia(cabledia) = Gland_xdia(cabledia) * 1.1 + 0.5; + +// origin is centre, on outside +// outside is in direction of positive X axies +module GlandNegative(cabledia){ + xlen = Gland_xlen(cabledia); + xdia = Gland_xdia(cabledia); + + hull(){ + rotate([0,90,0]) cylinder(r= cabledia/2, h=1); + translate([xdia,0,0]) rotate([0,90,0]) cylinder(r= xdia/2, h=1); + } + translate([-10,0,0]) + rotate([0,90,0]) + cylinder(r= cabledia/2, h=11); +} + +module GlandPositive(cabledia){ + translate([-0.1, 0,0]) + rotate([0,90,0]) + cylinder(r= Gland_xoutdia(cabledia)/2, h= Gland_xlen(cabledia) + 0.1); +} + +platesz = [wall, 24, 28]; +plateoff = [-platesz[0]/2, -platesz[1]/2, -platesz[2] + platesz[1]/2]; + +module Plate(){ + difference(){ + union(){ + GlandPositive(cd); + translate(plateoff) + cube(platesz); + } + GlandNegative(cd); + } +} + +module Test(){ ////toplevel + Plate(); + translate(plateoff){ + difference(){ + cube([15, 20, 1.2]); + Commitid_BestCount_M([15, 20]); + } + } +} + +//Test(); diff --git a/bike-lipo-box.scad b/bike-lipo-box.scad new file mode 100644 index 0000000..edd3701 --- /dev/null +++ b/bike-lipo-box.scad @@ -0,0 +1,294 @@ +// -*- C -*- + +include +include +include +include + +pxp6012_rad = 22.5 / 2 + 0.5; // make circular hole this size in outer wall +pxp6012_rad_outer = 32.0 / 2 - 0.5; + +s1930_y = 30.2 + 0.2; +s1930_x = 22 + 0.2; +s1930_y_outer = 36.4 + 0.2; +s1930_x_outer = 27.6 + 0.2; + +s1930_recess = 3; +s1930_around = 3; +s1930_behind = 3; + +jdae12pa_rad = 12 / 2 + 0.5; +jdae12pa_rad_outer = 19 / 2 + 0.5; // head of an "M12 bolt" + +totx_inner = 180; +toty_outer = 95; +totz_inner = 27.0; + +wallthick = 2.5; + +cabledia = 8.7; + +strap_w = 5 + 1; +strap_th = 4 + 1; +strap_pillar = 3; +strap_pillard = 5; +strap_over = 2; + +lipokeeper_w = 10; +lipokeeper_h = 8; +lipokeeper_d_min = 2; +lipokeeper_slope = 0.75; +lipokeeper_end_h = 12; +lipokeeper_end_d_min = 15; + +straps_at_box = [45, 95, 125, 160]; +straps_every = 30; + +// calculated + +totx_outer = totx_inner + wallthick*2; +toty_inner = toty_outer - wallthick*2; +totz_outer = totz_inner + wallthick*2; + +sb_box_sz = [totx_outer, totz_outer, toty_inner]; + +// origin is at centre on outer face wall +// outside is towards positive x +// mounting is vertical +module S1930_Positive(){ + d = s1930_recess + s1930_behind; + translate([-d/2, 0,0]) + cube([d, + s1930_x_outer + s1930_around, + s1930_y_outer + s1930_around], center=true); +} +module S1930_Negative(){ + cube([60, s1930_x, s1930_y], + center=true); + translate([1, 0,0]) + cube([s1930_recess*2+2, s1930_x_outer, s1930_y_outer], + center=true); +} + +module TestWall(){ ////toplevel + sw_ctr = [25, wallthick, 25]; + + rotate([0,0,-90]){ + difference(){ + union(){ + cube([50, wallthick, 42]); + } + + translate([30, -1, 20]) + rotate([-90,0,0]) + cylinder(r = pxp6012_rad, h=10, $fn=60); + + rotate([90,0,0]) + Commitid_BestCount([15,40]); + } + } + + difference(){ + union(){ + cube([50, wallthick, 50]); + translate(sw_ctr) + rotate([0,0,90]) + S1930_Positive(); + } + + translate(sw_ctr) { + rotate([0,0,90]) + S1930_Negative(); + } + } +} + +ts_totx = 30; +ts_toty = 25; +ts_totz_inner = 8; + +ts_box_sz = [ts_totx, ts_toty, ts_totz_inner]; + +$sealingbox_wallth = wallthick; +$sealingbox_floorth = wallthick; +$sealingbox_ceilth = wallthick; + +module TestSealBox(){ ////toplevel + $sealingbox_sz = ts_box_sz; + + SealingBox_RectBox(); + ts_cidoff = ($sealingbox_cnrrad * (1-.7) + wallthick * .8) * [1,1]; + translate(ts_cidoff) + Commitid_BestCount([ts_totx,ts_toty] - 2*ts_cidoff); +} + +module TestSealLid(){ ////toplevel + $sealingbox_sz = ts_box_sz; + + difference(){ + SealingBox_RectLid(); + + translate([ts_totx * .75, ts_toty/2, 0]) + cylinder(h=100, r=5); + + translate([-wallthick + $sealingbox_cnrrad*.5, + $sealingbox_cnrrad*.5 - wallthick, + ts_totz_inner + $sealingbox_ceilth]) + Commitid_BestCount([ts_totx * .75 - 2.5 - ($sealingbox_cnrrad*.5), + ts_toty - ($sealingbox_cnrrad*.5 - wallthick)*2]); + } +} + +module TestSealLidPrint(){ ////toplevel + rotate([180,0,0]) TestSealLid(); +} + +module ProfileDemos(){ ////toplevel + $sealingbox_sz = ts_box_sz; + + SealingBox_WallProfile(); + color("blue") SealingBox_FloorProfile(); + SealingBox_LidProfile(); + color("blue") SealingBox_CeilProfile(); + color("red") translate([-5,0]) square([1,ts_totz_inner]); +} + +module AtGlands(){ + for (dgy=[-15,-45]) { + translate([totx_inner + wallthick - $sealingbox_cnrrad * .3, + toty_inner + dgy, + totz_inner/2]) + children(); + } +} + +module StrapKeepers(at){ + strap_x_tot = strap_w + strap_pillar*2; + + for (sx= at) { + echo("strapkeeper at ",sx); + translate([sx - strap_x_tot, 0, 0]) + difference(){ + translate([0,0, -0.1]) + cube([strap_x_tot, strap_pillard, strap_th + strap_over]); + translate([strap_pillar, -1, 0]) + cube([strap_w, strap_pillard+2, strap_th]); + } + } +} + +chargingconn_x = pxp6012_rad_outer + 1 + $sealingbox_cnrrad; +switch_x = chargingconn_x + pxp6012_rad_outer + + s1930_y_outer/2 + s1930_around; + +module AtSealingBox(){ + rotate([90,0,0]) + translate([-wallthick,-wallthick, -toty_inner]) + children(); +} + +module Box(){ ////toplevel + $sealingbox_sz = sb_box_sz; + + difference(){ + union(){ + AtSealingBox() + SealingBox_RectBox(); + + translate([switch_x, toty_inner, totz_inner/2]) + rotate([90,0,90]) + S1930_Positive(); + + // keepers for lipo + for (keepers= [[ 35, lipokeeper_d_min, lipokeeper_h, + [ 40, 80, 120, 150 ] ], + [ 10, lipokeeper_end_d_min, lipokeeper_end_h, + [ 25 ] ] + // each entry: [ y, d_min, h, [ x, ...] ] + ]) + for (kx= keepers[3]) { + translate([kx, keepers[0], -1]) + hull(){ + cube([lipokeeper_w, keepers[1], keepers[2] +1]); + cube([lipokeeper_w, + keepers[1] + keepers[2] / lipokeeper_slope, + 1]); + } + } + + AtGlands() + GlandPositive(cabledia); + + translate([0, toty_inner+wallthick, -wallthick]) + rotate([180, 0,0]) + StrapKeepers(straps_at_box); + } + + // charging connector + translate([chargingconn_x, + toty_inner - (pxp6012_rad_outer + 5), + 10]) + cylinder(r= pxp6012_rad, h= totz_outer); + + // vent connector + translate([chargingconn_x, + toty_inner - (pxp6012_rad_outer*2 + 5 + 15 + + jdae12pa_rad_outer), + 10]) + cylinder(r= jdae12pa_rad, h= totz_outer); + + translate([switch_x, toty_inner, totz_inner/2]) + rotate([90,0,90]) + S1930_Negative(); + + AtGlands() + GlandNegative(cabledia); + + translate(-$sealingbox_cnrrad * [1,1,0] + + [totx_inner, toty_inner/2, -wallthick]) + rotate([0,0,180]) + scale([2,2,1]) + Commitid_Full16_M(); + } +} + +module BoxPrint(){ ////toplevel + rotate([-90,0,-90]) + Box(); +} + +module Lid(){ ////toplevel + $sealingbox_sz = sb_box_sz; + difference(){ + union(){ + AtSealingBox() + SealingBox_RectLid(); + translate([0, -wallthick, -SealingBox_lidbigger()]) + mirror([0,0,1]) + StrapKeepers([ straps_every : straps_every + : totx_inner-straps_every ]); + } + + translate($sealingbox_cnrrad * [1,0,1]) + rotate([90,0,0]) + scale([1.5, 1.5, 1]) + Commitid_Small16_M(); + } +} + +module LidPrint(){ ////toplevel + rotate([90,0,-90]) + Lid(); +} + +module Demo(){ ////toplevel + color("blue") Box(); + color("red") Lid(); +} + +//TestWall(); +//ProfileDemos(); +//TestSealBox(); +//TestSealLid(); +//FArcSegment_mask(350); +//StrapKeepers(); diff --git a/bike-phone-mount.scad b/bike-phone-mount.scad new file mode 100644 index 0000000..bb69726 --- /dev/null +++ b/bike-phone-mount.scad @@ -0,0 +1,101 @@ +// -*- C -*- + +// should rename this to actual name of the product + +include + +mount_lip_height = 2.0 - 0.15 - 0.15; +mount_lip_depth = 2.5 /*?*/ - 0.30; +mount_neck_width = 26.5 - 0.55 - 0.15; +mount_neck_length = 1.5 + 0.50; + +mount_diag_outer = 34.8 - 0.50; +mount_diag_inner = 34.6 - 0.20 - 0.50; + +mount_slope = .65; +mount_extra_slope = 3; + +mount_demo_ceil = 4; + +// calculated + +mnep0 = [0,0]; +mnep1 = mnep0 + [0,1] * mount_neck_length; +mnep7 = mnep0 + [1,0] * mount_lip_depth; +mnep2 = [ mnep7[0] + mount_extra_slope, mnep1[1] + mount_slope * (mnep7[0] + mount_extra_slope - mnep1[0]) ]; +mnep3 = mnep2 + [0, 0.1]; +mnep4 = [ mnep0[0]-1, mnep3[1] ]; +mnep6 = mnep7 + [0,-1] * mount_lip_height; +mnep5 = [ mnep4[0], mnep6[1] ]; +mnepm = [ mnep0[0], mnep3[1] ]; + +mount_total_height = mnep2[1] - mnep6[1]; +mnep_z_offset = -mnep2[1]; +mnep_side_offset = [ mount_neck_width/2, mnep_z_offset ]; + +module MountNeckEdgePlan() { + polygon([ mnep0, + mnep1, + mnep2, + mnep3, + mnep4, + mnep5, + mnep6, + mnep7 ]); +} + +module MountNeckSquare() { + intersection_for (r=[0,90]) { + rotate([0,0,r]){ + linextr_y_xz(-100,100,convexity=10){ + for (m=[0,1]) { + mirror([m,0]) { + translate(mnep_side_offset) MountNeckEdgePlan(); + rectfromto([-0.1, -mount_total_height], + mnep_side_offset + mnepm); + } + } + } + } + } +} + +module MountDiagonal() { + rotate([0,0,45]){ + translate([0,0, -mount_total_height]){ + linextr(0, mount_lip_height) + square(center=true, mount_diag_outer); + linextr(0, mount_total_height) + square(center=true, mount_diag_inner); + linextr(mount_lip_height + mount_neck_length, + mount_total_height + 1) + square(center=true, 100); + } + } +} + +module MountDemoCeil() { + c = mount_demo_ceil + mount_extra_slope; + linextr(0, 0.8) { + square(mount_neck_width + 2*(mount_demo_ceil + mount_extra_slope), + center=true); + } +} + +module Mount(){ + intersection(){ + MountNeckSquare(); + MountDiagonal(); + } +} + +module MountDemo(){ ////toplevel + Mount(); + MountDemoCeil(); +} + +//MountNeckEdgePlan(); +//MountNeck(); +//MountDemoCeil(); +//MountDiagonal(); +//MountDemo(); diff --git a/bike-stalk-led-mount.scad b/bike-stalk-led-mount.scad new file mode 100644 index 0000000..a3c0c4e --- /dev/null +++ b/bike-stalk-led-mount.scad @@ -0,0 +1,71 @@ +// -*- C -*- + +include + +stalk_dia = 6.4 + 0.25; + +length = 50; +width = 12; + +strap_below = 2; +strap_thick = 2; +strap_width = 5; +strap_above = 0.25; + +arch_above = 2; + +inside_gap = 0.5; + +// calculated + +height_base = stalk_dia/2 - inside_gap/2; +above_height = height_base + arch_above; +below_height = height_base + max(arch_above, + strap_below + strap_thick + strap_above); + +module StalkCutout(){ + translate([-length,0,0]) + rotate([0,90,0]) + cylinder(r= stalk_dia/2, h=length*2, $fn=40); +} + +module SomeBlockBase(height){ + translate([0,0, height/2 + inside_gap/2]) { + difference(){ + cube([length, width, height], center=true); + translate([-length/2, 0, height/2]) + Commitid_BestCount([length*.66, width/2]); + } + } +} + +module BlockAbove(){ ////toplevel + difference(){ + SomeBlockBase(above_height); + StalkCutout(); + } +} + +module BlockBelow(){ ////toplevel + difference(){ + SomeBlockBase(below_height); + StalkCutout(); + translate([0,0, inside_gap/2 + strap_above + stalk_dia/2 + strap_thick/2]) + cube([strap_width, width*2, strap_thick], center=true); + } +} + +module BlockAbovePrint(){ ////toplevel + rotate([180,0,0]) BlockAbove(); +} + +module BlockBelowPrint(){ ////toplevel + rotate([180,0,0]) BlockBelow(); +} + +module Demo(){ ////toplevel + BlockAbove(); + rotate([180,0,0]) BlockBelow(); +} + +//Demo(); diff --git a/biscuits.scad b/biscuits.scad new file mode 100644 index 0000000..5f6a42a --- /dev/null +++ b/biscuits.scad @@ -0,0 +1,30 @@ + +scale=0.75; +rad=30*scale; +hbase=28.4*scale; +voff=10*scale; +height=70*scale; + +wallheight = 15; +wallthick=0.8; + +module flatsolid() { + circle(r=rad,$fn=50); + polygon(points=[[-hbase,voff],[hbase,voff],[0,height]]); +} + +module mink() { + minkowski() { + flatsolid(); + circle(r=wallthick/2); + } +} + +module hollow() { + difference() { + mink(); + flatsolid(); + } +} + +linear_extrude(height=wallheight) hollow(); diff --git a/brompton-computer-guard.scad b/brompton-computer-guard.scad new file mode 100644 index 0000000..f0154c0 --- /dev/null +++ b/brompton-computer-guard.scad @@ -0,0 +1,107 @@ +// -*- C -*- + +arch_height = 18; +arch_width = 75; +end_width = 25; + +arch_thick = 4; + +arch_breadth = 25; + +hole_dia = 4 + 0.5; + +pbase_tab = 12; +pbase_thick = 4; +inner_pbase_thick = 12; +inner_pbase_rad_mul = 3; + +// computed + +arch_alpha = atan(arch_height / (arch_width/2)); +arch_beta = 2*arch_alpha; +echo(arch_alpha,arch_beta); +arch_in_rad = arch_width/2 / sin(arch_beta); +arch_to_chord = arch_in_rad * cos(arch_beta); + +echo(inner_pbase_thick); + +inner_pbase_rad = arch_in_rad * inner_pbase_rad_mul; + +end_thick = arch_thick; + +holes = [[[ 5 , 5 ], [16 , 21]], // left + [[ 18.5, 4.5], [ 4.5, 21]]]; // right + +module ArchCircle(rad){ + translate([0,-arch_to_chord]) + circle(rad, $fa=0.1); +} + +module ArchProfile(pbase){ + intersection(){ + translate([-200,0]) + square([400,200]); + difference(){ + union(){ + ArchCircle(arch_in_rad + arch_thick); + for (m=[0,1]) + mirror([m,0]) + translate([arch_width/2,0]) + multmatrix([[1,pbase ? -0.75 : 0,0,0], + [0,1,0,0], + [0,0,1,0], + [0,0,0,1]]) + square([end_width, pbase ? pbase_tab : end_thick]); + } + } + } +} + +module Holes(){ + for (m=[0,1]) { + mirror([1-m,0]) + translate([arch_width/2, 50, 0]) + rotate([90,0,0]) + for (h=holes[m]) { + translate(h) + cylinder(r=hole_dia/2, h=100, $fn=20); + } + } +} + +module MainCutout(){ + ArchCircle(arch_in_rad); +} + +module Arch(){ + difference(){ + rotate([0,0,180]){ + linear_extrude(height=arch_breadth) { + difference(){ + ArchProfile(false); + MainCutout(); + } + } + difference(){ + translate([0,0, arch_breadth - pbase_thick]) + linear_extrude(height=pbase_thick){ + difference(){ + hull(){ + ArchProfile(true); + ArchProfile(false); + } + intersection(){ + MainCutout(); + translate([0, -inner_pbase_thick + - (inner_pbase_rad - arch_in_rad)]) + ArchCircle(inner_pbase_rad); + } + } + } + } + } + Holes(); + } +} + +rotate([0,0,45]) translate([0,0,arch_breadth]) rotate([0,180,0]) Arch(); diff --git a/cable-hole-trunking-cover.scad b/cable-hole-trunking-cover.scad new file mode 100644 index 0000000..ed2bc31 --- /dev/null +++ b/cable-hole-trunking-cover.scad @@ -0,0 +1,119 @@ +// -*- C -*- + +holedia = 25; +tapethick = 1.5; +cutoutsz= 15; +innerz = 11; + +sidesflatbase = 2; +endsflatbase = 8; + +basex = holedia + endsflatbase*2; +basey = holedia + sidesflatbase*2; + +bevely = 2.75; +bevelslope = 0.75; +bevelz = bevely / bevelslope;; +basebevelt = 3; + +sideslop = 0.5; + +basebaset = 2; +sidewallt = 2; + +lidt = 1.3; +endwallt = 2; +zslop = 0.75; +endslop = 0.75; + +module sheared_cube(sz, xperz, yperz) { + multmatrix([[1,0,xperz,0], + [0,1,yperz,0], + [0,0,1, 0], + [0,0,0, 1]]) + cube(sz); +} + +module Base(cutouty){ + echo(cutouty); + difference(){ + union(){ + for (mir=[0,1]) mirror([0,mir,0]) { + translate([0, basey/2 - basebevelt, 0]) + sheared_cube([basex, basebevelt, bevelz], 0, bevelslope); + cube([basex, basey/2, basebaset]); + } + } + translate([basex/2, 0, -1]) + cylinder(r=holedia/2, h=bevelz+2); + } + rotate([90, 0, 90]) { + linear_extrude(height=endwallt) { + difference(){ + for (mir=[0,1]) mirror([mir,0,0]) { + polygon([[-0.1, 0], + [basey/2, 0], + [basey/2 + bevely, bevelz], + [basey/2 + bevely, innerz], + [-0.1, innerz]]); + } + translate([cutouty, 0]) + square(size=[cutoutsz, 3*innerz], center=true); + } + } + } +} + +module Lid(){ + lidx = basex + endslop + endwallt; + for (mir=[0,1]) mirror([0,mir,0]) { + translate([0, basey/2 + sideslop + bevely, 0]) + rotate([90,0,90]) + linear_extrude(height = lidx) + polygon([[0, 0], + [-bevely, 0], + [0, bevelz], + [0, innerz + lidt + zslop], + [sidewallt, innerz + lidt + zslop], + [sidewallt, -tapethick], + [0, -tapethick]]); + translate([0, -1, innerz + zslop]) + cube([lidx, 1 + basey/2 + sideslop + bevely + sidewallt, lidt]); + translate([basex + endslop, -1, -tapethick]) + cube([endwallt, 1 + basey/2 + sideslop + bevely + sidewallt, + tapethick + innerz + zslop + 0.1]); + } +} + +module LidT(){ ////toplevel + rotate([180,0,0]) Lid(); +} + +module BaseCMid(){ ////toplevel + Base(0); +} + +module BaseCTop(){ ////toplevel + Base(basey/2 + bevely - cutoutsz/2); +} + +module BaseCBot(){ ////toplevel + Base(-(basey/2 + bevely - cutoutsz/2)); +} + +module BaseCNone(){ ////toplevel + Base(basey); +} + +module Demo(){ ////toplevel + BaseCTop(); + %Lid(); +} + +//BaseCTop(); +//BaseCMid(); +//BaseCBot(); +//BaseCNone(); +//Lid(); +//LidT(); +//Demo(); diff --git a/cable-splice-clamp.scad b/cable-splice-clamp.scad new file mode 100644 index 0000000..bd27d86 --- /dev/null +++ b/cable-splice-clamp.scad @@ -0,0 +1,138 @@ +// -*- C -*- + +include + +rnom = 3.5 / 2; + +// alpha is slope angle, which is half of inner concave angle that +// wire sits in +alpha = 40; // degrees + +// mu is minimum number of cable radii that cable tangent point (line) +// with splint ought to be away from edge of split +mu = 1/4; + +// wall thickness, and base width as fraction of cable size +wall_r = 3.5 / 6.5; +base_r = 0.75; + +total_len = 60; + +strap_width = 3.0 + 0.5; + +strap_count = 4; + +// for cross-section calculations: +// +// origin O is at intersection of straight line segments forming walls +// C is centre of circle (wire x-section) (of radius r or radius 1) +// which is tangent to lines +// T is said tangent points +// B is inner base point, which is extension of line from B by mu*r + +sina = sin(alpha); +cosa = cos(alpha); +tana = sina/cosa; + +// blah_r is blah where r=1 +// d_AB is distance AB +// dy_AB is " " " vertical component + +d_OT_r = tana; +d_OB_r = tana + mu; + +d_OC_r = 1/cosa; + +dy_OB_r = d_OB_r * sina; + +// *0 and *1 relate to smallest and largest wire +// r[01] is radius +// r10 is radius ratio + +r10 = d_OC_r / dy_OB_r; + +r0 = rnom / sqrt(r10); +r1 = rnom * sqrt(r10); + +x_B_r = d_OB_r * cosa; +y_B_r = -dy_OB_r; + +x_T_r = sina; +y_T_r = -tana * sina; + +wall_x_r = wall_r / tan(90-alpha); + +top = wall_r * r1 - (d_OC_r - 1) * r0; +basew = base_r * rnom; + +echo("dias", r0*2, r1*2, "ratio",r1/r0); + +module CrossSectionHalf(plus=0) { + difference(){ + polygon([[-0.1, y_T_r * r0], + [x_T_r * r0, y_T_r * r0], + [x_B_r * r1, y_B_r * r1], + [x_B_r * r1 + wall_x_r * rnom + plus, y_B_r * r1], + [basew + plus, top], + [-0.1, top]]); + translate([0, -d_OC_r * r0]) + circle(r = r0, $fn=20); + } +} + +module CrossSection(plus=0) { + for (m=[0,1]) { + mirror([m,0]) + CrossSectionHalf(plus); + } +} + +module CrossSectionDemo(){ ////toplevel + color("black") CrossSection(2); + CrossSection(); + for (rc=[["red", r1], + ["blue",r0]]) { + color(rc[0]) translate([0, -d_OC_r * rc[1]]) circle(r = rc[1]); + } +} + +strap_wall_h = 1.5; +strap_wall_l = 2.0; + +writing_dx = total_len / 3; +writing_dy = basew*2; + +module HalfClamp(){ ////toplevel + difference(){ + rotate([90,0,0])rotate([0,90,0]){ + linear_extrude(height=total_len) + CrossSection(); + + for (i=[0 : strap_count]){ + if (i*2 != strap_count) { + translate([0, 0, + total_len * (i + 0.5) / (strap_count + 1)]) + for (m=[0,1]){ + mirror([0,0,m]) + translate([0,0, strap_width/2]) + linear_extrude(height=strap_wall_l) + CrossSection(strap_wall_h); + } + } + } + } + + translate([0, -basew, top]) + Commitid_BestCount([writing_dx, writing_dy]); + } +} + +module HalfClampPrint(){ ////toplevel + rotate([180,0,0]) + HalfClamp(); +} + +//CrossSection(); +//CrossSectionDemo(); +//HalfClamp(); +HalfClampPrint(); diff --git a/calib-fit.scad b/calib-fit.scad new file mode 100644 index 0000000..dbee918 --- /dev/null +++ b/calib-fit.scad @@ -0,0 +1,20 @@ +th=3; +holesz=6; +outsz=15; + +module small(sz=holesz,dsz=0,dz=0) { + cube([sz+dsz,sz+dsz,th+dz], center=true); +} + +module osmall() { + translate([0,outsz/2 + 10,0]) small(); +} +module obig() { + difference() { + cube([outsz,outsz,th], center=true); + small(dz=1); + } +} + +osmall(); +obig(); diff --git a/camera-mount.scad b/camera-mount.scad new file mode 100644 index 0000000..fec9096 --- /dev/null +++ b/camera-mount.scad @@ -0,0 +1,28 @@ +// -*- C -*- + +include + +inch = 25.4; + +negative_dia = inch * 1/4. + 0.375; +negative_default_l = 10.0; + +negative_tpi = 20; +negative_pitch = inch/negative_tpi; +negative_chamfer = negative_pitch/2; + +module CameraMountThread(l){ + rotate([0,180,0]) + english_thread(diameter=negative_dia/inch, + threads_per_inch=negative_tpi, + leadin=0, internal=true, test=$test, + length= (l + inch/19) / inch); + hull(){ + translate([0,0, negative_chamfer]) + cylinder(r= negative_dia/2 + negative_chamfer*2, + h=1); + mirror([0,0,1]) + cylinder(r= negative_dia/2 - negative_chamfer*2, + h= negative_chamfer*3); + } +} diff --git a/clip-spring-holder-clip.scad b/clip-spring-holder-clip.scad new file mode 100644 index 0000000..11f395f --- /dev/null +++ b/clip-spring-holder-clip.scad @@ -0,0 +1,48 @@ +// -*- C -*- +// +// For holding the spring while reassembling a candle holder. + +include + +spring_body_w = 5.0; +spring_body_l = 6.0; +axle_dia = 2.0; +recess_d = 13.0; +total_len = 45.0; + +th_y = 1.5; +th_x = 2; +handle_th = 2.5; + +// calculated + +outer_sz = [spring_body_l + th_x*2, spring_body_w + th_y*2]; +handle_sz = [outer_sz[0], handle_th]; +th_z = th_x; + +echo(outer_sz); + +module OuterElevation(){ + square(center=true, outer_sz); +} + +module Elevation(){ + difference(){ + OuterElevation(); + + square(center=true, [spring_body_l, spring_body_w]); + square(center=true, [outer_sz[0] + 10, axle_dia]); + } +} + +module Clip(){ + linextr(-th_z, recess_d) Elevation(); + linextr(-th_z, 0) OuterElevation(); + linextr(recess_d - total_len, 0) square(center=true, handle_sz); +} + +module Print(){ + rotate([0, 90, 0]) Clip(); +} + +Print(); diff --git a/cliphook.scad b/cliphook.scad new file mode 100644 index 0000000..22f08f5 --- /dev/null +++ b/cliphook.scad @@ -0,0 +1,103 @@ +// -*- C -*- +// +// cliphook.scad +// +// 3D design for a small clippy hook +// Copyright 2012,2016 Ian Jackson +// +// This work 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 work 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 work. If not, see . + +function ClipHook_r2(w,g,l,ye,k) = w/2 + g + w/2; +function ClipHook_r3(w,g,l,ye,k) = k * (ClipHook_r2(w,g,l,ye,k) + w + g); +function ClipHook_yd(w,g,l,ye,k) = g/2 + w + g + w/2 - ClipHook_r3(w,g,l,ye,k); +function ClipHook_xe(w,g,l,ye,k) = + l*1.5 + w + + sqrt(pow( ClipHook_r3(w,g,l,ye,k), 2) - + pow( ClipHook_yd(w,g,l,ye,k) - ye, 2)); + +module FlatArc(cx,cy,r1,r2,a1,a2=361,$fn=$fn) { + astep = (a2-a1)/6; + size = 5*(r2/2); + translate([cx,cy,0]) { + intersection() { + difference() { + circle(r=r2); + translate([0,0,-1]) + circle(r=r1); + } + scale(size) { + for (ai=[0:4]) { + //echo(" jarc ", a1,a2, astep, ai, a1 + astep*ai ); + rotate(a1 + astep*ai) { + polygon([ [0,0], [1,0], + [cos(astep*2),sin(astep*2)] ]); + } + } + } + } + } +} + +module ClipHook_2D(w,g,l,ye,k,h) { + r2 = ClipHook_r2(w,g,l,ye,k); + r3 = ClipHook_r3(w,g,l,ye,k); + yd = ClipHook_yd(w,g,l,ye,k); + xe = ClipHook_xe(w,g,l,ye,k); + + xd = l*1.5 + w; + xc = -l/2; + yc = g/2 + w/2; + + alpha = atan2((xe-xd)/r3, (ye-yd)/r3); + + echo("ClipHook(w g l ye k h) ", w, g, l, ye, k, h); + echo("ClipHook r2 r3 xd yd xe =", r2,r3, xd,yd, xe); + + $fn = 20; + + module jcirc(x,y) { translate([x,y,0]) circle(r=w/2); } + module jbox(y,x1,x2) { translate([x1,y-w/2,0]) square(size=[x2-x1, w]); } + module jarc(cx,cy,r,a1=0,a2=360) { FlatArc(cx,cy,r-w/2,r+w/2,a1,a2); } + + jcirc(-xc, -yc); + jbox(-yc, xc, -xc); + jarc(xc, yc, r2, 90, 270); + jbox(yc+r2, xc, xd); + jarc(xd, yd, r3, 90-alpha, 90); + jcirc(xe,ye); +} + +module ClipHook(w=1.2, g=0.2, l=0.0, ye=0, k=2.0, h=3.5, demo=false, + cupcaph=0, cupgapg=0) { + difference() { + linear_extrude(height=h) + ClipHook_2D(w,g,l,ye,k); + if (cupcapg != 0) { + translate([-g+0.01,-(w+g),h-cupcapg]) + cube([w,(w+g),cupcaph+1]); + } + } + if (cupcaph != 0) { + translate([-l/2, g/2+w/2, h-0.01]) + intersection() { + cylinder(r=ClipHook_r2(w,g,l,ye,k)+w*0.4, h=cupcaph, $fn=16); + translate([-50-g,-50,-1]) cube([50,100,h+2]); + } + } +} + +if (ClipHook_demo) { + ClipHook(l=0, k=1, cupcaph=1, cupcapg=0.4); + %translate([l+w,0,0]) rotate(180) ClipHook(l=0, k=1, cupcaph=1, cupcapg=0.4); +} diff --git a/commitid-2d-test.scad b/commitid-2d-test.scad new file mode 100644 index 0000000..a15de77 --- /dev/null +++ b/commitid-2d-test.scad @@ -0,0 +1,3 @@ +// -*- C -*- +include +Commitid_2DDemo(); diff --git a/commitid-best-test.scad.pl b/commitid-best-test.scad.pl new file mode 100755 index 0000000..b0ca1ba --- /dev/null +++ b/commitid-best-test.scad.pl @@ -0,0 +1,26 @@ +#!/usr/bin/perl -w +use strict; + +our @xm = qw(4.7 6.8 8.2 10 12 15 18 22 27 33 47 68 100); +our @ym = qw(3.9 5.6 8.2 12 18 27 39 56); + +sub p { print @_ or die $!; } + +p "include \n"; +p "p = Commitid_pixelsz();\n"; + +my $x = 0; +foreach my $xm (@xm) { + my $y = 0; + foreach my $ym (@ym) { + p " translate([$x,$y] * p) {\n"; + p " difference(){\n"; + p " translate(-0.5*p*[1,1]) square([$xm+1,$ym+1]*p);\n"; + p " square([$xm,$ym]*p);\n"; + p " }\n"; + p " Commitid_BestCount_2D([$xm,$ym] * p, margin=0.2);\n"; + p " }\n"; + $y += $ym + 2; + } + $x += $xm + 2; +} diff --git a/commitid-cube-test-X.scad b/commitid-cube-test-X.scad new file mode 100644 index 0000000..4f2f6fd --- /dev/null +++ b/commitid-cube-test-X.scad @@ -0,0 +1,76 @@ +// -*- C -*- + +include + +baseh= 1; + +sz = 20; + +fdo = [1, 3, 0]; + +$Commitid_depth = 1.0; + +module FD () { + translate(fdo) + Commitid_FontDemo(); +} + +module TC () { ////toplevel + difference(){ + cube([sz,sz,sz]); + translate([0,0, sz]) mirror([0,0,1]) FD(); + rotate([90,0,0]) translate([0,0,0]) FD(); + translate([sz,0,0]) mirror([1,0,0]) rotate([90,0,90]) FD(); + translate([sz,sz,0]) rotate([0,0,180]) FD(); + } + translate([sz,sz,0]) rotate([-90,0,0]) rotate([0,0,180]) FD(); + translate([0,sz,0]) rotate([-90,0,90]) rotate([0,0,180]) FD(); +} + +w = 3; +t = 4; + +fdsz = Commitid_FontDemo_sz(); +d = Commitid_depth(); +ru = Commitid_pixelsz(); + +module TTWall () { + difference(){ + translate([0, 0, -0.1]) + cube([w, sz, sz - 2 + 0.1]); + + translate([0,sz,0]) rotate([90,0,-90]) FD(); + translate([0, sz, 0]) + rotate([90, 0, -90]) + translate(fdo + [0, -ru*2, -d]) cube([fdsz[0], ru, d*2]); + } + translate([w,0,0]) rotate([90,0,90]) FD(); + + translate([0, sz+d, 0]) + rotate([90,0,0]) + translate([0, fdo[1], 0]) cube([d*2, fdsz[1], ru]); +} + +module TT () { ////toplevel + difference(){ + translate([-sz, 0, -t]) + cube([sz*2 + w, sz, t]); + + translate([0,0,-t]) rotate([0,180,0]) FD(); + translate([w,0,0]) rotate([0,0,0]) FD(); + + translate([(sz+w), 0, -t]) rotate([0,180,0]) + Commitid_BestCount([sz+w, sz]); + } + translate([-sz,0,0]) rotate([0,0,0]) FD(); + + TTWall(); + translate([0,0,-t]) rotate([90,0,0]) TTWall(); +} + +echo("pixelsz:", str(Commitid_pixelsz()), + "depth:", Commitid_depth(), + "sz:", Commitid_FontDemo_sz()); + +//TC(); +TT(); diff --git a/commitid-cube-test-Y.scad b/commitid-cube-test-Y.scad new file mode 100644 index 0000000..23aa076 --- /dev/null +++ b/commitid-cube-test-Y.scad @@ -0,0 +1,78 @@ +// -*- C -*- + +$Commitid_depth = 1.0; +$Commitid_pixelsz = 1.5; + +include + +baseh= 1; + +fdo = [1, 3, 0]; + +w = 3; +t = 4; + +fdsz = Commitid_FontDemo_sz(); +d = Commitid_depth(); +ru = Commitid_pixelsz(); +echo($Commitid_pixelsz, ru, fdsz); + +sz = max( fdsz[0], fdsz[1] ) + ru; + +module FD () { + translate(fdo) + Commitid_FontDemo(); +} + +module TC () { ////toplevel + difference(){ + cube([sz,sz,sz]); + translate([0,0, sz]) mirror([0,0,1]) FD(); + rotate([90,0,0]) translate([0,0,0]) FD(); + translate([sz,0,0]) mirror([1,0,0]) rotate([90,0,90]) FD(); + translate([sz,sz,0]) rotate([0,0,180]) FD(); + } + translate([sz,sz,0]) rotate([-90,0,0]) rotate([0,0,180]) FD(); + translate([0,sz,0]) rotate([-90,0,90]) rotate([0,0,180]) FD(); +} + +module TTWall () { + difference(){ + translate([0, 0, -0.1]) + cube([w, sz, sz - 2 + 0.1]); + + translate([0,sz,0]) rotate([90,0,-90]) FD(); + translate([0, sz, 0]) + rotate([90, 0, -90]) + translate(fdo + [0, -ru*2, -d]) cube([fdsz[0], ru, d*2]); + } + translate([w,0,0]) rotate([90,0,90]) FD(); + + translate([0, sz+d, 0]) + rotate([90,0,0]) + translate([0, fdo[1], 0]) cube([d*2, fdsz[1], ru]); +} + +module TT () { ////toplevel + difference(){ + translate([-sz, 0, -t]) + cube([sz*2 + w, sz, t]); + + translate([0,0,-t]) rotate([0,180,0]) FD(); + translate([w,0,0]) rotate([0,0,0]) FD(); + + translate([(sz+w), 0, -t]) rotate([0,180,0]) + Commitid_BestCount([sz+w, sz]); + } + translate([-sz,0,0]) rotate([0,0,0]) FD(); + + TTWall(); + translate([0,0,-t]) rotate([90,0,0]) TTWall(); +} + +echo("pixelsz:", str(Commitid_pixelsz()), + "depth:", Commitid_depth(), + "sz:", Commitid_FontDemo_sz()); + +//TC(); +TT(); diff --git a/commitid-cube-test.scad b/commitid-cube-test.scad new file mode 100644 index 0000000..0a5f21a --- /dev/null +++ b/commitid-cube-test.scad @@ -0,0 +1,74 @@ +// -*- C -*- + +include + +baseh= 1; + +sz = 20; + +fdo = [1, 3, 0]; + +module FD () { + translate(fdo) + Commitid_FontDemo(); +} + +module TC () { ////toplevel + difference(){ + cube([sz,sz,sz]); + translate([0,0, sz]) mirror([0,0,1]) FD(); + rotate([90,0,0]) translate([0,0,0]) FD(); + translate([sz,0,0]) mirror([1,0,0]) rotate([90,0,90]) FD(); + translate([sz,sz,0]) rotate([0,0,180]) FD(); + } + translate([sz,sz,0]) rotate([-90,0,0]) rotate([0,0,180]) FD(); + translate([0,sz,0]) rotate([-90,0,90]) rotate([0,0,180]) FD(); +} + +w = 3; +t = 2; + +fdsz = Commitid_FontDemo_sz(); +d = Commitid_depth(); +ru = Commitid_pixelsz(); + +module TTWall () { + difference(){ + translate([0, 0, -0.1]) + cube([w, sz, sz - t + 0.1]); + + translate([0,sz,0]) rotate([90,0,-90]) FD(); + translate([0, sz, 0]) + rotate([90, 0, -90]) + translate(fdo + [0, -ru*2, -d]) cube([fdsz[0], ru, d*2]); + } + translate([w,0,0]) rotate([90,0,90]) FD(); + + translate([0, sz+d, 0]) + rotate([90,0,0]) + translate([0, fdo[1], 0]) cube([d*2, fdsz[1], ru]); +} + +module TT () { ////toplevel + difference(){ + translate([-sz, 0, -t]) + cube([sz*2 + w, sz, t]); + + translate([0,0,-t]) rotate([0,180,0]) FD(); + translate([w,0,0]) rotate([0,0,0]) FD(); + + translate([(sz+w), 0, -t]) rotate([0,180,0]) + Commitid_BestCount([sz+w, sz]); + } + translate([-sz,0,0]) rotate([0,0,0]) FD(); + + TTWall(); + translate([0,0,-t]) rotate([90,0,0]) TTWall(); +} + +echo("pixelsz:", str(Commitid_pixelsz()), + "depth:", Commitid_depth(), + "sz:", Commitid_FontDemo_sz()); + +//TC(); +TT(); diff --git a/commitid-layering-test.scad b/commitid-layering-test.scad new file mode 100644 index 0000000..04d8c83 --- /dev/null +++ b/commitid-layering-test.scad @@ -0,0 +1,31 @@ +// -*- C -*- + +include + +baseh= 1; +basex = 31; +basey= 20; +basexpos = -12; +baseypos = -4; + +module Body(){ + mirror([0,0,1]) + translate([basexpos, baseypos]) + cube([basex, basey, baseh]); +} + +difference(){ + Body(); + translate([basexpos, baseypos, -baseh]) + Commitid_BestCount_M([basex,basey], margin=3); + + translate([-6, 6, -0.4]) + cylinder(r=5, h=3, $fn=50); +} + +translate([-6, 6, -0.5]) + cylinder(r=4, h=3.5, $fn=50); + +echo("pause height (mm)", baseh+0.01); + +Commitid_FontDemo(); diff --git a/commitid.scad.pl b/commitid.scad.pl new file mode 100755 index 0000000..62ae510 --- /dev/null +++ b/commitid.scad.pl @@ -0,0 +1,917 @@ +#!/usr/bin/perl -w + +# commitid.scad.pl - a program for annotating solid models with commit info +# Copyright (C)2016 Ian Jackson. See below. There is NO WARRANTY. + + +# USAGE +# ===== +# +# .../commitid.scad.pl [OPTION...] [STRING...] >commitid.scad.new \ +# && mv -f commitid.scad.new commitid.scad +# +# Run without arguments, commitid.scad.pl will output an openscad file +# which contains 2D and 3D models of the current git commit count and +# commit object id (commit hash), useful for identifying printed +# parts. +# +# See below for details. You probably want these two sections, as a +# quick starting point: +# General form of provided openscad modules +# Autoscaling modules +# +# We can also generate models of short mainly-numeric strings +# specified on the command line. +# +# +# Options: +# +# --git Generate git commit indications, as shown below +# (this is the default if no strings are requested with -t). +# Ie, produce the `Autoscaling modules' and `Specific layouts'. +# +# --git=objid +# Generate git commit indication based on commit object only +# (ie avoid counting commits). Ie, do not generate `Small' +# and `Full' layouts (and never select them for `Best'). +# +# -i Do not generate `+' dirty indication if git-untracked files +# are present (ie, missing .gitignore entries). The `*' +# dirty tree indication (for modified files) cannot be disabled. +# +# [-t[LAYOUT]] TEXT +# Generate a layout LAYOUT containing TEXT. TEXT can +# contain newlines (a final newline usually undesirable, as +# it will generate a blank line). If LAYOUT is not specified, +# generates Arg0, Arg1, Arg2, etc., for successive such +# TEXTs. The permissible character set in is TEXT is: +# space 0-9 a-f + * +# +# +# OPENSCAD INTERFACE +# ================== +# +# Dynamic variables for configuration +# ----------------------------------- +# +# We honour the following variables to control various scaling factors: +# +# default value notes +# $Commitid_pixelsz 0.8 \ multiplied together +# $Commitid_scale 1.0 / +# $Commitid_depth pixelsz/2 \ multiplied together +# $Commitid_depth_scale 1.0 / +# $Commitid_max_best_scale 2.0 limits XY scaling in *Best* +# +# FYI the font is nominally 3x5 pixels, with 1-pixel inter-line and +# inter-character gaps. (It's not strictly speaking a 3x5 bitmap +# font, size it contains partial pixels and diagonals.) +# +# +# Non-`module'-specific functions +# ------------------------------- +# +# We provide the following functions (which depend on the config +# variables, but not on anything else) and compute useful values: +# +# function Commitid_pixelsz() Actual size of each nominal pixel +# function Commitid_depth() Depth to use (the amount characters +# should be raised or sunken) +# +# General form of provided openscad modules +# ----------------------------------------- +# +# module Commitid_MODULE_2D(...) Collection of polygons forming characters +# module Commitid_MODULE(...) The above, extruded up and down in Z +# module Commitid_MODULE_M_2D(...) Mirror writing +# module Commitid_MODULE_M(...) 3D mirror writing +# function Commitid_MODULE_sz() A 2-vector giving the X,Y size +# +# Except for *Best* modules, the XY origin is in the bottom left +# corner without any margin. Likewise Commitid_MODULE_sz does not +# include any margin. +# +# For 3D versions, the model is 2*depth deep and the XY plane bisects +# the model. This means it's convenient to either add or subtract from +# a workpiece whose face is in the XY plane. +# +# The _M versions are provided to avoid doing inconvenient translation +# and rotation to get the flipped version in the right place. +# +# +# Autoscaling modules +# ------------------- +# +# These modules take a specification of the available XY space, and +# select and generate a suitable specific identification layout: +# +# module Commitid_BestCount_2D (max_sz, margin=Commitid_pixelsz()) +# module Commitid_BestCount (max_sz, margin=Commitid_pixelsz()) +# module Commitid_BestCount_M_2D(max_sz, margin=Commitid_pixelsz()) +# module Commitid_BestCount_M (max_sz, margin=Commitid_pixelsz()) +# module Commitid_BestObjid_2D (max_sz, margin=Commitid_pixelsz()) +# module Commitid_BestObjid (max_sz, margin=Commitid_pixelsz()) +# module Commitid_BestObjid_M_2D(max_sz, margin=Commitid_pixelsz()) +# module Commitid_BestObjid_M (max_sz, margin=Commitid_pixelsz()) +# +# max_sz should be [x,y]. +# +# BestCount includes (as much as it can of) the git commit count, +# ie the result of +# git rev-list --first-parent --count HEAD +# (and it may include some of the git revision ID too). +# +# BestObjid includes as much as it can of the git commit object hash, +# and never includes any of the count. +# +# All of these will autoscale and autorotate the selected model, and +# will include an internal margin of the specified size (by default, +# one pixel around each edge). If no margin is needed, pass margin=0. +# +# There are no `function Commitid_Best*_sz'. If they existed they +# would simply return max_sz. +# +# +# Output format +# ------------- +# +# In general the output, although it may be over multiple lines, +# is always in this order +# git commit object id (hash) +# dirty indicator +# git commit count +# +# Not all layouts have all these parts. The commit object id may +# sometimes be split over multiple lines, but the count will not be. +# If both commit id and commit count appear they will be separated +# by (at least) a newline, or a dirty indicator, or a space. +# +# The commit id is truncated to fit, from the right. +# +# The commit count is truncated from the _left_, leaving the least +# significant decimal digits. +# +# The dirty indicator can be +# +# * meaning the working tree contains differences from HEAD +# +# + meaning the working tree contains untracked files +# (ie files you have failed to `git add' and also failed +# to add to gitignore). (But see the -i option.) +# +# +# Specific layouts +# ---------------- +# +# If you want to control the exact layout (and make space for it in +# your design), you can use these: +# +# module Commitid_LAYOUT_2D() +# module Commitid_LAYOUT() +# module Commitid_LAYOUT_M_2D() +# module Commitid_LAYOUT_M() +# function Commitid_LAYOUT_sz() +# +# Here LAYOUT is one of the following (giving for example, `module +# Commitid_Full8_2D'). In the examples, we will assume that the tree +# is dirty, the commit count is 123456, and the commit object id +# starts abcdeffedbcaabcdef... In the examples `_' shows where a +# space would be printed. +# +# Small2 Small3 ... Small9 Small10 Small12 Small14 Small16 +# A single line containing as much of the count will fit, eg: +# Small5 3456* +# Small8 _*123456 +# The objectid is included if more than one character of of it +# will fit without makign the output ambiguous: +# Small9 ab*123456 +# +# Small2S Small4S ... Small16S +# Small3T Small9T Small12T +# Same as Small but split into two lines (S) +# or three lines (T). Eg: +# Small4S *4 Small6T _* +# 56 34 +# 56 +# Git2 Git3 ... Git9 Git10 Git12 Git14 Git16 +# Git4S Git6S ... Git16S +# Git6T Git9T Git12T +# Just the commit object hash, in one, two (S) or three (T) +# lines. E.g.: +# Git5 abcd* +# +# Full4 Full6 ... Full20: +# The commit object hash plus the commit count, on +# separate lines, eg: +# Full12 abcdef Full16 abcdeffe +# *23456 _*123456 +# +# Full6T Full9T ... Full30T +# As Full but the commit object id is split over two lines +# producing a 3-line layout, eg: +# Full9T abc Full21T abcdeff +# de* edbcaa* +# 456 _123456 +# +# Other LAYOUTs +# ------------- +# +# FontDemo +# +# A demonstration of the built-in 18-character font +# +# Arg0 Arg1, ... +# +# Strings passed on command line (without -t, or bare -t, +# rather than with -tLAYOUT). +# +# LAYOUT +# +# Generated by passing -tLAYOUT on the command line. +# + + +# COPYRIGHT, LICENCE AND LACK-OF-WARRANTY INFORMATION +# =================================================== +# +# This program is Free Software and a Free Cultural Work. +# +# 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 . +# +# Alternatively, at your option: +# +# This work is licensed under the Creative Commons +# Attribution-ShareAlike 4.0 International License. +# +# There is NO WARRANTY. + + +use strict; + +$SIG{__WARN__} = sub { die @_; }; + +our $debug=0; + +if (@ARGV && $ARGV[0] =~ m/^-(D+)$/) { + $debug = length $1; + shift @ARGV; +} + +sub p { print @_ or die $!; } + +sub p_debug { print STDERR @_ if $debug; } + +p <<'END'; +// *** AUTOGENERATED - DO NOT EDIT *** // +function Commitid_pixelsz() = + ($Commitid_pixelsz ? $Commitid_pixelsz : 0.8) * + ($Commitid_scale ? $Commitid_scale : 1.0); +function Commitid_depth() = + ($Commitid_depth ? $Commitid_depth : Commitid_pixelsz()/2) * + ($Commitid_depth_scale ? $Commitid_depth_scale : 1.0); +function Commitid__scale() = + Commitid_pixelsz() / 0.2; +END + +sub chrmodname ($) { + my ($chr) = @_; + my $chrx = sprintf '%#x', ord $chr; + return "Commitid__chr_$chrx"; +} + +our $gtm_demo_i = -1; +our $gtm_demo_j; +our @gtm_demo_o; + +sub gentextmodule_demo_start_batch () { + $gtm_demo_j = 0; + $gtm_demo_i++; +} + +sub argl_formal (@) { join ', ', @_; } +sub argl_actual (@) { join ',', map { m/=/ ? $` : $_ } @_; } + +sub gen3dmodule ($@) { + my ($modb,$size,@argl) = (@_); + $size ||= "${modb}_sz()"; + p "module ${modb}_M_2D(".argl_formal(@argl)."){\n"; + p " translate([${size}[0],0])\n"; + p " mirror([1,0,0])\n"; + p " ${modb}_2D(".argl_actual(@argl).");\n"; + p "};\n"; + foreach my $mir ('','_M') { + my $mm = "${modb}${mir}"; + p "module ${mm}(".argl_formal(@argl)."){\n"; + p " d=Commitid_depth();\n"; + p " translate([0,0,-d]) linear_extrude(height=d*2)\n"; + p " ${mm}_2D(".argl_actual(@argl).");\n"; + p "}\n"; + } +} + +sub gentextmodule ($@) { + my ($form, @lines) = @_; + my $modb = "Commitid_$form"; + p "module ${modb}_2D(){\n"; + p " // |$_|\n" foreach @lines; + p " scale(Commitid__scale()){\n"; + my $y = @lines; + my $cols = 1; + foreach my $line (@lines) { + $y--; + my $x = 0; + foreach my $chr (split //, $line) { + p sprintf " translate([%d * 0.8, %d * 1.2]) %s();\n", + $x, $y, chrmodname $chr + if $chr =~ m/\S/; + $x++; + } + $cols = $x if $x > $cols; + } + p " }\n"; + p "}\n"; + gen3dmodule($modb,''); + + p sprintf "function %s_sz() = Commitid__scale() * 0.1 * [ %d, %d ];\n", + $modb, 2 * ($cols * 4 - 1), 2 * (@lines * 6 - 1); + + push @gtm_demo_o, <commitid-DEBUG-simplify-$chr.ps"; + print S "%!\n"; + print S "(Courier-Bold) findfont 15 scalefont setfont\n"; + + $prcount=0; +} + +sub debug_simplify_done () { + return unless $debug; + print S "showpage\n"; + close S or die $!; +} + +sub debug_simplify_pr ($$$) { + my ($chr,$polys,$why) = @_; + + return unless $debug; + + print STDERR "PR $chr $why\n"; + my $ct_x = 10000 * ($prcount % 6); + my $ct_y = 18000 * int($prcount / 6); + printf S "0 setgray\n"; + printf S "%d %d moveto\n", map {$_/100 + 10} $ct_x,$ct_y; + printf S "(%s) show\n", $why; + my $pr_recur; + + $pr_recur = sub { + my ($tpolys, @levels) = @_; + return unless @$tpolys; + foreach my $i (0..$#$tpolys) { + printf STDERR "P@levels %02d :", $i; + my $pinfo = $tpolys->[$i]; + my $p = $pinfo->{E}; + printf STDERR "@$p\n"; + my $lw = 5 - 4*($i / ($#$tpolys || 1)); + my $pp = sub { + my $spec = $p->[$_[0]]; + $spec =~ m/^\d{5}/; + sprintf "%d %d",map { $_/100 } + 1000 + $ct_x + $&, + 5000 + $ct_y + $'; + }; + printf S "%s setrgbcolor\n", (@levels==0 ? '0 0 0' : + @levels==1 ? '0 0 1' + : '1 1 0'); + foreach my $eai (0..$#$p) { + my $ebi = ($eai + 1) % @$p; + printf S <($eai), $pp->($ebi); + %f setlinewidth + %s moveto + %s lineto + stroke +END + } + $pr_recur->($pinfo->{Holes}, @levels, $i); + } + }; + $pr_recur->($polys,0); + + $prcount++; +} + +sub simplify ($$) { + my ($chr,$polys) = @_; + use Data::Dumper; + + return unless @$polys; + + my $count=0; + my $pr = sub { }; + + if ($debug) { + debug_simplify_begin($chr); + } + + $pr->("start"); + + AGAIN: while(1) { + my %edges; + my $found_hole; + + foreach my $pi (0..$#$polys) { + my $p = $polys->[$pi]{E}; + foreach my $ei (0..$#$p) { + my $e = $p->[$ei].$p->[($ei+1) % @$p]; + die if $edges{$e}; + $edges{$e} = [ $p, $pi, $ei ]; + } + } + p_debug "AGAIN $count\n"; + my $merge = sub { + my ($pa, $pai, $eai, $pb, $pbi, $ebi) = @_; + p_debug "# merging $pai:$eai.. $pbi:$ebi..\n"; + splice @$pa, $eai, 1, + ((@$pb)[$ebi+1..$#$pb], (@$pb)[0..$ebi-1]); + @$pb = ( ); + }; + foreach my $pai (0..$#$polys) { + my $painfo = $polys->[$pai]; + my $pa = $painfo->{E}; + foreach my $eai (0..$#$pa) { + my $ear = $pa->[ ($eai+1) % @$pa ].$pa->[$eai]; + my $ebi = $edges{$ear}; + next unless $ebi; + my ($pb,$pbi); + ($pb, $pbi, $ebi) = @$ebi; + # $pai:($eai+1)..$eai and $pbi:$ebi..($ebi+1) are identical + # so we want to remove them. + if ($pai==$pbi) { + # we're making a hole! we make an assumption: + # holes have fewer line segments than the + # outlines. This is almost always true because of + # the way we construct our figures. + if (($ebi - $eai + @$pa) % @$pa > @$pa/2) { + # We arrange that $eai..$ebi is the hole + ($ebi,$eai) = ($eai,$ebi); + } + p_debug "HOLE $eai $ebi\n"; + # we want to make the smallest hole, to avoid + # making a hole that itself needs simplifying + my $holesz = ($ebi - $eai + @$pa) % @$pa; + $found_hole = [ $pa,$pai,$eai, $ebi, $holesz ] + unless $found_hole && $found_hole->[4] < $holesz; + } else { + $merge->($pa,$pai,$eai,$pb,$pbi,$ebi); + debug_simplify_pr($chr,$polys,"after $count"); + next AGAIN; + } + } + # we process hole joining last, so that the whole of the + # edge of the hole must be part of the same polygon + if ($found_hole) { + p_debug "HOLE DOING @$found_hole\n"; + my ($pa,$pai,$eai,$ebi) = @$found_hole; + # simplify the indexing + @$pa = ((@$pa)[$eai..$#$pa], (@$pa)[0..$eai-1]); + $ebi -= $eai; $ebi += @$pa; $ebi %= @$pa; + $eai = 0; + push @{ $painfo->{Holes} }, { + E => [ (@$pa)[$eai+1..$ebi-1] ], + Holes => [ ], + }; + splice @$pa, $eai, $ebi-$eai+1; + debug_simplify_pr($chr,$polys,"hole $count"); + next AGAIN; + } + } + last; + } + + debug_simplify_done(); +} + +sub p_edgelist ($$$) { + my ($points,$vecs,$p) = @_; + my @vec; + foreach my $pt (@$p) { + $pt =~ s{\d{5}}{$&,}; + $pt =~ s{\b\d}{$&.}g; + push @$points, "[$pt]"; + push @vec, $#$points; + } + push @$vecs, \@vec; +} + +sub parsefont () { + my %cellmap; + for (;;) { + $_ = // die; + last if %cellmap && !m/\S/; + next unless m/\S/; + chomp; + s{^(.) }{}; + $cellmap{$1} = $_; + } + my %chrpolys; + # $chrs{$chr}[$poly] = $poly + # $poly->{E} = [ "012345012345", ... ] + # $poly->{Holes} = $poly2 + while () { + next unless m/\S/; + chomp; + my @chrs = split / /, $_; + !~ m/\S/ or die; + foreach my $row (reverse 0..4) { + $_ = ; + chomp; + s{^}{ }; + $_ .= ' ' x 8; + m{\S/\S} and die; + s{/(?=\s)}{L}g; + s{/(?=\S)}{r}g; + s{\\(?=\s)}{l}g; + s{\\(?=\S)}{R}g; + p "// $_\n"; + foreach my $chr (@chrs) { + s{^ }{} or die "$chr $_ ?"; + foreach my $col (0..2) { + my @verts; + if (s{^ }{}) { + } elsif (s{^\S}{}) { + my $f = $cellmap{$&}; + die unless $f; + $f =~ s/\b\d/ sprintf '%05d', $col*2000 + $&*1000 /ge; + $f =~ s/\d\b/ sprintf '%05d', $row*2000 + $&*1000 /ge; + push @{ $chrpolys{$chr} }, { E => [ split / /, $f ] }; + } else { + die "$_ ?"; + } + } + } + die "$_ ?" if m{\S}; + } + } + + my $demo = ''; + my $democols = 6; + foreach my $chr (sort keys %chrpolys) { + + my $polys = $chrpolys{$chr}; + $_->{Holes} = [] foreach @$polys; + + simplify($chr,$polys); + + my $mod = chrmodname $chr; + p "module $mod () {\n"; + foreach my $poly (@$polys) { + p " polygon("; + my $holes = $poly->{Holes}; + my (@points, @vecs); + p_edgelist(\@points, \@vecs, $poly->{E}); + foreach my $hole (@$holes) { + p_edgelist(\@points, \@vecs, $hole->{E}); + } + p "points=[".(join ",",@points)."],"; + if (@$holes) { + p ",paths=[".(join ",", + map { "[".(join ",",@$_)."]" } + @vecs)."],"; + } + p "convexity=4);\n"; + } + p "}\n"; + $demo .= $chr; + } + @demo = reverse $demo =~ m{.{1,$democols}}go; +} + +parsefont(); + +our $do_git; # contains may chars 'c' (count) and/or 'o' (object) +our $do_git_untracked = 1; +our $argcounter; + +our @forms; +our %included; # 0 = not at all; 1 = truncated; 2 = full + +sub rjustt ($$$;$) { + # right justify and truncate (ie, pad and truncate at left) + # always includes prefix + # sets $included{$what} + my ($sz, $what, $whole, $prefix) = @_; + $prefix //= ''; + my $lw = length $whole; + my $spare = $sz - $lw - (length $prefix); + $included{$what}= 1 + ($spare > 0); + return + ($spare > 0 ? (' ' x $spare) : ''). + $prefix. + substr($whole, ($spare < 0 ? -$spare : 0)); +} + +sub ljustt ($$$;$) { + my ($sz, $what, $whole, $suffix) = @_; + $suffix //= ''; + $sz -= length $suffix; + $included{$what} = 1 + ($sz >= length $whole); + return sprintf "%-${sz}.${sz}s%s", $whole, $suffix; +} + +sub genform_prep() { + $included{$_}=0 foreach qw(Objid Count); +} + +sub genform ($@) { + my ($form, @lines) = @_; + gentextmodule($form, @lines); + my $f = { + Form => $form, + Chars => (length join '', @lines), + Lines => (scalar @lines), + Ambiguous => ($form =~ m/Full/ && !grep { m/\W/ } @lines), + Included => { %included }, + }; + push @forms, $f; +} + +sub genform_q ($$$) { + my ($form, $s, $lines) = @_; + $gtm_demo_j++; + my $l = length $s; + return if $l % $lines; + my $e = $l/$lines; + return if $e < 2; + $gtm_demo_j--; + genform($form, $s =~ m/.{$e}/g); +} + +sub genform_plusq ($$) { + my ($form, $s) = @_; + genform($form, $s); + genform_q("${form}S", $s, 2); + genform_q("${form}T", $s, 3); +} + +our @gcmd; + +sub gitrun_start () { + open F, "-|", @gcmd or die "$gcmd[0]: start: $!"; +} + +sub gitrun_done (;$) { + my ($errok) = @_; + $?=0; $!=0; + return if close F; + return if $errok; + die $! if $!; + die "@gcmd failed ($?)\n"; +} + +sub gitoutput (@) { + (@gcmd) = (qw(git), @_); + gitrun_start; + $_ = ; + gitrun_done; + defined or die "@gcmd produced no output"; + chomp or die "@gcmd produced no final newline"; + $_; +} + +sub do_git () { + return unless $do_git; + + @gcmd = qw(git status --porcelain); + push @gcmd, qw(--untracked=no) unless $do_git_untracked; + + my $git_dirty = ''; + gitrun_start; + while () { + if (m/^\?\?/ && $do_git_untracked) { + $git_dirty = '+'; + next; + } + $git_dirty = '*'; + last; + } + gitrun_done($git_dirty eq '*'); + + my $git_count; + my $git_object; + + if ($do_git =~ m/c/) { + $git_count = gitoutput qw(rev-list --first-parent --count HEAD); + } + if ($do_git =~ m/o/) { + $git_object = gitoutput qw(rev-parse HEAD); + } + print STDERR join ' ', map { $_ // '?' } + "-- commitid", $git_object, $git_dirty, $git_count, "--\n"; + + foreach my $sz (2..10, qw(12 14 16)) { + gentextmodule_demo_start_batch(); + + if (defined($git_count)) { + genform_prep(); + my $smallstr = rjustt($sz, 'Count', $git_count, $git_dirty); + my $forgitobj = $sz - length($git_count) - 1; + if (defined($git_object) && $forgitobj >= 2) { + $smallstr = ljustt($forgitobj, 'Objid', $git_object). + ($git_dirty || ' '). + $git_count; + } + genform_plusq("Small$sz", $smallstr); + } + + genform_prep(); + genform_plusq("Git$sz", ljustt($sz, 'Objid', $git_object, $git_dirty)) + if defined $git_object; + + if (defined $git_count && defined $git_object && $sz<=10) { + genform_prep(); + genform("Full".($sz*2), + ljustt($sz, 'Objid', $git_object), + rjustt($sz, 'Count', $git_count, $git_dirty)); + + genform_prep(); + my $e = $sz; + genform("Full".($e*3)."T", + ljustt($e*2, 'Objid', $git_object, $git_dirty) + =~ m/.{$e}/g, + rjustt($e, 'Count', $git_count)); + } + } +} + +sub do_some_best ($$) { + my ($bestwhat, $formre) = @_; + my $modname = "Best$bestwhat"; + my $fullmodname = "Commitid_${modname}_2D"; + my @argl = qw(max_sz margin=Commitid_pixelsz()); + p "module $fullmodname(".argl_formal(@argl).") {\n"; + my $mbs = '$Commitid_max_best_scale'; + p " sc_max = $mbs ? $mbs : 2;\n"; + p " sz = max_sz - 2*[margin,margin];\n"; + my @do; + foreach my $f ( + sort { + $b->{Included}{$bestwhat} <=> $a->{Included}{$bestwhat} or + $b->{Chars} <=> $a->{Chars} or + $a->{Lines} <=> $b->{Chars} + } + grep { + $_->{Form} =~ m/$formre/ && + !$_->{Ambiguous} + } + @forms + ) { + my $form = $f->{Form}; + p " sz_$form = Commitid_${form}_sz();\n"; + foreach my $rot (qw(0 1)) { + my $id = "${form}_r${rot}"; + p " sc_$id = min(sc_max"; + foreach my $xy (qw(0 1)) { + p ",sz[$xy]/sz_$form","[",(($xy xor $rot)+0),"]"; + } + p ");\n"; + push @do, " if (sc_$id >= 1.0"; + push @do, " && sc_$id >= sc_${form}_r1" if !$rot; + push @do, ") {\n"; + push @do, " translate([margin,margin]) scale(sc_$id)\n"; + push @do, " rotate(90) translate([0,-sz_$form"."[1]])\n" if $rot; + push @do, " Commitid_${form}_2D();\n"; + push @do, " } else"; + } + } + push @do, < 00 20 22 02 11 +< 00 20 11 22 02 + +0 1 2 3 4 5 6 7 8 9 + +/#\ r /#\ ##\ # # ### /#/ ### /#\ /#\ +# # /# # # # # # # # # # # # +# # # /#/ ##< \## ##\ ##\ // >#< \## +# # # # # # # # # # # # # +\#/ /#\ ### ##/ # ##/ \#/ # \#/ ##/ + +a b c d e f + + # # /## + # /## # /#\ # +/## ##\ # /## #r# ### +# # # # # # # #/ # +\## ##/ \## \## \#/ # + ++ * + + # # + # \#/ +### ### + # /#\ + # # diff --git a/crossbar-computer-led-mount.scad b/crossbar-computer-led-mount.scad new file mode 100644 index 0000000..535c680 --- /dev/null +++ b/crossbar-computer-led-mount.scad @@ -0,0 +1,340 @@ +// -*- C -*- + +led_dia = 5 + 0.6; +led_depth = 5; + +led_tip_height_above_crossbar = 70; +led_angle = -60; +crossbar_dia = 25; // fixme + +vert_space_inside = 8; +backfront_space_inside = 12; +width_space_inside = 10; + +backfront_mate_size = 25; +tower_frontheight = 10; +tower_base_height = 20; +tower_slot_width = 3; + +cableclamp_ctie_width = 4.0 + 1.0; +cableclamp_ctie_thick = 2.5 + 0.5; + +lidclamp_ctie_width = 4.0 + 1.0; +lidclamp_ctie_thick = 2.5 + 0.5; + +base_ctie_width = 4.0 + 1.0; +base_ctie_thick = 2.5 + 0.5; + +tube_ctie_width = 4.0 + 1.0; +tube_ctie_thick = 2.5 + 0.5; + +// tuning + +tower_over_angle = 45; +tower_wall_thick = 1.6; +tower_forehead_angle = 30; +lid_wall_thick = 1.6; +lid_slop = 0.75; +//cableclamp_ctie_anchor = 5; +lidclamp_cableclamp_ctie_between = 0; +base_ctie_anchor = 5; +tube_ctie_anchor = 5; +protrusion_size = 2; +protrusion_none_frontback = 10; +protrusion_slop = 0.25; +cableclamp_ctie_z = tower_frontheight/2; + +towerleg_backfront = 5; +towerleg_width = 3; +towerleg_foot_gap = 2; +towerleg_foot_backfront = 20; +towerleg_foot_width = 40; +towerleg_foot_height = 10; +towerleg_yslope = 0.7; +towerleg_xslope = 0.3; +echo(sqrt(towerleg_yslope*towerleg_yslope+towerleg_xslope*towerleg_xslope)); + +//--- tests --- + +test_width = 24; +test_height = 24; + +test_thicks = [9,14,21]; + +module Tests(){ ////toplevel + for (thicki=[0:len(test_thicks)-1]) { + translate([thicki*test_width-0.5, 0, 0]) { + difference(){ + cube([test_width, + test_thicks[thicki] + led_depth, + test_height]); + translate([test_width/2, -1, test_height/2]) + rotate([-90,0,0]) + cylinder(r=led_dia/2, h=led_depth+1, $fn=30); + } + } + } +} + +//Tests(); + +//--- real thing --- + +// calculated + +tower_overhang = led_dia * 2.5; +tower_width = width_space_inside + tower_wall_thick*2; + +tower_over_max_y = tower_overhang * sin(tower_over_angle); +tower_over_max_z = tower_frontheight + tower_overhang * cos(tower_over_angle); +tower_total_max_z = tower_over_max_z + vert_space_inside + led_depth; +tower_rearwall_y = -(backfront_space_inside + tower_wall_thick); +led_head_y = tower_over_max_y/2; +led_head_z = tower_frontheight + tower_overhang*sin(tower_over_angle)/2; +backfront_mate_extra = (backfront_mate_size - (-tower_rearwall_y)); + +tower_height_contribution = led_head_z + tower_base_height; + +base_ctie_anchor_eff = base_ctie_anchor+base_ctie_thick/2; +tube_ctie_anchor_eff = tube_ctie_anchor+tube_ctie_thick/2; + +base_width = 0.7 * crossbar_dia; +base_backfront = backfront_mate_extra - tower_rearwall_y; +base_height = led_tip_height_above_crossbar - tower_height_contribution; + +protrusion_frontback = base_backfront - protrusion_none_frontback; + +echo(tower_height_contribution, base_height); + +module TowerWallCrossSection(){ + // generates a 2D shape - a polygon + // x is what is going to be -y + // y is what is going to be z + polygon([[0, 0], + [0, tower_frontheight], + [-tower_over_max_y, tower_over_max_z], + [-tower_over_max_y + + tan(tower_forehead_angle) * (vert_space_inside + led_depth), + tower_total_max_z], + [-tower_rearwall_y, tower_total_max_z], + [-tower_rearwall_y, 0], + [-tower_rearwall_y, -tower_base_height], + [-backfront_mate_extra, -tower_base_height]], + convexity=5); +} + +module TowerWallSomeEdge(front){ + minkowski(){ + difference(){ + TowerWallCrossSection(); + translate([front ? 0.10 : -0.10, 0]) + TowerWallCrossSection(); + } + circle(r=tower_wall_thick, $fn=8); + } +} + +module TowerBulkCrossSection(){ + intersection(){ + TowerWallCrossSection(); + union(){ + translate([-led_head_y, led_head_z]) + circle(r = led_depth); + TowerWallSomeEdge(true); + translate([-50, -50]) + square([100, 50]); + } + } +} + +module TowerRearWallCrossSection(){ + intersection(){ + TowerWallCrossSection(); + union(){ + intersection(){ + translate([0,-10]) square([100, 10+led_head_z]); + TowerWallSomeEdge(false); + } + TowerBulkCrossSection(); + } + } +} + + +module TowerCrossSectionDemo(){ + %TowerWallCrossSection(); + //TowerBulkCrossSection(); + TowerRearWallCrossSection(); +} + +module TowerMain(){ + for (mir=[0,1]) + mirror([mir,0,0]) rotate([90,0,-90]) { + translate([0,0, tower_width/2-tower_wall_thick]) + linear_extrude(height=tower_wall_thick) { + TowerWallCrossSection(); + } + translate([0,0,-1]) + linear_extrude(height=tower_width/2+0.9) + union(){ + TowerBulkCrossSection(); + hull(){ + intersection(){ + TowerWallCrossSection(); + translate([-30, -30]) + square([30 + 0.1, 30 + tower_frontheight]); + } + } + } + translate([0,0, tower_slot_width/2]) + linear_extrude(height=(tower_width - tower_slot_width)/2 - 0.2) + TowerRearWallCrossSection(); + } +} + +module LedHole(){ + translate([0, led_head_y, led_head_z]) + rotate([90 + led_angle, 0, 0]) + translate([0,0,-10]) + cylinder(r=led_dia/2, h=led_depth+1+10, $fn=26, $fa=10); +} + +module TowerProper(){ + difference(){ + TowerMain(); + LedHole(); + // passages for cable ties + translate([0, + tower_rearwall_y/2, + cableclamp_ctie_z + + cableclamp_ctie_width/2 + lidclamp_ctie_thick/2 + + lidclamp_cableclamp_ctie_between]) + cube([50, lidclamp_ctie_width, lidclamp_ctie_thick], center=true); + translate([0, + (backfront_mate_extra+tower_rearwall_y)/2, + -tower_base_height + + max(protrusion_size + protrusion_slop + 0.1, + base_ctie_anchor_eff)]) + cube([50, base_ctie_width, base_ctie_thick], center=true); +// for (extra_y=[0, -(cableclamp_ctie_thick + cableclamp_ctie_anchor)]) { +// translate([-tower_width/2, +// -cableclamp_ctie_thick/2 - tower_wall_thick + extra_y, +// cableclamp_ctie_z]) +// cube([tower_wall_thick+2, +// cableclamp_ctie_thick, +// cableclamp_ctie_width], center=true); +// } + for (mir=[0,1]) + mirror([mir,0,0]) { + translate([tower_width/4, 20, cableclamp_ctie_z]) + cube([cableclamp_ctie_thick, + tower_wall_thick*2+1+40, + cableclamp_ctie_width], + center=true); + } + translate([0, tower_rearwall_y, -tower_base_height]) + BaseRegistrationProtrusion(protrusion_slop); + } +} + +module Tower(){ ////toplevel + TowerProper(); + for (mir=[0,1]) { + mirror([mir,0,0]){ + translate([0, + tower_rearwall_y + 0.1, + -1]) + mirror([0,0,1]) + multmatrix([[1,0, towerleg_xslope,0], + [0,1,-towerleg_yslope,0], + [0,0,1,0], + [0,0,0,1]]) + cube([towerleg_width, towerleg_backfront, tower_base_height-2]); + } + } + translate([-towerleg_foot_width/2, + tower_rearwall_y - towerleg_foot_gap, + -tower_base_height]) + mirror([0,1,0]) + cube([towerleg_foot_width, towerleg_foot_backfront, towerleg_foot_height]); +} + +module TowerMainHull(){ + hull(){ TowerMain(); } +} + +module Lid(){ + intersection(){ + difference(){ + minkowski(){ + TowerMainHull(); + sphere(r=lid_wall_thick+lid_slop, $fn=8); + } + minkowski(){ + TowerMainHull(); + sphere(r=lid_slop, $fn=6); + } + } + translate([-50,-50,led_head_z]) cube([100,100,100]); + } +} + +module LidT(){ ////toplevel + rotate([180,0,0]) Lid(); +} + +module BaseRegistrationProtrusion(extra){ + size = protrusion_size + extra; + translate([0, base_backfront/2, 0]){ + hull(){ + translate([0,0, -0.5]) + cube([protrusion_size*2, protrusion_frontback, 1.0], center=true); + translate([0, 0, protrusion_size-0.5]) + cube([0.05, protrusion_frontback-protrusion_size*2, 1.0], center=true); + } + } +} + +module Base(){ + difference(){ + mirror([0,0,1]){ + hull(){ + translate([-tower_width/2, 0, 0]) + cube([tower_width, base_backfront, 0.1]); + translate([-base_width/2, 0, base_height]) + cube([base_width, base_backfront, crossbar_dia/2]); + } + } + translate([0, base_backfront/2, -base_ctie_anchor_eff]) + cube([100, base_ctie_width, base_ctie_thick], center=true); + translate([0, base_backfront/2, -base_height + tube_ctie_anchor_eff]) + cube([100, tube_ctie_width, tube_ctie_thick], center=true); + translate([0, -1, -(base_height + crossbar_dia/2)]) + rotate([-90,0,0]) + cylinder(r=crossbar_dia/2, h=101); + } + BaseRegistrationProtrusion(0.0); +} + +module BaseT(){ ////toplevel + rotate([90,0,0]) Base(); +} + +module Demo(){ + Tower(); + %Lid(); + translate([0,0, 25]) Lid(); + translate([0, tower_rearwall_y, -(tower_base_height+5)]) Base(); +} + +//TowerCrossSectionDemo(); +//TowerWallSomeEdge(false); +//TowerWallFrontEdge(); +//TowerMainHull(); +//LidT(); +//Tower(); +//Lid(); +//BaseRegistrationProtrusion(); +//Base(); +//BaseT(); +//Demo(); diff --git a/dell-psu-glow-lampshade.scad b/dell-psu-glow-lampshade.scad new file mode 100644 index 0000000..8733948 --- /dev/null +++ b/dell-psu-glow-lampshade.scad @@ -0,0 +1,16 @@ +// -*- C -*- + +india = 11.01 + 0.50; +t = 0.9; +l = 7.5; + +$fa = 3; +$fs = 0.2; + +linear_extrude(height=l, convexity=10) { + difference(){ + circle(r = india/2 + t); + circle(r = india/2); + } +} + diff --git a/deore-crank-remover.scad b/deore-crank-remover.scad new file mode 100644 index 0000000..1b0a738 --- /dev/null +++ b/deore-crank-remover.scad @@ -0,0 +1,34 @@ +// -*- C -*- + +outdia=15.1; +india=13.0; +depth=10; + +eoutrad = outdia/2 + 1.0; +einrad = india/2 - 1.0; +edepth = depth + 3; + +handledepth = 5; +handlewidth = 20; +handlelength = 70; + +module FlatSplines(){ + for (rot=[0:7]) { + rotate([0,0, rot*360/8]) + for (m=[0,1]) { + mirror([m,0,0]) + polygon([[-0.1, 0], + [-0.01, eoutrad], + [einrad * sin(22.5), einrad * cos(22.5)], + [einrad * sin(22.5), einrad * cos(22.5) - 3], + [1, 0]]); + } + } +} + +translate([0,0,-1]) + linear_extrude(height=edepth+1) + FlatSplines(); + +translate([0,0,-handledepth/2]) + cube([handlelength,handlewidth,handledepth], center=true); diff --git a/distort-stl b/distort-stl new file mode 100755 index 0000000..68290c4 --- /dev/null +++ b/distort-stl @@ -0,0 +1,296 @@ +#!/usr/bin/perl -w +# +# usage: +# ./distort-stl OUTPUT DISTORTION [PARAMS...] ... +# +# DISTORTIONs: +# +# project-cylinder RADIUS +# projects the X-Z plane onto the cylinder of +# radius RADIUS with axis [0, 0, t] +# origin becomes [0, -RADIUS, 0] +# other planes of the input are projected onto smaller +# or larger cylinders accordingly +# probably a bad idea if +# object has any Y > RADIUS +# object has any |X| > tau / RADIUS +# technically, treats input as if it were +# polar-rectangular coords: +# Z' = Z; R' = Y + RADIUS; theta' = X / RADIUS +# and then converts back into cartesian +# honours fa but not fs or fn +# +# set-fa $FA + +use strict; +use autodie; + +use List::Util; +use POSIX; +use File::Temp (); +use Data::Dumper; + +sub TAU () { M_PI * 2; } + +our $debug = $ENV{DISTORT_DEBUG} // 0 ; + +my $ps = $ENV{DISTORT_PS}; +if ($ps) { + open PS, "> $ps" or die $!; + print PS "%!\n"; +} + +our $fa = 10; + +our $triangles; +our $output; + +sub shift_arg () { + die unless @ARGV; + scalar shift @ARGV; +} + +#no warnings qw(recursion); + +sub sprintf_triangle ($) { + my ($t) = @_; + + return '' unless $debug; + + if ($ps && $t->[3] =~ m/$ENV{DISTORT_PS_RE}/) { + printf PS <<'END', + %20.16g %20.16g %20.16g moveto + %20.16g %20.16g %20.16g lineto + %20.16g %20.16g %20.16g lineto + closepath stroke +END + $t->[0][0], $t->[0][1], $t->[0][2], + $t->[1][0], $t->[1][1], $t->[1][2], + $t->[2][0], $t->[2][1], $t->[2][2], + or die $!; + flush PS or die $!; + } + + sprintf + "%11.6f,%11.6f,%11.6f / ". + "%11.6f,%11.6f,%11.6f / ". + "%11.6f,%11.6f,%11.6f %-40s ", + $t->[0][0], $t->[0][1], $t->[0][2], + $t->[1][0], $t->[1][1], $t->[1][2], + $t->[2][0], $t->[2][1], $t->[2][2], + $t->[3]; +} + +sub maybe_subdivide_triangle ($$$$) { + my ($t, $ok, $changed, $edge_need_subdivide_fn) = @_; + + print STDERR sprintf_triangle $t if $debug; + + my (@longest) = qw(-1); + + foreach my $ix (0..2) { + my $jx = ($ix+1) % 3; + next unless $edge_need_subdivide_fn->($t->[$ix], $t->[$jx]); + my $l2 = 0; + foreach my $ci (0..2) { + my $d = $t->[$ix][$ci] - $t->[$jx][$ci]; + $l2 += $d*$d; + } + next unless $l2 > $longest[0]; + @longest = ($l2, $ix, $jx); + } + if ($longest[0] < 0) { + push @$ok, $t; + printf STDERR "OK nok=%d nchanged=%d\n", + (scalar @$ok), (scalar @$changed) + if $debug; + print STDERR Dumper(\@$ok) if $debug>=2; + return; + } + my ($dummy,$ix,$jx) = @longest; + my $kx = ($ix+2) % 3; + + printf STDERR + " S i=%d j=%d k=%d ", + $ix, $jx, $kx + if $debug; + my @midp; + foreach my $ci (0..2) { + push @midp, 0.5 * ($t->[$ix][$ci] + $t->[$jx][$ci]); + } + + printf STDERR + " midp %11.6f,%11.6f,%11.6f\n", + @midp + if $debug; + + # triangle i-j-k, splitting edge i-m + # gives i-m-k, k-m-j + my $gensplit = sub { + my ($ixjx, $xwhat) = @_; + my $n = [ @$t ]; + $n->[$ixjx] = \@midp; + $n->[3] = "$t->[3]$xwhat"; + printf STDERR "%s\n", sprintf_triangle $n if $debug; + unshift @$changed, $n; + }; + $gensplit->($ix, "a$ix$jx"); + $gensplit->($jx, "b$ix$jx"); + return; +} + +sub maybe_subdivide ($) { + my ($edge_need_subdivide_fn) = @_; + + my @small_enough = (); + while (my $t = shift @$triangles) { + maybe_subdivide_triangle $t, \@small_enough, $triangles, + $edge_need_subdivide_fn; + } + + $triangles = \@small_enough; +} + +sub append_triangle ($) { + my ($t) = @_; + push @$output, $t; +} + +#---------- set-fa ---------- + +sub op__set_fa () { + $fa = shift_arg; +} + +#---------- project-cylinder ---------- + +our $project_cylinder_radius; +our $project_cylinder_max_d_theta; + +sub project_cylinder_edge_need_subdivide ($$) { + my @thetas = map { $_->[0] / $project_cylinder_radius } @_; + return abs($thetas[0] - $thetas[1]) > $project_cylinder_max_d_theta; +} + +sub project_cylinder_tri { + my ($t) = @_; + + #print STDERR 'PROJECT', Dumper($t); + + my $radius = $project_cylinder_radius; + + my @ot; + foreach my $p (@$t[0..2]) { + my ($x,$y,$z) = @$p; + my $r = $radius - $y; + my $theta = $x / $radius; + push @ot, [ $r * sin($theta), + -$r * cos($theta), + $z ]; + } + push @ot, $t->[3].'P'; + append_triangle \@ot; +} + +sub op__project_cylinder () { + $project_cylinder_radius = shift_arg; + $project_cylinder_max_d_theta = $fa * TAU/360; + + maybe_subdivide \&project_cylinder_edge_need_subdivide; + + $output = []; + foreach my $t (@$triangles) { + project_cylinder_tri $t; + } + $triangles = $output; +} + +#---------- main program ---------- + +our $raw; + +while (@ARGV && $ARGV[0] =~ m/^-/) { + $_ = shift @ARGV; + last if m/^--$/; + if (s/^--raw$//) { + $raw = 1; + } else { + die "$_ ?"; + } +} + +my $itmp; +my $otmp; + +my $admesh_stdout = '--write-ascii-stl /dev/fd/3 3>&1 >/dev/null'; + +if ($raw) { + open I, "<& STDIN"; + $otmp = *STDOUT; +} else { + $itmp = new File::Temp; + $otmp = new File::Temp; + + system "cat >$itmp"; + + open I, "admesh $admesh_stdout $itmp |"; +} + +my $triangle; + +while () { + s/^\s*//; + if (m/^outer\s+loop/) { + die if $triangle; + $triangle = []; + } elsif (s/^vertex\s+//) { + my $lhs = $&; + s/\s+$//; + my @xyz = split /\s+/, $_; + die unless $triangle; + push @$triangle, \@xyz; + } elsif (m/^endloop/) { + die unless @$triangle == 3; + push @$triangle, $.; + push @$triangles, $triangle; + undef $triangle; + } elsif (m/^(?:solid|facet\s+normal|endfacet|endsolid)\s/) { + } else { + die "$_ ?"; + } +} + +close I; + if 0; # suppresses Name "main::I" used only once + +while (@ARGV) { + my $op = shift_arg; + $op =~ y/-/_/; + &{ ${*::}{"op__$op"} }; +} + +select $otmp; + +print "solid distort-stl\n"; + +foreach my $t (@$triangles) { + print " facet normal 0 0 0\n"; + print " outer loop\n"; + die unless @$t==4; + foreach my $p (@$t[0..2]) { + die unless @$p==3; + print " vertex"; + printf " %.18g", $_ foreach @$p; + print "\n"; + } + print " endloop\n"; + print " endfacet\n"; +} + +print "endsolid distort-stl\n"; + +flush $otmp; + +if (!$raw) { + system "admesh --normal-values $admesh_stdout $otmp"; +} diff --git a/diziet-utils/COPYING b/diziet-utils/COPYING new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/diziet-utils/COPYING @@ -0,0 +1,674 @@ + 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 +. diff --git a/README.md b/diziet-utils/README.md similarity index 100% rename from README.md rename to diziet-utils/README.md diff --git a/doveclip.scad b/doveclip.scad new file mode 100644 index 0000000..0536c1c --- /dev/null +++ b/doveclip.scad @@ -0,0 +1,161 @@ +// -*- C -*- +// +// doveclip.scad +// +// 3D design for a fastener suitable for Reprapss +// Copyright 2012,2016 Ian Jackson +// +// This work 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 work 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 work. If not, see . + + +toothheight = 1.2; +webthick = 1.8; +height = 7; +pinlengthfact = 1.2; +nomrad = height/2 - toothheight; +minrad = nomrad - 0.75; +maxrad = nomrad + 0.25; +jawthick = 1.5; + +webgap = 0.4; +basepinclear = 1.0; + +toothgap = webthick + webgap*2; +basethick = toothheight; + +module DoveClipPin(h=height) { + pinh = h * pinlengthfact; + pinheight = nomrad*2 + jawthick*2; + translate([0,0, pinheight/2]) intersection(){ + union(){ + for (m=[0,1]) { + mirror([0,0,m]) translate([0,0,pinheight/2]) rotate([90,0,0]) + cylinder($fn=20, r1=minrad, r2=maxrad, h=pinh); + } + translate([-webthick/2, -pinh, -pinheight/2-1]) + cube([webthick, pinh, pinheight+2]); + } + translate([-maxrad-1, -pinh-1, -pinheight/2]) + cube([maxrad*2+2, pinh+2, pinheight]); + } +} + +function DoveClip_depth() = + basethick + nomrad*2 + toothheight; + +module DoveClipEnd(baseextend=1, h=7) { + cubex = nomrad*2 + jawthick*2; + cube0y = -basethick-nomrad*2-toothheight; + centrey = -basethick-nomrad; + difference(){ + translate([-cubex/2, cube0y, 0]) + cube([cubex, -cube0y+baseextend, h]); + translate([0, centrey, -1]) + cylinder($fn=20, r=nomrad, h=h+2); + translate([-toothgap/2, cube0y-1, -1]) + cube([toothgap, toothheight+nomrad+1, h+2]); + } +} + +module DoveClipPair(baseextend=1, h=7) { + delta = nomrad*2 + jawthick*2 + toothgap; + for (x=[-delta/2,delta/2]) + translate([x,0,0]) + DoveClipEnd(baseextend=baseextend, h=h); +} + +module DoveClipPairBase(baseextend=0.1, h=7, count=2) { + delta = nomrad*2 + jawthick; + intrude = nomrad + basethick - basepinclear; + for (i=[0:count-1]) { + translate([(i - (count-1)/2) * delta, 0, 0]) + DoveClipEnd(baseextend=baseextend, h=h); + } + translate([-delta * count/2, -intrude, 0]) + cube([delta * count, intrude+0.1, h]); +} + +module DoveClipPairSane(baseextend=0, h=7, count=2) { + rotate([0,0,90]) + translate([0, DoveClip_depth(), 0]) + DoveClipPairBase(baseextend=baseextend, h=h, count=count); +} + +function DoveClipPairSane_width(count=2) = + 2 * (nomrad + jawthick + ((nomrad*2 + jawthick) * (count-1)/2)); + +module ExtenderPillar(length, height, + pillarw=3.5, pillarslope=0.75, webthick=1) { + pillarr=pillarw/2; + d = 0.25; + + intangle = atan(pillarslope); + polyjx = sin(intangle)*pillarr; + polyjy = cos(intangle)*pillarr; + polyex = -tan(intangle+90)*pillarr; + webmidy = height/2+d; + + for (xmir=[0,1]) + translate([0,0,height/2]) mirror([0,0,xmir]) + translate([0,0,-height/2]) { + intersection() { + translate([-1, -pillarr-5, 0.01]) + cube([length+2, height+pillarr*2+10, height]); + mirror([1,0,0]) rotate([0,-90,0]) + linear_extrude(height=length) union(){ + circle(r=pillarr, $fn=20); + polygon([[polyjx,polyjy-0.1], [polyex, 0], + [polyjx,-(polyjy-0.1)]]); + polygon([[0,-webthick/2], [0,webthick/2], + [webmidy,webthick/2], [webmidy,-webthick/2]]); + } + } + } +} + +module ExtenderPillars(length, width, height, + pillarw=3.5, pillarslope=0.75, webthick=1, + baseweb=false, basewebthick=1) { + pilesw = width - pillarw; + + for (ymir=[0,1]) mirror([0,ymir,0]) translate([0,-pilesw/2,0]) { + ExtenderPillar(length, height, pillarw, pillarslope, webthick); + } + + if (baseweb) { + translate([0, -pilesw/2, 0]) + cube([length, pilesw, basewebthick]); + } +} + +module DoveClipExtender(length, ha=7, hb=7, counta=2, countb=2, + pillarw=3.5, pillarslope=0.75, webthick=1) { + + mirror([1,0,0]) + DoveClipPairSane(h=ha, count=counta); + translate([length,0,0]) + DoveClipPairSane(h=hb, count=countb); + pillarlen = length - DoveClip_depth() * 2 + 2; + + pilesw = min(DoveClipPairSane_width(counta), DoveClipPairSane_width(countb)) + - 0.5; + pilesh = min(ha, hb) - 0.5; + + translate([DoveClip_depth() - 1, 0, 0]) + ExtenderPillars(pillarlen, pilesw, pilesh, + pillarw=pillarw, pillarslope=pillarslope, + webthick=webthick); +} + +//DoveClipExtender(length=100, ha=16, hb=20, counta=3, countb=4); diff --git a/dovecliptest.scad b/dovecliptest.scad new file mode 100644 index 0000000..e7e075c --- /dev/null +++ b/dovecliptest.scad @@ -0,0 +1,15 @@ +// -*- C -*- + +include + +for (y=[0,-15]) translate([0,y,0]) { + DoveClipPair(); + + translate([-8,0,0]) + cube([16,5,7]); + translate([15,0,0]) + DoveClipPin(); +} + +translate([0,20,0]) + DoveClipPairBase(); diff --git a/dungeonquest-cone.scad b/dungeonquest-cone.scad new file mode 100644 index 0000000..b56ff91 --- /dev/null +++ b/dungeonquest-cone.scad @@ -0,0 +1,19 @@ +// -*- C -*- + +basesz=12; +height=14.7; +topsz=0.5; +dsz=0; + +module One(){ ////toplevel + cylinder(h=height, r1=basesz/2-dsz, r2=topsz/2-dsz, $fn=50); +} + +module Four(){ ////toplevel + for (x=[0,1]) { + for (y=[0,1]) { + translate([x*(basesz+3), y*(basesz+3), 0]) + One(); + } + } +} diff --git a/dungeonquest-cone.slic3r b/dungeonquest-cone.slic3r new file mode 100644 index 0000000..b7d882f --- /dev/null +++ b/dungeonquest-cone.slic3r @@ -0,0 +1,2 @@ +bed_temperature = 80 +temperature = 205 diff --git a/earring-stand.scad b/earring-stand.scad new file mode 100644 index 0000000..85c28a8 --- /dev/null +++ b/earring-stand.scad @@ -0,0 +1,345 @@ +// -*- C -*- + +include + +front_height = 80; +front_width = 120; +front_setback = 30; +front_thick = 2.4; + +front_hex_stride = 12.5; +front_hex_dia = 9.5; + +front_hex_y_fudge = -0.65; + +front_surround_lr =3; + +back_thick = 3; +back_pillarw = 6; + +base_thick = 2.4; + +eclip_inner_rad = 2.5; +eclip_gap_rad = 0.1; +eclip_prong_th = 2.25; +eclip_outer_strt = 0.5; +eclip_inner_xstrt = 0.5; + +eclip_ult_angle = 44; +eclip_base_epsilon = 0.5; + +eclip_each_len = 6; +eclip_each_every = 29; + +test_alpha = 10; +test_main_th = 1.5; +test_eclips = 5; +test_base_th = 2.5; +test_len = eclip_each_len + eclip_each_every*(test_eclips-1); + +num_eclips = 5; + +// calculated + +include + +eclip_inner_strt = eclip_outer_strt + eclip_inner_xstrt; + +r0 = eclip_inner_rad; +r1 = r0 + eclip_gap_rad; +r2 = r1 + eclip_prong_th; +r2e = r1 + eclip_base_epsilon; + +ppxl = -(r0 / sqrt(2)) + (eclip_inner_strt / sqrt(2)); + +rgap = eclip_gap_rad; + +eclip_base_offset = r1; +eclip_wall_offset = -ppxl; + +eclip_ra_offset = r2 - 0.1; + +eclip_recept_height = r2; + +eclip_rhs_offset = ppxl + rgap + eclip_prong_th; +// does not include main_th + +$fn=70; + +module EclipLPlanCore(alpha){ + FArcSegment(0,0, r1,r2, + 180-eclip_ult_angle, eclip_ult_angle-alpha +1); + + difference(){ + hull(){ + intersection(){ + circle(r2); + rotate(-alpha) mirror([1,1]) square([r2e, 50]); + } + rotate(-alpha) mirror([1,1]) square([r2e, r2]); + } + circle(r1); + } +} + +module EclipRPlan(alpha, main_th){ + intersection(){ + rotate(alpha) + translate([ppxl + main_th + rgap, -r2*2]) + square([eclip_prong_th, r2*(2 + 1/sqrt(2))]); + translate([-r2, -r2e]) + square([r2*3, eclip_base_epsilon + r2*4]); + } +} + +module EclipLPlan(alpha){ + rotate(alpha) EclipLPlanCore(alpha); +} + +module EclipPPlan(main_th){ + intersection(){ + hull(){ + circle(r0); + rotate(90-eclip_ult_angle) square([r0,r0]); + } + translate([-(r0+.1), -(r0+.1)]) + square([(r0+.1) + main_th + ppxl, r2*2]); + } + translate([ppxl, 0]) square([main_th, r2]); +} + +module TestBase(){ ////toplevel + translate([0,0, eclip_base_offset]){ + for (i=[1 : 2: test_eclips-2]) { + translate([0, i*eclip_each_every]) + rotate([90,0,0]) + linear_extrude(height=eclip_each_len) + EclipLPlan(test_alpha); + } + for (j=[0 : 2: test_eclips-1]) { + translate([0, j*eclip_each_every]) + rotate([90,0,0]) + linear_extrude(height=eclip_each_len) + EclipRPlan(test_alpha, test_main_th); + } + } + translate([-r2, -eclip_each_len, -test_base_th]){ + difference(){ + cube([r2*2, + test_len, + test_base_th]); + mirror([0,0,1]) Commitid_BestCount_M([r2*2, test_len]); + } + } +} + +module TestProtr(){ ////toplevel + difference(){ + translate([0,0, test_main_th - eclip_wall_offset]) + rotate([0,90,0]) + linear_extrude(height=test_len) + EclipPPlan(test_main_th); + mirror([0,0,1]) Commitid_BestCount_M([test_len, r2]); + } +} + +module TestRAProtr(){ ////toplevel + rotate([-90,0,0]) TestProtr(); + mirror([1,0,0]) + translate([-test_len, + -r2, + -(eclip_ra_offset + test_base_th)]) + cube([test_len, + r2*2, + test_base_th]); +} + +module TestPlanDemo(){ + color("red") EclipLPlan(test_alpha); + color("blue") rotate(test_alpha) EclipPPlan(test_main_th); + color("green") EclipRPlan(test_alpha, test_main_th); +} + +beta = asin(front_setback / front_height); + +uf = [-sin(beta), cos(beta)]; +ur = [ -uf[1], uf[0]]; + +pp = [0, 0]; +pq = pp + uf*front_height + ur*eclip_ra_offset; +pr = [ pq[0] - eclip_base_offset - eclip_wall_offset, + 0 ]; + +echo("uf ur P Q R", uf, ur, pp, pq, pr); + +module Sketch(){ + polygon([pq, pp, pr]); +} + +thicks = [ base_thick, front_thick, back_thick ]; + +module Joins(alpha, objnum, objnum_f, objnum_m) { + pitch = (front_width - eclip_each_len) / (num_eclips-1); + + thm = thicks[objnum_m]; + stride = (front_width - eclip_each_len) / (num_eclips-1); + + if (objnum==objnum_f) { + for (i=[ 1 : 2 : num_eclips-1 ]) { + translate([0, i*stride + eclip_each_len, 0]) { + rotate([90,0,0]) + linear_extrude(height=eclip_each_len) + EclipLPlan(alpha); + } + } + for (i=[ 0 : 2 : num_eclips-1 ]) { + translate([0, i*stride + eclip_each_len, 0]) { + rotate([90,0,0]) + linear_extrude(height=eclip_each_len) + EclipRPlan(alpha, thm); + } + } + } + if (objnum==objnum_m) + mirror([0,1,0]) + rotate([90,0,0]) + linear_extrude(height=front_width) + rotate(alpha) + EclipPPlan(thm); +} + +function r3(pc) = [ pc[0], 0, pc[1] ]; + +module ObjectJoins(objnum){ + translate(r3(pp)) Joins(beta, objnum, 0,1); + translate(r3(pr)) mirror([1,0,0]) Joins(0, objnum, 0,2); + translate(r3(pq)) rotate([0,90,0]) mirror([1,0,0]) Joins(-beta, objnum, 2,1); +} + +module Base(){ + xmin = pr[0] - eclip_rhs_offset - thicks[2]; + xmax = pp[0] + eclip_rhs_offset + thicks[1] + + eclip_prong_th * (1/cos(beta) - 1) + + eclip_base_offset * tan(beta); + intersection(){ + ObjectJoins(0); + translate([xmin, + -1, + -50]) + cube([xmax - xmin, + front_width + 2, + 300]); + } + translate([xmin, + 0, + -eclip_base_offset - thicks[0]]){ + difference(){ + cube([xmax - xmin, + front_width, + thicks[0]]); + translate([xmax-xmin, front_width]/2) + rotate([0,0,270]) + Commitid_Full16_M(); + } + } +} + +module FrontPattern(){ + totalh = front_height - eclip_wall_offset + thicks[1]; + + ystride = front_hex_stride; + xstride = front_hex_stride * cos(30) * 2; + + difference(){ + square([front_width, totalh]); + translate([ front_surround_lr, + eclip_recept_height ]) + square([ front_width - front_surround_lr*2, + totalh - eclip_recept_height*2 + ]); + } + + difference(){ + square([front_width, totalh]); + for (xi=[ -5 : 5 ]) { + translate([front_width/2 + + xi * xstride, + 0]) { + for (yi=[ 0 : 10 ]) { + //echo(yi); + translate([0, yi * ystride + + front_hex_dia*front_hex_y_fudge]) { + for (dv=[ [0,0], + [-xstride/2, -ystride/2] + ]) + translate(dv) + circle(r= front_hex_dia/2, $fn=6); + } + } + } + } + } +} + +module Front(){ + ObjectJoins(1); + rotate([0, 90-beta, 0]) + translate([0, 0, ppxl]) + rotate([0,0,90]) { + linear_extrude(height=thicks[1]) + FrontPattern(); + } +} + +module Back(){ + ObjectJoins(2); + + zmin = pr[1]; + zmax = pq[1] + eclip_prong_th; + height = zmax - zmin; + + translate([pr[0] + eclip_wall_offset - thicks[2], + 0, 0]) + rotate([0,90,0]) + rotate([0,0,90]) { + difference(){ + cube([front_width, + height, + thicks[2]]); + translate([back_pillarw, + eclip_recept_height, + -10]) + cube([front_width - back_pillarw*2, + height - eclip_recept_height*2 - eclip_prong_th, + 20]); + } + } +} + +module BackPrint(){ ////toplevel + rotate([0,-90,0]) Back(); +} + +module FrontPrint(){ ////toplevel + rotate([0, 90+beta, 0]) Front(); +} + +module BasePrint(){ ////toplevel + Base(); +} + +module Demo(){ ////toplevel + color("red") Base(); + color("blue") Front(); + color("black") Back(); +} + +//PlanDemo(); +//TestBase(); +//TestProtr(); +//TestRAProtr(); +//Sketch(); +//Demo(); +//BackPrint(); +//FrontPrint(); +//BasePrint(); diff --git a/electron-token.scad.pl b/electron-token.scad.pl new file mode 100755 index 0000000..dc24c5a --- /dev/null +++ b/electron-token.scad.pl @@ -0,0 +1,140 @@ +#!/usr/bin/perl -w + +use strict; +use Math::Trig; +use Math::Vector::Real; +use IO::File; +use Data::Dumper; +use constant tau => pi*2; + +my $ellipse = 60 / 2; +my $circle = 3.5 / 2; +my $xscale = 33 / 100; +my $N = 180; # around ellipse +my $M = 80; # around each circle + +my $NMdiv = $ENV{'ELECTRONTOKEN_COARSE'} || 1; + +$M /= $NMdiv; +$N /= $NMdiv; + +print <versor(); + my $rad0 = $axis x V(0,0,1); + my $rad1 = $rad0 x $axis; + [ map { + my $theta = tau * $_ / $M; + $centre + $circle * ($rad0 * cos($theta) + $rad1 * sin($theta)); + } 0..($M-1) ]; +} 0..($N-1); + +sub scadvec ($) { + my ($v) = @_; + return "[ ".(join ", ", @$v)." ]" +} + +sub torusy () { + print "module Torusy(){ polyhedron(points=["; + my $ptix = 0; + my @cirpt; + foreach my $i (0..$N-1) { + foreach my $j (0..$M-1) { + print "," if $ptix; + print "\n"; + print " ",(scadvec $circles[$i][$j]); + $cirpt[$i][$j] = $ptix++; + } + } + print "\n ],\n"; + + print " faces=["; + foreach my $i (0..$N-1) { + my $i2 = ($i+1) % $N; + foreach my $j (0..$M-1) { + my $j2 = ($j+1) % $M; + print "," if $i || $j; + print "\n"; + print " [ ", (join ", ", + $cirpt[ $i ][ $j ], + $cirpt[ $i ][ $j2 ], + $cirpt[ $i2 ][ $j ], + ), " ],"; + print " [ ", (join ", ", + $cirpt[ $i ][ $j2 ], + $cirpt[ $i2 ][ $j2 ], + $cirpt[ $i2 ][ $j ], + ), " ]"; + } + } + print "\n ]);\n}\n"; +} + +torusy(); + + +our @distances; +push @distances, 0; +foreach my $i (1..$N) { + my $dist = $distances[ $i-1 ]; + $dist += abs($ellipse[$i % $N] - $ellipse[$i-1]); + $distances[$i] = $dist; +} + +sub infodistprop ($) { + my ($distprop) = @_; + # returns + # ( $ellipse_centreline_point, + # $along_vector ) + my $dist = $distprop * $distances[$N]; + foreach my $i (0..$N-1) { + my $prorata = + ($dist - $distances[$i]) / + ($distances[$i+1] - $distances[$i]); + next unless 0 <= $prorata && $prorata <= 1; + print "// infodistprop $distprop => #$i=$ellipse[$i] $prorata $ellipse[$i+1]\n"; + return ( + (1-$prorata) * $ellipse[$i] + ($prorata) * $ellipse[$i+1], + $alongs[$i], + ); + } + die "$distprop ?"; +} + +while () { print }; + +STDOUT->error and die $!; +STDOUT->flush or die $!; + +__DATA__ +module Token(){ + difference(){ + for (rot=[ 0,120,240 ]) + rotate([0,0, rot]) + translate([0,0,torusyup]) + Torusy(); + translate([-200,-200,-50]) + cube([400,400,50]); + } +} +Token(); diff --git a/experimental-prefix-nonworking b/experimental-prefix-nonworking new file mode 100644 index 0000000..1b679f3 --- /dev/null +++ b/experimental-prefix-nonworking @@ -0,0 +1,5 @@ +G28 ; home all axes +G1 F500 +G1 Y10 +M83 ; extruder relative +G1 F60 diff --git a/fairphone-battery-case.scad b/fairphone-battery-case.scad new file mode 100644 index 0000000..557271d --- /dev/null +++ b/fairphone-battery-case.scad @@ -0,0 +1,190 @@ +// -*- C -*- + +include + +mainwall_th = 3.0; +smallwall_th = 2.0; + +seal_th = 0.3 + 0.6 + 0.6 - 0.4 - 0.4 + 0.2; // total gap for seal etc. +behind_recess = 1.5; + +recess_gap_end = 0.4; + +lid_edge_th = 0.5; + +battery_len = 66.55 + 1.25 -.55; +battery_th = 6.55 + 0.75 - .60; +battery_wdth = 44.38 + 0.75 -.55; + +battery_base_indent = 0.94 + 0.50; +battery_base_indent_fromside_outside = 4; +battery_base_indent_fromside_inside = 10; + +handle_height = 3.5; +handle_inward = 10; +handle_len = 5; + +pushhole_ell_sz = 4.75; +pushhole_ell_th = 1.75; +pushhole_circle_dia = 4.0; + +// for testing: +//battery_len = 3; +//battery_wdth = 15; +//battery_base_indent_fromside_inside = 6; + +// calculated + +bpp0 = [0,0]; +bpp1 = bpp0 + [ 0, mainwall_th - behind_recess ]; +lppA = bpp1 + [ seal_th, -recess_gap_end ]; +lppB = lppA + [ lid_edge_th, 0 ]; +bpp2 = [ lppB[0], bpp1[1] ]; +bpp3 = [ bpp2[0] + (bpp1 - bpp0)[1], bpp0[1] ]; +bpp4 = [ bpp3[0], bpp0[1] + mainwall_th ]; +lppC = bpp3 + [ 0, -recess_gap_end ]; + +lppF = lppC + [ handle_height, 0 ]; + +s0 = battery_wdth/2; +s0i = s0 - battery_th/2; +s1 = s0 + smallwall_th; + +l1 = s1 - handle_inward; +l0 = l1 - handle_len; + +echo( + bpp0, + bpp1, + bpp2, + bpp3, + bpp4, + bpp5, + bpp6, + bpp7, + bpp8 +); + +echo( + lppA, + lppB, + lppC, + lppD, + lppE +); + +bpp8 = bpp0 + [ -battery_len,0 ]; +bpp5 = [ bpp8[0] - smallwall_th, bpp4[1] ]; +bpp9 = [ bpp0[0], bpp0[1] - battery_th/2 - 1.0 ]; +bpp7 = [ bpp8[0], bpp9[1] ]; +bpp6 = [ bpp5[0], bpp9[1] ]; +lppE = [ lppA[0], bpp9[1] ]; +lppD = [ lppC[0], bpp9[1] ]; + +module BaseHalfPlan(indent=0){ + polygon([ bpp0, + bpp1, + bpp2, + bpp3, + bpp4, + bpp5, + bpp6, + bpp7 + indent * [1,0], + bpp8 + indent * [1,0] + ]); +} + +module SideHalfPlan(){ + polygon([ bpp5, + bpp6, + bpp9, + bpp1 + ]); +} + +module LidHalfPlan(){ + polygon([ lppA, + lppE, + lppD, + lppC, + lppB + ]); +} + +module HandleHalfPlan(){ + translate(lppE) + square(lppF - lppE); +} + +module ExtrudePlan(from,to){ + rotate([0,-90,0]) + for (mj=[0,1]) { + mirror([0,0,mj]) translate([0,0,from]){ + linear_extrude(height= to-from, convexity=5){ + for (mi=[0,1]) { + mirror([0,mi]) + translate([0, battery_th/2]) + children(0); + } + } + } + } +} + +module PushHolePlan(){ ////toplevel + translate(-(pushhole_ell_th * 0.10 + + pushhole_ell_sz * 0.10) * [1,1]) { + for (r=[0,90]) + rotate(r) + translate(-pushhole_ell_th * 0.5 * [1,1]) + square([ pushhole_ell_sz, pushhole_ell_th ]); + } + circle(pushhole_circle_dia/2, $fn=40); +} + +module PlanDemo(){ ////toplevel + color("blue") BaseHalfPlan(); + color("red") LidHalfPlan(); + translate([0,0,-1]) color("lightblue") SideHalfPlan(); +} + +module Base(){ ////toplevel + difference(){ + ExtrudePlan(0,s1) BaseHalfPlan(); + linextr(-(10+battery_len), battery_len+10, convexity=5) PushHolePlan(); + } + difference(){ + union(){ + ExtrudePlan(s0i, s1) SideHalfPlan(); + ExtrudePlan(s0 - battery_base_indent_fromside_inside, + s0 - battery_base_indent_fromside_outside + ) BaseHalfPlan(indent = battery_base_indent); + } + for (m=[0,1]) + mirror([m,0,0]) + translate([s0i, 0, bpp7[0] - 0.1]) + cylinder(r= battery_th/2, h=100, $fs=0.5); + } +} + +module BaseHalfTest(){ ////toplevel + intersection(){ + Base(); + translate([-100,0,-100]) + cube([200,200,200]); + } +} + +module Lid(){ ////toplevel + ExtrudePlan(0,s1) LidHalfPlan(); + ExtrudePlan(l0,l1) HandleHalfPlan(); +} + +module Demo(){ ////toplevel + %Base(); + Lid(); +} + +//PlanDemo(); +//Demo(); +//Base(); diff --git a/fairphone-case-mounted.scad b/fairphone-case-mounted.scad new file mode 100644 index 0000000..8999348 --- /dev/null +++ b/fairphone-case-mounted.scad @@ -0,0 +1,14 @@ +// -*- C -*- + +include + +module CaseMounted(){ ////toplevel + Case(); + translate([ phone_width/2, + -phone_height/2, epp3[1] - case_th_bottom ]) + Mount(); +} + +//// toplevels-from: +include +$suppress_forward_holes = true; diff --git a/fairphone-case.scad b/fairphone-case.scad new file mode 100644 index 0000000..2998b54 --- /dev/null +++ b/fairphone-case.scad @@ -0,0 +1,1755 @@ +// -*- C -*- + +// Hard case for Fairphone 2 +// +// Copyright 2018 Ian Jackson. There is NO WARRANTY. +// See below for full licensing and disclaimer. +// +// Instructions +// +// 1. You will want to git clone this repository. +// +// 2. Decide about the notification LED aperture. See the variable +// led_window_style, below. The default here is "ad-hoc +// multi-colour", which can produces a translucent (clear-ish) +// window set into the lid, even on a single-nozzle printer. +// See "Ad-hoc multi-colour", below. +// +// 3. use "make" to generate the necessary files: +// +// make -j8 fairphone-case.auto.scads `for f in \ +// HingePrint \ +// LidWindowPrint \ +// LidPrint \ +// OneKeeperPrint \ +// Case \ +// ; do echo fairphone-case,$f.auto.stl; done` +// +// 4. Print them. Case and OneKeeperPrint should probably be +// the same colour. +// +// For Lid and LidWindowPrint, if you are doing ad-hoc +// multi-colour: +// i. Set up for clear filament +// ii. Print LidWindowPrint. Wait for it to finish. +// It won't take long. As soon as it finishes, tell +// your printer to warm up (so that in fact it does +// not cool down). +// iii. Leaving the output so far on the printbed, reload +// your printer with the main lid colour. +// iv. Print LidPrint. You can let this go unattended. +// +// 5. Assemble the hinge. You will need 4x M2 12mm machine screws +// and 8x M2 full nuts. +// +// Make sure you get the hinge the right way round. If you're not +// sure, run +// openscad fairphone-case,DemoHinge.auto.scad +// to see an assembly diagram. +// +// The nuts recess into the hinge. You will want very fine +// pliers. As you screw each screw in, add the second nut when +// the screw thread emerges from the first - this will be a +// locknut. Screw each screw to an appropriate tightness for the +// hinge stiffness. You want the lid-side hinge to be stiffer as +// that makes closing the case work better. +// +// When you have the stiffness right, tighten the locknuts onto +// each first nut. +// +// 6. In use: +// +// - To put the phone in, drop its RH side into the RH side of +// the case. Then feed the keeper through the small hole. +// Feed it right through. +// +// - The optional prop can be used to prop the phone up (in +// portrait orientation only right now). See +// openscad fairphone-case,DemoPropAngles.auto.scad +// +// Ad-hoc multi-colour +// +// This file is set up to let you make a translucent window using a +// single-extruder printer, using a "two print run" technique. This +// works well with our Lulzbot TAZ 5 and Aleph Objects' version of +// Cura. If you are using a different printer, you may need to +// adjust the parameters or try a different technique. In particular, +// initial_layer_thick +// set so that the window is one layer thick +// initial_layer_width +// set so that the slicer draws a rectangle around the whole +// object, rather than putting a "skirt" or anything inside +// +// If you have a dual-extruder printer, you can set led_window_style +// to 2 and do a single print of LidPrint and LidWindowPrint. +// +// Alternatively you can set it to 1 (just a hole) or 0 (no hole). +// +// Thanks to Clare Boothby for the ad-hoc multi-colour technique (and +// the parameters for our Lulzbot TAZ 5 and Aleph Objects's Cura). +// +// Other phones +// +// It might well be possible to adapt this file for other phones. +// If you do, let me know how you get on. +// +// +// AUTHORSHIP, COPYRIGHT, LICENCE, AND LACK OF WARRANTY +// +// Copyright (C)2018 Ian Jackson. +// +// This program for generating a 3D model 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 +// . +// +// In particular DO NOT BLAME ME IF THIS CASE DOES NOT ADEQUATELY +// PROTECT YOUR PHONE ! It is your responsibility to decide whether +// this case will meet your needs. + +include +include + +phone = [ 75.0, 145.0 ]; + +prop_buildout_less = 3; + +prop_angles = [ 15, 30, 45, 60 ]; + +bumper = [ 0.250, -0.025 ]; +// ^ One side. Overall size is increased by twice this. +// If no bumpers, is the gap around the phone. + +enable_support = 1; + +led_window_style = 3; +// 0: no window +// 1: simply an opening +// 2: opening with separate cover model, for printing in clear (two colour) +// 3: like 2 but one-layer window for ad-hoc multi-colour + +initial_layer_thick = 0.400; // ^ needed for mode 3 only +initial_layer_width = 0.750; // ^ needed for mode 3 only +multicolour_gap = 0.15; // each side + +phone_cnr_rad = 6.0; +phone_rim_depth = 0.80; // includes allowance for a screen protector + +button_cutout_depth = 9; + +phone_edge_thick = 9.0; +phone_total_thick = 12.0; +phone_backside_slope_inner = 1.5; // larger means shallower +phone_backside_slope_outer = 1.0; // larger means shallower + +camera_pos_tl = [ 6.450, 12.750 ]; // measured from tl corner +camera_pos_br = [ 22.300, 37.600 ]; // tl/br as seen from back + +jack_pos = [ 13.83, 8.485 ]; +jack_dia = 10.64 + .5; // some jack I had lying around + +led_pos = [ 13.98, 10.00 ]; +led_aperture = 9; +led_window_ledge = 0.75; // each side + +noisecancelmic_pos = [ 19.54, 7.37 ]; // from rhs +noisecancelmic_dia = 4.00; + +//fingerpushhole_dias = [ 15, 18 ]; +fingerpushhole_dias = []; + +lanyard_half_dia = 1.15; +lanyard_entry_rel_breadth = 2; +lanyard_channel_len = 15; +rearspeaker_pos_bl = [ 12.64, 18.72 ]; +rearspeaker_size = [ 3.76, 7.36 ]; + +microusb_above = 3.27 - 0.25; +microusb_below = 0.0; +microusb_width = 16.12 + 1.25; + +case_th_bottom = 2.5; +case_th_lid = 3.0; +case_th_side = 2.3; +case_th_lip = 1.2; + +lid_screen_gap_extra = .66; + +case_struts_count = 6; +case_struts_solid_below = 1.00; +case_struts_solid_above = 0.75; +case_struts_width = 0.10; + +keeper_th_z = 0.75; +keeper_th_x = 0.75; +keeper_inner_width = 2.75; +keeper_inner_height = 2.75; +keeper_slant_slope = 2; // larger means steeper + +keeper_gap_z_top = 0.25; +keeper_gap_z_bot = 0.75; +keeper_gap_x = 0.25; +keeper_gap_x_holes = 0.75; + +keeper_side = 0; // 0 = lhs; 1 = rhs + +case_lip = 1.25; + +lid_gap_x = 0.25; +lid_gap_z = 0.25; +lid_lip = 1.75; +lid_edgepart_width = 5.0; +lid_buttoncover_thick = 1.3; +lid_buttoncover_reinf = 0.65; + +foldover_gap = 0.50; +foldover_lever_gap = 0.50; + +// properties of the hinge fasteners +hingescrew_shaft_dia = 2.0 + 0.25; // M2 x 12mm machine screw +hingescrew_shaft_len = 12; +hingescrew_fasteners_extra_thick = 0.40; +// ^ amount of thread protruding if everything was completely nominal +// and we are using two nuts +hingescrew_nut_access_dia = 4.72 + 0.50; +// ^ washer is 4.72 dia +// also, want to get pliers or tiny spanner in to do up locknut +hingescrew_nut_across = 3.92 + 0.25; // incl. slop around recess slop +hingescrew_nut_thick = 1.93; +hingescrew_head_th = 1.38 + 0.75; +hingescrew_head_dia = 3.92; + +hingescrew_nut_recess_portion = 2/3; // portion of nut in recess + +lever_cover_th = 0.75; +hingemount_th = 2.5; +hingemount_wd = 4.8725; + +$fa = 5; +$fs = 0.1; + +button_l_fudge = 4.4; +buttonishleg_default_l_is_fudge = 10; + +hinge_base_slope = 1.5; // bigger is steeper + +strut_min_at_end = 1.5; + +hinge_x_gap = 0.125; +hinge_x_postscrew_gap = 0.75; +hinge_x_arms_gap = 0.35; +hinge_r_arms_gap = 0.55; + +rearspeaker_gap = [ 2.0, 2.0 ]; // each side + +thumbrecess_depth = 1.3; +thumbrecess_width = 16.5; +thumbrecess_topcurve_r = 5.0; + +prop_recess_under = 0.50; +prop_recess_slop = 0.200; // each side +prop_end_dia = 0.5; +prop_main_th = 3; +prop_taper_len = 6; +prop_main_width = 4; +prop_side_gap = 0.75; // each side +prop_lidrecess_behind = 0.75; +prop_caserecess_behind = 0.75; +prop_caserecess_taper = 0.45; // one side only +prop_prop_gap = 0.5; +prop_prong_heel_slope = 0.5; + +lid_fold_clearance_antislop = 0.5; + +$button_leg_only = false; +$suppress_forward_holes = false; + +// ---------- calculated ---------- + +phone_width = (phone + bumper*2)[0]; +phone_height = (phone + bumper*2)[1]; + +inside_br = [phone_width, -phone_height]; + +prop_prong_h = prop_main_th; + +//echo(camera_pos_tl + bumper, +// camera_pos_br + bumper); + +// ----- could be changed ----- +lid_buttoncover_gap = lid_gap_x; +lid_buttoncover_overlap = case_th_lip + keeper_gap_z_top; + +phone_backside_slope_thick = phone_total_thick - phone_edge_thick; + +//prop_lidrecess_depth = case_th_lid - prop_recess_under; + +//prop_nose_len = case_th_lid - prop_recess_under; +//prop_recess_slope = tan(prop_max_angle); // bigger means steeper +//prop_recess_width = prop_main_th / cos(prop_max_angle) + prop_backfwd_gap; + + +//lid_lip_overlap_width xxx bad name = ; +//lid_lip_inner_slope = [ 5, 5 ]; // xxx + +epp0 = [0,0]; +epp1 = [0, -phone_edge_thick]; +epp2i = epp1 + phone_backside_slope_thick * [ phone_backside_slope_inner, -1 ]; +epp2o = epp1 + phone_backside_slope_thick * [ phone_backside_slope_outer, -1 ]; +epp3 = epp2i + [10, 0]; +epp5 = epp0 + [0,1] * (keeper_th_z + keeper_gap_z_top + case_lip); +epp4 = epp5 + [-1,0] * case_th_side; + +kppe = [0,0]; +kppd = kppe + [1,0] * keeper_inner_width; +kppc = kppd + [0,1] * keeper_th_z; +kppb = [ kppe[0] - keeper_th_x, kppc[1] ]; +kppf = kppe - [0,1] * keeper_inner_height; +kppa = [ kppb[0], kppf[1] ]; + +lpp10 = [ epp5[0] + lid_gap_x, kppc[1] + lid_gap_z ]; +lpp11 = [ lpp10[0], epp5[1] + lid_gap_z ]; + +lpp14 = lpp10 + [1,0] * max(keeper_inner_width, lid_edgepart_width); +// exact x posn not very important; must extend past end of keeper + +lpp15 = [ lpp14[0], + epp0[1] - phone_rim_depth + 1/2.5 * case_th_lid + + lid_screen_gap_extra ]; +// ^ beam theory says to maximise force before contact, +// the gap below the `beam' (the lid) must be 1/3 +// the thickness (ie the lid thickness) if the beam +// is solid, or 1/2 if it has a top and bottom only. +// ours is mostly solid. + +lp_r12 = max(case_th_lid - (lpp11[1] - lpp15[1]), + case_th_lip); + +lpp12 = [ epp4[0] + lp_r12, lpp11[1] ]; +lpp13 = [ lpp12[0], lpp12[1] + lp_r12 ]; + +case_bottom_z = epp2o[1] - case_th_bottom; + +// button profile +bppM = epp4 + [0,5]; +bppN = [ bppM[0] + lid_buttoncover_thick, bppM[1] ]; +bppR = [ bppN[0] + lid_buttoncover_gap, -button_cutout_depth ]; +bppS = [ epp1[0], bppR[1] ]; +bppQ = [ bppM[0], bppR[1] - lid_buttoncover_overlap ]; +bppP = bppQ + [0,1] * lid_buttoncover_gap; +bppO = [ bppN[0], bppP[1] ]; +bppL = lpp10 + [5,0]; +bppK = [ bppL[0], bppN[1] ]; +bppJ = [ bppN[0], bppL[1] ]; +bppU = [ bppJ[0], lpp12[1] ]; +bppV = lpp11; +bppW = lpp10; + +echo("BUTTON COVER TH", bppO[0] - bppP[0]); + +// notification led aperture + +nla_r0 = led_aperture/2; +nla_r1 = nla_r0 + led_window_ledge; +nla_r2 = nla_r1 + multicolour_gap; +nla_t = + led_window_style >= 3 ? initial_layer_thick : + led_window_style >= 2 ? led_window_ledge : 0; + + +// hinge plan +hp_rn = hingescrew_nut_access_dia/2; +hp_r2_min = hp_rn + lever_cover_th; +hp_rs = hingescrew_shaft_dia/2; +hp_r1_min = hp_rs + hingemount_th; + +hp_r1 = max(hp_r1_min, hp_r2_min); +hp_r2 = hp_r1; + +hppU = lpp13; +hppS = epp2o + [0,-1] * case_th_bottom; +hp_k = 0.5 * (hppU[1] - hppS[1] + foldover_gap); + +hppM = [ epp4[0] - foldover_lever_gap - hp_r2, + 0.5 * (hppU + hppS)[1] ]; +hppT = [ hppM[0], hppU[1] - hp_r1 ]; +hppB = hppT + [0,-1] * hp_k; + +hppE_y = epp2o[1] - case_th_bottom + hp_r1; +hppE_x = hppB[0] + (hppB[1] - hppE_y) * hinge_base_slope; +hppE = [ hppE_x, hppE_y ]; + +// hinge elevation x coords + +hex20 = max(epp2o[0], + phone_cnr_rad, + kppd[0] + hingescrew_head_th + keeper_gap_x_holes); +hex21 = hex20 + hingemount_wd; +hex22 = hex21 + hinge_x_gap; +hex27 = hex20 + hingescrew_shaft_len; +hex24 = hex27 + hinge_x_postscrew_gap; +hex23 = hex27 - (hingescrew_nut_thick*2 + + hingescrew_fasteners_extra_thick); +hex26 = hex23 + hingescrew_nut_thick * 2/3; + +echo(hex20, hex21, hex22, hex23, hex24); +// 6, 10.8725, 10.9975, 13.74, 18.75 +module chk(act,exp) { + if (abs(act-exp) > 1e-9) echo("WRONG", act, exp); + else echo("ok", act); +} +chk(hex20, 6); +chk(hex21, 10.8725); +chk(hex22, 10.9975); +chk(hex23, 13.74); +chk(hex24, 18.75); + +lid_fold_clearance_skew = + (lpp10[1] - hppB[1]) / + (lpp10[0] - hppB[0]); + +echo("SK",lid_fold_clearance_skew); + +// thumb recess (used to be "catch" hence cpp* + +cppA = epp4 + [thumbrecess_depth, 0]; +cppB = [ cppA[0], epp1[1] ]; + +// lanyard + +ly_r = lanyard_half_dia / 2; +ly_rc = ly_r * 2; + +ly_theta = -atan2vector(epp2i - epp1); +ly_o = epp2i + 3 * ly_r * unitvector2d(epp1 - epp2i); + +max_case_bottom_edge_thickness = + case_th_bottom + + sin(ly_theta) * (epp2i-epp2o)[0]; + +ly_q_z = -(ly_rc + ly_r); +ly_re = max_case_bottom_edge_thickness - (-ly_q_z); + +ly_oec_y = lanyard_entry_rel_breadth * ly_r; + +// prop recess in case + +prop_x_pos = phone_width/2; + +prop_recess_hw = 0.5 * prop_main_width + prop_side_gap; + +prc_r1 = prop_end_dia/2; +prc_r3 = prc_r1 + prop_recess_slop; + +prcp2 = [ epp4[0] + prop_buildout_less, + case_bottom_z ]; + +prop_caserecess_buildout_r = -1; // prcp2[0] - epp2o[0]; + +prcp1 = [ epp2o[0] + prc_r3 + prop_caserecess_behind, + epp2i[1] - prc_r3 - prop_recess_under]; + +// prop recess in lid + +prl_r10 = prop_end_dia/2; +prl_r10o = prl_r10 + prop_recess_slop; + +prlp10 = lpp10 + [1,1] * prl_r10o + + [1,0] * prop_lidrecess_behind + + [0,1] * prop_recess_under; + +// prop + +$prpp10 = [0,0]; +$prpp11 = [0, prop_taper_len]; + +$prp_r10 = prl_r10; + +// ---------- modules ---------- + +module AdhocMultiprintFrame(phase, z0, zs) { + // from z0 to z0 + zs*layer + extra = phase * (initial_layer_width + multicolour_gap) + 5; + xextra = extra + -epp4[0]; + xrange = [ 0, phone_width ] + [-1,+1] * xextra; + yextra = extra + -epp4[0]; + yrange = [ -phone_height + +hppB[0] - hp_r2, 0 ] + [-1,+1] * yextra; + p0 = [ xrange[0], yrange[0] ]; + p1 = [ xrange[1], yrange[1] ]; + echo(p0, p1); + translate([0,0, z0]) + mirror([0,0, zs<0 ? 1 : 0]) + linear_extrude(height= initial_layer_thick) + difference(){ + rectfromto(p0 - [1,1] * initial_layer_width, + p1 + [1,1] * initial_layer_width); + rectfromto(p0, p1); + } +} + +module KeeperProfile(slant=0){ + use_e = kppe + [0,-1] * slant * keeper_inner_width / keeper_slant_slope; + polygon([use_e, kppd, kppc, kppb, kppa, kppf]); +} + +module EdgeProfile(){ + difference(){ + hull(){ + translate(epp3) square(case_th_bottom*2, center=true); + circleat(epp2o, r=case_th_bottom); + circleat(epp1, r=case_th_side); + rectfromto(epp0, epp4); + } + polygon([ epp5 + [0,10], + epp1, + epp2i, + epp3 + [10,0] ]); + } +} + +module LanyardLanyardProfile(entry=false){ + hull(){ + for (xs=[-1,+1] * (entry ? lanyard_entry_rel_breadth : 1)) + translate(xs * 0.5 * lanyard_half_dia * [1,0]) + circle(r= lanyard_half_dia/2); + } +} + +module LanyardCurveChannelProfile(){ + translate([0, -ly_r]) + LanyardLanyardProfile(); +} + +module LanyardEntryChannelProfile(){ + LanyardLanyardProfile(true); +} + +module LanyardMainChannelProfile(){ + LanyardCurveChannelProfile(); + difference(){ + square(center=true, ly_r * [6, 2]); + for (xs=[-1,+1]) + translate(ly_r * [3 * xs, -1]) + circle(r = ly_r); + } +} + +module LanyardEntryOuterProfile(){ + circleat([ly_re + ly_r, 0], ly_re); +} + +module LanyardEntry(){ + q_z = ly_q_z; + oec_y = ly_oec_y; + + d_x = -ly_rc; + + translate([d_x, 0, q_z]) { + intersection(){ + rotate([90,0,0]) + rotate_extrude(convexity=10) + rotate(90) + translate([0, -q_z]) + LanyardCurveChannelProfile(); + translate([0,-10,0]) + cube([20,20,20]); + } + } + + mirror([0,0,1]) + translate([0,0,-1]) + linear_extrude(height=20) + rotate(-90) + LanyardEntryChannelProfile(); + + translate([0, ly_r*2, 0]) + rotate([90,0,0]) + linear_extrude(height = ly_r*4){ + difference(){ + rectfromto([d_x, q_z], [ly_r, 0]); + circleat([d_x, q_z], ly_rc); + } + } + + translate([0,0,q_z]){ + for (my=[0,1]) + mirror([0,my,0]){ + translate([0, oec_y, 0]){ + difference(){ + translate(ly_re * [-1,0,-2]) + cube(ly_re * [2,1,2]); + rotate_extrude(convexity=10) + LanyardEntryOuterProfile(); + } + } + } + difference(){ + translate([-ly_re, -(oec_y + 0.01), -2*ly_re]) + cube([ly_re*2, 2*(oec_y + 0.01), 2*ly_re]); + for (mx=[0,1]) + mirror([mx,0,0]) + rotate([90,0,0]) + translate([0,0,-10]) + linear_extrude(height=20) + LanyardEntryOuterProfile(); + } + } +} + +module LanyardCutout(l){ + rotate([0,-90,0]) + linear_extrude(height=l) + rotate(-90) + LanyardMainChannelProfile(); + + for (ee=[0,1]){ + translate(ee * l * [-1,0]) + mirror([ee,0,0]) + LanyardEntry(); + } +} + +module LidEdgeProfile(){ + polygon([ lpp10, + lpp11, + lpp12, + lpp13, + lpp13 + [10, 0], + lpp15 + [10, 0], + lpp15, + lpp14, + ]); + intersection(){ + circleat(lpp12, r=lp_r12); + rectfromto( lpp12 + [-10, 0], + lpp12 + [+10, +10] ); + } +} + +module LidEdgeFoldClearanceProfile(){ + translate([-lid_fold_clearance_antislop, 0]) + polygon([ lpp10, + lpp11, + lpp11 + [-20, 0], + lpp11 + [-20, 20], + lpp11 + [+20, 20], + lpp10 + [+20, 0] ]); +} + +module ButtonCoverProfile(){ + intersection(){ + polygon(concat([ bppM, bppP, bppO, bppJ ], + (enable_support && !$button_suppress_over_keeper + ? [ bppU, bppV, bppW ] : []), + [ bppL, bppK ])); + hull(){ + EdgeProfile(); + LidEdgeProfile(); + } + } +} + +module ButtonPlan(l, deep, cut){ + epsilon = + (cut ? 0 : lid_buttoncover_gap); + + delta = + (deep ? lid_buttoncover_overlap : 0); + + C = [0,0]; // by definition + T = [ 0, epp4[1] ]; + G = T + [0,10]; + + B0 = C + [0,-1] * button_cutout_depth; + B1 = B0 + [0,1] * epsilon; + + r0 = 0.5 * (T[1] - B0[1]); + A = [ -(l + button_l_fudge)/2 + r0, 0.5 * (T[1] + B0[1]) ]; + H = A + [0,-1] * delta; + + D = A + [-2,0] * r0; + F = D + [0,10]; + + E0 = 0.5 * (D + A); + E1 = E0 + [1,0] * epsilon; + + I0 = [ E0[0], H[1] ]; + I1 = [ E1[0], H[1] ]; + + hull(){ + for (m=[0,1]) mirror([m,0]) + circleat(H, r0 - epsilon); + } + for (m=[0,1]) mirror([m,0]) { + difference(){ + polygon([ E1, + I1, + H, + B1, + G, + F, + D + ]); + circleat(D, r0 + epsilon); + } + } +} + +module ButtonCoverReinf(){ ////toplevel + minkowski(){ + rotate([90,0,0]) + linear_extrude(height=0.01) + intersection(){ + ButtonCoverProfile(); + translate([bppJ[0] + 0.1, -50]) mirror([1,0]) + square([100,100]); + } + mirror([0,0,1]) linear_extrude(height=0.01) intersection(){ + circle(r= lid_buttoncover_reinf); + translate([-20,0]) square(40, center=true); + } + } +} + +module ThumbRecessCutProfile(){ + difference(){ + polygon([ cppA + [-10,0], + cppB + [-10,0], + cppB, + cppA ]); + circleat(epp1, r=case_th_side); + } +} + +module Flip_rhs(yn=[0,1]) { + for ($rhsflip=yn) { + translate([phone_width/2, 0, 0]) + mirror([$rhsflip,0,0]) + translate([-phone_width/2, 0, 0]) + children(); + } +} + +module Flip_bot(yn=[0,1]) { + for ($botflip=yn) { + translate([0, -phone_height/2, 0]) + mirror([0, $botflip, 0]) + translate([0, phone_height/2, 0]) + children(); + } +} + +module AroundEdges(fill_zstart, fill_th, fill_downwards=0){ + // sides + Flip_rhs(){ + translate([0, -phone_cnr_rad, 0]) + rotate([90,0,0]) + linear_extrude(height = phone_height - phone_cnr_rad*2) + children(0); + } + // corners + Flip_rhs() Flip_bot() { + translate([+1,-1] * phone_cnr_rad) + intersection(){ + rotate_extrude() + intersection(){ + mirror([1,0,0]) + translate([-1,0] * phone_cnr_rad) + children(0); + rectfromto([0,-20],[10,20]); + } + translate([-10, 0, -20] + 0.01 * [+1,-1, 0] ) + cube([10,10,40]); + } + } + // top and bottom + Flip_bot(){ + translate([ phone_width - phone_cnr_rad, 0,0 ]) + rotate([90,0,-90]) + linear_extrude(height = phone_width - phone_cnr_rad*2) + children(0); + } + // fill + translate([0,0, fill_zstart]) + mirror([0,0, fill_downwards]) + linear_extrude(height = fill_th) + rectfromto([+1,-1] * phone_cnr_rad, + [phone_width, -phone_height] + [-1,+1] * phone_cnr_rad); +} + +module CaseAperture(pos, dia, $fn) { + theta = 180/$fn; + translate([ pos[0] + bumper[0], + -epp2i[0], + -pos[1] ]) + rotate([-90, theta, 0]) + cylinder(r = dia/2 / cos(theta), + h = 60); +} + +module SideButton(y, y_ref_sign, l, suppress_over_keeper=0){ + // y_ref_sign: + // +1 measured from top of actual phone to top of button + // -1 measured from bottom of actual phone to bottom of button + // 0 y is centre of button in coordinate system + $button_l= l; + $button_suppress_over_keeper= suppress_over_keeper; + eff_y = y_ref_sign > 0 ? -bumper [1] -y -l/2 : + y_ref_sign < 0 ? (-phone -bumper)[1] +y +l/2 : + y; + //echo(eff_y); + translate([0, eff_y, 0]) + children(); +} + +module LidButtonishLeg(y, y_ref_sign, l=buttonishleg_default_l_is_fudge) { + $button_leg_only = true; + SideButton(y, y_ref_sign, l) children(); +} + +module Buttons(){ + Flip_rhs(1) SideButton(15.580, +1, 8.9 ) children(); // power + Flip_rhs(1) SideButton(48.700, -1, 8.920 ) children(); // camera + Flip_rhs(0) SideButton(30.800, +1, 21.96, 1) children(); // volume + Flip_rhs( ) LidButtonishLeg(14, -1) children(); +// Flip_rhs(0) LidButtonishLeg(20, +1, 20) children(); +} + +module Struts(x_start, z_min, th){ + // if th is negative, starts at z_min and works towards -ve z + // and object should then be printed other way up + for (i= [1 : 1 : case_struts_count]) { + translate([0, + 0, + z_min]) + mirror([0,0, th<0 ? 1 : 0]) + translate([0, + -phone_height * i / (case_struts_count+1), + case_struts_solid_below]) + linear_extrude(height= abs(th) + -(case_struts_solid_below+case_struts_solid_above)) + rectfromto([ x_start, -0.5 * case_struts_width ], + [ phone_width - x_start, +0.5 * case_struts_width ]); + } +} + +module OrdinaryRearAperture(rhs,bot, pos){ + Flip_rhs(rhs) Flip_bot(bot) + linextr(-20, 20) + mirror([0,1]) + translate(pos + bumper) + children(); +} + +module MicroUSB(){ + Flip_bot(1){ + rotate([90,0,0]) + mirror([0,0,1]) + linextr(-epp2i[0], 60) + translate([0.5 * phone_width, 0, 0]) + rectfromto([-microusb_width/2, epp2i[1] + microusb_below], + [+microusb_width/2, epp0[1] + -microusb_above]); + } +} + +module OrdinaryRearApertures(){ + // rear speaker + OrdinaryRearAperture(1,1, rearspeaker_pos_bl) + rectfromto(-rearspeaker_gap, + rearspeaker_size + rearspeaker_gap); + + // finger hole to remove phone + if (len(fingerpushhole_dias)) + OrdinaryRearAperture(1,0, [ fingerpushhole_dias[0]/2 + epp2i[0], + phone[1]/2 ]) + scale(fingerpushhole_dias) + circle(r= 0.5 ); +} + +module RearCameraAperture(){ + Flip_rhs(1) + mirror([0, 0, 1]) + linear_extrude(height = 20) + mirror([0, 1, 0]) + translate(bumper) + rectfromto(camera_pos_tl, camera_pos_br); +} + +module HingeLidProfile(){ + hull(){ + circleat(hppT, hp_r1); + circleat(lpp12, lp_r12); + polygon([lpp10, + lpp13 + [2,0], + lpp12, + hppT]); + } +} + +module HingeBaseProfile(){ + difference(){ + hull(){ + circleat(hppB, hp_r1); + circleat(hppE, hp_r1); + circleat(epp2o, case_th_bottom); + circleat(hppB + [10,0], hp_r1); + } + polygon([epp5, epp1, epp2i, epp3, bppL]); + } +} + +module HingeLeverOuterProfile(){ + hull(){ + circleat(hppT, hp_r2); + circleat(hppB, hp_r2); + } +} + +module HingeLeverInnerProfile(){ + for (s = [-1,+1]) { + c = s > 0 ? hppT : hppB; + translate(c) + mirror([0,0,s>0]) + rotate(s<0 ? -40 : 0) + hull() + for (x=[-20,20]) + for (y=[0, s * 10]) + translate([x,y]) + circle(hp_rn); + } +} + +module HingeLeverNutProfile(){ + for (c= [hppB, hppT]) { + translate(c) + circle($fn=6, r= 0.5 * hingescrew_nut_across / cos(30)); + } +} + +module Flip_hinge(doflip=1){ + hinge_origin = [0, -(phone_height - hppB[0]), hppB[1]]; + translate(hinge_origin) + rotate([doflip*180,0,0]) + translate(-hinge_origin) + children(); +} + +module HingePortion(x0,x1){ + Flip_rhs() Flip_bot(1) + translate([x0,0,0]) + mirror([1,0,0]) + rotate([90,0,-90]) + linear_extrude(height=x1-x0) + children(); +} + +module ThumbRecessApply(ztop){ + width = thumbrecess_width; + w = width + thumbrecess_topcurve_r*2 + 1; + translate([phone_width/2, 0,0]){ + difference(){ + rotate([90,0,-90]) + linextr(-w/2, w/2) + children(0); + translate([0, 50, 0]) + rotate([90,0,0]) + linear_extrude(height=100){ + for (m=[0,1]) mirror([m,0,0]) { + hull(){ + translate([w/2, ztop - thumbrecess_topcurve_r]) + circle(thumbrecess_topcurve_r); + translate([w/2, -50]) + square(thumbrecess_topcurve_r*2, center=true); + } + } + } + } + } +} + +module CaseBase(){ + AroundEdges(epp3[1], case_th_bottom, 1) + EdgeProfile(); +} + +function prop_x(gamma) = hp_k / (2 * sin(gamma/2)) - hppT[0]; + +module PropProfileAssignments(gamma){ + // https://en.wikipedia.org/wiki/Solution_of_triangles#Two_sides_and_the_included_angle_given_(SAS) + x = prop_x(gamma); + p = phone_height + prlp10[0] - hppB[0]; + b = p + x; + + q = phone_height - hppT[0] - prcp1[0]; // $prpp7[0] is 0 by definition + a = q + x; + c = sqrt(a*a + b*b - 2*a*b*cos(gamma)); + $prp_alpha = acos( (b*b + c*c - a*a) / (2*b*c) ); + + $prp_theta = 90 - $prp_alpha; + beta = 180 - $prp_alpha - gamma; + psi = 90 - beta; + + //echo("abc", a,b,c); + + v1 = [ [ cos(psi), -sin(psi) ], // x + [ sin(psi), cos(psi) ] ]; // y + + $prpp7 = [0, c + (lpp13[1] - $prpp10[1] - hp_k) ]; + + $prp_r1 = prc_r1; + $prp_r11 = prop_main_th/2; + + $prpp1 = $prpp7 + [1,0] * + // this is approximate, but will do + (prop_main_th/2 + prop_prop_gap + prcp1[0] - cppA[0]); + $prpp3 = $prpp1 + + v1[0] * -$prp_r1 + + v1[1] * ((prcp2[1] - prcp1[1]) - prop_prop_gap); + $prpp12 = $prpp3 + v1[0] * + (prop_end_dia + prop_caserecess_taper * ($prpp1[1] - $prpp3[1])); + $prp_r8 = prop_main_th; + $prpp4 = [ prop_main_th/2, $prpp3[1] ]; + $prp_r5 = $prp_r8; + $prpp5 = [ $prpp12[0] - $prp_r5, + $prpp3[1] - prop_prong_h + $prp_r5 ]; + $prpp6 = $prpp4 + [0,-1] * (prop_prong_h + + prop_prong_heel_slope * ($prpp5[0] - $prpp4[0])); + $prpp8 = $prpp4 + [0,-1] * $prp_r8; + $prpp9 = $prpp8 + [-1,0] * $prp_r8; + + children(); +} + +module PropProfile(gamma, cut=0, rot=0){ + PropProfileAssignments(gamma){ + + //#circleat($prpp3,1); + //#circleat($prpp12,1); + + if (!cut) { + hull(){ + translate($prpp8) + intersection(){ + circle($prp_r8); + polygon([[-20,-0], [20,20], [0,0]]); + } + rectfromto($prpp6, $prpp9); + translate($prpp5) intersection(){ + circle($prp_r5); + polygon([[-10,-10], [0,0], [10,0]]); + } + rectfromto($prpp12 + [0,-0.1], $prpp3); + } + hull(){ + circleat($prpp1, $prp_r1); + rectfromto($prpp12 + [0,-0.1], $prpp3); + } + } + // main shaft + rotate([0,0, rot*-$prp_theta]){ + hull(){ + extra = cut ? prop_recess_slop : 0; + rectfromto($prpp6, $prpp9); + circleat($prpp11, $prp_r11 + extra); + circleat($prpp10, $prp_r10 + extra); + } + } + } +} + +module PropAggregateProfile(){ + for (angle = prop_angles) + PropProfile(angle, 0,0); +} + +module Prop(){ ////toplevel + hw = prop_main_width/2; + linextr(-hw, +hw) + PropAggregateProfile(); +} + +module Case(){ ////toplevel + difference(){ + union(){ + CaseBase(); + + // ledge (fixed keeper) + Flip_rhs(1-keeper_side) intersection(){ + rotate([90, 0, 0]) + linear_extrude(height = phone_height + phone_cnr_rad * 2) + KeeperProfile(1); + + // outline of the whole case, to stop it protruding + translate([0,0, -25]) + linear_extrude(height = 50) + hull() + Flip_bot() + circleat([+1,-1] * phone_cnr_rad, phone_cnr_rad + case_th_side/2); + } + + // hinge + HingePortion(hex20, hex21) HingeBaseProfile(); + + // buildout for prop recess + if (prop_caserecess_buildout_r > 0) Flip_rhs(1) + linextr(case_bottom_z, epp2i[1]) + hull() { + for (dxs = [-1,+1]) + circleat([ prop_x_pos + dxs * prop_caserecess_buildout_r, + -epp2o[0] ], + r = epp2o[0] - prcp2[0]); + } + } + + // slot for keeper + Flip_rhs(keeper_side) + translate([0, -phone_cnr_rad, 0]) + rotate([90, 0, 0]) + linear_extrude(height = phone_height + phone_cnr_rad * 2) + minkowski(){ + KeeperProfile(); + rectfromto([ -keeper_gap_x, -keeper_gap_z_bot ], + [ keeper_gap_x_holes, +keeper_gap_z_top ]); + } + + // front camera + RearCameraAperture(); + + // struts (invisible, because they're buried in the case) + Struts(epp2i[0], epp2i[1] - case_th_bottom, case_th_bottom); + + Buttons(){ + mirror([1,0,0]) + rotate([90,0,90]) { + if (!($button_leg_only && enable_support)) + intersection(){ + translate([0,0,-10]) + linear_extrude(height= 20) + ButtonPlan($button_l, 0,1); + if ($button_leg_only) + rotate([-90,90,0]) + translate([phone_width/2, -400, kppe[1]]) + mirror([1-abs($rhsflip - keeper_side),0,0]) + cube([400, 800, 50]); + if (enable_support && !$button_suppress_over_keeper) + rotate([-90,90,0]) + translate([-400, -400, kppd[1]]) + mirror([0,0,1]) + cube([800,800,100]); + } + translate([0,0, -bppR[0]]) + linear_extrude(height= 20) + ButtonPlan($button_l, 1,1); + } + + } + + // apertures along top edge + if (!$suppress_forward_holes) { + CaseAperture(jack_pos, jack_dia, 8); + Flip_rhs(1) + CaseAperture(noisecancelmic_pos, noisecancelmic_dia, 8); + } + + OrdinaryRearApertures(); + + MicroUSB(); + + // gaps for the lid's hinge arms + HingePortion(hex20 - hinge_x_arms_gap, + hex21 + hinge_x_arms_gap) + minkowski(){ + HingeLidProfile(); + circle(r= hinge_r_arms_gap, $fn= 8); + } + + // screw holes in the hinge arms + HingeScrews(); + + // thumb recess + ThumbRecessApply(epp4[1]) + ThumbRecessCutProfile(); + + // lanyard + Flip_bot(1) + translate([ly_o[0], -(phone_cnr_rad + ly_re), ly_o[1]]) + rotate([0, ly_theta, 0]) + rotate([0,0,90]) + LanyardCutout(lanyard_channel_len); + + // prop recess + Flip_rhs(1) + translate([prop_x_pos,0,0]) + mirror([0,1,0]) + rotate([90,0,90]) + linextr(-prop_recess_hw, +prop_recess_hw) + hull(){ + for (d=[ [0,0], [0,-1], [+1,-1/prop_caserecess_taper] ]) + circleat(prcp1 + 20*d, + prc_r3); + } + } +} + +module LidAdhocMultiprintFrame(phase){ + if (led_window_style >= 3) { + AdhocMultiprintFrame(phase, lpp13[1], -1); + } +} + +module LidAroundEdges(){ + AroundEdges(lpp15[1], lpp13[1] - lpp15[1], 0) + children(); +} + +module Lid(){ ////toplevel + skew_centre = [0, lpp11[0], lpp11[1]]; + difference(){ + union(){ + intersection(){ + LidAroundEdges() + LidEdgeProfile(); + + translate(skew_centre) + multmatrix([[ 1, 0, 0, 0 ], + [ 0, 1, -lid_fold_clearance_skew, 0 ], + [ 0, 0, 1, 0 ], + [ 0, 0, 0, 1 ]]) + translate(-skew_centre) + LidAroundEdges() + LidEdgeFoldClearanceProfile(); + } + + // button covers + Buttons(){ + intersection(){ + rotate([90,0,90]) + translate([0,0,-10]) + linear_extrude(height= 20) + ButtonPlan($button_l, 1,0); + union(){ + rotate([90,0,0]) + translate([0,0,-100]) + linear_extrude(height= 200) + ButtonCoverProfile(); + hull() + for (y= [-1,+1] * (($button_l + button_l_fudge)/2 + - lid_buttoncover_reinf)) + translate([0,y,0]) + ButtonCoverReinf(); + } + } + } + + // hinge arms + HingePortion(hex20, hex21) { + LidEdgeProfile(); + HingeLidProfile(); + } + } + Struts(lpp10[0] + strut_min_at_end, lpp13[1], -case_th_lid); + + // screw holes in the hinge arms + HingeScrews(); + + // prop recess + translate([prop_x_pos, -prlp10[0], prlp10[1]]) + mirror([0,1,0]) + rotate([90,0,90]) + linextr(-prop_recess_hw, +prop_recess_hw) + hull() + for (pa = prop_angles) + PropProfile(pa, 1,1); + + // notification led aperture + if (led_window_style) + translate([led_pos[0], -led_pos[1], lpp13[1]]) { + translate([0,0,-10]) + cylinder(r=nla_r0, h=20); + if (led_window_style >= 2) + translate([0,0, -nla_t]) + cylinder(r=nla_r2, height=20); + } + + } + + LidAdhocMultiprintFrame(1); +} + +module HingeLever(){ ////toplevel + difference() { + // outer body, positive + HingePortion(hex22, hex22 + phone_width/2) + HingeLeverOuterProfile(); + + // space for the screws + HingePortion(hex26, hex24) + HingeLeverInnerProfile(); + + // recesses for the nuts + HingePortion(hex23, hex26+1) + HingeLeverNutProfile(); + + // bores for the screws + HingeScrews(); + + // space for the charging cable + MicroUSB(); + Flip_hinge() MicroUSB(); + } +} + +module LidWindow(){ ////toplevel + translate([led_pos[0], -led_pos[1], lpp13[1]]) + mirror([0,0,1]) + cylinder(r= nla_r1, h=nla_t); + LidAdhocMultiprintFrame(0); +} + +module LidWindowPrint(){ ////toplevel + rotate([0,180,0]) + LidWindow(); +} + +module DemoLidWindowSelect(){ + translate([led_pos[0], led_pos[1], -100]) { + translate([0, -30, 0]) cube([400, 400, 200]); + } +} + +module DemoLidWindow(){ ////toplevel + %Lid(); + LidWindow(); + translate([0,40,0]){ + color("blue") intersection(){ Lid(); DemoLidWindowSelect(); } + color("red") intersection(){ LidWindow(); DemoLidWindowSelect(); } + } +} + +module HingeLeverPrint(){ ////toplevel + rotate([-90,0,0]) + translate([-phone_width/2, phone_height, 0]) + HingeLever(); +} + +module TestSelectLength(){ + translate([-30, -200, -20]) + cube([30 + 15, 250, 40]); +} + +module TestLength(){ ////toplevel + intersection(){ + Case(); + TestSelectLength(); + } +} + +module TestLengthRight(){ ////toplevel + intersection(){ + Case(); + Flip_rhs(1) + TestSelectLength(); + } +} + +module TestSelectWidth(){ + translate([-30, -(phone_height - 25), -20]) + mirror([0, 1, 0]) + cube([200, 50, 40]); +} + +module TestWidth(){ ////toplevel + intersection(){ + Case(); + TestSelectWidth(); + } +} + +module TestLidWidthPrint(){ ////toplevel + rotate([0,180.0]) intersection(){ + Lid(); + TestSelectWidth(); + } +} + +module TestSelectRearAperture(){ + minkowski(){ + union() children(); + translate([20, 0,0]) + cube([42, 2, 1], center=true); + } +} + +module TestSelectCamera(){ + minkowski(){ + TestSelectRearAperture() + RearCameraAperture(); + cube([0.1, 50, 0.1]); + } +} + +module TestSelectOrdinaryRearApertures(){ + TestSelectRearAperture() + OrdinaryRearApertures(); +} + +module TestCamera(){ ////toplevel + intersection(){ + Case(); + TestSelectCamera(); + } +} + +module TestLidByCamera(){ ////toplevel + intersection(){ + Lid(); + TestSelectCamera(); + } +} + +module TestLidByCameraPrint(){ ////toplevel + rotate([180,0,0]) TestLidByCamera(); +} + +module DemoByCamera(){ ////toplevel + color("blue") TestLidByCamera(); + color("red") TestCamera(); +} + +module OneKeeper(){ ////toplevel + translate([0, -phone_cnr_rad, 0]) + rotate([90, 0, 0]) + linear_extrude(height = phone_height - phone_cnr_rad * 2) + KeeperProfile(); +} + +module OneKeeperPrint(){ ////toplevel + rotate([0,180,0]) + OneKeeper(); +} + +module LidPrint(){ ////toplevel + rotate([0,180,0]) + Lid(); +} + +module TestSelectFrame(){ + include = [1,-1] * (epp2i[0] + 4); + + difference(){ + cube(1000, center=true); + translate([0,0, -100]) + linear_extrude(height=200) + rectfromto(include, inside_br - include); + } +} + +module TestSelectLidFrame(){ + TestSelectFrame(); + translate([led_pos[0], -led_pos[1], -50]) + cylinder(r= nla_r2+3, h=100); +} + +module TestFrameCase(){ ////toplevel + intersection(){ + Case(); + union(){ + TestSelectFrame(); + TestSelectCamera(); + TestSelectOrdinaryRearApertures(); + } + } +} + +module TestSelectTopApertures(){ + translate([-100, -35, -100]) + cube([400, 100, 200]); + LidAdhocMultiprintFrame(0); + LidAdhocMultiprintFrame(1); +} + +module TestTopApertures(){ ////toplevel + intersection(){ + Case(); + TestSelectFrame(); + TestSelectTopApertures(); + } +} + +module TestLidTopAperturesPrint(){ ////toplevel + rotate([0,180,0]) intersection(){ + Lid(); + TestSelectLidFrame(); + TestSelectTopApertures(); + } +} + +module TestLidWindowTopAperturesPrint(){ ////toplevel + rotate([0,180,0]) intersection(){ + LidWindow(); + TestSelectTopApertures(); + } +} + +module TestFrameLidPrint(){ ////toplevel + rotate([0,180,0]) intersection(){ + Lid(); + TestSelectLidFrame(); + } +} + +module ButtonPlanForDemo(z, deep, cut){ + translate([0,0,z]) + ButtonPlan(8, deep, cut); +} + +module HingeScrews(){ + Flip_rhs() Flip_bot(1){ + for (c= [ hppT, hppB ]) + translate([ hex20, + -c[0], + c[1] ]){ + rotate([0,90,0]) + translate([0,0,-.2]) + cylinder( r= hingescrew_shaft_dia/2, + h = hingescrew_shaft_len+0.2 ); + rotate([0,-90,0]) + translate([0,0,+.1]) + cylinder( r= hingescrew_head_dia/2, h = hingescrew_head_th ); + } + } +} + +module DemoPropAngleSelect(c){ + color(c) difference(){ + union(){ children(); } + translate([ prop_x_pos, -400, -200 ]) + cube([ 400,800,400 ]); + } +} + +module DemoPropAngle(ang){ + hL = [0, -(phone_height - hppT[0]), hppT[1] - hp_k*2]; + hC = [0, -(phone_height - hppB[0]), hppB[1]]; + + translate(hL) + rotate([ang/2,0,0]) + translate(-hL) + translate(hC) + rotate([ang/2,0,0]) + translate(-hC) { + DemoPropAngleSelect("red") Case(); + + color("orange") + translate([prop_x_pos, -prcp1[0], prcp1[1]]) + PropProfileAssignments(ang) { + echo($prpp1); + rotate([-$prp_theta, 0, 0]) + translate([0, $prpp1[0], -$prpp1[1]]) + rotate([90,0,-90]) + Prop(); + } + } + + translate([0,0, -hp_k*2]) + DemoPropAngleSelect("blue") + Lid(); +} + +module DemoPropAngles(){ ////toplevel + for (i=[0 : len(prop_angles)-1]) + translate(i * [0, -100, 100]) + DemoPropAngle(prop_angles[i]); +} + +module DemoHingeAngle(ang1,ang2){ + hL = [0, -(phone_height - hppT[0]), hppT[1]]; + hC = [0, -(phone_height - hppB[0]), hppB[1]]; + + translate(hL) + rotate([ang2,0,0]) + translate(-hL) + translate(hC) + rotate([ang1,0,0]) + translate(-hC) { + color("red") Lid(); + } + + color("blue") intersection(){ + Case(); + union(){ + translate([bppJ[0], -400, -200]) + mirror([1,0,0]) + cube([400, 800, 400]); + translate([10, -400, -200]) + cube([10, 800, 400]); + } + } +} + +module DemoHingeAngles(){ ////toplevel + angles = [ 0, 4, 8, 12 ]; + echo("angles",angles); + for (i=[0 : len(angles)-1]) { + translate(i * [0, 0, 30]) { + DemoHingeAngle(0,angles[i]); + translate([0, 200, 0]) + DemoHingeAngle(angles[i],0); + } + } +} + +module DemoSelectAdhocLeftRight(right=0) { + translate([phone_width/2, -400, -100]) // , -15, -100 to cross-section + mirror([1-right, 0,0]) + cube([400, 800, 200]); +} + +module DemoLeft(){ ////toplevel + color("red") intersection(){ Case(); DemoSelectAdhocLeftRight(); } + color("blue") intersection(){ Lid(); DemoSelectAdhocLeftRight(); } +} + +module DemoFrame(){ ////toplevel + color("red") TestFrameCase(); + color("blue") intersection(){ Lid(); TestSelectLidFrame(); } + color("black") HingeScrews(); + %HingeLever(); +} + +module DemoLanyardCutout(){ ////toplevel + LanyardCutout(25); +} + +module DemoHingedFrame(){ ///toplevel + color("red") TestFrameCase(); + translate([0,0, -2*hp_k]) + color("blue") intersection(){ Lid(); TestSelectLidFrame(); } + + Flip_hinge(){ + color("orange") HingeLever(); + color("black") HingeScrews(); + } +} + +module DemoHinge(){ ////toplevel + translate([ -0.5*phone_width, phone_height, hp_k*3 ]) { + DemoFrame(); + translate([0,0, -hp_k*3]) + DemoHingedFrame(); + } +} + +module DemoProfiles(){ ////toplevel + LidEdgeProfile(); + %EdgeProfile(); + KeeperProfile(); + translate([0,0,-1]) color("black") KeeperProfile(1); + translate(ly_o){ + rotate(-ly_theta){ + translate([0,0,+1]) color("purple") LanyardMainChannelProfile(); + translate([0,0,+2]) color("red") LanyardCurveChannelProfile(); + translate([0, ly_q_z]){ + translate([0,0,-1]) color("blue") LanyardEntryChannelProfile(); + translate([ly_oec_y,0,-2]) color("black") LanyardEntryOuterProfile(); + } + } + } + translate([0,0,-5]) color("white") translate(epp2i) + rotate(-ly_theta) + rectfromto([-15, 0], + [+15, -max_case_bottom_edge_thickness]); + + translate([0,20]) { + LanyardMainChannelProfile(); + translate([0,0,1]) color("purple") LanyardCurveChannelProfile(); + translate([0,0,-1]) color("red") LanyardEntryChannelProfile(); + } + + translate([20,0]) { + LidEdgeProfile(); + %EdgeProfile(); + + demopoint_QR = [ bppS[0], bppQ[1] - 0.1]; + + color("blue") ButtonCoverProfile(); + color("red") { + rectfromto(bppQ, demopoint_QR); + rectfromto(bppR, demopoint_QR); + } + } + + translate([-20,0]) { + color("black") ButtonPlanForDemo(-2, 0,1); + color("red" ) ButtonPlanForDemo(-4, 1,1); + color("blue") ButtonPlanForDemo(-6, 1,0); + } + + translate([0, -30]) { + %LidEdgeProfile(); + %EdgeProfile(); + color("blue") HingeLidProfile(); + color("red") HingeBaseProfile(); + color("black") translate([0,0,-2]) HingeLeverOuterProfile(); + } + + for (f=[0,1]) { + translate([-30, -60 + 30*f]) { + translate([0,0,-4]) EdgeProfile(); + %translate([0,0,-10]) HingeBaseProfile(); + translate([0,-2] * f * hp_k) { + translate([0,0,-4]) LidEdgeProfile(); + %translate([0,0,-10]) %HingeLidProfile(); + } + translate(+hppB) rotate([0,0,180*f]) translate(-hppB) { + translate([0,0,-2]) color("black") HingeLeverOuterProfile(); + translate([0,0,0]) color("red") difference(){ + HingeLeverOuterProfile(); + HingeLeverInnerProfile(); + } + translate([0,0,3]) color("yellow") HingeLeverNutProfile(); + } + } + } + + translate([20,-30]) { + %EdgeProfile(); + %LidEdgeProfile(); + //translate([0,0,1]) ThumbRecessCutProfile(); + translate([0,0,+1]) color("red") + difference(){ EdgeProfile(); ThumbRecessCutProfile(); } + } + + translate([40,-30]) { + difference(){ + LidEdgeProfile(); + translate(prlp10) + PropProfile(10, 1, 0); + } + translate(prlp10) + PropProfile(15, 0); + } + translate([60,-30]) { + PropAggregateProfile(); + } +} + +//EdgeProfile(); +//KeeperProfile(); +//CaseBase(); +//%Case(); +//Keeper(); +//LidEdgeProfile(); +//KeeperProfile(); +//DemoProfiles(); +//PropRecess(); diff --git a/fairphone4-case-coarse.scad b/fairphone4-case-coarse.scad new file mode 100644 index 0000000..e5ea9a1 --- /dev/null +++ b/fairphone4-case-coarse.scad @@ -0,0 +1,7 @@ +// -*- C -*- + +//// toplevels-from: +include + +$fa = 20; +$fs = 2; diff --git a/fairphone4-case-mounted.scad b/fairphone4-case-mounted.scad new file mode 100644 index 0000000..fecff5a --- /dev/null +++ b/fairphone4-case-mounted.scad @@ -0,0 +1,15 @@ +// -*- C -*- + +include + +module CaseMounted(){ ////toplevel + Case(); + translate([ phone_width/2, + -phone_height/2, epp3[1] - case_th_bottom ]) + Mount(); +} + +//// toplevels-from: +include +$suppress_forward_holes = true; +$suppress_hinge = true; diff --git a/fairphone4-case-tripod.scad b/fairphone4-case-tripod.scad new file mode 100644 index 0000000..b244673 --- /dev/null +++ b/fairphone4-case-tripod.scad @@ -0,0 +1,37 @@ +// -*- C -*- + +include + +tr_cube_offset = 20; +tr_cube_sz = [20, 20, 15]; +tr_around = 10; + +module Mount(){ + translate([0, - tr_cube_sz[1], 0]) + difference(){ + translate([0, tr_cube_sz[1]/2 - tr_cube_offset/2, tr_cube_sz[2]/2]) + cube(tr_cube_sz + [0, tr_cube_offset, 0], center=true); + translate([0, tr_cube_sz[1]/2 - tr_cube_offset, 0]) + rotate([180,0,0]) + render() CameraMountThread(tr_cube_sz[2] + 1); + } +} + +module CaseMounted(){ ////toplevel + difference(){ + render() Case(); + translate([ phone_width/2, -phone_height/2 ]) + linextr(-50, 50) + square([phone_width, phone_height] - tr_around * 2 * [1,1], + center=true); + } + translate([ phone_width, + -phone_height + tr_cube_sz[0] * 0.7, + epp3[1] - case_th_bottom ]) + rotate([0,0,90]) + Mount(); +} + +//// toplevels-from: +include +$suppress_hinge = true; diff --git a/fairphone4-case.scad b/fairphone4-case.scad new file mode 100644 index 0000000..0a4b63d --- /dev/null +++ b/fairphone4-case.scad @@ -0,0 +1,1801 @@ +// -*- C -*- + +// Hard case for Fairphone 2 +// +// Copyright 2018 Ian Jackson. There is NO WARRANTY. +// See below for full licensing and disclaimer. +// +// Instructions +// +// 1. You will want to git clone this repository. +// +// 2. +// +// 3. use "make" to generate the necessary files: +// +// make -j8 fairphone-case.auto.scads `for f in \ +// HingeLeverPrint \ +// LidPrint \ +// OneKeeperPrint \ +// Case \ +// ; do echo fairphone-case,$f.auto.stl; done` +// +// 4. Print them. Case and OneKeeperPrint should probably be +// the same colour. +// +// 5. Assemble the hinge. After placing the parts in the appropirate +// relative placement: +// +// Use long bit of wire to ensure holes are lined up and proper +// Cut four short bits of wire, using above as a guage +// +// Push two short bits into two holes on same side +// Use long bit of wire to ensure properly in holes +// Keep that side up so they don't fall out! +// +// For each of the two holes +// Use 20-30cm hunk of 2.85mm PLA +// Use gas flame to melt end until it catches fire (!) +// Remove from flame, wave to extinguish, and quickly: +// Dab end onto where hole is +// As it congeals, use sidecutters to cut off by hole +// +// Repeat for two holes on other side +// When cool, file down rough edges +// +// 6. In use: +// +// - To put the phone in, drop its RH side into the RH side of +// the case. Then feed the keeper through the small hole. +// Feed it right through. +// +// - The optional prop can be used to prop the phone up (in +// portrait orientation only right now). See +// openscad fairphone-case,DemoPropAngles.auto.scad +// +// Other phones +// +// It might well be possible to adapt this file for other phones. +// If you do, let me know how you get on. +// +// +// AUTHORSHIP, COPYRIGHT, LICENCE, AND LACK OF WARRANTY +// +// Copyright (C) 2018-2022 Ian Jackson. +// +// This program for generating a 3D model 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 +// . +// +// In particular DO NOT BLAME ME IF THIS CASE DOES NOT ADEQUATELY +// PROTECT YOUR PHONE ! It is your responsibility to decide whether +// this case will meet your needs. + +include +include + +phone = [ 75.86, 162.0 ]; + +prop_buildout_less = 3; + +prop_angles = [ 15, 30, 45, 60 ]; + +bumper = [ 0.250, -0.025 ]; +// ^ One side. Overall size is increased by twice this. +// If no bumpers, is the gap around the phone. + +enable_support = 1; + +led_window_style = 0; +// 0: no window +// 1: simply an opening +// 2: opening with separate cover model, for printing in clear (two colour) +// 3: like 2 but one-layer window for ad-hoc multi-colour + +initial_layer_thick = 0.400; // ^ needed for mode 3 only +initial_layer_width = 0.750; // ^ needed for mode 3 only +multicolour_gap = 0.15; // each side + +phone_cnr_rad = 7.0; // actuall 8.mumble, but smaller is fine +phone_rim_depth = 0.01; // includes allowance for a screen protector + +button_cutout_depth = 9; + +phone_edge_thick = 11.25; + +camera_pos_tl = [ 5.600, 5.750 ]; // from tl corner (as seen from back) +camera_edge_rad = 9.750 + 0.700; +camera_sz = 32.920 + .750 + 1.000; + +// this is disabled, FP4 doesn't have one +jack_pos = [ 13.83, 8.485 ]; +jack_dia = 10.64 + .5; // some jack I had lying around + +// this led stuff, is irrelevant, we have disabled it as it doesn't have one +led_pos = []; // [ 13.98, 10.00 ]; +led_aperture = 9; +led_window_ledge = 0.75; // each side + +noisecancelmic_pos = [ 15.08 + .720, 4.35 ]; // from rhs, from top edge +noisecancelmic_dia = 4.00; + +mainmic_pos = [ 21.0, 4.65 ]; // from lhs, from top edge +mainmic_dia = 4.00; + +lhshole_pos = [ phone[1]/2 + 0.40, 4.35 ]; + +fingerpushhole_dias = []; +//fingerpushhole_dias = [ 15, 18 ]; // this is for testing + +lanyard_half_dia = 1.15; +lanyard_entry_rel_breadth = 2; +lanyard_channel_len = 8; +//rearspeaker_pos_bl = [ 12.64, 18.72 ]; +//rearspeaker_size = [ 3.76, 7.36 ]; + +bottomspeaker_size = [ 11.35, 1.90 ] + [1,1] * 0.5; +bottomspeaker_pos = [ 17.55, 5.17 ]; // from rhs, from top + +microusb_above = 1.64 - 0.25; +microusb_below = 2.42; +microusb_width = 12.16 + 2.0 + 1.25; + +case_th_bottom = 2.5; +case_th_lid = 3.0; +case_th_side = 2.6; +case_th_lip = 1.2; + +lid_screen_gap_extra = .66; + +case_struts_count = 6; +case_struts_solid_below = 1.00; +case_struts_solid_above = 0.75; +case_struts_width = 0.10; + +keeper_th_z = 0.75; +keeper_th_x = 0.75; +keeper_inner_width = 2.75; +keeper_inner_height = 2.75; +keeper_slant_slope = 2; // larger means steeper + +keeper_gap_z_top = 0.25; +keeper_gap_z_bot = 0.75; +keeper_gap_x = 0.25; +keeper_gap_x_holes = 0.75; +keeper_fatter = 0.45; +keeper_fatter_hole = 1.20; +keeper_stubbier = 0.0; + +keeper_side = 0; // 0 = lhs; 1 = rhs + +case_lip = 1.25; + +lid_gap_x = 0.25; +lid_gap_z = 0.25; +lid_lip = 1.75; +lid_edgepart_width = 5.0; +lid_buttoncover_thick = 1.3; +lid_buttoncover_reinf = 0.95; + +foldover_gap = 0.50; +foldover_lever_gap = 0.50; + +// properties of the hinge fasteners +hingescrew_shaft_dia = 1.600 + 0.45; // beading wire +hingescrew_shaft_len = 10; +hingescrew_fasteners_extra_thick = 0.40; +// ^ amount of thread protruding if everything was completely nominal +// and we are using two nuts +hingescrew_nut_access_dia = 4.72 + 0.50; +// ^ washer is 4.72 dia +// also, want to get pliers or tiny spanner in to do up locknut +hingescrew_nut_across = 3.92 + 0.25; // incl. slop around recess slop +hingescrew_nut_thick = 1.93; +hingescrew_head_th = 1.38 + 0.75; +hingescrew_head_dia = 3.92; + +hingescrew_nut_recess_portion = 2/3; // portion of nut in recess + +lever_cover_th = 0.75; +hingemount_th = 2.5; +hingemount_wd = 4.8725; + +$fa = 5; +$fs = 0.1; + +button_l_fudge = 4.4; +buttonishleg_default_l_is_fudge = 10; + +hinge_base_slope = 1.5; // bigger is steeper + +strut_min_at_end = 1.5; + +hinge_x_gap = 0.125; +hinge_x_postscrew_gap = 0.75; +hinge_x_arms_gap = 0.35; +hinge_r_arms_gap = 0.55; +hinge_over_nut_plate = -0.50; // bodge apropos slope + +// there isn't one of these, speaker is by hinge +// rearspeaker_gap = [ 2.0, 2.0 ]; // each side + +thumbrecess_depth = 1.3; +thumbrecess_width = 16.5; +thumbrecess_topcurve_r = 5.0; + +prop_recess_under = 0.50; +prop_recess_slop = 0.200; // each side +prop_end_dia = 0.5; +prop_main_th = 3; +prop_taper_len = 6; +prop_main_width = 4; +prop_side_gap = 0.75; // each side +prop_lidrecess_behind = 0.75; +prop_caserecess_behind = 0.75; +prop_caserecess_taper = 0.45; // one side only +prop_prop_gap = 0.5; +prop_prong_heel_slope = 0.5; + +lid_fold_clearance_antislop = 0.5; + +$button_leg_only = false; +$suppress_forward_holes = false; +$suppress_hinge = false; + +// ---------- calculated ---------- + +phone_total_thick = phone_edge_thick; + +phone_width = (phone + bumper*2)[0]; +phone_height = (phone + bumper*2)[1]; + +inside_br = [phone_width, -phone_height]; + +prop_prong_h = prop_main_th; + +//echo(camera_pos_tl + bumper, +// camera_pos_br + bumper); + +// ----- could be changed ----- +lid_buttoncover_gap = lid_gap_x; +lid_buttoncover_overlap = case_th_lip + keeper_gap_z_top; + +//prop_lidrecess_depth = case_th_lid - prop_recess_under; + +//prop_nose_len = case_th_lid - prop_recess_under; +//prop_recess_slope = tan(prop_max_angle); // bigger means steeper +//prop_recess_width = prop_main_th / cos(prop_max_angle) + prop_backfwd_gap; + + +epp0 = [0,0]; +epp1 = [0, -phone_edge_thick]; +epp2i = epp1; // conflated for FP4 +epp2o = epp2i; +epp3 = epp2i + [10, 0]; +epp5 = epp0 + [0,1] * (keeper_th_z + keeper_gap_z_top + case_lip); +epp4 = epp5 + [-1,0] * case_th_side; + +kppe = [0,0]; +kppd = kppe + [1,0] * keeper_inner_width; +kppc = kppd + [0,1] * keeper_th_z; +kppb = [ kppe[0] - keeper_th_x, kppc[1] ]; +kppf = kppe - [0,1] * keeper_inner_height; +kppa = [ kppb[0], kppf[1] ]; + +lpp10 = [ epp5[0] + lid_gap_x, kppc[1] + lid_gap_z ]; +lpp11 = [ lpp10[0], epp5[1] + lid_gap_z ]; + +lpp14 = lpp10 + [1,0] * max(keeper_inner_width, lid_edgepart_width); +// exact x posn not very important; must extend past end of keeper + +lpp15 = [ lpp14[0], + epp0[1] - phone_rim_depth + 1/2.5 * case_th_lid + + lid_screen_gap_extra ]; +// ^ beam theory says to maximise force before contact, +// the gap below the `beam' (the lid) must be 1/3 +// the thickness (ie the lid thickness) if the beam +// is solid, or 1/2 if it has a top and bottom only. +// ours is mostly solid. + +lp_r12 = max(case_th_lid - (lpp11[1] - lpp15[1]), + case_th_lip); + +lpp12 = [ epp4[0] + lp_r12, lpp11[1] ]; +lpp13 = [ lpp12[0], lpp12[1] + lp_r12 ]; + +case_bottom_z = epp2o[1] - case_th_bottom; + +// button profile +bppM = epp4 + [0,5]; +bppN = [ bppM[0] + lid_buttoncover_thick, bppM[1] ]; +bppR = [ bppN[0] + lid_buttoncover_gap, -button_cutout_depth ]; +bppS = [ epp1[0], bppR[1] ]; +bppQ = [ bppM[0], bppR[1] - lid_buttoncover_overlap ]; +bppP = bppQ + [0,1] * lid_buttoncover_gap; +bppO = [ bppN[0], bppP[1] ]; +bppL = lpp10 + [5,0]; +bppK = [ bppL[0], bppN[1] ]; +bppJ = [ bppN[0], bppL[1] ]; +bppU = [ bppJ[0], lpp12[1] ]; +bppV = lpp11; +bppW = lpp10; + +echo("BUTTON COVER TH", bppO[0] - bppP[0]); + +// notification led aperture + +nla_r0 = led_aperture/2; +nla_r1 = nla_r0 + led_window_ledge; +nla_r2 = nla_r1 + multicolour_gap; +nla_t = + led_window_style >= 3 ? initial_layer_thick : + led_window_style >= 2 ? led_window_ledge : 0; + + +// hinge plan +hp_rn = hingescrew_nut_access_dia/2; +hp_r2_min = hp_rn + lever_cover_th; +hp_rs = hingescrew_shaft_dia/2; +hp_r1_min = hp_rs + hingemount_th; + +hp_r1 = max(hp_r1_min, hp_r2_min); +hp_r2 = hp_r1; + +hppU = lpp13; +hppS = epp2o + [0,-1] * case_th_bottom; +hp_k = 0.5 * (hppU[1] - hppS[1] + foldover_gap); + +hppM = [ epp4[0] - foldover_lever_gap - hp_r2, + 0.5 * (hppU + hppS)[1] ]; +hppT = [ hppM[0], hppU[1] - hp_r1 ]; +hppB = hppT + [0,-1] * hp_k; + +hppE_y = epp2o[1] - case_th_bottom + hp_r1; +hppE_x = hppB[0] + (hppB[1] - hppE_y) * hinge_base_slope; +hppE = [ hppE_x, hppE_y ]; + +// hinge elevation x coords + +hex20 = max(epp2o[0], + phone_cnr_rad, + kppd[0] + hingescrew_head_th + keeper_gap_x_holes); +hex21 = hex20 + hingemount_wd; +hex22 = hex21 + hinge_x_gap; +hex27 = hex20 + hingescrew_shaft_len; +hex24 = hex27 + hinge_x_postscrew_gap; +hex23 = hex27 - (hingescrew_nut_thick*2 + + hingescrew_fasteners_extra_thick); +hex26 = hex23 + hingescrew_nut_thick * 2/3; + +//echo(hex20, hex21, hex22, hex23, hex24); +//// 6, 10.8725, 10.9975, 13.74, 18.75 +//module chk(act,exp) { +// if (abs(act-exp) > 1e-9) echo("WRONG", act, exp); +// else echo("ok", act); +//} +//chk(hex20, 6); +//chk(hex21, 10.8725); +//chk(hex22, 10.9975); +//chk(hex23, 13.74); +//chk(hex24, 18.75); + +lid_fold_clearance_skew = + (lpp10[1] - hppB[1]) / + (lpp10[0] - hppB[0]); + +echo("SK",lid_fold_clearance_skew); + +// thumb recess (used to be "catch" hence cpp* + +cppA = epp4 + [thumbrecess_depth, 0]; +cppB = [ cppA[0], epp1[1] ]; + +// lanyard + +ly_r = lanyard_half_dia / 2; +ly_rc = ly_r * 2; + +ly_theta = 90; +ly_o = epp2i + 3 * ly_r * [0,1]; + +max_case_bottom_edge_thickness = + case_th_bottom; + +ly_q_z = -(ly_rc + ly_r); +ly_re = max_case_bottom_edge_thickness - (-ly_q_z); + +ly_oec_y = lanyard_entry_rel_breadth * ly_r; + +// prop recess in case + +prop_x_pos = phone_width/2; + +prop_recess_hw = 0.5 * prop_main_width + prop_side_gap; + +prc_r1 = prop_end_dia/2; +prc_r3 = prc_r1 + prop_recess_slop; + +prcp2 = [ epp4[0] + prop_buildout_less, + case_bottom_z ]; + +prop_caserecess_buildout_r = -1; // prcp2[0] - epp2o[0]; + +prcp1 = [ epp2o[0] + prc_r3 + prop_caserecess_behind, + epp2i[1] - prc_r3 - prop_recess_under]; + +// prop recess in lid + +prl_r10 = prop_end_dia/2; +prl_r10o = prl_r10 + prop_recess_slop; + +prlp10 = lpp10 + [1,1] * prl_r10o + + [1,0] * prop_lidrecess_behind + + [0,1] * prop_recess_under; + +// prop + +$prpp10 = [0,0]; +$prpp11 = [0, prop_taper_len]; + +$prp_r10 = prl_r10; + +// ---------- modules ---------- + +module AdhocMultiprintFrame(phase, z0, zs) { + // from z0 to z0 + zs*layer + extra = phase * (initial_layer_width + multicolour_gap) + 5; + xextra = extra + -epp4[0]; + xrange = [ 0, phone_width ] + [-1,+1] * xextra; + yextra = extra + -epp4[0]; + yrange = [ -phone_height + +hppB[0] - hp_r2, 0 ] + [-1,+1] * yextra; + p0 = [ xrange[0], yrange[0] ]; + p1 = [ xrange[1], yrange[1] ]; + echo(p0, p1); + translate([0,0, z0]) + mirror([0,0, zs<0 ? 1 : 0]) + linear_extrude(height= initial_layer_thick) + difference(){ + rectfromto(p0 - [1,1] * initial_layer_width, + p1 + [1,1] * initial_layer_width); + rectfromto(p0, p1); + } +} + +module KeeperProfile(fatter=0, slant=0, stubbier=0){ + use_e = kppe + [0,-1] * slant * keeper_inner_width / keeper_slant_slope; + polygon([use_e + [+1,-1] * fatter, + kppd + [ 0,-1] * fatter - stubbier * [1,0], + kppc - stubbier * [1,0], + kppb, + kppa + stubbier * [0,1], + kppf + [+1, 0] * fatter + stubbier * [0,1] + ]); +} + +module EdgeProfile(){ + difference(){ + hull(){ + translate(epp3) square(case_th_bottom*2, center=true); + circleat(epp2o, r=case_th_bottom); + circleat(epp1, r=case_th_side); + rectfromto(epp0, epp4); + } + polygon([ epp5 + [0,10], + epp1, + epp3 + [10,0] ]); + } +} + +module LanyardLanyardProfile(entry=false){ + hull(){ + for (xs=[-1,+1] * (entry ? lanyard_entry_rel_breadth : 1)) + translate(xs * 0.5 * lanyard_half_dia * [1,0]) + circle(r= lanyard_half_dia/2); + } +} + +module LanyardCurveChannelProfile(){ + translate([0, -ly_r]) + LanyardLanyardProfile(); +} + +module LanyardEntryChannelProfile(){ + LanyardLanyardProfile(true); +} + +module LanyardMainChannelProfile(){ + LanyardCurveChannelProfile(); + difference(){ + square(center=true, ly_r * [6, 2]); + for (xs=[-1,+1]) + translate(ly_r * [3 * xs, -1]) + circle(r = ly_r); + } +} + +module LanyardEntryOuterProfile(){ + circleat([ly_re + ly_r, 0], ly_re); +} + +module LanyardEntry(){ + q_z = ly_q_z; + oec_y = ly_oec_y; + + d_x = -ly_rc; + + translate([d_x, 0, q_z]) { + intersection(){ + rotate([90,0,0]) + rotate_extrude(convexity=10) + rotate(90) + translate([0, -q_z]) + LanyardCurveChannelProfile(); + translate([0,-10,0]) + cube([20,20,20]); + } + } + + mirror([0,0,1]) + translate([0,0,-1]) + linear_extrude(height=20) + rotate(-90) + LanyardEntryChannelProfile(); + + translate([0, ly_r*2, 0]) + rotate([90,0,0]) + linear_extrude(height = ly_r*4){ + difference(){ + rectfromto([d_x, q_z], [ly_r, 0]); + circleat([d_x, q_z], ly_rc); + } + } + + translate([0,0,q_z]){ + for (my=[0,1]) + mirror([0,my,0]){ + translate([0, oec_y, 0]){ + difference(){ + translate(ly_re * [-1,0,-2]) + cube(ly_re * [2,1,2]); + rotate_extrude(convexity=10) + LanyardEntryOuterProfile(); + } + } + } + difference(){ + translate([-ly_re, -(oec_y + 0.01), -2*ly_re]) + cube([ly_re*2, 2*(oec_y + 0.01), 2*ly_re]); + for (mx=[0,1]) + mirror([mx,0,0]) + rotate([90,0,0]) + translate([0,0,-10]) + linear_extrude(height=20) + LanyardEntryOuterProfile(); + } + } +} + +module LanyardCutout(l){ + rotate([0,-90,0]) + linear_extrude(height=l) + rotate(-90) + LanyardMainChannelProfile(); + + for (ee=[0,1]){ + translate(ee * l * [-1,0]) + mirror([ee,0,0]) + LanyardEntry(); + } +} + +module LidEdgeProfile(){ + polygon([ lpp10, + lpp11, + lpp12, + lpp13, + lpp13 + [10, 0], + lpp15 + [10, 0], + lpp15, + lpp14, + ]); + intersection(){ + circleat(lpp12, r=lp_r12); + rectfromto( lpp12 + [-10, 0], + lpp12 + [+10, +10] ); + } +} + +module LidEdgeFoldClearanceProfile(){ + translate([-lid_fold_clearance_antislop, 0]) + polygon([ lpp10, + lpp11, + lpp11 + [-20, 0], + lpp11 + [-20, 20], + lpp11 + [+20, 20], + lpp10 + [+20, 0] ]); +} + +module ButtonCoverProfile(){ + intersection(){ + polygon(concat([ bppM, bppP, bppO, bppJ ], + (enable_support && !$button_suppress_over_keeper + ? [ bppU, bppV, bppW ] : []), + [ bppL, bppK ])); + hull(){ + EdgeProfile(); + LidEdgeProfile(); + } + } +} + +module ButtonPlan(l, deep, cut){ + epsilon = + (cut ? 0 : lid_buttoncover_gap); + + delta = + (deep ? lid_buttoncover_overlap : 0); + + C = [0,0]; // by definition + T = [ 0, epp4[1] ]; + G = T + [0,10]; + + B0 = C + [0,-1] * button_cutout_depth; + B1 = B0 + [0,1] * epsilon; + + r0 = 0.5 * (T[1] - B0[1]); + A = [ -(l + button_l_fudge)/2 + r0, 0.5 * (T[1] + B0[1]) ]; + H = A + [0,-1] * delta; + + D = A + [-2,0] * r0; + F = D + [0,10]; + + E0 = 0.5 * (D + A); + E1 = E0 + [1,0] * epsilon; + + I0 = [ E0[0], H[1] ]; + I1 = [ E1[0], H[1] ]; + + hull(){ + for (m=[0,1]) mirror([m,0]) + circleat(H, r0 - epsilon); + } + for (m=[0,1]) mirror([m,0]) { + difference(){ + polygon([ E1, + I1, + H, + B1, + G, + F, + D + ]); + circleat(D, r0 + epsilon); + } + } +} + +module ButtonCoverReinf(){ ////toplevel + minkowski(){ + rotate([90,0,0]) + linear_extrude(height=0.01) + intersection(){ + ButtonCoverProfile(); + translate([bppJ[0] + 0.1, -50]) mirror([1,0]) + square([100,100]); + } + mirror([0,0,1]) linear_extrude(height=0.01) intersection(){ + circle(r= lid_buttoncover_reinf); + translate([-20,0]) square(40, center=true); + } + } +} + +module ThumbRecessCutProfile(){ + difference(){ + polygon([ cppA + [-10,0], + cppB + [-10,0], + cppB, + cppA ]); + circleat(epp1, r=case_th_side); + } +} + +module Flip_rhs(yn=[0,1]) { + for ($rhsflip=yn) { + translate([phone_width/2, 0, 0]) + mirror([$rhsflip,0,0]) + translate([-phone_width/2, 0, 0]) + children(); + } +} + +module Flip_bot(yn=[0,1]) { + for ($botflip=yn) { + translate([0, -phone_height/2, 0]) + mirror([0, $botflip, 0]) + translate([0, phone_height/2, 0]) + children(); + } +} + +module AroundEdges(fill_zstart, fill_th, fill_downwards=0){ + // sides + Flip_rhs(){ + translate([0, -phone_cnr_rad, 0]) + rotate([90,0,0]) + linear_extrude(height = phone_height - phone_cnr_rad*2) + children(0); + } + // corners + Flip_rhs() Flip_bot() { + translate([+1,-1] * phone_cnr_rad) + intersection(){ + rotate_extrude() + intersection(){ + mirror([1,0,0]) + translate([-1,0] * phone_cnr_rad) + children(0); + rectfromto([0,-20],[10,20]); + } + translate([-10, 0, -20] + 0.01 * [+1,-1, 0] ) + cube([10,10,40]); + } + } + // top and bottom + Flip_bot(){ + translate([ phone_width - phone_cnr_rad, 0,0 ]) + rotate([90,0,-90]) + linear_extrude(height = phone_width - phone_cnr_rad*2) + children(0); + } + // fill + translate([0,0, fill_zstart]) + mirror([0,0, fill_downwards]) + linear_extrude(height = fill_th) + rectfromto([+1,-1] * phone_cnr_rad, + [phone_width, -phone_height] + [-1,+1] * phone_cnr_rad); +} + +module CaseAperture(pos, dia, $fn, topbottom=0) { + theta = 180/$fn; + translate([ bumper[0], + -epp2i[0], + 0 ]) + rotate([0,0, 90*topbottom]) + translate([ pos[0] * (topbottom>0 ? -1 : +1), 0, -pos[1] ]) + rotate([-90, theta, 0]) + cylinder(r = dia/2 / cos(theta), + h = 60); +} + +module SideButton(y, y_ref_sign, l, suppress_over_keeper=0){ + // y_ref_sign: + // +1 measured from top of actual phone to top of button + // -1 measured from bottom of actual phone to bottom of button + // 0 y is centre of button in coordinate system + $button_l= l; + $button_suppress_over_keeper= suppress_over_keeper; + eff_y = y_ref_sign > 0 ? -bumper [1] -y -l/2 : + y_ref_sign < 0 ? (-phone -bumper)[1] +y +l/2 : + y; + //echo(eff_y); + translate([0, eff_y, 0]) + children(); +} + +module LidButtonishLeg(y, y_ref_sign, l=buttonishleg_default_l_is_fudge) { + $button_leg_only = true; + SideButton(y, y_ref_sign, l) children(); +} + +module Buttons(){ + Flip_rhs(1) SideButton(30.320, +1, 22.960 ) children(); // volume + Flip_rhs(1) SideButton(64.220, +1, 14.500 ) children(); // power + Flip_rhs(1) LidButtonishLeg(14, -1) children(); + Flip_rhs(0) LidButtonishLeg(21, -1) children(); + Flip_rhs(0) LidButtonishLeg(38, +1) children(); + Flip_rhs(0) LidButtonishLeg(14, +1) children(); +} + +module Struts(x_start, z_min, th){ + // if th is negative, starts at z_min and works towards -ve z + // and object should then be printed other way up + for (i= [1 : 1 : case_struts_count]) { + translate([0, + 0, + z_min]) + mirror([0,0, th<0 ? 1 : 0]) + translate([0, + -phone_height * i / (case_struts_count+1), + case_struts_solid_below]) + linear_extrude(height= abs(th) + -(case_struts_solid_below+case_struts_solid_above)) + rectfromto([ x_start, -0.5 * case_struts_width ], + [ phone_width - x_start, +0.5 * case_struts_width ]); + } +} + +module OrdinaryRearAperture(rhs,bot, pos){ + Flip_rhs(rhs) Flip_bot(bot) + linextr(-20, 20) + mirror([0,1]) + translate(pos + bumper) + children(); +} + +module MicroUSBEtc(){ + Flip_bot(1){ + rotate([90,0,0]) + mirror([0,0,1]) + linextr(-epp2i[0], 60) + translate([0.5 * phone_width, 0, 0]) + rectfromto([-microusb_width/2, epp2i[1] + microusb_below], + [+microusb_width/2, epp0[1] + -microusb_above]); + } +} + +module OrdinaryBottomEdgeApertures(){ + Flip_bot(1) + CaseAperture(mainmic_pos, mainmic_dia, 8); + + Flip_bot(1) Flip_rhs(1) { + linextr_y_xz(-epp2i[0], 60) + hull() + for (x= [-1,+1]) { + translate([ -bottomspeaker_pos[0], -bottomspeaker_pos[1] ] + + [ 0.5 * x * bottomspeaker_size[0] - bottomspeaker_size[1], + 0 ]) + rotate(360/16) + circle(r = bottomspeaker_size[1], $fn = 8); + } + } +} + +module OrdinaryRearApertures(){ + // rear speaker + // OrdinaryRearAperture(1,1, rearspeaker_pos_bl) + // rectfromto(-rearspeaker_gap, + // rearspeaker_size + rearspeaker_gap); +} + +module NotInTestFrameRearApertures(){ + // finger hole to remove phone + if (len(fingerpushhole_dias)) + OrdinaryRearAperture(0,0, [ fingerpushhole_dias[0] + epp2i[0], + phone[1]/2 ]) + scale(fingerpushhole_dias) + circle(r= 0.5 ); +} + +module RearCameraAperture(){ + Flip_rhs(1) + mirror([0, 0, 1]) + translate([0,0,0]) + hull() // there is some kind of bug if hull() is done in 2D here! + linear_extrude(height = 20) + mirror([0, 1, 0]) + translate(bumper) + translate(camera_pos_tl) + for (xy = [ [0,0], [0,1], [1,0] ]) { + translate( + camera_edge_rad * [1,1] + + xy * (camera_sz - camera_edge_rad * 2) + ) + circle(r = camera_edge_rad); + } +} + +module HingeLidProfile(){ + hull(){ + circleat(hppT, hp_r1); + circleat(lpp12, lp_r12); + polygon([lpp10, + lpp13 + [2,0], + lpp12, + hppT]); + } +} + +module HingeBaseProfile(){ + difference(){ + hull(){ + circleat(hppB, hp_r1); + circleat(hppE, hp_r1); + circleat(epp2o, case_th_bottom); + circleat(hppB + [10,0], hp_r1); + } + polygon([epp5, epp1, epp3, bppL]); + } +} + +module HingeLeverOuterProfile(){ + hull(){ + circleat(hppT, hp_r2); + circleat(hppB, hp_r2); + } +} + +module HingeLeverInnerProfile(){ + for (s = [-1,+1]) { + c = s > 0 ? hppT : hppB; + translate(c) + mirror([0,0, s>0 ? 1 : 0]) + rotate(s<0 ? -40 : 0) + hull() + for (x=[-20,20]) + for (y=[0, s * 10]) + translate([x,y]) + circle(hp_rn); + } +} + +module HingeLeverNutProfile(){ + for (c= [hppB, hppT]) { + translate(c) + circle($fn=6, r= 0.5 * hingescrew_nut_across / cos(30)); + } +} + +module Flip_hinge(doflip=1){ + hinge_origin = [0, -(phone_height - hppB[0]), hppB[1]]; + translate(hinge_origin) + rotate([doflip*180,0,0]) + translate(-hinge_origin) + children(); +} + +module HingePortion(x0,x1){ + Flip_rhs() Flip_bot(1) + translate([x0,0,0]) + mirror([1,0,0]) + rotate([90,0,-90]) + linear_extrude(height=x1-x0) + children(); +} + +module ThumbRecessApply(ztop){ + width = thumbrecess_width; + w = width + thumbrecess_topcurve_r*2 + 1; + translate([phone_width/2, 0,0]){ + difference(){ + rotate([90,0,-90]) + linextr(-w/2, w/2) + children(0); + translate([0, 50, 0]) + rotate([90,0,0]) + linear_extrude(height=100){ + for (m=[0,1]) mirror([m,0,0]) { + hull(){ + translate([w/2, ztop - thumbrecess_topcurve_r]) + circle(thumbrecess_topcurve_r); + translate([w/2, -50]) + square(thumbrecess_topcurve_r*2, center=true); + } + } + } + } + } +} + +module CaseBase(){ + AroundEdges(epp3[1], case_th_bottom, 1) + EdgeProfile(); +} + +function prop_x(gamma) = hp_k / (2 * sin(gamma/2)) - hppT[0]; + +module PropProfileAssignments(gamma){ + // https://en.wikipedia.org/wiki/Solution_of_triangles#Two_sides_and_the_included_angle_given_(SAS) + x = prop_x(gamma); + p = phone_height + prlp10[0] - hppB[0]; + b = p + x; + + q = phone_height - hppT[0] - prcp1[0]; // $prpp7[0] is 0 by definition + a = q + x; + c = sqrt(a*a + b*b - 2*a*b*cos(gamma)); + $prp_alpha = acos( (b*b + c*c - a*a) / (2*b*c) ); + + $prp_theta = 90 - $prp_alpha; + beta = 180 - $prp_alpha - gamma; + psi = 90 - beta; + + //echo("abc", a,b,c); + + v1 = [ [ cos(psi), -sin(psi) ], // x + [ sin(psi), cos(psi) ] ]; // y + + $prpp7 = [0, c + (lpp13[1] - $prpp10[1] - hp_k) ]; + + $prp_r1 = prc_r1; + $prp_r11 = prop_main_th/2; + + $prpp1 = $prpp7 + [1,0] * + // this is approximate, but will do + (prop_main_th/2 + prop_prop_gap + prcp1[0] - cppA[0]); + $prpp3 = $prpp1 + + v1[0] * -$prp_r1 + + v1[1] * ((prcp2[1] - prcp1[1]) - prop_prop_gap); + $prpp12 = $prpp3 + v1[0] * + (prop_end_dia + prop_caserecess_taper * ($prpp1[1] - $prpp3[1])); + $prp_r8 = prop_main_th; + $prpp4 = [ prop_main_th/2, $prpp3[1] ]; + $prp_r5 = $prp_r8; + $prpp5 = [ $prpp12[0] - $prp_r5, + $prpp3[1] - prop_prong_h + $prp_r5 ]; + $prpp6 = $prpp4 + [0,-1] * (prop_prong_h + + prop_prong_heel_slope * ($prpp5[0] - $prpp4[0])); + $prpp8 = $prpp4 + [0,-1] * $prp_r8; + $prpp9 = $prpp8 + [-1,0] * $prp_r8; + + children(); +} + +module PropProfile(gamma, cut=0, rot=0){ + PropProfileAssignments(gamma){ + + //#circleat($prpp3,1); + //#circleat($prpp12,1); + + if (!cut) { + hull(){ + translate($prpp8) + intersection(){ + circle($prp_r8); + polygon([[-20,-0], [20,20], [0,0]]); + } + rectfromto($prpp6, $prpp9); + translate($prpp5) intersection(){ + circle($prp_r5); + polygon([[-10,-10], [0,0], [10,0]]); + } + rectfromto($prpp12 + [0,-0.1], $prpp3); + } + hull(){ + circleat($prpp1, $prp_r1); + rectfromto($prpp12 + [0,-0.1], $prpp3); + } + } + // main shaft + rotate([0,0, rot*-$prp_theta]){ + hull(){ + extra = cut ? prop_recess_slop : 0; + rectfromto($prpp6, $prpp9); + circleat($prpp11, $prp_r11 + extra); + circleat($prpp10, $prp_r10 + extra); + } + } + } +} + +module PropAggregateProfile(){ + for (angle = prop_angles) + PropProfile(angle, 0,0); +} + +module Prop(){ ////toplevel + hw = prop_main_width/2; + linextr(-hw, +hw) + PropAggregateProfile(); +} + +module Case(){ ////toplevel + difference(){ + union(){ + CaseBase(); + + // ledge (fixed keeper) + Flip_rhs(1-keeper_side) intersection(){ + rotate([90, 0, 0]) + linear_extrude(height = phone_height + phone_cnr_rad * 2) + KeeperProfile(fatter=0, slant=1); + + // outline of the whole case, to stop it protruding + translate([0,0, -25]) + linear_extrude(height = 50) + hull() + Flip_bot() + circleat([+1,-1] * phone_cnr_rad, phone_cnr_rad + case_th_side/2); + } + + // hinge + if (!$suppress_hinge) + HingePortion(hex20, hex21) HingeBaseProfile(); + + // buildout for prop recess + if (prop_caserecess_buildout_r > 0) Flip_rhs(1) + linextr(case_bottom_z, epp2i[1]) + hull() { + for (dxs = [-1,+1]) + circleat([ prop_x_pos + dxs * prop_caserecess_buildout_r, + -epp2o[0] ], + r = epp2o[0] - prcp2[0]); + } + } + + // slot for keeper + Flip_rhs(keeper_side) + translate([0, -phone_cnr_rad, 0]) + rotate([90, 0, 0]) + linear_extrude(height = phone_height + phone_cnr_rad * 2) + minkowski(){ + KeeperProfile(fatter=keeper_fatter_hole); + rectfromto([ -keeper_gap_x, -keeper_gap_z_bot ], + [ keeper_gap_x_holes, +keeper_gap_z_top ]); + } + + // front camera + RearCameraAperture(); + + // struts (invisible, because they're buried in the case) + Struts(epp2i[0], epp2i[1] - case_th_bottom, case_th_bottom); + + Buttons(){ + mirror([1,0,0]) + rotate([90,0,90]) { + if (!($button_leg_only && enable_support)) + intersection(){ + translate([0,0,-10]) + linear_extrude(height= 20) + ButtonPlan($button_l, 0,1); + if ($button_leg_only) + rotate([-90,90,0]) + translate([phone_width/2, -400, kppe[1]]) + mirror([1-abs($rhsflip - keeper_side),0,0]) + cube([400, 800, 50]); + if (enable_support && !$button_suppress_over_keeper) + rotate([-90,90,0]) + translate([-400, -400, kppd[1]]) + mirror([0,0,1]) + cube([800,800,100]); + } + translate([0,0, -bppR[0]]) + linear_extrude(height= 20) + ButtonPlan($button_l, 1,1); + } + + } + + // apertures along top edge + if (!$suppress_forward_holes) { + // CaseAperture(jack_pos, jack_dia, 8); + Flip_rhs(1) + CaseAperture(noisecancelmic_pos, noisecancelmic_dia, 8); + } + CaseAperture(lhshole_pos, noisecancelmic_dia, 8, 1); + + OrdinaryBottomEdgeApertures(); + + OrdinaryRearApertures(); + NotInTestFrameRearApertures(); + + MicroUSBEtc(); + + // gaps for the lid's hinge arms + if (!$suppress_hinge) { + HingePortion(hex20 - hinge_x_arms_gap, + hex21 + hinge_x_arms_gap) + minkowski(){ + HingeLidProfile(); + circle(r= hinge_r_arms_gap, $fn= 8); + } + + // screw holes in the hinge arms + HingeScrews(); + } + + // thumb recess + ThumbRecessApply(epp4[1]) + ThumbRecessCutProfile(); + + // lanyard + Flip_bot(1) + translate([ly_o[0], -(phone_cnr_rad + ly_re), ly_o[1]]) + rotate([0, ly_theta, 0]) + rotate([0,0,90]) + LanyardCutout(lanyard_channel_len); + + // prop recess + Flip_rhs(1) + translate([prop_x_pos,0,0]) + mirror([0,1,0]) + rotate([90,0,90]) + linextr(-prop_recess_hw, +prop_recess_hw) + hull(){ + for (d=[ [0,0], [0,-1], [+1,-1/prop_caserecess_taper] ]) + circleat(prcp1 + 20*d, + prc_r3); + } + } +} + +module LidAdhocMultiprintFrame(phase){ + if (led_window_style >= 3) { + AdhocMultiprintFrame(phase, lpp13[1], -1); + } +} + +module LidAroundEdges(){ + AroundEdges(lpp15[1], lpp13[1] - lpp15[1], 0) + children(); +} + +module Lid(){ ////toplevel + skew_centre = [0, lpp11[0], lpp11[1]]; + difference(){ + union(){ + intersection(){ + LidAroundEdges() + LidEdgeProfile(); + + translate(skew_centre) + multmatrix([[ 1, 0, 0, 0 ], + [ 0, 1, -lid_fold_clearance_skew, 0 ], + [ 0, 0, 1, 0 ], + [ 0, 0, 0, 1 ]]) + translate(-skew_centre) + LidAroundEdges() + LidEdgeFoldClearanceProfile(); + } + + // button covers + Buttons(){ + intersection(){ + rotate([90,0,90]) + translate([0,0,-10]) + linear_extrude(height= 20) + ButtonPlan($button_l, 1,0); + union(){ + rotate([90,0,0]) + translate([0,0,-100]) + linear_extrude(height= 200) + ButtonCoverProfile(); + hull() + for (y= [-1,+1] * (($button_l + button_l_fudge)/2 + - lid_buttoncover_reinf)) + translate([0,y,0]) + ButtonCoverReinf(); + } + } + } + + // hinge arms + HingePortion(hex20, hex21) { + LidEdgeProfile(); + HingeLidProfile(); + } + } + Struts(lpp10[0] + strut_min_at_end, lpp13[1], -case_th_lid); + + // screw holes in the hinge arms + HingeScrews(); + + // prop recess + translate([prop_x_pos, -prlp10[0], prlp10[1]]) + mirror([0,1,0]) + rotate([90,0,90]) + linextr(-prop_recess_hw, +prop_recess_hw) + hull() + for (pa = prop_angles) + PropProfile(pa, 1,1); + + // notification led aperture + if (led_window_style) + translate([led_pos[0], -led_pos[1], lpp13[1]]) { + translate([0,0,-10]) + cylinder(r=nla_r0, h=20); + if (led_window_style >= 2) + translate([0,0, -nla_t]) + cylinder(r=nla_r2, height=20); + } + + } + + LidAdhocMultiprintFrame(1); +} + +module HingeLever(){ ////toplevel + difference() { + // outer body, positive + HingePortion(hex22, hex22 + phone_width/2) + HingeLeverOuterProfile(); + + // space for the screws +// HingePortion(hex26, hex24) +// HingeLeverInnerProfile(); + + // recesses for the nuts +// HingePortion(hex23, hex26+1) +// HingeLeverNutProfile(); + + // bores for the screws + HingeScrews(); + + // space for the charging cable and speaker and micc apertures + hull() { + for (x = [-1,+1]) { + multmatrix([[ 1,0, + + x + * ( (hex24 + hinge_over_nut_plate) - + (phone_width/2 - microusb_width/2) + ) + / ( (epp0[1] - microusb_above) + - + (hppB[1] - hp_r2) ), + + x * (epp0[1] - microusb_above) + + ], + [ 0,1,0, 0 ], + [ 0,0,1, 0 ]]) { + union(){ + MicroUSBEtc(); + Flip_hinge() MicroUSBEtc(); + } + } + } + } + } +} + +module LidWindow(){ ////toplevel + translate([led_pos[0], -led_pos[1], lpp13[1]]) + mirror([0,0,1]) + cylinder(r= nla_r1, h=nla_t); + LidAdhocMultiprintFrame(0); +} + +module LidWindowPrint(){ ////toplevel + rotate([0,180,0]) + LidWindow(); +} + +module DemoLidWindowSelect(){ + translate([led_pos[0], led_pos[1], -100]) { + translate([0, -30, 0]) cube([400, 400, 200]); + } +} + +module DemoLidWindow(){ ////toplevel + %Lid(); + LidWindow(); + translate([0,40,0]){ + color("blue") intersection(){ Lid(); DemoLidWindowSelect(); } + color("red") intersection(){ LidWindow(); DemoLidWindowSelect(); } + } +} + +module HingeLeverPrint(){ ////toplevel + rotate([-90,0,0]) + translate([-phone_width/2, phone_height, 0]) + HingeLever(); +} + +module TestSelectLength(){ + translate([-30, -200, -20]) + cube([30 + 15, 250, 40]); +} + +module TestLength(){ ////toplevel + intersection(){ + Case(); + TestSelectLength(); + } +} + +module TestLengthRight(){ ////toplevel + intersection(){ + Case(); + Flip_rhs(1) + TestSelectLength(); + } +} + +module TestSelectWidth(){ + translate([-30, -(phone_height - 25), -20]) + mirror([0, 1, 0]) + cube([200, 50, 40]); +} + +module TestWidth(){ ////toplevel + intersection(){ + Case(); + TestSelectWidth(); + } +} + +module TestLidWidthPrint(){ ////toplevel + rotate([0,180.0]) intersection(){ + Lid(); + TestSelectWidth(); + } +} + +module TestSelectRearAperture(){ + minkowski(){ + union() children(); + translate([20, 0,0]) + cube([42, 2, 1], center=true); + } +} + +module TestSelectCamera(){ + minkowski(){ + TestSelectRearAperture() + RearCameraAperture(); + cube([0.1, 50, 0.1]); + } +} + +module TestSelectOrdinaryRearApertures(){ + TestSelectRearAperture() + OrdinaryRearApertures(); +} + +module TestCamera(){ ////toplevel + intersection(){ + Case(); + TestSelectCamera(); + } +} + +module TestLidByCamera(){ ////toplevel + intersection(){ + Lid(); + TestSelectCamera(); + } +} + +module TestLidByCameraPrint(){ ////toplevel + rotate([180,0,0]) TestLidByCamera(); +} + +module DemoByCamera(){ ////toplevel + color("blue") TestLidByCamera(); + color("red") TestCamera(); +} + +module OneKeeper(){ ////toplevel + translate([0, -phone_cnr_rad, 0]) + rotate([90, 0, 0]) + linear_extrude(height = phone_height - phone_cnr_rad * 2) + KeeperProfile(fatter=keeper_fatter, stubbier=keeper_stubbier); +} + +module OneKeeperPrint(){ ////toplevel + rotate([0,180,0]) + OneKeeper(); +} + +module LidPrint(){ ////toplevel + rotate([0,180,0]) + Lid(); +} + +module TestSelectFrame(){ + include = [1,-1] * (epp2i[0] + 4); + + difference(){ + cube(1000, center=true); + translate([0,0, -100]) + linear_extrude(height=200) + rectfromto(include, inside_br - include); + } + + for (i= [1,2]) { + translate([ 0, -phone[1] * i/3, 0 ]) + cube(center=true, [1000, 4, 100]); + } +} + +module TestSelectLidFrame(){ + TestSelectFrame(); + if (len(led_pos)) + translate([led_pos[0], -led_pos[1], -50]) + cylinder(r= nla_r2+3, h=100); +} + +module TestFrameCase(){ ////toplevel + intersection(){ + Case(); + union(){ + TestSelectFrame(); + TestSelectCamera(); + TestSelectOrdinaryRearApertures(); + } + } +} + +module TestSelectTopApertures(){ + translate([-100, -35, -100]) + cube([400, 100, 200]); + LidAdhocMultiprintFrame(0); + LidAdhocMultiprintFrame(1); +} + +module TestTopApertures(){ ////toplevel + intersection(){ + Case(); + TestSelectFrame(); + TestSelectTopApertures(); + } +} + +module TestLidTopAperturesPrint(){ ////toplevel + rotate([0,180,0]) intersection(){ + Lid(); + TestSelectLidFrame(); + TestSelectTopApertures(); + } +} + +module TestLidWindowTopAperturesPrint(){ ////toplevel + rotate([0,180,0]) intersection(){ + LidWindow(); + TestSelectTopApertures(); + } +} + +module TestFrameLidPrint(){ ////toplevel + rotate([0,180,0]) intersection(){ + Lid(); + TestSelectLidFrame(); + } +} + +module ButtonPlanForDemo(z, deep, cut){ + translate([0,0,z]) + ButtonPlan(8, deep, cut); +} + +module HingeScrews(){ + Flip_rhs() Flip_bot(1){ + for (c= [ hppT, hppB ]) + translate([ hex20, + -c[0], + c[1] ]){ + rotate([0,90,0]) + translate([0,0,-.2]) + cylinder( r= hingescrew_shaft_dia/2, + h = hingescrew_shaft_len+0.2 ); + rotate([0,-90,0]) + translate([0,0,+.1]) + cylinder( r= hingescrew_head_dia/2, h = hingescrew_head_th ); + } + } +} + +module DemoPropAngleSelect(c){ + color(c) difference(){ + union(){ children(); } + translate([ prop_x_pos, -400, -200 ]) + cube([ 400,800,400 ]); + } +} + +module DemoPropAngle(ang){ + hL = [0, -(phone_height - hppT[0]), hppT[1] - hp_k*2]; + hC = [0, -(phone_height - hppB[0]), hppB[1]]; + + translate(hL) + rotate([ang/2,0,0]) + translate(-hL) + translate(hC) + rotate([ang/2,0,0]) + translate(-hC) { + DemoPropAngleSelect("red") Case(); + + color("orange") + translate([prop_x_pos, -prcp1[0], prcp1[1]]) + PropProfileAssignments(ang) { + echo($prpp1); + rotate([-$prp_theta, 0, 0]) + translate([0, $prpp1[0], -$prpp1[1]]) + rotate([90,0,-90]) + Prop(); + } + } + + translate([0,0, -hp_k*2]) + DemoPropAngleSelect("blue") + Lid(); +} + +module DemoPropAngles(){ ////toplevel + for (i=[0 : len(prop_angles)-1]) + translate(i * [0, -100, 100]) + DemoPropAngle(prop_angles[i]); +} + +module DemoHingeAngle(ang1,ang2){ + hL = [0, -(phone_height - hppT[0]), hppT[1]]; + hC = [0, -(phone_height - hppB[0]), hppB[1]]; + + translate(hL) + rotate([ang2,0,0]) + translate(-hL) + translate(hC) + rotate([ang1,0,0]) + translate(-hC) { + color("red") Lid(); + } + + color("blue") intersection(){ + Case(); + union(){ + translate([bppJ[0], -400, -200]) + mirror([1,0,0]) + cube([400, 800, 400]); + translate([10, -400, -200]) + cube([10, 800, 400]); + } + } +} + +module DemoHingeAngles(){ ////toplevel + angles = [ 0, 4, 8, 12 ]; + echo("angles",angles); + for (i=[0 : len(angles)-1]) { + translate(i * [0, 0, 30]) { + DemoHingeAngle(0,angles[i]); + translate([0, 200, 0]) + DemoHingeAngle(angles[i],0); + } + } +} + +module DemoSelectAdhocLeftRight(right=0) { + translate([phone_width/2, -400, -100]) // , -15, -100 to cross-section + mirror([1-right, 0,0]) + cube([400, 800, 200]); +} + +module DemoLeft(){ ////toplevel + color("red") intersection(){ Case(); DemoSelectAdhocLeftRight(); } + color("blue") intersection(){ Lid(); DemoSelectAdhocLeftRight(); } +} + +module DemoFrame(){ ////toplevel + color("red") render() TestFrameCase(); + color("blue") render() intersection(){ Lid(); TestSelectLidFrame(); } + color("black") render() HingeScrews(); + %render() HingeLever(); +} + +module DemoLanyardCutout(){ ////toplevel + LanyardCutout(25); +} + +module DemoHingedFrame(){ ///toplevel + color("red") render() TestFrameCase(); + translate([0,0, -2*hp_k]) + color("blue") render() intersection(){ Lid(); TestSelectLidFrame(); } + + Flip_hinge(){ + color("orange") render() HingeLever(); + color("black") render() HingeScrews(); + } +} + +module DemoHinge(){ ////toplevel + translate([ -0.5*phone_width, phone_height, hp_k*3 ]) { + DemoFrame(); + translate([0,0, -hp_k*3]) + DemoHingedFrame(); + } +} + +module DemoProfiles(){ ////toplevel + LidEdgeProfile(); + %EdgeProfile(); + KeeperProfile(); + translate([0,0,-1]) color("black") KeeperProfile(1); + translate(ly_o){ + rotate(-ly_theta){ + translate([0,0,+1]) color("purple") LanyardMainChannelProfile(); + translate([0,0,+2]) color("red") LanyardCurveChannelProfile(); + translate([0, ly_q_z]){ + translate([0,0,-1]) color("blue") LanyardEntryChannelProfile(); + translate([ly_oec_y,0,-2]) color("black") LanyardEntryOuterProfile(); + } + } + } + translate([0,0,-5]) color("white") translate(epp2i) + rotate(-ly_theta) + rectfromto([-15, 0], + [+15, -max_case_bottom_edge_thickness]); + + translate([0,20]) { + LanyardMainChannelProfile(); + translate([0,0,1]) color("purple") LanyardCurveChannelProfile(); + translate([0,0,-1]) color("red") LanyardEntryChannelProfile(); + } + + translate([20,0]) { + LidEdgeProfile(); + %EdgeProfile(); + + demopoint_QR = [ bppS[0], bppQ[1] - 0.1]; + + color("blue") ButtonCoverProfile(); + color("red") { + rectfromto(bppQ, demopoint_QR); + rectfromto(bppR, demopoint_QR); + } + } + + translate([-20,0]) { + color("black") ButtonPlanForDemo(-2, 0,1); + color("red" ) ButtonPlanForDemo(-4, 1,1); + color("blue") ButtonPlanForDemo(-6, 1,0); + } + + translate([0, -30]) { + %LidEdgeProfile(); + %EdgeProfile(); + color("blue") HingeLidProfile(); + color("red") HingeBaseProfile(); + color("black") translate([0,0,-2]) HingeLeverOuterProfile(); + } + + for (f=[0,1]) { + translate([-30, -60 + 30*f]) { + translate([0,0,-4]) EdgeProfile(); + %translate([0,0,-10]) HingeBaseProfile(); + translate([0,-2] * f * hp_k) { + translate([0,0,-4]) LidEdgeProfile(); + %translate([0,0,-10]) %HingeLidProfile(); + } + translate(+hppB) rotate([0,0,180*f]) translate(-hppB) { + translate([0,0,-2]) color("black") HingeLeverOuterProfile(); + translate([0,0,0]) color("red") difference(){ + HingeLeverOuterProfile(); + HingeLeverInnerProfile(); + } + translate([0,0,3]) color("yellow") HingeLeverNutProfile(); + } + } + } + + translate([20,-30]) { + %EdgeProfile(); + %LidEdgeProfile(); + //translate([0,0,1]) ThumbRecessCutProfile(); + translate([0,0,+1]) color("red") + difference(){ EdgeProfile(); ThumbRecessCutProfile(); } + } + + translate([40,-30]) { + difference(){ + LidEdgeProfile(); + translate(prlp10) + PropProfile(10, 1, 0); + } + translate(prlp10) + PropProfile(15, 0); + } + translate([60,-30]) { + PropAggregateProfile(); + } +} + +//EdgeProfile(); +//KeeperProfile(); +//CaseBase(); +//%Case(); +//Keeper(); +//LidEdgeProfile(); +//KeeperProfile(); +//DemoProfiles(); +//PropRecess(); diff --git a/filament-test.scad b/filament-test.scad new file mode 100644 index 0000000..443aab5 --- /dev/null +++ b/filament-test.scad @@ -0,0 +1,16 @@ +// -*- C -*- +translate([3,3,0]) mirror([1,1,0]) cube([15,15,1]); + +multmatrix([[ 1, 0, 0, 0 ], + [ 0, 1, 1.0, 0 ], + [ 0, 0, 1, 0 ], + [ 0, 0, 0, 1 ]]) + cylinder(r=6.1/2, h=8); + +w=0.5; + +translate([15,0]) +difference(){ + cube([8,8,8]); + translate([w,w,-1]) cube([8-w*2, 8-w*2, 8+2]); +} diff --git a/filamentclip.scad b/filamentclip.scad new file mode 100644 index 0000000..e6d7afb --- /dev/null +++ b/filamentclip.scad @@ -0,0 +1,53 @@ +include +include + +rad=19; +h=3.5; +w=2.5; + +looprad=2.5; +loopw=w; + +fdia=1.77; +//fdia=3; + +d=0.01; + +module our_ClipHook(ye){ + ClipHook(h=h, w=w, g=0.6, k=1.5, g=0.6, ye=ye, cupcaph=0.5, cupcapg=0.8); +} + +module FilamentClip() { + rotate([0,0,-70]) { + translate([0,rad-1.5,0]) { + rotate([0,0,8]) + our_ClipHook(ye=-1.3); + } + } + + rotate([0,0,-35]) { + translate([0,rad,0]) { + rotate([0,0,180]) + our_ClipHook(ye=0.8); + } + } + + linear_extrude(height=h) { + assign($fn=80) { + FlatArc(0,0, rad-w/2,rad+w/2, 80,350); + } + assign($fn=30) { + FlatArc(0,rad+looprad+w, looprad,looprad+loopw); + } + } + + for (mir=[0,1]) { + mirror([mir,0,0]) + rotate([0,0,-40]) + translate([rad+w*0.3+teethw*0.3+fdia/2, 0, 0]) + rotate([0,0,95]) + FilamentTeeth(fdia=fdia, h=h); + } +} + +FilamentClip(); diff --git a/filamentspool-lt.scad b/filamentspool-lt.scad new file mode 100644 index 0000000..3605f00 --- /dev/null +++ b/filamentspool-lt.scad @@ -0,0 +1,4 @@ +//// toplevels-from: +include +lightduty = true; +fdia = 2.85; diff --git a/filamentspool-number.eps.pl b/filamentspool-number.eps.pl new file mode 100755 index 0000000..c05903a --- /dev/null +++ b/filamentspool-number.eps.pl @@ -0,0 +1,14 @@ +#!/usr/bin/perl -w +use strict; +die unless @ARGV==1 && $ARGV[0] =~ m/^\d+/; +my $num = $ARGV[0]; +$num /= 1000; +printf < +lightduty = true; +fdia = 1.75; diff --git a/filamentspool-storarm3.scad b/filamentspool-storarm3.scad new file mode 100644 index 0000000..31dbaa9 --- /dev/null +++ b/filamentspool-storarm3.scad @@ -0,0 +1,7 @@ +// -*- C -*- +include +lightduty = false; +fdia = 2.85; +storarm_spools=3; +//// module StorageArmLeft ////toplevel +//// module StorageArmRight ////toplevel diff --git a/filamentspool.scad b/filamentspool.scad new file mode 100644 index 0000000..b2991ea --- /dev/null +++ b/filamentspool.scad @@ -0,0 +1,1025 @@ +// -*- C -*- + +// filamentspool.scad +// 3D design for filament spools to hold coils as supplied by Faberdashery +// + +// +// Copyright 2012,2013,2016 Ian Jackson +// +// This work 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 work 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 work. If not, see +// + +// +// Each spool is a hub with 3 or 4 arms. Each arm has a cup for +// holding the filament. The effective diameter can be adjusted by +// setting the cup into a different seat in the arm. The cups are +// held on with simple clips, so the filement coil can easily be +// removed and replaced. +// +// This file (and its includes) can generate: +// +// ===== Heavy duty 4-armed spool for 3mm x 100m coil ===== +// +// A heavy duty 4-armed spool suitable for holding a 100m +// Faberdashery coil on the spool arm of a Lulzbot TAZ-5. +// +// Set +// fdia=2.85 +// lightduty=false +// And print following parts +// Hub +// ArmEnd x 4 +// FilamentCup x 4 (or FilamentCupPair x 2) +// CupSecuringClip x 4 +// +// You will also need 4 x M4 machine screws and nuts. +// +// This is the default. +// +// ===== Light duty 3-armed spool for 3mm x <=30m coil ===== +// +// A light duty 3-armed spool suitable for up to around 30m +// of Faberdashery 2.85mm PLA. +// +// Set +// fdia=2.85 +// lightduty=true +// (or look in filamentspool-lt.scad). +// +// And print following parts +// Hub +// ArmEnd x 3 +// FilamentCup x 3 (or FilamentCup + FilamentCupPair) +// CupSecuringClip x 3 +// TowerDoveClipPin x 6 +// +// When assembling, insert one TowerDoveClipPin from each side, +// joining each ArmEnd to the Hub with two TowerDoveClipPins. +// Modest force with pliers is good to seat them properly. +// +// (note that the light duty and heavy duty CupSecuringClips +// are slightly different) +// +// ===== Notes regarding both the above spools ===== +// +// When mounting either spool on the TAZ-5 spool arm, put the `pointy' +// end of the hub towards the printer - ie, put put the spool on +// `backwards'. This ensures that the spool's arms will clear the +// printer framework. +// +// For the above, I generally used the Cura `Standard' PLA profile. +// +// ===== TAZ-5 feed tube adjustment kit ===== +// +// With a TAZ-5 I recommend using this kit to improve the feed +// reliability: +// +// Set +// fdia=2.85 +// And print following parts +// FilamentGuideSpacer (ideally, at `high detail') +// FilamentGuideArmPrint (optional; `high detail' or `standard') +// +// And possibly also +// t-nut_jig_0.2.stl +// from Aleph Objects - look here: +// http://download.lulzbot.com/TAZ/accessories/tool_heads/version_2/Dual_Extruder_v2/production_parts/stl/ +// +// The spacer clips onto the filament guide tube holder arm, on the +// inside, with the pointy flanged end towards the filament guide +// tube. It stops the filament guide tube angle (and so the +// filament's natural pickup location) changing as the print head moves. +// +// The FilamentGuideArm[Print] is a replacement for the arm supplied +// with your TAZ-5. It's longer, so that the filament pickup point is +// closer to the middle of the coil. Use the t-nut_jig to stop the +// T-nuts in the aluminium channel from annoyingly sliding down to the +// bottom while you swap out the arm. +// +// (Faberdashery coils, and therefore both the above spools, have a +// larger diameter than the flat-walled spools often supplied by other +// vendors. And the spools above have individual arms rather than a +// continuous disc. If the filament `unhooks' from the arm, it can +// pull taught around the hub and stop feeding properly.) +// +// ===== Spool storage arm, for mounting on walls ===== +// +// A storage arm suitable for screwing to walls, bookshelves, +// etc. (requires non-countersunk M4 screws); will hold two heavy duty +// spools each with a 100m coil. +// +// Set +// fdia=2.85 +// lightduty=false +// And print one of these, according to taste +// StorageArmLeft +// StorageArmRight +// +// NB that the `light duty' version of this is shorter and +// will only take two `light duty' spools. +// +// A longer arm for three spools is also available: +// Set +// fdia=2.85 +// lightduty=false +// storarm_spools=3 +// (or look in filamentspool-storarm3.scad). +// +// And print one of these, according to taste +// StorageArmLeft +// StorageArmRight +// +// For all of these, I used the Cura `High detail' PLA profile because +// I wanted it pretty, but the `Standard' profile should do fine. +// +// ===== Spools for 1.75mm filament ===== +// +// Spool (in many parts) for handing 1.75mm filament, printable +// on, and with parts for mounting on, a Reprappro Huxley. + + +fdia=2.85; // or 1.75 +lightduty=false; // or true + + +slop=0.5; +bigslop=slop*2; + +function selsz(sm,lt,lg) = fdia < 2 ? sm : lightduty ? lt : lg; +function usedove() = selsz(true,true,false); + +num_arms = selsz(3,3,4); + +channelslop=selsz(slop,0.75,slop); + +exteffrad = 70; +hubeffrad = selsz(30, 52, 40); +hubbigrad = selsz(20, 38, 38); +hublwidth = selsz(3, 2.5, 3.0); +hubstemwidth = 2; +hublthick = 10; +hubaxlerad = selsz(5, 28/2, 28/2); +totalheightfromtower = 240; +axletowerfudgebend = 0; +axleaxlefudgebend = 3; +axlepadlen = 1.0; + +armend_length = selsz(120, 150, 120); + +prongthick=selsz(5,4,5); +prongwidth=selsz(5,4,5); +prongribwidth=3; +prongribheight=selsz(0,0,4); +ratchetstep=10; +ratchettooth=3; +ratchettoothheight=5; +ratchettoothsmoothr=1; +ratchettoothslope=0.75; +overlap=0.5; +cupwidth=selsz(40,25,50); +cupheight=selsz(75,35,75); + +cupstrong_dx=selsz(0,0,-10); + +propxshift = -6; + +doveclipheight = 10; + +teethh=3; +teethgapx=4+fdia; + +prongstalkxwidth=3; + +stalklength=selsz(35,25,55); +overclipcupgap=5; +overclipdepth=15; +overcliproundr=2.0; +overclipthick=1.0; +overclipcupnextgap=selsz(20,15,20); + +hubaxlelen = selsz(25, 62.5, 77.5); +echo(hubaxlelen); + +overclipsmaller=0.5; +overclipbigger=2.5; + +wingspoke=2.5; +wingsize=6; +wingthick=3; + +armendwallthick=selsz(2.5, 1.8, 2.5); +armendbasethick=selsz(1.2, 1.2, 1.2); + +numbers_relief = 0.7; +numbers_tick_len = 8; +numbers_tick_width = 0.75; +numbers_tick_linespc = 1.0; +numbers_height_allow = 8; + +axlehorizoffset = 12.5; +axlevertheight = 100; +towercliph = 16; +towerclipcount = 3; +towerpillarw = 5; + +axlepinrad = 2; +axlepintabrad = 5; + +washerthick = 1.2; +washerthinthick = 0.8; +washerverythinthick = 0.4; +washerrad = hubaxlerad + 7.5; +frictionwasherarmwidth = 3; +frictionwasherextrapush = 1.0; + +ratchetpawl=ratchetstep-ratchettooth-bigslop*2; + +nondove_armhole_x = 32; +nondove_armhole_hole = 4 + 0.8; +nondove_armhole_support = 7; +nondove_armhole_wall = 3.2; +nondove_armhole_slop = 0.5; +nondove_armhole_slop_x = 0.5; + +nondove_armbase = nondove_armhole_x + nondove_armhole_hole/2 + + nondove_armhole_support; +echo(nondove_armbase); + +include +include +include +include +include + +hub_clip_baseextend = (hubeffrad - DoveClip_depth() + - hubbigrad + hublwidth); + +real_exteffrad = selsz(exteffrad + hub_clip_baseextend, + hubeffrad + DoveClip_depth(), + hubeffrad + nondove_armbase); + +channelwidth = prongthick + channelslop; +channeldepth = prongwidth + ratchettoothheight; +totalwidth = armendwallthick*2 + channelwidth; +totalheight = channeldepth + armendbasethick; +stalkwidth = prongwidth + prongstalkxwidth; + +tau = PI*2; + +module ArmEnd(length=armend_length){ ////toplevel + if (usedove()) { + translate([ratchettoothsmoothr, channelwidth/2, -armendbasethick]) { + rotate([0,0,-90]) + DoveClipPairBase(h=doveclipheight); + } + } else { + difference(){ + translate([1, -armendwallthick, -armendbasethick]) + mirror([1,0,0]) + cube([nondove_armbase+1, totalwidth, totalheight]); + translate([-nondove_armbase + nondove_armhole_x, + -armendwallthick + totalwidth/2, + -armendbasethick -1]) + cylinder(r= nondove_armhole_hole/2, h=totalheight+2, $fn=10); + translate([-nondove_armbase, -armendwallthick, -armendbasethick]) + rotate([90,0,0]) + Commitid_BestCount([nondove_armbase, totalwidth]); + } + } + + difference(){ + union(){ + difference(){ + translate([0, -armendwallthick, -armendbasethick]) + cube([length, totalwidth, totalheight]); + translate([-1, 0, 0]) + cube([length+1 - ratchettooth, channelwidth, channeldepth+1]); + translate([-1, 0, ratchettoothheight]) + cube([length+2, channelwidth, channeldepth+1]); + } + for (dx = [0 : ratchetstep : length - ratchetstep]) translate([dx,0,0]) { + translate([ratchettoothsmoothr+0.5, armendwallthick/2, 0]) minkowski(){ + rotate([90,0,0]) + cylinder($fn=20, r=ratchettoothsmoothr, h=armendwallthick); + multmatrix([ [ 1, 0, ratchettoothslope, 0 ], + [ 0, 1, 0, 0 ], + [ 0, 0, 1, 0 ], + [ 0, 0, 0, 1 ]]) + cube([ratchettooth - ratchettoothsmoothr*2, + channelwidth, ratchettoothheight - ratchettoothsmoothr]); + } + } + } + + for (otherside=[0,1]) { + for (circum = [300:100:1500]) { + assign(rad = circum / tau) + assign(fn = str("filamentspool-number-n",circum,".dxf")) + assign(rotateoffset = [0, totalwidth/2, 0]) + assign(xlen = rad - real_exteffrad) { + if (xlen >= numbers_tick_width/2 + + (otherside ? numbers_height_allow : 0) && + xlen <= length - (otherside ? 0 : numbers_height_allow)) + translate([xlen, -armendwallthick, + -armendbasethick + (totalheight - numbers_tick_len)/2]) + translate(rotateoffset) + rotate([0,0, otherside*180]) + translate(-rotateoffset){ + translate([-numbers_tick_width/2, -1, 0]) + cube([numbers_tick_width, numbers_relief+1, numbers_tick_len]); + translate([numbers_tick_width/2 + numbers_tick_linespc, + 1, + numbers_tick_len]) + rotate([90,0,0]) + rotate([0,0,-90]) + linear_extrude(height= numbers_relief+1) + // scale(templatescale) + import(file=fn, convexity=100); + } + } + } + } + + if (usedove()){ + translate([0, -armendwallthick, -armendbasethick]) + Commitid_BestCount_M([length/3, totalwidth]); + } + } +} + +module FilamentCupHandle(){ + pawlusewidth = ratchetpawl-ratchettoothsmoothr*2; + mirror([0,1,0]) { + cube([stalklength, stalkwidth, prongthick]); + translate([stalklength, stalkwidth/2, 0]) + cylinder(r=stalkwidth/2, h=prongthick, $fn=20); + translate([ratchettoothsmoothr, stalkwidth, 0]) { + minkowski(){ + cylinder($fn=20,r=ratchettoothsmoothr, h=1); + multmatrix([ [ 1, -ratchettoothslope, 0, 0 ], + [ 0, 1, 0, 0 ], + [ 0, 0, 1, 0 ], + [ 0, 0, 0, 1 ]]) + cube([pawlusewidth, + ratchettoothheight - ratchettoothsmoothr, + prongthick - 1]); + } + } + } +} + +module FilamentCupCup(){ + for (my=[0,1]) mirror([0,my,0]) { + translate([0, cupwidth/2, 0]) + cube([cupheight + prongwidth, prongwidth, prongthick]); + } +} + +module FilamentCupPositive() { + FilamentCupHandle(); + + gapy = prongwidth; + dy = cupwidth/2 + gapy + overclipcupgap; + baselen = dy+cupwidth/2; + + translate([0, dy, 0]) + FilamentCupCup(); + cube([prongwidth, baselen+1, prongthick]); + + translate([cupstrong_dx, prongwidth, 0]) { + cube([prongwidth, baselen-prongwidth, prongthick]); + for (y = [0, .33, .67, 1]) + translate([0, (baselen - prongwidth) * y, 0]) + cube([-cupstrong_dx + 1, prongwidth, prongthick]); + } + if (cupstrong_dx != 0) { + rotate([0,0,45]) + translate([-prongwidth*.55, -prongwidth*2.1, 0]) + cube([prongwidth*(2.65), prongwidth*4.2, prongthick]); + } + + translate([0, -0.2, 0]) + cube([prongribwidth, baselen, prongthick + prongribheight]); + + if (prongribheight > 0) { + translate([-prongwidth, baselen, 0]) + cube([cupheight/2, prongwidth + prongribheight, prongribwidth]); + } + + midrad = cupwidth/2 + prongwidth/2; + + propshift = stalklength - overclipdepth - prongthick + propxshift; + proptaken = propshift; + echo(midrad, propshift, proptaken); + + translate([propshift, -1, 0]) { + // something is wrong with the y calculation + cube([prongwidth, + gapy+2, + prongthick]); + } + for (y = [overclipcupgap, overclipcupgap+overclipcupnextgap]) { + translate([cupstrong_dx, y + prongwidth, 0]) + rotate([0,0, 102 + fdia]) + FilamentTeeth(fdia=fdia, h=teethh); + } + for (x = [-0.3, -1.3]) { + translate([cupheight + overclipcupnextgap*x, baselen + prongwidth, 0]) + rotate([0,0, 12 + fdia]) + FilamentTeeth(fdia=fdia, h=teethh); + } +} + +module FilamentCup() { ////toplevel + difference(){ + FilamentCupPositive(); + translate([0, -stalkwidth, 0]) + Commitid_BestCount_M([stalklength - stalkwidth, stalkwidth]); + } +} + +module CupSecuringClipSolid(w,d,h1,h2){ + rotate([0,-90,0]) translate([0,-h1/2,-w/2]) linear_extrude(height=w) { + polygon(points=[[0,0], [d,0], [d,h2], [0,h1]]); + } +} + +module CupSecuringClipSolidSmooth(xrad=0, xdepth=0){ + hbase = totalheight + prongstalkxwidth - overcliproundr*2; + minkowski(){ + CupSecuringClipSolid(w=totalwidth, + d=overclipdepth + xdepth, + h1=hbase + overclipbigger, + h2=hbase - overclipsmaller); + cylinder($fn=20, h=0.01, r=overcliproundr+xrad); + } +} + +module CupSecuringClip(){ ////toplevel + wingswidth = wingspoke*2 + overclipthick*2 + overcliproundr*2 + totalwidth; + difference(){ + union(){ + CupSecuringClipSolidSmooth(xrad=overclipthick, xdepth=0); + translate([-wingswidth/2, -wingsize/2, 0]) + cube([wingswidth, wingsize, wingthick]); + translate([-wingsize/2, -wingswidth/2, 0]) + cube([wingsize, wingswidth, wingthick]); + } + translate([0,0,-0.1]) + CupSecuringClipSolidSmooth(xrad=0, xdepth=0.2); + } +} + +module ArmDoveClipPin(){ ////toplevel + DoveClipPin(h=doveclipheight); +} + +module TowerDoveClipPin(){ ////toplevel + DoveClipPin(h=towercliph/2); +} + +module Hub(){ ////toplevel + axlerad = hubaxlerad + slop; + xmin = axlerad+hublwidth/2; + xmax = hubbigrad-hublwidth/2; + hole = hubeffrad - hubbigrad - DoveClip_depth() - hublwidth*2; + holewidth = DoveClipPairSane_width() - hubstemwidth*2; + nondove_allwidth = nondove_armhole_wall*2 + totalwidth; + difference(){ + union(){ + difference(){ + cylinder($fn=60, h=hublthick, r=hubbigrad); + translate([0,0,-1]) + cylinder($fn=30, h=hublthick+2, r=(hubbigrad-hublwidth)); + } + cylinder(h=hubaxlelen, r=axlerad+hublwidth); + for (ang=[0 : 360/num_arms : 359]) + rotate([0,0,ang]) { + if (usedove()){ + difference() { + translate([hubeffrad,0,0]) + DoveClipPairSane(h=doveclipheight, + baseextend = hub_clip_baseextend); + if (hole>hublwidth && holewidth > 2) { + translate([hubbigrad + hublwidth, -holewidth/2, -1]) + cube([hole, holewidth, hublthick+2]); + } + } + } else { + difference(){ + translate([0, + -nondove_allwidth/2, + 0]) + cube([hubeffrad + nondove_armhole_x + + nondove_armhole_hole/2 + nondove_armhole_support, + nondove_allwidth, + nondove_armhole_wall + totalheight]); + translate([hubeffrad - nondove_armhole_slop_x, + -nondove_allwidth/2 + + nondove_armhole_wall - nondove_armhole_slop, + nondove_armhole_wall]) + cube([nondove_armhole_x + 50, + totalwidth + nondove_armhole_slop*2, + totalheight + 1]); + translate([hubeffrad + nondove_armhole_x, 0, -20]) + cylinder(r= nondove_armhole_hole/2, h=50, $fn=10); + } + } + } + for (ang = [0 : 180/num_arms : 359]) + rotate([0,0,ang]) rotate([90,0,0]) { + translate([0,0,-hublwidth/2]) + linear_extrude(height=hublwidth) + polygon([[xmin,0.05], [xmax,0.05], + [xmax,hublthick-0.2], [xmin, hubaxlelen-0.2]]); + } + } + translate([0,0,-1]) cylinder($fn=60, h=hubaxlelen+2, r=axlerad); + + rotate([0,0, selsz(0,0,45)]) + translate([axlerad+hublwidth, + -hublwidth/2, + 0]) + rotate([90,0,0]) + Commitid_BestCount([(hubbigrad-hublwidth) - (axlerad+hublwidth), + hublthick + + hublwidth/2 * hubaxlelen/(hubbigrad-axlerad), + ]); + } +} + +module ArmExtender(){ ////toplevel + DoveClipExtender(length=exteffrad-hubeffrad, + ha=doveclipheight, + hb=doveclipheight); +} + +module FsAxlePin(){ ////toplevel + AxlePin(hubaxlerad, washerrad*2, axlepinrad, axlepintabrad, slop); +} + +module Axle(){ ////toplevel + pillarswidth = DoveClipPairSane_width(towerclipcount); + + rotate([0,0, -( axleaxlefudgebend + atan(slop/hubaxlelen) ) ]) + translate([-axlehorizoffset, -axlevertheight, 0]) { + rotate([0,0,-axletowerfudgebend]) + rotate([0,0,-90]) + DoveClipPairSane(h=towercliph, count=towerclipcount, baseextend=3); + translate([0, DoveClip_depth(), 0]) + rotate([0,0,90]) + ExtenderPillars(axlevertheight - DoveClip_depth(), + pillarswidth, towercliph, + pillarw=towerpillarw); + } + + axleclearlen = hubaxlelen + slop*4 + washerthick*2 + axlepadlen; + axlerad = hubaxlerad-slop; + bump = axlerad * 0.2; + shift = axlerad-bump; + joinbelowallow = 3; + + intersection(){ + translate([0, 0, shift]) { + difference() { + union(){ + translate([-1, 0, 0]) + rotate([0,90,0]) + cylinder($fn=60, + r = axlerad, + h = 1 + axleclearlen + axlepinrad*2 + 2); + mirror([1,0,0]) rotate([0,90,0]) + cylinder(r = axlerad*1.75, h = 3); + intersection(){ + mirror([1,0,0]) + translate([axlehorizoffset - pillarswidth/2, 0, 0]) + rotate([0,90,0]) + cylinder($fn=60, + r = towercliph - shift, + h = pillarswidth); + translate([-50, -joinbelowallow, -50]) + cube([100, joinbelowallow+50, 100]); + } + } + rotate([90,0,0]) + translate([axleclearlen + axlepinrad/2, 0, -25]) + cylinder(r = axlepinrad + slop, h=50); + } + } + translate([-50,-50,0]) cube([100,100,100]); + } +} + +module washer(thick){ + Washer(hubaxlerad, washerrad, thick, slop); +} + +module AxleWasher(){ ////toplevel + washer(thick=washerthick); +} + +module AxleThinWasher(){ ////toplevel + washer(thick=washerthinthick); +} + +module AxleVeryThinWasher(){ ////toplevel + washer(thick=washerverythinthick); +} + +module AxleFrictionWasher(){ ////toplevel + difference(){ + cylinder(h=washerthick, r=washerrad); + translate([0,0,-1]) cylinder(h=washerthick+2, r=hubaxlerad+slop); + } + frarmr = hubbigrad; + frarmw = frictionwasherarmwidth; + frarmpawlr = hublwidth; + frarmpawlpush = slop*4 + frictionwasherextrapush; + for (ang=[0,180]) rotate([0,0,ang]) { + translate([washerrad-1, -frarmw/2, 0]) + cube([frarmr - washerrad + 1, frarmw, washerthick]); + intersection(){ + translate([frarmr - frarmpawlr, -50, 0]) + cube([frarmpawlr, 100, 50]); + rotate([0,90,0]) + cylinder(h = 50, r = frarmpawlpush, $fn=36); + } + } +} + +module TowerExtender(){ ////toplevel + l = totalheightfromtower - axlevertheight; + echo("TowerExtender",l); + DoveClipExtender(length = l, + ha = towercliph, hb = towercliph, + counta = towerclipcount, countb = towerclipcount, + pillarw = towerpillarw); +} + +module FilamentCupPair(){ ////toplevel + FilamentCup(); + translate([cupheight + prongthick*3, + cupwidth/2*1.7, + 0]) + rotate([0,0,180]) FilamentCup(); +} + +//----- storarm ----- + +storarm_hooklen = 8; +storarm_hookheight = 5; +storarm_thick = 10; +storarm_axleslop = 4; + +storarm_base_w = 30; +storarm_base_h = 100; +storarm_base_d = 15; +storarm_base_mind = 2; + +storarm_cope_hubaxle_mk1 = true; + +storarm_screw_hole = 4; +storarm_screw_hole_slop = 0.5; +storarm_besides_hole = 4; + +storarm_under_hole = 5; +storarm_screw_hole_head = 8.8; +storarm_screw_hole_head_slop = 1.5; + +// calculated + +storarm_spools = 2; + +storarm_axlerad = hubaxlerad - storarm_axleslop; +storarm_mainlen = hubaxlelen*storarm_spools + + storarm_axleslop*(storarm_spools-1) + + (storarm_cope_hubaxle_mk1 ? 10 : 0); +storarm_totlen = storarm_mainlen + storarm_hooklen; + +storarm_taller = storarm_axleslop * (storarm_spools-2); + +storarm_mid_off_y = storarm_axlerad; + +storarm_base_off_y = storarm_mid_off_y + storarm_base_h/2; + +module StorageArmDiagPartSide(xmin, xmax){ + xsz = xmax-xmin; + yuse = storarm_thick/2; + + intersection(){ + translate([xmin-1, -storarm_axlerad, storarm_thick/2]) + rotate([0,90,0]) + cylinder(r=storarm_axlerad, h=xsz+2, $fn=60); + translate([xmin, -yuse, 0]) + cube([xsz, yuse, storarm_thick]); + } +} + +module StorageArmDiagPart(xmin, xmax, adjbot, shear){ + hull(){ + StorageArmDiagPartSide(xmin,xmax); + + multmatrix([[1,0,0,0], + [shear,1,0,0], + [0,0,1,0], + [0,0,0,1]]) + translate([0, -storarm_axlerad*2 + adjbot, 0]) + mirror([0,1,0]) + StorageArmDiagPartSide(xmin,xmax); + } +} + +module StorageArmBaseTemplate(){ + square([storarm_base_w, storarm_base_h]); +} + +module StorageArmAtMountingHoles(){ + bes = storarm_besides_hole + storarm_screw_hole; + + x0 = bes; + x1 = storarm_base_w-bes; + y1 = storarm_base_h - bes; + y0 = bes; + + for (pos=[ [x0, y1], + [x1, y1], + [x1, y0] ]) { + rotate([0,90,0]) + translate([pos[0] - storarm_base_w, + pos[1] - storarm_base_off_y, -storarm_base_d]) + children(); + } +} + +module StorageArmRight(){ ////toplevel + shear = storarm_hookheight / (storarm_mainlen/2); + shear2 = shear + storarm_taller / (storarm_mainlen/2); + base_xyz = [-storarm_base_d, -storarm_base_off_y, storarm_base_w]; + + StorageArmDiagPart(-1, storarm_mainlen/2+1, + -storarm_taller, shear2); + StorageArmDiagPart(storarm_mainlen/2-1, storarm_mainlen+1, + storarm_hookheight/2, shear/2); + + translate([0, storarm_hookheight, 0]) + StorageArmDiagPart(storarm_mainlen, storarm_totlen, + -storarm_hookheight/2, shear/2); + + difference(){ + union(){ + hull(){ + translate(base_xyz) + rotate([0,90,0]) + linear_extrude(height=storarm_base_mind) + StorageArmBaseTemplate(); + StorageArmDiagPart(-1, 0, -storarm_taller, shear); + } + StorageArmAtMountingHoles(){ + cylinder(r= storarm_screw_hole_head/2, + h=10); + } + } + StorageArmAtMountingHoles(){ + translate([0,0,-1]) + cylinder(r= (storarm_screw_hole + storarm_screw_hole_slop)/2 , + h=20); + translate([0,0,storarm_under_hole]) + cylinder(r= (storarm_screw_hole_head + storarm_screw_hole_head_slop)/2, + h=20); + } + translate(base_xyz + [0, storarm_base_h/4, -storarm_base_w/4]) + rotate([0,90,0]) + Commitid_BestCount([storarm_base_w/2, storarm_base_h/2]); + } +} + +module StorageArmLeft(){ ////toplevel + mirror([1,0,0]) StorageArmRight(); +} + +module StorArmHoleTest(){ ////toplevel + sz = storarm_screw_hole_head + storarm_besides_hole*2; + intersection(){ + StorageArmRight(); + translate([-50, -storarm_base_off_y, -1]) + cube([100, sz, sz+1]); + } +} + + +//----- filament guide spacer ----- + +guide_armdia = 15.0; +guide_armwidth = 10.2; +guide_armcorelen = 25.0; +guide_clipcirclethick = 10.0; + +guidefilclip_outerdia = 22.8; + +guidespacer_armslop = 0.75; +guidespacer_armlenslop = 1.05; + +guidespacer_prongprotrude = 4; +guidespacer_thick = 1.6; + +// calculated + +guidespacer_armdia = guide_armdia + guidespacer_armslop; +guidespacer_armwidth = guide_armwidth + guidespacer_armslop; +guidespacer_len = guide_armcorelen - guide_clipcirclethick + + guidespacer_armlenslop; + +guidespacer_wingheight = (guidefilclip_outerdia - guidespacer_armdia)/2; + +module FilamentGuideArmTemplate(extra=0){ + intersection(){ + circle(r= (guidespacer_armdia/2) + extra); + square(center=true, [guidespacer_armwidth+extra*2, + guidespacer_armdia + extra*2 + 10]); + } +} + +module FilamentGuideSpacerInnerTemplate(){ + FilamentGuideArmTemplate(); + translate([0, -guidespacer_armdia/2]) + square(center=true, [guidespacer_armwidth - guidespacer_prongprotrude, + guidespacer_armdia]); +} + +module FilamentGuideSpacer(){ ////toplevel + difference(){ + union(){ + linear_extrude(height= guidespacer_len) + FilamentGuideArmTemplate(extra= guidespacer_thick); + for (angle=[26, 60]) { + for (m=[0,1]) { + mirror([m,0,0]) { + rotate([0,0,angle]) { + hull(){ + for (t=[[0, guidespacer_wingheight], + [guidespacer_len-1, -guidespacer_wingheight]]) + translate([0,0, t[0] + 0.5]) + cube([guidespacer_thick, guidespacer_armdia + t[1]*2, + 1], + center=true); + } + } + } + } + } + } + translate([0,0,-1]) + linear_extrude(height= guidespacer_len+5) + FilamentGuideSpacerInnerTemplate(); + } +} + + +//----- replacement filament guide arm for TAZ-5 ----- + +guidearm_armslop = 0.25; +guidearm_armlenslop = 0.25; + +guidearm_hookprotr = 3; +guidearm_hookprotrflat = 1; +guidearm_hookslope = 0.3; + +guidearm_totallen = 60; + +guidearm_screwplatesz = 12; +guidearm_screwplateth = 4; +guidearm_screwplatewd = 15; +guidearm_screwhole = 5 + 0.5; + +guidearm_bendlen = 40; +guidearm_bendslot = 4.5; + +guidearm_stopthick = 4; +guidearm_protrslop = 1.0; + +// calculated + +guidearm_armdia = guide_armdia - guidearm_armslop; +guidearm_armwidth = guide_armwidth - guidearm_armslop; +guidearm_armcorelen = guide_armcorelen + guidearm_armlenslop; + +guidearm_base_z0 = -(guidearm_totallen - guidearm_armcorelen); + +guidearm_realbendlen = min(guidearm_bendlen, + guidearm_totallen - guidearm_screwplateth - 0.1); +guidearm_slopelen = guidearm_hookprotr/guidearm_hookslope; + +module FilamentGuideArmStop(h){ + for (ts=[-1,+1]) { + translate([ts * guidearm_hookprotr, 0,0]) + cylinder(r=guidearm_armdia/2, h, $fn=80); + } +} + +module FilamentGuideArmShaftPositive(){ + r = guidearm_armdia/2; + + translate([0,0, guidearm_base_z0+1]) + cylinder(r=r, h= guidearm_totallen, $fn=80); + translate([0,0, guidearm_armcorelen]){ + hull(){ + FilamentGuideArmStop(guidearm_hookprotrflat); + translate([0,0, guidearm_slopelen]) + cylinder(r=r, h=guidearm_hookprotrflat, $fn=80); + } + } + mirror([0,0,1]) + FilamentGuideArmStop(guidearm_stopthick); +} + +module FilamentGuideArmBase(){ + translate([0, + (guidearm_screwplatewd - guidearm_armwidth)/2, + guidearm_base_z0]){ + difference(){ + translate([0,0, guidearm_screwplateth/2]) + cube(center=true, + [guidearm_armdia + guidearm_screwplatesz*2, + guidearm_screwplatewd, + guidearm_screwplateth]); + for (ts=[-1,+1]) { + translate([ts * (guidearm_armdia/2 + guidearm_screwplatesz/2), + 0, + -20]) + cylinder(r= guidearm_screwhole/2, h=40, $fn=20); + } + } + } +} + +module FilamentGuideArm(){ ///toplevel + intersection(){ + difference(){ + FilamentGuideArmShaftPositive(); + translate([-guidearm_bendslot/2, + -50, + -guidearm_realbendlen + guidearm_armcorelen]) + cube([guidearm_bendslot, + 100, + guidearm_realbendlen + 100]); + hull(){ + for (zx=[ [ 0, guidearm_bendslot ], + [ guidearm_armcorelen + guidearm_slopelen, + guidearm_hookprotr*2 + guidearm_protrslop ] + ]) { + translate([-zx[1]/2, -50, zx[0]]) + cube([zx[1], 100, 1]); + } + } + } + cube(center=true, + [guidearm_armdia*2, + guidearm_armwidth, + guidearm_totallen*3]); + } + FilamentGuideArmBase(); +} + +module FilamentGuideArmPrint(){ ////toplevel + rotate([90,0,0]) + FilamentGuideArm(); +} + +module Demo(){ ////toplevel + translate([-real_exteffrad,-20,0]) Hub(); + ArmEnd(); + translate([ratchettooth*2, 30, 0]) FilamentCup(); + if (selsz(true,false,false)) { + translate([-exteffrad + hubeffrad - hub_clip_baseextend, -10, 0]) + ArmExtender(); + } +} + +//ArmEnd(); +//FilamentCup(); +//FilamentCupPair(); +//CupSecuringClip(); +//Hub(); +//ArmExtender(); +//Axle(); +//AxleWasher(); +//AxlePin(); +//AxleFrictionWasher(); +//StorageArmLeft(); +//StorArmHoleTest(); +//FilamentGuideSpacer(); +//FilamentGuideArm(); +//FilamentGuideArmPrint(); +//Demo(); diff --git a/filamentteeth.scad b/filamentteeth.scad new file mode 100644 index 0000000..f948c6e --- /dev/null +++ b/filamentteeth.scad @@ -0,0 +1,61 @@ +// -*- C -*- +// +// filamentteeth.scad +// +// 3D design for clips to hold FFF filament +// Copyright 2012,2016 Ian Jackson +// +// This work 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 work 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 work. If not, see . + + +d=0.01; +teethw=1.5; + +module FilamentTeeth(fdia, h, teethw=teethw, + stembendd=0.5, stembendl=7, teethxl=1.5) { + gapw = fdia-stembendd*2; + teethbigw = gapw + teethw*2; + basew = fdia+teethw*2-stembendd*2; + based = basew/3; + + translate([-based, -basew/2, 0]) cube([based, basew, h]); + difference() { + union() { + translate([-d, -teethbigw/2, 0]) + cube([d+stembendl + teethw, teethbigw, h]); +// translate([ +// stembigw = fdia + stembend +// translate([-d, -stemw, + linear_extrude(height=h) { + translate([stembendl-fdia/2, 0]) circle(fdia/2+teethw, $fn=30); + } + } + translate([0,0,-1]) { + translate([0,-gapw/2]) + cube([stembendl+teethxl+1, gapw, h+2]); + linear_extrude(height=h+2) { + translate([stembendl-fdia/2, 0]) circle(fdia/2, $fn=30); + } + } + } + + for (mirr=[0:1]) { + mirror([0,mirr,0]) { + translate([stembendl + teethw, gapw/2, 0]) + rotate([0,0,30]) + cube([teethxl, teethw, h]); + } + } +} + diff --git a/filamenttrestle.scad b/filamenttrestle.scad new file mode 100644 index 0000000..376a1ae --- /dev/null +++ b/filamenttrestle.scad @@ -0,0 +1,284 @@ +// -*- C -*- + +spoolinnerdia = 32; +spoolwidth = 88.0; +spoolinnerrad = (spoolinnerdia - 0.2) / 2; +spoolouterrad = spoolinnerrad + 61.5; + +include +include + +spoolradclear = 10; +spoolradslop = 2; + +spoolinnerslop = 3; +axleslop = 0.5; + +axlerad = 7; +barwasherrad = 17; + +hubbasethick = 4; +hubmainthick = 15; +hubbaseweb = 1.2; +hubbasestalkwidth = 4; +hubwalls = 2.5; +hubpillarw = 4; +hubbaserad = spoolinnerrad + 10; +hubmainrad = spoolinnerrad - spoolradslop; + +legw = 12; +plugl = 20; +plugwmin = 3; +plugh = 10; +plugslope = 0.5; +plugwmax = plugwmin + plugh * plugslope * 2; + +trestlefoot = 15; + +trestlelegw = 10; +trestlebaseh = 10; +trestleplugd = 1; + +topblockthick = 3; +topblockbasedepth = 5; + +pinbasew = 4.0; +pinminh = 1.0; +pinmaxh = 3.5; +pindh = 1.75; +pindwidth = 1.75; + +pintaperlen = 20; +pinstraightlen = 30-pintaperlen; + +spoolouterpad = AxlePin_holerad()*2 * 1.5; +spoolbarlen = spoolwidth + + 2*(Washer_thick() + hubbasethick + AxlePin_holerad() + + spoolinnerslop + spoolouterpad); + barz = axlerad * 0.5; +axlepin_x = spoolwidth/2 + hubbasethick + + Washer_thick() + spoolinnerslop + AxlePin_holerad()*0.5; + +trestleheight = spoolouterrad + spoolradclear - barz; +trestlebase = trestleheight * 1.2; + +module Plug(d=0){ + dw = d; + dh = d; + dhb = d*2; + a = atan(plugslope); + bdy = -dhb; + bdx = dw / cos(a) + bdy * plugslope; + tdy = dh; + tdx = bdx + tdy * plugslope; + translate([-d,0,0]) rotate([90,0,90]) linear_extrude(height=plugl+0.1+d*2){ + polygon([[-(plugwmin/2 + bdx), bdy], + [-(plugwmax/2 + tdx), plugh + tdy], + [+(plugwmax/2 + tdx), plugh + tdy], + [+(plugwmin/2 + bdx), bdy]]); + } +} + +module Bar(){ ////toplevel + spoolw = spoolbarlen; + biggestw = spoolw + 50; + + intersection(){ + for (mir=[0,1]) { + mirror([mir,0,0]) { + translate([spoolw/2, 0, 0]) + Plug(); + translate([-1, -50, -50]) + cube([spoolw/2+1.1, 100, 100]); + } + } + difference(){ + translate([-biggestw/2, -50, 0]) + cube([biggestw, 100, 100]); + for (mir=[0,1]) { + mirror([mir,0,0]) + translate([axlepin_x, 0, -50]) + cylinder(r=AxlePin_holerad(), 100, $fn=15); + } + } + translate([0,0,barz]) { + translate([-100,0,0]) + rotate([0,90,0]) cylinder(r=axlerad, h=200, $fn=60); + } + } +} + +module FtAxlePin(){ ////toplevel + AxlePin(axlerad, (axlerad + barwasherrad*2)/3 * 2); +} + +module AxleWasher(){ ////toplevel + Washer(axlerad, barwasherrad); +} + +module Trestle(){ ////toplevel + legang = atan2(trestlebase/2, trestleheight); + eplen = sqrt(trestleheight*trestleheight + trestlebase*trestlebase*0.25); + topblockw = plugwmax + trestleplugd*2 + topblockthick*2; + + pinholebasew = pinbasew + pindwidth*2; + pinholeh = pinmaxh + pindh; + + difference(){ + union(){ + for (mir=[0,1]) { + mirror([mir,0,0]) { + rotate([0,0, -90-legang]) + ExtenderPillars(length=eplen+trestlelegw, + width=trestlelegw, + height=legw, + baseweb=true); + + translate([-trestlebase/2, -trestleheight, 0]) + cylinder(r=trestlelegw/2*1.2, h=trestlefoot); + } + } + translate([-topblockw/2, -topblockbasedepth, 0]) + cube([topblockw, + topblockbasedepth + plugh + topblockthick + + (pinmaxh - pinminh)*0.5, + plugl]); + + translate([-trestlebase/2, -trestleheight, 0]) + ExtenderPillars(length=trestlebase, width=trestlebaseh*2, height=legw); + } + translate([-300, -trestleheight-50, -1]) + cube([600, 50, 52]); + + rotate([-90,-90,0]) + Plug(d=trestleplugd); + + for (rot=[0,180]) { + translate([0,0,plugl/2]) rotate([0,rot,0]) translate([0,0,-plugl/2]) { + translate([0, + plugh - (pinmaxh - pinminh)*1.00, + (plugl - pinholebasew*2)/3]) { + translate([-(topblockw*0.25+1), 0, pinholebasew/2]) + rotate([-90,0,0]) %Pin(); + translate([-(topblockw+1), 0, 0]) { + rotate([0,90,0]) { + linear_extrude(height = topblockw*2.0+2) { + polygon([[-1.0 * pinholebasew, -0.01], + [-0.5 * pinholebasew, pinholeh], + [ 0 , -0.01]]); + } + } + } + } + } + } + } +} + +module Pin(){ ////toplevel + rotate([90,0,90]) { + hull(){ + for (mir=[0,1]) { + mirror([mir,0,0]) { + linear_extrude(height=0.1) { + polygon([[-0.01, 0], + [-0.01, pinminh], + [pinbasew*0.5*(pinminh/pinmaxh), 0]]); + } + translate([0,0,pintaperlen]) + linear_extrude(height=pinstraightlen) { + polygon([[-0.01, 0], + [-0.01, pinmaxh], + [pinbasew*0.5, 0]]); + } + } + } + } + } +} + +module HubEnd(){ ////toplevel + thick = hubmainthick+hubbasethick; + difference(){ + union(){ + for (ang=[0 : 60 : 359]) { + rotate([0,0,ang]) { + translate([hubmainrad - hubwalls/2, -hubbasestalkwidth/2, 0]) + cube([hubbaserad - (hubmainrad - hubwalls/2), + hubbasestalkwidth, hubbasethick]); + ExtenderPillar(length = hubmainrad-hubwalls/2, + height = hubbasethick + hubmainthick, + pillarw = hubpillarw); + } + } + cylinder(r=axlerad+hubwalls, h=thick); + cylinder(r=hubmainrad-0.1, h=hubbaseweb); + difference(){ + cylinder(r=hubmainrad, h=thick, $fn=100); + translate([0,0,-1]) + cylinder(r=hubmainrad-hubwalls, h=thick+2); + } + difference(){ + cylinder(r=hubbaserad, h=hubbasethick, $fn=50); + translate([0,0,-1]) + cylinder(r=hubbaserad-hubwalls, h=hubbasethick+2); + } + } + translate([0,0,-1]) + cylinder(r=axlerad+axleslop, h=thick+2, $fn=50); + } +} + + +module TestKit(){ ////toplevel + translate([60,0,0]) mirror([1,0,0]) Pin(); + translate([60,15,0]) mirror([1,0,0]) Pin(); + translate([0,40,0]) intersection(){ + Trestle(); + translate([-50,-10,-1]) cube([100,100,100]); + } + intersection(){ + translate([-60,10,0]) Bar(); + cube(50,center=true); + } + %translate([50,40, AxlePin_zoffset()]) FtAxlePin(); + %translate([0,-20,0]) AxleWasher(); +} + +module DemoSpool(){ + rotate([0,90,0]) translate([0,0,-spoolwidth/2]) + difference(){ + cylinder(r=spoolouterrad, h=spoolwidth); + translate([0,0,-1]) cylinder(r=spoolinnerrad, h=spoolwidth+2); + } +} + +module Demo(){ ////toplevel + color("blue") Bar(); + for (mir=[0,1]) { + mirror([mir,0,0]) { + color("red") translate([spoolbarlen/2,0,0]) + rotate([90,0,90]) Trestle(); + color("orange") + translate([spoolwidth/2 + hubbasethick + spoolinnerslop*2/3, 0, barz]) + rotate([0,90,0]) AxleWasher(); + color("orange") translate([axlepin_x, 0, barz]) + rotate([90,0,90]) FtAxlePin(); + color("cyan") + translate([spoolwidth/2 + hubbasethick + spoolinnerslop*1/3, 0, barz]) + rotate([0,-90,0]) HubEnd(); + } + } + %translate([0,0,barz]) DemoSpool(); +} + +//Bar(); +//FtAxlePin(); +//AxleWasher(); +//Trestle(); +//Pin(); +//TestKit(); +//Plug(d=1); +//ExtenderPillars(80,12,8, baseweb=true); +//HubEnd(); +//Demo(); diff --git a/fire-blanket-wall-mushroom.scad b/fire-blanket-wall-mushroom.scad new file mode 100644 index 0000000..dae4769 --- /dev/null +++ b/fire-blanket-wall-mushroom.scad @@ -0,0 +1,40 @@ +// -*- C -*- + +fudge=0.15; + +screwrad = 4.5 / 2 + fudge; // xxx check +shaftrad = 7.5 / 2 - fudge; + +diskrad = 12.0 / 2 - fudge; + +csinkpart = 0.5; + +shaftlen = 8; // xxx check + +diskthick = 1.5; + +disktaperratio = 2; + +// computed + +disktaperrad = diskrad - diskthick / disktaperratio; +totallen = shaftlen + diskthick; + +module SidePlan(){ + polygon([[-screwrad, 0], + [-disktaperrad, 0], + [-diskrad, -diskthick], + [-shaftrad, -diskthick], + [-shaftrad, -totallen], + [-screwrad, -totallen]]); +} + +module Bush(){ + rotate_extrude($fn=25, convexity=3){ + SidePlan(); + } +} + +//SidePlan(); +rotate([0,180,0]) + Bush(); diff --git a/fire-blanket-wall-mushroom.slic3r b/fire-blanket-wall-mushroom.slic3r new file mode 100644 index 0000000..2aa4f4a --- /dev/null +++ b/fire-blanket-wall-mushroom.slic3r @@ -0,0 +1 @@ +first_layer_extrusion_width = 100% diff --git a/firmware-eeprom.hex b/firmware-eeprom.hex new file mode 100644 index 0000000..5064bfa --- /dev/null +++ b/firmware-eeprom.hex @@ -0,0 +1,65 @@ +:20000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00 +:20002000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 +:20004000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0 +:20006000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0 +:20008000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80 +:2000A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF60 +:2000C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF40 +:2000E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF20 +:20010000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +:20012000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDF +:20014000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBF +:20016000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9F +:20018000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F +:2001A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5F +:2001C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F +:2001E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1F +:20020000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE +:20022000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDE +:20024000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBE +:20026000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9E +:20028000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7E +:2002A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5E +:2002C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3E +:2002E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1E +:20030000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD +:20032000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDD +:20034000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBD +:20036000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9D +:20038000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7D +:2003A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D +:2003C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3D +:2003E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1D +:20040000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC +:20042000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC +:20044000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBC +:20046000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C +:20048000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7C +:2004A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5C +:2004C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3C +:2004E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1C +:20050000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB +:20052000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDB +:20054000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBB +:20056000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9B +:20058000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7B +:2005A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5B +:2005C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3B +:2005E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1B +:20060000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA +:20062000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDA +:20064000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBA +:20066000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9A +:20068000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7A +:2006A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5A +:2006C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3A +:2006E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1A +:20070000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9 +:20072000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD9 +:20074000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB9 +:20076000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF99 +:20078000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF79 +:2007A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF59 +:2007C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF39 +:2007E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF19 +:00000001FF diff --git a/firmware-efuse.hex b/firmware-efuse.hex new file mode 100644 index 0000000..1a73311 --- /dev/null +++ b/firmware-efuse.hex @@ -0,0 +1,2 @@ +:0100000000FF +:00000001FF diff --git a/firmware-flash.hex b/firmware-flash.hex new file mode 100644 index 0000000..78762bd --- /dev/null +++ b/firmware-flash.hex @@ -0,0 +1,2045 @@ +:200000000C949E000C94C6000C94C6000C94C6000C94C6000C94C6000C94C6000C94C600D8 +:200020000C94C6000C94C6000C94C6000C94C6000C94C6000C94C6000C94C6000C94C60090 +:200040000C94C6000C94C6000C941B300C94C6000C9425310C94C6000C94C6000C94C6005B +:200060000C94C6000C94C6000C94C6000C94C6000C944D310C94C6000C94C6007C3C3E5EAA +:200080002B3D3F2F5B5D3B2C2A225C00002124272A002225282B00202326290202020202F7 +:2000A0000202020404040404040404030303030303030301010101010101010102040810DB +:2000C000204080010204081020408001020408102040808040201008040201000000010240 +:2000E000000000000000000403070600000000000000000000000000000000494E46494E78 +:200100004954594E414ECDCCCC3D0AD7233C17B7D13877CC2B329595E6241FB14F0A000056 +:2001200020410000C84200401C4620BCBE4CCA1B0E5AAEC59D7471062F2FC93211241FBE19 +:20014000CFEFD0E1DEBFCDBF15E0A0E0B1E0EAE9F6E702C005900D92AC32B107D9F71DE0F8 +:20016000ACE2B5E001C01D92A630B107E1F711E0CCE3D1E004C02297FE010E941638C633D0 +:20018000D107C9F70E940C350C944B3B0C94000080912E07882399F14091AD035091AE0390 +:2001A0006091AF037091B00380912C0790912D072CE235E00E94B623882319F140912F07F5 +:2001C000509130076091310770913207411551056105710591F080912C0790912D072CE2F4 +:2001E00035E00E94B623882361F010922F0710923007109231071092320710922E0781E0D5 +:20020000089580E00895EF92FF920F931F937B018C010E94C8008823A9F0ECE2F5E01192E1 +:2002200087E0EC32F807D9F7E092AD03F092AE030093AF031093B00380912E078160809340 +:200240002E0781E01F910F91FF90EF900895DF92EF92FF920F931F937B018C01D42E80911A +:20026000AD039091AE03A091AF03B091B0038E159F05A007B107C1F00E94C8008823D9F0F0 +:2002800080912C0790912D07B801A7012CE235E00E94B024882379F0E092AD03F092AE0362 +:2002A0000093AF031093B00380912E078D2980932E0781E001C080E01F910F91FF90EF907F +:2002C000DF9008958F929F92AF92BF92CF92DF92EF92FF920F931F93CF93DF936C01142F72 +:2002E00070932D0760932C07442321F488249924540140C0453008F01CC160E070E080E02D +:2003000090E040E00E942701882309F412C1C12FD0E02197FE0174E0EE0FFF1F7A95E1F75B +:20032000E45DFA4FE254FE4F8081EE5BF14090E08F779070892B09F0FCC0E653FE4F8081CF +:200340009181A281B38184369105A105B10508F4F0C064E0CC0FDD1F6A95E1F7CE50D94FA4 +:2003600088809980AA80BB8081149104A104B10409F4DFC0C501B40140E00E9427018823C7 +:2003800009F4D7C080913705909138058050924009F0CFC020913C05222309F4CAC0809125 +:2003A0003A0590913B05892B09F4C3C080913905882309F4BEC0F601228B809139058483FA +:2003C000158661E070E007C04F5FF60145874150483008F0AEC0F6014585848190E09B0178 +:2003E000042E02C0220F331F0A94E2F78217930759F720914205309143052115310519F016 +:2004000040E050E008C020915005309151054091520550915305F60125833683478350874D +:20042000E0903A05F0903B0500E010E0E80CF91C0A1D1B1DE38AF48A058B168B80913D05A6 +:2004400090913E05918F808F60913C0570E080E090E00E9485376E0D7F1D801F911FF601FC +:20046000628F738F848F958F20913D0530913E0555E0220F331F5A95E1F721503E4F232F8C +:200480003327269540E050E0260F371F481F591F26873787408B518B80913F0590914005C0 +:2004A000009719F0A0E0B0E008C080914C0590914D05A0914E05B0914F0585017401E21ADF +:2004C000F30A040B150BA8019701280F391F4A1F5B1FF601058404C05695479537952795AA +:2004E0000A94D2F72187328743875487253FFFE03F07F0E04F07F0E05F0710F48CE006C074 +:20050000255F3F4F4040504028F480E1F601878B81E010C08091580590915905A0915A0585 +:20052000B0915B05F601828F938FA48FB58F80E2EECF80E0DF91CF911F910F91FF90EF90CC +:20054000DF90CF90BF90AF909F908F9008954F925F926F927F928F929F92AF92BF92CF922B +:20056000DF92EF92FF920F931F93CF93DF93EC016A017B01280139014230510561057105F5 +:2005800008F46FC089859A85AB85BC850196A11DB11D84179507A607B70708F462C02B89FB +:2005A0003C894D895E898F89803129F499278F2D7E2D6D2D09C0C701B60117E0969587958C +:2005C000779567951A95D1F74B015C01820E931EA41EB51E8091AD039091AE03A091AF03A7 +:2005E000B091B00388169906AA06BB0639F0C501B40140E00E942701882399F18F898031CD +:2006000049F4F601F070EE0FFF1FE45DFA4F518240820DC0F601EF77F070EE0FFF1FEE0F6A +:20062000FF1FE45DFA4F408251826282738280912E07816080932E078A89823080F08D81F2 +:200640009E81AF81B885880E991EAA1EBB1E80922F0790923007A0923107B092320781E039 +:2006600001C080E0DF91CF911F910F91FF90EF90DF90CF90BF90AF909F908F907F906F9073 +:200680005F904F900895CF92DF92EF92FF920F931F93CF93DF93EC017A018B016901898577 +:2006A0009A85AB85BC850196A11DB11D84179507A607B70708F450C02B893C894D895E89A3 +:2006C0008F89803129F49927812F702F6F2D09C0C801B701E7E09695879577956795EA95AA +:2006E000D1F7260F371F481F591F8091AD039091AE03A091AF03B091B003281739074A078E +:200700005B0739F0CA01B90140E00E942701882319F18F89803159F4F701F070EE0FFF1FA1 +:20072000E45DFA4F80819181A0E0B0E00EC0F701EF77F070EE0FFF1FEE0FFF1FE45DFA4FC0 +:2007400080819181A281B381BF70F60180839183A283B38381E001C080E0DF91CF911F9195 +:200760000F91FF90EF90DF90CF900895AF92BF92CF92DF92EF92FF920F931F93DF93CF93C2 +:2007800000D000D0CDB7DEB76C017A018B0182E090E0A0E0B0E0F60180839183A283B383E1 +:2007A0005E010894A11CB11CC601B801A70195010E944303882319F1C601B801A70100E051 +:2007C00010E020E030E00E94A7028823C1F0E980FA800B811C81F6018789803129F088EF1E +:2007E0009FEFAFEFBFE004C088EF9FEFA0E0B0E0E816F9060A071B07B8F281E001C080E0F9 +:200800000F900F900F900F90CF91DF911F910F91FF90EF90DF90CF90BF90AF9008954F9254 +:200820005F926F927F928F929F92AF92BF92CF92DF92EF92FF920F931F93DF93CF9300D0F5 +:2008400000D0CDB7DEB76C0149835A836B837C833901EE24FF2487012E010894411C511C20 +:20086000812CA2E09A2EA12CB12C49815A816B817C81C60192010E944303882351F1D50144 +:20088000C401F601058404C0880F991FAA1FBB1F0A94D2F7E80EF91E0A1F1B1F29813A8121 +:2008A0004B815C818789803129F088EF9FEFAFEFBFE004C088EF9FEFA0E0B0E0281739071B +:2008C0004A075B0790F2F301E082F1820283138381E00F900F900F900F90CF91DF911F91A2 +:2008E0000F91FF90EF90DF90CF90BF90AF909F908F907F906F905F904F9008952F923F9295 +:200900004F925F926F927F928F929F92AF92BF92CF92DF92EF92FF920F931F93DF93CF9303 +:20092000CDB7DEB72F970FB6F894DEBF0FBECDBF1C014A875B876C877D873F872E87D90175 +:200940000D911D912D913C91011511052105310549F0480159010894811C911CA11CB11CEC +:20096000198610C0FC0180809180A280B38019868A859B85AC85BD850197A105B10511F46B +:2009800091E09987D10119968D919D910D90BC91A02D0196A11DB11D8D839E83AF83B8877D +:2009A000750164014424552432018E010F5F1F4FF10181859285A385B485481659066A0640 +:2009C0007B0608F090C08D819E81AF81B8858C159D05AE05BF0550F482E0882E912CA12C14 +:2009E000B12CB2E0CB2ED12CE12CF12CC101B701A60198010E944303882309F474C08981E0 +:200A00009A81AB81BC81A70196012F5F3F4F4F4F5F4F0097A105B10519F049015A010DC03D +:200A2000281939094A095B098A859B85AC85BD85281739074A075B0759F00894411C511CF9 +:200A4000611C711C0894C11CD11CE11CF11CB0CFC101A601B7010FEF1FEF2FEF3FE00E9491 +:200A6000A702882399F43FC02601370108944108510861087108C101B301A20197018601DF +:200A80000E94A702882379F1730162018C149D04AE04BF0448F3AE85BF854D915D916D91ED +:200AA0007C91411551056105710539F0C101950184010E94A7028823B1F0EE85FF8580820B +:200AC0009182A282B382F985FF2359F00894811C911CA11CB11CD1018D929D92AD92BC92A4 +:200AE000139781E001C080E02F960FB6F894DEBF0FBECDBFCF91DF911F910F91FF90EF9090 +:200B0000DF90CF90BF90AF909F908F907F906F905F904F903F902F9008958130910579F074 +:200B2000823091051CF4009741F00EC08230910541F08330910541F406C05F9A05C0469A6C +:200B400003C02B9A01C0299AFC01EE0FFF1FEE0FFF1FE553F84F80819181A281B3810196D6 +:200B6000A11DB11D80839183A283B3835F9846982B98299808950F931F93CF93DF938C01CC +:200B8000EB012130310519F02FEF3FEF4BC081E030C0DF01AA0FBB1FAA0FBB1FAC0FBD1F94 +:200BA00012966D917C911397601771070CF53197EE0FFF1FEE0FFF1FEC0FFD1F228133817C +:200BC0000190F081E02D021B130B8D919C918E1B9F0B621B730B9C01029FC001039F900DF4 +:200BE000129F900D11240E94B0376E0F7F1F16C08F5FE82FF0E0E417F5075CF2E417F507E7 +:200C000019F060E070E00AC041505040440F551F440F551FC40FD51F688179812FEF33E0E7 +:200C2000261B370BC901DF91CF911F910F910895CF93DF93EB012130310519F06FEF7FEF8E +:200C40004CC02FEF33E0281B390B81E031C0DF01AA0FBB1FAA0FBB1FAC0FBD1F6D917C91D6 +:200C60001197261737071CF53197EE0FFF1FEE0FFF1FEC0FFD1F408151810280F381E02D95 +:200C8000241B350B12968D919C9113978E1B9F0B641B750BAC01249FC001259F900D349F81 +:200CA000900D11240E94B0376E0F7F1F16C08F5FE82FF0E0E417F50754F2E417F50719F0D6 +:200CC00060E070E00AC041505040440F551F440F551FC40FD51F6A817B81CB01DF91CF91C1 +:200CE0000895AF92BF92CF92DF92EF92FF920F931F93E0903404F0903504A0903A04B0907E +:200D00003B04C0903C04D0903D04662777276E197F09882777FD8095982F0E941736A60194 +:200D200095010E947C350E94E4357093430B6093420B0027F7FC0095102FC801B7010E946D +:200D40001736A60195010E947C350E94E4357093450B6093440B04E414E085E090E0B801FC +:200D60004EE150E021E030E00E94BB059093470B8093460B8CE291E0B8014EE150E021E0D0 +:200D800030E00E94BB059093490B8093480B10925B0B10925C0B10925F0B1092610B82E077 +:200DA00090E0A0E0B0E08093620B9093630BA093640BB093650B1092790B84E295E0909329 +:200DC000810B8093800B1092840B90939D0B80939C0B1092A00B1F910F91FF90EF90DF9019 +:200DE000CF90BF90AF900895EF92FF920F931F93CF93DF930E948B302091510730915207AF +:200E00004091530750915407621B730B840B950B603771058105910508F41DC10E948B30E1 +:200E20006093510770935207809353079093540787E00E943F2FCFEFD3E0C81BD90BD0930E +:200E40002B0BC0932A0B8091460B9091470B8C179D0784F082E090E09093380780933707BF +:200E600081E090E090933A07809339071092290B1092280B8091480B9091490BC817D907A7 +:200E800024F01092290B1092280B0091280B1091290B0C1B1D0B1093410B0093400BB80125 +:200EA000882777FD8095982F0E941736209136043091370440913804509139040E94CB368F +:200EC0000E94E4357B017093390B6093380B8091340B9091350B800F911F2091420B3091AF +:200EE000430B821793074CF04091440B5091450B9C01481759070CF49A013093350B209337 +:200F0000340BB901882777FD8095982F0E94173620913A0430913B0440913C0450913D04C8 +:200F20000E94CB360E94E4358B0170933B0B60933A0B8091360B9091370BBE01681B790BCB +:200F4000882777FD8095982F0E94173620913E0430913F0440914004509141040E94CB36CE +:200F60000E94E4359B0170933D0B60933C0BD093370BC093360BB701621B730B600F711FAA +:200F800077FF03C060E070E008C08091320490913304861797070CF4BC0170933F0B6093E9 +:200FA0003E0B8DE00E945D2F80913707909138070297D9F02091280B3091290B8091460B01 +:200FC0009091470B821793079CF480913B0790913C07019690933C0780933B07019705979E +:200FE00044F010923C0710923B0780E180B901C0149A0E948B302091550730915607409192 +:20100000570750915807621B730B840B950B6858734180409040F8F00E948B306093550770 +:2010200070935607809357079093580786E00E943F2F2FEF33E0281B390B30932F0B20937F +:201040002E0B80912C0B90912D0B2817390714F05A9801C05A9ADF91CF911F910F91FF90DD +:20106000EF9008958091390790913A07019741F4109238071092370710923A07109239074E +:201080000E948B3020912A0B30912B0B8091280B9091290B2817390724F410923807109263 +:2010A000370708952F923F924F925F926F927F928F929F92AF92BF92CF92DF92EF92FF9217 +:2010C0000F931F93DF93CF93CDB7DEB7C856D0400FB6F894DEBF0FBECDBFA3969FAF8EAF96 +:2010E000A3976091AB077091AC078091AD079091AE072091BB073091BC074091BD07509157 +:20110000BE070E94C736181614F4459801C0459A6091AF077091B0078091B1079091B207B6 +:201120002091BF073091C0074091C1075091C2070E94C736181614F4479A01C04798609126 +:20114000B3077091B4078091B5079091B6072091C3073091C4074091C5075091C6070E947A +:20116000C736181614F42A9A01C02A986091B7077091B8078091B9079091BA072091C70754 +:201180003091C8074091C9075091CA070E94C736181614F4289801C0289A80913D07882354 +:2011A00059F4329B09C0A396AEADBFADA3971D921D921D921C92139780913E07882351F467 +:2011C000339B08C0A396EEADFFADA397148215821682178280913F07882361F4349B0AC071 +:2011E000A396AEADBFADA39718961D921D921D921C921B97A396EEADFFADA397A080B1808F +:20120000C280D380A114B104C104D10409F05E98A3962EAD3FADA3972C5F3F4F3AAF29AF32 +:20122000A396AEADBFADA3971496ED90FD900D911C911797E114F1040105110509F05E98D2 +:20124000A396EEADFFADA3973896F8AFEFABA396AEADBFADA39718962D913D914D915C9186 +:201260001B97211531054105510509F01598A396EEADFFADA3973C96A196FFAFEEAFA197C8 +:20128000A396AEADBFADA3971C966D917D918D919C911F976F966CAF7DAF8EAF9FAF6F9778 +:2012A000611571058105910509F05E98FE01319680E1DF011D928A95E9F7A982BA82CB82CE +:2012C000DC82ED82FE820F83188729873A874B875C876F966CAD7DAD8EAD9FAD6F976D87A1 +:2012E0007E878F87988BAE14BF04C006D106B0F42E153F054007510760F46E157F058007E2 +:20130000910738F481E090E061969FAF8EAF61973CC0AE14BF04C006D106A8F02A153B0589 +:201320004C055D0580F46F966CAD7DAD8EAD9FAD6F976A157B058C059D0528F461961FAE9F +:201340001EAE619722C02A153B054C055D05B8F02E153F054007510790F06F968CAD9DADDF +:20136000AEADBFAD6F9782179307A407B50738F4A2E0B0E06196BFAFAEAF619706C0E3E085 +:20138000F0E06196FFAFEEAF61976196EEADFFAD6197EE0FFF1FEE0FFF1FEC0FFD1F21811E +:2013A0003281438154812BAB3CAB4DAB5EAB56954795379527956B962CAF3DAF4EAF5FAF01 +:2013C0006B976896BFAD68976996AFAD69976A967FAD6A976B966FAD6B9720E030E080E08B +:2013E00090E0AE014F5E5F4F6196EEADFFAD61972E173F0739F0FA01E80FF91FB083A18328 +:2014000072836383FC01E553F84F10821182128213822F5F3F4F04962430310529F76196D0 +:20142000EEADFFAD6197EE0FFF1FEE0FFF1FDF01A552B84F2D913D914D915C9167962CAF2A +:201440003DAF4EAF5FAF67972093A7073093A8074093A9075093AA07E759F84F7080618055 +:201460003281A4963FAFA4974381A5964FAFA5977092990760929A0730939B0740939C070D +:2014800061968EAC9FAC6197272D362DA4964FADA497A5965FADA597C901DA017C018D017D +:2014A000CC24DD24AA24BB24A396EEADFFADA397EA0DFB1D2081318142815381211531056F +:2014C0004105510551F161966EAD7FAD6197C616D70619F1F501E759F84F208031804280A5 +:2014E0005380C201B1010E948537F401EE0FFF1FEE0FFF1FA396AEADBFADA397EA0FFB1FCE +:2015000020813181428153810E94C337E216F3060407150710F4460102C017012801089443 +:20152000C11CD11CE4E0F0E0AE0EBF1EF4E0CF16D10419F082017101B7CF60E071EE85EF8F +:2015400095E0272D362DA4964FADA497A5965FADA5970E94C337C901DA0127968CAF9DAFE6 +:20156000AEAFBFAF27979401220F331F220F331FA3964EAD5FADA397420F531F5AAB49AB11 +:201580001EAE1DAE1CAE1BAEA396EEADFFADA3976BAD7CADE60FF71F608071808280938035 +:2015A000611471048104910409F44FC0C201B1010E9415365B016C01A9A9BAA96D917D912F +:2015C0008D919C910E9415367B018C01C401B3010E9415369B01AC01C801B7010E947C3547 +:2015E0009B01AC01C601B5010E94CB360E94E9359B01AC01E1E2F0E0EC0FFD1F6BAD7CAD8E +:20160000E60FF71F20833183428353838DAD9EAD6196AEADBFAD61978A179B07B1F42093F7 +:20162000990730939A0740939B0750939C0760E071EE85EF95E00E94C337C901DA01279625 +:201640008CAF9DAFAEAFBFAF2797EDADFEAD3196FEAFEDAF2BAD3CAD2C5F3F4F3CAF2BAF86 +:20166000349709F091CF2BED422E27E0522E91E2692E712C6C0E7D1EA8961FAEA897A996F2 +:201680001FAEA99722243324CC24DD24A396EEADFFADA397EC0DFD1D80819181A281B38178 +:2016A0000097A105B10509F47DC06F964CAD5DAD6EAD7FAD6F97411551056105710561F1CE +:2016C000D2016D917D918D919C910E9417369B01AC0160E27CEB8EEB9CE40E947C357B0137 +:2016E0008C01F30160817181828193810E9415369B01AC0160E27CEB8EEB9CEC0E947C354C +:201700009B01AC01C801B7010E9414357B018C01F601E758F84F2BC0D2016D917D918D91A6 +:201720009C910E9417369B01AC0160E27CEB8EEB9CE40E947C357B018C01F301608171817F +:20174000828193810E9415369B01AC0160E27CEB8EEB9CEC0E947C359B01AC01C801B70175 +:201760000E9414357B018C01F601E757F84F60817181828193810E9415369B01AC01C80110 +:20178000B7010E947C354B015C01A8966FADA897A9967FADA997C101A50194010E94C736B5 +:2017A00018164CF4A8968FADA897A9969FADA997D1014C015D0124E030E0C20ED31E420E95 +:2017C000531E620E731E30E1C316D10451F0D501C401A8968FAEA897A9969FAFA9971D0157 +:2017E00055CF61960EAD1FAD6197000F111F000F111FF801E552F84F608171818281938170 +:201800000E9417369B01AC0160E27CEB8EEB9CE40E947C356B017C010C0F1D1FD80191965B +:201820006D917D918D919C9194970E9415369B01AC0160E27CEB8EEB9CEC0E947C359B0157 +:20184000AC01C701B6010E941435A50194010E947C350E94E93560939D0770939E078093D1 +:201860009F079093A0070E94153620E030E040E05FE30E94CB36A50194010E94CB367B019C +:201880008C0127966CAD7DAD8EAD9FAD27970E9417369B01AC01C801B7010E941435A5012C +:2018A00094010E94CB360E94E4350E9415362EEA37E441E85FE30E94CB360E94E935609354 +:2018C000A1077093A2078093A3079093A40781E08093A5078091990790919A07A0919B07C3 +:2018E000B0919C0767962CAD3DAD4EAD5FAD679782179307A407B50710F41092A5070E94B1 +:20190000993023966CAF7DAF8EAF9FAF239724E630E040E050E00E948537609341077093B3 +:201920004207809343079093440760934507709346078093470790934807609349077093EB +:201940004A0780934B0790934C0760934D0770934E0780934F079093500760E071EE85EFC6 +:2019600095E067962CAD3DAD4EAD5FAD67970E94C337C901DA012B968CAF9DAFAEAFBFAFD9 +:201980002B9761968EAD9FAD6197880F991F880F991FA3964EAD5FADA397480F591F63962F +:2019A0005FAF4EAF63972BA93CA94DA95EA92F962CAF3DAF4EAF5FAF2F9722243324210150 +:2019C000AC014F5B584FA7965FAF4EAFA797BCC20E94F4068091A507882309F423C12114EB +:2019E00031044104510489F48091990790919A07A0919B07B0919C078093A7079093A807DE +:201A0000A093A907B093AA071DC18091A1079091A207A091A307B091A40782159305A405EF +:201A2000B50508F488C060919D0770919E0780919F079091A00720E137E240E050E00E94E2 +:201A4000E537122F032FF42EE52E0E94993023962CAD3DAD4EAD5FAD2397621B730B840B90 +:201A6000950B24E630E040E050E00E94C337CA01B901212F302F4F2D5E2D0E9485379B018B +:201A8000AC0127966CAD7DAD8EAD9FAD2797260F371F481F591F60E071EE85EF95E00E94C0 +:201AA000E537C901DA018093A7079093A807A093A907B093AA0767962CAD3DAD4EAD5FAD34 +:201AC000679782179307A407B50750F41092A6072093A7073093A8074093A9075093AA07F1 +:201AE0006B964CAD5DAD6EAD7FAD6B97241635064606570608F4A6C02092A1073092A20754 +:201B00004092A3075092A4072091A7073091A8074091A9075091AA0760E071EE85EF95E052 +:201B20000E94C337C901DA012B968CAF9DAFAEAFBFAF2B9785C02F962CAD3DAD4EAD5FADBB +:201B40002F9782179307A407B50708F46BC08091A607882359F40E94993023966CAF7DAFDD +:201B60008EAF9FAF239731E03093A60760919D0770919E0780919F079091A00720E137E2CB +:201B800040E050E00E94E537122F032FF42EE52E0E94993023962CAD3DAD4EAD5FAD2397E7 +:201BA000621B730B840B950B24E630E040E050E00E94C337CA01B901212F302F4F2D5E2DBA +:201BC0000E9485372B962CAD3DAD4EAD5FAD2B97261B370B480B590B60E071EE85EF95E098 +:201BE0000E94E537C901DA018093A7079093A807A093A907B093AA072091990730919A0765 +:201C000040919B0750919C07281739074A075B07C8F42093A7073093A8074093A9075093A6 +:201C2000AA0710C067964CAD5DAD6EAD7FAD67974093A7075093A8076093A9077093AA0774 +:201C40001092A6076396EEADFFAD639780819181A281B3810097A105B10509F475C180915A +:201C60003D078823C9F4329B17C061962EAD3FAD6197232B09F495C1A396EEADFFADA39703 +:201C800080819181A281B3810097A105B10521F0108211821282138280913E078823B9F4DA +:201CA000339B15C06196EEADFFAD6197319709F478C1E9ADFAAD80819181A281B38100970F +:201CC000A105B10521F0108211821282138280913F078823B9F4349B15C06196EEADFFADB8 +:201CE0006197329709F45DC1EFA9F8AD80819181A281B3810097A105B10521F01082118238 +:201D0000128213820E94993024E630E040E050E00E948537A796EEADFFADA7972081318152 +:201D200042815381621B730B840B950B6093FC077093FD078093FE079093FF0797FFE2C06C +:201D40000E94993024E630E040E050E00E948537A796AEADBFADA7976D937D938D939C93AF +:201D600013978091A7079091A807A091A907B091AA07B695A795979587958093FC0790934F +:201D8000FD07A093FE07B093FF07BCC00197A109B1096396EEADFFAD639780839183A283D0 +:201DA000B3838091FC079091FD07A091FE07B091FF072091A7073091A8074091A907509106 +:201DC000AA07821B930BA40BB50B8093FC079093FD07A093FE07B093FF0761968EAD9FAD6C +:201DE00061970E948D05A796EEADFFADA79780819181A281B3812091A7073091A8074091EB +:201E0000A9075091AA07820F931FA41FB51F80839183A283B383A3968EAC9FACA397B1E1AA +:201E2000AB2EB12CAC0EBD1E3E010894611C711CCC24DD2461962EAD3FAD6197C216D3061A +:201E4000E1F1F40180819181A281B3810097A105B10599F1D501ED90FD900D911C91F301B5 +:201E600080819181A281B381E81AF90A0A0B1B0BD501ED92FD920D931C93139717FF1DC0E8 +:201E8000C6010E948D05F40180819181A281B3810197A109B10980839183A283B3832BA9A6 +:201EA0003CA94DA95EA9E20EF31E041F151FD501ED92FD920D931C9313970894C11CD11CA5 +:201EC000E4E0F0E08E0E9F1EAE0EBF1E6E0E7F1EF4E0CF16D10409F0ADCF0894211C311C3A +:201EE000411C511C2F962CAD3DAD4EAD5FAD2F9721503040404050402F962CAF3DAF4EAF49 +:201F00005FAF2F972091FC073091FD074091FE075091FF078091A7079091A807A091A90747 +:201F2000B091AA07281739074A075B0768F06396EEADFFAD639780819181A281B3810097EA +:201F4000A105B10509F022CFE9ADFAAD80819181A281B381EFA9F8AD20813181428153816D +:201F6000820F931FA41FB51FA396EEADFFADA3972081318142815381820F931FA41FB51F09 +:201F8000A196EEADFFADA1972081318142815381820F931FA41FB51F0097A105B10509F0DB +:201FA00017CD159AABEA6A2EA7E07A2EFBEBCF2EF7E0DF2EEBEC8E2EE7E09E2E71EBA72E14 +:201FC00073E0B72ED601ED90FD900D911C91F3016081718182819381A80197010E94C736DF +:201FE0001816DCF4D4016D917D918D919C910E941536F50120813181428153810E947C3597 +:202000009B01AC01C801B7010E941435D6016D937D938D939C93139719C0F401608171818A +:20202000828193810E941536D5012D913D914D915C910E947C359B01AC01C801B7010E94B0 +:202040001335F601608371838283938324E030E0620E731EC20ED31E820E931EA20EB31EB7 +:202060003BEB631637E0730609F0ACCFC859DF4F0FB6F894DEBF0FBECDBFCF91DF911F91A7 +:202080000F91FF90EF90DF90CF90BF90AF909F908F907F906F905F904F903F902F900895E1 +:2020A0002F923F924F925F926F927F928F929F92AF92BF92CF92DF92EF92FF920F931F938E +:2020C000DF93CF93CDB7DEB766970FB6F894DEBF0FBECDBFBDE3EB2EB7E0FB2E00E010E086 +:2020E000DD24D394F801E555F84FD801A554B84F60817181828193812D913D914D915C91E4 +:202100000E94C73688231CF0F701D08202C0F70110820C5F1F4F0894E11CF11C003111050D +:2021200009F76091AB077091AC078091AD079091AE0720E030E046E153E40E94C736181672 +:2021400064F480E090E0A6E1B3E48093AB079093AC07A093AD07B093AE076091AF07709117 +:20216000B0078091B1079091B20720E030E044E153E40E94C736181664F480E090E0A4E11F +:20218000B3E48093AF079093B007A093B107B093B2076091B3077091B4078091B5079091C9 +:2021A000B60720E030E048EC52E40E94C736181664F480E090E0A8ECB2E48093B3079093D9 +:2021C000B407A093B507B093B607AA24BB24F501E555F84FD501A554B84F60817181828185 +:2021E00093812D913D914D915C910E9413356B017C01F501EC5FF74F608371838283938328 +:2022000020E030E040E050E00E94C736181624F0F7FAF094F7F8F0948501075A184FF50151 +:20222000EF54FC4FC701B60120813181428153810E94CB360E94E935F8016083718382836F +:20224000938384E090E0A80EB91E90E1A916B10409F0BDCF8091CD049091CE040A9734F4FF +:202260008AE090E09093CE048093CD04A0900408B0900508C0900608D0900708C601B501D8 +:2022800020E030E040E050E00E94C736181654F0C601B50120E030E040E050E00E947835A1 +:2022A0008823BCF5609108087091090880910A0890910B0820E030E040E050E00E947835A9 +:2022C000882339F560910C0870910D0880910E0890910F0820E030E040E050E00E947835FC +:2022E0008823B9F4C601B50120E030E040E050E00E94C736181624F0D7FAD094D7F8D09460 +:20230000A0920008B0920108C0920208D092030810C1C601B50120E030E040E050E00E941F +:202320007835882309F060C0E0900808F090090800910A0810910B08C801B70120E030E033 +:2023400040E050E00E94C736181654F0C801B70120E030E040E050E00E9478358823E4F469 +:2023600060910C0870910D0880910E0890910F0820E030E040E050E00E947835882361F434 +:20238000C801B70120E030E040E050E00E94C73618160CF4C6C0C1C0C801B70120E030E0F7 +:2023A00040E050E00E9478358823F1F4E0900C08F0900D0800910E0810910F08C801B701F5 +:2023C00020E030E040E050E00E94C73618160CF4A8C0C801B70120E030E040E050E00E94E5 +:2023E000783588230CF499C0C601B50120E030E040E050E00E94C73618163CF1C601B501D8 +:2024000020E030E040E050E00E94783587FD1DC0E0900808F090090800910A0810910B0844 +:20242000C801B70120E030E040E050E00E94C73618165CF0C801B70120E030E040E050E0C1 +:202440000E94783588230CF04BC0E0900808F090090800910A0810910B08C601B501A601EF +:2024600095010E94CB365B016C01C801B701A80197010E94CB369B01AC01C601B5010E948D +:2024800014350E9432377B018C01A0900C08B0900D08C0900E08D0900F08C601B50120E0EC +:2024A00030E040E050E00E94C7361816D4F5C801B701A80197010E94CB367B018C01C601F1 +:2024C000B501A60195010E94CB369B01AC01C801B7010E9414350E9432377B018C0121C0BC +:2024E000E0901008F09011080091120810911308C801B70120E030E040E050E00E94C736D4 +:2025000018167CF0C801B70120E030E040E050E00E94783588230CF010C117FB109517F9B2 +:202520001095E0920008F092010800930208109303086091CD047091CE04882777FD8095D9 +:20254000982F0E94173620EC31EE44E65CE40E947C359B01AC016091000870910108809180 +:202560000208909103080E947C353B014C011A8A198AE989FA89E75AF84F80819181A2814F +:20258000B3810097A105B10509F463C0E989FA89EC5FF74FA080B180C280D380C601B5010B +:2025A00020E030E040E050E00E94C73618161CF48601750106C08601750117FB109517F957 +:2025C0001095C401B30120EC31EE44E65CE40E947C356B8B7C8B8D8B9E8BE989FA89EF5380 +:2025E000FC4F2080318042805380C801B7012B893C894D895E890E947C35A20191010E94C9 +:20260000C736181634F5C601B50120E030E040E050E00E94C736181624F0D7FAD094D7F8A4 +:20262000D094C401B301A20191010E947C357B018C01C601B5012B893C894D895E890E94D7 +:202640007C359B01AC01C801B7010E94CB363B014C01E989FA893496FA8BE98B709709F01B +:2026600088CFC301D4018093EF079093F007A093F107B093F207EE24FF24F701E75AF84F2B +:2026800060817181828193816115710581059105C1F087010552184F0E9415369B01AC011B +:2026A000C401B3010E947C3520E030E048EC52E40E94CB360E94E435F801608371838283A1 +:2026C000938384E090E0E80EF91E90E1E916F104A1F68091590790915A07A0915B07B09140 +:2026E0005C0789839A83AB83BC8380915D0790915E07A0915F07B09160078D839E83AF8344 +:20270000B8878091610790916207A0916307B091640789879A87AB87BC87809165079091EC +:202720006607A0916707B09168078D879E87AF87B88BCE0101960E94520866960FB6F8947C +:20274000DEBF0FBECDBFCF91DF911F910F91FF90EF90DF90CF90BF90AF909F908F907F909C +:202760006F905F904F903F902F9008950E948B3060934A0B70934B0B80934C0B90934D0B7E +:202780008091370790913807029759F587EC9BE00E942B2F60E071E00E94453387EC9BE020 +:2027A0000E942B2F6091390770913A070E94663487EC9BE00E942B2F64E071E00E944533D5 +:2027C00087EC9BE00E942B2FE0913907F0913A07EE0FFF1FEE53FB4F608171810E94453309 +:2027E00009C0E0911C0BF0911D0BEC5EF44F8081882341F487EC9BE00E942B2F67E071E0DF +:202800000E94743308950F931F9307EC1BE0C8010E942B2F0E94AA32C8010E942B2F6AE03E +:2028200071E00E944533C8010E942B2F4091F7075091F8076091F9077091FA074F5F5F4F6A +:202840006F4F7F4F0E9453340E94B6131F910F91089540911C0B50911D0B20E630E0B9019A +:20286000469F9001479F300D569F300D1124682F772767FD7095C9018C5E974F0E94D63A6E +:202880009C019093270B8093260B80E0232B09F081E008958091260B9091270B019660E0F1 +:2028A00070E00E941A3808951092C10B8091840B882321F080E89BE00E94DE2686E59BE0FE +:2028C00060E04FE10E94C024882339F487EC9BE00E942B2F62E171E027C082E69BE066E597 +:2028E0007BE041E00E946201882381F482E69BE066E57BE040E00E946201882339F487EC3E +:202900009BE00E942B2F6FE171E00EC080E89BE062E67BE00E94D629882349F487EC9BE0D4 +:202920000E942B2F62E371E00E947433089581E08093C10B0895AF92BF92CF92DF92EF925D +:20294000FF920F931F93CF93DF9387E40E942914882309F4CFC20E944A140E94E4356C31E3 +:20296000710509F4CFC06D3171056CF477FF02C00C94531E62307105A4F06430710511F0F1 +:202980000C94531E8BC06B35710509F497C26C35710509F497C26A35710511F00C94531EDB +:2029A0008AC2EBEBEE2EE7E0FE2E0BEA17E0C0E0D0E0FE01E853FB4F80810E94291488239B +:2029C00041F10E944A145B016C01FE01ED5CF84F8081882311F061E002C06091FB0770E07A +:2029E000882777FD8095982F0E941736F70120813181428153810E94CB369B01AC01C60154 +:202A0000B5010E941435F80160837183828393830AC0F70180819181A281B381F801808302 +:202A20009183A283B383219644E050E0E40EF51E0C5F1F4FC430D10509F0BBCF86E40E94E5 +:202A400029148823E9F00E944A140E94E4357B018C017093EC076093EB07B701882777FD3B +:202A60008095982F0E94173620E030E040E050E00E94C736181624F4F092CE04E092CD04AF +:202A80000E9450100E948B3060934A0B70934B0B80934C0B90934D0B0C94551E80E50E9437 +:202AA0002914882321F4AA24BB24650106C00E944A140E94E9355B016C0183E50E94291470 +:202AC000882361F00E944A1420E030E04AE754E40E94CB360E94E9355B016C010E948B30F8 +:202AE0007B018C01EA0CFB1C0C1D1D1D02C00E94F4060E948B306E157F0580079107B8F3D1 +:202B00000C94531E8091CD049091CE049093EE078093ED078091BB079091BC07A091BD0704 +:202B2000B091BE078093AB079093AC07A093AD07B093AE078091BF079091C007A091C1075D +:202B4000B091C2078093AF079093B007A093B107B093B2078091C3079091C407A091C5071D +:202B6000B091C6078093B3079093B407A093B507B093B6078091C7079091C807A091C907DD +:202B8000B091CA078093B7079093B807A093B907B093BA071092CE041092CD048091C804B5 +:202BA0000E942914882371F48091C9040E942914882341F48091CA040E942914882311F41B +:202BC00081E001C080E08093CC04882339F48091C8040E942914882309F466C00F2EF0E021 +:202BE000EF2EF0E0FF2EF0E00F2FF0E01F2FF02DE092BB07F092BC070093BD071093BE073A +:202C000080E090E0A1E6B3EC8093AB079093AC07A093AD07B093AE076091D1037091D203A9 +:202C20008091D3039091D4030E94E4357093CE046093CD040E945010E092BB07F092BC07E6 +:202C40000093BD071093BE0780E090E0A0EAB0E48093AB079093AC07A093AD07B093AE074D +:202C60000E94501080E090E0A0E2B1EC8093AB079093AC07A093AD07B093AE070E945010E7 +:202C8000E092BB07F092BC070093BD071093BE07E092AB07F092AC070093AD071093AE0704 +:202CA0001092CE041092CD048091CC04882339F48091C9040E942914882309F466C00F2EAC +:202CC000F0E0EF2EF0E0FF2EF0E00F2FF0E01F2FF02DE092BF07F092C0070093C107109342 +:202CE000C20780E090E0AEE5B3EC8093AF079093B007A093B107B093B2076091D5037091B5 +:202D0000D6038091D7039091D8030E94E4357093CE046093CD040E945010E092BF07F092E3 +:202D2000C0070093C1071093C20780E090E0A0EAB0E48093AF079093B007A093B107B09346 +:202D4000B2070E94501080E090E0A0E2B1EC8093AF079093B007A093B107B093B2070E949D +:202D60005010E092BF07F092C0070093C1071093C207E092AF07F092B0070093B10710935C +:202D8000B2071092CE041092CD048091CC04882339F48091CA040E942914882309F478C03C +:202DA0000F2EF0E0EF2EF0E0FF2EF0E00F2FF0E01F2FF02DE092C307F092C4070093C507BB +:202DC0001093C60780E090E0A6E1B3EC8093B3079093B407A093B507B093B6076091D90326 +:202DE0007091DA038091DB039091DC030E94E4357093CE046093CD040E945010E092C30774 +:202E0000F092C4070093C5071093C60780E090E0A0E0B0E48093B3079093B407A093B50718 +:202E2000B093B6070E94501080E090E0A0E2B1EC8093B3079093B407A093B507B093B60707 +:202E40000E94501089EC9BE060E070E00E943B2F282F30E0C901880F892F881F990B892B65 +:202E600011F020503140B901882777FD8095982F0E94173620E030E048EC52E40E947C35FB +:202E80006093C3077093C4078093C5079093C6078091ED079091EE079093CE048093CD04E4 +:202EA0000E948B3060934A0B70934B0B80934C0B90934D0BF8C61092FB07F5C681E080939E +:202EC000FB07F1C6C8ECD4E00BEB17E088810E942914882339F00E944A14F8016083718358 +:202EE0008283938321960C5F1F4FF4E0CC3CDF0769F7D9C68DE40E942914882309F4B6C6F2 +:202F00000E944A140E94E4356C35710509F44DC46D3571050CF045C06931710509F48FC15B +:202F20006A317105ECF46531710509F4FCC0663171056CF46530710509F4D7C064317105C4 +:202F400009F4DCC06430710509F0ADC674C06731710509F4F2C0683171050CF067C1E8C096 +:202F60006235710509F4E7C3633571056CF46B31710509F491C16B3171050CF468C16C31F6 +:202F8000710509F090C6C0C16435710509F4DAC3643571050CF4D2C36535710509F083C64C +:202FA000EEC36737710509F4A8C4683771050CF56B36710509F4B8C36C3671056CF4693627 +:202FC000710509F453C26A3671050CF083C36836710509F068C612C26237710509F434C4FE +:202FE0006337710509F421C46D36710509F05BC6CBC26A3C710509F4F1C46B3C71056CF4D4 +:203000006E3B710509F4ECC2693C710509F4BBC46C38710509F047C610C26D3C710509F441 +:203020006AC221E06D32720709F41DC56B3C710509F039C6FEC487EC9BE00E942B2F62E465 +:2030400071E00E94453387EC9BE00E942B2F60913707709138070E945E3487EC9BE00E94E8 +:203060002B2F64E071E00E94453387EC9BE00E942B2FE0913707F0913807EE0FFF1FE4549B +:20308000FB4F608171810E9474338091370790913807029709F007C687EC9BE00E942B2FD2 +:2030A00060E071E00E94453387EC9BE00E942B2F6091390770913A070E945E3487EC9BE0E6 +:2030C0000E942B2F64E071E00E94453387EC9BE00E942B2FE0913907F0913A07EE0FFF1FCD +:2030E000EE53FB4F60817181DCC5109238071092370710923A0710923907D5C587EC9BE0C3 +:203100000E942B2F65E471E00E94743380E89BE060E040E00E94D52A87EC9BE00E942B2F02 +:2031200065E571E0BEC51092C00B0E945414BBC51092C00B1092C10BB6C58091C10B88239C +:2031400009F4B1C51092C00B8CE99BE00E94DE268091260B9091270B04966AE270E00E948C +:20316000D63AFC01009711F0319710824091260B5091270B4C5F5F4F8CE99BE060E87BE04F +:2031800021E00E94242E882309F449C087EC9BE00E942B2F63E671E00E94453387EC9BE0FD +:2031A0000E942B2F6091260B7091270B6C5F7F4F0E94453387EC9BE00E942B2F60E771E089 +:2031C0000E94453387EC9BE00E942B2F4091AE0B5091AF0B6091B00B7091B10B0E941B346C +:2031E0001092BC0B1092BD0B1092BE0B1092BF0B8091AE0B9091AF0BA091B00BB091B10B97 +:203200008093B80B9093B90BA093BA0BB093BB0B87EC9BE00E942B2F67E771E042C587ECED +:203220009BE00E942B2F65E871E03BC58091C10B882309F438C581E08093C00B34C58091AE +:20324000C00B882309F42FC51092C00B2CC58091C10B882309F427C583E50E942914882346 +:2032600009F421C58091260B9091270B019660E070E04AE050E00E947A39AB01BC014093C4 +:20328000BC0B5093BD0B8093BE0B7093BF0B8CE99BE00E94D02507C58091C10B882369F1DE +:2032A00087EC9BE00E942B2F66E971E00E94453387EC9BE00E942B2F4091BC0B5091BD0B3F +:2032C0006091BE0B7091BF0B0E94173487EC9BE00E942B2F68EA71E00E94453387EC9BE0E7 +:2032E0000E942B2F4091B80B5091B90B6091BA0B7091BB0B0E941B34D6C487EC9BE00E9401 +:203300002B2F6AEA71E0CDC48091C10B882309F4CAC48CE99BE00E94DE261092C00B8091F6 +:20332000260B9091270B04966AE270E00E94D63AEC01009709F120911C0B30911D0B80E67C +:2033400090E0AC01249FC001259F900D349F900D11248C5E974F6EE470E00E94D63A60E260 +:2033600070E00E94D63A9C012F5F3F4F3093270B2093260B219718824091260B5091270B52 +:203380004C5F5F4F8CE99BE060E87BE026E50E94242E8823E9F487EC9BE00E942B2F6AEB7B +:2033A00071E00E94453387EC9BE00E942B2F6091260B7091270B6C5F7F4F0E94453387EC3D +:2033C0009BE00E942B2F6EEC71E00E9445336BC481E08093C20B87EC9BE00E942B2F60ED0A +:2033E00071E00E94453387EC9BE00E942B2F6091260B7091270B6C5F7F4F53C483E50E9469 +:203400002914882391F00E944A140E94E435DC01CB0164E474E04EE150E021E030E00E9431 +:20342000BB059093290B8093280B8091390790913A07019709F037C4D0C083E50E94291419 +:20344000882309F430C40E944A140E94E435DC01CB0160ED74E044E150E021E030E00E94C3 +:20346000BB0590932D0B80932C0B1DC480912A0B90912B0B64E474E04EE150E021E030E05D +:203480000E9418069093310B8093300B80912E0B90912F0B60ED74E044E150E021E030E013 +:2034A0000E9418069093330B8093320B87EC9BE00E942B2F62EE71E00E94453387EC9BE008 +:2034C0000E942B2F6091300B7091310B0E945E3487EC9BE00E942B2F68EE71E00E944533A8 +:2034E00087EC9BE00E942B2F6091320B7091330B0E946634DAC387EC9BE00E942B2F6CEE58 +:2035000071E00E94453387EC9BE00E942B2F60913E0B70913F0B0E945E3487EC9BE00E940D +:203520002B2F62EF71E00E94453387EC9BE00E942B2F6091380B7091390B0E945E3487EC6B +:203540009BE00E942B2F67EF71E00E94453387EC9BE00E942B2F60913A0B70913B0B0E942A +:203560005E3487EC9BE00E942B2F6CEF71E00E94453387EC9BE00E942B2F60913C0B7091E6 +:203580003D0B0E945E3491C383E50E942914882321F10E944A147B018C0160914204709116 +:2035A0004304882777FD8095982F0E9417369B01AC01C801B7010E9413350E94E435DC018A +:2035C000CB0164E474E04EE150E021E030E00E94BB059093290B8093280B0E94320863C312 +:2035E00083E50E942914882391F00E944A140E94E435DC01CB0164E474E04EE150E021E0F8 +:2036000030E00E94BB0590932D0B80932C0B0E948B307B018C0151C00E948B306E197F09B0 +:20362000800B910B695E73408040904008F443C080912A0B90912B0B64E474E04EE150E0C2 +:2036400021E030E00E9418069093310B8093300B87EC9BE00E942B2F61E072E00E94453355 +:2036600087EC9BE00E942B2F6091300B7091310B0E945E3487EC9BE00E942B2F68EE71E032 +:203680000E94453387EC9BE00E942B2F8C0180912E0B90912F0B64E474E04EE150E021E0F8 +:2036A00030E00E941806BC01C8010E9466340E948B307B018C010E94F40620912E0B3091CB +:2036C0002F0B80912C0B90912D0B281739070CF4A3CFE9C283E50E942914882319F15C9A81 +:2036E0000E944A1420E030E040E050E00E94783588231CF460E070E011C00E944A1420E0FF +:2037000030E04FE753E40E94C73618161CF46FEF70E004C00E944A140E94E4358CE00E9414 +:203720005D2FC1C25C9ABFC28CE060E070E00E945D2F5C98B8C210923607B5C281E08093A1 +:203740003607B1C283E50E942914882399F00E944A1420E030E04AE754E40E94CB360E9480 +:20376000E9356093520B7093530B8093540B9093550B99C25E9A5E9A159A5E9A94C283E5D5 +:203780000E9429140E944A1420E030E04AE754E40E94CB360E94E93560934E0B70934F0BC5 +:2037A0008093500B9093510B7EC2C8ECD4E001EB13E088810E942914882339F00E944A14D9 +:2037C000F801608371838283938321960C5F1F4FF4E0CC3CDF0769F7C0E0D0E08E0107590D +:2037E000184FFE01E352FC4FDE01AF54BC4F60817181828193812D913D914D915C910E9413 +:20380000CB369B01AC0160E27CEB8EEB9CE40E947C350E94E935F8016083718382839383BE +:203820002496C031D105D1F63EC287EC9BE00E942B2F64E072E00E94453387EC9BE00E9416 +:203840002B2F6DE074E02DC287EC9BE00E942B2F6CE172E00E94453387EC9BE00E942B2FF1 +:203860004091BB075091BC076091BD077091BE070E94FD3487EC9BE00E942B2F6FE172E037 +:203880000E94453387EC9BE00E942B2F4091BF075091C0076091C1077091C2070E94FD348F +:2038A00087EC9BE00E942B2F62E272E00E94453387EC9BE00E942B2F4091C3075091C4073D +:2038C0006091C5077091C6070E94FD3487EC9BE00E942B2F65E272E00E94453387EC9BE0FF +:2038E0000E942B2F4091C7075091C8076091C9077091CA070E940135D6C187EC9BE00E94EB +:203900002B2F68E272E00E94453387EC9BE00E942B2F329903C06FE272E002C062E372E023 +:203920000E94453387EC9BE00E942B2F65E372E00E94453387EC9BE00E942B2F339903C056 +:203940006FE272E002C062E372E00E94453387EC9BE00E942B2F6CE372E00E94453387EC39 +:203960009BE00E942B2F349903C06FE272E002C062E372E00E94453387EC9BE00E942B2F40 +:2039800063E472E08EC148ECE42E44E0F42EC0E0D0E0F70180810E9429148823A9F00E94A5 +:2039A0004A148E010758184FFE01EF54FC4F20813181428153810E94CB360E94E935F80181 +:2039C00060837183828393830894E11CF11C2496FCECEF16F4E0FF06E1F665C138ECE32E9D +:2039E00034E0F32EC0E0D0E0F70180810E9429148823A9F00E944A148E010757184FFE01D3 +:203A0000EF54FC4F20813181428153810E94CB360E94E935F8016083718382839383089444 +:203A2000E11CF11C2496FCECEF16F4E0FF06E1F63AC18AE50E942914882309F434C10E949D +:203A40004A1420E030E048EC52E40E94CB360E94E9359B01AC0189EC9BE060E070E0422FF1 +:203A60000E94362F20C180E50E942914882351F00E944A1460933604709337048093380474 +:203A80009093390489E40E942914882351F00E944A1460933A0470933B0480933C049093A5 +:203AA0003D0484E40E942914882351F00E944A1460933E0470933F04809340049093410458 +:203AC00086E40E942914882341F00E944A140E94E43570933304609332048AE50E94291455 +:203AE000882341F00E944A140E94E435709343046093420487E50E942914882341F00E94E3 +:203B00004A140E94E435709335046093340487EC9BE00E942B2F64E472E00E94453387EC14 +:203B20009BE00E942B2F409136045091370460913804709139040E94013587EC9BE00E9414 +:203B40002B2F68E472E00E94453387EC9BE00E942B2F40913A0450913B0460913C04709108 +:203B60003D040E94013587EC9BE00E942B2F6CE472E00E94453387EC9BE00E942B2F4091CB +:203B80003E0450913F0460914004709141040E94013587EC9BE00E942B2F60E572E00E9449 +:203BA000453387EC9BE00E942B2F60913204709133040E94663487EC9BE00E942B2F69E5D0 +:203BC00072E00E94453387EC9BE00E942B2F60913404709135040E94663487EC9BE00E9460 +:203BE0002B2F64E672E00E94453387EC9BE00E942B2F60914204709143040E946634E090A0 +:203C00003404F0903504662777276E197F09882777FD8095982F0E94173620913A043091DB +:203C20003B0440913C0450913D040E947C350E94E4357093430B6093420B0027F7FC0095C4 +:203C4000102FC801B7010E94173620913A0430913B0440913C0450913D040E947C350E949E +:203C6000E4357093450B6093440B1DC087EC9BE00E942B2F6BE672E00E94743387EC9BE0F5 +:203C80000E942B2F40911C0B50911D0B20E630E0429FB001439F700D529F700D11246C5EB3 +:203CA000774F0E9474330E94B613DF91CF911F910F91FF90EF90DF90CF90BF90AF90089563 +:203CC000AF92BF92CF92DF92EF92FF920F931F93DF93CF930F92CDB7DEB78091200B90912F +:203CE000210B03970CF47AC16CC24D3051F04A3341F02091230B3091240B2F3531050CF4C0 +:203D00004EC1E091230BF091240B309709F459C2A0911E0BB0911F0BAC9D7001AD9DF00CA1 +:203D2000BC9DF00C1124EE0DFF1DEC5EF74F10828091250B882309F02BC1AC5EB44F1C9234 +:203D400087010C5E174FC8016EE470E00E94D63A9C01009709F4B0C09093270B8093260BB4 +:203D60002F5F3F4F201B310B2E0D3F1DC9018C5E974F60E070E04AE050E00E947A3960934D +:203D8000F3077093F4078093F5079093F6072091F7073091F8074091F9075091FA072F5F4C +:203DA0003F4F4F4F5F4F6217730784079507D9F080911E0B90911F0B9C012C9DC0012D9DD0 +:203DC000900D3C9D900D11248C5E974F6CE772E00E94E13A009739F487EC9BE00E942B2FBB +:203DE00061E872E03AC080911E0B90911F0B8C9D80018D9D100D9C9D100D1124C8018C5E7A +:203E0000974F6AE270E00E94D63A9C010097E1F140E0FF24C80102C0FE264F5FFC01E40FD8 +:203E2000F11DEC5EF74FE081EA32B1F73093270B2093260BC901019660E070E00E941A3801 +:203E40000E94E4352F2D30E02617370721F187EC9BE00E942B2F61EC72E00E94453387EC98 +:203E60009BE00E942B2F4091F7075091F8076091F9077091FA070E9453340E9403141092A5 +:203E8000240B1092230B9DC187EC9BE00E942B2F66EE72E0E2CF8091F3079091F407A0912C +:203EA000F507B091F6078093F7079093F807A093F907B093FA071EC0C8016AE270E00E9439 +:203EC000D63A0097B9F087EC9BE00E942B2F66E173E00E94453387EC9BE00E942B2F409139 +:203EE000F7075091F8076091F9077091FA070E945334C5CF80911E0B90911F0B8C9D700115 +:203F00008D9DF00C9C9DF00C112487010C5E174FC80167E470E00E94D63A9C01009711F16D +:203F20009093270B8093260B2F5F3F4F201B310B2E0D3F1DC9018C5E974F60E070E00E94F2 +:203F40001A380E94E4356230710560F48091C20B882341F487EC9BE00E942B2F67E071E0B8 +:203F60000E94743380911E0B90911F0B019668E070E00E94B03790931F0B80931E0B809121 +:203F8000200B9091210B01969093210B8093200B1092250B1092240B1092230B24C04B33B0 +:203FA00011F4B092250B8091250B8823E1F480911E0B90911F0B8C9DF0018D9DF00D9C9DCA +:203FC000F00D1124E20FF31FEC5EF74F40832F5F3F4F3093240B2093230B05C0A0E6CA2E27 +:203FE000D12CBB24B39487EC9BE00E942B2F0E946E32882309F4D2C18091200B9091210BAE +:2040000008970CF0CBC187EC9BE00E942B2F0E948232482F8093220B8A3009F066CE71CE5C +:204020008091230B9091240B892B09F0CAC0A5C08CE99BE0B70141E050E00E94B527019746 +:2040400019F08FEF9FEF02C0898190E09093C40B8093C30B482F8093220B8A3079F08D30A5 +:2040600069F08A3359F02091230B3091240B2F35310524F48F5F9F4F09F060C02091A50B0A +:204080003091A60B4091A70B5091A80B2093BC0B3093BD0B4093BE0B5093BF0B8091B80B75 +:2040A0009091B90BA091BA0BB091BB0B281739074A075B0750F01092C00B87EC9BE00E94AF +:2040C0002B2F66E473E00E9474338091230B9091240B009709F475C020911E0B30911F0B83 +:2040E000209FF001219FF00D309FF00D1124E80FF91FEC5EF74F10828091250B8823B9F488 +:20410000F901EC5EF44FD0828091200B9091210B01969093210B8093200BC901019668E070 +:2041200070E00E94B03790931F0B80931E0B1092250B1092240B1092230B27C08B3311F400 +:20414000D092250B8091250B8823F9F480911E0B90911F0B809FF001819FF00D909FF00D16 +:204160001124E20FF31FEC5EF74F40832F5F3F4F3093240B2093230B08C07E010894E11CE5 +:20418000F11C00E610E0DD24D3942091B80B3091B90B4091BA0B5091BB0B8091BC0B9091A5 +:2041A000BD0BA091BE0BB091BF0B82179307A407B50738F48091200B9091210B08970CF444 +:2041C00037CF8091200B9091210B892B09F491C08091C20B882309F474C020911C0B3091FB +:2041E0001D0B80E690E0289F5001299FB00C389FB00C1124F4E1CF2EF8E0DF2ECA0CDB1CD9 +:20420000C60169E573E00E94E13A009709F046C0D6010D900020E9F77D010894E108F10873 +:20422000EC18FD0810929E0BC6016EE470E00E94D63A8C01009731F4F501EE0DFF1DED5E6E +:20424000F74F0FC060E270E00E94D63A6C010894C11CD11CC8016AE270E00E94D63AFC011E +:2042600031978DE081838AE0828313828CE99BE0B6010E94A42D80919E0B882341F087ECDE +:204280009BE00E942B2F6DE573E00E94743387EC9BE00E942B2F67E071E010C08CE99BE077 +:2042A0000E9496268CE99BE00E94DE261092C20B87EC9BE00E942B2F63E773E00E947433CB +:2042C00002C00E949B148091200B9091210B01979093210B8093200B80911C0B90911D0B9C +:2042E000019668E070E00E94B03790931D0B80931C0B0E94F4060E948B30E0904E0BF0903F +:204300004F0B0091500B1091510B20914A0B30914B0B40914C0B50914D0B621B730B840B52 +:20432000950BE616F7060807190798F4E114F1040105110571F01092290B1092280B5D9822 +:2043400010922D0B10922C0B5A985E9A5E9A159A5E9A0E948B30E090520BF090530B009188 +:20436000540B1091550B20914A0B30914B0B40914C0B50914D0B621B730B840B950BE61639 +:20438000F7060807190780F4E114F1040105110559F05E9A5E9A159A5E9A06C08091C00BF5 +:2043A000882309F40ECF3CCE0F90CF91DF911F910F91FF90EF90DF90CF90BF90AF900895A8 +:2043C000CF92DF92EF92FF920F931F93CF93DF938EED9CE040E052EC61E070E00E947531A3 +:2043E0008EED9CE065E873E00E947433E4E1FBE011928BE0EC31F807D9F70C9A149A3D9A18 +:204400003F9A229A209A569A5E9A569A5E9A0D9A159A569A5E9A3A98429A3B98439A3C980D +:20442000449A549A5C9A559A529A579A3E9A239A219AC0E0D0E0FE01EF54FC4FE080F180F0 +:204440000281138199E6C92E97E0D92ECC0EDD1EFE01E352FC4FC801B70120813181428166 +:2044600053810E94CB369B01AC0160E27CEB8EEB9CE40E947C350E94E935F60160837183F9 +:204480008283938389E7C82E87E0D82ECC0EDD1EFE01E351FC4F60817181828193810E944F +:2044A0001736A80197010E94CB360E94E935F6016083718382839383B9E8CB2EB7E0DB2EE8 +:2044C000CC0EDD1EFE01E350FC4F60817181828193810E941736A80197010E94CB360E942B +:2044E000E935F60160837183828393832496C031D10509F0A0CF0E945414DF91CF911F9142 +:204500000F91FF90EF90DF90CF900895FC01673020F086E1858380E00895262F30E060FDB0 +:2045200002C0663019F48DB58E7F02C08DB581608DBD8CB58C7F8CBD4CB522FD02C090E0B1 +:2045400001C092E036952795822F8170842B892B8CBD81E00895FF920F931F93CF93DF939C +:204560008B010E948B30EB01FF24FA94FEBC0DB407FEFDCF8EB58F3F11F481E008C00E9488 +:204580008B306C1B7D0B6017710780F380E0DF91CF911F910F91FF900895FC01848160E001 +:2045A0000E94D02F0895FC01848161E00E94D02F0895DC016EBDFA0120E030E00DB407FE63 +:2045C000FDCF80818EBD0DB407FEFDCF81818EBD2E5F3F4F329682E02030380779F70DB4DF +:2045E00007FEFDCF8FEF8EBD0DB407FEFDCF8FEF8EBD0DB407FEFDCF8FEF8EBD0DB407FEA5 +:20460000FDCF8EB51A968C931A978F71853011F481E0089581E115968C931597CD010E940B +:20462000D32280E00895FF920F931F93CF93DF93EC010E948B308B01FF24FA9409C00E94DD +:204640008B30601B710B6D52714010F08FE00DC0FEBC0DB407FEFDCF8EB58A878F3F79F322 +:204660008E3F11F481E006C08DE08D83CE010E94D32280E0DF91CF911F910F91FF900895B2 +:20468000CF93DF93EC018E818823D1F08FEF8EBD2F8138854FEF04C00DB407FEFDCF4EBD09 +:2046A0002F5F3F4FC901019781509240A8F338872F830DB407FEFDCFCE010E94D3221E8235 +:2046C000DF91CF910895DF92EF92FF920F931F93CF93DF93EC01D62E79018A010E944023C7 +:2046E000CE010E94CD22CE016CE271E00E94AB228D2D80648EBD0DB407FEFDCF28E130E0E9 +:20470000D801C701022E04C0B695A795979587950A94D2F78EBD0DB407FEFDCF2850304009 +:204720008FEF283F380761F7DD2011F485E906C088E0D81611F487E801C08FEF8EBD0DB4B2 +:2047400007FEFDCF90E02FEF2EBD0DB407FEFDCF8EB587FF02C09150B9F78A87DF91CF9180 +:204760001F910F91FF90EF90DF900895CF92DF92EF92FF920F931F93CF93DF93EC017A015B +:204780008B016901411551056105710511F482E137C08B85833039F029E0EE0CFF1C001F13 +:2047A000111F2A95D1F7CE0168E1A80197010E946323882311F084E023C0CE016EEFA601FB +:2047C0000E94D9228823E9F0CE0168E572E00E94AB22882311F485E113C0CE016DE020E0D6 +:2047E00030E040E050E00E946323882341F48FEF8EBD0DB407FEFDCF8EB5882379F084E13A +:204800008D83CE010E94D32280E0DF91CF911F910F91FF90EF90DF90CF900895CE010E94B8 +:20482000D32281E0F2CF8F929F92AF92BF92CF92DF92EF92FF920F931F93CF93DF93EC0184 +:204840005A016B0149010115110509F47BC0C801820F931F8150924008F06FC08E81882353 +:2048600071F088819981AA81BB81481759076A077B0729F48F8198858816990618F5A882DD +:20488000B982CA82DB828B85833039F069E0AA0CBB1CCC1CDD1C6A95D1F7CE0161E1A60112 +:2048A00095010E946323882319F083E08D8345C0CE010E941323882309F43FC018861F8281 +:2048C00081E08E838FEF8EBD8F8198852FEF05C00DB407FEFDCF2EBD019688159905C0F38B +:2048E00098878F83D801119720E030E09FEF0BC00DB407FEFDCF8EB5F701E20FF31F8083CA +:204900009EBD2F5F3F4F2A173B0790F30DB407FEFDCF8EB5AE0DBF1D8C932F813885200FF3 +:20492000311F38872F838985882319F02050324048F0CE010E94402305C0CE010E94D322DB +:2049400080E001C081E0DF91CF911F910F91FF90EF90DF90CF90BF90AF909F908F90089560 +:20496000EF92FF920F931F93790120E030E000E012E00E9413241F910F91FF90EF900895A1 +:20498000BF92CF92DF92EF92FF920F931F93CF93DF93EC01B62E1B8619861E821D824C839B +:2049A0000E948B306B018C8161E00E94B22FCE010E94D32286E060E00E94B22F85E061E028 +:2049C0000E94B22F87E061E00E94B22F84E061E00E94B22F83E58CBD8DB58E7F8DBD80E057 +:2049E0009FEF9EBD0DB407FEFDCF8F5F8A30C9F7CE010E94CD2209C00E948B306C197D0943 +:204A0000615D774010F081E05EC0CE0160E020E030E040E050E00E946323182F8A87813002 +:204A200059F7CE0168E02AEA31E040E050E00E94632382FF02C01B8711C080E02FEF2EBD53 +:204A40000DB407FEFDCF9EB58F5F8430C1F79A879A3A11F082E037C082E08B878B85823092 +:204A600021F0EE24FF2487010FC0E12CF12C012D70E4172F09C00E948B306C197D09615DB8 +:204A8000774010F088E01FC0CE0167E320E030E040E050E00E946323CE0169E2A80197011C +:204AA0000E9463238A87882331F78B85823031F5CE016AE320E030E040E050E00E9463235E +:204AC000882339F086E08D83CE010E94D32280E01CC08FEF8EBD0DB407FEFDCF8EB5807C50 +:204AE000803C11F483E08B8780E09FEF9EBD0DB407FEFDCF2EB58F5F8330C1F7CE010E94F8 +:204B0000D322CE016B2D0E948622DF91CF911F910F91FF90EF90DF90CF90BF900895CF93A5 +:204B2000DF93EC01DB0180E090E020E2FD01E80FF91F208301968B309105C1F757E040E0C1 +:204B400021C02E3219F08CE790E007C05A3019F15AE048E017C03217F1F0FC010196349111 +:204B60003323C9F75417B8F02132A8F02F3798F4822F81568A3108F42052FD01E40FF11D7F +:204B800020834F5F29912223E1F690E08C91803219F091E001C090E0892FDF91CF910895DF +:204BA0006F927F928F929F92AF92BF92CF92DF92EF92FF920F931F93CF93DF93EC017A018B +:204BC0008B012C81222309F480C08A899B89AC89BD8984179507A607B70708F476C085C04F +:204BE000E114F1040105110549F41D821E821F82188619861A861B861C8665C029853A85E0 +:204C00004B855C85EA8DFB8D858590E00996215030404040504039014A01082E04C0969431 +:204C20008794779467940A94D2F72F5F3F4F4F4F5F4F0894E108F108010911095701680121 +:204C400004C0D694C794B794A7948A95D2F70894E11CF11C011D111DA614B704C804D9044D +:204C600028F0211531054105510549F48E899F89A88DB98D8D839E83AF83B88716C0A618E7 +:204C8000B708C808D90811C04D815E816F8178858A8D9B8D94010E9443030894A108B1087F +:204CA000C108D108882331F410C085E0882E912C8C0E9D1EA114B104C104D10429F7E986F2 +:204CC000FA860B871C8781E001C080E0DF91CF911F910F91FF90EF90DF90CF90BF90AF9013 +:204CE0009F908F907F906F900895223009F078CFE6CFCF93DF93EC01462F6D857E858F8535 +:204D000098890E942701882319F420E030E00AC08989282F30E095E0220F331F9A95E1F79E +:204D2000245D3A4FC901DF91CF9108950F931F93CF93DF938C01FC0184818823C9F1838112 +:204D400087FF33C0C80161E00E947926EC01009779F1F8018481823040F482899389A48969 +:204D6000B5898C8F9D8FAE8FBF8FF80186899789A08DB18D9B8F8A8FCD01AA27BB279D8BA4 +:204D80008C8BE091C50BF091C60B309751F0BE016A5E7F4FCE0148960995888D998D9B8B60 +:204DA0008A8BF80183818F7783830E94C80001C080E0DF91CF911F910F910895CF93DF93B9 +:204DC000EC010E949626882311F01C8281E0DF91CF9108956F927F928F929F92AF92BF927A +:204DE000CF92DF92EF92FF920F931F93DF93CF9300D000D0CDB7DEB77C015A016B01DC01CD +:204E000014968C911497813009F08FC013968C9181FF8BC09EC00097A105B10511F481E0DF +:204E200085C0F7016184728483849484C701B601A5010E94D025882309F477C0D7015A96D8 +:204E40008D919C915B97A114B104C104D10489F456964D915D916D917C9159970E94B60386 +:204E6000882309F462C0F701168A178A108E118E3DC0D70115964D915D916D917C911897EC +:204E80009E012F5F3F4F0E944303882309F44DC0D7015A96ED91FC915B9749815A816B8164 +:204EA0007C818789803129F088EF9FEFAFEFBFE004C088EF9FEFA0E0B0E0481759076A07D0 +:204EC0007B07A0F4CF010E94B603882371F1F7014581568167817085828D938D0FEF1FEFD7 +:204EE0002FEF3FE00E94A7028823F9F0D7015296AD92BD92CD92DC92559713968C9113971F +:204F0000806813968C93C7010E949626882369F0B601A5016A147B048C049D0410F4B40173 +:204F2000A301C7010E94D02501C080E00F900F900F900F90CF91DF911F910F91FF90EF90A3 +:204F4000DF90CF90BF90AF909F908F907F906F900895F70182899389A489B589841795073B +:204F6000A607B70708F057CFE0CF2F923F924F925F926F927F928F929F92AF92BF92CF923E +:204F8000DF92EF92FF920F931F93CF93DF93EC012A018C81882309F4C6C08B8180FFC3C005 +:204FA000D8C025014E185F084B0175E0272E312C2C0E3D1E3201B1C029853A854B855C85BC +:204FC0006FEFA62E61E0B62EA222B3228C8179018A0199E016950795F794E7949A95D1F712 +:204FE000EA8DFB8D823049F4428D538D648D758D4E0D5F1D601F711F3FC0D480DA94DE207C +:20500000A114B104D9F4DD20C9F4211531054105510549F48E899F89A88DB98D8D839E836F +:20502000AF83B8870BC04D815E816F817885CF0191010E944303882309F475C0EA8DFB8D74 +:205040004D815E816F8178854250504060407040058404C0440F551F661F771F0A94D2F7AE +:2050600086859785A089B189480F591F6A1F7B1F4D0D511D611D711D80E092E08A199B09C7 +:2050800063018615970508F46C018B8186FD06C080E0C81682E0D80609F073C08091AD034C +:2050A0009091AE03A091AF03B091B003481759076A077B0709F465C080912C0790912D07DA +:2050C0009501860174010E941324882361F18C0C9D1C12C09501245D3A4FA9014C0D5D1D28 +:2050E000D401F90102C081918D93E417F507D9F7E21BF30B8E0E9F1E960140E050E08985DD +:205100009A85AB85BC85820F931FA41FB51F89879A87AB87BC876C187D086114710409F093 +:205120004BCFA20102C04FEF5FEFCA01DF91CF911F910F91FF90EF90DF90CF90BF90AF900F +:205140009F908F907F906F905F904F903F902F900895AA88BB88CC88DD88E984FA840B8551 +:205160001C859A0140E050E0D601C5018E199F09A00BB10B82179307A407B50708F411CFDA +:2051800013CFCB01BA0140E00E942701882309F0A1CFC9CFCF92DF92EF92FF920F931F93D8 +:2051A000DF93CF930F92CDB7DEB76C01FC018481823070F0E184F28403851485C601BE015E +:2051C0006F5F7F4F41E050E00E94B527019769F020E030E0C9010F90CF91DF911F910F91DA +:2051E000FF90EF90DF90CF900895F60181859285A385B4854F96A11DB11D81879287A38705 +:20520000B487F5E016950795F794E794FA95D1F78E2D8F70282F30E0E5E0220F331FEA95F2 +:20522000E1F7245D3A4FD6CFDF93CF9300D00F92CDB7DEB7282F6AE00E94A437805D898382 +:20524000822F0E94A437905D9A831B8287EC9BE00E942B2FBE016F5F7F4F0E9445330F907B +:205260000F900F90CF91DF910895EF92FF920F931F938C01812F8695869586950E941429B0 +:20528000B7ECEB2EBBE0FB2EC7010E942B2F6AE30E943D33C801A5E096958795AA95E1F7BF +:2052A0008F730E941429C7010E942B2F6AE30E943D330F711070802F880F0E9414291F9115 +:2052C0000F91FF90EF900895EF92FF920F931F937C0107EC1BE0C8010E942B2FB701672F9F +:2052E000772766956454784F0E942634C8010E942B2F6DE20E943D33C70125E09695879560 +:205300002A95E1F78F700E941429C8010E942B2F6DE20E943D338E2D8F710E9414291F91A8 +:205320000F91FF90EF900895DF92EF92FF920F931F93CF93DF937C01D62EEC0110E000E039 +:205340008881803291F0083041F487EC9BE00E942B2F6EE20E943D331F5F87EC9BE00E944A +:205360002B2F68810E9435331F5F0F5F21960B3039F7F70183858871803171F487EC9BE0D5 +:205380000E942B2F6FE205C087EC9BE00E942B2F60E20E943D331F5F1D15B0F3DF91CF919A +:2053A0001F910F91FF90EF90DF9008950F931F93CF93DF93EC018B018C81882309F041C030 +:2053C000FB0187898031B1F482E08C831E8A1F8A188E198E808D918DA0E0B0E045E0880F65 +:2053E000991FAA1FBB1F4A95D1F78A8B9B8BAC8BBD8B15C0803229F583E08C83FB01428D0F +:20540000538D648D758D4E8B5F8B688F798F9E012E5E3F4FC8010E940F04882391F01B8FEA +:205420000A8F81E08B831D821E821F82188619861A861B861C861D861E861F86188A198A33 +:2054400001C080E0DF91CF911F910F9108951F93CF93DF93EC01142FE62FF0E075E0EE0F81 +:20546000FF1F7A95E1F7E45DFA4F8385817121F0842F827409F054C0698B8091AD03909106 +:20548000AE03A091AF03B091B0038D879E87AF87B88B84899589A0E0B0E0BC0155274427F3 +:2054A000828D938DA0E0B0E0482B592B6A2B7B2B4E8B5F8B688F798F838590E08871907048 +:2054C000009751F4848D958DA68DB78D8A8B9B8BAC8BBD8B81E00CC0409711F59E012E5E57 +:2054E0003F4F8A8D9B8D0E940F048823C9F084E08C83812F8F708B831D821E821F82188618 +:2055000019861A861B861C8616FD02C081E009C0CE0140E050E060E070E00E94EA2601C0E8 +:2055200080E0DF91CF911F910895DF92EF92FF920F931F93CF93DF938C01EB017A01D22E4F +:20554000FC018481882341F5822F8073803321F18A8D9B8D938F828FE5E0440F551FEA9582 +:20556000E1F760E070E0CE010E94D0258823A1F0CE010E94CA28FC01009771F0808188231D +:2055800059F0853E49F08E3239F06E2D6F70C8014D2D0E94272A01C080E0DF91CF911F918C +:2055A0000F91FF90EF90DF9008952F923F924F925F926F927F928F929F92AF92BF92CF9276 +:2055C000DF92EF92FF920F931F93DF93CF93CDB7DEB76E970FB6F894DEBF0FBECDBF6C014E +:2055E0006D8FE42EFC0115821682178210861186128613861486862F90E063E0462E512C87 +:205600004822592251E0652E712C6822792244E0842E912C882299221E010894211C311CE2 +:205620002E2D2E5F2E8F32E0A32EB12CA822B9228BC0F8018081882309F48DC0853E09F466 +:2056400083C08E3209F480C0838583FD7DC0FF2408C087EC9BE00E942B2F60E20E943D331C +:20566000F394FE14B1F74114510411F460E001C06EE0C8010E9494296114710489F0F80167 +:20568000808D918D0E94642987EC9BE00E942B2F60E20E943D33F801868997890E9435294A +:2056A000F801838588718031A9F0A114B10491F087EC9BE00E942B2F60E20E943D3387EC0A +:2056C0009BE00E942B2FF801448D558D668D778D0E94173487EC9BE00E942B2F0E945D33A7 +:2056E0008114910489F1F80183858871803161F5F60181859285A385B48525E0B695A79504 +:20570000979587952A95D1F78C0184E295E09A8389831D82A80141505040C101B60121E046 +:205720000E94952A882329F0C1016D8D4E8D0E94D52A85E0000F111F8A95E1F7A80160E088 +:2057400070E0C6010E94D025C6010E94CA288C01009709F06ECF6E960FB6F894DEBF0FBE27 +:20576000CDBFCF91DF911F910F91FF90EF90DF90CF90BF90AF909F908F907F906F905F90C8 +:205780004F903F902F900895CF93DF93EC019C012B5F3F4F8A8D9B8D41E050E060E070E069 +:2057A0000E947E048823A1F08E899F89A88DB98D0097A105B10559F48D819E81AF81B885F5 +:2057C0008E8B9F8BA88FB98F8B8180688B8381E0DF91CF9108952F923F924F925F927F92C2 +:2057E0008F929F92AF92BF92CF92DF92EF92FF920F931F93DF93CF9300D000D000D0CDB7C5 +:20580000DEB76C01162F072F5E834D83DC0114968C911497813009F075C113968C9181FFE5 +:2058200071C18FC1F601428953896489758981859285A385B48584179507A607B70731F01C +:20584000C6010E94D025882309F45CC1812F902F9C0129012D803E8019C1D6015A96ED9165 +:20586000FC915B97DA01C90119E0B695A795979587951A95D1F774807A9478227FEF872E06 +:2058800071E0972E82229322772009F050C08114910409F04CC0D60115964D915D916D917E +:2058A0007C911897411551056105710581F456968D919D910D90BC91A02D0097A105B1054D +:2058C00059F1F60185839683A783B08730C0CF019E012F5F3F4F0E944303882319F440E0CA +:2058E00050E016C129813A814B815C81D6015A96ED91FC915B978789803129F088EF9FEFF0 +:20590000AFEFBFE004C088EF9FEFA0E0B0E0281739074A075B0730F0C6010E94C42B88231C +:2059200031F4F0C0F601258336834783508780E092E08819990951018215930508F45C01AA +:20594000D6015A96ED91FC915B971596ED90FD900D911C9118978EEF9FEFAFEFBFEFE80E87 +:20596000F91E0A1F1B1F058404C0EE0CFF1C001F111F0A94D2F786859785A089B189E80E15 +:20598000F91E0A1F1B1FE70CF11C011D111D90E0A91692E0B90651F58091AD039091AE0308 +:2059A000A091AF03B091B0038E159F05A007B10761F48FEF9FEFAFEFBFEF8093AD039093D7 +:2059C000AE03A093AF03B093B00380912C0790912D07B801A70192010E94B623882309F48B +:2059E00091C0A0E0B2E04A0E5B1E3EC08114910409F5F60121853285438554858289938931 +:205A0000A489B589281739074A075B0798F00E94C800882309F476C0E092AD03F092AE03C4 +:205A20000093AF031093B00380912E07816080932E0708C0C801B70141E00E94270188237D +:205A400009F460C09401245D3A4FA9014A0D5B1DD201F90102C08D918193E417F507D9F789 +:205A6000E21BF30B4E0E5F1E2A183B08950140E050E0F60181859285A385B485820F931F2F +:205A8000A41FB51F81879287A387B487D60119962D913D914D915C911C972114310409F0F6 +:205AA000DCCE52968D919D910D90BC91A02D82179307A407B50748F4F601228B338B448B4A +:205AC000558B83818068838311C08091C50B9091C60B892B59F08D819E81892B39F0D60172 +:205AE00013968C911397806813968C93F601838183FF05C0C6010E949626882319F04D819D +:205B00005E8106C081E0D60112968C934FEF5FEFCA0126960FB6F894DEBF0FBECDBFCF9127 +:205B2000DF911F910F91FF90EF90DF90CF90BF90AF909F908F907F905F904F903F902F9082 +:205B4000089582FD6FCE82CEDB010D900020E9F71197A61BB70BAD010E94EB2B0895DF9383 +:205B6000CF930F92CDB7DEB76983BE016F5F7F4F41E050E00E94EB2B0F90CF91DF910895AD +:205B8000DF92EF92FF920F931F93CF93DF93EC010E94C42B882309F44EC0EA8DFB8DED80BA +:205BA000FE800F8118858EEF9FEFAFEFBFEFE80EF91E0A1F1B1F058404C0EE0CFF1C001FF2 +:205BC000111F0A94D2F786859785A089B189E80EF91E0A1F1B1FD4800894E108F108010958 +:205BE00011090BC0C801B7016D0D711D811D911D0E9403018823F9F0DA94DD2099F7EA8D3F +:205C0000FB8D20E032E040E050E0058404C0220F331F441F551F0A94D2F78A899B89AC8920 +:205C2000BD89820F931FA41FB51F8A8B9B8BAC8BBD8B81E001C080E0DF91CF911F910F91E8 +:205C4000FF90EF90DF9008956F927F928F929F92AF92BF92CF92DF92EF92FF920F931F93FC +:205C6000DF93CF93CDB7DEB72B970FB6F894DEBF0FBECDBF5C016B01822EDC0114968C9111 +:205C8000882309F0D2C0CA018E010F5F1F4FB8010E948F25882309F4C8C0F601828D938D33 +:205CA000D5015B969C938E935A971582168217821086D60119961D921D921D921C921C978A +:205CC0009924380141C0C6010E94CA28FC01009709F4ABC085E016950795F794E7948A95A5 +:205CE000D1F71E2D1F708081882311F0853ED1F4992091F4D50151961C9351972091AD03DA +:205D00003091AE034091AF035091B0031D962D933D934D935C9350978081882399F499240B +:205D2000939421C0C301BF014BE050E00E94C93A009751F4882D8073803309F476C0C501A7 +:205D4000612F6FC099249394F601E184F2840385148582899389A489B589E816F9060A070D +:205D60001B0708F4B0CF882D8271823109F05DC0992041F0C50161E00E9479268C010097BF +:205D800089F453C0D60114968C91823009F44DC0C6010E94C02D882309F447C0F501118A83 +:205DA0000CE215E080E2D8011D928A95E9F7D801FE0131968BE001900D928150E1F7E091C3 +:205DC000C50BF091C60B309739F0B801625F7F4FC8014096099509C081E298E2F801918B71 +:205DE000808B80E098E097878687D80150968D919C91519753969C938E93529759969C9363 +:205E00008E9358971E968D919C911F9757969C938E9356970E94C800882339F0C501F50199 +:205E20006189482D0E94272A01C080E02B960FB6F894DEBF0FBECDBFCF91DF911F910F91C7 +:205E4000FF90EF90DF90CF90BF90AF909F908F907F906F900895FC018081918108958EEDB7 +:205E60009CE09093C80B8093C70B0895CB01642F0E94033B0895CB010E94FB3A08959091F1 +:205E8000CF049295990F990F907C8770892B80937C0080917A00806480937A0080917A00EB +:205EA00086FDFCCF2091780040917900942F80E030E0282B392BC90108951F93CF93DF934A +:205EC000182FEB0161E00E94B22FE12FF0E0E552FF4F8491833051F48091800080688093CD +:205EE0008000D0938900C093880038C0843051F480918000806280938000D0938B00C09323 +:205F00008A002CC0813029F484B5806884BDC7BD25C0823029F484B5806284BDC8BD1EC0E4 +:205F2000863041F48091B00080688093B000C093B30014C0873041F48091B000806280938E +:205F4000B000C093B4000AC0C038D1051CF4812F60E002C0812F61E00E94D02FDF91CF91CE +:205F60001F910895282F30E0C90185549F4FFC01949125563F4FF9018491882381F0E82F6F +:205F8000F0E0E457FF4FE491F0E0662329F4808190958923808308958081892B80830895F6 +:205FA000482F50E0CA0185529F4FFC012491CA0185549F4FFC01949145565F4FFA0134913B +:205FC0003323C1F1222331F1213019F484B58F7704C0223021F484B58F7D84BD1BC02330D6 +:205FE00021F4809180008F7705C0243031F4809180008F7D809380000DC0263021F480913E +:20600000B0008F7705C0273029F48091B0008F7D8093B000E32FF0E0EF56FF4FE491F0E047 +:20602000662329F4808190958923808308958081892B808308951F920F920FB60F92112406 +:206040002F938F939F93AF93BF938091CA0B9091CB0BA091CC0BB091CD0B0196A11DB11D75 +:206060008093CA0B9093CB0BA093CC0BB093CD0B8091CE0B9091CF0BA091D00BB091D10B0C +:206080008050904CAF4FBF4F8093CE0B9093CF0BA093D00BB093D10B27C08091CE0B909140 +:2060A000CF0BA091D00BB091D10B80589E43A040B0408093CE0B9093CF0BA093D00BB0931A +:2060C000D10B8091D20B9091D30BA091D40BB091D50B0196A11DB11D8093D20B9093D30BB2 +:2060E000A093D40BB093D50B8091CE0B9091CF0BA091D00BB091D10B81589E43A040B040D3 +:2061000060F6BF91AF919F918F912F910F900FBE0F901F9018958FB7F8942091D20B309101 +:20612000D30B4091D40B5091D50B8FBFB901CA0108956FB7F89486B590E0A0E0B0E0A89BF0 +:2061400008C00097A105B10521F480E091E0A0E0B0E02091CA0B3091CB0B4091CC0B5091E8 +:20616000CD0B6FBF542F432F322F2227280F391F4A1F5B1F82E0220F331F441F551F8A952D +:20618000D1F7B901CA010895789484B5826084BD84B5816084BD85B5826085BD85B58160D9 +:2061A00085BDEEE6F0E0808181608083E1E8F0E0808182608083808181608083E0E8F0E018 +:2061C000808181608083E1EBF0E0808184608083E0EBF0E0808181608083EAE7F0E0808134 +:2061E000846080838081826080838081816080838081806880831092C10008950F931F93AD +:20620000CF93DF93482FFB018B0100581F4FD801CD91DC91CE01019660E870E00E94B037BA +:206220009C01EE57FF4F80819181E258F0402817390731F0CE0FDF1F4883F801318320831B +:20624000DF91CF911F910F9108951F920F920FB60F9211242F933F934F935F936F937F9318 +:206260008F939F93AF93BF93EF93FF938091C60066ED7BE00E94FE30FF91EF91BF91AF912D +:206280009F918F917F916F915F914F913F912F910F900FBE0F901F9018951F920F920FB6C0 +:2062A0000F9211242F933F934F935F936F937F938F939F93AF93BF93EF93FF938091CE00B1 +:2062C0006AE57CE00E94FE30FF91EF91BF91AF919F918F917F916F915F914F913F912F91E3 +:2062E0000F900FBE0F901F9018955F926F927F928F929F92AF92BF92CF92DF92EF92FF926C +:206300000F931F93CF93DF93EC013A014B01413482E458078FE0680780E078070CF07FC0AF +:2063200060E874E88EE190E0A40193010E94E5372150304040405040CA01B90122E030E05B +:2063400040E050E00E94E53759016A01A6019501209530954095509594E0220F331F441F9F +:20636000551F9A95D1F760E074E284EF90E00E94E537CA01B9012FEF30E040E050E00E94D6 +:206380008537A40193010E94E537C90181509F4F181619061CF4522E5A9403C055245394D3 +:2063A000521A60E079E08DE390E0A40193010E94E5372150304040405040CA01B90122E089 +:2063C00030E040E050E00E94E537209530954095509583E0220F331F441F551F8A95D1F7C7 +:2063E00060E074E284EF90E00E94E537CA01B9012FEF30E040E050E00E948537A4019301CC +:206400000E94E537C90181509F4F181619061CF4822F815002C081E0821B851500F5E8859A +:20642000F98581E090E00A8802C0880F991F0A94E2F7808360E079E08DE390E0A40193013E +:206440000E94E5372150304040405040CA01B90122E030E040E050E00E94E53704C0E885B7 +:20646000F98510829501EC81FD813083EE81FF812083EA85FB85208141E050E0CA010E8408 +:2064800002C0880F991F0A94E2F7282B2083EA85FB852081CA010F8402C0880F991F0A94E1 +:2064A000E2F7282B2083EA85FB858081088802C0440F551F0A94E2F7842B8083DF91CF910B +:2064C0001F910F91FF90EF90DF90CF90BF90AF909F908F907F906F905F900895DC01129695 +:2064E000ED91FC911397E058FF4F8191919180589F4F20813181821B930B60E870E00E949F +:20650000B0370895CF93DF93DC011296ED91FC911397EF01CE57DF4F48815981E058FF4F7D +:2065200080819181E058F0408417950719F42FEF3FEF0CC0E40FF51F2081CA01019660E832 +:2065400070E00E94B0379983888330E0C901DF91CF910895DC011296ED91FC911397EE5775 +:20656000FF4F80819181929382930895FC01A085B18521898C9190E0022E02C0959587951C +:206580000A94E2F780FFF6CF0484F585E02D608308952AE235E03093DF0C2093DE0C86EDD2 +:2065A0009BE09093E10C8093E00C85EC90E09093E30C8093E20C84EC90E09093E50C809356 +:2065C000E40C80EC90E09093E70C8093E60C81EC90E09093E90C8093E80C86EC90E09093D3 +:2065E000EB0C8093EA0CE4E0E093EC0C73E07093ED0C67E06093EE0C55E05093EF0C41E0B5 +:206600004093F00C3093F20C2093F10C8AE59CE09093F40C8093F30C8DEC90E09093F60C0C +:206620008093F50C8CEC90E09093F80C8093F70C88EC90E09093FA0C8093F90C89EC90E017 +:206640009093FC0C8093FB0C8EEC90E09093FE0C8093FD0CE093FF0C7093000D6093010D33 +:206660005093020D4093030D0895DC01ED91FC910190F081E02D09950895DC01ED91FC918E +:206680000190F081E02D099508950F931F93CF93DF938C01EB0109C02196D801ED91FC91AB +:2066A0000190F081E02DC801099568816623A1F7DF91CF911F910F9108950F931F938C01BC +:2066C000DC01ED91FC910190F081E02D6DE00995D801ED91FC910190F081E02DC8016AE0D2 +:2066E00009951F910F9108950F931F938C010E944533C8010E945D331F910F9108952F926B +:206700003F924F925F926F927F928F929F92AF92BF92CF92DF92EF92FF920F931F93DF9336 +:20672000CF93CDB7DEB7A0970FB6F894DEBF0FBECDBF1C016A017B014115510561057105D4 +:2067400049F4DC01ED91FC910190F081E02D60E3099554C0882499245401422E55246624DF +:20676000772401E010E00C0F1D1F080D191DC701B601A30192010E94C337F8016083089441 +:20678000811C911CA11CB11CC701B601A30192010E94C337C901DA016C017D01C114D10499 +:2067A000E104F104F1F681E0E82EF12CEC0EFD1EE80CF91C3E010894611C711CD501C401E6 +:2067C0000197A109B1096C01C818D90814C0F601EE0DFF1D60816A3010F4605D01C0695CEB +:2067E000D101ED91FC910190F081E02DC10109950894E108F1086E147F0449F7A0960FB68F +:20680000F894DEBF0FBECDBFCF91DF911F910F91FF90EF90DF90CF90BF90AF909F908F901E +:206820007F906F905F904F903F902F9008952AE00E947F3308950F931F938C010E94173488 +:20684000C8010E945D331F910F910895AB0160E070E00E9417340895EF92FF920F931F9324 +:20686000CF93DF93EC017A018B0177FF0FC0E881F9810190F081E02D6DE2099510950095F2 +:20688000F094E094E11CF11C011D111DCE01B801A7012AE00E947F33DF91CF911F910F91FC +:2068A000FF90EF9008950F931F938C010E942C34C8010E945D331F910F910895AB01662729 +:2068C00057FD6095762F0E942C3408950F931F938C01AB01662757FD6095762F0E942C3421 +:2068E000C8010E945D331F910F9108959F92AF92BF92CF92DF92EF92FF920F931F93CF9353 +:20690000DF93EC017A018B01922ECB01BA0120E030E040E050E00E947835882364F4E881AF +:20692000F9810190F081E02DCE016DE2099517FB109517F9109520E030E040E05FE3AA2466 +:206940000BC0CA01B90120E030E040E251E40E947C359B01AC01A394A91498F3C801B701E4 +:206960000E9414355B016C010E94E9357B018C01CE01B801A7010E941734992029F0CE01DC +:206980006BEA73E00E944533C801B7010E9415369B01AC01C601B5010E94133520C020E037 +:2069A00030E040E251E40E94CB367B018C010E94E4355B016C01CC24B7FCC094DC2CCE0172 +:2069C000B601A5010E942C34C601B5010E9417369B01AC01C801B7010E9413359A94992051 +:2069E000F1F6DF91CF911F910F91FF90EF90DF90CF90BF90AF909F90089522E00E9476340C +:206A000008950F931F938C010E94FD34C8010E945D331F910F9108950E94C4300E94E02104 +:206A20000E94601EFDCF5058BB27AA270ED075C166D130F06BD120F031F49F3F11F41EF43E +:206A40005BC10EF4E095E7FB51C1E92F77D180F3BA17620773078407950718F071F49EF501 +:206A60008FC10EF4E0950B2EBA2FA02D0B01B90190010C01CA01A0011124FF27591B99F038 +:206A8000593F50F4503E68F11A16F040A22F232F342F4427585FF3CF469537952795A795CA +:206AA000F0405395C9F77EF41F16BA0B620B730B840BBAF09150A1F0FF0FBB1F661F771FF9 +:206AC000881FC2F70EC0BA0F621F731F841F48F4879577956795B795F7959E3F08F0B3CF7A +:206AE0009395880F08F09927EE0F979587950895D9D008F481E008950CD00FC107D140F0E6 +:206B0000FED030F021F45F3F19F0F0C0511139C1F3C014D198F39923C9F35523B1F3951B58 +:206B2000550BBB27AA2762177307840738F09F5F5F4F220F331F441FAA1FA9F333D00E2E66 +:206B40003AF0E0E830D091505040E695001CCAF729D0FE2F27D0660F771F881FBB1F261794 +:206B600037074807AB07B0E809F0BB0B802DBF01FF2793585F4F2AF09E3F510568F0B6C038 +:206B800000C15F3FECF3983EDCF3869577956795B795F7959F5FC9F7880F911D96958795CD +:206BA00097F90895E1E0660F771F881FBB1F621773078407BA0720F0621B730B840BBA0BBD +:206BC000EE1F88F7E095089504D06894B111D9C00895BCD088F09F5790F0B92F9927B75125 +:206BE000A0F0D1F0660F771F881F991F1AF0BA95C9F712C0B13081F0C3D0B1E00895C0C05C +:206C0000672F782F8827B85F39F0B93FCCF3869577956795B395D9F73EF4909580957095E5 +:206C200061957F4F8F4F9F4F0895E89409C097FB3EF490958095709561957F4F8F4F9F4F4F +:206C40009923A9F0F92F96E9BB279395F695879577956795B795F111F8CFFAF4BB0F11F4AD +:206C600060FF1BC06F5F7F4F8F4F9F4F16C0882311F096E911C0772321F09EE8872F762F14 +:206C800005C0662371F096E8862F70E060E02AF09A95660F771F881FDAF7880F96958795D8 +:206CA00097F90895990F0008550FAA0BE0E8FEEF16161706E807F907C0F012161306E40715 +:206CC000F50798F0621B730B840B950B39F40A2661F0232B242B252B21F408950A2609F48C +:206CE000A140A6958FEF811D811D089597F99F6780E870E060E008959FEF80EC089500243B +:206D00000A941616170618060906089500240A9412161306140605060895092E0394000C23 +:206D200011F4882352F0BB0F40F4BF2B11F460FF04C06F5F7F4F8F4F9F4F089557FD905810 +:206D4000440F551F59F05F3F71F04795880F97FB991F61F09F3F79F08795089512161306D5 +:206D60001406551FF2CF4695F1DF08C0161617061806991FF1CF8695710561050894089542 +:206D8000E894BB2766277727CB0197F908958ADF08F48FEF08950BD0C0CFB1DF28F0B6DF4A +:206DA00018F0952309F0A2CFA7CF1124EACFC6DFA0F3959FD1F3950F50E0551F629FF001DB +:206DC000729FBB27F00DB11D639FAA27F00DB11DAA1F649F6627B00DA11D661F829F222794 +:206DE000B00DA11D621F739FB00DA11D621F839FA00D611D221F749F3327A00D611D231F21 +:206E0000849F600D211D822F762F6A2F11249F5750408AF0E1F088234AF0EE0FFF1FBB1FD5 +:206E2000661F771F881F91505040A9F79E3F510570F05CCFA6CF5F3FECF3983EDCF386950F +:206E400077956795B795F795E7959F5FC1F7FE2B880F911D9695879597F9089511F40EF437 +:206E60004BCF3EC073DFD0F39923D9F3CEF39F57550B87FF43D00024A0E640EA9001805870 +:206E80005695979528F4805C660F771F881F20F026173707480730F4621B730B840B202960 +:206EA00031294A2BA69517940794202531254A2758F7660F771F881F20F02617370748079B +:206EC00030F4620B730B840B200D311D411DA09581F7B901842F9158880F969587950895BD +:206EE0009F3F31F0915020F4879577956795B795880F911D9695879597F908959150504004 +:206F0000660F771F881FD2F70895629FD001739FF001829FE00DF11D649FE00DF11D929F39 +:206F2000F00D839FF00D749FF00D659FF00D9927729FB00DE11DF91F639FB00DE11DF91FAB +:206F4000BD01CF0111240895991B79E004C0991F961708F0961B881F7A95C9F780950895CA +:206F600097FB092E07260AD077FD04D049D006D000201AF4709561957F4F0895F6F7909564 +:206F800081959F4F0895A1E21A2EAA1BBB1BFD010DC0AA1FBB1FEE1FFF1FA217B307E407F3 +:206FA000F50720F0A21BB30BE40BF50B661F771F881F991F1A9469F760957095809590959F +:206FC0009B01AC01BD01CF01089597FB092E05260ED057FD04D0D7DF0AD0001C38F4509586 +:206FE0004095309521953F4F4F4F5F4F0895F6F790958095709561957F4F8F4F9F4F089571 +:20700000AA1BBB1B51E107C0AA1FBB1FA617B70710F0A61BB70B881F991F5A95A9F7809538 +:207020009095BC01CD010895EE0FFF1F0590F491E02D0994A0E0B0E0E0E2F8E30C941A3B82 +:20704000EC015B016115710519F0FB0191838083F9908F2D90E00E94A93A892BC9F7FDE252 +:20706000FF1621F4F990EE24E39405C02BE2F21609F4F990EE248E0101501040C8016BEF0F +:2070800070E043E050E00E94B13A892B01F58E010E5F1F4FC8016EEF70E045E050E00E943F +:2070A000B13A892B19F48E01095F1F4FA114B10419F0F50111830083E0FC04C070E090E0DF +:2070C00080E814C070E090E080E86FEF08C1C80163E071E043E050E00E94B13A892B69F4D7 +:2070E000A114B10429F470E090E080EC6FE7F7C02296F501D183C083F6CF8824992440E03D +:2071000050E060E070E0EF2DE053EA30A0F5F2E0EF2A8E2D90E09C0128703070E2FE06C020 +:20712000232B79F50894811C911C2BC0232B19F0089481089108DB01CA0112E0880F991FC5 +:20714000AA1FBB1F1A95D1F7480F591F6A1F7B1F440F551F661F771F4E0F511D611D711D6A +:20716000483929E9520729E9620729E1720748F084E0E82A06C0EE3F31F4E3FC39C098E00F +:20718000E92AF990C0CFE53311F0E53189F529912D3219F4E0E1EE2A05C02B3219F081E08C +:2071A00090E003C0299182E090E0E22FE053EA3018F0C81BD90B1CC020E030E0FCE02038C3 +:2071C0003F075CF4C901880F991F880F991F280F391F220F331F2E0F311DE991E053EA304D +:2071E00068F3E4FE03C0309521953F4F820E931ECE2CDD24E1FE07C0A114B10421F0219771 +:20720000F501D183C083CB01BA010E9415367B018C01F3E0CF22DD2423E0C216D10421F4DA +:2072200017FB109517F9109557016801C801B70120E030E040E050E00E947835882309F449 +:207240004AC097FE0DC02AE1E22E21E0F22E9094819491089394C0E2D0E000E010E012C099 +:2072600092E3E92E91E0F92EF6CFF7012591359145915491C601B5010E94CB365B016C010D +:207280008C1A9D0A8C169D0684F7D595C7950F5F1F4F0630110529F08CEF9FEFE80EF91EC4 +:2072A000F1CFC501D6017C018D018C2D880F8D2D881F8F3F51F0C601B50120E030E040E0F9 +:2072C00050E00E947835882331F482E290E09093050D8093040D7E2D9F2D802F612F272F26 +:2072E000392F482F562FB901CA01CDB7DEB7ECE00C94363B2F923F925F926F927F928F92F9 +:207300009F92AF92BF92CF92DF92EF92FF920F931F93CF93DF938C011B01EA01611571051E +:2073200019F0FB0191838083209749F0CE010297839728F020E030E040E050E0F6C0F80198 +:20734000A1908F018A2D90E00E94A93A892BB9F7FDE2AF1631F4F801A1908F015524539479 +:2073600007C0FBE2AF1619F4F801A1908F015524209719F0C031D105C1F4F0E3AF1679F423 +:20738000F8018081883711F0883549F4F801A1800E5F1F4FF2E05F2AC0E1D0E006C020971B +:2073A00021F480E3A816E9F427C0C830D10531F1C930D10524F4C230D10531F50CC0CA3048 +:2073C000D10589F0C031D105F9F4C12CD12CE12CB8E0FB2E28C0C12CD12CE12CA0E4FA2E67 +:2073E00022C0CAE0D0E0FCECCF2EFCECDF2EFCECEF2EFCE0FF2E17C0C8E0D0E0C12CD12C50 +:20740000E12CE0E1FE2E0FC09E01442737FD4095542F60E070E080E090E80E94C337C9013F +:20742000DA016C017D0120E030E040E050E060E03E01882477FC8094982C70EDB72EBA0CA8 +:20744000E9E0EB1570F48A2D81548A3118F499ECB92E06C08A2D81568A3150F589EAB82E93 +:20746000BA0C8B2D90E08C179D0714F56F3FE1F0C216D306E406F506B0F0CA01B901A401EF +:2074800093010E9485379B01AC012B0D311D411D511D2130F0E03F07F0E04F07F0E85F0794 +:2074A00010F461E001C06FEFF801A1908F01C5CF2114310481F0662331F001501040F10102 +:2074C0001183008308C051FE1AC002501040F1011183008314C067FF12C050FC05C02FEFBE +:2074E0003FEF4FEF5FE704C020E030E040E050E882E290E09093050D8093040D16C050FE5D +:2075000008C050954095309521953F4F4F4F5F4F0CC057FF0AC082E290E09093050D80938C +:20752000040D2FEF3FEF4FEF5FE7B901CA01DF91CF911F910F91FF90EF90DF90CF90BF909A +:20754000AF909F908F907F906F905F903F902F900895911166C0803219F089508550D0F77E +:207560000895FB01DC014150504088F08D9181341CF08B350CF4805E659161341CF06B3548 +:207580000CF4605E861B611171F3990B0895881BFCCFFB01DC0104C08D910190801921F40D +:2075A00041505040C8F7881B990B0895FC018191861721F08823D9F7992708953197CF01DA +:2075C0000895FB0151915523A9F0BF01DC014D9145174111E1F759F4CD010190002049F019 +:2075E0004D9140154111C9F3FB014111EFCF81E090E001970895F999FECF92BD81BDF89ABA +:20760000992780B50895262FF999FECF1FBA92BD81BD20BD0FB6F894FA9AF99A0FBE019605 +:2076200008959927882708952F923F924F925F926F927F928F929F92AF92BF92CF92DF9275 +:20764000EF92FF920F931F93CF93DF93CDB7DEB7CA1BDB0B0FB6F894DEBF0FBECDBF099428 +:207660002A88398848885F846E847D848C849B84AA84B984C884DF80EE80FD800C811B8198 +:20768000AA81B981CE0FD11D0FB6F894DEBF0FBECDBFED010895F894FFCF45433A002C2080 +:2076A000006F6B00526573656E643A00534420696E6974206661696C00766F6C756D652E68 +:2076C000696E6974206661696C6564006F70656E526F6F74206661696C656400533A0042C7 +:2076E0006567696E2066696C65206C69737400456E642066696C65206C6973740046696C7D +:2077000065206F70656E65643A002053697A653A0046696C652073656C65637465640066EB +:20772000696C652E6F70656E206661696C6564005344207072696E74696E672062797465B4 +:2077400020002F004E6F74205344207072696E74696E67006F70656E206661696C65642C04 +:207760002046696C653A20002E0057726974696E6720746F2066696C653A20006F6B205492 +:207780003A0020423A006F6B206F3A002C20703A002C20693A002C20643A00543A00464984 +:2077A000524D574152455F4E414D453A72727020555549443A00583A00593A005A3A00455E +:2077C0003A00785F6D696E3A004C2000482000795F6D696E3A007A5F6D696E3A00004B70DE +:2077E00020004B6920004B6420005049445F4D415820005049445F495F4D415820004E5AF2 +:207800004F4E452000556E6B6E6F776E20636F6D6D616E643A004D3131300053657269616A +:207820006C204572726F723A204C696E65204E756D626572206973206E6F74204C61737426 +:20784000204C696E65204E756D6265722B312C204C617374204C696E653A004572726F72CF +:207860003A20636865636B73756D206D69736D617463682C204C617374204C696E653A0023 +:207880004572726F723A204E6F20436865636B73756D2077697468206C696E65206E756D60 +:2078A0006265722C204C617374204C696E653A004572726F723A204E6F204C696E65204E96 +:2078C000756D626572207769746820636865636B73756D2C204C617374204C696E653A007C +:2078E000446F6E65207072696E74696E672066696C65004D3239006572726F722077726963 +:2079000074696E6720746F2066696C6500446F6E6520736176696E672066696C652E007363 +:2079200074617274004F6B005344004572726F72004E6F204572726F7200486F74656E64E8 +:2079400000426564002E00FFFFFFFF71DBB64271DBB64200007A45008063440060EA4600F4 +:2079600060EA460000FA430060EA460080BB440080BB440000F0420000C8410000C841CD9B +:20798000CC4C3E00002041E8030000E803000032000000FA000000F4010000F40100003212 +:2079A000000000F401000030303030303030302D303030302D303030302D303030302D302E +:2079C000303030303030303030303000FF005000000000400AD7233C0000A04105000100E1 +:2079E000A10324002B014700F6006A00D9008D00C600B000B800D300AD00F600A300190125 +:207A00009A003C0193005F018C0082018600A5018000C8017A00EB0175000E02700031028A +:207A20006B0054026600770261009A025B00BD025600E002510003034C00260346004903F9 +:207A40003F006C0338008F033000B2032600D5031700F80300008B038E0391039703A003C9 +:207A6000A70358595A4501DC05010100C0023600D8006B00AF00A0009800D50089000A019D +:207A80007D003F01730074016A00A9016300DE015B001302550048024E007D024700B20214 +:207AA0004100E7023A001C03320051032A0086031F00BB031100F003000000000000AF2D4D +:207AC00000000000B632FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD8 +:207AE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA6 +:207B0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF85 +:207B2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF65 +:207B4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45 +:207B6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF25 +:207B8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF05 +:207BA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5 +:207BC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC5 +:207BE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA5 +:207C0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF84 +:207C2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF64 +:207C4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF44 +:207C6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF24 +:207C8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04 +:207CA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE4 +:207CC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC4 +:207CE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA4 +:207D0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF83 +:207D2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF63 +:207D4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43 +:207D6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF23 +:207D8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF03 +:207DA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE3 +:207DC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC3 +:207DE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA3 +:207E0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF82 +:207E2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF62 +:207E4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF42 +:207E6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF22 +:207E8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF02 +:207EA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE2 +:207EC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC2 +:207EE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA2 +:207F0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF81 +:207F2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF61 +:207F4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF41 +:207F6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF21 +:207F8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF01 +:207FA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE1 +:207FC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1 +:207FE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA1 +:20800000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80 +:20802000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF60 +:20804000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF40 +:20806000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF20 +:20808000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00 +:2080A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 +:2080C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0 +:2080E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0 +:20810000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F +:20812000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5F +:20814000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F +:20816000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1F +:20818000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +:2081A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDF +:2081C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBF +:2081E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9F +:20820000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7E +:20822000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5E +:20824000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3E +:20826000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1E +:20828000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE +:2082A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDE +:2082C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBE +:2082E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9E +:20830000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7D +:20832000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D +:20834000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3D +:20836000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1D +:20838000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD +:2083A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDD +:2083C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBD +:2083E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9D +:20840000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7C +:20842000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5C +:20844000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3C +:20846000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1C +:20848000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC +:2084A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC +:2084C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBC +:2084E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C +:20850000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7B +:20852000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5B +:20854000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3B +:20856000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1B +:20858000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB +:2085A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDB +:2085C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBB +:2085E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9B +:20860000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7A +:20862000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5A +:20864000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3A +:20866000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1A +:20868000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA +:2086A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDA +:2086C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBA +:2086E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9A +:20870000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF79 +:20872000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF59 +:20874000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF39 +:20876000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF19 +:20878000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9 +:2087A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD9 +:2087C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB9 +:2087E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF99 +:20880000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF78 +:20882000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF58 +:20884000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF38 +:20886000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF18 +:20888000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8 +:2088A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD8 +:2088C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB8 +:2088E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF98 +:20890000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF77 +:20892000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF57 +:20894000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF37 +:20896000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF17 +:20898000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7 +:2089A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD7 +:2089C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB7 +:2089E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF97 +:208A0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF76 +:208A2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF56 +:208A4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF36 +:208A6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF16 +:208A8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6 +:208AA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6 +:208AC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB6 +:208AE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF96 +:208B0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF75 +:208B2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF55 +:208B4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF35 +:208B6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF15 +:208B8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5 +:208BA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD5 +:208BC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB5 +:208BE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF95 +:208C0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF74 +:208C2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF54 +:208C4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF34 +:208C6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF14 +:208C8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4 +:208CA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD4 +:208CC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB4 +:208CE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF94 +:208D0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF73 +:208D2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF53 +:208D4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF33 +:208D6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF13 +:208D8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3 +:208DA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD3 +:208DC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB3 +:208DE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF93 +:208E0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF72 +:208E2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +:208E4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF32 +:208E6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF12 +:208E8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2 +:208EA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD2 +:208EC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB2 +:208EE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF92 +:208F0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71 +:208F2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51 +:208F4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF31 +:208F6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF11 +:208F8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1 +:208FA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD1 +:208FC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB1 +:208FE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF91 +:20900000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70 +:20902000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF50 +:20904000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF30 +:20906000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF10 +:20908000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0 +:2090A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD0 +:2090C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0 +:2090E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF90 +:20910000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6F +:20912000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4F +:20914000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2F +:20916000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0F +:20918000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF +:2091A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCF +:2091C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAF +:2091E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F +:20920000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6E +:20922000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4E +:20924000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2E +:20926000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0E +:20928000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEE +:2092A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCE +:2092C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAE +:2092E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8E +:20930000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6D +:20932000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4D +:20934000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2D +:20936000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0D +:20938000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED +:2093A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCD +:2093C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAD +:2093E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8D +:20940000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C +:20942000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4C +:20944000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2C +:20946000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0C +:20948000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEC +:2094A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCC +:2094C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAC +:2094E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8C +:20950000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6B +:20952000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4B +:20954000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2B +:20956000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0B +:20958000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEB +:2095A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCB +:2095C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAB +:2095E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8B +:20960000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6A +:20962000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4A +:20964000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2A +:20966000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0A +:20968000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEA +:2096A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA +:2096C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAA +:2096E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8A +:20970000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF69 +:20972000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF49 +:20974000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF29 +:20976000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF09 +:20978000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9 +:2097A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC9 +:2097C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA9 +:2097E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF89 +:20980000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF68 +:20982000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF48 +:20984000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF28 +:20986000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF08 +:20988000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8 +:2098A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC8 +:2098C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8 +:2098E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF88 +:20990000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67 +:20992000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF47 +:20994000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF27 +:20996000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF07 +:20998000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7 +:2099A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7 +:2099C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA7 +:2099E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF87 +:209A0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF66 +:209A2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF46 +:209A4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF26 +:209A6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF06 +:209A8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE6 +:209AA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC6 +:209AC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA6 +:209AE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF86 +:209B0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF65 +:209B2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45 +:209B4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF25 +:209B6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF05 +:209B8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5 +:209BA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC5 +:209BC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA5 +:209BE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF85 +:209C0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF64 +:209C2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF44 +:209C4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF24 +:209C6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04 +:209C8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE4 +:209CA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC4 +:209CC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA4 +:209CE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF84 +:209D0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF63 +:209D2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43 +:209D4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF23 +:209D6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF03 +:209D8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE3 +:209DA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC3 +:209DC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA3 +:209DE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF83 +:209E0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF62 +:209E2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF42 +:209E4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF22 +:209E6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF02 +:209E8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE2 +:209EA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC2 +:209EC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA2 +:209EE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF82 +:209F0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF61 +:209F2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF41 +:209F4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF21 +:209F6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF01 +:209F8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE1 +:209FA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1 +:209FC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA1 +:209FE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF81 +:20A00000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF60 +:20A02000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF40 +:20A04000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF20 +:20A06000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00 +:20A08000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 +:20A0A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0 +:20A0C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0 +:20A0E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80 +:20A10000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5F +:20A12000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F +:20A14000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1F +:20A16000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +:20A18000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDF +:20A1A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBF +:20A1C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9F +:20A1E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F +:20A20000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5E +:20A22000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3E +:20A24000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1E +:20A26000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE +:20A28000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDE +:20A2A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBE +:20A2C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9E +:20A2E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7E +:20A30000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D +:20A32000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3D +:20A34000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1D +:20A36000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD +:20A38000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDD +:20A3A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBD +:20A3C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9D +:20A3E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7D +:20A40000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5C +:20A42000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3C +:20A44000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1C +:20A46000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC +:20A48000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC +:20A4A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBC +:20A4C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C +:20A4E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7C +:20A50000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5B +:20A52000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3B +:20A54000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1B +:20A56000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB +:20A58000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDB +:20A5A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBB +:20A5C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9B +:20A5E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7B +:20A60000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5A +:20A62000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3A +:20A64000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1A +:20A66000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA +:20A68000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDA +:20A6A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBA +:20A6C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9A +:20A6E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7A +:20A70000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF59 +:20A72000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF39 +:20A74000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF19 +:20A76000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9 +:20A78000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD9 +:20A7A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB9 +:20A7C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF99 +:20A7E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF79 +:20A80000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF58 +:20A82000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF38 +:20A84000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF18 +:20A86000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8 +:20A88000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD8 +:20A8A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB8 +:20A8C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF98 +:20A8E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF78 +:20A90000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF57 +:20A92000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF37 +:20A94000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF17 +:20A96000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7 +:20A98000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD7 +:20A9A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB7 +:20A9C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF97 +:20A9E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF77 +:20AA0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF56 +:20AA2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF36 +:20AA4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF16 +:20AA6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6 +:20AA8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6 +:20AAA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB6 +:20AAC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF96 +:20AAE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF76 +:20AB0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF55 +:20AB2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF35 +:20AB4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF15 +:20AB6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5 +:20AB8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD5 +:20ABA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB5 +:20ABC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF95 +:20ABE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF75 +:20AC0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF54 +:20AC2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF34 +:20AC4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF14 +:20AC6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4 +:20AC8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD4 +:20ACA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB4 +:20ACC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF94 +:20ACE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF74 +:20AD0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF53 +:20AD2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF33 +:20AD4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF13 +:20AD6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3 +:20AD8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD3 +:20ADA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB3 +:20ADC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF93 +:20ADE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF73 +:20AE0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +:20AE2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF32 +:20AE4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF12 +:20AE6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2 +:20AE8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD2 +:20AEA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB2 +:20AEC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF92 +:20AEE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF72 +:20AF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51 +:20AF2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF31 +:20AF4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF11 +:20AF6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1 +:20AF8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD1 +:20AFA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB1 +:20AFC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF91 +:20AFE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71 +:20B00000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF50 +:20B02000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF30 +:20B04000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF10 +:20B06000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0 +:20B08000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD0 +:20B0A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0 +:20B0C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF90 +:20B0E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70 +:20B10000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4F +:20B12000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2F +:20B14000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0F +:20B16000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF +:20B18000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCF +:20B1A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAF +:20B1C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F +:20B1E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6F +:20B20000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4E +:20B22000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2E +:20B24000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0E +:20B26000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEE +:20B28000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCE +:20B2A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAE +:20B2C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8E +:20B2E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6E +:20B30000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4D +:20B32000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2D +:20B34000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0D +:20B36000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED +:20B38000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCD +:20B3A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAD +:20B3C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8D +:20B3E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6D +:20B40000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4C +:20B42000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2C +:20B44000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0C +:20B46000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEC +:20B48000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCC +:20B4A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAC +:20B4C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8C +:20B4E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C +:20B50000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4B +:20B52000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2B +:20B54000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0B +:20B56000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEB +:20B58000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCB +:20B5A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAB +:20B5C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8B +:20B5E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6B +:20B60000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4A +:20B62000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2A +:20B64000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0A +:20B66000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEA +:20B68000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA +:20B6A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAA +:20B6C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8A +:20B6E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6A +:20B70000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF49 +:20B72000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF29 +:20B74000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF09 +:20B76000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9 +:20B78000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC9 +:20B7A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA9 +:20B7C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF89 +:20B7E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF69 +:20B80000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF48 +:20B82000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF28 +:20B84000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF08 +:20B86000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8 +:20B88000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC8 +:20B8A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8 +:20B8C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF88 +:20B8E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF68 +:20B90000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF47 +:20B92000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF27 +:20B94000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF07 +:20B96000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7 +:20B98000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7 +:20B9A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA7 +:20B9C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF87 +:20B9E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67 +:20BA0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF46 +:20BA2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF26 +:20BA4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF06 +:20BA6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE6 +:20BA8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC6 +:20BAA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA6 +:20BAC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF86 +:20BAE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF66 +:20BB0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45 +:20BB2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF25 +:20BB4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF05 +:20BB6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5 +:20BB8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC5 +:20BBA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA5 +:20BBC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF85 +:20BBE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF65 +:20BC0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF44 +:20BC2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF24 +:20BC4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04 +:20BC6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE4 +:20BC8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC4 +:20BCA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA4 +:20BCC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF84 +:20BCE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF64 +:20BD0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43 +:20BD2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF23 +:20BD4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF03 +:20BD6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE3 +:20BD8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC3 +:20BDA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA3 +:20BDC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF83 +:20BDE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF63 +:20BE0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF42 +:20BE2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF22 +:20BE4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF02 +:20BE6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE2 +:20BE8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC2 +:20BEA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA2 +:20BEC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF82 +:20BEE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF62 +:20BF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF41 +:20BF2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF21 +:20BF4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF01 +:20BF6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE1 +:20BF8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1 +:20BFA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA1 +:20BFC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF81 +:20BFE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF61 +:20C00000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF40 +:20C02000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF20 +:20C04000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00 +:20C06000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 +:20C08000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0 +:20C0A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0 +:20C0C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80 +:20C0E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF60 +:20C10000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F +:20C12000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1F +:20C14000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +:20C16000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDF +:20C18000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBF +:20C1A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9F +:20C1C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F +:20C1E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5F +:20C20000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3E +:20C22000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1E +:20C24000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE +:20C26000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDE +:20C28000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBE +:20C2A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9E +:20C2C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7E +:20C2E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5E +:20C30000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3D +:20C32000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1D +:20C34000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD +:20C36000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDD +:20C38000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBD +:20C3A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9D +:20C3C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7D +:20C3E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D +:20C40000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3C +:20C42000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1C +:20C44000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC +:20C46000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC +:20C48000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBC +:20C4A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C +:20C4C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7C +:20C4E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5C +:20C50000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3B +:20C52000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1B +:20C54000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB +:20C56000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDB +:20C58000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBB +:20C5A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9B +:20C5C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7B +:20C5E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5B +:20C60000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3A +:20C62000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1A +:20C64000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA +:20C66000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDA +:20C68000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBA +:20C6A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9A +:20C6C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7A +:20C6E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5A +:20C70000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF39 +:20C72000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF19 +:20C74000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9 +:20C76000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD9 +:20C78000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB9 +:20C7A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF99 +:20C7C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF79 +:20C7E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF59 +:20C80000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF38 +:20C82000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF18 +:20C84000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8 +:20C86000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD8 +:20C88000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB8 +:20C8A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF98 +:20C8C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF78 +:20C8E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF58 +:20C90000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF37 +:20C92000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF17 +:20C94000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7 +:20C96000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD7 +:20C98000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB7 +:20C9A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF97 +:20C9C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF77 +:20C9E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF57 +:20CA0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF36 +:20CA2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF16 +:20CA4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6 +:20CA6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6 +:20CA8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB6 +:20CAA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF96 +:20CAC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF76 +:20CAE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF56 +:20CB0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF35 +:20CB2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF15 +:20CB4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5 +:20CB6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD5 +:20CB8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB5 +:20CBA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF95 +:20CBC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF75 +:20CBE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF55 +:20CC0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF34 +:20CC2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF14 +:20CC4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4 +:20CC6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD4 +:20CC8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB4 +:20CCA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF94 +:20CCC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF74 +:20CCE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF54 +:20CD0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF33 +:20CD2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF13 +:20CD4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3 +:20CD6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD3 +:20CD8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB3 +:20CDA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF93 +:20CDC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF73 +:20CDE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF53 +:20CE0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF32 +:20CE2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF12 +:20CE4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2 +:20CE6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD2 +:20CE8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB2 +:20CEA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF92 +:20CEC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF72 +:20CEE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +:20CF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF31 +:20CF2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF11 +:20CF4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1 +:20CF6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD1 +:20CF8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB1 +:20CFA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF91 +:20CFC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71 +:20CFE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51 +:20D00000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF30 +:20D02000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF10 +:20D04000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0 +:20D06000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD0 +:20D08000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0 +:20D0A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF90 +:20D0C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70 +:20D0E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF50 +:20D10000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2F +:20D12000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0F +:20D14000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF +:20D16000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCF +:20D18000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAF +:20D1A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F +:20D1C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6F +:20D1E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4F +:20D20000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2E +:20D22000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0E +:20D24000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEE +:20D26000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCE +:20D28000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAE +:20D2A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8E +:20D2C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6E +:20D2E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4E +:20D30000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2D +:20D32000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0D +:20D34000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED +:20D36000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCD +:20D38000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAD +:20D3A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8D +:20D3C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6D +:20D3E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4D +:20D40000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2C +:20D42000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0C +:20D44000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEC +:20D46000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCC +:20D48000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAC +:20D4A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8C +:20D4C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C +:20D4E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4C +:20D50000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2B +:20D52000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0B +:20D54000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEB +:20D56000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCB +:20D58000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAB +:20D5A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8B +:20D5C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6B +:20D5E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4B +:20D60000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2A +:20D62000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0A +:20D64000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEA +:20D66000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA +:20D68000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAA +:20D6A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8A +:20D6C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6A +:20D6E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4A +:20D70000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF29 +:20D72000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF09 +:20D74000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9 +:20D76000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC9 +:20D78000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA9 +:20D7A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF89 +:20D7C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF69 +:20D7E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF49 +:20D80000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF28 +:20D82000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF08 +:20D84000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8 +:20D86000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC8 +:20D88000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8 +:20D8A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF88 +:20D8C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF68 +:20D8E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF48 +:20D90000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF27 +:20D92000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF07 +:20D94000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7 +:20D96000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7 +:20D98000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA7 +:20D9A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF87 +:20D9C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67 +:20D9E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF47 +:20DA0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF26 +:20DA2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF06 +:20DA4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE6 +:20DA6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC6 +:20DA8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA6 +:20DAA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF86 +:20DAC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF66 +:20DAE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF46 +:20DB0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF25 +:20DB2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF05 +:20DB4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5 +:20DB6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC5 +:20DB8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA5 +:20DBA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF85 +:20DBC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF65 +:20DBE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45 +:20DC0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF24 +:20DC2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04 +:20DC4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE4 +:20DC6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC4 +:20DC8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA4 +:20DCA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF84 +:20DCC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF64 +:20DCE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF44 +:20DD0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF23 +:20DD2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF03 +:20DD4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE3 +:20DD6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC3 +:20DD8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA3 +:20DDA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF83 +:20DDC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF63 +:20DDE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43 +:20DE0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF22 +:20DE2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF02 +:20DE4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE2 +:20DE6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC2 +:20DE8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA2 +:20DEA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF82 +:20DEC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF62 +:20DEE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF42 +:20DF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF21 +:20DF2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF01 +:20DF4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE1 +:20DF6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1 +:20DF8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA1 +:20DFA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF81 +:20DFC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF61 +:20DFE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF41 +:20E00000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF20 +:20E02000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00 +:20E04000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 +:20E06000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0 +:20E08000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0 +:20E0A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80 +:20E0C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF60 +:20E0E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF40 +:20E10000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1F +:20E12000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +:20E14000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDF +:20E16000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBF +:20E18000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9F +:20E1A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F +:20E1C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5F +:20E1E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F +:20E20000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1E +:20E22000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE +:20E24000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDE +:20E26000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBE +:20E28000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9E +:20E2A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7E +:20E2C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5E +:20E2E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3E +:20E30000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1D +:20E32000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD +:20E34000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDD +:20E36000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBD +:20E38000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9D +:20E3A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7D +:20E3C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D +:20E3E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3D +:20E40000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1C +:20E42000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC +:20E44000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC +:20E46000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBC +:20E48000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C +:20E4A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7C +:20E4C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5C +:20E4E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3C +:20E50000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1B +:20E52000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB +:20E54000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDB +:20E56000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBB +:20E58000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9B +:20E5A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7B +:20E5C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5B +:20E5E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3B +:20E60000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1A +:20E62000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA +:20E64000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDA +:20E66000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBA +:20E68000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9A +:20E6A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7A +:20E6C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5A +:20E6E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3A +:20E70000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF19 +:20E72000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9 +:20E74000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD9 +:20E76000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB9 +:20E78000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF99 +:20E7A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF79 +:20E7C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF59 +:20E7E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF39 +:20E80000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF18 +:20E82000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8 +:20E84000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD8 +:20E86000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB8 +:20E88000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF98 +:20E8A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF78 +:20E8C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF58 +:20E8E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF38 +:20E90000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF17 +:20E92000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7 +:20E94000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD7 +:20E96000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB7 +:20E98000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF97 +:20E9A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF77 +:20E9C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF57 +:20E9E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF37 +:20EA0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF16 +:20EA2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6 +:20EA4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6 +:20EA6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB6 +:20EA8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF96 +:20EAA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF76 +:20EAC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF56 +:20EAE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF36 +:20EB0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF15 +:20EB2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5 +:20EB4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD5 +:20EB6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB5 +:20EB8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF95 +:20EBA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF75 +:20EBC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF55 +:20EBE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF35 +:20EC0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF14 +:20EC2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4 +:20EC4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD4 +:20EC6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB4 +:20EC8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF94 +:20ECA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF74 +:20ECC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF54 +:20ECE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF34 +:20ED0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF13 +:20ED2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3 +:20ED4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD3 +:20ED6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB3 +:20ED8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF93 +:20EDA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF73 +:20EDC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF53 +:20EDE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF33 +:20EE0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF12 +:20EE2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2 +:20EE4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD2 +:20EE6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB2 +:20EE8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF92 +:20EEA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF72 +:20EEC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +:20EEE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF32 +:20EF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF11 +:20EF2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1 +:20EF4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD1 +:20EF6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB1 +:20EF8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF91 +:20EFA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71 +:20EFC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51 +:20EFE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF31 +:20F00000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF10 +:20F02000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0 +:20F04000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD0 +:20F06000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0 +:20F08000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF90 +:20F0A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70 +:20F0C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF50 +:20F0E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF30 +:20F10000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0F +:20F12000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF +:20F14000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCF +:20F16000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAF +:20F18000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F +:20F1A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6F +:20F1C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4F +:20F1E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2F +:20F20000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0E +:20F22000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEE +:20F24000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCE +:20F26000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAE +:20F28000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8E +:20F2A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6E +:20F2C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4E +:20F2E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2E +:20F30000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0D +:20F32000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED +:20F34000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCD +:20F36000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAD +:20F38000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8D +:20F3A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6D +:20F3C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4D +:20F3E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2D +:20F40000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0C +:20F42000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEC +:20F44000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCC +:20F46000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAC +:20F48000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8C +:20F4A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C +:20F4C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4C +:20F4E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2C +:20F50000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0B +:20F52000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEB +:20F54000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCB +:20F56000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAB +:20F58000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8B +:20F5A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6B +:20F5C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4B +:20F5E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2B +:20F60000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0A +:20F62000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEA +:20F64000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA +:20F66000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAA +:20F68000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8A +:20F6A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6A +:20F6C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4A +:20F6E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2A +:20F70000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF09 +:20F72000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9 +:20F74000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC9 +:20F76000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA9 +:20F78000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF89 +:20F7A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF69 +:20F7C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF49 +:20F7E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF29 +:20F800000C943E7C0C945B7C0C945B7C0C945B7C0C945B7C0C945B7C0C945B7C0C945B7C4D +:20F820000C945B7C0C945B7C0C945B7C0C945B7C0C945B7C0C945B7C0C945B7C0C945B7C10 +:20F840000C945B7C0C945B7C0C945B7C0C945B7C0C945B7C0C945B7C0C945B7C0C945B7CF0 +:20F860000C945B7C0C945B7C0C945B7C0C945B7C0C945B7C0C945B7C0C945B7C11241FBE35 +:20F88000CFEFD0E1DEBFCDBF11E0A0E0B1E0E6E6FFEF02C005900D92A030B107D9F712E0D4 +:20F8A000A0E0B1E001C01D92A930B107E1F70E94537D0C94B27F0C94007CCF93DF93CDB7A7 +:20F8C000DEB724970FB6F894DEBF0FBECDBF882309F481E020E0482F55274115510509F4EC +:20F8E0003DC0289A19821A821B821C820BC089819A81AB81BC810196A11DB11D89839A8332 +:20F90000AB83BC8389819A81AB81BC8180589E43A040B04060F3289819821A821B821C82DE +:20F920000BC089819A81AB81BC810196A11DB11D89839A83AB83BC8389819A81AB81BC8127 +:20F9400080509A4FA040B04060F32F5F822F992787FD9095841795070CF4C3CF19821A8223 +:20F960001B821C8289819A81AB81BC8180509147A240B040A0F489819A81AB81BC8101968B +:20F98000A11DB11D89839A83AB83BC8389819A81AB81BC8180509147A240B04060F3249630 +:20F9A0000FB6F894DEBF0FBECDBFDF91CF910895EF92FF920F931F93EE24FF2487012898B0 +:20F9C0008091C00087FD17C00894E11CF11C011D111D81E0E81689E0F8068DE3080780E064 +:20F9E000180770F3E0910001F091010109958091C00087FFE9CF289A8091C600992787FD06 +:20FA000090951F910F91FF90EF900895982F8091C00085FFFCCF9093C60008950E94D87C63 +:20FA2000803271F0809102018F5F80930201853009F00895E0910001F09101010995089520 +:20FA400084E10E94067D80E10E94067D0895CF93C82F0E94D87C803241F0809102018F5FC5 +:20FA600080930201853081F40AC084E10E94067D8C2F0E94067D80E10E94067D05C0E09156 +:20FA80000001F09101010995CF910895282F90E007C08091C0008823E4F78091C6009F5F8D +:20FAA0009217B8F30895CFEFD0E1DEBFCDBF000094B714BE80916000886180936000109231 +:20FAC000600091FF74C189E18093C4001092C50088E18093C10086E08093C2005098589A07 +:20FAE000209A83E00E945D7C81E00E945D7C0E94D87C8033B9F18133C1F1803409F456C012 +:20FB0000813409F45CC0823409F46EC0853409F471C0803539F1813509F4F3C0823511F151 +:20FB2000853509F4D3C0863509F4CBC0843609F465C0843709F4EBC0853709F4D2C08637F1 +:20FB400009F44AC0809102018F5F80930201853071F6E0910001F091010109950E94D87CE1 +:20FB6000803349F60E940E7DC2CF0E94D87CC82F803241F784E10E94067D81E40E94067DEA +:20FB800086E50E94067D82E50E94067D8C2F0E94067D89E40E94067D83E50E94067D80E5E5 +:20FBA0000E94067D80E10E94067DA1CF0E94D87C8638C0F20E94D87C0E940E7D98CF0E9498 +:20FBC000D87C803809F407C1813809F400C1823809F4F9C0883921F080E00E94277D87CF9F +:20FBE00083E00E94277D83CF84E10E94467D0E940E7D7DCF85E00E94467DF9CF0E94D87C3F +:20FC0000809306020E94D87C80930502809108028E7F809308020E94D87C853409F44BC0BD +:20FC2000E5E0F1E0119281E0E438F807D9F3D0F3C0E0D0E0809105029091060218161906A2 +:20FC400078F405E011E00E94D87CF80181938F0121968091050290910602C817D90798F38D +:20FC60000E94D87C803209F06DCF8091080280FFB6C0C0E0D0E0209105023091060212169E +:20FC80001306B8F4E0910301F0910401A5E0B1E0F999FECFF2BDE1BD8D9180BDFA9AF99A60 +:20FCA00031962196C217D30798F3F0930401E093030184E175CF80910802816080930802C7 +:20FCC000AFCF84E00E94467D80E087CF0E94D87C809303010E94D87C809304010E940E7DDF +:20FCE00006CF0E94D87C803209F02CCF84E10E94067D8EE10E94067D86E90E94067D8AE077 +:20FD00004FCF0E940E7D88E080936000FFCF0E94D87C809306020E94D87C809305020E942C +:20FD2000D87C853409F449C0809108028E7F809308028091030190910401880F991F9093BE +:20FD40000401809303010E94D87C803209F0CFCE84E10E94067DC0E0D0E0209105023091F6 +:20FD600006021216130608F01DCFE0910301F09104018091080280FF96C0F999FECFF2BD5D +:20FD8000E1BDF89A80B50E94067DE0910301F09104013196F0930401E09303012091050260 +:20FDA000309106022196C217D30718F3FBCEE0910001F0910101099586CE80910802816059 +:20FDC00080930802C0CF80E10E94277D90CE81E00E94277D8CCE82E00E94277D88CE809162 +:20FDE000030190910401880F991F90930401809303018091050280FF09C0809105029091B2 +:20FE0000060201969093060280930502F999FECF1127E0910301F0910401C5E0D1E0809105 +:20FE2000050290910602103091F40091570001700130D9F303E000935700E8950091570045 +:20FE400001700130D9F301E100935700E895099019900091570001700130D9F301E00093DF +:20FE60005700E8951395103898F011270091570001700130D9F305E000935700E8950091CB +:20FE8000570001700130D9F301E100935700E8953296029709F0C7CF103011F00296E5CFD7 +:20FEA000112484E17DCE869580FF06C03196F0930401E093030176CF84910E94067D209107 +:20FEC000050230910602E0910301F0910401EECF1F93CF930E94D87CC82F0E94067D0E94D2 +:20FEE000D87C182F0E94067DC1362CF0C75511363CF0175508C0C033D4F3C0531136CCF795 +:20FF000010330CF01053C295C07FC10F8C2F992787FD9095CF911F910895CF93282F99278F +:20FF200087FD9095807F9070959587959595879595958795959587958A303CF0895AC22F47 +:20FF4000CF70CA303CF0C95A06C0805DC22FCF70CA30CCF7C05D0E94067D8C2F0E94067D67 +:06FF6000CF910895FFCFD0 +:00000001FF diff --git a/firmware-hfuse.hex b/firmware-hfuse.hex new file mode 100644 index 0000000..1a73311 --- /dev/null +++ b/firmware-hfuse.hex @@ -0,0 +1,2 @@ +:0100000000FF +:00000001FF diff --git a/firmware-lfuse.hex b/firmware-lfuse.hex new file mode 100644 index 0000000..1a73311 --- /dev/null +++ b/firmware-lfuse.hex @@ -0,0 +1,2 @@ +:0100000000FF +:00000001FF diff --git a/floating-phases.scad b/floating-phases.scad new file mode 100644 index 0000000..b419918 --- /dev/null +++ b/floating-phases.scad @@ -0,0 +1,103 @@ +// -*- C -*- + +// caller should define +// +// z_pause = 2; // higher than any thing in the model +// total_sz = [ 200, 141 ]; +// phases=4; // how many phases +// colours = [ +// "blue", +// "black", +// "red", +// "yellow", +// ]; +// +// Pause height z_pause value from caller +// head park X 15 +// head park Y 0 +// head move Z 1 +// min head park Z 1 +// retraction 1 +// re-home [ ] [ ] + +// when z pause occurs +// * set feed rate to 10% (or whatever minimum is) +// * press knob, printer will start +// * quickly, press again, select "stop" +// * set temp +// * set feed rate back to 100% +// * now change filament etc., start next file + +include + +$test_thicker = 1.0; // 2.5; + +th_l0 = .425 * $test_thicker; +th_l1 = .250 * $test_thicker; +frame_w = 0.8; +tower_w = 2.0; + +th_most = th_l0 + th_l1*2; + +noz_gap = 8; + + +multicolour_gap = 0.15; // each side + +underlayer_smaller = 0.35; // each side + +total_sz_actual = $test ? $test : total_sz; + +module Interlayer_Bigger(){ + offset(r=multicolour_gap, $fn=20){ + union(){ children(); } + } +} + +module Interlayer_Smaller(){ + offset(r=-multicolour_gap, $fn=20){ + union(){ children(); } + } +} + +module Underlayer_Smaller(){ + offset(r=-underlayer_smaller, $fn=20){ + union(){ children(); } + } +} + +module FloatingPhaseFraming(phase, zmin) { + frame_inner = + total_sz_actual + + noz_gap * [2,2] * (phase > 0 ? phase : 0.5); + + frame_outer = + frame_inner + + frame_w * [2,2]; + + tower_pos = + -0.5 * frame_inner + + noz_gap * [1,0] * (phases - phase) + + -[1,0] * tower_w + 0.5 * [0,-1] * frame_w; + + // frame for alignment + linear_extrude(height= th_l0) + difference(){ + square(frame_outer, center=true); + square(frame_inner, center=true); + } + + // tower to avoid diagonal traverse to start position + linear_extrude(height= zmin + th_l1) + translate(tower_pos) + square([1,1] * tower_w); + + // trick to pause rather than finishing + if (phase != phases-1) + translate([0,0, z_pause+th_l1]) + linear_extrude(th_l1) + translate(tower_pos) + square([1,1] * tower_w); +} + +echo(str("SET PAUSE AT Z HEIGHT TO ",z_pause)); diff --git a/floating-test.scad b/floating-test.scad new file mode 100644 index 0000000..5f4000c --- /dev/null +++ b/floating-test.scad @@ -0,0 +1,19 @@ +// -*- C -*- + +frameth=0.8; + +l0= 0.425; +l1= 0.25; + +del=l0+l1*2; + +for (r=[0,90,180,270]) + rotate([0,0,r]) + translate([10,-(10+frameth),0]) + cube([frameth, 20+2*frameth, 0.4]); + +translate([-11,-11,0]) +cube([2,2, del + l1]); + +translate([-3,-3, del]) + cube([6,6, l1*2]); diff --git a/flyscreen-handle.scad b/flyscreen-handle.scad new file mode 100644 index 0000000..28753b7 --- /dev/null +++ b/flyscreen-handle.scad @@ -0,0 +1,258 @@ +// -*- C -*- + +opening_height = 7.84; +opening_depth = 7.88; +openingedge_dia = 2.00; +opening_protrh = 2.00; + +pivot_x = 6; +inside_len = 4; + +pivoting_gap = 0.1; + +outside_gap = 3; +outside_len = 13; +outend_height = 3; + +outside_len_bot = 23; + +outside_pushh = 4; +outside_pushslope = 1.4; +outside_push_inadj = 0.82; + +ourcirc_r = 0.5 / 2; + +ribble_dia = 2.2;; + +opening_protr_slop = 0.1; + +intooth_top_slop = 0.1; +inside_h_xgap = 1; + +pivot_r = 2; +pivot_slop = 0.25; + +strap_above = 0.1; +strap_th = 2.5; +strap_below = 3; +strap_width = 5; + +width = 35; +nstraps = 2; + +test_width = 5; + +// calculated + +inside_h = opening_height/2 - opening_protrh - inside_h_xgap/2; + +edge_or = openingedge_dia/2 + opening_protr_slop; + +Q0 = [ openingedge_dia/2, + openingedge_dia/2 + opening_height/2 ]; + +p4p5d = [edge_or + ourcirc_r, 0]; + +P0 = [ pivot_x, pivoting_gap ]; +P4 = Q0 - p4p5d; +P3t = [ P4[0], Q0[1] - openingedge_dia/2 + opening_protrh + - intooth_top_slop - ourcirc_r ]; +P2 = P4 + [ -(inside_len - ourcirc_r*2), 0 ]; +P1 = [ P2[0], P3t[1] - (inside_h + ourcirc_r*2) ]; + +P5 = Q0 + p4p5d; + +P8t = [ outside_len - ourcirc_r, P5[1] ]; +P9t = P8t + [ 0, -(strap_above + strap_th + strap_below - ourcirc_r*2) ]; + +P9b = [ P9t[0], -P9t[1] + outside_gap ]; +P8b = P9b + [ 0, outend_height ]; + +P89eadj = [ outside_len_bot - outside_len, 0 ]; +P8eb = P8b + P89eadj; +P9eb = P9b + P89eadj; + +P6t = P5 + [ 0, outside_pushh - ourcirc_r*2 ]; +P7 = [ P6t[0] + (P6t[1] - P1[1]) / outside_pushslope, + P1[1] ]; + +P3a = P3t + [ -outside_push_inadj, 0 ]; +P6a = P6t + [ -outside_push_inadj, 0 ]; + +outside_push_inadj_slope = (P3t[1]-P4[1]) / (P6a[1]-P5[1]); + +ribble_rad = ribble_dia/2; + +kit_adj_shift = -opening_height - 2.0; + +module ExtrusionSect(){ + cr = openingedge_dia/2; + toph = opening_height/2 + opening_protrh; + + for (my=[0,1]) { + mirror([0,my]) { + translate(Q0) { + hull(){ + circle(r=cr, $fn=20); + translate([-cr,10]) square([cr*2, 1]); + } + } + } + } + translate([-opening_depth, -toph]) { + difference(){ + translate([-5,-5]) + square([opening_depth+6, toph*2+10]); + square([opening_depth+2, toph*2]); + } + } +} + +module PsHull(ps) { + hull(){ + for (p = ps) { + translate(p) + circle(r = ourcirc_r, $fn=10); + } + } +} + +module LeverSect(top, inadj=false){ + P3 = inadj ? P3a : P3t; + P6 = inadj ? P6a : P6t; + P8 = top ? P8t : P8b; + P9 = top ? P9t : P9b; + difference(){ + union(){ + PsHull([P2,P3,P4]); + PsHull([P0,P1,P2,P5,P8,P9]); + } + hull(){ + for (dp = [ [0,0], + (P6-P5), + (P3-P4) + ]) { + translate(Q0 + 5*dp) circle(r=edge_or, $fn=20); + } + } + } +} + +module StrapSectTop(){ + translate(P9t + ourcirc_r * [+1,-1]) { + difference(){ + circle(r = strap_below + strap_th, $fn=40); + circle(r = strap_below, $fn=40); + } + } +} + +module StrapSectBot(inadj=false){ + mirror([0,1]){ + for (dx = [ -(strap_below + strap_th), + 0 ]) { + translate(P9b + [ ourcirc_r + dx, -10 ]) { + square([strap_th, 20]); + } + } + } +} + +module Ribbles(xmax, xmin, y){ + for (x = [ xmax + ourcirc_r - ribble_rad : + -ribble_rad * 4 : + xmin ]) { + translate([x, y]) + circle(r = ribble_rad, $fn=20); + } +} + +module LeverSectTop(){ + difference(){ + union(){ + LeverSect(true, false); + Ribbles(P8t[0], + Q0[0] + edge_or + ribble_rad*2, + P5[1] + ourcirc_r); + } + translate([pivot_x,0]) circle(r= pivot_r + pivot_slop, $fn=20); + } +} + +module LeverSectBot(inadj=false){ + P6 = inadj ? P6a : P6t; + mirror([0,1]) { + LeverSect(false, inadj); + PsHull([P5,P6,P7]); + PsHull([P8b,P8eb,P9eb,P9b]); + Ribbles(P8eb[0], + P9b[0], + P8eb[1]); + translate([pivot_x,0]) circle(r=pivot_r, $fn=20); + } +} + +module Demo(){ + translate([0,0,-5]) color("white") ExtrusionSect(); + LeverSectTop(); + translate([0,0,5]) LeverSectBot(); + color("black") LeverSectBot(true); + color("blue") translate([0,0,10]) StrapSectTop(); + color("purple") translate([0,0,-10]) StrapSectBot(); +} + +module SomeLever() { + // SomeLever(){ LeverBot(inadj); LeverSectBot(); } + difference(){ + linear_extrude(height=width, convexity=100) children(0); + for (i = [ 0 : nstraps - 1 ]) { + translate([0,0, (i + 0.5) / nstraps * width - strap_width/2]) + linear_extrude(height=strap_width, convexity=10) + children(1); + } + } +} + +module Test(){ + linear_extrude(height=test_width, convexity=100) { + translate([0,2,0]) LeverSectTop(); + LeverSectBot(); + translate([0,kit_adj_shift]) LeverSectBot(true); + } +} + +module LeverTop(){ ////toplevel + SomeLever(){ + LeverSectTop(); + StrapSectTop(); + } +} +module LeverBotOutside(){ ////toplevel + SomeLever(){ + LeverSectBot(); + StrapSectBot(); + } +} +module LeverBotInside(){ ////toplevel + SomeLever(){ + LeverSectBot(true); + StrapSectBot(true); + } +} + +module KitOutside(){ ////toplevel + translate([0,2,0]) LeverTop(); + LeverBotOutside(); +} + +module KitInside(){ ////toplevel + translate([0,2,0]) LeverTop(); + LeverBotInside(); +} + +//LeverSectBot(true); +//Demo(); +//LeverTop(); +//Test(); +//Kit(); +//KitInside(); diff --git a/flyscreen-wall-spacer.scad b/flyscreen-wall-spacer.scad new file mode 100644 index 0000000..4abe1ef --- /dev/null +++ b/flyscreen-wall-spacer.scad @@ -0,0 +1,100 @@ +// -*- C -*- + +include + +bracket_th = 2.70; +left_inboard_to_wall = 9.78; +right_inboard_to_wall = 13.21; + +plug_dia = 10; +screw_dia = 5; +bucket_wall = 2.5; +bucket_floor = 2.5; +whole_dia = plug_dia + bucket_wall *2; + +min_spacing = 8; +max_spacing = 19; + +general_spacer_height = 10; + +// calculated + +module Oval(r, dc) { + hull(){ + circle(r); + translate([0, dc]) + circle(r); + } +} + +module MainCircle() { + difference(){ + circle(r = whole_dia/2); + circle(r = screw_dia/2); + } +} + +module MultiSpacer() { + difference(){ + linextr(0, $inboard_to_wall - bracket_th){ + Oval(whole_dia/2, max_spacing); + } + + linextr(bucket_floor, 100) { + Oval(plug_dia/2, max_spacing); + } + + linextr(-1, 100) { + circle(screw_dia/2); + + translate([0, min_spacing]) + Oval(screw_dia/2, max_spacing - min_spacing); + } + } +} + +module AnySpacer(max_z) { + linextr(0, bucket_wall) + MainCircle(); + linextr(0, max_z){ + difference(){ + MainCircle(); + circle(r = plug_dia/2); + } + } +} + +module Spacer($inboard_to_wall) { + AnySpacer($inboard_to_wall - bracket_th); +} + +module Spacers1() { + for (dy = [0, 30]) { + translate([0,dy,0]) { + Spacer($inboard_to_wall = left_inboard_to_wall); + translate([0, 70, 0]) + Spacer($inboard_to_wall = right_inboard_to_wall); + } + } + + translate([40, 0, 0]) + MultiSpacer($inboard_to_wall = left_inboard_to_wall); + translate([40, 70, 0]) + MultiSpacer($inboard_to_wall = right_inboard_to_wall); +} + +module Spacers2() { + for (dy = 30 * [0]) { + echo(dy); + translate([0, dy, 0]) + AnySpacer(general_spacer_height); + } +} + +module Spacers3() { + AnySpacer(6.08); + translate([0, 30, 0]) + AnySpacer(8.18); +} + +Spacers3(); diff --git a/fruit-bowl-stand.scad b/fruit-bowl-stand.scad new file mode 100644 index 0000000..634f4d6 --- /dev/null +++ b/fruit-bowl-stand.scad @@ -0,0 +1,51 @@ +// -*- C -*- + +include + +across = 12.5; +r0 = 71; +h = 36; +feet = 5; + +// calculated + +r_eff_across = across/2 * cos(360/8/2); + +effective_corner = across/2 * [ sin(360/8/2), cos(360/8/2) ]; + +r_mid = r0 + effective_corner[0]; + +h_mid = h - effective_corner[1] - r_eff_across;; + +module XSection(){ + rotate(360/8/2) + circle(r= across/2, $fn=8); +} + +module Ring(){ + rotate_extrude($fa=1) + translate([r_mid, 0,0]) + XSection(); +} + +module Foot(){ + rotate([180,0,0]) + linear_extrude(h_mid) + XSection(); +} + +module Stand(){ + Ring(); + intersection(){ + for (a=[0:feet-1]) { + rotate([0,0, 360*a/feet]) + translate([-r_mid, 0,0]) + Foot(); + } + + linextr(-across - h, across) + circle(r= r_mid + r_eff_across, $fa=1); + } +} + +Stand(); diff --git a/funcs.scad.cpp b/funcs.scad.cpp new file mode 100644 index 0000000..c34d157 --- /dev/null +++ b/funcs.scad.cpp @@ -0,0 +1,86 @@ +// -*- C -*- + +function vecdiff2d(a,b) = [b[0]-a[0], b[1]-a[1]]; +function vecdiff(a,b) = [b[0]-a[0], b[1]-a[1], b[2]-a[2]]; + +#define dsq(i) (a[i]-b[i])*(a[i]-b[i]) +function dist2d(a,b) = sqrt(dsq(0) + dsq(1)); +function dist(a,b) = sqrt(dsq(0) + dsq(1) + dsq(2)); +#undef dsq + +#define vsq(i) (v[i]*v[i]) +function vectorlen2d(v) = sqrt(vsq(0) + vsq(1)); +function vectorlen(v) = sqrt(vsq(0) + vsq(1) + vsq(2)); +#undef vsq + +function unitvector2d(v) = v / vectorlen2d(v); +function unitvector(v) = v / vectorlen(v); + +function atan2vector(v) = atan2(v[1], v[0]); + +// | m[0][0] m[0][1] | +// | m[1][0] m[1][1] | +function determinant2(m) = (m[0][0] * m[1][1] - m[0][1] * m[1][0]); + +function clockwise2d(v) = [v[1], -v[0]]; + +function rotate2d(theta, v) = [ v[0] * cos(theta) - v[1] * sin(theta), + v[1] * cos(theta) + v[0] * sin(theta) ]; + +// intersection of lines p1..p2 and p3..p4 +function line_intersection_2d(p1,p2,p3,p4) = [ + // from https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection#Given_two_points_on_each_line + #define XY12 determinant2([p1,p2]) + #define XY34 determinant2([p3,p4]) + #define XU12 QU(0,1,2) + #define XU34 QU(0,3,4) + #define YU12 QU(1,1,2) + #define YU34 QU(1,3,4) + #define QU(c,i,j) determinant2([[ p##i[c], 1 ], \ + [ p##j[c], 1 ]]) + #define DENOM \ + determinant2([[ XU12, YU12 ], \ + [ XU34, YU34 ]]) + //---- + determinant2([[ XY12, XU12 ], + [ XY34, XU34 ]]) / DENOM, + determinant2([[ XY12, YU12 ], + [ XY34, YU34 ]]) / DENOM, + ]; + #undef XY12 + #undef XY34 + #undef XU12 + #undef XU34 + #undef YU12 + #undef YU34 + #undef QU + #undef DENOM + + +function circle_point(c, r, alpha) = [ c[0] + r * cos(alpha), + c[1] + r * sin(alpha) ]; + +#define d (dist2d(a,c)) +#define alpha (atan2(a[1]-c[1],a[0]-c[0])) +#define gamma (asin(r / d)) +#define beta (alpha + 90 - gamma) + +function tangent_intersect_beta(c,r,a) = + beta; + +function tangent_intersect_b(c,r,a) = + circle_point(c, r, beta); +#undef d +#undef alpha +#undef gamma +#undef beta + +function tangents_intersect_beta(cbig,rbig,csmall,rsmall) = + tangent_intersect_beta(cbig,rbig-rsmall,csmall); + +function reflect_in_y(p) = [-p[0], p[1]]; + +function angle_map_range(in,base) = + in < base ? in + 360 : + in >= base + 360 ? in - 360 : + in; diff --git a/hole-repair-20191117.scad b/hole-repair-20191117.scad new file mode 100644 index 0000000..0138c67 --- /dev/null +++ b/hole-repair-20191117.scad @@ -0,0 +1,49 @@ +// -*- C -*- + +post_dia = 23.0; +post_height = 20; + +th = 4; + +nom_hole = 25; +min_r = 15 + nom_hole/2; +maj_r = 15 + nom_hole/2; + +postwall_th = 2; + +$fa=1; +$fs=1; + +module Profile(r) { + polygon([ [0, 0], + [r, 0], + [r-th, th], + [0, th] ]); +} + +module Body(){ + hull(){ + for (x= [-1,+1] * (maj_r-min_r)) + translate([x,0,0]) + rotate_extrude() + Profile(min_r); + } +} + +module Post(){ + difference(){ + translate([0,0,-1]) + cylinder(r= post_dia/2, h= post_height+1); + translate([0,0,-2]) + cylinder(r= post_dia/2 - postwall_th, h= post_height+3); + } +} + +module Cover(){ + rotate([0,180,0]) Body(); + Post(); +} + +//Body(); +//Post(); +Cover(); diff --git a/hole-transfer-punch.scad b/hole-transfer-punch.scad new file mode 100644 index 0000000..d9e4859 --- /dev/null +++ b/hole-transfer-punch.scad @@ -0,0 +1,32 @@ +// -*- C -*- + +include + +dia = 6; + +point = 3; +solid = 3; + +$fa= 1; +$fs = 0.1; + +// calculated + +depth = dia * 1.5; + +module Blivet(){ + rotate_extrude(){ + polygon([[ 0,0 ], + [ point, 0 ], + [ point, solid ], + [ 0, solid + point]]); + } + linextr(0, solid){ + square(center=true, [ dia*3, dia ]); + } + linextr(-depth, solid){ + circle(r= dia/2); + } +} + +Blivet(); diff --git a/holetest.scad b/holetest.scad new file mode 100644 index 0000000..328ef2d --- /dev/null +++ b/holetest.scad @@ -0,0 +1,52 @@ +// -*- C -*- + +h=2; + +$fa=1; +$fs=0.1; + +label=true; + +spc= 7; +l = 50; +w = 10; + +lt = 0.5; +lw = 10; + +// calculated + +// Actual sizes (according to calipers) of things that fit +// A +// C - 1.88mm (M3 screw) +// E - 2.97mm (3mm HSS bit shank) +// G - +// I - 3.15mm tight fit (Yale padlock from extra padlocks tray) +// K - 3.33mm (M3.5 screw) + +ly0 = -w/2 -lw; + +difference(){ + union(){ + cube([l,w,h], center=true); + if (label) + translate([-l/2, ly0, -h/2]) + cube([l, lw, lt]); + } + + for (i=[0:2:10]) { + + sz = 3 + 0.5 * i/10; + + echo(sz); + translate([(i-5)/2 * spc, 0, -7 ]) { + cylinder(r= sz/2, h=14); + linear_extrude(height=14, convexity=100) { + translate([0, ly0 + lw * .2]) + text(halign="center", + size= lw * .6, font="DejaVu Sans:style=Bold", + chr(i + 65)); + } + } + } +} diff --git a/hotel-piece-model.scad b/hotel-piece-model.scad new file mode 100644 index 0000000..2f8af81 --- /dev/null +++ b/hotel-piece-model.scad @@ -0,0 +1,29 @@ +// -*- C -*- + +h = 15; +w = 20; +l = 30; +roof = 10; +eave = 1; +peakw = 1; +overhang = 3.0; +chimnd= 7; +chimnhr = 1.00; + +$fs = 0.1; + +module Hotel(){ + cube([w,l,h + 0.1]); + hull(){ + translate([0,0, h] + overhang * [-1,-1,0]) + cube([w,l,eave] + overhang * [2,2,0]); + translate([0,0, h] + overhang * [0,-1,0] + + (w-peakw) * 0.5 * [1,0,0]) + cube([peakw, l, roof] + overhang * [0,2,0]); + } + translate([w/4, l/2, h] + overhang * [-0.5, 0,0]) + cylinder(r= chimnd/2, h = roof * chimnhr); +} + +scale(1.11) +Hotel(); diff --git a/itx-aperture-grommet.scad b/itx-aperture-grommet.scad new file mode 100644 index 0000000..53f74fa --- /dev/null +++ b/itx-aperture-grommet.scad @@ -0,0 +1,56 @@ +// -*- C -*- + +include +include + +ap_width = 21.30; +ap_height = 16.45; +tot_height = 22.74 + 1.0; +screw_ctr_to_tr = [ 7.89, 3.87 ]; + +tab_th = 2.5; +wall_th = 1; +wall_h = 2; + +app_slop = 0.60; // total across both sides + +// calculated + +tab_h = tot_height - ap_height; + +real_main_sz = [ ap_width, ap_height ] - app_slop * [ 1,1 ]; +real_all_sz = real_main_sz + tab_h * [0,1]; +real_inner_sz = real_main_sz - wall_th * [ 2,1 ]; + +screw_pos = real_all_sz - (screw_ctr_to_tr - 0.5 * app_slop * [1,1]); + +module GapPlan() { + rectfromto([ wall_th, -1 ], + real_main_sz - wall_th * [1,1]); +} + +module MainPlan() { + rectfromto([0,0], + real_main_sz); +} + +module AllPlan() { + rectfromto([0,0], real_all_sz); +} + +module Grommet(){ ////toplevel + difference(){ + union(){ + linextr(0, tab_th + wall_h) MainPlan(); + linextr(0, tab_th) AllPlan(); + } + linextr(-1, tab_th + wall_h + 1) GapPlan(); + translate(concat(screw_pos, [-1])) + english_thread(diameter = 0.1380, + threads_per_inch = 32, + length = tab_th + 2, + internal = true); + } +} + +Grommet(); diff --git a/keyring-kay.scad b/keyring-kay.scad new file mode 100644 index 0000000..9ebb34a --- /dev/null +++ b/keyring-kay.scad @@ -0,0 +1,59 @@ +// -*- C -*- + +letterheight = 25; +linewidth = 3.5; +letterthick = 2.5; + +basethick = 2.5; + +xborder = 5; +yborder = 5; + +kdiag = 1; +kprop = 0.50; + +diaglinewidth = linewidth * sqrt(1 + kdiag*kdiag); + +ringholerad = 2.5; +ringedgewidth = 3; + +module kay_leg (transamount, llen, mir) { + translate([0,transamount,0]) + mirror([0,mir,0]) + translate([0,-0.1,0]) + multmatrix([[1,kdiag,0,0], + [0,1,0,0], + [0,0,1,0], + [0,0,0,1]]) + cube([diaglinewidth, llen + 0.1, letterthick]); +} + +module kay () { + translate([0.1,0,0]) + cube([linewidth, letterheight, letterthick]); + kay_leg(letterheight*kprop, letterheight*(1-kprop), 0); + kay_leg(letterheight*kprop, letterheight*kprop, 1); +} + +totalw = letterheight*kprop + diaglinewidth + xborder*2; +totalh = letterheight + yborder*2; +basez = -(basethick-0.1); + +module main () { + kay(); + translate([-xborder, -yborder, basez]) + cube([totalw, totalh, basethick]); +} + +module ring (rad, extra) { + translate([totalw/2 - xborder, totalh - yborder, basez-extra]) + cylinder(r=rad, h=basethick + extra*2, $fn=30); +} + +difference(){ + union() { + main(); + ring(ringholerad + ringedgewidth/2, 0); + } + ring(ringholerad, 1); +} diff --git a/knifeblock,BlockPrint.auto.slic3r b/knifeblock,BlockPrint.auto.slic3r new file mode 100644 index 0000000..22dacf8 --- /dev/null +++ b/knifeblock,BlockPrint.auto.slic3r @@ -0,0 +1 @@ +fill_density = 0.1 diff --git a/knifeblock-knives-filter b/knifeblock-knives-filter new file mode 100755 index 0000000..17cff74 --- /dev/null +++ b/knifeblock-knives-filter @@ -0,0 +1,36 @@ +#!/usr/bin/perl -w + +use strict; +use POSIX; + +our %want; + +our $nknives = 3; + +our @part_order = qw(h b l); + +my $want = shift @ARGV; +my ($wknife,$wparts) = $want =~ m/^(\d)([a-z]+)$/ or die; + +sub want ($) { + my ($colournum) = @_; + my $knife = $nknives-1 - ($colournum-1) % $nknives; + return 0 unless $knife == $wknife; + my $part = $part_order[ floor(($colournum-1) / $nknives) ]; + die "huh colour $colournum?" unless defined $part; + return 0 unless $part =~ m/[$wparts]/o; + print STDERR "$0: including colour $colournum ($knife $part)\n"; + return 1; +} + +our $drop; +while (<>) { + if (m/^\S/) { + $drop = + m/^2 5 / || + (m/^(?:3 1|2 3) \d+ \d+ (\d+) / && !want($1)); + } + next if $drop; + + print or die $!; +} diff --git a/knifeblock-knives-photo.jpg b/knifeblock-knives-photo.jpg new file mode 100644 index 0000000..0d757cc Binary files /dev/null and b/knifeblock-knives-photo.jpg differ diff --git a/knifeblock-knives-trace.fig b/knifeblock-knives-trace.fig new file mode 100644 index 0000000..c42c2c6 --- /dev/null +++ b/knifeblock-knives-trace.fig @@ -0,0 +1,66 @@ +#FIG 3.2 Produced by xfig version 3.2.5b +Landscape +Center +Metric +A4 +100.00 +Single +-2 +1200 2 +2 5 0 1 0 -1 50 -1 -1 0.000 0 0 -1 0 0 5 + 0 knifeblock-knives-photo.jpg + 585 270 11557 270 11557 8499 585 8499 585 270 +2 3 1 1 9 7 30 -1 -1 4.000 0 0 7 0 0 6 + 3093 6395 6633 6470 10898 6641 5808 7070 5818 6778 3093 6395 +2 3 1 1 8 7 30 -1 -1 4.000 0 0 7 0 0 6 + 3038 4586 6578 4661 10843 4832 5753 5261 5763 4969 3038 4586 +2 3 1 1 7 7 30 -1 -1 4.000 0 0 7 0 0 6 + 2978 2996 6518 3071 10783 3242 5693 3671 5703 3379 2978 2996 +3 1 0 1 2 7 40 -1 -1 0.000 0 0 0 21 + 5858 5445 6063 5290 6283 5115 6523 4865 6658 4670 6768 4510 + 6758 4405 6438 4365 5923 4315 5423 4295 4823 4290 4418 4300 + 4003 4335 3648 4380 3593 5170 3883 5190 4368 5185 4598 5160 + 4993 5075 5718 5365 5838 5435 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 +3 1 0 1 3 7 40 -1 -1 0.000 0 0 0 23 + 5878 6218 5318 6198 4858 6198 4463 6208 4118 6223 3908 6258 + 3908 6953 4293 6978 4668 6938 5078 6873 5693 7028 5718 7113 + 5783 7143 5873 7128 6028 7028 6243 6833 6453 6608 6583 6458 + 6638 6398 6598 6348 6548 6303 6418 6283 6033 6243 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 +3 1 0 1 1 7 40 -1 -1 0.000 0 0 0 20 + 5918 3753 6120 3555 6435 3285 6615 3060 6840 2745 6975 2520 + 6975 2475 6615 2430 5985 2385 5490 2355 4950 2340 4498 2360 + 3883 2385 3458 2425 3443 3430 3838 3435 4248 3410 5593 3723 + 5783 3858 5773 3848 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 +3 1 0 1 4 7 40 -1 -1 0.000 0 0 0 23 + 9223 2689 8811 2659 8398 2621 7993 2606 7603 2584 7228 2569 + 6861 2561 5871 2539 5121 3529 5818 3694 5991 3769 6583 3776 + 7206 3769 8113 3746 8826 3709 9298 3649 9816 3581 10311 3431 + 10737 3204 10702 3099 10551 3026 10243 2869 9606 2734 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 +3 1 0 1 5 7 40 -1 -1 0.000 0 0 0 23 + 7191 5366 8098 5329 8586 5291 9051 5194 9298 5119 9652 4993 + 9802 4898 9812 4828 9722 4748 9283 4676 9028 4616 8706 4594 + 8278 4549 7851 4534 7371 4534 6883 4511 6141 4511 5998 4744 + 5661 4969 5593 5366 6043 5351 6478 5366 7026 5374 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 +3 1 0 1 6 7 40 -1 -1 0.000 0 0 0 21 + 6816 7069 7191 7047 7558 6994 7896 6927 8097 6852 8277 6772 + 8267 6677 8067 6622 7881 6544 7611 6499 7356 6454 7093 6432 + 6838 6409 6561 6409 6096 6387 5901 6454 5578 6784 5668 7024 + 5811 7069 6141 7084 6388 7077 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 diff --git a/knifeblock.scad b/knifeblock.scad new file mode 100644 index 0000000..c1f1869 --- /dev/null +++ b/knifeblock.scad @@ -0,0 +1,346 @@ +// -*- C -*- + +// properties of the knives +nknives = 3; +widths = [15.5, 15.8, 19.0]; +handlelenbase = 75; +handlelendelta = [-15, 0, 10]; +locations = [-35, 0, 37]; +bladew = 5; // 2.5 +maxhandledepth = 45; + +templatescale = 27.2 / 19.6; + +coverlonglen = 120; // xxx +covershortlen = 70; // xxx + +// other tuneables +front = 5; +back = 5; +height = 50; +minsidein = 4; +minsideout = 4; + +frontbackslop = 0.25; + +knifewidthslop = 2.0; + +screwbackdepth = 6.0 - 1.0; +screwdia = 4.0 + 0.5; +screwcsinkdia = 9.8 + 1.0; + +screwabove = 15; + +coverthick = 2.4; +coverside = coverthick; + +covertopwing = 15; +covertopwingbase = 20; +coveredge = 3; + +holesize = 12.5; +holestrut = 7; +holeedge = 4; + +holeoffx = 0.33; +holeoffy = 0.23; + +indentdepth = 1; +indentoutersize = holesize + 2.15; +indentinnersize = indentoutersize - indentdepth * 3.0; + +pegstem = 3.5; +peghead = 10; +pegstemheight = 2; +pegheight = 9; +peglen = 12; + +recessblockwidth = peghead + pegstem*3; +recessblockheight = peglen/2 + pegstem*1.5; + +pegsloph = 0.5; +pegslopv = 0.5; +pegslopl = 0.5; + +pegdepthproportion = 0.80; + +// computed + +function width(k) = widths[k] + knifewidthslop; + +side = minsidein + screwcsinkdia + minsideout; +totaldepth = front + maxhandledepth + back; + +minkx = locations[0] - width(0) /2; +maxkx = locations[nknives-1] + width(nknives-1)/2; + +minx = minkx - side; +maxx = maxkx + side; + +holepitch = holesize+holestrut; + +pegrecess = pegdepthproportion*totaldepth - 0.5*peglen; + +module ImportTemplate(w,k,t) { + fn = str("knifeblock-knives-t",k,t,".dxf"); + echo(fn); + translate([0,0, -w/2]) + linear_extrude(height=w) + scale(templatescale) import(file=fn, convexity=100); +} + +module Knife(k){ + ImportTemplate(bladew, k,"bl"); + hull(){ + ImportTemplate(width(k), k,"hl"); + translate([-100,0,0]) + ImportTemplate(width(k), k,"hl"); + } +} + +module DoKnife(k){ + translate([locations[k],0,0]){ + rotate([0,90,0]) + translate([-(handlelenbase + handlelendelta[k]),0,0]) + Knife(k); + } +} + +module DoKnives(){ + for (k=[0:nknives-1]) + DoKnife(k); +} + +module ScrewHole(){ + translate([0,-50,0]) + rotate([-90,0,0]) + cylinder(r=screwdia/2, h=150, $fn=40); + translate([0, totaldepth-front - screwbackdepth, 0]) + rotate([90,0,0]) + cylinder(r=screwcsinkdia/2 / (sqrt(3)/2), h=100, $fn=6); +} + +module PegTemplate(apex){ + for (mx=[0,1]) for (my=[0,1]) { + mirror([mx,0,0]) mirror([0,my,0]) + polygon([[-0.1, -0.1], + [pegstem/2, -0.1], + [pegstem/2, pegstemheight/2], + [peghead/2, pegheight /2], + [-0.1, pegheight /2 + apex]]); + } +} + +module AtSides(){ + translate([minx,0,0]) child(0); + translate([maxx,0,0]) mirror([1,0,0]) child(1); +} + +module BlockPegSlot(){ + translate([recessblockwidth/2, pegrecess - peglen, -height]){ + rotate([-90,0,0]) linear_extrude(height=totaldepth){ + PegTemplate(peghead/2 * 1.2); + } + } +} + +module DecorativeIndents(){ + translate([0, -front, 0]) + rotate([90,0,0]) + HexGrid(-height, 0, minx,maxx) { + hull(){ + translate([0, 0, -indentdepth]) + cylinder(r=indentinnersize/2, h=indentdepth, $fn=40); + cylinder(r=indentoutersize/2, h=indentdepth, $fn=40); + } + } +} + +module Block(){ + sidemidx = minsideout + screwcsinkdia/2; + + difference(){ + mirror([0,0,1]) { + translate([minx, -front, 0]) + cube([maxx-minx, totaldepth, height]); + } + for (x=[minx + sidemidx, maxx - sidemidx]) { + translate([x, 0, -screwabove]) + ScrewHole(); + } + for (yshift=[-1,1]) + translate([0, yshift * frontbackslop, 0]) + DoKnives(); + AtSides() { BlockPegSlot(); BlockPegSlot(); } + DecorativeIndents(); + } +} + +module BlockPrint(){ ////toplevel + rotate([0,0,90]) + Block(); +} + +module CoverTemplate(){ + linear_extrude(height=coverthick) + polygon([[minx, 0], + [maxx, 0], + [maxx, coverlonglen+0.1], + [maxx - coverside, coverlonglen+0.1], + [minx, covershortlen+0.1]]); +} + +module CoverSide(len){ + translate([0, 0 ,0]) { + rotate([90,0,90]) + linear_extrude(height=coverside) + polygon([[0, 0], + [0, totaldepth], + [covertopwing, totaldepth], + [covertopwingbase, coverside + coverthick], + [len - covertopwingbase, coverside + coverthick], + [len - covertopwing, totaldepth], + [len, totaldepth], + [len, 0]]); + cube([recessblockwidth, recessblockheight, totaldepth]); + } +} + +module Peg(){ + echo("peg angle slope (must be <1)", + (peghead-pegstem)/(pegheight-pegstemheight)); + dx = pegsloph; + dy = pegslopv; + rotate([90,0,0]) { + linear_extrude(height=peglen-pegslopl) { + intersection(){ + translate([-dx,-dy,0]) PegTemplate(0); + translate([-dx,+dy,0]) PegTemplate(0); + translate([+dx,+dy,0]) PegTemplate(0); + translate([+dx,-dy,0]) PegTemplate(0); + } + } + } +} + +module CoverPegSlot(coverlen){ + translate([recessblockwidth/2, 0, -1]){ + linear_extrude(height= 1 + pegrecess + 0.5*peglen){ + PegTemplate(0); + } + } +} + +module HolesScope(){ + intersection_for (dx=[-1,+1]) { + intersection_for (dy=[-1,+1]) { + translate([dx * holeedge, dy * holeedge, -5]) + scale([1,1,10]) + CoverTemplate(); + } + } +} + +module HexGrid(xa,xb,ya,yb) { + imin = floor(xa / holepitch); + imax = ceil(xb / holepitch); + jmin = floor(ya / (sqrt(3)*holepitch)); + jmax = ceil(yb / (sqrt(3)*holepitch)); + echo("HexGrid ",imin,imax,jmin,jmax); + for (i=[imin:imax]) { + for (j=[jmin:jmax]) { + translate([(j * sqrt(3) + holeoffx) * holepitch, + (i + 0.5 + holeoffy) * holepitch, + 0]) { + child(); + translate([sqrt(3)/2 * holepitch, -0.5 * holepitch, 0]) + child(); + } + } + } +} + +module Hole(){ + cylinder(r=holesize/2, h=40, $fn=40); +} + +module Holes(){ + intersection(){ + translate([0, 0, -20]) + HexGrid(0, coverlonglen, minx, maxx) + Hole(); + HolesScope(); + } +} + +module CoverCover(){ + difference(){ + CoverTemplate(); + Holes(); + } +} + +module Cover(){ + difference(){ + union(){ + CoverCover(); + AtSides() { CoverSide(covershortlen); CoverSide(coverlonglen); } + } + AtSides() { CoverPegSlot(); CoverPegSlot(); } + } +} + +module CoverAligned(){ + translate([0,-front,-height]) + rotate([-90,0,0]) + Cover(); +} + +module DemoPeg(){ + translate([recessblockwidth/2, pegrecess, -height]) + Peg(); +} + +module Demo(){ ////toplevel + %Block(); + DoKnives(); + color([0,0,1]) CoverAligned(); + color([1,0,0]) AtSides() { DemoPeg(); DemoPeg(); } +} + +module Pegs(){ ////toplevel + Peg(); + translate([-peghead-3, 0,0]) Peg(); +} + +module CoverParts(){ ////toplevel + Cover(); + translate([0, coverlonglen, pegheight/2-pegslopv]) + Pegs(); +} + +module FrontDemo(){ ////toplevel + color([1,0,1]) Block(); + color([1,0,1]) CoverAligned(); + color([0,0,0]) DoKnives(); +} + +module BlockFrontTest(){ ////toplevel + intersection(){ + Block(); + translate([minx-10, -front-10, -height-10]) { + cube([75,14,35]); + cube([75,25,13]); + } + } +} + +//Block(); +//Demo(); +//Cover(); +//CoverParts(); +//Peg(); +//Cover(); +//Holes(); +//%CoverTemplate(); +//Pegs(); diff --git a/ksafe-base.scad b/ksafe-base.scad new file mode 100644 index 0000000..c2e2704 --- /dev/null +++ b/ksafe-base.scad @@ -0,0 +1,373 @@ +// -*- C -*- + +// from actual ksafe +bolt_above = 8.50 - 0.50; +bolthole_height = 4.24 + 1.00; +wall_thick = 4.50; +bolthole_width = 16.62 + 1.00; +main_sz = 149.06 - 0.25; +cnr_rad = 19.5; +lidinner_thick_allow = 20.78 + 0.50; +display_width = 69.81 - 0.50; + +dpp3 = [ -5.5, 8.5 ]; +dpp2 = [ -11.0, 7.0 ]; +dpp1 = [ -34.0, 14.0 ]; + +// other parameters +web_thick = 4; +web_height = 20; // excluding wall and base thick +bolthole_rhs = 20; +bolthole_lhs = 20; +boltreinf_thick = 6; +anchor_wall_space = 25; +base_thick = 4; +space = 25; +anchor_thick = 4; +anchor_rad = 4; +bevel = 8; +string_slot = 3.0; +string_depth = 6.0; +thumbslot_depth = 5.0; +thumbslot_width = 15.0; +thumbslot_between = 10; +ksafecover_lip = 4.62; +display_rhs_secs = 15; +dcover_endthick = 3.0; +dcover_mainthick = 5.0; +dcover_slop_height = 0.35; +dcover_slop_depth = 0.25; +dcover_slop_inside = 1.50; +dcover_commonvertoff = 0.00; // slop_height or slop_inside is added too +dcover_edge_gap_more_width = 2.0; // each side + +// ----- calculated ----- + +hsz = main_sz/2; +cut = main_sz + 20; + +gppA = [0,0]; +gppB = gppA - [ wall_thick, 0 ]; + +gppL = [ gppB[0], -(lidinner_thick_allow + space + base_thick) ]; + +yw1 = -web_thick/2; +yw2 = yw1 - bolthole_rhs; +yw3 = yw2 - anchor_thick; +yw4 = yw3 - anchor_wall_space; +yw5 = yw4 - wall_thick; +yw6 = -(hsz - cnr_rad + 0.1); + +yw10 = web_thick/2; +yw11 = yw2 + anchor_wall_space; +yw12 = yw11 + wall_thick; +yw13 = -yw6; + +cpp1 = dpp1 + [ dcover_slop_depth, dcover_slop_height ]; +cpp2 = [ dpp2[0] - dcover_slop_depth, dpp3[1] + dcover_slop_height ]; +cppH = cpp1 + [ 0, dcover_endthick ]; +cppA = [ cpp2[0], dpp3[1] + dcover_slop_inside ]; +cppK = cppA + [ 0, dcover_mainthick ]; +cppZ = [ -ksafecover_lip, -dcover_commonvertoff ]; +cppD = cppZ + [ 0, -dcover_slop_inside ]; +cppC = [ dcover_slop_inside, cppD[1] ]; +cppF = cppC + dcover_mainthick * [1,-1]; +cppB = [ cppC[0], cppA[1] ]; +cppG = [ cppF[0], cppK[1] ]; +cppE = [ cppD[0], cppF[1] - (cppF[0] - cppD[0]) ]; + +// anchor + +anchor_b = anchor_thick + anchor_rad; +appM = gppL + anchor_b * [1,1]; + +a_bevel = 2 * anchor_b * (1 + sqrt(0.5)); + +module upp_app_Vars(t_bevel){ + $xppE = gppL + t_bevel * [0,1]; + $xppF = gppL + t_bevel * [1,0]; + + $xppJ = $xppE + wall_thick * [ 1, tan(22.5) ]; + $xppI = $xppF + base_thick * [ tan(22.5), 1 ]; + + // must pass a_bevel for t_bevel for these to be valid + $gppP = gppA + [0,-1] * lidinner_thick_allow; + $gppQ = $gppP + [1,-1] * web_height; + $gppR = $xppJ + [ 1, tan(22.5) ] * web_height; + $gppS = $xppI + [ tan(22.5), 1 ] * web_height; + $gppT = [ $gppQ[0], $xppE[1] ]; + + children(); +} + +module upp_app_Profile(){ + polygon([ gppA, + gppB, + $xppE, + $xppF, + $xppF + [1,0], + $xppI + [1,0], + $xppJ ], + convexity=10); +} + + +module UsualProfile(){ + upp_app_Vars(bevel) upp_app_Profile(); +} + +module NearAnchorProfile(){ + upp_app_Vars(a_bevel) upp_app_Profile(); +} + +module AnchorProfile(){ + upp_app_Vars(a_bevel) { + + upp_app_Profile(); + + difference(){ + hull(){ + polygon([ $xppE, + $xppF, + $xppF + [0,1], + $xppE + [1,0] ], + convexity=10); + translate(appM) circle(r= anchor_b); + } + translate(appM) circle(r= anchor_rad); + } + } +} + +module AnchorWallProfile(){ + UsualProfile(); + NearAnchorProfile(); + hull(){ + for (bev = [bevel, a_bevel]) { + upp_app_Vars(bev) { + polygon([ $xppE, + $xppF, + $xppI, + $xppJ ], + convexity=10); + } + } + } +} + +module WebProfile(){ + upp_app_Vars(a_bevel){ + if ($gppR[1] <= $gppP[1]) { + polygon([ $gppP, + $xppE, + $gppT, + $gppQ ]); + polygon([ $gppP, + $xppE, + $xppF, + $gppS, + $gppR ], + convexity=10); + } else { + polygon([ $gppP, + $xppE, + $xppF, + $gppS, + $gppP + web_height * [1,0] ], + convexity=10); + } + polygon([ $gppS, + $xppF, + $xppF + [1,0], + $gppS + [1,0] ], + convexity=10); + } +} + +module SomeBaseProfile(I, F){ + polygon([ I, + F, + [ hsz+1, F[1] ], + [ hsz+1, I[1] ] ]); +} + +module BaseProfile(){ + SomeBaseProfile($xppI, $xppF); +} + +module DCoverProfileRaw(){ + polygon([ cpp1, + cpp2, + cppA, + cppB, + cppC, + cppD, + cppE, + cppF, + cppG, + cppK, + cppH ], + convexity = 10); +} + +module DCoverProfile(){ + mirror([1,0]) + translate(-cppZ) + DCoverProfileRaw(); +} + +module SWalls(ymin, ymax, t_bevel) { + upp_app_Vars(t_bevel) { + translate([0,ymin,0]) + mirror([0,1,0]) + rotate([90,0,0]) + linear_extrude(height= ymax-ymin, convexity=10) + for (xm=[0,1]) + mirror([xm,0]) + translate([-hsz, 0]) + children(); + } +} + +module AtTwoCorners(){ + for (xm=[0,1]) { + mirror([xm,0,0]) + translate((hsz - cnr_rad) * [1,1]) + intersection(){ + rotate_extrude(convexity=10) + translate([-cnr_rad,0]) + children(); + translate([0,0,-250]) + cube([50,50,500]); + } + } +} + +module Box(){ + /// corners, and front and back of base + for (ym=[0,1]) mirror([0,ym,0]) { + AtTwoCorners(){ + UsualProfile(); + } + hull() AtTwoCorners(){ + upp_app_Vars(bevel){ + polygon([ $xppI, + $xppF, + $xppF + [0.1, 0], + $xppI + [0.1, 0] + ]); + } + } + } + + // side walls and base + SWalls(yw6 , yw4 , bevel ) { UsualProfile(); BaseProfile(); } + SWalls(yw5 , yw4 , a_bevel) { AnchorWallProfile(); BaseProfile(); } + SWalls(yw5 , yw12, a_bevel) { NearAnchorProfile(); BaseProfile(); } + SWalls(yw3 , yw2 , a_bevel) { AnchorProfile(); BaseProfile(); } + SWalls(yw11, yw12, a_bevel) { AnchorWallProfile(); BaseProfile(); } + SWalls(yw11, yw13, bevel ) { UsualProfile(); BaseProfile(); } + SWalls(yw1, yw10, a_bevel) { WebProfile(); SomeBaseProfile($gppS, $xppF); } + + // front and rear walls + rotate([0,0,90]) SWalls(yw6, yw13, bevel) UsualProfile(); +} + +module DCover(){ ////toplevel + translate([ -display_width/2, -hsz, 0 ]) + rotate([0,90,0]) + rotate([0,0,90]) + linear_extrude( display_width - display_rhs_secs, convexity = 10) + DCoverProfile(); +} + +module DCoverSupportAllowance(){ + translate([0, -hsz, 0]) + cube(center=true, + [ display_width + 2 * dcover_edge_gap_more_width, + wall_thick * 2, + dcover_slop_inside * 2 + 0.01 ]); +} + +module BoltHoles(){ + translate([0,0, -(bolt_above + 0.5 * bolthole_height)]) + cube(center=true, [ cut, bolthole_width, bolthole_height ]); +} + +module KsafeBase(){ ////toplevel + DCover(); + + difference(){ + Box(); + + BoltHoles(); + + // string slot + translate([ -cut, + -(bolthole_width/2 + bolthole_rhs), + 1 ]) + mirror([0,1,0]) mirror([0,0,1]) + cube([ cut*2, + string_slot, + lidinner_thick_allow + string_depth + 1 ]); + + // thumb slots + for (mx=[0,1]) mirror([mx,0,0]) { + translate([ thumbslot_between/2, + 0, + -thumbslot_depth ]) + cube([ thumbslot_width, + cut, + thumbslot_depth+1 ]); + } + + DCoverSupportAllowance(); + } +} + +module DemoProfiles(){ ////toplevel + translate([0,0,-2]) color("yellow") AnchorWallProfile(); + color("red") AnchorProfile(); + translate([0,0,2]) color("black") NearAnchorProfile(); + translate([0,0,4]) color("blue") UsualProfile(); + translate([0,0,-4]) color("pink") WebProfile(); + translate([0,0,6]) color("purple") DCoverProfile(); +} + +module RimTest(){ ////toplevel + intersection(){ + Box(); + cube(center=true, [ main_sz*2, main_sz*2, + 2.5 ]); + } +} + +module DCoverTest(){ ////toplevel + intersection(){ + difference(){ + union(){ + Box(); + DCover(); + } + DCoverSupportAllowance(); + BoltHoles(); + } + translate([0,0,60]) + cube(center=true, [ main_sz*2, main_sz*2, + 2 * (60 + 10) ]); + } +} + +module BoltTest(){ ////toplevel + dy = 0.5 * (bolthole_width+4); + intersection(){ + KsafeBase(); + translate([ 0, -dy, -(bolt_above + bolthole_height + 1) ]) + cube([ main_sz, dy*2, 50 ]); + } +} + +//DemoProfiles(); +//Box(); +//KsafeBase(); +//RimTest(); diff --git a/laptop-camera-tripod-bracket.scad b/laptop-camera-tripod-bracket.scad new file mode 100644 index 0000000..cc6ffb2 --- /dev/null +++ b/laptop-camera-tripod-bracket.scad @@ -0,0 +1,76 @@ +// -*- C -*- + +// High Detail +// support enabled +// distance x/y 2.5mm +// fill density 30% + +laptop_w = 310; +laptop_th_rear = 14; +laptop_th_front = 11; +laptop_halfdepth_real = 125; +laptop_halfdepth = 115; //125; +laptop_inner_x_clear = 95; + +include +include + +bar_w = 15; +bar_th = 12; +flex_allow = 3; +claw_th = 6; +claw_overlap = 15; +mount_dia = 50; + +min_ceil = 1; + +//$test=true; +$test=false; + +module ClawProfile(laptop_th){ + laptop_zmin = bar_th + flex_allow; + laptop_zmax = laptop_zmin + laptop_th; + difference(){ + rectfromto([-claw_overlap, 0], + [claw_th, laptop_zmax + claw_th]); + rectfromto([-claw_overlap-1, laptop_zmin ], + [ 0, laptop_zmax ]); + } +} + +module ClawBar(inner_len, laptop_th){ + rotate([0,0,180]) linextr_y_xz(-bar_w/2, +bar_w/2) { + rectfromto([0,0], + [inner_len, bar_th]); + translate([inner_len, 0]) + ClawProfile(laptop_th); + } +} + +module Body(){ + translate([0, laptop_halfdepth - laptop_halfdepth_real, 0]) + for (m=[0,1]) { + mirror([m,0]) { + ClawBar(laptop_w/2, laptop_th_rear); + translate([ laptop_w/2 - laptop_inner_x_clear + bar_w/2, 0]) + rotate([0,0,-90]) + ClawBar(laptop_halfdepth, laptop_th_front); + } + } + cylinder(r = mount_dia/2, h= bar_th); +} + +module Bracket(){ + difference(){ + Body(); + rotate([0,180,0]) + CameraMountThread( bar_th + 2 ); + } + translate([0,0, bar_th-min_ceil]) + cylinder(r= mount_dia/2-1, h=min_ceil); +} + +//ClawProfile(laptop_th_front); +//ClawBar(125, laptop_th_front); +//Body(); +Bracket(); diff --git a/laptop-sound-cable-hooks.scad b/laptop-sound-cable-hooks.scad new file mode 100644 index 0000000..8cfd468 --- /dev/null +++ b/laptop-sound-cable-hooks.scad @@ -0,0 +1,145 @@ +// -*- C -*- + +include + +wall_th = 2; +hook_th = 4; +hook_hole = 4; +hook_w_min = 6; +hook_hook = 12; + +plug_entry_gap = 2.0; + +plug_l_d = [[ 27.78, + 10.62 + 0.75 ], + [ 40.88, + 8.56 + 0.75 ], + ]; + +plug_stem = [ 2.72 + 0.50, + 5.20 + 0.50 ]; + +palmrest_from_plug_z = 3.98; +laptop_th = 16.31 + 0.75; + +tongue_len = 50; + +// calculated + +hook_th_plug_holder = + plug_l_d[0][1]/2 + wall_th * sin(22.5); + +hook_tongue_h = hook_hole + wall_th*2; + +plug_l_d_smallest = plug_l_d[len(plug_l_d)-1]; +plug_hook_x_min = -plug_l_d_smallest[0] - wall_th; +plug_hook_z_start = -plug_l_d_smallest[1]/2 - wall_th; + +z_laptop_base = palmrest_from_plug_z - laptop_th; +z_hook_min = z_laptop_base - hook_tongue_h; + +module PlugMainPlan() { + for (l_d = plug_l_d) { + l = l_d[0]; + d = l_d[1]; + rectfromto([ -l, -d/2 ], + [ 0, +d/2 ]); + } +} + +module PlugHolderPlan() { + intersection(){ + hull() + offset(r= wall_th) + PlugMainPlan(); + + rectfromto([-100,-100], [-plug_entry_gap,+100]); + } +} + +module PlugHookHookPlan(){ + polygon([ [ plug_hook_x_min, 0 ], + [ plug_hook_x_min, plug_hook_z_start ], + [ plug_hook_x_min + (plug_hook_z_start - z_hook_min), + z_hook_min ], + [ -plug_entry_gap, z_hook_min ], + [ -plug_entry_gap, 0 ], + ]); +} + +module TonguePlan(){ + difference(){ + rectfromto([ -plug_entry_gap - 1, z_hook_min ], + [ tongue_len, z_laptop_base ]); + translate([ tongue_len - wall_th - hook_hole/2, + z_hook_min + wall_th + hook_hole/2 ]) + circle(r = hook_hole/2); + } +} + +module FarHookPlan(){ + mirror([1,0,0]) + TonguePlan(); + + rectfromto([ 0, z_hook_min ], + [ hook_w_min, palmrest_from_plug_z + 0.1]); + + translate([0, palmrest_from_plug_z]) + rectfromto([ -hook_hook, 0 ], + [ hook_w_min, hook_w_min ]); +} + +module RotateIntersect(n=6){ + intersection_for (r = [0:n-1]) { + rotate([r/n * 360,0,0]) + linextr(-100,100) children(0); + } +} + +module PlugHolder(){ + difference(){ + union(){ + RotateIntersect(8) + PlugHolderPlan(); + + rotate([0,0,180]) { + linextr_y_xz(-hook_th_plug_holder/2, + +hook_th_plug_holder/2) + PlugHookHookPlan(); + + linextr_y_xz(-hook_th/2, + +hook_th/2) + TonguePlan(); + } + } + + RotateIntersect(6) + PlugMainPlan(); + + linextr(-plug_stem[1]/2, 100) + rectfromto([ -100, -plug_stem[0]/2 ], + [ +100, +plug_stem[0]/2 ]); + } +} + +module PlugHolderPrint(){ ////toplevel + render() PlugHolder(); +} + +module FarHookPrint(){ ////toplevel + linextr(0, hook_th) + FarHookPlan(); +} + +module DemoPlan() { ////toplevel + translate([0,0,-10]) color("grey") PlugHolderPlan(); + PlugMainPlan(); + translate([0,0,-5]) color("blue") { + PlugHookHookPlan(); + TonguePlan(); + } + + translate([0,40,0]) { + FarHookPlan(); + } +} diff --git a/led-panel-ceiling-bracket.scad b/led-panel-ceiling-bracket.scad new file mode 100644 index 0000000..8f39a5b --- /dev/null +++ b/led-panel-ceiling-bracket.scad @@ -0,0 +1,56 @@ +// -*- C -*- + +holespc = 20; + +len = 50; +width = 20; +backspc = 8; +extra_height = 2; +light_height = 12.5; +hole_from_back = 7.2 + 0.5; +hole_dia = 3.5 + 0.5; +bolthead_dia = 7 + 1.0; +bolthead_depth = 5 + 20 - 12 + 2.7/2; + +plasfix_dia = 4.5 + 0.5 + 1.1; +plasfix_head = 8.7 + 0.5 + 1.1; +plasfix_headdep = plasfix_dia; +plasfix_sink = 8; + +height = light_height + backspc + extra_height; + +octagon_fudge = 1/cos(22.5); + +echo("remain", width - bolthead_depth); + +module Bracket(){ + difference(){ + translate([-len/2, 0, 0]) + cube([len, width, height]); + for (xsgn=[-1,+1]) { + translate([xsgn * holespc/2, -1, + light_height - hole_from_back + extra_height]) { + rotate([-90,0,0]) { + rotate([0,0,360/8/2]) { + cylinder(r=bolthead_dia/2 * octagon_fudge, + h= bolthead_depth +1, $fn=8); + cylinder(r=hole_dia/2 * octagon_fudge, + h=50, $fn=8); + } + } + } + } + translate([0, width/2, 0]) { + cylinder(r= plasfix_dia/2, h=50, $fn=20); + translate([0,0,-1]) + cylinder(r= plasfix_head/2, h= plasfix_sink + 1, $fn=20); + } + } +} + +module BracketPrint(){ + rotate([0,180,0]) + Bracket(); +} + +BracketPrint(); diff --git a/led-panel-ceiling-bracket.slic3r b/led-panel-ceiling-bracket.slic3r new file mode 100644 index 0000000..612eb56 --- /dev/null +++ b/led-panel-ceiling-bracket.slic3r @@ -0,0 +1,3 @@ +bottom_solid_layers = 3 +top_solid_layers = 3 +perimeters = 3 diff --git a/lemon-stand.scad.pl b/lemon-stand.scad.pl new file mode 100755 index 0000000..8c1d10f --- /dev/null +++ b/lemon-stand.scad.pl @@ -0,0 +1,164 @@ +#!/usr/bin/perl -w + +use strict; +use Math::Trig; +use Math::Vector::Real; +use IO::File; +use Data::Dumper; +use constant tau => pi*2; + +my $ellipse = 25 / 2; +my $circle = 7 / 2; +my $channelh = 3; +my $channelw = 4; +my $xscale = 35 / 25; +my $N = 180; # around ellipse +my $M = 80; # around each circle +my @channeldistprops = (0, 1/3, 2/3); + +my $NMdiv = $ENV{'LEMONSTAND_COARSE'} || 1; + +$M /= $NMdiv; +$N /= $NMdiv; + +print <versor(); + my $rad0 = $axis x V(0,0,1); + my $rad1 = $rad0 x $axis; + [ map { + my $theta = tau * $_ / $M; + $centre + $circle * ($rad0 * cos($theta) + $rad1 * sin($theta)); + } 0..($M-1) ]; +} 0..($N-1); + +sub scadvec ($) { + my ($v) = @_; + return "[ ".(join ", ", @$v)." ]" +} + +sub torusy () { + print "module Torusy(){ polyhedron(points=["; + my $ptix = 0; + my @cirpt; + foreach my $i (0..$N-1) { + foreach my $j (0..$M-1) { + print "," if $ptix; + print "\n"; + print " ",(scadvec $circles[$i][$j]); + $cirpt[$i][$j] = $ptix++; + } + } + print "\n ],\n"; + + print " faces=["; + foreach my $i (0..$N-1) { + my $i2 = ($i+1) % $N; + foreach my $j (0..$M-1) { + my $j2 = ($j+1) % $M; + print "," if $i || $j; + print "\n"; + print " [ ", (join ", ", + $cirpt[ $i ][ $j ], + $cirpt[ $i ][ $j2 ], + $cirpt[ $i2 ][ $j ], + ), " ],"; + print " [ ", (join ", ", + $cirpt[ $i ][ $j2 ], + $cirpt[ $i2 ][ $j2 ], + $cirpt[ $i2 ][ $j ], + ), " ]"; + } + } + print "\n ]);\n}\n"; +} + +torusy(); + + +our @distances; +push @distances, 0; +foreach my $i (1..$N) { + my $dist = $distances[ $i-1 ]; + $dist += abs($ellipse[$i % $N] - $ellipse[$i-1]); + $distances[$i] = $dist; +} + +sub infodistprop ($) { + my ($distprop) = @_; + # returns + # ( $ellipse_centreline_point, + # $along_vector ) + my $dist = $distprop * $distances[$N]; + foreach my $i (0..$N-1) { + my $prorata = + ($dist - $distances[$i]) / + ($distances[$i+1] - $distances[$i]); + next unless 0 <= $prorata && $prorata <= 1; + print "// infodistprop $distprop => #$i=$ellipse[$i] $prorata $ellipse[$i+1]\n"; + return ( + (1-$prorata) * $ellipse[$i] + ($prorata) * $ellipse[$i+1], + $alongs[$i], + ); + } + die "$distprop ?"; +} + +sub channels(){ + print "module Channels(){\n"; + + foreach my $cdp ( + (map { 0.5 * $_ } @channeldistprops), + (map { 0.5 * ($_+1) } @channeldistprops), + ) { + my ($ctr, $along) = infodistprop($cdp); + my $angle = atan2(-$along->[0], $along->[1]); + print " translate(",scadvec($ctr),")\n"; + print " rotate([0,0,$angle*360/",tau,"])\n"; + print " rotate([0,90,0])\n"; + print " translate([0,0, -2*$circle])\n"; + print " scale([1, $channelw/$channelh/2, 1])\n"; + print " rotate([0,0,360/8/2])\n"; + print " cylinder(r=$channelh, h=4*$circle, \$fn=8);\n"; + } + print "}\n"; +} + +channels(); + +while () { print }; + +STDOUT->error and die $!; +STDOUT->flush or die $!; + +__DATA__ +module Stand(){ + difference(){ + translate([0,0,torusyup]) + Torusy(); + Channels(); + translate([-200,-200,-50]) + cube([400,400,50]); + } +} +Stand(); diff --git a/light-bracket.scad b/light-bracket.scad new file mode 100644 index 0000000..c49dc09 --- /dev/null +++ b/light-bracket.scad @@ -0,0 +1,139 @@ +shrinkage = 1.0126; // width of 56.2 gives 55.5 +remote_width= 56.35 * shrinkage; +remote_height=124.7 * shrinkage; +remote_thick=6.1; // height of 6.8 gives 6.3 +mainhole_thick=remote_thick+1; +hook_hook_thick=1.5; +hook_stem_thick=1.5; +hook_hook_len=1.5; +base_thick=3.5; +base_margin=3.0; +base_width=remote_width-base_margin*2; +base_height=remote_height-base_margin*2; +base_edgewidth=4; + +screw_ys=[ 28, remote_height-28 ]; + +// origin is base of mainhole + +module mainhole() { + translate([ -remote_width/2, 0, 0 ]) + cube(center=false, + size=[ remote_width, remote_height, mainhole_thick ] ); +} + +module hhook(extent) { + translate([ -hook_stem_thick, 0, -base_thick*2 ]) + cube(center=false, + size=[ + hook_stem_thick, + extent, + base_thick*2 + mainhole_thick + hook_hook_thick + ]); + translate([ -hook_stem_thick, 0, -base_thick*2 ]) + cube(center=false, + size=[ + hook_stem_thick+base_margin+base_edgewidth-1, + extent, + base_thick*2 + ]); + translate([ -hook_stem_thick+1.0, 0, mainhole_thick ]) + rotate(v=[0,1,0], a=-30) + cube(center=false, + size=[ + 3, + extent, + hook_hook_thick + ]); + //difference() { + // #translate([ -hook_stem_thick, 0, -base_thick*2 ]) + // cube(center=false, + // size=[ + // hook_stem_thick+base_margin+base_edgewidth-1, + // extent, + // base_thick*2 + mainhole_thick + hook_hook_thick + // ]); + // translate([hook_hook_len, -5, 0]) + // cube(center=false, size=[ 20, extent+10, 30 ]); + //} +} + +module hhookside(extent) { + translate([ -remote_width/2, 0, 0 ]) + hhook(extent); +} + +module hhookbot(extent) { + rotate(a=90, v=[0,0,1]) hhook(extent); +} + +module hstuff() { + translate([0,70,0]) hhookside(15); + translate([0,10,0]) hhookside(15); + translate([-10,0,0]) hhookbot(15); +} + +module slashes() { + for (y=[-30 : 60 : +40]) + translate([0,y,0]) + rotate(v=[0,0,1],a=45) + cube(center=true, [ 5,200,200 ]); +} + +module base() { + translate([ 0, base_height/2 + base_margin, -base_thick/2 ]) + intersection() { + cube(center=true, + [ base_width, base_height, base_thick+10 ]); + union() { + difference() { + cube(center=true, [ 200,200,200 ]); + cube(center=true, + [ base_width - base_edgewidth*2, + base_height - base_edgewidth*2, + base_thick + 15 ]); + + } + slashes(); + mirror([1,0,0]) slashes(); + } + } +// translate([-base_width/2, base_margin, -base_thick*2]) +// cube(center=false, [base_width,base_height,base_thick+10]); +} + +module stuff() { + hstuff(); + mirror([1,0,0]) hstuff(); + base(); + for (y=screw_ys) translate([0, y, -20]) + cylinder(r=6.5, h=21); +} + +module screwhole(holedia, csdia) { + // screw goes along z axis downwards + // origin is top of head + // results are positive, so this should be subtracted + translate([0,0,-100]) cylinder(h=200, r=holedia/2); + csdist=(csdia-holedia)/2; + translate([0,0,-csdist]) cylinder(h=csdist, r1=holedia/2, r2=csdia/2); + cylinder(h=100, r=csdia/2); +} + +module bracket() { + // this is the actual thing we want + difference() { + stuff(); + mainhole(); + for (y=screw_ys) translate([0, y, 0]) + screwhole(5.4,10); //dia=4 gives 2.9 + //holedia=10 gives 9.0 want 7.0 + translate([0,0,-50 - base_thick]) + cube(center=true,[300,300,100]); // print bed + } +} + +intersection() { + !bracket(); + translate([-50,6,-50]) #cube(center=false, [100,27,100]); +} diff --git a/lipo-flat-mount.scad b/lipo-flat-mount.scad new file mode 100644 index 0000000..865b6d3 --- /dev/null +++ b/lipo-flat-mount.scad @@ -0,0 +1,184 @@ +// -*- C -*- + +include +include + +// pimoroni 3000mAh +battery = [ 51.5, + 81.3, + 8.0 ]; + +battery_wall = 2.0; +battery_wall_unsupp = 4.0; +battery_wall_top_gap = 0.75; + +battery_keeper_m_th = 4; +battery_keeper_m_w = 4; +battery_keeper_x_gap = 0.75; // each side +battery_keeper_y_gap_overhang = 0.75; +battery_keeper_y_gap_nutbox = 1.0; +battery_keeper_z_gap_nutbox = 0.50; +battery_keeper_z_gap_overhang = 0.75; + +battery_keeper_x_th_min = 1.5 * 1.5; +battery_keeper_x_th_max = 2.5 * 1.5; +battery_keeper_x_w = 5; +battery_keeper_x_n = 5; + +battery_keeper_screw_x_off = -2.5; + +battery_wire_y = 4; + +battery_nutbox = nutbox_data_M3; + +// calculated + +battery_fix_sz = NutBox_outer_size(battery_nutbox); + +battery_nutbox_z = max( battery[2] + battery_wall_top_gap, + NutBox_h_base(battery_nutbox) ); +battery_keeper_overhang_z = battery[2] + battery_keeper_m_th + + battery_keeper_z_gap_overhang; +battery_keeper_overhang_wall = battery_keeper_m_w; +battery_keeper_overhang_th = battery_keeper_m_th; + +// calculated outputs + +battery_keeper_tab_top_z = battery_nutbox_z + + battery_keeper_z_gap_nutbox + battery_keeper_m_th; + // NB does not include screw head + +battery_keeper_legs_top_z = battery_keeper_overhang_z + + battery_keeper_overhang_th; + +battery_keeper_frame_top_z = battery[2] + battery_keeper_m_th; + +battery_mount_y_min = -battery_fix_sz; +battery_mount_y_max = battery[1] + battery_wall; +battery_mount_x_sz = battery[0] + battery_wall_unsupp*2; + +module BatteryPlan(){ + rectfromto([ -battery[0]/2, 0 ], + [ +battery[0]/2, battery[1] ]); +} + +module BatteryBase(){ ////toplevel + // wall + linextr(-0.1, battery[2] - battery_wall_top_gap, convexity=7) { + difference(){ + union(){ + offset(r=battery_wall) BatteryPlan(); + rectfromto([ 0,0 ], + [ -(battery[0]/2 + battery_wall_unsupp), battery[1]/3 ]); + } + BatteryPlan(); + rectfromto([ battery_fix_sz/2 - 0.5 + + battery_keeper_screw_x_off, -30 ], + [ -battery[0], battery_wire_y ]); + } + } + + // nutbox + translate([battery_keeper_screw_x_off, -battery_fix_sz/2, battery_nutbox_z]) + NutBox(battery_nutbox, battery_nutbox_z + 0.1); + + // overhang for legs at rear + for (m=[0,1]) { + mirror([m,0,0]) { + translate([ battery[0]/2, battery[1], 0]) { + difference(){ + linextr(-0.1, + battery_keeper_overhang_z + + battery_keeper_overhang_th, + convexity=1) + rectfromto([ -battery_keeper_m_w*2, -battery_keeper_m_w ], + [ battery_keeper_overhang_wall, battery_wall ]); + linextr(-1, battery_keeper_overhang_z, + convexity=1) + rectfromto([-20, -20], [0,0]); + } + } + } + } +} + +module BatteryKeeper(){ ////toplevel + // A-frame + translate([0,0, battery[2]]) { + linextr(0, battery_keeper_m_th) { + intersection(){ + // main legs + translate([0, +battery[1], 0]) + multmatrix([[ 1, -battery_keeper_screw_x_off/battery[1], 0, 0, ], + [ 0,1,0, 0, ], + [ 0,0,1, 0, ]]) + translate([0, -battery[1], 0]) + for (sx=[-1,+1]) { + multmatrix([[ 1,0,0, 0, ], + [ 0,1,0, 0, ], + [ 0,0,1, 0, ]] + + sx * + ( battery[0]/2 - 0.5 * battery_keeper_m_w + - battery_keeper_x_gap ) / + ( battery[1] - 0.5 * battery_keeper_m_w ) + * + [[ 0,1,0, 0, ], + [ 0,0,0, 0, ], + [ 0,0,0, 0, ]]) + rectfromto([ -battery_keeper_m_w/2, + battery_keeper_y_gap_nutbox ], + [ +battery_keeper_m_w/2, + battery[1] - battery_keeper_y_gap_overhang ]); + } + + // shape to round off the leg end corners + hull(){ + for (sx=[-1,+1]) { + translate([ sx * ( battery[0]/2 - battery_keeper_m_w/2 + -battery_keeper_x_gap) , + battery[1] - battery_keeper_m_w/2 + -battery_keeper_y_gap_overhang ]) + circle(r = battery_keeper_m_w/2); + } + square(center=true, [ battery[0], 1 ]); + } + } + } + + // x struts + for (i=[0 : battery_keeper_x_n-1]) { + linextr(0, + battery_keeper_x_th_min + + (battery_keeper_x_th_max - battery_keeper_x_th_min) + * pow( i/(battery_keeper_x_n-1)*2 - 1 , 2) + ) { + difference(){ + translate([0, battery[1] * ((i + 0.5) / battery_keeper_x_n)]) + square(center=true, [ battery[0], battery_keeper_x_w ]); + children(0); + } + } + } + } + + // tab for screw and nutbox + translate([battery_keeper_screw_x_off, + 0, + battery_nutbox_z + battery_keeper_z_gap_nutbox]) + linextr(0, battery_keeper_m_th, convexity=4) { + difference(){ + rectfromto([ -battery_fix_sz/2, -battery_fix_sz ], + [ +battery_fix_sz/2, + 0.5 * battery[1] / battery_keeper_x_n + + 0.5 * battery_keeper_m_w ]); + translate([ 0, -battery_fix_sz/2 ]) + circle(r = battery_nutbox[0]/2); + } + } +} + +module BatteryDemo(){ ////toplevel + color("grey") BatteryBase(); + BatteryKeeper() { union(){ } } +} + diff --git a/lock-inframe-bracket.scad b/lock-inframe-bracket.scad new file mode 100644 index 0000000..bfa6e39 --- /dev/null +++ b/lock-inframe-bracket.scad @@ -0,0 +1,349 @@ +// -*- C -*- + +// use shell thickness 1.50 +// use fill density 40% + +include + +tube_dia = 27.5 + 1.625 + 1.32; +lock_w = 42.5 + 0.5; +lock_d = 28.0 + 0.5; +main_h = 45.0; +backflange_d = 12; +backflange_hole_dy = -1; +lockshaft_dia = 14.35; + +cliprecess_h = 16; +total_h = 75; + +back_gap = 12.5; +main_th = 4.50; +tube_th = 5.50; + +midweb_d = 3; +clip_th = 3.5; +clip_gap = 2.5; +clip_d = 22.0; + +mountscrew_dia = 4 + 0.5; +clipbolt_dia = 5 + 0.6; + +mountscrew_washer = 10; + +backflange_th = 4.5; + +$fn=50; + +join_cr = 9; + +tube_rear_extra_th = 1; + +divide_shaft_w = 1.75; +divide_shaft_l = 1.5; +divide_head_dx = 1.75; +divide_head_th = 1.5; +divide_gap = 0.75; + +divide_angle = 26; +divide_fudge_r = 4.75; + +backflange_angle = 20; + +// calculated + +lockshaft_r = [1, 1] * lockshaft_dia / 2; +front_th = main_th; + +tube_or = tube_dia/2 + tube_th; +back_ohw = back_gap/2 + backflange_th; +backflange_ymin = tube_dia/2 + backflange_d; + +lock_0y = tube_dia/2 + lock_d/2 + midweb_d; +lock_0x = lock_w/2 - lock_d/2; +lock_0 = [lock_0x,lock_0y]; + +lock_or = [lock_w, lock_d]/2 + [front_th,front_th]; + +module oval(sz){ // sz[0] > sz[1] + xr = sz[0]; + yr = sz[1]; + hull(){ + for (sx=[-1,+1]) { + translate([sx * (xr-yr), 0]) + circle(r=yr); + } + } +} + +module JoinCircs(jr){ + // http://mathworld.wolfram.com/Circle-CircleIntersection.html + R = tube_or + join_cr; + r = lock_or[1] + join_cr; + d = dist2d( [0,0], lock_0 ); + x = (d*d - r*r + R*R) / (2*d); + y = sqrt( R*R - x*x ); + + echo(lock_0x, lock_0y, R,r, d, x,y); + + for (m=[0,1]) { + mirror([m,0]) { + rotate(atan2(lock_0y, lock_0x)) { + translate([x,-y]) + circle(r= jr); + } + } + } +} + +module DivideHook(){ ////toplevel + w = tube_th/2; + d = divide_gap; + + translate([-1,0] * (w + d + w)){ + for (sx=[-1,+1]) + translate([-(w + w+d) * sx, 0]) circle(r= w); + difference(){ + circle(r = 3*w + d); + circle(r = w + d); + translate([-10*w, -10*w]) square([20*w, 10*w]); + } + } +} + +module DivideCut(){ + w = tube_th/2; + d = divide_gap; + br = tube_dia/2 + tube_th; + + difference(){ + offset(r=divide_gap) DivideHook(); + DivideHook(); + translate([-2*w,0]) mirror([0,1]) square([4*w, 4*w]); + } +} + +module DivideCutB(){ + w = tube_th/2; + d = divide_gap; + br = tube_dia/2 + tube_th; + + intersection(){ + translate([br - tube_th/2,0]) { + difference(){ + circle(r=br + d); + circle(r=br); + } + } + translate([-2*w, 0]) mirror([0,1]) square(4*w); + } +} + +module DivideSurround(){ + w = tube_th/2; + d = divide_gap; + + offset(r= w*2) { + hull() { + DivideCut(); + translate([-(4*w + 2*d), 8*w]) circle(r=w); + } + } +} + +module DivideInPlace(){ + rotate([0,0, -divide_angle]) + translate([ -tube_dia/2 -tube_th/2, 0]) + children(); +} + +module MainPlan(){ ////toplevel + difference(){ + union(){ + difference(){ + union(){ + hull(){ + for (t=[0, tube_rear_extra_th]) + translate([0, -t]) + circle(r = tube_or); + } + rotate([0,0, backflange_angle]) + translate([-back_ohw,0]) mirror([0,1]) + square([back_ohw*2, backflange_ymin]); + + translate([0, lock_0y]){ + oval(lock_or); + } + + hull(){ + JoinCircs(0.01); + polygon([[0,0], lock_0, [-lock_0[0], lock_0[1]]]); + } + } + + rotate([0,0, backflange_angle]) + translate([-back_gap/2,1]) mirror([0,1]) + square([back_gap, backflange_ymin+2]); + + JoinCircs(join_cr); + } + + DivideInPlace() DivideSurround(); + } + translate([0, lock_0y]){ + oval([lock_w/2, lock_d/2]); + } + + circle(r = tube_dia/2); + + DivideInPlace() DivideCut(); + DivideInPlace() DivideCutB(); + } +} + +lockshaft_or = lockshaft_r + [clip_th,clip_th]; +cliprecess_ymax = cliprecess_h - lockshaft_r[1]; +clip_ymin = cliprecess_ymax - main_h; +clip_ogap = clip_gap + clip_th*2; + +module ClipElevationPositive(){ + hull(){ + oval(lockshaft_or); + translate([0, -lockshaft_or[1] * sqrt(2)]) + square(center=true, 0.5); + } + translate([-lockshaft_or[0], 0]) + square([lockshaft_or[0]*2, cliprecess_ymax]); + translate([-clip_ogap/2, 0]) mirror([0,1]) square([clip_ogap, -clip_ymin]); +} + +module ClipElevationNegative(){ + hull(){ + for (y=[0, cliprecess_ymax+1]) + translate([0, y]) + oval(lockshaft_r); + } + translate([-clip_gap/2, 1]) mirror([0,1]) square([clip_gap, 2-clip_ymin]); +} + +module ClipElevation(){ + difference(){ + ClipElevationPositive(1); + ClipElevationNegative(0); + } +} + +module ExtrudeClipElevation(extra=0){ + translate([0, + lock_0y + lock_d/2 + clip_d + extra, + -clip_ymin]) + rotate([90,0,0]) + linear_extrude(height= clip_d + extra*2, convexity=100) + children(0); +} + +module ThroughHole(r, y, z, x=-50) { + translate([x, y, z]) + rotate([0, 90, 0]) + cylinder(r=r, h=100, $fn=20); +} + +module MountingHoleCylinders(r, x=-50){ + for (z=[ 1/4, 3/4 ]) { + rotate([0,0, backflange_angle]) + ThroughHole( r, + -tube_dia/2 -0.5*backflange_d + backflange_hole_dy, + total_h * z, + x); + } +} + +module ThroughHoles(){ + MountingHoleCylinders(mountscrew_dia/2); + + ThroughHole( clipbolt_dia/2, + lock_0y + lock_d/2 + clip_d/2 + front_th/2, + main_h - cliprecess_h - clip_th - clip_d/2 ); +} + +module SlopeTrimElevation(){ + far_corner_nom = [ lock_0y + lock_d/2, main_h ]; + round_centre = far_corner_nom + lock_d/2 * [0,1]; + hull(){ + translate(round_centre) circle(r= lock_d/2); + translate([ lock_0y - lock_d/2, total_h ]) square([ lock_d + clip_d, 1 ]); + translate(far_corner_nom) square([clip_d*2, 1]); + } +} + +module SlopeTrim(){ + rotate([0,90,0]) + rotate([0,0,90]) + translate([0,0, -lock_w]) + linear_extrude(convexity=100, height=lock_w*2) + SlopeTrimElevation(); +} + +module MainPositive(){ + difference(){ + union(){ + linear_extrude(height=total_h, convexity=100) MainPlan(); + ExtrudeClipElevation() ClipElevationPositive(); + } + ExtrudeClipElevation(1) ClipElevationNegative(); + } +} + +module Bracket(){ ////toplevel + difference(){ + MainPositive(); + ThroughHoles(); + SlopeTrim(); + } +} + +module TestTopEdge(){ ////toplevel + intersection(){ + translate([0,0, -total_h]) + translate([0,0, 4]) + Bracket(); + translate([-200,-200,0]) + cube([400,400,100]); + } +} + +module TestClipBoltHole(){ ////toplevel + intersection(){ + union(){ + translate([0, 0, -5]) + Bracket(); + translate([-4, lock_0y + lock_d/2 + 1, 0]) + cube([8, 4, 1.5]); + } + translate([-200, lock_0y + lock_d/2 + 0.1]) + cube([400, 400, total_h-20]); + } +} + +module Demo(){ ////toplevel + Bracket(); + color("blue") MountingHoleCylinders(mountscrew_dia/2 - 0.1); + color("black") MountingHoleCylinders(mountscrew_washer/2, + back_ohw + 0.25); +} + +module DivideDemo(){ ////toplevel + color("black") translate([0,0,-2]) MainPlan(); + color("grey") DivideInPlace() DivideHook(); + color("blue") translate([0,0,-4]) DivideInPlace() DivideCut(); +} + +//MainPlan(); +//ClipElevationPositive(); +//ClipElevation(); +//MainPositive(); +//%ThroughHoles(); +//TestTopEdge(); +//TestClipBoltHole(); + +//Bracket(); + diff --git a/maglite-holder-photo.jpg b/maglite-holder-photo.jpg new file mode 100644 index 0000000..c0d19ce Binary files /dev/null and b/maglite-holder-photo.jpg differ diff --git a/maglite-holder-torch.fig b/maglite-holder-torch.fig new file mode 100644 index 0000000..9c25deb --- /dev/null +++ b/maglite-holder-torch.fig @@ -0,0 +1,19 @@ +#FIG 3.2 Produced by xfig version 3.2.6 +Landscape +Center +Metric +A4 +100.00 +Single +-2 +1200 2 +5 1 0 1 4 4 50 -1 -1 0.000 0 0 0 0 707.697 1147.762 -1207 1110 -1113 554 -858 45 +2 2 0 1 2 1 75 -1 -1 0.000 0 0 -1 0 0 5 + -1800 -1350 2025 -1350 2025 3825 -1800 3825 -1800 -1350 +2 5 0 1 0 -1 100 -1 -1 0.000 0 0 -1 0 0 5 + 0 maglite-holder-photo.jpg + -1572 -1185 1891 -1185 1891 3762 -1572 3762 -1572 -1185 +2 2 0 1 2 1 75 -1 -1 0.000 0 0 -1 0 0 5 + -859 13 857 13 857 -795 -859 -795 -859 13 +2 3 0 1 1 1 50 -1 -1 0.000 0 0 -1 0 0 6 + -1201 1100 -1204 2667 -231 1187 -225 -159 -846 17 -1201 1100 diff --git a/maglite-holder.scad b/maglite-holder.scad new file mode 100644 index 0000000..9aed425 --- /dev/null +++ b/maglite-holder.scad @@ -0,0 +1,173 @@ +// -*- C -*- + +dxf_off = [ -40, -85 ]; + +torch_lit_dia = 37.5; +torch_big_dia = 56.5; +torch_tot_len = 256; +torch_big_len = 60; + +torch_clear = 30; +torch_clear_below = 10; + +stem_width = 20; +stem_thick = 8; + +torch_recess = 11; +arm_width = 10; +block_thick = 15; + +torch_out_more = 10; + +brace = [ 40, 20, 20 ]; + +hole_dia = 4 + 0.5; +hole_slot = 5; + +movement_extra_angle = 5; + +slop = 4; // total, not each side + +torch_min_xcoord_fig_cm = -2.7; // coordinates of bottom left of curve +torch_min_ycoord_fig_cm = -5.9; // & big part in fig file. mid top is origin +torch_smm_xcoord_fig_cm = -1.9; // x coord of lhs of narrow part + +miniature = 1; // can adjust this to get commitid size right and rescale *Print + +$fa=5; + +// calculated + +include + +torch_dxf_scale = + [ (torch_big_dia - torch_lit_dia) / + (-(torch_min_xcoord_fig_cm - torch_smm_xcoord_fig_cm) * 10 * 2), + torch_big_len / (-torch_min_ycoord_fig_cm * 10) ]; + +echo(torch_dxf_scale); + +above = torch_big_len + torch_clear + torch_clear_below; + +holes = [ 172, 265 ]; + +stem_below = stem_width/2; + +stem_len = holes[1] - above + stem_below; + +torch_out = stem_thick + torch_big_dia/2 + torch_out_more; + +block_width = arm_width*2 + torch_big_dia; + +block_out = torch_out + torch_big_dia/2/sqrt(2); + +module TorchOrig(){ + mirror([0,0,1]){ + hull(){ + rotate_extrude() + translate([-torch_lit_dia/2, 0]) + scale(torch_dxf_scale) + translate(dxf_off) + translate([-torch_smm_xcoord_fig_cm * 10, 0]) + import(file="maglite-holder-torch-curve.dxf", + convexity=10, center=true); + } + translate([0,0, -1]) + cylinder(r=torch_lit_dia/2, h= torch_tot_len - torch_big_len + 1); + } +} + +module Torch(){ + scale(slop/torch_lit_dia + 1.0) + TorchOrig(); +} + +module ScrewHole(y, rot) { + translate([0,0, above -y]){ + rotate([0,rot,0]){ + hull(){ + for (d= [-1,+1] * hole_slot/2) { + translate([d,0,0]) + rotate([90,0,0]) + translate([0,0,-stem_thick*2]) + cylinder(r= hole_dia/2, h= stem_thick*4); + } + } + } + } +} + +module TorchMovement(){ + translate([0, -torch_out, 0]) { + translate([0, 0, -torch_recess]) + Torch(); + for (as=[-1,+1]) { + rotate([0,0, as*movement_extra_angle]) + rotate([90,0,0]) + linear_extrude(height= block_out) + projection() rotate([-90,0,0]) Torch(); + } + } +} + +module Bracket(){ ////toplevel + cid_w = stem_width * .75; + hole_near = hole_slot + hole_dia; + + difference(){ + mirror([0,1,0]) { + translate([-stem_width/2, 0, -stem_len]) + cube([stem_width, stem_thick, stem_len]); + translate([0,0, -block_thick]) hull(){ + translate([-stem_width/2, 0, -brace[2]]) + cube([stem_width, stem_thick, 1]); + translate([-brace[0]/2, 0, 0]) + cube([brace[0], brace[1], 1]); + } + } + ScrewHole(holes[0], 90); + ScrewHole(holes[1], 0); + translate([-cid_w/2, 0, above - holes[0] - hole_near]) + rotate([-90,0,0]) + scale([miniature, miniature, 1]) + Commitid_BestCount([cid_w, holes[1]-holes[0] - hole_near*2] + / miniature); + } + difference(){ + mirror([0,1,0]) + translate([-block_width/2, 0, -block_thick]) + cube([block_width, block_out, block_thick]); + TorchMovement(); + } +} + +module BracketPrint(){ ////toplevel + scale(1/miniature) + rotate([-90,0,0]) + Bracket(); +} + +module TestTorchPrint(){ ////toplevel + scale(1/miniature) + intersection(){ + translate([0,0, torch_lit_dia / 2 / sqrt(2)]) + rotate([-90,0,0]) + Torch(); + translate([-100, -torch_tot_len*2, 0]) + cube([200, torch_tot_len*4, 200]); + } +} + +module Demo(){ ////toplevel + color("red") + translate([0, -torch_out, 0]) + TorchOrig(); + color("blue") + translate([0, -torch_out, above]) + cylinder(r=torch_big_dia/2, h=1); + Bracket(); +} + +//Demo(); +//BracketPrint(); +//TestTorchPrint(); diff --git a/makita-drill-handle-blivet.scad b/makita-drill-handle-blivet.scad new file mode 100644 index 0000000..831b83f --- /dev/null +++ b/makita-drill-handle-blivet.scad @@ -0,0 +1,42 @@ +// -*- C -*- + +include + +hex_across = 12.70 - 0.3; +screw_dia = 8.0 + 0.0; + +min_th = 0.425; +extra_th = 1.0; + +// calculated + +total_th = min_th + extra_th; +hex_rad = hex_across / 2 / cos(30); + +module Plan(){ + difference(){ + circle(r = hex_rad, $fn = 6); + circle(r = screw_dia/2); + } +} + +module Elevation(){ + hull(){ + rectfromto([ -hex_rad, -1], + [ 0.1, min_th]); + translate([ hex_rad, 0 ]) + rectfromto([ 0, -1 ], + [ 1, total_th]); + } +} + +module Blivet(){ + intersection(){ + linextr(0, total_th + 1) + Plan(); + linextr_y_xz(-hex_across, hex_across) + Elevation(); + } +} + +Blivet(); diff --git a/manual-gcode-generator b/manual-gcode-generator new file mode 100755 index 0000000..ba9a0cd --- /dev/null +++ b/manual-gcode-generator @@ -0,0 +1,142 @@ +#!/usr/bin/perl -w + +use strict; + +our @array; +our %procs; + +sub readdata () { + my $l = ''; + my $current = \@array; + while (<>) { + chomp or die; + s/\s+$//; + s/^\s*\!\s*/!/; + $l .= $_; + next if $l =~ s/\\$//; + + $_=$l; $l=''; + if (m/^\!(\w+)\s*\(\)\s*\{$/) { + my $pname=$1; + die if $current ne \@array; + die if exists $procs{$pname}; + $current = $procs{$pname} = []; + next; + } + if (m/^\!\}$/) { + $current = \@array; + next; + } + push @$current, $_; + } +} +readdata(); + +our %c; + +sub defvar ($;$) { + my ($cv,$v) = @_; + $c{$cv} = $v; +} + +defvar('extruderate',0.097200); +defvar('feedrate',540); +defvar('jerkfeedrate',7800); +defvar('retract',4.5); +defvar('restart',4.5); +defvar('restartfeedrate',1800); +defvar('retractfeedrate',1800); +defvar('movefeedrate',7800); +defvar('zlift',0.1); +defvar('zprint'); +defvar('orgx',0); +defvar('orgy',0); + +sub float_g ($) { + my ($f) = @_; + return sprintf "%.5f", $f; +} +sub coords_g ($) { + my ($coords) = @_; + return "X".float_g($coords->[0])." Y".float_g($coords->[1]); +} + +sub p ($) { print "$_[0]" or die $!; } +sub pl ($) { p("$_[0]\n"); } + +sub proc ($); + +sub proc ($) { + my ($aref) = @_; + local ($_); + foreach (@$aref) { + if (!m/^\!/) { + pl($_); + next; + } + pl(";$_"); + if (m/^\!(\w+)\s*\(\)$/) { + my $pname = $1; + die "$pname ?" unless $procs{$pname}; + proc($procs{$pname}); + } elsif (m/^\!draw\s+/) { + my @coords = split /\s+/, $'; #'; + my @undefs = grep { !defined $c{$_} } qw(zprint); + die "@undefs ?" if @undefs; + @coords = map { + my $jerk = s/^\*//; + m/\,/ or die $!; + [ $`, $', !!$jerk ]; # ']; + } @coords; + foreach my $co (@coords) { + foreach my $xy (qw(0 1)) { + my $xyv = $co->[$xy]; + next unless $xyv =~ s/^\@//; + my $orgxy = ($c{orgx},$c{orgy})[$xy]; + $co->[$xy] = float_g($xyv + $orgxy); + } + } + my $extrudepos=$c{restart}; + pl("G92 E0"); + my $zmove=$c{zprint}+$c{zlift}; + pl("G1 F$c{movefeedrate} Z$zmove"); + pl("G1 ".coords_g($coords[0])); + pl("G1 Z$c{zprint}"); + pl("G1 F$c{restartfeedrate} E".float_g($extrudepos)); + my $lastfeedrate=-1; + foreach (my $ci=1; $ci<@coords; $ci++) { + my $g = "G1 ".coords_g($coords[$ci]); + my $wantfeedrate; + if (!$coords[$ci][2]) { + $wantfeedrate=$c{feedrate}; + my $dist = 0; + foreach my $xy (qw(0 1)) { + my $dxy = $coords[$ci][$xy] - $coords[$ci-1][$xy]; + $dist += $dxy * $dxy; + } + $dist = sqrt($dist); + $extrudepos += $dist * $c{extruderate}; + $g .= " E".float_g($extrudepos); + } else { + $wantfeedrate=$c{jerkfeedrate}; + } + if ($wantfeedrate != $lastfeedrate) { + $g .= " F$wantfeedrate"; + $lastfeedrate = $wantfeedrate; + } + pl($g); + } + $extrudepos -= $c{retract}; + pl("G1 F$c{retractfeedrate} E".float_g($extrudepos)); + pl("G1 F$c{movefeedrate} Z$zmove"); + next; + } elsif (m/^\!(\w+)\=(\S+)$/) { + die "$1 ?" unless exists $c{$1}; + $c{$1} = $2; + } else { + die "$_ ?"; + } + } +} + +proc(\@array); diff --git a/mic-camera-adapter.scad b/mic-camera-adapter.scad new file mode 100644 index 0000000..a6cb9f6 --- /dev/null +++ b/mic-camera-adapter.scad @@ -0,0 +1,54 @@ +// -*- C -*- + +// print on High Detail +// but adjust infill to 50%, shell thickness to 2mm + +include +include + +positive_dia = inch * 3/8. - 0.375; +positive_l = inch * 1/2.; + +negative_l = negative_default_l; + +negative_wall = 4; +midsection = 4; + +spanner = 12; + +base_dia = 35; +base_th_min = 1; +base_th_max = 4; + +//$test = true; +$test = false; +$fs=0.1; +$fa=5; + +module Adapter(){ + translate([0,0,-0.1]) + english_thread(diameter=positive_dia/inch, threads_per_inch=16, + leadin=1, test=$test, + length= (positive_l + 0.1) / inch); + rotate([180,0,0]) { + difference(){ + union(){ + cylinder(r= spanner/2 * 1/(0.5 * sqrt(3)), + h = negative_l + midsection, + $fn=6); + translate([0,0, midsection+negative_l]) { + mirror([0,0,1]) { + hull(){ + cylinder(r= base_dia/2, h = base_th_min); + cylinder(r= 0.1, h = base_th_max); + } + } + } + } + translate([0,0, midsection + negative_l]) + CameraMountThread(negative_l); + } + } +} + +Adapter(); diff --git a/mic-table-clamp.scad b/mic-table-clamp.scad new file mode 100644 index 0000000..b88e8d1 --- /dev/null +++ b/mic-table-clamp.scad @@ -0,0 +1,229 @@ +// -*- C -*- + +// print Stem and Wingnut on High Detail +// but adjust shell thickness to 2mm + +// others on Standard + +include +include +include + +positive_dia = inch * 3/8. - 0.375; +positive_l = inch * 1/2.; + +positive_blank_dia = 8.12; +blank_l = 17; +blank_taper = 1.0; + +stem_l = 40; +stem_dia = 12; +stem_th = 3; +stem_ceil = 2; +stem_base_th = 4; +stem_base_dia = 25; +stem_inner_l = 15; + +thread_nom = 8; +thread_pitch = 1.25; +thread_act = thread_nom + 0.600; + +clamp_l = 40; +clamp_top_th = 7; +clamp_bot_th = 10; +clamp_bot_tooth_h = 2.5; +clamp_bot_tooth_d = 10; +clamp_bot_collar = 20; +clamp_bot_collar_th = 3.0; +clamp_reg_sz1 = 3; +clamp_reg_sz2 = 5; +clamp_w = 15; +clamp_max_table_th = 35; + +clamp_hole_dia = thread_nom + 0.30; + +clamp_reg_clear_x = 2.5; +clamp_reg_clear_y = 0.75; // each side +clamp_reg_extra_x = 4; + +//ct_h = 7; + +wingnut_th = 5; +wingnut_wall = 4; +wingnut_wing_mindia = 17.0; +wingnut_wing_xrad = 8; +wingnut_wing_xh = 5; +wingnut_wing_th = 3; + +//$test= true; +$test= false; + +$fa= 3; +$fs= 0.2; + +// calculated + +wingnut_cnr = wingnut_wing_th/2 -0.1; + +clamp_reg_bot_x_min = -stem_base_dia/2 -clamp_reg_clear_x -clamp_reg_sz2; +clamp_collar_r = thread_nom/2 + clamp_bot_collar_th; + +module OurThread(l){ + translate([0,0,-0.01]) + metric_thread(diameter=thread_act, pitch=thread_pitch, + leadin=3, internal=true, + test=$test, length=l); +} + +module StemWith(){ + translate([0,0, stem_l -0.1]) + children(); + + difference(){ + union(){ + cylinder(r= stem_dia/2 * 1/(0.5 * sqrt(3)), + h = stem_l, + $fn=6); + cylinder(r= stem_base_dia/2, + h = stem_base_th); + } + OurThread(stem_inner_l); + } +} + +module Stem(){ ////toplevel + StemWith() + english_thread(diameter=positive_dia/inch, threads_per_inch=16, + leadin=1, test=$test, + length= (positive_l + 0.1) / inch); +} + +module StemBlankPart(){ + hull(){ + cylinder(h = blank_l + 0.1 - blank_taper, + r = positive_blank_dia/2); + cylinder(h = blank_l + 0.1, + r = positive_blank_dia/2 - blank_taper); + } +} + +module BlankStem(){ ////toplevel + StemWith() + StemBlankPart(); +} + +module Wingnut(){ ////toplevel + difference(){ + union(){ + cylinder(r= (thread_nom+wingnut_wall)/2, + h= wingnut_th); + minkowski(){ + sphere(r= wingnut_cnr); + translate([0,0, wingnut_cnr*0.5]) + linear_extrude(height= wingnut_wing_xh + wingnut_th + - wingnut_cnr*1.5) + square([wingnut_wing_mindia + wingnut_wing_xrad*2 - wingnut_cnr*2, + wingnut_wing_th - wingnut_cnr*2], + center=true); + } + } + translate([0,0, wingnut_th]) + linear_extrude(height= wingnut_wing_xh+1) + square(wingnut_wing_mindia, center=true); + translate([0,0, wingnut_th]) + rotate([180,0,0]) + OurThread(wingnut_th+3); + mirror([0,0,1]) + linear_extrude(height=5) + square(center=true, wingnut_wing_mindia*2); + } +} + +module ClampCollarPlan(){ + circle(r= clamp_collar_r); +} +module ClampHolePlan(){ + circle(r= clamp_hole_dia/2); +} +module ClampArmPlan(){ + r = clamp_collar_r; + hull(){ + rectfromto([r, -clamp_w/2], + [clamp_l, +clamp_w/2]); + ClampCollarPlan(); + } +} + +module ClampTop(){ ////toplevel + linear_extrude(height = clamp_top_th, convexity=4) { + difference(){ + union(){ + ClampArmPlan(); + ClampCollarPlan(); + } + ClampHolePlan(); + } + } + linear_extrude(height = clamp_reg_sz1, convexity=4) { + difference(){ + for (m=[0,1]){ + mirror([0,m,0]) + translate([0, clamp_reg_sz2/2 + clamp_reg_clear_y, 0]) + rectfromto([clamp_reg_bot_x_min - clamp_reg_extra_x, 0 ], + [0, clamp_reg_sz1 ]); + } + ClampHolePlan(); + } + } +} + +module ClampBot(){ ////toplevel + linear_extrude(height = clamp_bot_th, convexity=4) { + difference(){ + ClampArmPlan(); + ClampHolePlan(); + } + } + translate([clamp_l, 0, clamp_bot_th-0.1]) + linear_extrude(height = clamp_bot_tooth_h +0.1) + rectfromto([ -clamp_bot_tooth_d, -clamp_w/2 ], + [ 0, +clamp_w/2 ]); + translate([0,0, clamp_bot_th]) + mirror([0,0,1]) + linear_extrude(height = clamp_bot_collar) + difference(){ + ClampCollarPlan(); + ClampHolePlan(); + } + translate([0, 0, clamp_bot_th]) { + linextr(-clamp_reg_sz2, clamp_max_table_th+clamp_reg_sz2) { + translate([clamp_reg_bot_x_min, 0]) { + rectfromto([ 0, -clamp_reg_sz2/2 ], + [ clamp_reg_sz2, +clamp_reg_sz2/2 ]); + } + } + linextr(-clamp_reg_sz2, 0) { + difference(){ + rectfromto([ clamp_reg_bot_x_min, -clamp_reg_sz2/2 ], + [ 0, +clamp_reg_sz2/2 ]); + ClampHolePlan(); + } + } + } +} + +module StemBlankTest(){ ////toplevel + StemBlankPart(); + linextr(-1.5,0) square(center=true, [10,35]); +} + +module Demo(){ ////toplevel + color("blue") translate([0,0, clamp_top_th+0.5]) BlankStem(); + color("red") ClampTop(); + color("grey") translate([0,0, -(clamp_bot_th + 5)]) ClampBot(); + translate([0,0, -(clamp_bot_collar +10)]) + rotate([180,0,0]) Wingnut(); +} + +//Wingnut(); +//Stem(); diff --git a/nook-case-test.scad b/nook-case-test.scad new file mode 100644 index 0000000..3f4cc51 --- /dev/null +++ b/nook-case-test.scad @@ -0,0 +1,6 @@ +// -*- C -*- + +//// toplevels-from: +include + +$test = true; diff --git a/nook-case.scad b/nook-case.scad new file mode 100644 index 0000000..ecbbbc2 --- /dev/null +++ b/nook-case.scad @@ -0,0 +1,351 @@ +// -*- C -*- + +// Infill density: 20% + +include +include + +nook_th = 12.41 + 0.50 - 1.50 + 1.35 - .25; +nook_w = 127.12 + 0.75 - .95 - .50; +nook_h = 123.44 + 21.88 + 21.05 + 0.75 - 1.90 - 0.50 - 0.50; + +edge_ledge_w = 9.60; +edge_ledge_h = 2.44 - .25; +edge_ledge_inc_ang = 10; // degrees + +usb_w = 14.5; +usb_below = 1.5; + +open_recess_w = 12.5; +open_recess_h = 2.5; + +open_recess_2_len = 15; +open_recess_2_d_tooth = 30; + +nook_cnr_rad = 10; + +case_th = 2.5; +ledge_w = 4; +tape_th = 1.75; +tape_inside = 2.0; + +gap = 0.5 * [1,1]; + +tape_w = 15; + +test_pillar = 4; + +engage_l0 = 10; +engage_l1 = 10; +engage_l2 = 3; + +tooth_inward = gap[0] * 1.0 + 0.25 + 0.25; +tooth_w = 15; + +diag_near_hinge_slope = 0.5; + +$test = false; + +$fa = $test ? 10 : 3; +$fs = $test ? 0.1 : 1; + +// calculated + +tooth_height = nook_th; +ledge_h = case_th; +lid_th = case_th; +tooth_th = case_th; + +spp0 = [0,0]; +spp1 = spp0 + case_th * [-1,0]; +spp9 = spp0 + ledge_h * [0,-1]; +spp8 = spp9 + nook_th * [0,-1]; +spp7 = spp8 + case_th * [-1,-1]; + +spp11y = spp1[1] - tape_th; +spp4y = 0.5 * (spp0[1] + spp7[1]); +spp3y = spp4y + tape_inside/2; spp5y = spp4y - tape_inside/2; +spp2y = spp3y + tape_th; spp6y = spp5y - tape_th; + +spp20 = spp8 + nook_cnr_rad * [1,0]; +spp20x = spp20[0]; + +tppA = spp0 + gap; +tppB = spp1 + [0, gap[1]]; +tppC = tppB + lid_th * [0,1]; +tppD = [ spp20x, tppC[1] ]; +tppE = [ spp20x, tppB[1] ]; +tppF = tppA + ledge_w * [1,0]; +tppG = tppF + ledge_h * [0,-1]; +tppH = [ tppA[0], tppG[1] ]; + +tppJx = tppA[0] + tape_th; + +tppK = [ tppC[0], tppG[1] ]; +spp31 = tppK - [0, gap[1]]; +spp30 = [ spp8[0], spp31[1] ]; + +nom_cnr = 0.5 * [nook_w, nook_h, 0] - nook_cnr_rad * [1,1,0]; + +tooth_y = nom_cnr[1] - tooth_w/2; + +etxa = nom_cnr[0] - engage_l2; +etxb = etxa - engage_l1; +etxc = -(nom_cnr[0] - engage_l2); + +tapa = nom_cnr[1] - engage_l2; +tapb = tapa - tape_w; + +opra = nom_cnr[1] - engage_l2; +oprb = opra - open_recess_w; + +opqa = tooth_y - open_recess_2_d_tooth + open_recess_2_len/2; +opqb = opqa - open_recess_2_len; + +tppS = tppB + [-gap[0], 0]; +tppP = [ tppS[0] - tooth_th, tppC[1] ]; +tppQ = tppP + tooth_height * [0,-1] + tooth_inward * [1,0]; +tppR = [ tppS[0] + tooth_inward, tppQ[1] ]; +tppM = (tppQ + tppR) * 0.5 + tooth_th * 0.5 * [0,1]; + +edge_ledge_rad = edge_ledge_h; + +module RightSideMainProfile() { + rectfromto(spp7, spp0); + rectfromto(spp7, spp20); + EdgeLedgeProfile(); +} + +module LeftSideMainProfile() { + rectfromto(spp7, spp30); + rectfromto(spp7, spp20); + EdgeLedgeProfile(); +} + +module EdgeLedgeProfile() { + intersection(){ + hull(){ + for (t=[[0,0], [-20,0], [0,-10]]) { + translate(spp8 + + [edge_ledge_w, edge_ledge_h] + + edge_ledge_rad * [ -sin(edge_ledge_inc_ang), + -cos(edge_ledge_inc_ang) ] + + t) + circle(edge_ledge_rad); + } + } + translate(spp7) + square(30); + } +} + +module TopTapeCutout() { + polygon([ tppA, + tppA + [-40, 0], + tppG + [-40,-1], + [ tppJx, tppH[1]-1 ], + [ tppJx, tppC[1]+1 ], + [ tppA[0], tppC[1]+1 ]]); +} + +module RightTopMainProfile() { + l = [ tppA, tppB, tppC, tppD, tppE, tppF, tppG, tppH ]; + polygon(l); +} + +module LeftTopMainProfile() { + l = [ tppC, tppD, tppE, tppF, tppG, tppK ]; + polygon(l); +} + +module SideTapeCutout1(y0,y1) { + rectfromto([ spp7[0]-1, y0 ], + [ spp8[0]+1, y1 ]); +} + +module SideTapeCutout() { + SideTapeCutout1(spp6y, spp5y); + SideTapeCutout1(spp3y, spp2y); + SideTapeCutout1(spp3y, spp2y); + SideTapeCutout1(spp11y, spp1[1] + 1); // obsolete I think +} + +module ToothProfile(){ + polygon([tppA, + tppB, + tppS + [-0.1,0], + tppP, + tppC]); + hull(){ + polygon([tppP, + tppM, + tppS]); + translate(tppM) + circle(r= tooth_th/2); + } +} + +module Demo(){ ////toplevel + translate([-1,0,0]) { + translate([0,0,-2]) LeftSideMainProfile(); + translate([0,0,-2]) color("yellow") LeftTopMainProfile(); + color("red") difference(){ + LeftSideMainProfile(); + SideTapeCutout(); + } + translate([0,0,-4]) color("brown") EdgeLedgeProfile(); + translate(concat(spp8 + [edge_ledge_w, edge_ledge_h], [2])) + rotate(-edge_ledge_inc_ang) { + color("blue") square(3); + color("lightblue") mirror([1,0]) square(3); + } + } + translate([0,0,0]) color("purple") difference(){ + LeftTopMainProfile(); + TopTapeCutout(); + } + translate([nook_cnr_rad*2 + 5, 0,0]) mirror([1,0,0]) { + color("red") RightSideMainProfile(); + color("purple") RightTopMainProfile(); + color("grey") translate([0,0,-2]) ToothProfile(); + } + //%SideTapeCutout(); +} + +module FaceCore(z0,z1, extra_left, extra_right){ + difference(){ + for (mx=[0,1]) mirror([mx,0,0]) { + for (my=[0,1]) mirror([0,my,0]) { + translate(-nom_cnr) { + rotate_extrude(angle=90, convexity=10) { + intersection(){ + translate(-[1,0,0] * nook_cnr_rad) + children(mx); + rectfromto([-100,-100], [0,100]); + } + } + } + } + translate([nook_w/2, 0,0]) + linextr_y_xz(-nom_cnr[1]-0.1, nom_cnr[1]+0.1) + children(1-mx); + } + for (my=[0,1]) mirror([0,my,0]) { + translate([-nook_w/2, 0,0]) + mirror([1,0,0]) + linextr_y_xz(tapb, tapa) + children(2); + } + } + for (my=[0,1]) mirror([0,my,0]) { + translate([0, -nook_h/2, 0]) { + linextr_x_yz(-nom_cnr[0]-0.1, etxc + extra_left) children(0); + linextr_x_yz(etxc - extra_right, etxb + extra_right) children(1); + linextr_x_yz(etxb - extra_left, etxa + extra_left) children(0); + linextr_x_yz(etxa - extra_right, nom_cnr[0]+0.1) children(1); + } + } + if (!$test) { + linextr(z0,z1) + rectfromto(-nom_cnr, nom_cnr); + } +} + +module DiagonaliseNearHinge(wider){ + sz = spp0[1] - spp30[1] + gap[1]; + + for (my=[0,1]) mirror([0,my,0]) { + translate([-etxa, -nook_h/2, 0]) + mirror([1,0,0]) + linextr_y_xz(spp31[0] - wider, spp30[0] + gap[0] + 0.1) + translate([ 0, spp30[1] ]) + polygon([[ -1, 0 ], + [ 0, 0 ], + [ sz/diag_near_hinge_slope, sz ], + [ sz/diag_near_hinge_slope, sz + 0.1 ], + [ -1, sz + 0.1 ]]); + } +} + +module Base(){ ////toplevel + difference(){ + FaceCore(spp7[1],spp8[1], 0.3, 0) { + LeftSideMainProfile(); + RightSideMainProfile(); + SideTapeCutout(); + } + translate([0, -nook_h/2, 0]) + mirror([0,1,0]) + linextr_x_yz(-usb_w/2, usb_w/2) + rectfromto(spp8 + [-40, usb_below], [40, 40]); + translate([ gap[0], 0,0 ]) + DiagonaliseNearHinge(10); +/* + translate([nook_w/2, 0, 0]) + linextr_y_xz(oprb, opra) + translate(spp0) + rectfromto([-40, -open_recess_h], [40, 1]); +*/ + } + if ($test) { + linextr(spp7[1], spp8[1]) { + hull(){ + for (r=[0,180]) + rotate([0,0,r]) + translate(nom_cnr + -1 * nook_cnr_rad*[1,1]) + square(12); + } + } + } +} + +module Top(){ ////toplevel + difference(){ + FaceCore(tppE[1],tppD[1], -gap[0], gap[0] + 0.3) { + LeftTopMainProfile(); + RightTopMainProfile(); + TopTapeCutout(); + } + translate([nook_w/2, 0,0]) + linextr_y_xz(opqb, opqa) + rectfromto(spp8, tppC + [-1,1]); + } + translate([0,0, gap[1]]) + DiagonaliseNearHinge(0); + translate([nook_w/2, tooth_y, 0]) + linextr_y_xz(-tooth_w/2, +tooth_w/2) + ToothProfile(); +} +module TopPrint(){ ////toplevel + rotate([0,0,90]) rotate([180,0,0]) Top(); +} +module BasePrint(){ ////toplevel + rotate([0,0,90]) Base(); +} + +module TestExtrude(){ + difference(){ + linextr_y_xz(-test_pillar, tape_w+test_pillar) children(0); + linextr_y_xz( 0, tape_w ) children(1); + } +} + +module BaseTestRest(){ ////toplevel + cube([30,15, spp8[1]-spp7[1]]); +} + +module Demo3(){ ////toplevel + color("purple") Top(); + color("red") Base(); +} + +module TestSide(){ ////toplevel + TestExtrude() { LeftSideMainProfile(); SideTapeCutout(); } +} + +module TestTop(){ ////toplevel + TestExtrude() { LeftTopMainProfile(); TopTapeCutout(); } +} +module TestTopPrint(){ ////toplevel + rotate([180,0,0]) TestTop(); +} diff --git a/nutbox.scad.m4 b/nutbox.scad.m4 new file mode 100644 index 0000000..5384eff --- /dev/null +++ b/nutbox.scad.m4 @@ -0,0 +1,65 @@ +// -*- C -*- +// edit nutbos.scad.m4, not nutbos.scad! +// shaft, nut_across, nut_thick, nut_recess, wall, ceil + +nutbox_data_M4 = [ + 4.0 + 0.5, + 6.89 + 0.45, + 3.10 + 0.75, + 0.75, + 2.0, + 2.5 + ]; + +nutbox_data_M3 = [ + 3.0 + 0.5, + 5.48 + 0.45, + 2.26 + 0.75, + 0.75, + 1.8, + 2.0 + ]; + +m4_define(shaft, (nutbox_data[0])) +m4_define(nut_across, (nutbox_data[1])) +m4_define(nut_thick, (nutbox_data[2])) +m4_define(nut_recess, (nutbox_data[3])) +m4_define(wall, (nutbox_data[4])) +m4_define(ceil, (nutbox_data[5])) + +m4_define(nut_dia, (nut_across / cos(30))) +m4_define(outer_size, (nut_dia + wall * 2)) +m4_define(h_base, (ceil + nut_thick + nut_recess)) + +function NutBox_shaft(nutbox_data) = shaft; +function NutBox_outer_size(nutbox_data) = outer_size; +function NutBox_h_base(nutbox_data) = h_base; +function NutBox_wall(nutbox_data) = wall; // not sure why anyone needs this + +module NutBox(nutbox_data, h, h_above_extra=0) { + // origin is centre of top of mount + // entrance is to positive y + // height is h which must be at least h_base + // can be mad extra tall (with hole all the way through) with h_above_extra + w = outer_size; + difference(){ + mirror([0,0,1]) translate([-w/2,-w/2, -h_above_extra]) + cube([w,w, h + h_above_extra]); + mirror([0,0,1]) translate([0,0,-1 -h_above_extra]) + cylinder(r = shaft/2, h = h+2 + h_above_extra, $fn=20); + for (offset = [ [0,0, -nut_recess], + [0, outer_size, 0] ]) { + hull(){ + for (toffset = [[0,0,0], offset]) { + translate(toffset) + translate([0,0, -ceil]) + mirror([0,0,1]) + rotate([0,0, 360/6/2]) + cylinder(r = nut_dia/2, + h = nut_thick, + $fn = 6); + } + } + } + } +} diff --git a/osstest-arm-hub-bracket.scad b/osstest-arm-hub-bracket.scad new file mode 100644 index 0000000..63fefed --- /dev/null +++ b/osstest-arm-hub-bracket.scad @@ -0,0 +1,36 @@ +// -*- C -*- + +len = 80; +basethick = 4; +sidewall = 5; +width = 40; + +strapthick = 4; +strapwidth = 7; + +strapbotgap = 1; +strapsidegap = 4; +overstrap = 4; + +wallheight = strapbotgap + strapthick + overstrap; + +availlen = (len - strapsidegap); +numstraps = floor(availlen / (strapwidth + strapsidegap)); +strapstride = availlen / numstraps; +echo(numstraps, strapstride); + +module Bracket(){ + difference(){ + cube([len, width, basethick+wallheight]); + translate([-1, sidewall, basethick]) + cube([len+2, width-sidewall*2, wallheight+1]); + for (i=[0:numstraps-1]) { + translate([ (0.5+i)*strapstride + strapsidegap/2, + width/2, + basethick + strapbotgap + strapthick/2 ]) + cube([strapwidth, width*2, strapthick], center=true); + } + } +} + +Bracket(); diff --git a/osstest-arm-net-bracket.scad b/osstest-arm-net-bracket.scad new file mode 100644 index 0000000..54e7d3b --- /dev/null +++ b/osstest-arm-net-bracket.scad @@ -0,0 +1,94 @@ +// -*- C -*- + +holedist = 64; +tonguewidth = 10; +tongue2width = 15; +totaldepth = 26; +tongue2depth = 35; +thick = 4; +tabover = 7+6; +tabunder = 15; + +tabsidel = 7+1; +tabsider = 7+10; + +tonguethick = 4; +tongue2thick = 5; +strapthick = 2; +strapwidth = 5 + 0.35; +ridgewidth = 2; + +hstrengthick = 2.5; +hstrengdepth = strapwidth; + +cutoutover = 7; +rcutoutside = 7+2 - 0.5; +lcutoutside = 7-6.5 - 0.5; + +t2strengwidth = 10; +t2strengwidtht = 4; +t2strenglen = tongue2depth + 5; +t2strengthicker = 1; + +strapholethicker = 1.5; + +holedia = 3.5; + +tongue2x = tongue2width - holedist; + +module Tongue(tw,tt,ad,slots=2){ + y0=thick+0.1; + yn=ad-ridgewidth-strapwidth; + difference(){ + union(){ + translate([-tw, 0, 0]) + cube([tw, ad, tt+strapthick]); + child(); + } + for (yi=[1:slots-1]) + translate([-tw-1, y0 + (yn-y0)*yi/(slots-1), tt]) + cube([tw+2, strapwidth, strapthick+strapholethicker]); + } +} + +module Body(){ + translate([-holedist-tabsider, 0, 0]) { + cube([tabsidel+tabsider+holedist, thick, tabunder+tabover]); + cube([tabsidel+tabsider+holedist, thick+hstrengdepth, hstrengthick]); + } + Tongue(tonguewidth,tonguethick,totaldepth,3); + translate([tongue2x,0,0]) + Tongue(tongue2width,tongue2thick,tongue2depth+thick,5) { + mirror([1,0,0]) hull(){ + translate([-(tongue2width-t2strengwidth)*0.05, 0,0]) + cube([t2strengwidth,t2strenglen, + tongue2thick+strapthick+strapholethicker+t2strengthicker]); + cube([t2strengwidtht,thick+0.1,tabunder+tabover]); + } + } +} + +module Object(){ + difference(){ + Body(); + translate([0,-25,tabunder+cutoutover]) { + translate([-(holedist+rcutoutside), 0,0]) + mirror([1,0,0]) + cube([50,50,50]); + translate([lcutoutside, 0,0]) + cube([50,50,50]); + } + for (x=[-holedist,0]) + translate([x, 0, tabunder]) { + translate([0, -1, 0]) { + rotate([-90,0,0]) { + cylinder(r= holedia/2+0.5, h=thick+2, $fn=20); + } + } + translate([0, 19.95 + thick, 0]) + cube(center=true,[10,40,10]); + } + } +} + +Object(); diff --git a/osstest-arm-psu-bracket.scad b/osstest-arm-psu-bracket.scad new file mode 100644 index 0000000..2703cbc --- /dev/null +++ b/osstest-arm-psu-bracket.scad @@ -0,0 +1,88 @@ +// -*- C -*- + +mainlen = 33; +straps = [10,23]; +width = 60; +endwall = 5; +sidewall = 8; +basethick = 3; +endwallheight = 20; +morebase = 20; + +plugwidth = 35; +plugstartheight = 10; + +strapthick = 4; +strapwidth = 7; +strapbotgap = 1; +overstrap = 6; + +discdia = 60; +discoff_rear = 10; +discoff_front = 50; + +sidewallraise = strapbotgap + strapthick + overstrap; + +module Sides(){ + difference(){ + for (y=[0, width-sidewall]) { + translate([0,y,0]) + cube([mainlen, sidewall, basethick + sidewallraise]); + } + for (x=straps) { + translate([x, 0, basethick + strapbotgap + strapthick/2]) + cube([strapwidth, width*3, strapthick], center=true); + } + } +} + +module Ell(baseoff){ + translate([-endwall,0,0]) { + translate([baseoff,0,0]) + cube([mainlen + endwall + morebase, width, basethick]); + cube([endwall+0.1, width, endwallheight + sidewallraise + basethick]); + } +} + +module Plug(){ + translate([0, width/2, + basethick + sidewallraise + plugstartheight + 50]) + cube([endwall*3, plugwidth, 100], center=true); +} + +module Disc(discoff){ + translate([discoff + discdia/2, width/2, -1]) + cylinder(r=discdia/2, h=50, $fn=100); +} + +module Main(baseoff){ + difference(){ + union(){ + Ell(baseoff); + Sides(); + } + Plug(); + } +} + +module RearBlock(){ + difference(){ + Main(-morebase); + Disc(discoff_rear); + } +} + +module FrontBlock(){ + difference(){ + Main(0); + Disc(discoff_front - endwall); + } +} + +module Both(){ + RearBlock(); + translate([mainlen + endwall + 10, 0, 0]) + FrontBlock(); +} + +Both(); diff --git a/pandemic-counter-letters.fig b/pandemic-counter-letters.fig new file mode 100644 index 0000000..fb9c92a --- /dev/null +++ b/pandemic-counter-letters.fig @@ -0,0 +1,16 @@ +#FIG 3.2 Produced by xfig version 3.2.5b +Landscape +Center +Metric +A4 +100.00 +Single +-2 +1200 2 +1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 3780 3870 675 675 3780 3870 4455 3870 +4 0 0 32 -1 14 56 0.0000 4 540 555 3522 4119 A\001 +4 0 0 30 -1 14 56 0.0000 4 570 555 3510 4140 C\001 +4 0 0 33 -1 14 56 0.0000 4 570 555 3510 4140 S\001 +4 0 0 35 -1 14 48 0.0000 4 465 960 3337 4098 DF\001 +4 0 0 34 -1 14 56 0.0000 4 540 555 3510 4140 T\001 +4 0 0 31 -1 14 56 0.0000 4 540 555 3537 4125 L\001 diff --git a/pandemic-counter.scad b/pandemic-counter.scad new file mode 100644 index 0000000..4d427af --- /dev/null +++ b/pandemic-counter.scad @@ -0,0 +1,115 @@ +// -*- C -*- + +tokenrad=13; +tokenthick=1.9; + +joinwidth=1.0; + +circlerad=15; + +module Letter(depth) { + translate([-circlerad,-circlerad]) + import(file=str("pandemic-counter-l",depth,".dxf"), convexity=100); +} + +module Token(depth) { + rotate([0,180,0]) + linear_extrude(height=tokenthick) union(){ + difference(){ + circle(tokenrad); + Letter(depth); + } + child(); + } +} + +module Token_CDC(){ ////toplevel + Token(30){}; +} +module Token_Lab(){ ////toplevel + Token(31){}; +} +module Token_Act(){ ////toplevel + Token(32){ + translate([0, 1]) + square([tokenrad*.75, joinwidth], center=true); + } +} +module Token_Spec(){ ////toplevel + Token(33){}; +} +//module Token_Terr(){ ////toplevel +// Token(34){}; +//} +//module Token_TerrMove(){ ////toplevel +// Token(35){ +// translate([-tokenrad*.75, -1]) +// square([tokenrad*.75, joinwidth]); +// }; +//} + +spacing = tokenrad * 2 + 2; + +module Tokens(rows=1,cols=1) { + for (i=[0:rows-1]) + for (j=[0:cols-1]) + translate([j*spacing, i*spacing, 0]) + child(0); +} + +module Tokens_Act(){ ////toplevel + // Print *twice*, LAPIS BLUE or SQUEEZED ORANGE + // ordinary actions + // up to 4 for 5 players, plus 2 for Borrowed Time plus 1 for Generalist + // so need 23, make 24 + Tokens(4,3) Token_Act(); +} + +module Tokens_Spec(){ ////toplevel + // ELECTRIC BLUE or MELLOW YELLOW + // once-per-turn special action, one each for 5 players + Tokens(3) Token_Spec(); + translate([spacing,0,0]) Tokens(2) Token_Spec(); +} + +module Tokens_CDC(){ ////toplevel + // STORM GREY + // CDC + // 1 action per turn + 2 Borrowed Time + Tokens(3) Token_CDC(); +} + +module Tokens_Lab(){ ////toplevel + // WHITE + // free Lab action (on building research station, etc) + // make 2 (probably want less than that) + Tokens(2) Token_Lab(); +} + +//module Tokens_Terr(){ ////toplevel +// // FIRE TRUCK RED +// // Bioterrorist general actions +// Tokens(2) Token_Terr(); +//} + +//module Tokens_TerrMove(){ ////toplevel +// // CLASSIC BLACK +// // Bioterrorist drive/ferry +// Tokens(1) Token_TerrMove(); +//} + +module PosToken(i,j){ + translate([j*spacing, i*spacing, 0]) child(); +} + +module Demo(){ ////toplevel + PosToken(0,0) Token_CDC(); + PosToken(1,0) Token_Lab(); + PosToken(2,0) Token_Act(); + PosToken(3,0) Token_Spec(); +// PosToken(1,1) Token_Terr(); +// PosToken(2,1) Token_TerrMove(); +} + +//Tokens_Act(); +//Demo(); diff --git a/pandemic-counter.slic3r b/pandemic-counter.slic3r new file mode 100644 index 0000000..add6df7 --- /dev/null +++ b/pandemic-counter.slic3r @@ -0,0 +1 @@ +fill_density = 0.5 diff --git a/pandemic-quarantine-numbers.fig b/pandemic-quarantine-numbers.fig new file mode 100644 index 0000000..1524380 --- /dev/null +++ b/pandemic-quarantine-numbers.fig @@ -0,0 +1,13 @@ +#FIG 3.2 Produced by xfig version 3.2.5b +Landscape +Center +Metric +A4 +100.00 +Single +-2 +1200 2 +2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 + 1800 1800 2385 1800 2385 2385 1800 2385 1800 1800 +4 0 0 1 -1 14 24 0.0000 4 255 240 1980 2205 1\001 +4 0 0 2 -1 14 24 0.0000 4 255 240 1980 2205 2\001 diff --git a/pandemic-quarantines.scad b/pandemic-quarantines.scad new file mode 100644 index 0000000..834d128 --- /dev/null +++ b/pandemic-quarantines.scad @@ -0,0 +1,65 @@ +// -*- C -*- + +prisml = 13; +triedge = 13; + +etchdepth = 1.0; + +figboxsize = 13; + +// calculated + +triheight = triedge / 2 * sqrt(3); +tricentre = triedge / 2 * tan(30); + +module Number(number) { + translate([-figboxsize/2, -figboxsize/2]) + import(file=str("pandemic-quarantine-l",number,".dxf"), convexity=100); +} + +module FaceTriangle(){ + x = triedge / 2; + y = triheight; + polygon([[-x, 0], + [ 0, y], + [ x, 0]]); +} + +module Body(){ + translate([0, prisml/2, 0]) + rotate([90,0,0]) + linear_extrude(height=prisml) FaceTriangle(); +} + +module NumberCut(number){ + translate([0,0, -etchdepth]) + linear_extrude(height= etchdepth + 1) + Number(number); +} + +module Etchings(){ + for (rot=[0,180]) { + rotate([0,0, rot]) + translate([0, -prisml/2, triedge * 0.3]) + rotate([90, 0, 0]) + NumberCut(2); + } + for (rot=[0,120,240]) { + translate([0,0, tricentre]) + rotate([0, rot, 0]) + translate([0,0, -tricentre]) + rotate([0,180,0]) + rotate([0,0, rot==240 ? 90 : -90]) + NumberCut(1); + } +} + +module Counter(){ + difference(){ + Body(); + Etchings(); + } +} + +Counter(); +//NumberCut(1); diff --git a/pannierstay.scad b/pannierstay.scad new file mode 100644 index 0000000..65538a6 --- /dev/null +++ b/pannierstay.scad @@ -0,0 +1,14 @@ +len = 54.3 - 1; +bigdep = 10.7 - 1; +smalldep= 4.9 - 1; +tallw1 = 3.5 - 1.5; +tallw2 = 3.5 - 1.5; // ish +totalw = 11.6 - 2; + +gapw = totalw - tallw1 - tallw2; + +difference() { + cube([len, totalw, bigdep]); + translate([-1, tallw2, smalldep]) + cube([len+2, gapw, bigdep - smalldep + 1]); +} diff --git a/pattress-boxes-3-cover.scad b/pattress-boxes-3-cover.scad new file mode 100644 index 0000000..7c1d4b8 --- /dev/null +++ b/pattress-boxes-3-cover.scad @@ -0,0 +1,201 @@ +// -*- C -*- + +patbox_side = 87; +patbox_centres = 60.3; + +lid_thinboxbase_overlap = 5; +lid_fatbox_overlap = 12; + +lid_thinbox_h = 9; +lid_fatbox_h = 24; +lid_fatbox_switches_h = 6+4; + +lid_max_switches_w = 70; +lid_switches_y_slop = 3; + +total_len = 260; +thinbox_len = 87; + +rail_overlap = 8; + +lid_top_wall = 1.5; +lid_front_wall = 1.5; +lid_side_wall = 1.5; + +peg_engage_depth = 1; +peg_engage_dia = 6.5; +peg_main_dia = 9; +peg_max_dia = 15; +peg_inner_dia = 3.5; +peg_top_thick = 1; +peg_straight_len = 3; + +$peg_inner_slop = 0.75; +$peg_outer_slop = -0.9; +$peg_outer_slop_engage = 0.1; + +peg_slope = 1; + +lid_side_slop = 0.5; +lid_rail_behindslop = 0.5; +lid_rail_strongwall = 2.5; + +// computed + +lid_inner_max_h = + lid_thinboxbase_overlap + lid_fatbox_h + lid_fatbox_switches_h; +lid_inner_min_h = lid_fatbox_overlap + lid_fatbox_switches_h; + +lid_inner_kink = [thinbox_len, thinbox_len*2]; + +lid_inner_w_nom = patbox_side; +lid_inner_w = lid_inner_w_nom + lid_side_slop * 2; + +lid_seatline_w = (lid_inner_w - lid_max_switches_w)/2 - lid_switches_y_slop; + +lid_seatline_h = lid_fatbox_switches_h; + +peg_main_height = peg_straight_len + (peg_max_dia - peg_main_dia)/2/peg_slope; + +thinbox_front_z = lid_fatbox_switches_h + lid_fatbox_h - lid_thinbox_h; + +raillen = patbox_side/2 + rail_overlap; + +module LidSideProfile(){ + polygon([[-lid_top_wall, lid_inner_max_h], + [min(lid_inner_kink[0],total_len), lid_inner_max_h], + [min(lid_inner_kink[1],total_len), lid_inner_min_h], + [total_len, lid_inner_min_h], + [total_len, -lid_front_wall], + [-lid_top_wall, -lid_front_wall]]); +} + +module RailProfile(lslop=0.1){ + yt_base = thinbox_front_z; + yt = yt_base - lid_rail_behindslop; + pegx = (lid_inner_w_nom - patbox_centres)/2; + sw = lid_rail_strongwall; + + polygon([[-lslop, yt], + [pegx - peg_main_dia/2, yt], + [pegx - peg_main_dia/2, yt_base - peg_straight_len], + [sw, + yt_base - peg_straight_len - (pegx - peg_main_dia/2)/peg_slope + +sw], + [sw, + lid_seatline_h - 1], + [-lslop, + lid_seatline_h - 1]]); +} + +module LidSide(){ + overlap = [0.1, 0.1, 0.1]; + + // main side profile + rotate([90,0,0]) + linear_extrude(height= lid_side_wall) + LidSideProfile(); + + // seatline + translate(-overlap) + cube(overlap + [total_len, lid_seatline_w, lid_seatline_h]); + + // lid front + translate([-0.1, -0.1, -lid_front_wall]) + cube([total_len+0.1, lid_inner_w/2 + 0.2, lid_front_wall]); + + // lid top + translate([-lid_top_wall, -lid_side_wall, -lid_front_wall]) + cube([lid_top_wall, lid_inner_w/2 + 10, lid_front_wall + lid_inner_max_h]); + + // rail + rotate([90,0,90]) + translate([0,0,-0.1]) + linear_extrude(height=raillen+0.1) //todo + RailProfile(); + + // rail end + translate([raillen, 0,0]) + intersection(){ + rotate_extrude($fn=50) + RailProfile(lslop=0); + translate([0, 25-0.1, 0]) + cube(50, center=true); + } +} + +module Lid(){ ////toplevel + for (m=[0,1]) + mirror([0,m,0]) + translate([0, -lid_inner_w/2, 0]) LidSide(); +} + +module PegProfile(){ + polygon([[-peg_engage_depth, (peg_engage_dia - $peg_outer_slop_engage)/2], + [0, (peg_engage_dia - $peg_outer_slop_engage)/2], + [0, (peg_main_dia - $peg_outer_slop)/2], + [peg_straight_len, (peg_main_dia - $peg_outer_slop)/2], + [peg_main_height, (peg_max_dia - $peg_outer_slop)/2], + [peg_main_height+peg_top_thick, (peg_max_dia - $peg_outer_slop)/2], + [peg_main_height+peg_top_thick, (peg_inner_dia + $peg_inner_slop)/2], + [-peg_engage_depth, (peg_inner_dia + $peg_inner_slop)/2]]); +} + +module Peg(){ ////toplevel + echo($peg_outer_slop_engage); + rotate_extrude($fn=50) + rotate([0,0,-90]) + PegProfile(); +} + +module Pegs(){ ////toplevel + baseslop = 0.1; + dslops = [0, -0.5, -1.0, -1.5]; + stride = peg_max_dia + 4; + for (i=[0:len(dslops)-1]) { + translate([i*stride,0,0]) + assign($peg_outer_slop_engage= baseslop + dslops[i]) + Peg(); + } +} + +module AtFixingCentres(){ + for (fc=[-1,+1]) { + translate([patbox_side/2 + fc*patbox_centres/2, + patbox_side/2, + 0]) + children(); + } +} + +module TopPattressBox(){ + difference(){ + translate([0,0, -lid_thinbox_h]) + cube([patbox_side, patbox_side, lid_thinbox_h]); + AtFixingCentres(){ + translate([0,0,-10]) cylinder(r=peg_engage_dia/2, h=20); + } + } +} + +module Demo(){ + Lid(); + translate([0,0, thinbox_front_z]) + rotate([0,180,0]) translate([0, -patbox_side/2, 0]) + rotate([0,0,90]) union(){ + %TopPattressBox(); + color("blue") AtFixingCentres(){ + rotate([180,0,0]) Peg(); + } + } +} + +//LidSide(); +//PegProfile(); +//Peg(); +//Pegs(); +//TopPattressBox(); +//RailProfile(); +//Demo(); +//Lid(); +//translate([0,0,-lid_fatbox_switches_h]) Lid(); diff --git a/pawn.scad b/pawn.scad new file mode 100644 index 0000000..7277dcd --- /dev/null +++ b/pawn.scad @@ -0,0 +1,80 @@ +// -*- C -*- + +// shape parameters + +r1 = 2.85; +r2 = 4; a2 = 27; +r3 = r2; +r4 = 4; a4 = 18; +r5 = 30; +h6 = 7; a6 = 4; + +// coordinates + + z1 = 0; +h2 = r2 * sin(a2); z2 = z1 - h2; +h3 = r3 * sin(a2); z3 = z2 - h3; +h4 = r4 * sin(a4); z4 = z3 - h4; + +zc5 = z4 - r5 * sin(a4); +z5 = zc5 + r5 * sin(a6); z6 = z5 - h6; + +x1 = 0 - r1; +x2 = x1 + r2 * (1-cos(a2)); +x3 = x2 + r3 * (1-cos(a2)); +x4 = x3 - r4 * (1-cos(a4)); + +xc5 = x4 + r5 * cos(a4); +x5 = xc5 - r5 * cos(a6); + +x6 = x5 - h6 * tan(a6); + +htotal = r1 - z6; +echo("height", htotal); + +d = 0.01; +dx = 0.00; + +$fa=2; +$fs=0.2; + +module SegmentBasisSquare(zmin, zmax, xmin){ + translate([xmin, zmin-d]) square([-xmin+dx, zmax-zmin+d*2]); +} +module ConvexSegment(xc, zc, r, zmin, zmax){ + intersection(){ + translate([xc,zc]) circle(r=r); + SegmentBasisSquare(zmin,zmax,-50); + } +} +module ConcaveSegment(xc, zc, r, zmin, zmax){ + difference(){ + SegmentBasisSquare(zmin,zmax, xc); + translate([xc,zc]) circle(r=r); + } +} + +module PawnTemplate(){ + ConvexSegment( x1 + r1, z1, r1, z1, 50); + ConvexSegment( x1 + r2, z1, r2, z2, z1); + ConcaveSegment( x3 - r3, z3, r3, z3, z2); + ConcaveSegment( x3 - r4, z3, r4, z4, z3); + ConvexSegment( xc5, zc5, r5, z5, z4); + polygon([[x6, z6], + [x5, z5+d], + [dx, z5+d], + [dx, z6]]); +} + +module Pawn(h=htotal){ + scale(h/htotal) { + rotate_extrude(convexity=10, $fn=50){ + assign($fn=undef){ + PawnTemplate(); + } + } + } +} + +Pawn(h=30); +//PawnTemplate(); diff --git a/pawn.slic3r b/pawn.slic3r new file mode 100644 index 0000000..be356f2 --- /dev/null +++ b/pawn.slic3r @@ -0,0 +1,7 @@ +first_layer_bed_temperature = 80 +bed_temperature = 70 +skirts = 3 +first_layer_temperature = 190 +temperature = 177 +extrusion_multiplier = 0.9 +fill_density = 1.0 diff --git a/pin-hinge.scad b/pin-hinge.scad new file mode 100644 index 0000000..81d527e --- /dev/null +++ b/pin-hinge.scad @@ -0,0 +1,100 @@ +// -*- C -*- + +include + +$hinge_pin_dia = 0.795 + 0.75; +$hinge_main_dia = 4.0; +$hinge_inter_gap = 0.50; +$hinge_prong_minwidth = 3.0; +$hinge_noncrit_gap = 1.0; + +$fa = 3; +$fs = 0.05; + +module HingePinPlan(){ + circle(r= $hinge_pin_dia/2); +} + +module HingeProngPlan(behind){ + hull(){ + circle(r= $hinge_main_dia/2); + polygon([[0,0], + [-$hinge_main_dia/2, -behind], + [+$hinge_main_dia/2, -behind]]); + } +} + +module HingeGapPlan() { + circle(r = $hinge_main_dia/2 + $hinge_inter_gap); +} + +module PlanDemo(){ + HingeProngPlan(5); + %HingeGapPlan(); + translate([0,0,1]) color("red") HingePinPlan(); +} + +module HingePinUnitCell(l) { + eff_l = l + $hinge_inter_gap; + pairs = floor(eff_l / (2*($hinge_prong_minwidth + $hinge_inter_gap))); + stride = eff_l / pairs; + $hinge__prong_width = stride/2 - $hinge_inter_gap; + for (i=[0:pairs-1]) { + translate(stride * i * [1,0,0]) + children(0); + } +} + +module HingePositive(l, behind){ + HingePinUnitCell(l){ + linextr_x_yz(0, $hinge__prong_width) + HingeProngPlan(behind); + } +} + +module HingeNegative(l){ + linextr_x_yz(-0.1, l+0.1) + HingePinPlan(); + HingePinUnitCell(l){ + linextr_x_yz($hinge__prong_width, + $hinge__prong_width*2 + 2*$hinge_inter_gap) + HingeGapPlan(); + } +} + +test_l = 30; +test_wb = 12; +test_h = 12; + +test_face_gap = 0.75; + +module Demo(){ + difference(){ + HingePositive(test_l, test_h/2); + %HingeNegative(test_l); + } +} + +module TestBody(){ + linextr_x_yz(0, test_l){ + offset(delta = -test_face_gap/2) + polygon([[0,0], + [-test_wb/2, -test_h], + [+test_wb/2, -test_h]]); + } +} + +module Test(){ + difference(){ + union(){ + TestBody(); + HingePositive(test_l, test_h/2); + } + HingeNegative(test_l); + } +} + +//PlanDemo(); +//Demo(); +//TestBody(); +Test(); diff --git a/poster-tube-lid-coarse.scad b/poster-tube-lid-coarse.scad new file mode 100644 index 0000000..2ff8f3d --- /dev/null +++ b/poster-tube-lid-coarse.scad @@ -0,0 +1,6 @@ +// -*- C -*- + +//// toplevels-from: +include + +coarse = true; diff --git a/poster-tube-lid-parametric.scad.pl b/poster-tube-lid-parametric.scad.pl new file mode 100755 index 0000000..64d4d00 --- /dev/null +++ b/poster-tube-lid-parametric.scad.pl @@ -0,0 +1,234 @@ +#!/usr/bin/perl -w +use strict; + +use Math::Vector::Real; +use Math::Trig qw(pi); +use POSIX; +use Data::Dumper; + +sub TAU () { pi*2; } + +my $thick = 2.5; + +my $small_dia = 20; +my $large_dia = 30; +my $slope_angle = 45 * TAU/360; +my $jcurverad = 5; +my $tall = 50; + +my $lin_len = 2; +my $sine_size = 5; +my $sine_angle = 1.20 * TAU/8; + +my $ballend_xr = $thick/2; + +my $skew_slope = 0.7; + +my @i_sections = qw(ball0 -6 + sine0 -10 + lin0 -2 + circle 40 + lin1 2 + sine1 10 + ball2 6 + - + ); + +my @j_sections = qw(lin0 2 + - + curve1 10 + - + curveE 20 + - + curve2 -10 + - + ); + +sub point ($$$$) { + my ($ip,$it, $jp,$jt) = @_; + + my ($i_offset); + + my $i_outward = V( 0, + ($ip =~ m/0$/ ? -1 : +1), + 0 ); + + my $i_j_y_angle = 0; + + my $i_thickscale = 1.0; + my $sine_len = $sine_size * sin($sine_angle); + my $sine_height = $sine_size * (1 - cos($sine_angle)); + + if ($ip =~ m/^lin[01]$/) { + $i_offset = V( -$lin_len * $it, + 0, + 0 ); + } elsif ($ip =~ m/^circle$/) { + $i_offset = V( 0,0,0 ); + $i_outward = V( sin($it * TAU/2), + -cos($it * TAU/2), + 0 ); + } elsif ($ip =~ m/^sine[01]$/) { + my $angle = $it * $sine_angle; + $i_offset = V( -$lin_len -$sine_size * sin($angle), + 0, + +$sine_size * (1 - cos($angle)) + ); + $i_j_y_angle = $angle; + } elsif ($ip =~ m/^ball[02]$/) { + $i_j_y_angle = $sine_angle; + my $angle = $it * TAU/4; + my $dx = sin($angle) * $ballend_xr; + $i_offset = V( -$lin_len -$sine_len - $dx * cos($sine_angle), + 0, + +$sine_height + $dx * sin($sine_angle) + ); + $i_thickscale = cos($angle); + } else { + die "$ip ?"; + } + + my $i_j_y_vect = V( sin($i_j_y_angle), + 0, + cos($i_j_y_angle )); + + my $j_plus_th = $jp =~ m/2$/ ? $thick : 0; + + my $i_thick = $thick * $i_thickscale; + my $j_p_x = $small_dia/2 + $thick/2; + my $j_rs_x = $large_dia/2 + $thick/2; + my $j_dqr_x = (1-cos($slope_angle)) * $jcurverad; + my $j_q_x = $j_rs_x - $j_dqr_x; + my $j_dpq = ($j_q_x - $j_p_x) / asin($slope_angle); + #print STDERR "($j_q_x - $j_p_x) / asin($slope_angle); => $j_dpq\n"; + my $j_p_y = 0; + my $j_q_y = $j_p_y + $j_dpq * cos($slope_angle); + my $j_r_y = $j_q_y + sin($slope_angle) * $jcurverad; + my $j_s_y = $tall; + my $j_qrc_x = $j_rs_x - $jcurverad; + my $j_qrc_y = $j_r_y; + + my $j_x; + my $j_y; + + if ($jp =~ m/^curveE$/) { + my $angle = ($jt + 1) * TAU/2 - $slope_angle; + $j_x = $j_p_x + $i_thick/2 * cos($angle); + $j_y = $j_p_y + $i_thick/2 * sin($angle); + } elsif ($jp =~ m/^curve[12]$/) { + my $angle = $slope_angle * $jt; + my $outwards = $jp =~ m/1/ ? -1 : +1; + $j_x = $j_qrc_x + cos($angle) * ($jcurverad + $outwards * $i_thick/2); + $j_y = $j_qrc_y - sin($angle) * ($jcurverad + $outwards * $i_thick/2); + } elsif ($jp =~ m/^lin0$/) { + $j_x = $j_rs_x + $i_thick * (+0.5 - $jt); + $j_y = $j_s_y; + $i_offset->[2] = 0; + } else { + die "$jp ?"; + } + + $j_y -= $j_qrc_y; + + if ($j_y > 0) { + $i_j_y_vect = V(0,0,1); + } + +# print STDERR "@_ $j_x $j_y $i_offset $i_outward\n"; + return + $i_offset + + $j_x * $i_outward + + $i_j_y_vect * $j_y + + V(0,0,1) * $j_qrc_y + + V(0,0,-$tall) ; +} + +sub get_sections_ptvals { + my $last_ptval; + my @out; + while (my $name = shift @_) { + if ($name eq '-') { + push @out, $last_ptval; + } else { + my $count = shift @_; + my $neg = sub { $_[0] }; + if ($count < 0) { + $count = -$count; + $neg = sub { 1- $_[0] }; + } + foreach (my $ix = 0; $ix < $count; $ix++) { + push @out, [ $name, $neg->($ix/$count) ]; + } + $last_ptval = [ $name, $neg->(1.0) ]; + } + } + return @out; +} + +our @points; +our %point_indices; +our @triangles; + +my @ipts; +my @jpts; + +my $qi; +my $qj; + +sub triangle { + my @pixs; + foreach my $pval (@_) { + my $pix = $point_indices{$pval} + //= ((push @points, $pval), $#points); + if (grep { $pix eq $_ } @pixs) { + print "// elide @{ $ipts[$qi] } @{ $jpts[$qj] }\n"; + return; + } + push @pixs, $pix; + } + push @triangles, [ $qi,$qj, \@pixs ]; +} + +sub make_sheet () { + @ipts = get_sections_ptvals(@i_sections); + @jpts = get_sections_ptvals(@j_sections); + my @sheet; + foreach my $ipt (@ipts) { + my @row = (); + foreach my $jpt (@jpts) { + push @row, &point(@$ipt, @$jpt); + } + push @sheet, \@row; + } + foreach ($qi=0; $qi<$#ipts; $qi++) { # i direction does not wrap + my $qi2 = $qi+1; + foreach ($qj=0; $qj<@jpts; $qj++) { # j direction does wrap + my $qj2 = ($qj+1) % @jpts; + my $p0 = $sheet[$qi][$qj]; + triangle($p0, $sheet[$qi2][$qj], $sheet[$qi2][$qj2]); + triangle($p0, $sheet[$qi2][$qj2], $sheet[$qi][$qj2]); + } + } +} + +sub pv ($) { + my $v = shift @_; + return "[".(join ',', @$v)."]"; +} + +sub write_out () { + print "module ImplHeadCup(){ polyhedron(points=[\n" or die $!; + print pv($_),",\n" or die $! foreach @points; + print "],faces=[\n" or die $!; + foreach (@triangles) { + print pv($_->[2]),", // @{ $ipts[$_->[0]] } @{ $jpts[$_->[1]] }\n" or die $!; + } + print "],convexity=10); }\n" or die $!; + print < +include + +coarse = false; +enable_head_cups = false; + +main_dia = 71.2 + 0.50 - 2.26; +top_thick_middle = 4; +top_thick_by_oring = 3.0; +top_middle_dr = 11; + +main_cnr = 6.0; + +min_wall = 3; + +rivet_posn = 6.0 + 0.30; +rivet_thick = 1.67; +rivet_width = 4.15 + 1.0; +rivet_tall = 5.51 + 1.49; + +over_rivet_wall = 1.0; +side_rivet_gap = 1.5; +inside_rivet_gap = 1.5; + +bayo_interf = 0.30; +bayo_behind = 8.5; +bayo_interf_width = 2.0; +bayo_interf_slope = 0.5; + +oring_thick = 5.0; +oring_bore = 62.0; + +oring_upper_embed_angle = 80; +oring_compress = 0.1; // proportion +oring_compress_more = 0.2; + +oring_rm_beside = 8; +oring_rm_scale = 2.0; +oring_rm_angle = 20; + +side_taper = 1.0; + +bayo_gap = 6.0; + +bayo_entry = 1.167; +bayo_inramp = 0.9; + +bayo_slice_size = coarse ? 5 : 1; + +brace_hole_width = 1.0; +brace_above_below = 1.2; +brace_end_shorter = 0.3; + +jig_thick = 1.4; +jig_hole_dia = 3.0; +jig_rim = 5; +jig_mark = 5; + +strap_loop_thick = 6; +strap_loop_inside = 10; +strap_loop_strlen = 10; +strap_loop_elevation = 45; + +sm_inner_circum = 218 - 1.90 - 1.00 - 0.50; +sm_main_thick = 2.0; +sm_main_width = 20; + +sm_bolt_dia = 3.5 + 0.1; +sm_bolt_shaft = 21.0; +sm_bolt_head_dia = 6.94 + 1.0; +sm_bolt_head_thick = 2.14; +sm_bolt_nut_width = 5.89 + 0.25; +sm_bolt_nut_thick = 3.68; +sm_bolt_tighten_allow = 2.0; + +sm_bolt_y_clear = 0.75; +sm_bolt_y_over = 0.5; + +sm_closure_cnr = 3.0; + +wm_thick = 5; +wm_screw_dia = 4.5; // Timco wood screw 40mm, use brown plug +wm_screwdriver_dia = 6.3 + 1.5; +wm_screw_around = 5.0; +wm_screw_slot = 3.5; +wm_screw_head = 8.0; + +wmb_screw_dia = 5; +wmb_screw_head_dia = 8.7 + 0.5; +wmb_screw_around_x = 4; +wmb_screw_around_z = 6; +wmb_screw_depth_min = 10; +web_screw_len = 16 + 0.5; +wmb_nut_across = 7.82 + 0.35; +wmb_nut_around_min = 2; +wmb_nut_behind_min = 5; +wmb_nut_th = 3.84 + 0.75; +wmb_mount_wall = 4.5; +wmb_mount_gap_xy = 0.1; +wmb_mount_gap_z = 0.2; +wmb_mount_y_width = 10; +wmb_bottom_gap = 35; // includes allowance for padding, etc. +wmb_bottom_th = 7; +wmb_bottom_th_min = 1; +wmb_ring_gap = 1.0; +wmb_base_extra_rad = 10; +wmb_jig_th = 1; +wmb_jig_around_gap = 1; + +catch_stalk_h = 4.5; +catch_stalk_len = 50; +catch_tip_th = 4; +catch_head_th = 3; + +catch_pin_slop = 0.25; // each side, and above +catch_pin_slop_x_extra = 0.0; // only on one side +catch_stalk_above_gap = 1.5; +catch_stalk_eff_bend_rad = catch_stalk_len * 0.75; + +catch_strap_width = 12; +catch_stalk_base_width = 15; + +catch_knob_dia = 6; +catch_knob_above_gap = 5; +catch_knob_height = 3.0; + +catch_stalk_below_gap = 1.0; +catch_stalk_beside_gap = 2.0; + +// calculated + +TAU = PI*2; + +bayo_entry_x = bayo_entry; +bayo_entry_z = bayo_entry; +bayo_inramp_x = bayo_inramp; +bayo_inramp_z = bayo_inramp; + +oring_mid_dia = oring_bore + oring_thick; +oring_outer_dia = oring_mid_dia + oring_thick; + +oring_oblate = (1 - oring_compress); + +oring_y_rad = oring_thick/2 * oring_oblate; +oring_x_rad = oring_thick/2 / oring_oblate; + +by_oring_z = oring_y_rad * (1 + cos(oring_upper_embed_angle)); + +side_height = rivet_posn + bayo_behind + rivet_thick/2; +side_thick = rivet_tall + over_rivet_wall; + +top_z = top_thick_by_oring + oring_y_rad + by_oring_z; + +middle_bot_z = top_z - top_thick_middle; + +bayo_top_z = bayo_behind + bayo_gap; + +bayo_nom_rad = main_dia/2 + side_thick; +bayo_real_rad = main_dia/2 + rivet_tall; + +rivet_entry_width = rivet_width + side_rivet_gap; + +jig_mark_rad = jig_mark + main_dia/2 + jig_thick; + +handling_dia = oring_bore + oring_thick*2 + min_wall*2; +handling_angle = 45; + +sm_inner_rad = (sm_inner_circum + sm_bolt_tighten_allow/2) / TAU; +sm_outer_rad = sm_inner_rad + sm_main_thick; + +wm_main_width = sm_main_width; +wm_y_min = sqrt( pow(sm_inner_rad, 2) - + pow(sm_inner_rad - (wm_thick - sm_main_thick), 2) ); +wm_y_screw = wm_y_min + wm_screw_around + wm_screw_dia/2; +wm_y_max = wm_y_screw + wm_screw_dia/2 + wm_screw_around; +wm_lhs_y_min = -wm_y_max; +wm_y_slotc_screw = wm_y_screw + wm_screw_slot/2; +wm_y_slot1_screw = wm_y_screw + wm_screw_slot; +wm_y_slot1_max = wm_y_max + wm_screw_slot/2; +wm_z_slot0_screw = wm_main_width + wm_screwdriver_dia/2; +wm_z_slotc_screw = wm_z_slot0_screw + wm_screw_slot/2; +wm_z_slot1_screw = wm_z_slot0_screw + wm_screw_slot; +wm_z_max = wm_z_slot1_screw + wm_screw_around; + +wmb_mount_cut_rad = sm_outer_rad + wmb_ring_gap; +wmb_nut_rad = wmb_nut_across / cos(30) * 0.5; +wmb_x_screw_plus_around_r = max( + wmb_screw_around_x + wmb_screw_dia/2, + wmb_nut_around_min + wmb_nut_across/2 + ); +wmb_x_screw = -sm_outer_rad + wmb_x_screw_plus_around_r; +wmb_x_outer = -sm_outer_rad + wmb_x_screw_plus_around_r * 2; +function wmb_screw_thing_y_min(dia) = sqrt( + pow(wmb_mount_cut_rad, 2) - + pow(wmb_x_screw + dia/2, 2) + ); +wmb_y_screw_end = wmb_screw_thing_y_min(wmb_screw_dia); +wmb_y_nut_min = max( + wmb_screw_thing_y_min(wmb_nut_across + wmb_nut_around_min*2), + wm_y_slot1_max + ); +wmb_y_mount_max = max( + wmb_y_nut_min + wmb_nut_th + wmb_nut_behind_min, + wmb_y_screw_end + wmb_screw_depth_min + ); +wmb_z_screw = max( + wmb_screw_around_z + wmb_screw_dia/2, + wmb_nut_around_min + wmb_nut_rad + ); +wmb_z_max = wmb_z_screw * 2; +wmbb_y_max = max( + wmb_y_mount_max + wmb_mount_gap_xy + wmb_mount_wall, + wmb_y_screw_end + web_screw_len + ); +wmbb_x_outer = wmb_x_outer + (wmb_mount_gap_xy + wmb_mount_wall); +wmbb_z_flat_max = -wmb_bottom_gap; +wmbb_z_flat_whole_min = wmbb_z_flat_max - wmb_bottom_th_min; +wmbb_z_min = wmbb_z_flat_max - wmb_bottom_th; +wmbb_r_top = main_dia/2 + wmb_base_extra_rad; +wmbb_r_bottom = wmbb_r_top - (wmb_bottom_th - wmb_bottom_th_min); + +smc_pos = [ 0, sm_inner_rad, 0 ]; + +smc_bolt_nut_dia = sm_bolt_nut_width / cos(30); +smc_bolt_nut_eff_thick = sm_bolt_nut_thick + sm_bolt_tighten_allow; + +smc_bolt_y = sm_bolt_dia/2 + sm_bolt_y_clear; +smc_max_y = smc_bolt_y + sm_bolt_y_over + + max(sm_bolt_head_dia/2, smc_bolt_nut_dia/2); +smc_cnr_c_x = sm_bolt_shaft/2 - sm_closure_cnr + + sm_bolt_head_thick/2 + smc_bolt_nut_eff_thick/2; + +catch_cr = catch_knob_dia/2 + catch_stalk_beside_gap; +catch_strap_thick = sm_main_thick; + +echo("R ", sm_inner_rad, bayo_real_rad, bayo_nom_rad); + +$fs= coarse ? 2.5 : 0.5; +$fa= coarse ? 5 : 1; + +include + +// bayonet definition + +bayo_a = [ bayo_entry_x, 0 ]; +bayo_p = [ 0, bayo_entry_z ]; +bayo_n = [ 0, bayo_behind-bayo_inramp_z ]; +bayo_m = [ bayo_inramp_x, bayo_behind ]; +bayo_l = bayo_m + bayo_interf * [ 1/bayo_interf_slope, 1 ]; +bayo_k = bayo_l + [ bayo_interf_width, 0 ]; +bayo_j = bayo_k + bayo_interf * [ 1/bayo_interf_slope, -1 ]; +bayo_i = bayo_j + [ rivet_width + inside_rivet_gap, 0 ]; +bayo_h = [ bayo_i[0], bayo_behind + bayo_gap + bayo_interf ]; +bayo_g = [ bayo_m[0] - rivet_width, bayo_h[1] ]; + +bayo_e = [-bayo_p[0], bayo_p[1]] - [rivet_entry_width,0]; +bayo_d = [-bayo_a[0], bayo_a[1]] - [rivet_entry_width,0]; +bayo_c = bayo_d + [0,-5]; +bayo_b = bayo_a + [0,-5]; + +bayo_f = [ bayo_e[0], bayo_g[1] + (bayo_e[0] - bayo_g[0]) ]; + +bayo_polygon = [ bayo_a, + bayo_b, + bayo_c, + bayo_d, + bayo_e, + bayo_f, + bayo_g, + bayo_h, + bayo_i, + bayo_j, + bayo_k, + bayo_l, + bayo_m, + bayo_n, + bayo_p ]; + +echo(bayo_polygon); + +// CATCH + +cppxC = 0.41 * sm_inner_rad * TAU; + +// catch pin + +cpp_adj = (bayo_n[0] - bayo_f[0]) * (1 - sm_inner_rad / bayo_nom_rad); +// radius scaling due to nom and actual radius difference in +// bayo entry construction + +cppa = bayo_f + [1,-1] * catch_pin_slop + [1,0] * cpp_adj; +cppb = bayo_g + [1,-1] * catch_pin_slop + [1,0] * cpp_adj; +cppd = [ bayo_n[0] + - catch_pin_slop - catch_pin_slop_x_extra, + -catch_stalk_above_gap ]; +cppi = [ cppa[0], cppd[1] ]; +cppc = [ cppd[0], cppb[1] ]; +cpph = cppd + [0,-1] * catch_stalk_h; +cppe = cppd + [0,-1] * (catch_knob_above_gap + catch_knob_dia/2); +cppf = [ cppa[0], cppe[1] ]; +cppg = [ cppa[0], cpph[1] ]; +cppB = 0.5 * (cppf + cppe); + +echo("RR", sm_inner_rad / bayo_nom_rad); + +// catch assembly depression below pin + +cppy6 = cppB[1] - (catch_knob_dia/2 + + (cppc[1] - cppd[1]) + + catch_stalk_below_gap); +cpp7 = [ cppB[0], cppy6 + catch_cr ]; +cpp11 = cpp7 + [1,0] * catch_cr; +cppy9 = cppy6 + catch_strap_width * 1/3; +cpp9 = [ cpp7[0] + catch_cr * 2, cppy9 ]; +cpp8 = cpp9 + [0,-1] * catch_cr; +cpp10 = cpp8 + [-1,0] * catch_cr; +cppC = [ cppxC, cpp9[1] ]; +cppD = cppC + [0,-1] * catch_strap_width; + +// catch assembly stalk and so on + +catch_cr3 = catch_cr + catch_stalk_h; + +cppF = [ cppg[0] - catch_stalk_eff_bend_rad, cppd[1] ]; +cpp4 = [ cppg[0] - catch_stalk_len, cpph[1] ] + [1,-1] * catch_cr; +cpp5 = [ cpp4[0], cppC[1] + catch_cr ]; +cpp2 = cpp5 + [-1,0] * (catch_cr * 2 + catch_stalk_base_width); +cpp2r = cpp2 + [1,0] * catch_cr; +cpp2d = cpp2 + [0,-1] * catch_cr; +cpp3 = [ cpp2[0] + catch_cr + catch_cr3, cppd[1] - catch_cr3 ]; +cppA = [ -cppxC, cpp9[1] ]; +cppE = [ cppA[0], cppD[1] ]; + +catch_assembly_dy = -cppy9 + catch_strap_width; + + +module MainProfile(){ + main_cnr_pos = [ side_thick, top_z ] - [1,1]*main_cnr; + difference(){ + union(){ + translate(main_cnr_pos){ + intersection(){ + difference(){ + circle(r = main_cnr); + circle(r = main_cnr * 0.5); + } + square([10,10]); + } + } + polygon([[ -top_middle_dr, middle_bot_z ], + [ -top_middle_dr, top_z ], + [ main_cnr_pos[0], top_z ], + [ side_thick, main_cnr_pos[1] ], + [ side_thick, -side_height ], + [ side_taper, -side_height ], + [ 0, -rivet_posn ], + [ 0, by_oring_z ], + [ -oring_x_rad, by_oring_z ], + ], + convexity=10); + } + translate([ oring_mid_dia/2 - main_dia/2, 0 ]) + hull(){ + translate([ 0, oring_y_rad ]) + scale([ 1/oring_oblate * (oring_compress_more+1) , oring_oblate ]) + circle(oring_thick/2); + translate([ 0, oring_y_rad*2 - oring_thick/2 ]) + circle(oring_thick/2); + } + } +} + +module StrapLoopProfile(){ + circle(r = strap_loop_thick/2); +} + +module StrapLoop(){ ////toplevel + bigrad = strap_loop_inside/2 + strap_loop_thick/2; + extralen = strap_loop_thick * 5; + + intersection(){ + rotate([strap_loop_elevation, 0,0]){ + for (x= [ -1, +1 ] * bigrad) { + translate([x, -extralen, 0]) + rotate([-90,0,0]) + linear_extrude(height= extralen + strap_loop_strlen + 0.1, + convexity=10) + StrapLoopProfile(); + } + translate([0, strap_loop_strlen, 0]){ + intersection(){ + rotate_extrude(convexity=10) + translate([bigrad, 0,0]) + StrapLoopProfile(); + translate([0,50,0]) + cube([100,100,100], center=true); + } + } + } + translate([0, 50, 0]) + cube(100, center=true); + } +} + +module RotateProjectSlice(offset, slice_size, nom_rad, real_rad){ + // nom_rad > real_rad + rotate([0,0, atan2(offset, nom_rad) ]){ + intersection(){ + translate([-offset, -10, 0]) + rotate([90,0,0]) + linear_extrude(height= nom_rad*2, convexity=50) + children(0); + translate([0,0, -25]) + cylinder(h=50, r= real_rad); + translate([0,0, -25]) + linear_extrude(height= 50, convexity=50) + polygon([ [ 0,0 ], + [ -slice_size, -real_rad*2 ], + [ +slice_size, -real_rad*2 ] ]); + } + } +} + +module RotateProject(x_min, x_max, slice_size, nom_rad, real_rad){ + offs = [ for (i=[ x_min : + slice_size : + x_max + slice_size ]) i ]; + echo (offs); + for (off=offs) + RotateProjectSlice(off, slice_size, nom_rad, real_rad) + children(0); +} + +module BayonetCutout(){ + RotateProject(bayo_c[0], bayo_i[0], bayo_slice_size, + bayo_nom_rad, + bayo_real_rad) + translate([-0.5 * (bayo_a[0] + bayo_d[0]), 0]) + polygon(bayo_polygon, convexity=10); +} + +module ProfilesDemo(){ ////toplevel + translate([-10,0]) MainProfile(); + translate([+10, -side_height]) polygon(bayo_polygon, convexity=10); +} + +module LimitForHandling(){ ////toplevel + hull() for (r=[0,180]) + rotate([0,0,r]) { + for (rs=[-1,+1]) { + for (xd=[0,1]) { + rotate([0,0, rs * handling_angle/2]) { + translate([rs * xd * main_dia/2 * tan(handling_angle/2), + main_dia/2 + side_thick - main_cnr, + top_z - main_cnr]) { + mirror([0,0,1]) + cylinder(r= main_cnr, h=50); + sphere(main_cnr); + } + } + } + } + } + hull() rotate_extrude(convexity=10){ + translate([ handling_dia/2 - main_cnr, top_z - main_cnr ]) { + circle(r = main_cnr); + mirror([0,1]) square([ main_cnr, 50 ]); + } + } + //cylinder(r= handling_dia/2, h=20); +} + +module Cover(){ ////toplevel + render() difference(){ + intersection(){ + union(){ + rotate_extrude(convexity=10) + translate([main_dia/2, 0]) + MainProfile(); + translate([0,0, middle_bot_z]) + cylinder(h= top_thick_middle, r = main_dia/2 - top_middle_dr + 1); + } + LimitForHandling(); + } + for (r=[0,180]){ + rotate([0,0, r]) + translate([0,0, -side_height]) + BayonetCutout(); + rotate([0,0, r + asin((-oring_rm_beside) / (main_dia/2))]) + translate([0, + oring_mid_dia/2 + oring_thick/4 * oring_rm_scale, + oring_y_rad * 1.5]) + rotate([-oring_rm_angle, 0, 0]) + mirror([0,0,1]) + cylinder(r = oring_thick/4 * oring_rm_scale, h=20); + } + for (r=[0 : 60 : 179]) { + rotate([0,0, r]) { + height = top_thick_middle - brace_above_below*2; + translate([0,0, middle_bot_z + brace_above_below + height/2 ]) + cube(center=true, [ oring_bore - brace_end_shorter, + brace_hole_width, height ]); + } + } + } + if (enable_head_cups) + for (r=[0,180]) + rotate([0,0,r]) + translate([-implheadcup_large_dia * .5 - implheadcup_thick/2, + -implheadcup_large_dia * .0, + middle_bot_z + 0.1]) + ImplHeadCup(); + +// translate(strap_loop_thick * [-0.5, 0, +1]) +// translate([handling_dia/2, 0, -side_height]) +// rotate([0,180,0]) rotate([0,0,90]) +// StrapLoop(); +} + +module SavingHole(){ + translate([0,0, -10]) + cylinder(r= main_dia/2 - jig_rim, h=20); +} + +module Jig(){ ////toplevel + difference(){ + union(){ + translate([0,0, -side_height]){ + cylinder(r= main_dia/2 + jig_thick, h= side_height + jig_thick); + } + translate([-jig_mark_rad, 0, jig_thick - jig_mark]) + cube([jig_mark_rad*2, jig_mark, jig_mark]); + } + translate([0,0, -side_height-1]) + cylinder(r= main_dia/2, h= side_height + 1); + SavingHole(); + translate([0,0, -rivet_posn]) + rotate([90, 0,0]) + translate([0,0, -100]) + cylinder(r= jig_hole_dia/2, h = 200); + } +} + +module CoverPrint(){ ////toplevel + rotate([0,180,0]) Cover(); +} + +module CoverTest2(){ ////toplevel + difference(){ + Cover(); + SavingHole(); + } +} + +module CoverTest1(){ ////toplevel + difference(){ + CoverTest2(); + difference(){ + for (r= [ 40, 147 ]){ + rotate([0,0, r]){ + translate([0,0, -10]) { + cube([ main_dia*3, main_dia * .53, 18], center=true); + } + } + } +// translate([ 50, 0, 0 ]) +// cube([ 100, +// strap_loop_inside + strap_loop_thick*2 + 1, +// 100 ], +// center=true); + } + } +} + +module ImplHeadCupTest(){ ////toplevel + for (r=[0,180]) + rotate([0,0,r]) + translate([-17,0,0]) + ImplHeadCup(); +} + +module SomeStrap(width, cut_width=0){ + // children(0) is to add, (1) subtract + difference(){ + union(){ + cylinder(r=sm_outer_rad, h=width); + StrapMountProtrusion(smc_cnr_c_x + sm_closure_cnr, + smc_max_y, + sm_closure_cnr, + width); + children(0); + } + translate([0,0,-1]) + cylinder(r=sm_inner_rad, h=max(width+2, cut_width)); + translate(smc_pos) + StrapMountBolt(5, width); + translate(smc_pos) + cube([ sm_bolt_tighten_allow, 40,100 ], center=true); + children(1); + } +} + +module StrapMountBolt(l_delta, strap_width){ ///toplevel + // positioned relative to smc_pos + translate([(smc_bolt_nut_eff_thick - sm_bolt_head_thick)/2, + smc_bolt_y, + strap_width/2]){ + translate([ -sm_bolt_shaft/2-1, 0,0 ]){ + rotate([0,90,0]) cylinder(r= sm_bolt_dia/2, h= sm_bolt_shaft+2); + } + translate([ -sm_bolt_shaft/2, 0,0 ]) + rotate([0,-90,0]) + cylinder($fn=6, r=smc_bolt_nut_dia/2, + h=smc_bolt_nut_eff_thick + l_delta); + translate([ sm_bolt_shaft/2, 0,0 ]) + rotate([0,90,0]) + cylinder(r=sm_bolt_head_dia/2, h=sm_bolt_head_thick + l_delta); + } +} + +module StrapMountProtrusion(half_x, max_y, cnr, width){ + translate(smc_pos){ + linear_extrude(height=width, convexity=10){ + hull(){ + for (m = [0,1]) mirror([m,0,0]) { + translate([-(half_x - cnr), max_y - cnr]) + circle(r=cnr); + translate([-half_x, -sm_inner_rad]) + square([1,1]); + } + } + } + } +} + +module StrapMount(){ ////toplevel + SomeStrap(sm_main_width){ + rotate([0,0,180]){ + StrapMountProtrusion(strap_loop_inside/2 + strap_loop_thick, + strap_loop_thick, + sm_closure_cnr, + sm_main_width); + translate(smc_pos + + [0,0, sm_main_width] + + strap_loop_thick * [ 0, 0.5, -1.0 ]) + StrapLoop(); + } + union(){ }; + } +} + +module WallScrewHoleSlot(){ ////toplevel + ds = [-1,+1] * wm_screw_slot/2; + linextr_x_yz(-(wm_thick + 1), 1) { + hull(){ + for (d = ds) + translate([d, 0]) + circle(r = wm_screw_dia/2); + } + } + hull(){ + for (d = ds){ + translate([0, d, 0]){ + linextr_x_yz(0, 1) + circle(r = wm_screw_head/2); + linextr_x_yz(-(wm_screw_head - wm_screw_dia)/2, 0) + circle(r = wm_screw_dia/2); + } + } + } +} + +module WallMountMounts(){ + linextr(0, wm_z_max){ + translate([ -sm_outer_rad, 0 ]) + rectfromto([ 0, wm_lhs_y_min ], + [ wm_thick, wm_y_slot1_max ]); + } +} +module WallMountScrewHoles(){ + translate([ -sm_outer_rad + wm_thick, 0, wm_z_slotc_screw ]) { + translate([ 0, wm_y_slotc_screw, 0 ]) + WallScrewHoleSlot(); + translate([ 0, -wm_y_slotc_screw, 0 ]) + rotate([90,0,0]) + WallScrewHoleSlot(); + } +} + +module WallMount(){ ////toplevel + SomeStrap(sm_main_width, wm_z_max + 2){ + WallMountMounts(); + WallMountScrewHoles(); + } +} + +module WallMountBaseRingCut(){ + circle(r = wmb_mount_cut_rad); +} + +module WallMountBaseMounts(){ + linextr(0, wmb_z_max) { + difference(){ + rectfromto([ -sm_outer_rad, -wmb_y_mount_max ], + [ wmb_x_outer, +wmb_y_mount_max ]); + WallMountBaseRingCut(); + } + } +} + +// screws, nuts, slots for nuts to go down into +module WallMountBaseScrewsEtc(){ ////toplevel + for (my=[0,1]) { + mirror([0, my, 0]) { + translate([wmb_x_screw, 0, wmb_z_screw]) { + linextr_y_xz(wmb_y_screw_end, + wmb_y_screw_end + 50) + circle(r = wmb_screw_dia/2); + linextr_y_xz(wmb_y_screw_end + web_screw_len, + wmb_y_screw_end + 50) + circle(r = wmb_screw_head_dia/2); + linextr_y_xz(wmb_y_nut_min, + wmb_y_nut_min + wmb_nut_th) { + hull(){ + rotate(30) + circle(r = wmb_nut_rad, $fn = 6); + translate([0, 50]) + square(wmb_nut_across, center=true); + } + } + } + } + } +} + +module WallMountForBase(){ ////toplevel + SomeStrap(sm_main_width, wm_z_max + 2){ + union(){ + WallMountMounts(); + WallMountBaseMounts(); + } + union(){ + WallMountScrewHoles(); + WallMountBaseScrewsEtc(); + } + } +} + +module WallMountForBaseFixingsTest(){ ////toplevel + intersection(){ + WallMountForBase(); + linextr(-100,100) + rectfromto([ -sm_outer_rad-10, -wm_y_min ], + [ wmb_x_outer + 1, -100 ]); + } +} + +module WallMountBaseFixingsTest(){ ////toplevel + intersection(){ + WallMountBase(); + linextr(-2,100) + rectfromto([ -sm_outer_rad-10, -wm_y_min ], + [ wmbb_x_outer + 1, -100 ]); + } +} + +module WallMountBasePillarsPlan(){ + for (my = [0,1]) { + mirror([0, my]) { + rectfromto([ -sm_outer_rad, wmbb_y_max - wmb_mount_y_width ], + [ wmbb_x_outer, wmbb_y_max ]); + } + } +} + +// trim parts that are would foul the wall +module WallMountTrimWallFoulPlan(){ + translate([ -sm_outer_rad, 0]) + rectfromto([ -wmbb_r_top, -(wmbb_r_top + 1) ], + [ 0, +(wmbb_r_top + 1) ]); +} + +module WallMountBase(){ ////toplevel + difference(){ + union(){ + // vertical blocks rising to join to wall mount + linextr(wmbb_z_min, wmb_z_max) { + difference(){ + WallMountBasePillarsPlan(); + WallMountBaseRingCut(); + } + } + + hull(){ + linextr(wmbb_z_flat_whole_min, wmbb_z_flat_max) + circle(r = wmbb_r_top); + linextr(wmbb_z_min, wmbb_z_flat_max) + circle(r = wmbb_r_bottom); + } + linextr(wmbb_z_min, wmbb_z_flat_max) { + hull(){ + WallMountBasePillarsPlan(); + circle(r = wmbb_r_bottom); + } + } + } + + // cutaway for mount part + linextr(-wmb_mount_gap_z, wmb_z_max+1) { + for (my = [0,1]) { + mirror([0, my]) + rectfromto([ -sm_outer_rad-1, wmb_y_mount_max + wmb_mount_gap_xy ], + [ wmb_x_outer + wmb_mount_gap_xy, 1 ]); + } + } + + linextr(wmbb_z_min - 1, wmb_z_max + 1) + WallMountTrimWallFoulPlan(); + WallMountBaseScrewsEtc(); + } +} + +module WallMountBaseCutJigPlan(){ ////toplevel + difference(){ + union(){ + circle(r = wmbb_r_top); + } + + translate([ wmb_jig_around_gap, 0 ]) + WallMountTrimWallFoulPlan(); + + offset(delta = wmb_jig_around_gap) + WallMountBasePillarsPlan(); + } +} + +module WallMountBaseCutJig(){ ////toplevel + translate([ 0,0, wmbb_z_flat_max + 0.5 ]) + linextr(0, wmb_jig_th) + WallMountBaseCutJigPlan(); +} + +module WallMountForBaseDemo(){ ////toplevel + render() WallMountForBase(); + color("blue") render() WallMountBase(); + %WallMountBaseScrewsEtc(); + %WallMountBaseCutJig(); +} + +module CatchAssemblyCoreProfile(){ + difference(){ + union(){ + hull(){ + translate(cpp3) circle(r= catch_cr3); + polygon([ cpp3, + cpp2r, + cpp5, + cpph, + cppd + ]); + } + polygon([cppD, + cppC, + cpp9, + cpp10, + cpp11, + cpp4, + cpp2r, + cpp2d, + cppA, + cppE + ]); + translate(cpp8) circle(r= catch_cr); + } + hull(){ + translate(cpp4) circle(r= catch_cr); + translate(cpp5) circle(r= catch_cr); + translate(cpp7) circle(r= catch_cr); + polygon([cpp4, + cppg, + cpph, + cpp10, + cpp11, + ]); + } + translate(cpp2) circle(r= catch_cr); + } + // if cpp11 is above cpp10, the subtracted hull above + // can go down too far. Ensure we do not cut off below cppy6. + polygon([ cppE, + cppD, + cpp9, + [ cpp9[0], cppy6 ], + [ cpp7[0] - catch_cr, cppy6 ], + cpp2d + ]); +} + +module CatchTipProfile(dy){ + ddy = [0,dy]; + intersection(){ + translate(cppF){ + difference(){ +// circle(r = dist2d(cppF, cppd)); + //circle(r = dist2d(cppF, cppa)); + } + } + polygon([ cppa, + cppi + ddy, + cppd + ddy, + cppc, + cppb ]); + } +} + +module CatchHeadProfile(){ + polygon([ cppd, + cppd, + cppi, + cppf, + cppe, + cpph ]); +} + + +module CatchCore(){ /////toplevel + linear_extrude(height=catch_strap_thick, convexity=10) + CatchAssemblyCoreProfile(); + + hull(){ + linear_extrude(height=catch_head_th, convexity=10) + CatchTipProfile(0); + linear_extrude(height=catch_tip_th, convexity=10) + CatchTipProfile(catch_tip_th - catch_head_th); + } + + linear_extrude(height=catch_head_th, convexity=10) + CatchHeadProfile(); + + translate(concat(cppB,[0])) hull(){ + translate([0,0, catch_knob_height + catch_head_th - catch_knob_dia/2]) + sphere(r = catch_knob_dia/2); + cylinder(r = catch_knob_dia/2, h = 0.1); + } +} + +module CatchPreDistort(){ /////toplevel + scale(100 / sm_inner_rad) + rotate([90,0,0]) + CatchCore(); +} + +module CatchAssembly(){ /////toplevel + rotate([0,0, -(cppe[0] + cppB[0] + catch_pin_slop) / sm_inner_rad * 360/TAU]) + translate([0,0, catch_assembly_dy]) + scale(sm_inner_rad / 100) + import(str("poster-tube-lid,CatchPostDistort-fa", + (coarse ? 20 : 3), + ".stl"), + convexity=20); + + SomeStrap(catch_strap_width){ + union(){ } + union(){ + translate([-200, -200, -200]) + cube([400, 200, 400]); + } + } +} + +module CatchDemo(){ /////toplevel + color("blue") translate([0,0, + -catch_assembly_dy + ]) + CatchAssembly(); + translate([0,0,+side_height + ]) + Cover(); +} + +module CatchDemoS(){ /////toplevel + color("blue") translate([0,0, + -catch_assembly_dy + ]) + CatchAssembly(); + intersection(){ + translate([0,0,+side_height + ]) + Cover(); + mirror([0,1,0]) translate([-250,33,0]) cube([500,500,500]); + } + color("black") + translate([0,-33,0]) + cube([6.15, 2,2], center=true); +} + +module CatchPinProfileDemo(){ /////toplevel + translate([0, 0 * -bayo_behind,0]) { + echo("G ", + bayo_n[0] - bayo_e[0]); + color("blue") translate([0,0, + +1, + ]) { + CatchAssemblyCoreProfile(); + CatchHeadProfile(); + } + translate([0,0,10]) + color("red") + CatchTipProfile(0); + + polygon(bayo_polygon, convexity=10); + + // adhoc show a position + color("purple") + translate(concat( + cppa, + 10 + )) difference(){ circle(2.5); circle(2.0); } + + } +} + +//ProfilesDemo(); +//BayonetCutout(); +//MainProfile(); +//Cover(); +//Jig(); +//CoverTest(); diff --git a/powerbank-anker-10000.eps b/powerbank-anker-10000.eps new file mode 100644 index 0000000..01359d8 --- /dev/null +++ b/powerbank-anker-10000.eps @@ -0,0 +1,89 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: cairo 1.16.0 (https://cairographics.org) +%%CreationDate: Fri Feb 5 23:12:37 2021 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%BoundingBox: 149 274 598 1452 +%%EndComments +%%BeginProlog +50 dict begin +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +/cairo_data_source { + CairoDataIndex CairoData length lt + { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } + { () } ifelse +} def +/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def +/cairo_image { image cairo_flush_ascii85_file } def +/cairo_imagemask { imagemask cairo_flush_ascii85_file } def +%%EndProlog +%%BeginSetup +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%PageBoundingBox: 149 274 598 1452 +%%EndPageSetup +q 149 274 449 1178 rectclip +1 0 0 -1 0 1612 cm q +0 g +360.93 1337.57 m 298.676 1334.211 219.23 1335.672 183.594 1274.547 c 142.047 + 1187.812 152.582 1088.758 149.211 995.395 c 151.73 795.32 144.426 595.004 + 156.238 395.148 c 157.656 328.41 155.359 251.004 205.434 199.816 c 263.293 + 157.641 339.281 161.27 407.469 160.113 c 465.984 160.328 537.961 171.273 + 565.277 230.957 c 601.477 310.977 590.16 401.633 593.281 486.977 c 592.355 + 612.16 596.633 737.312 597.473 862.445 c 596.184 971.23 597.672 1080.117 + 595.984 1188.836 c 591.852 1244.773 555.328 1300.199 498.418 1313.117 c + 459.289 1331.371 416.695 1338.148 373.711 1336.93 c 367.316 1337.203 l +h +360.93 1337.57 m f +Q Q +showpage +%%Trailer +end +%%EOF diff --git a/powerbank-anker-10000.svg b/powerbank-anker-10000.svg new file mode 100644 index 0000000..5999a71 --- /dev/null +++ b/powerbank-anker-10000.svg @@ -0,0 +1,59 @@ + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/powerbank-bike-clamp.scad b/powerbank-bike-clamp.scad new file mode 100644 index 0000000..2a755a8 --- /dev/null +++ b/powerbank-bike-clamp.scad @@ -0,0 +1,431 @@ +// -*- C -*- + +// Print one of each: +// Main +// TubeClampRight + +include + +tube_dia = 22.4; + +hinge_around = 2.5; +hinge_pin = 1.8 + 0.75; +main_th = 3; +minor_wall_min = 1; + +screw = 5.0 + 0.75; +screw_head = 8.7 + 1.2; +screw_head_space_above = 10; +screw_nut_across = 7.9 + 0.75; +screw_nut_th = 3.9 + 0.75; + +knob_behind_across = 12.2 + 0.75; +behind_knob_th = 5; +knob_standout_h = 2; + +clamp_min_width = 20; + +clamp_gap = 2; + +corner_rounding_r = 10; + +lower_th = 1; + +overlap_l = 0.1; + +bridge_slop = 1.2; + +hinge_lobe_per = 10; +hinge_gap_z = 0.75; +hinge_gap_xy = 0.75; + +$fs = 0.1; +$fa = 5; + +bank_eps_bbox_x = [149, 598]; +bank_eps_bbox_y = [274, 1452]; + +bank_y_sz = 102.25 + 0.50 + 3.2; +bank_x_sz = (26.0 + 0.5); +bank_recess_y = 5; + +strap_th = 3; +strap_w = 5; +strap_above = 2.5; + +strap_around_over = 1.0; +strap_around_attach = 2.0; + +retainer_walls = [18, 30]; + +bank_profile_scale_bodge = 1.0; + +bank_output_ctr = [ 12.5, 11.5 ]; // from nearest corner +bank_output_sz = [ 11.0, 10.5 ]; + +mounted_pos_y_offset_lim = -100; + +liner_th = 0.8; + +brace_r = 5; +brace_len = 50; + +straps_y_adj = [ 3.5, + 0, + 0 ]; + +// calculated + +straps_y = [ -bank_y_sz * 0.25, // these entries are special and used + +bank_y_sz * 0.25, // for the brace struts + 0 ]; + +screw_head_behind = main_th; +endwall_th = main_th; + +bank_recess_dx = minor_wall_min; + +pspt_to_mm = 25.4 / 72; + +main_r = tube_dia/2 + main_th; + +screw_max_y_lhs = -main_r -screw_nut_across/2; +screw_max_y_rhs = -main_r -knob_behind_across/2; + +screw_y = min(screw_max_y_lhs, + screw_max_y_rhs); + +bot_y = screw_y -max( screw_nut_across/2, knob_behind_across/2 ) + -minor_wall_min; + +holder_x_sz = bank_x_sz + bank_recess_dx*2; +bank_bot_y = strap_above + strap_th; +strap_r = strap_th; + +brace_total_len = brace_len + main_th; +brace_ctrs_y_nom = [ straps_y[0] - (brace_r + strap_w/2), + straps_y[1] + (brace_r + strap_w/2) ]; + +brace_ctrs_y = [ (straps_y + straps_y_adj)[0] + (brace_r + strap_w/2), + (straps_y + straps_y_adj)[1] + (brace_r + strap_w/2) ]; + +clamp_width_actual = max(clamp_min_width, holder_x_sz); + +hinge_lobes = floor(clamp_width_actual / hinge_lobe_per); +hinge_stride = (clamp_width_actual + hinge_gap_z) / hinge_lobes; + +hinge_outer_r = hinge_around + hinge_pin/2; +hinge_y = tube_dia/2 + hinge_outer_r; + +top_cnr_r = min(endwall_th, main_th); + +mounted_pos_y_offset = max(mounted_pos_y_offset_lim, + bot_y - (-(bank_y_sz/2 + endwall_th))); + + +module TubePlan(){ circle(r = tube_dia/2); } +module HingePinPlan(){ translate([0, hinge_y]) circle(r= hinge_pin/2); } +module HingeBodyPlan(){ translate([0, hinge_y]) circle(r= hinge_outer_r); } + +module TubeClampLeftPlan(){ + difference(){ + union(){ + polygon([[ 0, hinge_y + hinge_outer_r ], + [ -(main_r + overlap_l), hinge_y + hinge_outer_r ], + [ -(main_r + overlap_l), bot_y ], + [ -clamp_gap/2, bot_y ], + [ -clamp_gap/2, 0, ], + [ 0, 0, ], + ]); + HingeBodyPlan(); + } + TubePlan(); + HingePinPlan(); + } +} + +module TubeClampLeft() { ////toplevel + linextr(-clamp_width_actual/2, clamp_width_actual/2) + TubeClampLeftPlan(); +} + +module TubeClampRightPlan(){ ////toplevel + difference(){ + // It broke at the inside corner, round these a bit + offset(r=-corner_rounding_r) + offset(r=+corner_rounding_r) + difference(){ + union(){ + rectfromto([ clamp_gap/2, bot_y ], + [ clamp_gap/2 + behind_knob_th, 0 ]); + intersection(){ + circle(r= main_r); // maybe split off from main_r and increase? + union(){ + rectfromto([0,0], + main_r * [5,5]); + rectfromto([ clamp_gap/2, main_r*5 ], + main_r * [2,-5]); + } + } + HingeBodyPlan(); + } + TubePlan(); + } + HingePinPlan(); + } +} + +module Screws(){ + linextr_x_yz(-main_r*5, main_r*5) + translate([screw_y, 0]) + circle(r= screw/2); + + translate([0, screw_y, 0]) { + linextr_x_yz(-(clamp_gap/2 + screw_nut_th), 0) + square([screw_nut_across, + screw_nut_across / cos(30) + bridge_slop*2], + center=true); + + linextr_x_yz(-(main_r + bank_recess_y + screw_head_space_above), + -(clamp_gap/2 + screw_nut_th + screw_head_behind)) + square([screw_head, screw_head + bridge_slop*2], + center=true); + } +} + +module SomeClamp(hinge_alt=false){ + difference(){ + linextr(-clamp_width_actual/2, clamp_width_actual/2) + children(0); + + Screws(); + + for (i=[0 : hinge_lobes-1]) { + translate([0, + hinge_y, + -clamp_width_actual/2 + i * hinge_stride + + (hinge_alt ? hinge_stride/2 : 0) + ]) + linextr(-hinge_gap_z, hinge_stride/2) + square(hinge_outer_r*2 + hinge_gap_xy, center=true); + } + } +} + +module PowerBankItselfSidePlan(){ + translate([0, bank_bot_y]){ + minkowski(){ + circle($fn=8, r=liner_th); + scale( bank_profile_scale_bodge * + bank_x_sz / ( ( + bank_eps_bbox_x[1] - + bank_eps_bbox_x[0] + ) * pspt_to_mm )) + translate(pspt_to_mm * + [-0.5 * (bank_eps_bbox_x[0] + + bank_eps_bbox_x[1]), + -bank_eps_bbox_y[0]]) + import("powerbank-anker-10000.dxf", convexity=5); + } + } +} + +module PowerBankItself(){ ////toplevel + rotate([0,90,0]) + linextr_y_xz(-bank_y_sz/2, + +bank_y_sz/2) + PowerBankItselfSidePlan(); +} + +module PowerBankSidePlan(){ ////toplevel + render() difference(){ + rectfromto([ -holder_x_sz/2, 0 ], + [ +holder_x_sz/2, bank_recess_y + bank_bot_y ]); + + PowerBankItselfSidePlan(); + } +} + +module PowerBankStrapCut(){ ////toplevel + difference(){ + rectfromto([ -holder_x_sz, -0.05 ], + [ +holder_x_sz, strap_th + strap_r ]); + hull(){ + for (sx=[-1,+1]) { + translate([sx * (holder_x_sz/2 - strap_r + 0.1), + strap_th + strap_r]) + circle(strap_r); + } + } + } +} + +module PowerBankHolderTest(){ ////toplevel + difference(){ + linextr(-1,5) PowerBankSidePlan(); + linextr(0, strap_w) PowerBankStrapCut(); + } +} + +module EndRetainer(depth){ ////toplevel + translate([0, -bank_y_sz/2, 0]) { + linextr_y_xz(-endwall_th, 0) + rectfromto([ 0, -holder_x_sz/2 ], + [ -depth, +holder_x_sz/2 ]); + + for (m=[0,1]) { + mirror([0,0,m]) { + linextr(-holder_x_sz/2, -bank_x_sz/2){ + hull(){ + rectfromto([ 0, -endwall_th ], + [ depth, 0 ]); + rectfromto([ 0, 0 ], + [ 0.1, depth-0.1 ]); + } + } + } + } + } +} + +module BraceTubePlan(){ + intersection(){ + circle(r= brace_r); + rectfromto(brace_r * [-2, 0], + brace_r * [+2, +2]); + } +} + +module PowerBankHolder(){ ////toplevel + difference(){ + union(){ + rotate([0,90,0]) + linextr_y_xz(-(bank_y_sz/2 + 0.1), + +(bank_y_sz/2 + 0.1)) + PowerBankSidePlan(); + + EndRetainer(retainer_walls[0]); + mirror([0,1,0]) EndRetainer(retainer_walls[1]); + + translate([0,0, bank_x_sz/2]){ + for (y = brace_ctrs_y) { + translate([0,y,0]) { + linextr_x_yz(0, brace_total_len) + BraceTubePlan(); + } + } + translate([brace_total_len, 0,0]) + linextr_y_xz(brace_ctrs_y_nom[0] - brace_r, + brace_ctrs_y_nom[1] + brace_r) + BraceTubePlan(); + } + + for (strap_y = straps_y + straps_y_adj) { + translate([0, strap_y, 0]) { + linextr(-holder_x_sz/2, + +holder_x_sz/2){ + hull(){ + for (dy = [-1,+1] * + (strap_w/2 + strap_around_attach - strap_around_over)) { + translate([0, dy, 0]) + circle(r=strap_around_over); + } + } + } + } + } + } + + for (strap_y = straps_y + straps_y_adj) + translate([0, strap_y, 0]) + rotate([0,0,-90]) + rotate([0,90,0]) + linextr(-strap_w/2, + +strap_w/2) + PowerBankStrapCut(); + + translate([ bank_bot_y, -bank_y_sz/2, -bank_x_sz/2 ]) + linextr_y_xz(-50,50) + rotate([0,0,90]) + translate(bank_output_ctr) + square(center=true, bank_output_sz); + + translate([0, -(bank_y_sz/2 + endwall_th), 0] + 0.01 * [-1,-1]) { + linextr(-200,200){ + difference(){ + square(center=true, top_cnr_r*2); + translate(top_cnr_r * [1,1]) + circle(r= top_cnr_r); + } + } + } + } +} + +module TubeClampLeft() { ////toplevel + // We want this to print with the recess overhand to the right + // where the workpiece cooling fan is + rotate([0,0,180]){ + difference(){ + SomeClamp(true) + TubeClampLeftPlan(); + + Screws(); + } + } +} + +module PlacePowerBank(){ + translate([main_r, -mounted_pos_y_offset, 0]) + children(0); +} + +module Main(){ ////toplevel + TubeClampLeft(); + difference(){ + PlacePowerBank() + PowerBankHolder(); + rotate([0,0,180]) + Screws(); + } +} + +module TubeClampRight() { ////toplevel + rotate([0,0,180]) { + rotate([180,0,0]) { + difference(){ + union(){ + SomeClamp() + TubeClampRightPlan(); + + translate([clamp_gap/2 + behind_knob_th, screw_y, 0]) { + hull(){ + linextr_x_yz(-0.1, 0) + square(center=true, + [knob_behind_across, + knob_behind_across + knob_standout_h*2]); + linextr_x_yz(0, knob_standout_h) + square(center=true, + knob_behind_across); + } + } + } + Screws(); + } + } + } +} + +module TubeClampDemo() { ////toplevel + TubeClampLeft(); + rotate([180,0,0]) + TubeClampRight(); +} + +module Demo() { ////toplevel + Main(); + rotate([180,0,0]) + TubeClampRight(); + PlacePowerBank() + %PowerBankItself(); +} diff --git a/pronsolerc b/pronsolerc new file mode 100644 index 0000000..3073286 --- /dev/null +++ b/pronsolerc @@ -0,0 +1,37 @@ +set port /dev/ttyUSB0 +set last_temperature 205.0 + +macro button_retract + M83 + G1 E-220 F2000 + M84 + +macro button_prefeed + M83 + G1 E220 F2000 + M84 + +button 3 "FAN ON" /c "#C8C8C8" M106 S200 +button 4 "GET POS" /c "#C8C8C8" M114 +button 5 "RETRACT" button_retract +button 6 "PREFEED" button_prefeed +button 7 "BL" G1 X135 Y15 F12000 +button 8 "CENTRE" G1 X70 Y70 F12000 +button 9 "BR" G1 X15 Y15 F12000 +button 10 "FL" G1 X135 Y135 F12000 +button 11 "UP" G1 Z6 F200 +button 12 "FR" G1 X15 Y135 F12000 +set last_bed_temperature 60.0 +set baudrate 115200 +set last_file_path /home/reprap/play +set xy_feedrate 3000 +set z_feedrate 200 +set e_feedrate 1500 + +set slicecommand /home/reprap/Slic3r/bin/slic3r $s --load /home/reprap/play/slic3r-config.ini --output $o + +set sliceoptscommand /home/reprap/Slic3r/bin/slic3r --load /home/reprap/play/slic3r-config.ini --ignore-nonexistent-config + +#set sliceoptscommand python xskeinforge/skeinforge_application/skeinforge.py +#set slicecommand python xskeinforge/skeinforge_application/skeinforge_utilities/skeinforge_craft.py $s +set build_dimensions 140x150x80+0+0+0 diff --git a/pull-cord-keeper.scad b/pull-cord-keeper.scad new file mode 100644 index 0000000..c8655c9 --- /dev/null +++ b/pull-cord-keeper.scad @@ -0,0 +1,189 @@ +// -*- C -*- + +hoopthick = 3; + +hinnerrad = 15; +houterrad = hinnerrad + hoopthick; +hcentredist = 10; + +blockdepth = 5; +blockwidth = hcentredist*2 + 6; + +height = 20; + +roundedgedia = 7.5; + +ziglen = hcentredist/2; + +feedxgap = 5; +feedzgap = 5; +ribsgap = 1; + +ribdepth = 3; +ribheight = 4; + +backxgap = 1; + +blockoverlapcnr = 5; + +screwholedia = 4 + 0.5; + +module Oval(centredist, rad) { + hull() { + translate([-centredist/2,0,0]) circle(r=rad); + translate([+centredist/2,0,0]) circle(r=rad); + } +} + +module VExtrude(){ + translate([0,0, -height/2]) + linear_extrude(height=20) + children(0); +} + +module OuterOval(){ + Oval(hcentredist, houterrad); +} + +module Hoop(){ + difference(){ + hull(){ + OuterOval(); + translate([0, (blockdepth + hoopthick)/2 + hinnerrad]) + square([blockwidth, + blockdepth + hoopthick], + center=true); + } + Oval(hcentredist, hinnerrad); + } +} + +module RoundEdges(){ + intersection(){ + VExtrude() + OuterOval(); + + for (xi=[-1,1]) { + hull(){ + for (yi=[-1,1]) { + translate([xi * (hcentredist/2 + hinnerrad), + houterrad, + yi * (height/2 - roundedgedia / 4 * sqrt(2))]) + rotate([90,0,0]) + cylinder(r=roundedgedia/2, h=houterrad*2, $fn=20); + } + } + } + } +} + +module Positive(){ + difference(){ + VExtrude() + Hoop(); + + rotate([90,0,0]) + translate([0,0,-50]) + cylinder(r=screwholedia/2, h=100); + } + + RoundEdges(); +} + +module Ribs(){ + imax = ceil(height*2 / ribheight); + for (i=[-imax:imax]) { + hull(){ + translate([-ribdepth/2, + ribheight*i, + 0]) + polygon([[0, 0], + [ribdepth, -ribheight], + [ribdepth, +ribheight]]); + translate([50, 0]) + square([1, height*2], center=true); + } + } +} + +module Division(cutmore) { + mirror([0,0,1]) { + translate([0, 0, -cutmore*feedzgap/2]) { + translate([-ziglen + -cutmore*feedxgap/2, -100, 0]) + cube([100, 100, 50]); + } + } + translate([blockwidth/2 - blockoverlapcnr + -cutmore*backxgap/2, + -1, + -50]) + cube([100, 100, 100]); + + translate([ziglen + -cutmore*feedxgap/2, + -50, + -50]) + cube([100, 51, 100]); + + translate([50, + hinnerrad/2 + houterrad/2 + blockdepth/2 + -cutmore*ribsgap/2, + 0]) + rotate([-90,0,90]) + linear_extrude(height=100) + Ribs(); +} + +module SDemo(){ + //difference(){ + % Positive(); + // Division(0); + //} + Division(-1); +} + +module A(){ + difference(){ + Positive(); + Division(+1); + } +} + +module B(){ + intersection(){ + Positive(); + Division(-1); + } +} + +module Demo(){ + color("red") A(); + color("blue") B(); +} + +module APrint(){ ////toplevel + rotate([0,180,0]) + A(); +} + +module BPrint(){ ////toplevel + B(); +} + +module Kit(){ ////toplevel + translate([0, hinnerrad, 0]) + APrint(); + rotate([0,0,180]) + BPrint(); +} + +//Ribs(); +//Demo(); + +//A(); +//B(); +//%Division(+1); + +//Hoop(); + +//Demo(); +//BPrint(); + +//Kit(); diff --git a/quacks-ingredients-L1.scad b/quacks-ingredients-L1.scad new file mode 100644 index 0000000..5a85e58 --- /dev/null +++ b/quacks-ingredients-L1.scad @@ -0,0 +1,5 @@ +// autogenerated by quacks-ingredients-updates-levels - do not edit +$phase=1; +module Token_L(){ Token_L1(); } +//// toplevels-from: +include diff --git a/quacks-ingredients-L2.scad b/quacks-ingredients-L2.scad new file mode 100644 index 0000000..6c7a087 --- /dev/null +++ b/quacks-ingredients-L2.scad @@ -0,0 +1,5 @@ +// autogenerated by quacks-ingredients-updates-levels - do not edit +$phase=2; +module Token_L(){ Token_L2(); } +//// toplevels-from: +include diff --git a/quacks-ingredients-L3.scad b/quacks-ingredients-L3.scad new file mode 100644 index 0000000..b39277d --- /dev/null +++ b/quacks-ingredients-L3.scad @@ -0,0 +1,5 @@ +// autogenerated by quacks-ingredients-updates-levels - do not edit +$phase=3; +module Token_L(){ Token_L3(); } +//// toplevels-from: +include diff --git a/quacks-ingredients-L4.scad b/quacks-ingredients-L4.scad new file mode 100644 index 0000000..9f86e2a --- /dev/null +++ b/quacks-ingredients-L4.scad @@ -0,0 +1,5 @@ +// autogenerated by quacks-ingredients-updates-levels - do not edit +$phase=4; +module Token_L(){ Token_L4(); } +//// toplevels-from: +include diff --git a/quacks-ingredients-L5.scad b/quacks-ingredients-L5.scad new file mode 100644 index 0000000..2f35fd3 --- /dev/null +++ b/quacks-ingredients-L5.scad @@ -0,0 +1,5 @@ +// autogenerated by quacks-ingredients-updates-levels - do not edit +$phase=5; +module Token_L(){ Token_L5(); } +//// toplevels-from: +include diff --git a/quacks-ingredients-counts b/quacks-ingredients-counts new file mode 100755 index 0000000..5377cbc --- /dev/null +++ b/quacks-ingredients-counts @@ -0,0 +1,111 @@ +#!/usr/bin/perl -w + +use strict; + +use Data::Dumper; +use POSIX; + +our $which = shift @ARGV; + +sub xdata ($) { + my ($cb) = @_; + return unless $which eq 'Base'; + foreach my $count (qw(1 2 3)) { + foreach my $nspots (qw(0 1 2 3 4)) { + $_ = $cb->($count,$nspots)."\t".$_; + } + } +} + +$_=; chomp or die; +xdata sub { + my ($xcount,$xnspots) = @_; + "${xcount}x". (qw(Zero One Two Three Four)[$xnspots]); +}; +our @names = split /\t/, $_; + +our %count; + +foreach my $nspots (qw(1 2 3 4 0)) { + $_=; chomp or die; + xdata sub { + my ($xcount,$xnspots) = @_; + $xnspots == $nspots and "$xcount+0"; + }; + my @l = split /\t/, $_; + foreach my $i (0..$#names) { + $_ = $l[$i] || '0+0'; + $_ ||= 0; + m/\+/ or die "$which $nspots ?"; + + $count{$names[$i]}{$nspots} = + $which eq 'All' ? $` + $' : + $which eq 'Base' ? $` : + $which eq 'Witches' ? $' : + die "$which ?"; + } +} + +$_ = Dumper(\%count); +s{^}{// }mg; +#print STDERR; + +our $name; +our $total_count; +our $total_real_count; +our $max_nrows=0; +our $max_rowsz=0; + +sub wrtoplevel () { + my $cs = $count{$name}; + my $total = 0; $total += $_ foreach values %$cs; + return unless $total; + print "module ${which}_$name(){ ////toplevel\n"; + my $rowsz = ceil(sqrt($total)); + my $nrows = ceil($total / $rowsz); + $total_count += $total; + $total_real_count += $total if $name =~ m/^[A-Z][a-z]+$/; + $max_nrows = $nrows if $nrows > $max_nrows; + $max_rowsz = $rowsz if $rowsz > $max_rowsz; + my $ix = 0; + printf "// %s %-10s total=%2d rowsz=$rowsz nrows=$nrows\n", + $which, "$name", $total; + foreach my $nspots (sort keys %$cs) { + my $c = $cs->{$nspots}; + print <error and die $!; + +__DATA__ +White Green Blue Red Yellow Purple Black Orange Orange6 Loco WhiteSpare +21+6 15+10 14+8 12+6 13+6 15+8 18+8 20+12 1+0 +9+3 10+5 10+5 8+5 6+5 1+0 +5+2 1+0 + 13+5 10+5 10+5 10+5 + 0+20 0+25 diff --git a/quacks-ingredients-counts.scad b/quacks-ingredients-counts.scad new file mode 100644 index 0000000..c2a8d08 --- /dev/null +++ b/quacks-ingredients-counts.scad @@ -0,0 +1,1826 @@ +// autogenerated - do not edit +// update script is quacks-ingredients-updates-levels +// source is quacks-ingredients-counts +module Base_1xFour(){ ////toplevel +// Base 1xFour total= 1 rowsz=1 nrows=1 + union(){ + Frame($phase, token_pitch * [ 1 + 1.00, 1 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 1 + 1.00, 1 + 0.50 ]); + $nspots = 1; + }; + union(){ + Frame($phase, token_pitch * [ 1 + 1.00, 1 + 0.50 ]); + $nspots = 2; + }; + union(){ + Frame($phase, token_pitch * [ 1 + 1.00, 1 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 1 + 1.00, 1 + 0.50 ]); + $nspots = 4; + translate(token_pitch * [ 0.0, 0.0 ]) Token_L(); + }; +} +module Base_1xOne(){ ////toplevel +// Base 1xOne total= 1 rowsz=1 nrows=1 + union(){ + Frame($phase, token_pitch * [ 1 + 1.00, 1 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 1 + 1.00, 1 + 0.50 ]); + $nspots = 1; + translate(token_pitch * [ 0.0, 0.0 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 1 + 1.00, 1 + 0.50 ]); + $nspots = 2; + }; + union(){ + Frame($phase, token_pitch * [ 1 + 1.00, 1 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 1 + 1.00, 1 + 0.50 ]); + $nspots = 4; + }; +} +module Base_1xThree(){ ////toplevel +// Base 1xThree total= 1 rowsz=1 nrows=1 + union(){ + Frame($phase, token_pitch * [ 1 + 1.00, 1 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 1 + 1.00, 1 + 0.50 ]); + $nspots = 1; + }; + union(){ + Frame($phase, token_pitch * [ 1 + 1.00, 1 + 0.50 ]); + $nspots = 2; + }; + union(){ + Frame($phase, token_pitch * [ 1 + 1.00, 1 + 0.50 ]); + $nspots = 3; + translate(token_pitch * [ 0.0, 0.0 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 1 + 1.00, 1 + 0.50 ]); + $nspots = 4; + }; +} +module Base_1xTwo(){ ////toplevel +// Base 1xTwo total= 1 rowsz=1 nrows=1 + union(){ + Frame($phase, token_pitch * [ 1 + 1.00, 1 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 1 + 1.00, 1 + 0.50 ]); + $nspots = 1; + }; + union(){ + Frame($phase, token_pitch * [ 1 + 1.00, 1 + 0.50 ]); + $nspots = 2; + translate(token_pitch * [ 0.0, 0.0 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 1 + 1.00, 1 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 1 + 1.00, 1 + 0.50 ]); + $nspots = 4; + }; +} +module Base_1xZero(){ ////toplevel +// Base 1xZero total= 1 rowsz=1 nrows=1 + union(){ + Frame($phase, token_pitch * [ 1 + 1.00, 1 + 0.50 ]); + $nspots = 0; + translate(token_pitch * [ 0.0, 0.0 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 1 + 1.00, 1 + 0.50 ]); + $nspots = 1; + }; + union(){ + Frame($phase, token_pitch * [ 1 + 1.00, 1 + 0.50 ]); + $nspots = 2; + }; + union(){ + Frame($phase, token_pitch * [ 1 + 1.00, 1 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 1 + 1.00, 1 + 0.50 ]); + $nspots = 4; + }; +} +module Base_2xFour(){ ////toplevel +// Base 2xFour total= 2 rowsz=2 nrows=1 + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 1 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 1 + 0.50 ]); + $nspots = 1; + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 1 + 0.50 ]); + $nspots = 2; + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 1 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 1 + 0.50 ]); + $nspots = 4; + translate(token_pitch * [ -0.5, 0.0 ]) Token_L(); + translate(token_pitch * [ 0.5, 0.0 ]) Token_L(); + }; +} +module Base_2xOne(){ ////toplevel +// Base 2xOne total= 2 rowsz=2 nrows=1 + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 1 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 1 + 0.50 ]); + $nspots = 1; + translate(token_pitch * [ -0.5, 0.0 ]) Token_L(); + translate(token_pitch * [ 0.5, 0.0 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 1 + 0.50 ]); + $nspots = 2; + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 1 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 1 + 0.50 ]); + $nspots = 4; + }; +} +module Base_2xThree(){ ////toplevel +// Base 2xThree total= 2 rowsz=2 nrows=1 + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 1 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 1 + 0.50 ]); + $nspots = 1; + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 1 + 0.50 ]); + $nspots = 2; + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 1 + 0.50 ]); + $nspots = 3; + translate(token_pitch * [ -0.5, 0.0 ]) Token_L(); + translate(token_pitch * [ 0.5, 0.0 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 1 + 0.50 ]); + $nspots = 4; + }; +} +module Base_2xTwo(){ ////toplevel +// Base 2xTwo total= 2 rowsz=2 nrows=1 + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 1 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 1 + 0.50 ]); + $nspots = 1; + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 1 + 0.50 ]); + $nspots = 2; + translate(token_pitch * [ -0.5, 0.0 ]) Token_L(); + translate(token_pitch * [ 0.5, 0.0 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 1 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 1 + 0.50 ]); + $nspots = 4; + }; +} +module Base_2xZero(){ ////toplevel +// Base 2xZero total= 2 rowsz=2 nrows=1 + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 1 + 0.50 ]); + $nspots = 0; + translate(token_pitch * [ -0.5, 0.0 ]) Token_L(); + translate(token_pitch * [ 0.5, 0.0 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 1 + 0.50 ]); + $nspots = 1; + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 1 + 0.50 ]); + $nspots = 2; + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 1 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 1 + 0.50 ]); + $nspots = 4; + }; +} +module Base_3xFour(){ ////toplevel +// Base 3xFour total= 3 rowsz=2 nrows=2 + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 2 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 2 + 0.50 ]); + $nspots = 1; + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 2 + 0.50 ]); + $nspots = 2; + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 2 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 2 + 0.50 ]); + $nspots = 4; + translate(token_pitch * [ -0.5, -0.5 ]) Token_L(); + translate(token_pitch * [ -0.5, 0.5 ]) Token_L(); + translate(token_pitch * [ 0.5, -0.5 ]) Token_L(); + }; +} +module Base_3xOne(){ ////toplevel +// Base 3xOne total= 3 rowsz=2 nrows=2 + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 2 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 2 + 0.50 ]); + $nspots = 1; + translate(token_pitch * [ -0.5, -0.5 ]) Token_L(); + translate(token_pitch * [ -0.5, 0.5 ]) Token_L(); + translate(token_pitch * [ 0.5, -0.5 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 2 + 0.50 ]); + $nspots = 2; + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 2 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 2 + 0.50 ]); + $nspots = 4; + }; +} +module Base_3xThree(){ ////toplevel +// Base 3xThree total= 3 rowsz=2 nrows=2 + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 2 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 2 + 0.50 ]); + $nspots = 1; + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 2 + 0.50 ]); + $nspots = 2; + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 2 + 0.50 ]); + $nspots = 3; + translate(token_pitch * [ -0.5, -0.5 ]) Token_L(); + translate(token_pitch * [ -0.5, 0.5 ]) Token_L(); + translate(token_pitch * [ 0.5, -0.5 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 2 + 0.50 ]); + $nspots = 4; + }; +} +module Base_3xTwo(){ ////toplevel +// Base 3xTwo total= 3 rowsz=2 nrows=2 + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 2 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 2 + 0.50 ]); + $nspots = 1; + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 2 + 0.50 ]); + $nspots = 2; + translate(token_pitch * [ -0.5, -0.5 ]) Token_L(); + translate(token_pitch * [ -0.5, 0.5 ]) Token_L(); + translate(token_pitch * [ 0.5, -0.5 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 2 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 2 + 0.50 ]); + $nspots = 4; + }; +} +module Base_3xZero(){ ////toplevel +// Base 3xZero total= 3 rowsz=2 nrows=2 + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 2 + 0.50 ]); + $nspots = 0; + translate(token_pitch * [ -0.5, -0.5 ]) Token_L(); + translate(token_pitch * [ -0.5, 0.5 ]) Token_L(); + translate(token_pitch * [ 0.5, -0.5 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 2 + 0.50 ]); + $nspots = 1; + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 2 + 0.50 ]); + $nspots = 2; + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 2 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 2 + 0.50 ]); + $nspots = 4; + }; +} +module Base_Black(){ ////toplevel +// Base Black total=18 rowsz=5 nrows=4 + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 4 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 4 + 0.50 ]); + $nspots = 1; + translate(token_pitch * [ -2.0, -1.5 ]) Token_L(); + translate(token_pitch * [ -2.0, -0.5 ]) Token_L(); + translate(token_pitch * [ -2.0, 0.5 ]) Token_L(); + translate(token_pitch * [ -2.0, 1.5 ]) Token_L(); + translate(token_pitch * [ -1.0, -1.5 ]) Token_L(); + translate(token_pitch * [ -1.0, -0.5 ]) Token_L(); + translate(token_pitch * [ -1.0, 0.5 ]) Token_L(); + translate(token_pitch * [ -1.0, 1.5 ]) Token_L(); + translate(token_pitch * [ 0.0, -1.5 ]) Token_L(); + translate(token_pitch * [ 0.0, -0.5 ]) Token_L(); + translate(token_pitch * [ 0.0, 0.5 ]) Token_L(); + translate(token_pitch * [ 0.0, 1.5 ]) Token_L(); + translate(token_pitch * [ 1.0, -1.5 ]) Token_L(); + translate(token_pitch * [ 1.0, -0.5 ]) Token_L(); + translate(token_pitch * [ 1.0, 0.5 ]) Token_L(); + translate(token_pitch * [ 1.0, 1.5 ]) Token_L(); + translate(token_pitch * [ 2.0, -1.5 ]) Token_L(); + translate(token_pitch * [ 2.0, -0.5 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 4 + 0.50 ]); + $nspots = 2; + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 4 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 4 + 0.50 ]); + $nspots = 4; + }; +} +module Base_Blue(){ ////toplevel +// Base Blue total=34 rowsz=6 nrows=6 + union(){ + Frame($phase, token_pitch * [ 6 + 1.00, 6 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 6 + 1.00, 6 + 0.50 ]); + $nspots = 1; + translate(token_pitch * [ -2.5, -2.5 ]) Token_L(); + translate(token_pitch * [ -2.5, -1.5 ]) Token_L(); + translate(token_pitch * [ -2.5, -0.5 ]) Token_L(); + translate(token_pitch * [ -2.5, 0.5 ]) Token_L(); + translate(token_pitch * [ -2.5, 1.5 ]) Token_L(); + translate(token_pitch * [ -2.5, 2.5 ]) Token_L(); + translate(token_pitch * [ -1.5, -2.5 ]) Token_L(); + translate(token_pitch * [ -1.5, -1.5 ]) Token_L(); + translate(token_pitch * [ -1.5, -0.5 ]) Token_L(); + translate(token_pitch * [ -1.5, 0.5 ]) Token_L(); + translate(token_pitch * [ -1.5, 1.5 ]) Token_L(); + translate(token_pitch * [ -1.5, 2.5 ]) Token_L(); + translate(token_pitch * [ -0.5, -2.5 ]) Token_L(); + translate(token_pitch * [ -0.5, -1.5 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 6 + 1.00, 6 + 0.50 ]); + $nspots = 2; + translate(token_pitch * [ -0.5, -0.5 ]) Token_L(); + translate(token_pitch * [ -0.5, 0.5 ]) Token_L(); + translate(token_pitch * [ -0.5, 1.5 ]) Token_L(); + translate(token_pitch * [ -0.5, 2.5 ]) Token_L(); + translate(token_pitch * [ 0.5, -2.5 ]) Token_L(); + translate(token_pitch * [ 0.5, -1.5 ]) Token_L(); + translate(token_pitch * [ 0.5, -0.5 ]) Token_L(); + translate(token_pitch * [ 0.5, 0.5 ]) Token_L(); + translate(token_pitch * [ 0.5, 1.5 ]) Token_L(); + translate(token_pitch * [ 0.5, 2.5 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 6 + 1.00, 6 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 6 + 1.00, 6 + 0.50 ]); + $nspots = 4; + translate(token_pitch * [ 1.5, -2.5 ]) Token_L(); + translate(token_pitch * [ 1.5, -1.5 ]) Token_L(); + translate(token_pitch * [ 1.5, -0.5 ]) Token_L(); + translate(token_pitch * [ 1.5, 0.5 ]) Token_L(); + translate(token_pitch * [ 1.5, 1.5 ]) Token_L(); + translate(token_pitch * [ 1.5, 2.5 ]) Token_L(); + translate(token_pitch * [ 2.5, -2.5 ]) Token_L(); + translate(token_pitch * [ 2.5, -1.5 ]) Token_L(); + translate(token_pitch * [ 2.5, -0.5 ]) Token_L(); + translate(token_pitch * [ 2.5, 0.5 ]) Token_L(); + }; +} +module Base_Green(){ ////toplevel +// Base Green total=38 rowsz=7 nrows=6 + union(){ + Frame($phase, token_pitch * [ 7 + 1.00, 6 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 7 + 1.00, 6 + 0.50 ]); + $nspots = 1; + translate(token_pitch * [ -3.0, -2.5 ]) Token_L(); + translate(token_pitch * [ -3.0, -1.5 ]) Token_L(); + translate(token_pitch * [ -3.0, -0.5 ]) Token_L(); + translate(token_pitch * [ -3.0, 0.5 ]) Token_L(); + translate(token_pitch * [ -3.0, 1.5 ]) Token_L(); + translate(token_pitch * [ -3.0, 2.5 ]) Token_L(); + translate(token_pitch * [ -2.0, -2.5 ]) Token_L(); + translate(token_pitch * [ -2.0, -1.5 ]) Token_L(); + translate(token_pitch * [ -2.0, -0.5 ]) Token_L(); + translate(token_pitch * [ -2.0, 0.5 ]) Token_L(); + translate(token_pitch * [ -2.0, 1.5 ]) Token_L(); + translate(token_pitch * [ -2.0, 2.5 ]) Token_L(); + translate(token_pitch * [ -1.0, -2.5 ]) Token_L(); + translate(token_pitch * [ -1.0, -1.5 ]) Token_L(); + translate(token_pitch * [ -1.0, -0.5 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 7 + 1.00, 6 + 0.50 ]); + $nspots = 2; + translate(token_pitch * [ -1.0, 0.5 ]) Token_L(); + translate(token_pitch * [ -1.0, 1.5 ]) Token_L(); + translate(token_pitch * [ -1.0, 2.5 ]) Token_L(); + translate(token_pitch * [ 0.0, -2.5 ]) Token_L(); + translate(token_pitch * [ 0.0, -1.5 ]) Token_L(); + translate(token_pitch * [ 0.0, -0.5 ]) Token_L(); + translate(token_pitch * [ 0.0, 0.5 ]) Token_L(); + translate(token_pitch * [ 0.0, 1.5 ]) Token_L(); + translate(token_pitch * [ 0.0, 2.5 ]) Token_L(); + translate(token_pitch * [ 1.0, -2.5 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 7 + 1.00, 6 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 7 + 1.00, 6 + 0.50 ]); + $nspots = 4; + translate(token_pitch * [ 1.0, -1.5 ]) Token_L(); + translate(token_pitch * [ 1.0, -0.5 ]) Token_L(); + translate(token_pitch * [ 1.0, 0.5 ]) Token_L(); + translate(token_pitch * [ 1.0, 1.5 ]) Token_L(); + translate(token_pitch * [ 1.0, 2.5 ]) Token_L(); + translate(token_pitch * [ 2.0, -2.5 ]) Token_L(); + translate(token_pitch * [ 2.0, -1.5 ]) Token_L(); + translate(token_pitch * [ 2.0, -0.5 ]) Token_L(); + translate(token_pitch * [ 2.0, 0.5 ]) Token_L(); + translate(token_pitch * [ 2.0, 1.5 ]) Token_L(); + translate(token_pitch * [ 2.0, 2.5 ]) Token_L(); + translate(token_pitch * [ 3.0, -2.5 ]) Token_L(); + translate(token_pitch * [ 3.0, -1.5 ]) Token_L(); + }; +} +module Base_Orange(){ ////toplevel +// Base Orange total=20 rowsz=5 nrows=4 + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 4 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 4 + 0.50 ]); + $nspots = 1; + translate(token_pitch * [ -2.0, -1.5 ]) Token_L(); + translate(token_pitch * [ -2.0, -0.5 ]) Token_L(); + translate(token_pitch * [ -2.0, 0.5 ]) Token_L(); + translate(token_pitch * [ -2.0, 1.5 ]) Token_L(); + translate(token_pitch * [ -1.0, -1.5 ]) Token_L(); + translate(token_pitch * [ -1.0, -0.5 ]) Token_L(); + translate(token_pitch * [ -1.0, 0.5 ]) Token_L(); + translate(token_pitch * [ -1.0, 1.5 ]) Token_L(); + translate(token_pitch * [ 0.0, -1.5 ]) Token_L(); + translate(token_pitch * [ 0.0, -0.5 ]) Token_L(); + translate(token_pitch * [ 0.0, 0.5 ]) Token_L(); + translate(token_pitch * [ 0.0, 1.5 ]) Token_L(); + translate(token_pitch * [ 1.0, -1.5 ]) Token_L(); + translate(token_pitch * [ 1.0, -0.5 ]) Token_L(); + translate(token_pitch * [ 1.0, 0.5 ]) Token_L(); + translate(token_pitch * [ 1.0, 1.5 ]) Token_L(); + translate(token_pitch * [ 2.0, -1.5 ]) Token_L(); + translate(token_pitch * [ 2.0, -0.5 ]) Token_L(); + translate(token_pitch * [ 2.0, 0.5 ]) Token_L(); + translate(token_pitch * [ 2.0, 1.5 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 4 + 0.50 ]); + $nspots = 2; + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 4 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 4 + 0.50 ]); + $nspots = 4; + }; +} +module Base_Purple(){ ////toplevel +// Base Purple total=15 rowsz=4 nrows=4 + union(){ + Frame($phase, token_pitch * [ 4 + 1.00, 4 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 4 + 1.00, 4 + 0.50 ]); + $nspots = 1; + translate(token_pitch * [ -1.5, -1.5 ]) Token_L(); + translate(token_pitch * [ -1.5, -0.5 ]) Token_L(); + translate(token_pitch * [ -1.5, 0.5 ]) Token_L(); + translate(token_pitch * [ -1.5, 1.5 ]) Token_L(); + translate(token_pitch * [ -0.5, -1.5 ]) Token_L(); + translate(token_pitch * [ -0.5, -0.5 ]) Token_L(); + translate(token_pitch * [ -0.5, 0.5 ]) Token_L(); + translate(token_pitch * [ -0.5, 1.5 ]) Token_L(); + translate(token_pitch * [ 0.5, -1.5 ]) Token_L(); + translate(token_pitch * [ 0.5, -0.5 ]) Token_L(); + translate(token_pitch * [ 0.5, 0.5 ]) Token_L(); + translate(token_pitch * [ 0.5, 1.5 ]) Token_L(); + translate(token_pitch * [ 1.5, -1.5 ]) Token_L(); + translate(token_pitch * [ 1.5, -0.5 ]) Token_L(); + translate(token_pitch * [ 1.5, 0.5 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 4 + 1.00, 4 + 0.50 ]); + $nspots = 2; + }; + union(){ + Frame($phase, token_pitch * [ 4 + 1.00, 4 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 4 + 1.00, 4 + 0.50 ]); + $nspots = 4; + }; +} +module Base_Red(){ ////toplevel +// Base Red total=30 rowsz=6 nrows=5 + union(){ + Frame($phase, token_pitch * [ 6 + 1.00, 5 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 6 + 1.00, 5 + 0.50 ]); + $nspots = 1; + translate(token_pitch * [ -2.5, -2.0 ]) Token_L(); + translate(token_pitch * [ -2.5, -1.0 ]) Token_L(); + translate(token_pitch * [ -2.5, 0.0 ]) Token_L(); + translate(token_pitch * [ -2.5, 1.0 ]) Token_L(); + translate(token_pitch * [ -2.5, 2.0 ]) Token_L(); + translate(token_pitch * [ -1.5, -2.0 ]) Token_L(); + translate(token_pitch * [ -1.5, -1.0 ]) Token_L(); + translate(token_pitch * [ -1.5, 0.0 ]) Token_L(); + translate(token_pitch * [ -1.5, 1.0 ]) Token_L(); + translate(token_pitch * [ -1.5, 2.0 ]) Token_L(); + translate(token_pitch * [ -0.5, -2.0 ]) Token_L(); + translate(token_pitch * [ -0.5, -1.0 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 6 + 1.00, 5 + 0.50 ]); + $nspots = 2; + translate(token_pitch * [ -0.5, 0.0 ]) Token_L(); + translate(token_pitch * [ -0.5, 1.0 ]) Token_L(); + translate(token_pitch * [ -0.5, 2.0 ]) Token_L(); + translate(token_pitch * [ 0.5, -2.0 ]) Token_L(); + translate(token_pitch * [ 0.5, -1.0 ]) Token_L(); + translate(token_pitch * [ 0.5, 0.0 ]) Token_L(); + translate(token_pitch * [ 0.5, 1.0 ]) Token_L(); + translate(token_pitch * [ 0.5, 2.0 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 6 + 1.00, 5 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 6 + 1.00, 5 + 0.50 ]); + $nspots = 4; + translate(token_pitch * [ 1.5, -2.0 ]) Token_L(); + translate(token_pitch * [ 1.5, -1.0 ]) Token_L(); + translate(token_pitch * [ 1.5, 0.0 ]) Token_L(); + translate(token_pitch * [ 1.5, 1.0 ]) Token_L(); + translate(token_pitch * [ 1.5, 2.0 ]) Token_L(); + translate(token_pitch * [ 2.5, -2.0 ]) Token_L(); + translate(token_pitch * [ 2.5, -1.0 ]) Token_L(); + translate(token_pitch * [ 2.5, 0.0 ]) Token_L(); + translate(token_pitch * [ 2.5, 1.0 ]) Token_L(); + translate(token_pitch * [ 2.5, 2.0 ]) Token_L(); + }; +} +module Base_White(){ ////toplevel +// Base White total=35 rowsz=6 nrows=6 + union(){ + Frame($phase, token_pitch * [ 6 + 1.00, 6 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 6 + 1.00, 6 + 0.50 ]); + $nspots = 1; + translate(token_pitch * [ -2.5, -2.5 ]) Token_L(); + translate(token_pitch * [ -2.5, -1.5 ]) Token_L(); + translate(token_pitch * [ -2.5, -0.5 ]) Token_L(); + translate(token_pitch * [ -2.5, 0.5 ]) Token_L(); + translate(token_pitch * [ -2.5, 1.5 ]) Token_L(); + translate(token_pitch * [ -2.5, 2.5 ]) Token_L(); + translate(token_pitch * [ -1.5, -2.5 ]) Token_L(); + translate(token_pitch * [ -1.5, -1.5 ]) Token_L(); + translate(token_pitch * [ -1.5, -0.5 ]) Token_L(); + translate(token_pitch * [ -1.5, 0.5 ]) Token_L(); + translate(token_pitch * [ -1.5, 1.5 ]) Token_L(); + translate(token_pitch * [ -1.5, 2.5 ]) Token_L(); + translate(token_pitch * [ -0.5, -2.5 ]) Token_L(); + translate(token_pitch * [ -0.5, -1.5 ]) Token_L(); + translate(token_pitch * [ -0.5, -0.5 ]) Token_L(); + translate(token_pitch * [ -0.5, 0.5 ]) Token_L(); + translate(token_pitch * [ -0.5, 1.5 ]) Token_L(); + translate(token_pitch * [ -0.5, 2.5 ]) Token_L(); + translate(token_pitch * [ 0.5, -2.5 ]) Token_L(); + translate(token_pitch * [ 0.5, -1.5 ]) Token_L(); + translate(token_pitch * [ 0.5, -0.5 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 6 + 1.00, 6 + 0.50 ]); + $nspots = 2; + translate(token_pitch * [ 0.5, 0.5 ]) Token_L(); + translate(token_pitch * [ 0.5, 1.5 ]) Token_L(); + translate(token_pitch * [ 0.5, 2.5 ]) Token_L(); + translate(token_pitch * [ 1.5, -2.5 ]) Token_L(); + translate(token_pitch * [ 1.5, -1.5 ]) Token_L(); + translate(token_pitch * [ 1.5, -0.5 ]) Token_L(); + translate(token_pitch * [ 1.5, 0.5 ]) Token_L(); + translate(token_pitch * [ 1.5, 1.5 ]) Token_L(); + translate(token_pitch * [ 1.5, 2.5 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 6 + 1.00, 6 + 0.50 ]); + $nspots = 3; + translate(token_pitch * [ 2.5, -2.5 ]) Token_L(); + translate(token_pitch * [ 2.5, -1.5 ]) Token_L(); + translate(token_pitch * [ 2.5, -0.5 ]) Token_L(); + translate(token_pitch * [ 2.5, 0.5 ]) Token_L(); + translate(token_pitch * [ 2.5, 1.5 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 6 + 1.00, 6 + 0.50 ]); + $nspots = 4; + }; +} +module Base_WhiteSpare(){ ////toplevel +// Base WhiteSpare total= 3 rowsz=2 nrows=2 + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 2 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 2 + 0.50 ]); + $nspots = 1; + translate(token_pitch * [ -0.5, -0.5 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 2 + 0.50 ]); + $nspots = 2; + translate(token_pitch * [ -0.5, 0.5 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 2 + 0.50 ]); + $nspots = 3; + translate(token_pitch * [ 0.5, -0.5 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 2 + 0.50 ]); + $nspots = 4; + }; +} +module Base_Yellow(){ ////toplevel +// Base Yellow total=29 rowsz=6 nrows=5 + union(){ + Frame($phase, token_pitch * [ 6 + 1.00, 5 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 6 + 1.00, 5 + 0.50 ]); + $nspots = 1; + translate(token_pitch * [ -2.5, -2.0 ]) Token_L(); + translate(token_pitch * [ -2.5, -1.0 ]) Token_L(); + translate(token_pitch * [ -2.5, 0.0 ]) Token_L(); + translate(token_pitch * [ -2.5, 1.0 ]) Token_L(); + translate(token_pitch * [ -2.5, 2.0 ]) Token_L(); + translate(token_pitch * [ -1.5, -2.0 ]) Token_L(); + translate(token_pitch * [ -1.5, -1.0 ]) Token_L(); + translate(token_pitch * [ -1.5, 0.0 ]) Token_L(); + translate(token_pitch * [ -1.5, 1.0 ]) Token_L(); + translate(token_pitch * [ -1.5, 2.0 ]) Token_L(); + translate(token_pitch * [ -0.5, -2.0 ]) Token_L(); + translate(token_pitch * [ -0.5, -1.0 ]) Token_L(); + translate(token_pitch * [ -0.5, 0.0 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 6 + 1.00, 5 + 0.50 ]); + $nspots = 2; + translate(token_pitch * [ -0.5, 1.0 ]) Token_L(); + translate(token_pitch * [ -0.5, 2.0 ]) Token_L(); + translate(token_pitch * [ 0.5, -2.0 ]) Token_L(); + translate(token_pitch * [ 0.5, -1.0 ]) Token_L(); + translate(token_pitch * [ 0.5, 0.0 ]) Token_L(); + translate(token_pitch * [ 0.5, 1.0 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 6 + 1.00, 5 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 6 + 1.00, 5 + 0.50 ]); + $nspots = 4; + translate(token_pitch * [ 0.5, 2.0 ]) Token_L(); + translate(token_pitch * [ 1.5, -2.0 ]) Token_L(); + translate(token_pitch * [ 1.5, -1.0 ]) Token_L(); + translate(token_pitch * [ 1.5, 0.0 ]) Token_L(); + translate(token_pitch * [ 1.5, 1.0 ]) Token_L(); + translate(token_pitch * [ 1.5, 2.0 ]) Token_L(); + translate(token_pitch * [ 2.5, -2.0 ]) Token_L(); + translate(token_pitch * [ 2.5, -1.0 ]) Token_L(); + translate(token_pitch * [ 2.5, 0.0 ]) Token_L(); + translate(token_pitch * [ 2.5, 1.0 ]) Token_L(); + }; +} +// Base total_count=252 total_real_count=219 +// Base max_rowsz=7 max_nrows=6 +module All_Black(){ ////toplevel +// All Black total=26 rowsz=6 nrows=5 + union(){ + Frame($phase, token_pitch * [ 6 + 1.00, 5 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 6 + 1.00, 5 + 0.50 ]); + $nspots = 1; + translate(token_pitch * [ -2.5, -2.0 ]) Token_L(); + translate(token_pitch * [ -2.5, -1.0 ]) Token_L(); + translate(token_pitch * [ -2.5, 0.0 ]) Token_L(); + translate(token_pitch * [ -2.5, 1.0 ]) Token_L(); + translate(token_pitch * [ -2.5, 2.0 ]) Token_L(); + translate(token_pitch * [ -1.5, -2.0 ]) Token_L(); + translate(token_pitch * [ -1.5, -1.0 ]) Token_L(); + translate(token_pitch * [ -1.5, 0.0 ]) Token_L(); + translate(token_pitch * [ -1.5, 1.0 ]) Token_L(); + translate(token_pitch * [ -1.5, 2.0 ]) Token_L(); + translate(token_pitch * [ -0.5, -2.0 ]) Token_L(); + translate(token_pitch * [ -0.5, -1.0 ]) Token_L(); + translate(token_pitch * [ -0.5, 0.0 ]) Token_L(); + translate(token_pitch * [ -0.5, 1.0 ]) Token_L(); + translate(token_pitch * [ -0.5, 2.0 ]) Token_L(); + translate(token_pitch * [ 0.5, -2.0 ]) Token_L(); + translate(token_pitch * [ 0.5, -1.0 ]) Token_L(); + translate(token_pitch * [ 0.5, 0.0 ]) Token_L(); + translate(token_pitch * [ 0.5, 1.0 ]) Token_L(); + translate(token_pitch * [ 0.5, 2.0 ]) Token_L(); + translate(token_pitch * [ 1.5, -2.0 ]) Token_L(); + translate(token_pitch * [ 1.5, -1.0 ]) Token_L(); + translate(token_pitch * [ 1.5, 0.0 ]) Token_L(); + translate(token_pitch * [ 1.5, 1.0 ]) Token_L(); + translate(token_pitch * [ 1.5, 2.0 ]) Token_L(); + translate(token_pitch * [ 2.5, -2.0 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 6 + 1.00, 5 + 0.50 ]); + $nspots = 2; + }; + union(){ + Frame($phase, token_pitch * [ 6 + 1.00, 5 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 6 + 1.00, 5 + 0.50 ]); + $nspots = 4; + }; +} +module All_Blue(){ ////toplevel +// All Blue total=52 rowsz=8 nrows=7 + union(){ + Frame($phase, token_pitch * [ 8 + 1.00, 7 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 8 + 1.00, 7 + 0.50 ]); + $nspots = 1; + translate(token_pitch * [ -3.5, -3.0 ]) Token_L(); + translate(token_pitch * [ -3.5, -2.0 ]) Token_L(); + translate(token_pitch * [ -3.5, -1.0 ]) Token_L(); + translate(token_pitch * [ -3.5, 0.0 ]) Token_L(); + translate(token_pitch * [ -3.5, 1.0 ]) Token_L(); + translate(token_pitch * [ -3.5, 2.0 ]) Token_L(); + translate(token_pitch * [ -3.5, 3.0 ]) Token_L(); + translate(token_pitch * [ -2.5, -3.0 ]) Token_L(); + translate(token_pitch * [ -2.5, -2.0 ]) Token_L(); + translate(token_pitch * [ -2.5, -1.0 ]) Token_L(); + translate(token_pitch * [ -2.5, 0.0 ]) Token_L(); + translate(token_pitch * [ -2.5, 1.0 ]) Token_L(); + translate(token_pitch * [ -2.5, 2.0 ]) Token_L(); + translate(token_pitch * [ -2.5, 3.0 ]) Token_L(); + translate(token_pitch * [ -1.5, -3.0 ]) Token_L(); + translate(token_pitch * [ -1.5, -2.0 ]) Token_L(); + translate(token_pitch * [ -1.5, -1.0 ]) Token_L(); + translate(token_pitch * [ -1.5, 0.0 ]) Token_L(); + translate(token_pitch * [ -1.5, 1.0 ]) Token_L(); + translate(token_pitch * [ -1.5, 2.0 ]) Token_L(); + translate(token_pitch * [ -1.5, 3.0 ]) Token_L(); + translate(token_pitch * [ -0.5, -3.0 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 8 + 1.00, 7 + 0.50 ]); + $nspots = 2; + translate(token_pitch * [ -0.5, -2.0 ]) Token_L(); + translate(token_pitch * [ -0.5, -1.0 ]) Token_L(); + translate(token_pitch * [ -0.5, 0.0 ]) Token_L(); + translate(token_pitch * [ -0.5, 1.0 ]) Token_L(); + translate(token_pitch * [ -0.5, 2.0 ]) Token_L(); + translate(token_pitch * [ -0.5, 3.0 ]) Token_L(); + translate(token_pitch * [ 0.5, -3.0 ]) Token_L(); + translate(token_pitch * [ 0.5, -2.0 ]) Token_L(); + translate(token_pitch * [ 0.5, -1.0 ]) Token_L(); + translate(token_pitch * [ 0.5, 0.0 ]) Token_L(); + translate(token_pitch * [ 0.5, 1.0 ]) Token_L(); + translate(token_pitch * [ 0.5, 2.0 ]) Token_L(); + translate(token_pitch * [ 0.5, 3.0 ]) Token_L(); + translate(token_pitch * [ 1.5, -3.0 ]) Token_L(); + translate(token_pitch * [ 1.5, -2.0 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 8 + 1.00, 7 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 8 + 1.00, 7 + 0.50 ]); + $nspots = 4; + translate(token_pitch * [ 1.5, -1.0 ]) Token_L(); + translate(token_pitch * [ 1.5, 0.0 ]) Token_L(); + translate(token_pitch * [ 1.5, 1.0 ]) Token_L(); + translate(token_pitch * [ 1.5, 2.0 ]) Token_L(); + translate(token_pitch * [ 1.5, 3.0 ]) Token_L(); + translate(token_pitch * [ 2.5, -3.0 ]) Token_L(); + translate(token_pitch * [ 2.5, -2.0 ]) Token_L(); + translate(token_pitch * [ 2.5, -1.0 ]) Token_L(); + translate(token_pitch * [ 2.5, 0.0 ]) Token_L(); + translate(token_pitch * [ 2.5, 1.0 ]) Token_L(); + translate(token_pitch * [ 2.5, 2.0 ]) Token_L(); + translate(token_pitch * [ 2.5, 3.0 ]) Token_L(); + translate(token_pitch * [ 3.5, -3.0 ]) Token_L(); + translate(token_pitch * [ 3.5, -2.0 ]) Token_L(); + translate(token_pitch * [ 3.5, -1.0 ]) Token_L(); + }; +} +module All_Green(){ ////toplevel +// All Green total=58 rowsz=8 nrows=8 + union(){ + Frame($phase, token_pitch * [ 8 + 1.00, 8 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 8 + 1.00, 8 + 0.50 ]); + $nspots = 1; + translate(token_pitch * [ -3.5, -3.5 ]) Token_L(); + translate(token_pitch * [ -3.5, -2.5 ]) Token_L(); + translate(token_pitch * [ -3.5, -1.5 ]) Token_L(); + translate(token_pitch * [ -3.5, -0.5 ]) Token_L(); + translate(token_pitch * [ -3.5, 0.5 ]) Token_L(); + translate(token_pitch * [ -3.5, 1.5 ]) Token_L(); + translate(token_pitch * [ -3.5, 2.5 ]) Token_L(); + translate(token_pitch * [ -3.5, 3.5 ]) Token_L(); + translate(token_pitch * [ -2.5, -3.5 ]) Token_L(); + translate(token_pitch * [ -2.5, -2.5 ]) Token_L(); + translate(token_pitch * [ -2.5, -1.5 ]) Token_L(); + translate(token_pitch * [ -2.5, -0.5 ]) Token_L(); + translate(token_pitch * [ -2.5, 0.5 ]) Token_L(); + translate(token_pitch * [ -2.5, 1.5 ]) Token_L(); + translate(token_pitch * [ -2.5, 2.5 ]) Token_L(); + translate(token_pitch * [ -2.5, 3.5 ]) Token_L(); + translate(token_pitch * [ -1.5, -3.5 ]) Token_L(); + translate(token_pitch * [ -1.5, -2.5 ]) Token_L(); + translate(token_pitch * [ -1.5, -1.5 ]) Token_L(); + translate(token_pitch * [ -1.5, -0.5 ]) Token_L(); + translate(token_pitch * [ -1.5, 0.5 ]) Token_L(); + translate(token_pitch * [ -1.5, 1.5 ]) Token_L(); + translate(token_pitch * [ -1.5, 2.5 ]) Token_L(); + translate(token_pitch * [ -1.5, 3.5 ]) Token_L(); + translate(token_pitch * [ -0.5, -3.5 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 8 + 1.00, 8 + 0.50 ]); + $nspots = 2; + translate(token_pitch * [ -0.5, -2.5 ]) Token_L(); + translate(token_pitch * [ -0.5, -1.5 ]) Token_L(); + translate(token_pitch * [ -0.5, -0.5 ]) Token_L(); + translate(token_pitch * [ -0.5, 0.5 ]) Token_L(); + translate(token_pitch * [ -0.5, 1.5 ]) Token_L(); + translate(token_pitch * [ -0.5, 2.5 ]) Token_L(); + translate(token_pitch * [ -0.5, 3.5 ]) Token_L(); + translate(token_pitch * [ 0.5, -3.5 ]) Token_L(); + translate(token_pitch * [ 0.5, -2.5 ]) Token_L(); + translate(token_pitch * [ 0.5, -1.5 ]) Token_L(); + translate(token_pitch * [ 0.5, -0.5 ]) Token_L(); + translate(token_pitch * [ 0.5, 0.5 ]) Token_L(); + translate(token_pitch * [ 0.5, 1.5 ]) Token_L(); + translate(token_pitch * [ 0.5, 2.5 ]) Token_L(); + translate(token_pitch * [ 0.5, 3.5 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 8 + 1.00, 8 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 8 + 1.00, 8 + 0.50 ]); + $nspots = 4; + translate(token_pitch * [ 1.5, -3.5 ]) Token_L(); + translate(token_pitch * [ 1.5, -2.5 ]) Token_L(); + translate(token_pitch * [ 1.5, -1.5 ]) Token_L(); + translate(token_pitch * [ 1.5, -0.5 ]) Token_L(); + translate(token_pitch * [ 1.5, 0.5 ]) Token_L(); + translate(token_pitch * [ 1.5, 1.5 ]) Token_L(); + translate(token_pitch * [ 1.5, 2.5 ]) Token_L(); + translate(token_pitch * [ 1.5, 3.5 ]) Token_L(); + translate(token_pitch * [ 2.5, -3.5 ]) Token_L(); + translate(token_pitch * [ 2.5, -2.5 ]) Token_L(); + translate(token_pitch * [ 2.5, -1.5 ]) Token_L(); + translate(token_pitch * [ 2.5, -0.5 ]) Token_L(); + translate(token_pitch * [ 2.5, 0.5 ]) Token_L(); + translate(token_pitch * [ 2.5, 1.5 ]) Token_L(); + translate(token_pitch * [ 2.5, 2.5 ]) Token_L(); + translate(token_pitch * [ 2.5, 3.5 ]) Token_L(); + translate(token_pitch * [ 3.5, -3.5 ]) Token_L(); + translate(token_pitch * [ 3.5, -2.5 ]) Token_L(); + }; +} +module All_Loco(){ ////toplevel +// All Loco total=25 rowsz=5 nrows=5 + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 5 + 0.50 ]); + $nspots = 0; + translate(token_pitch * [ -2.0, -2.0 ]) Token_L(); + translate(token_pitch * [ -2.0, -1.0 ]) Token_L(); + translate(token_pitch * [ -2.0, 0.0 ]) Token_L(); + translate(token_pitch * [ -2.0, 1.0 ]) Token_L(); + translate(token_pitch * [ -2.0, 2.0 ]) Token_L(); + translate(token_pitch * [ -1.0, -2.0 ]) Token_L(); + translate(token_pitch * [ -1.0, -1.0 ]) Token_L(); + translate(token_pitch * [ -1.0, 0.0 ]) Token_L(); + translate(token_pitch * [ -1.0, 1.0 ]) Token_L(); + translate(token_pitch * [ -1.0, 2.0 ]) Token_L(); + translate(token_pitch * [ 0.0, -2.0 ]) Token_L(); + translate(token_pitch * [ 0.0, -1.0 ]) Token_L(); + translate(token_pitch * [ 0.0, 0.0 ]) Token_L(); + translate(token_pitch * [ 0.0, 1.0 ]) Token_L(); + translate(token_pitch * [ 0.0, 2.0 ]) Token_L(); + translate(token_pitch * [ 1.0, -2.0 ]) Token_L(); + translate(token_pitch * [ 1.0, -1.0 ]) Token_L(); + translate(token_pitch * [ 1.0, 0.0 ]) Token_L(); + translate(token_pitch * [ 1.0, 1.0 ]) Token_L(); + translate(token_pitch * [ 1.0, 2.0 ]) Token_L(); + translate(token_pitch * [ 2.0, -2.0 ]) Token_L(); + translate(token_pitch * [ 2.0, -1.0 ]) Token_L(); + translate(token_pitch * [ 2.0, 0.0 ]) Token_L(); + translate(token_pitch * [ 2.0, 1.0 ]) Token_L(); + translate(token_pitch * [ 2.0, 2.0 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 5 + 0.50 ]); + $nspots = 1; + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 5 + 0.50 ]); + $nspots = 2; + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 5 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 5 + 0.50 ]); + $nspots = 4; + }; +} +module All_Orange(){ ////toplevel +// All Orange total=32 rowsz=6 nrows=6 + union(){ + Frame($phase, token_pitch * [ 6 + 1.00, 6 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 6 + 1.00, 6 + 0.50 ]); + $nspots = 1; + translate(token_pitch * [ -2.5, -2.5 ]) Token_L(); + translate(token_pitch * [ -2.5, -1.5 ]) Token_L(); + translate(token_pitch * [ -2.5, -0.5 ]) Token_L(); + translate(token_pitch * [ -2.5, 0.5 ]) Token_L(); + translate(token_pitch * [ -2.5, 1.5 ]) Token_L(); + translate(token_pitch * [ -2.5, 2.5 ]) Token_L(); + translate(token_pitch * [ -1.5, -2.5 ]) Token_L(); + translate(token_pitch * [ -1.5, -1.5 ]) Token_L(); + translate(token_pitch * [ -1.5, -0.5 ]) Token_L(); + translate(token_pitch * [ -1.5, 0.5 ]) Token_L(); + translate(token_pitch * [ -1.5, 1.5 ]) Token_L(); + translate(token_pitch * [ -1.5, 2.5 ]) Token_L(); + translate(token_pitch * [ -0.5, -2.5 ]) Token_L(); + translate(token_pitch * [ -0.5, -1.5 ]) Token_L(); + translate(token_pitch * [ -0.5, -0.5 ]) Token_L(); + translate(token_pitch * [ -0.5, 0.5 ]) Token_L(); + translate(token_pitch * [ -0.5, 1.5 ]) Token_L(); + translate(token_pitch * [ -0.5, 2.5 ]) Token_L(); + translate(token_pitch * [ 0.5, -2.5 ]) Token_L(); + translate(token_pitch * [ 0.5, -1.5 ]) Token_L(); + translate(token_pitch * [ 0.5, -0.5 ]) Token_L(); + translate(token_pitch * [ 0.5, 0.5 ]) Token_L(); + translate(token_pitch * [ 0.5, 1.5 ]) Token_L(); + translate(token_pitch * [ 0.5, 2.5 ]) Token_L(); + translate(token_pitch * [ 1.5, -2.5 ]) Token_L(); + translate(token_pitch * [ 1.5, -1.5 ]) Token_L(); + translate(token_pitch * [ 1.5, -0.5 ]) Token_L(); + translate(token_pitch * [ 1.5, 0.5 ]) Token_L(); + translate(token_pitch * [ 1.5, 1.5 ]) Token_L(); + translate(token_pitch * [ 1.5, 2.5 ]) Token_L(); + translate(token_pitch * [ 2.5, -2.5 ]) Token_L(); + translate(token_pitch * [ 2.5, -1.5 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 6 + 1.00, 6 + 0.50 ]); + $nspots = 2; + }; + union(){ + Frame($phase, token_pitch * [ 6 + 1.00, 6 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 6 + 1.00, 6 + 0.50 ]); + $nspots = 4; + }; +} +module All_Orange6(){ ////toplevel +// All Orange6 total=20 rowsz=5 nrows=4 + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 4 + 0.50 ]); + $nspots = 0; + translate(token_pitch * [ -2.0, -1.5 ]) Token_L(); + translate(token_pitch * [ -2.0, -0.5 ]) Token_L(); + translate(token_pitch * [ -2.0, 0.5 ]) Token_L(); + translate(token_pitch * [ -2.0, 1.5 ]) Token_L(); + translate(token_pitch * [ -1.0, -1.5 ]) Token_L(); + translate(token_pitch * [ -1.0, -0.5 ]) Token_L(); + translate(token_pitch * [ -1.0, 0.5 ]) Token_L(); + translate(token_pitch * [ -1.0, 1.5 ]) Token_L(); + translate(token_pitch * [ 0.0, -1.5 ]) Token_L(); + translate(token_pitch * [ 0.0, -0.5 ]) Token_L(); + translate(token_pitch * [ 0.0, 0.5 ]) Token_L(); + translate(token_pitch * [ 0.0, 1.5 ]) Token_L(); + translate(token_pitch * [ 1.0, -1.5 ]) Token_L(); + translate(token_pitch * [ 1.0, -0.5 ]) Token_L(); + translate(token_pitch * [ 1.0, 0.5 ]) Token_L(); + translate(token_pitch * [ 1.0, 1.5 ]) Token_L(); + translate(token_pitch * [ 2.0, -1.5 ]) Token_L(); + translate(token_pitch * [ 2.0, -0.5 ]) Token_L(); + translate(token_pitch * [ 2.0, 0.5 ]) Token_L(); + translate(token_pitch * [ 2.0, 1.5 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 4 + 0.50 ]); + $nspots = 1; + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 4 + 0.50 ]); + $nspots = 2; + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 4 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 4 + 0.50 ]); + $nspots = 4; + }; +} +module All_Purple(){ ////toplevel +// All Purple total=23 rowsz=5 nrows=5 + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 5 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 5 + 0.50 ]); + $nspots = 1; + translate(token_pitch * [ -2.0, -2.0 ]) Token_L(); + translate(token_pitch * [ -2.0, -1.0 ]) Token_L(); + translate(token_pitch * [ -2.0, 0.0 ]) Token_L(); + translate(token_pitch * [ -2.0, 1.0 ]) Token_L(); + translate(token_pitch * [ -2.0, 2.0 ]) Token_L(); + translate(token_pitch * [ -1.0, -2.0 ]) Token_L(); + translate(token_pitch * [ -1.0, -1.0 ]) Token_L(); + translate(token_pitch * [ -1.0, 0.0 ]) Token_L(); + translate(token_pitch * [ -1.0, 1.0 ]) Token_L(); + translate(token_pitch * [ -1.0, 2.0 ]) Token_L(); + translate(token_pitch * [ 0.0, -2.0 ]) Token_L(); + translate(token_pitch * [ 0.0, -1.0 ]) Token_L(); + translate(token_pitch * [ 0.0, 0.0 ]) Token_L(); + translate(token_pitch * [ 0.0, 1.0 ]) Token_L(); + translate(token_pitch * [ 0.0, 2.0 ]) Token_L(); + translate(token_pitch * [ 1.0, -2.0 ]) Token_L(); + translate(token_pitch * [ 1.0, -1.0 ]) Token_L(); + translate(token_pitch * [ 1.0, 0.0 ]) Token_L(); + translate(token_pitch * [ 1.0, 1.0 ]) Token_L(); + translate(token_pitch * [ 1.0, 2.0 ]) Token_L(); + translate(token_pitch * [ 2.0, -2.0 ]) Token_L(); + translate(token_pitch * [ 2.0, -1.0 ]) Token_L(); + translate(token_pitch * [ 2.0, 0.0 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 5 + 0.50 ]); + $nspots = 2; + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 5 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 5 + 0.50 ]); + $nspots = 4; + }; +} +module All_Red(){ ////toplevel +// All Red total=46 rowsz=7 nrows=7 + union(){ + Frame($phase, token_pitch * [ 7 + 1.00, 7 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 7 + 1.00, 7 + 0.50 ]); + $nspots = 1; + translate(token_pitch * [ -3.0, -3.0 ]) Token_L(); + translate(token_pitch * [ -3.0, -2.0 ]) Token_L(); + translate(token_pitch * [ -3.0, -1.0 ]) Token_L(); + translate(token_pitch * [ -3.0, 0.0 ]) Token_L(); + translate(token_pitch * [ -3.0, 1.0 ]) Token_L(); + translate(token_pitch * [ -3.0, 2.0 ]) Token_L(); + translate(token_pitch * [ -3.0, 3.0 ]) Token_L(); + translate(token_pitch * [ -2.0, -3.0 ]) Token_L(); + translate(token_pitch * [ -2.0, -2.0 ]) Token_L(); + translate(token_pitch * [ -2.0, -1.0 ]) Token_L(); + translate(token_pitch * [ -2.0, 0.0 ]) Token_L(); + translate(token_pitch * [ -2.0, 1.0 ]) Token_L(); + translate(token_pitch * [ -2.0, 2.0 ]) Token_L(); + translate(token_pitch * [ -2.0, 3.0 ]) Token_L(); + translate(token_pitch * [ -1.0, -3.0 ]) Token_L(); + translate(token_pitch * [ -1.0, -2.0 ]) Token_L(); + translate(token_pitch * [ -1.0, -1.0 ]) Token_L(); + translate(token_pitch * [ -1.0, 0.0 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 7 + 1.00, 7 + 0.50 ]); + $nspots = 2; + translate(token_pitch * [ -1.0, 1.0 ]) Token_L(); + translate(token_pitch * [ -1.0, 2.0 ]) Token_L(); + translate(token_pitch * [ -1.0, 3.0 ]) Token_L(); + translate(token_pitch * [ 0.0, -3.0 ]) Token_L(); + translate(token_pitch * [ 0.0, -2.0 ]) Token_L(); + translate(token_pitch * [ 0.0, -1.0 ]) Token_L(); + translate(token_pitch * [ 0.0, 0.0 ]) Token_L(); + translate(token_pitch * [ 0.0, 1.0 ]) Token_L(); + translate(token_pitch * [ 0.0, 2.0 ]) Token_L(); + translate(token_pitch * [ 0.0, 3.0 ]) Token_L(); + translate(token_pitch * [ 1.0, -3.0 ]) Token_L(); + translate(token_pitch * [ 1.0, -2.0 ]) Token_L(); + translate(token_pitch * [ 1.0, -1.0 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 7 + 1.00, 7 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 7 + 1.00, 7 + 0.50 ]); + $nspots = 4; + translate(token_pitch * [ 1.0, 0.0 ]) Token_L(); + translate(token_pitch * [ 1.0, 1.0 ]) Token_L(); + translate(token_pitch * [ 1.0, 2.0 ]) Token_L(); + translate(token_pitch * [ 1.0, 3.0 ]) Token_L(); + translate(token_pitch * [ 2.0, -3.0 ]) Token_L(); + translate(token_pitch * [ 2.0, -2.0 ]) Token_L(); + translate(token_pitch * [ 2.0, -1.0 ]) Token_L(); + translate(token_pitch * [ 2.0, 0.0 ]) Token_L(); + translate(token_pitch * [ 2.0, 1.0 ]) Token_L(); + translate(token_pitch * [ 2.0, 2.0 ]) Token_L(); + translate(token_pitch * [ 2.0, 3.0 ]) Token_L(); + translate(token_pitch * [ 3.0, -3.0 ]) Token_L(); + translate(token_pitch * [ 3.0, -2.0 ]) Token_L(); + translate(token_pitch * [ 3.0, -1.0 ]) Token_L(); + translate(token_pitch * [ 3.0, 0.0 ]) Token_L(); + }; +} +module All_White(){ ////toplevel +// All White total=46 rowsz=7 nrows=7 + union(){ + Frame($phase, token_pitch * [ 7 + 1.00, 7 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 7 + 1.00, 7 + 0.50 ]); + $nspots = 1; + translate(token_pitch * [ -3.0, -3.0 ]) Token_L(); + translate(token_pitch * [ -3.0, -2.0 ]) Token_L(); + translate(token_pitch * [ -3.0, -1.0 ]) Token_L(); + translate(token_pitch * [ -3.0, 0.0 ]) Token_L(); + translate(token_pitch * [ -3.0, 1.0 ]) Token_L(); + translate(token_pitch * [ -3.0, 2.0 ]) Token_L(); + translate(token_pitch * [ -3.0, 3.0 ]) Token_L(); + translate(token_pitch * [ -2.0, -3.0 ]) Token_L(); + translate(token_pitch * [ -2.0, -2.0 ]) Token_L(); + translate(token_pitch * [ -2.0, -1.0 ]) Token_L(); + translate(token_pitch * [ -2.0, 0.0 ]) Token_L(); + translate(token_pitch * [ -2.0, 1.0 ]) Token_L(); + translate(token_pitch * [ -2.0, 2.0 ]) Token_L(); + translate(token_pitch * [ -2.0, 3.0 ]) Token_L(); + translate(token_pitch * [ -1.0, -3.0 ]) Token_L(); + translate(token_pitch * [ -1.0, -2.0 ]) Token_L(); + translate(token_pitch * [ -1.0, -1.0 ]) Token_L(); + translate(token_pitch * [ -1.0, 0.0 ]) Token_L(); + translate(token_pitch * [ -1.0, 1.0 ]) Token_L(); + translate(token_pitch * [ -1.0, 2.0 ]) Token_L(); + translate(token_pitch * [ -1.0, 3.0 ]) Token_L(); + translate(token_pitch * [ 0.0, -3.0 ]) Token_L(); + translate(token_pitch * [ 0.0, -2.0 ]) Token_L(); + translate(token_pitch * [ 0.0, -1.0 ]) Token_L(); + translate(token_pitch * [ 0.0, 0.0 ]) Token_L(); + translate(token_pitch * [ 0.0, 1.0 ]) Token_L(); + translate(token_pitch * [ 0.0, 2.0 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 7 + 1.00, 7 + 0.50 ]); + $nspots = 2; + translate(token_pitch * [ 0.0, 3.0 ]) Token_L(); + translate(token_pitch * [ 1.0, -3.0 ]) Token_L(); + translate(token_pitch * [ 1.0, -2.0 ]) Token_L(); + translate(token_pitch * [ 1.0, -1.0 ]) Token_L(); + translate(token_pitch * [ 1.0, 0.0 ]) Token_L(); + translate(token_pitch * [ 1.0, 1.0 ]) Token_L(); + translate(token_pitch * [ 1.0, 2.0 ]) Token_L(); + translate(token_pitch * [ 1.0, 3.0 ]) Token_L(); + translate(token_pitch * [ 2.0, -3.0 ]) Token_L(); + translate(token_pitch * [ 2.0, -2.0 ]) Token_L(); + translate(token_pitch * [ 2.0, -1.0 ]) Token_L(); + translate(token_pitch * [ 2.0, 0.0 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 7 + 1.00, 7 + 0.50 ]); + $nspots = 3; + translate(token_pitch * [ 2.0, 1.0 ]) Token_L(); + translate(token_pitch * [ 2.0, 2.0 ]) Token_L(); + translate(token_pitch * [ 2.0, 3.0 ]) Token_L(); + translate(token_pitch * [ 3.0, -3.0 ]) Token_L(); + translate(token_pitch * [ 3.0, -2.0 ]) Token_L(); + translate(token_pitch * [ 3.0, -1.0 ]) Token_L(); + translate(token_pitch * [ 3.0, 0.0 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 7 + 1.00, 7 + 0.50 ]); + $nspots = 4; + }; +} +module All_WhiteSpare(){ ////toplevel +// All WhiteSpare total= 3 rowsz=2 nrows=2 + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 2 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 2 + 0.50 ]); + $nspots = 1; + translate(token_pitch * [ -0.5, -0.5 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 2 + 0.50 ]); + $nspots = 2; + translate(token_pitch * [ -0.5, 0.5 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 2 + 0.50 ]); + $nspots = 3; + translate(token_pitch * [ 0.5, -0.5 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 2 + 1.00, 2 + 0.50 ]); + $nspots = 4; + }; +} +module All_Yellow(){ ////toplevel +// All Yellow total=45 rowsz=7 nrows=7 + union(){ + Frame($phase, token_pitch * [ 7 + 1.00, 7 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 7 + 1.00, 7 + 0.50 ]); + $nspots = 1; + translate(token_pitch * [ -3.0, -3.0 ]) Token_L(); + translate(token_pitch * [ -3.0, -2.0 ]) Token_L(); + translate(token_pitch * [ -3.0, -1.0 ]) Token_L(); + translate(token_pitch * [ -3.0, 0.0 ]) Token_L(); + translate(token_pitch * [ -3.0, 1.0 ]) Token_L(); + translate(token_pitch * [ -3.0, 2.0 ]) Token_L(); + translate(token_pitch * [ -3.0, 3.0 ]) Token_L(); + translate(token_pitch * [ -2.0, -3.0 ]) Token_L(); + translate(token_pitch * [ -2.0, -2.0 ]) Token_L(); + translate(token_pitch * [ -2.0, -1.0 ]) Token_L(); + translate(token_pitch * [ -2.0, 0.0 ]) Token_L(); + translate(token_pitch * [ -2.0, 1.0 ]) Token_L(); + translate(token_pitch * [ -2.0, 2.0 ]) Token_L(); + translate(token_pitch * [ -2.0, 3.0 ]) Token_L(); + translate(token_pitch * [ -1.0, -3.0 ]) Token_L(); + translate(token_pitch * [ -1.0, -2.0 ]) Token_L(); + translate(token_pitch * [ -1.0, -1.0 ]) Token_L(); + translate(token_pitch * [ -1.0, 0.0 ]) Token_L(); + translate(token_pitch * [ -1.0, 1.0 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 7 + 1.00, 7 + 0.50 ]); + $nspots = 2; + translate(token_pitch * [ -1.0, 2.0 ]) Token_L(); + translate(token_pitch * [ -1.0, 3.0 ]) Token_L(); + translate(token_pitch * [ 0.0, -3.0 ]) Token_L(); + translate(token_pitch * [ 0.0, -2.0 ]) Token_L(); + translate(token_pitch * [ 0.0, -1.0 ]) Token_L(); + translate(token_pitch * [ 0.0, 0.0 ]) Token_L(); + translate(token_pitch * [ 0.0, 1.0 ]) Token_L(); + translate(token_pitch * [ 0.0, 2.0 ]) Token_L(); + translate(token_pitch * [ 0.0, 3.0 ]) Token_L(); + translate(token_pitch * [ 1.0, -3.0 ]) Token_L(); + translate(token_pitch * [ 1.0, -2.0 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 7 + 1.00, 7 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 7 + 1.00, 7 + 0.50 ]); + $nspots = 4; + translate(token_pitch * [ 1.0, -1.0 ]) Token_L(); + translate(token_pitch * [ 1.0, 0.0 ]) Token_L(); + translate(token_pitch * [ 1.0, 1.0 ]) Token_L(); + translate(token_pitch * [ 1.0, 2.0 ]) Token_L(); + translate(token_pitch * [ 1.0, 3.0 ]) Token_L(); + translate(token_pitch * [ 2.0, -3.0 ]) Token_L(); + translate(token_pitch * [ 2.0, -2.0 ]) Token_L(); + translate(token_pitch * [ 2.0, -1.0 ]) Token_L(); + translate(token_pitch * [ 2.0, 0.0 ]) Token_L(); + translate(token_pitch * [ 2.0, 1.0 ]) Token_L(); + translate(token_pitch * [ 2.0, 2.0 ]) Token_L(); + translate(token_pitch * [ 2.0, 3.0 ]) Token_L(); + translate(token_pitch * [ 3.0, -3.0 ]) Token_L(); + translate(token_pitch * [ 3.0, -2.0 ]) Token_L(); + translate(token_pitch * [ 3.0, -1.0 ]) Token_L(); + }; +} +// All total_count=376 total_real_count=353 +// All max_rowsz=8 max_nrows=8 +module Witches_Black(){ ////toplevel +// Witches Black total= 8 rowsz=3 nrows=3 + union(){ + Frame($phase, token_pitch * [ 3 + 1.00, 3 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 3 + 1.00, 3 + 0.50 ]); + $nspots = 1; + translate(token_pitch * [ -1.0, -1.0 ]) Token_L(); + translate(token_pitch * [ -1.0, 0.0 ]) Token_L(); + translate(token_pitch * [ -1.0, 1.0 ]) Token_L(); + translate(token_pitch * [ 0.0, -1.0 ]) Token_L(); + translate(token_pitch * [ 0.0, 0.0 ]) Token_L(); + translate(token_pitch * [ 0.0, 1.0 ]) Token_L(); + translate(token_pitch * [ 1.0, -1.0 ]) Token_L(); + translate(token_pitch * [ 1.0, 0.0 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 3 + 1.00, 3 + 0.50 ]); + $nspots = 2; + }; + union(){ + Frame($phase, token_pitch * [ 3 + 1.00, 3 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 3 + 1.00, 3 + 0.50 ]); + $nspots = 4; + }; +} +module Witches_Blue(){ ////toplevel +// Witches Blue total=18 rowsz=5 nrows=4 + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 4 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 4 + 0.50 ]); + $nspots = 1; + translate(token_pitch * [ -2.0, -1.5 ]) Token_L(); + translate(token_pitch * [ -2.0, -0.5 ]) Token_L(); + translate(token_pitch * [ -2.0, 0.5 ]) Token_L(); + translate(token_pitch * [ -2.0, 1.5 ]) Token_L(); + translate(token_pitch * [ -1.0, -1.5 ]) Token_L(); + translate(token_pitch * [ -1.0, -0.5 ]) Token_L(); + translate(token_pitch * [ -1.0, 0.5 ]) Token_L(); + translate(token_pitch * [ -1.0, 1.5 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 4 + 0.50 ]); + $nspots = 2; + translate(token_pitch * [ 0.0, -1.5 ]) Token_L(); + translate(token_pitch * [ 0.0, -0.5 ]) Token_L(); + translate(token_pitch * [ 0.0, 0.5 ]) Token_L(); + translate(token_pitch * [ 0.0, 1.5 ]) Token_L(); + translate(token_pitch * [ 1.0, -1.5 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 4 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 4 + 0.50 ]); + $nspots = 4; + translate(token_pitch * [ 1.0, -0.5 ]) Token_L(); + translate(token_pitch * [ 1.0, 0.5 ]) Token_L(); + translate(token_pitch * [ 1.0, 1.5 ]) Token_L(); + translate(token_pitch * [ 2.0, -1.5 ]) Token_L(); + translate(token_pitch * [ 2.0, -0.5 ]) Token_L(); + }; +} +module Witches_Green(){ ////toplevel +// Witches Green total=20 rowsz=5 nrows=4 + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 4 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 4 + 0.50 ]); + $nspots = 1; + translate(token_pitch * [ -2.0, -1.5 ]) Token_L(); + translate(token_pitch * [ -2.0, -0.5 ]) Token_L(); + translate(token_pitch * [ -2.0, 0.5 ]) Token_L(); + translate(token_pitch * [ -2.0, 1.5 ]) Token_L(); + translate(token_pitch * [ -1.0, -1.5 ]) Token_L(); + translate(token_pitch * [ -1.0, -0.5 ]) Token_L(); + translate(token_pitch * [ -1.0, 0.5 ]) Token_L(); + translate(token_pitch * [ -1.0, 1.5 ]) Token_L(); + translate(token_pitch * [ 0.0, -1.5 ]) Token_L(); + translate(token_pitch * [ 0.0, -0.5 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 4 + 0.50 ]); + $nspots = 2; + translate(token_pitch * [ 0.0, 0.5 ]) Token_L(); + translate(token_pitch * [ 0.0, 1.5 ]) Token_L(); + translate(token_pitch * [ 1.0, -1.5 ]) Token_L(); + translate(token_pitch * [ 1.0, -0.5 ]) Token_L(); + translate(token_pitch * [ 1.0, 0.5 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 4 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 4 + 0.50 ]); + $nspots = 4; + translate(token_pitch * [ 1.0, 1.5 ]) Token_L(); + translate(token_pitch * [ 2.0, -1.5 ]) Token_L(); + translate(token_pitch * [ 2.0, -0.5 ]) Token_L(); + translate(token_pitch * [ 2.0, 0.5 ]) Token_L(); + translate(token_pitch * [ 2.0, 1.5 ]) Token_L(); + }; +} +module Witches_Loco(){ ////toplevel +// Witches Loco total=25 rowsz=5 nrows=5 + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 5 + 0.50 ]); + $nspots = 0; + translate(token_pitch * [ -2.0, -2.0 ]) Token_L(); + translate(token_pitch * [ -2.0, -1.0 ]) Token_L(); + translate(token_pitch * [ -2.0, 0.0 ]) Token_L(); + translate(token_pitch * [ -2.0, 1.0 ]) Token_L(); + translate(token_pitch * [ -2.0, 2.0 ]) Token_L(); + translate(token_pitch * [ -1.0, -2.0 ]) Token_L(); + translate(token_pitch * [ -1.0, -1.0 ]) Token_L(); + translate(token_pitch * [ -1.0, 0.0 ]) Token_L(); + translate(token_pitch * [ -1.0, 1.0 ]) Token_L(); + translate(token_pitch * [ -1.0, 2.0 ]) Token_L(); + translate(token_pitch * [ 0.0, -2.0 ]) Token_L(); + translate(token_pitch * [ 0.0, -1.0 ]) Token_L(); + translate(token_pitch * [ 0.0, 0.0 ]) Token_L(); + translate(token_pitch * [ 0.0, 1.0 ]) Token_L(); + translate(token_pitch * [ 0.0, 2.0 ]) Token_L(); + translate(token_pitch * [ 1.0, -2.0 ]) Token_L(); + translate(token_pitch * [ 1.0, -1.0 ]) Token_L(); + translate(token_pitch * [ 1.0, 0.0 ]) Token_L(); + translate(token_pitch * [ 1.0, 1.0 ]) Token_L(); + translate(token_pitch * [ 1.0, 2.0 ]) Token_L(); + translate(token_pitch * [ 2.0, -2.0 ]) Token_L(); + translate(token_pitch * [ 2.0, -1.0 ]) Token_L(); + translate(token_pitch * [ 2.0, 0.0 ]) Token_L(); + translate(token_pitch * [ 2.0, 1.0 ]) Token_L(); + translate(token_pitch * [ 2.0, 2.0 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 5 + 0.50 ]); + $nspots = 1; + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 5 + 0.50 ]); + $nspots = 2; + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 5 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 5 + 0.50 ]); + $nspots = 4; + }; +} +module Witches_Orange(){ ////toplevel +// Witches Orange total=12 rowsz=4 nrows=3 + union(){ + Frame($phase, token_pitch * [ 4 + 1.00, 3 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 4 + 1.00, 3 + 0.50 ]); + $nspots = 1; + translate(token_pitch * [ -1.5, -1.0 ]) Token_L(); + translate(token_pitch * [ -1.5, 0.0 ]) Token_L(); + translate(token_pitch * [ -1.5, 1.0 ]) Token_L(); + translate(token_pitch * [ -0.5, -1.0 ]) Token_L(); + translate(token_pitch * [ -0.5, 0.0 ]) Token_L(); + translate(token_pitch * [ -0.5, 1.0 ]) Token_L(); + translate(token_pitch * [ 0.5, -1.0 ]) Token_L(); + translate(token_pitch * [ 0.5, 0.0 ]) Token_L(); + translate(token_pitch * [ 0.5, 1.0 ]) Token_L(); + translate(token_pitch * [ 1.5, -1.0 ]) Token_L(); + translate(token_pitch * [ 1.5, 0.0 ]) Token_L(); + translate(token_pitch * [ 1.5, 1.0 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 4 + 1.00, 3 + 0.50 ]); + $nspots = 2; + }; + union(){ + Frame($phase, token_pitch * [ 4 + 1.00, 3 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 4 + 1.00, 3 + 0.50 ]); + $nspots = 4; + }; +} +module Witches_Orange6(){ ////toplevel +// Witches Orange6 total=20 rowsz=5 nrows=4 + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 4 + 0.50 ]); + $nspots = 0; + translate(token_pitch * [ -2.0, -1.5 ]) Token_L(); + translate(token_pitch * [ -2.0, -0.5 ]) Token_L(); + translate(token_pitch * [ -2.0, 0.5 ]) Token_L(); + translate(token_pitch * [ -2.0, 1.5 ]) Token_L(); + translate(token_pitch * [ -1.0, -1.5 ]) Token_L(); + translate(token_pitch * [ -1.0, -0.5 ]) Token_L(); + translate(token_pitch * [ -1.0, 0.5 ]) Token_L(); + translate(token_pitch * [ -1.0, 1.5 ]) Token_L(); + translate(token_pitch * [ 0.0, -1.5 ]) Token_L(); + translate(token_pitch * [ 0.0, -0.5 ]) Token_L(); + translate(token_pitch * [ 0.0, 0.5 ]) Token_L(); + translate(token_pitch * [ 0.0, 1.5 ]) Token_L(); + translate(token_pitch * [ 1.0, -1.5 ]) Token_L(); + translate(token_pitch * [ 1.0, -0.5 ]) Token_L(); + translate(token_pitch * [ 1.0, 0.5 ]) Token_L(); + translate(token_pitch * [ 1.0, 1.5 ]) Token_L(); + translate(token_pitch * [ 2.0, -1.5 ]) Token_L(); + translate(token_pitch * [ 2.0, -0.5 ]) Token_L(); + translate(token_pitch * [ 2.0, 0.5 ]) Token_L(); + translate(token_pitch * [ 2.0, 1.5 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 4 + 0.50 ]); + $nspots = 1; + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 4 + 0.50 ]); + $nspots = 2; + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 4 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 5 + 1.00, 4 + 0.50 ]); + $nspots = 4; + }; +} +module Witches_Purple(){ ////toplevel +// Witches Purple total= 8 rowsz=3 nrows=3 + union(){ + Frame($phase, token_pitch * [ 3 + 1.00, 3 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 3 + 1.00, 3 + 0.50 ]); + $nspots = 1; + translate(token_pitch * [ -1.0, -1.0 ]) Token_L(); + translate(token_pitch * [ -1.0, 0.0 ]) Token_L(); + translate(token_pitch * [ -1.0, 1.0 ]) Token_L(); + translate(token_pitch * [ 0.0, -1.0 ]) Token_L(); + translate(token_pitch * [ 0.0, 0.0 ]) Token_L(); + translate(token_pitch * [ 0.0, 1.0 ]) Token_L(); + translate(token_pitch * [ 1.0, -1.0 ]) Token_L(); + translate(token_pitch * [ 1.0, 0.0 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 3 + 1.00, 3 + 0.50 ]); + $nspots = 2; + }; + union(){ + Frame($phase, token_pitch * [ 3 + 1.00, 3 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 3 + 1.00, 3 + 0.50 ]); + $nspots = 4; + }; +} +module Witches_Red(){ ////toplevel +// Witches Red total=16 rowsz=4 nrows=4 + union(){ + Frame($phase, token_pitch * [ 4 + 1.00, 4 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 4 + 1.00, 4 + 0.50 ]); + $nspots = 1; + translate(token_pitch * [ -1.5, -1.5 ]) Token_L(); + translate(token_pitch * [ -1.5, -0.5 ]) Token_L(); + translate(token_pitch * [ -1.5, 0.5 ]) Token_L(); + translate(token_pitch * [ -1.5, 1.5 ]) Token_L(); + translate(token_pitch * [ -0.5, -1.5 ]) Token_L(); + translate(token_pitch * [ -0.5, -0.5 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 4 + 1.00, 4 + 0.50 ]); + $nspots = 2; + translate(token_pitch * [ -0.5, 0.5 ]) Token_L(); + translate(token_pitch * [ -0.5, 1.5 ]) Token_L(); + translate(token_pitch * [ 0.5, -1.5 ]) Token_L(); + translate(token_pitch * [ 0.5, -0.5 ]) Token_L(); + translate(token_pitch * [ 0.5, 0.5 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 4 + 1.00, 4 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 4 + 1.00, 4 + 0.50 ]); + $nspots = 4; + translate(token_pitch * [ 0.5, 1.5 ]) Token_L(); + translate(token_pitch * [ 1.5, -1.5 ]) Token_L(); + translate(token_pitch * [ 1.5, -0.5 ]) Token_L(); + translate(token_pitch * [ 1.5, 0.5 ]) Token_L(); + translate(token_pitch * [ 1.5, 1.5 ]) Token_L(); + }; +} +module Witches_White(){ ////toplevel +// Witches White total=11 rowsz=4 nrows=3 + union(){ + Frame($phase, token_pitch * [ 4 + 1.00, 3 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 4 + 1.00, 3 + 0.50 ]); + $nspots = 1; + translate(token_pitch * [ -1.5, -1.0 ]) Token_L(); + translate(token_pitch * [ -1.5, 0.0 ]) Token_L(); + translate(token_pitch * [ -1.5, 1.0 ]) Token_L(); + translate(token_pitch * [ -0.5, -1.0 ]) Token_L(); + translate(token_pitch * [ -0.5, 0.0 ]) Token_L(); + translate(token_pitch * [ -0.5, 1.0 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 4 + 1.00, 3 + 0.50 ]); + $nspots = 2; + translate(token_pitch * [ 0.5, -1.0 ]) Token_L(); + translate(token_pitch * [ 0.5, 0.0 ]) Token_L(); + translate(token_pitch * [ 0.5, 1.0 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 4 + 1.00, 3 + 0.50 ]); + $nspots = 3; + translate(token_pitch * [ 1.5, -1.0 ]) Token_L(); + translate(token_pitch * [ 1.5, 0.0 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 4 + 1.00, 3 + 0.50 ]); + $nspots = 4; + }; +} +module Witches_Yellow(){ ////toplevel +// Witches Yellow total=16 rowsz=4 nrows=4 + union(){ + Frame($phase, token_pitch * [ 4 + 1.00, 4 + 0.50 ]); + $nspots = 0; + }; + union(){ + Frame($phase, token_pitch * [ 4 + 1.00, 4 + 0.50 ]); + $nspots = 1; + translate(token_pitch * [ -1.5, -1.5 ]) Token_L(); + translate(token_pitch * [ -1.5, -0.5 ]) Token_L(); + translate(token_pitch * [ -1.5, 0.5 ]) Token_L(); + translate(token_pitch * [ -1.5, 1.5 ]) Token_L(); + translate(token_pitch * [ -0.5, -1.5 ]) Token_L(); + translate(token_pitch * [ -0.5, -0.5 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 4 + 1.00, 4 + 0.50 ]); + $nspots = 2; + translate(token_pitch * [ -0.5, 0.5 ]) Token_L(); + translate(token_pitch * [ -0.5, 1.5 ]) Token_L(); + translate(token_pitch * [ 0.5, -1.5 ]) Token_L(); + translate(token_pitch * [ 0.5, -0.5 ]) Token_L(); + translate(token_pitch * [ 0.5, 0.5 ]) Token_L(); + }; + union(){ + Frame($phase, token_pitch * [ 4 + 1.00, 4 + 0.50 ]); + $nspots = 3; + }; + union(){ + Frame($phase, token_pitch * [ 4 + 1.00, 4 + 0.50 ]); + $nspots = 4; + translate(token_pitch * [ 0.5, 1.5 ]) Token_L(); + translate(token_pitch * [ 1.5, -1.5 ]) Token_L(); + translate(token_pitch * [ 1.5, -0.5 ]) Token_L(); + translate(token_pitch * [ 1.5, 0.5 ]) Token_L(); + translate(token_pitch * [ 1.5, 1.5 ]) Token_L(); + }; +} +// Witches total_count=154 total_real_count=134 +// Witches max_rowsz=5 max_nrows=5 diff --git a/quacks-ingredients-demos.scad b/quacks-ingredients-demos.scad new file mode 100644 index 0000000..1f02c60 --- /dev/null +++ b/quacks-ingredients-demos.scad @@ -0,0 +1,39 @@ +// -*- C -*- + +include + +sandingframe_gap = 0.3; // to be added to radius +sandingframe_nw = 5; +sandingframe_nl = 6; +sandingframe_th = thick*2/3; + +module Demo(){ ////toplevel + $nspots = 3; + color("red") { Token_L3(); } + color("white") { Token_L1(); Token_L5(); } + color("black") { Token_L2(); Token_L4(); } +} + +module SandingFrame(){ ////toplevel + stridel = token_dia + 5; + nl = sandingframe_nl; + nw = sandingframe_nw; + stridew = stridel * cos(30); + stride = [stridel,stridew]; + + linear_extrude(height = sandingframe_th) { + difference(){ + translate((token_dia/2 + stridel) * 0.5 * [-1,-1]) + square([ stridel * (nl + 0.5), + stridew * nw + stridel * 0.5 ]); + for (j = [0 : nw-1]) { + eo = j % 2; + for (i = [0 : nl-1-0.5*eo]) { + translate([stridel * (i + 0.5 * eo), + stridew * j]) + circle(r = token_dia/2 + sandingframe_gap); + } + } + } + } +} diff --git a/quacks-ingredients-make-copy-gcodes b/quacks-ingredients-make-copy-gcodes new file mode 100755 index 0000000..fd34367 --- /dev/null +++ b/quacks-ingredients-make-copy-gcodes @@ -0,0 +1,135 @@ +#!/bin/bash +# +# usage: +# ./quacks-ingredients-make-copy-gcodes Tests_L +# Uses +# quacks-ingredients-L$l,Tests_L.auto.stl +# to make +# quacks-ingredients-L$l,Tests_L.auto.gcode +# and then edits them and copies them to the SD card as +# PREPARED/Q$l.G + +set -e + +f=$1 +shift + +lhs=quacks-ingredients-L + +gh () { + g=$lhs$l.auto.gcode + h=/media/sd/PREPARED/Q$l.G +} + +for l in 1 2 3 4 5; do + gh + qi=quacks-L$l.auto.ini + + cp quacks.ini $qi + + case $l in + 2|4|5) + perl -i~ -pe ' + s/^(retraction_hop *= *.*)/retraction_hop = 0.6/m + ' $qi + ;; + esac + + cura -i $qi -s $lhs$l,$f.auto.stl -o $g + case $l in + 1|2|3|4) + perl -i~ -pe 's/^/;/ if m/^M140 S0\b.*\n/' $g + ;; + esac + + perl -i~ -ne ' + $l =~ s/^/;/ if m/^M400/; + $l .= "G91\nG1 Z5\nG90\n" if m/^M84/; + print $l or die $!; + $l = $_; + END { print $l or die $!; } + ' $g +done + +for l in 2 4 5; do + gh + : perl -i~ -0777 -ne ' + @l = split m{^(?=;LAYER:\d+\n)}m, $_; + foreach my $i (0..$#l) { + $l[$i] =~ + s{ + ( ^G1 \ Z\S+ \s*\n + | ^\;LAYER:\d+ \s*\n + (?: ^M10[67].* \s*\n )? + ) + ^G0 \ F(\d+) \ ( X\S+ \ Y\S+ ) + \ Z(\S+) \s*\n + }{ + die "$& $2" unless $2 > 9000; + $1 . + "G1 Z$4\n". + "G0 F$2 $3\n". + "G1 Z$4\n" + }mxe or $i==0 + or die "$l[$i] $i"; + $l[$i] =~ + s{ + ^G1 \ Z([0-9.]+) \s*\n + ( ^G0 \ F(\d+) \ X\S+ \ Y\S+ \s*\n + (?: ; .* \s*\n )? + ^G1 \ Z([0-9.]+) \s*\n ) + }{ + die "$& $3" unless $1 >= $4; + die "$& $3" unless $3 > 9000; + my $z = $i == $#l ? $1 : $4 + 0.5; + "G0 F$3\n". + "G1 Z$z\n" . + $2 + }gmxe or $i==0 or die "$l[$i] $i"; + } + print or die $! foreach @l; + ' $g +done + +exec 3>${lhs}234.auto.gcode +for l in 2 3; do + gh + perl -pe 's/^/;/ if m/^M104 S0\b/ || (m/^M84/..0)' $g >&3 +done +for l in 4; do + gh + cat $g >&3 +done + +copies="3:5 2:234 1:1" +copyls="" +for copy in $copies; do + l=-P-${copy%:*} + ci=$lhs${copy#*:}.auto.gcode + copyls+=" $l" + gh + rm -f $g + ln -vs $ci $g +done + +umount /media/sd >/dev/null 2>&1 ||: +mount /media/sd + +for l in 1 2 3 4 5 234 $copyls; do + gh + cp $g $h +done + +sleep 0.5 + +umount /media/sd +mount /media/sd + +for l in 1 2 3 4 5 234 $copyls; do + gh + cmp $g $h + ls -l $h +done +sleep 0.5 + +umount /media/sd diff --git a/quacks-ingredients-update-levels b/quacks-ingredients-update-levels new file mode 100755 index 0000000..395770d --- /dev/null +++ b/quacks-ingredients-update-levels @@ -0,0 +1,28 @@ +#!/bin/sh +set -e + +for l in 1 2 3 4 5; do + f=quacks-ingredients-L$l.scad + cat >$f.tmp < +END + mv -f $f.tmp $f +done + +f=quacks-ingredients-counts.scad +cat >$f.tmp <>$f.tmp +done +mv -f $f.tmp $f + +egrep '^// [A-Z][a-z]* *[A-Za-z]' $f | sort diff --git a/quacks-ingredients.scad b/quacks-ingredients.scad new file mode 100644 index 0000000..6925a1b --- /dev/null +++ b/quacks-ingredients.scad @@ -0,0 +1,145 @@ +// -*- C -*- + +// +// git clean -xdff +// ./quacks-ingredients-update-levels +// make autoincs +// +// make -j8 quacks-stls 2>&1 | tee log +// OR EG +// make -j8 quacks-ingredients-L{1,2,3,4,5},Base_Yellow.auto.stl +// +// ./quacks-ingredients-make-copy-gcodes Base_Yellow etc. +// +// Print Q-P-1 in spots, Q-P-2 in main colour, Q-P-3 in spots +// +// For colours which only have zero-spot counters, print only Q-P-2 + +token_dia = 20; +spot_dia = 4.3; +spot_gap = spot_dia / 3.0; + +thick = 3.0; + +multicolour_gap = 0.075; // each side +initial_layer_thick = 0.400; +initial_layer_width = 0.750; +final_layer_thick = 0.500; +multicolour_post = 4; + +$fs=0.1; +$fa=1; + +// calculated + +token_pitch = token_dia + 3; + +// autoadjusted + +$spots_absent = false; +$spots_plusgap = false; + +module Spots_Extrude_Lower(){ + d = $spots_plusgap ? 1 : 0; + translate([0,0,-d]) + linear_extrude(height= initial_layer_thick + d) + children(0); +} + +module Spots_Extrude_Upper(){ + d = $spots_plusgap ? 1 : 0; + translate([0,0, thick + d]) + mirror([0,0, 1]) + linear_extrude(height= final_layer_thick + d) + children(0); +} + +module SpotAt(condition, xy) { + if (condition == !$spots_absent) { + translate(xy * (spot_gap + spot_dia) * sqrt(0.5)) + circle(r= spot_dia/2 + + ($spots_plusgap ? multicolour_gap : 0)); + } +} + +module Token_Spots(){ + SpotAt(($nspots % 2) > 0, [0,0]); + SpotAt($nspots >= 2, [ 1, 1]); + SpotAt($nspots >= 2, [-1,-1]); + SpotAt($nspots >= 4, [ 1,-1]); + SpotAt($nspots >= 4, [-1, 1]); +} + +module Token_Spots_All(){ + $nspots = 5; + Token_Spots(); +} + +module Token_L1(){ + Spots_Extrude_Lower() + Token_Spots(); +} + +module Token_L2(){ + $spots_absent = true; + Spots_Extrude_Lower() + Token_Spots(); +} + +module Token_L3(){ + $spots_plusgap = true; + difference(){ + linear_extrude(height=thick) + circle(r=token_dia/2); + Spots_Extrude_Lower() Token_Spots_All(); + Spots_Extrude_Upper() Token_Spots_All(); + } +} + +module Token_L4(){ + $spots_absent = true; + Spots_Extrude_Upper() + Token_Spots(); +} + +module Token_L5(){ + Spots_Extrude_Upper() + Token_Spots(); +} + +module Frame(phase, base_sz) { + zs = [ initial_layer_thick, + initial_layer_thick, + thick, + thick, + thick ]; + + sz = base_sz + phase * initial_layer_width * 2 * [1,1]; + linear_extrude(height= initial_layer_thick) { + difference(){ + square(center=true, sz + initial_layer_width * 2 * [1,1]); + square(center=true, sz); + } + } + // Priming tower + translate([-base_sz[0]/2, (2.8-phase)*(multicolour_post*1.7)]) + linear_extrude(height= zs[phase-1]) + square(multicolour_post); +} + +module Tests(){ + for ($nspots = [1,2,3,4]) { + translate(($nspots - 2) * token_pitch * [1,0]) + children(); + } +} + +module Tests_L() { ////toplevel + Frame($phase, token_dia * [ 6, 1.5 ]); + Tests() Token_L(); +} + +//// toplevels-from: +include + +//Demo(); diff --git a/quacks.ini b/quacks.ini new file mode 100644 index 0000000..8a4f7cc --- /dev/null +++ b/quacks.ini @@ -0,0 +1,266 @@ +[profile] +layer_height = 0.14 +wall_thickness = 1 +retraction_enable = True +solid_layer_thickness = 1 +fill_density = 20 +perimeter_before_infill = True +nozzle_size = 0.5 +print_speed = 50 +print_temperature = 0 +print_temperature2 = 0 +print_temperature3 = 0 +print_temperature4 = 0 +print_temperature5 = 0 +print_bed_temperature = 0 +support = None +platform_adhesion = None +support_dual_extrusion = Both +wipe_tower = False +wipe_tower_volume = 15 +ooze_shield = False +filament_diameter = 2.85 +filament_diameter2 = 0 +filament_diameter3 = 0 +filament_diameter4 = 0 +filament_diameter5 = 0 +filament_flow = 100.0 +retraction_speed = 10 +retraction_amount = 1.5 +retraction_dual_amount = 16.5 +retraction_min_travel = 1.5 +retraction_combing = All +retraction_minimal_extrusion = 0.005 +retraction_hop = 0.1 +bottom_thickness = 0.425 +layer0_width_factor = 125 +object_sink = 0.0 +overlap_dual = 0.15 +travel_speed = 175 +bottom_layer_speed = 15 +infill_speed = 40 +solidarea_speed = 30 +inset0_speed = 30 +insetx_speed = 35 +fill_angle = 45 +cool_min_layer_time = 20 +fan_enabled = True +skirt_line_count = 1 +skirt_gap = 3.0 +skirt_minimal_length = 250 +fan_full_height = 0.5 +fan_speed = 75 +fan_speed_max = 100 +cool_min_feedrate = 10 +cool_head_lift = False +solid_top = True +solid_bottom = True +fill_overlap = 15 +support_type = Lines +support_angle = 60 +support_fill_rate = 30 +support_xy_distance = 1.5 +support_z_distance = 0.1 +spiralize = False +simple_mode = False +brim_line_count = 10 +raft_margin = 5.0 +raft_line_spacing = 3.0 +raft_base_thickness = 0.3 +raft_base_linewidth = 1.0 +raft_interface_thickness = 0.27 +raft_interface_linewidth = 0.4 +raft_airgap_all = 0.0 +raft_airgap = 0.5 +raft_surface_layers = 2 +raft_surface_thickness = 0.27 +raft_surface_linewidth = 0.4 +fix_horrible_union_all_type_a = True +fix_horrible_union_all_type_b = False +fix_horrible_use_open_bits = False +fix_horrible_extensive_stitching = False +plugin_config = +object_center_x = -1 +object_center_y = -1 +simplemodesettings = +simplemodeprofile = Standard +simplemodematerial = PLA +simplemodematerialtype = Beginner + +[alterations] +start.gcode = ;Sliced at: {day} {date} {time} + ;Basic settings: Layer height: {layer_height} Walls: {wall_thickness} Fill: {fill_density} + ;Print time: {print_time} + ;Filament used: {filament_amount}m {filament_weight}g + ;Filament cost: {filament_cost} + ;M190 R{print_bed_temperature} ;Uncomment to add your own bed temperature line + ;M109 R{print_temperature} ;Uncomment to add your own temperature line + G21 ;metric values + G90 ;absolute positioning + M82 ;set extruder to absolute mode + M107 ;start with the fan off + G28 X0 Y0 ;move X/Y to min endstops + G28 Z0 ;move Z to min endstops + G1 Z15.0 F{travel_speed};move the platform down 15mm + G92 E0 ; zero the extruded length + G1 F200 E0 ; extrude 3mm of feed stock + G92 E0 ; zero the extruded length again + G1 F{travel_speed} ; set travel speed + M203 X192 Y208 Z3 ; speed limits + M117 Printing... ; send message to LCD +end.gcode = M400 + M104 S0 ; hotend off + M140 S0 ; heated bed heater off (if you have it) + M107 ; fans off + G91 ; relative positioning + G1 E-1 F300 ; retract the filament a bit before lifting the nozzle, to release some of the pressure + G1 Z+0.5 E-5 X-20 Y-20 F3000 ; move Z up a bit and retract filament even more + G90 ; absolute positioning + G1 X0 Y250 ; move to cooling position + M84 ; steppers off + G90 ; absolute positioning + M117 TAZ Ready. + ;{profile_string} +start2.gcode = ;Sliced at: {day} {date} {time} + ;Basic settings: Layer height: {layer_height} Walls: {wall_thickness} Fill: {fill_density} + ;Print time: {print_time} + ;Filament used: {filament_amount}m {filament_weight}g + ;Filament cost: {filament_cost} + ;M190 R{print_bed_temperature} ;Uncomment to add your own bed temperature line + ;M104 S{print_temperature} ;Uncomment to add your own temperature line + ;M109 T1 S{print_temperature2} ;Uncomment to add your own temperature line + ;M109 T0 S{print_temperature} ;Uncomment to add your own temperature line + G21 ;metric values + G90 ;absolute positioning + M107 ;start with the fan off + G28 X0 Y0 ;move X/Y to min endstops + G28 Z0 ;move Z to min endstops + G1 Z15.0 F{travel_speed} ;move the platform down 15mm + T1 ;Switch to the 2nd extruder + G92 E0 ;zero the extruded length + G1 F200 E10 ;extrude 10mm of feed stock + G92 E0 ;zero the extruded length again + G1 F200 E-{retraction_dual_amount} + T0 ;Switch to the first extruder + G92 E0 ;zero the extruded length + G1 F200 E10 ;extrude 10mm of feed stock + G92 E0 ;zero the extruded length again + G1 F{travel_speed} + ;Put printing message on LCD screen + M117 Printing... +end2.gcode = ;End GCode + M104 T0 S0 ;extruder heater off + M104 T1 S0 ;extruder heater off + M140 S0 ;heated bed heater off (if you have it) + G91 ;relative positioning + G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure + G1 Z+0.5 E-5 X-20 Y-20 F{travel_speed} ;move Z up a bit and retract filament even more + G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way + M84 ;steppers off + G90 ;absolute positioning + ;{profile_string} +start3.gcode = ;Sliced at: {day} {date} {time} + ;Basic settings: Layer height: {layer_height} Walls: {wall_thickness} Fill: {fill_density} + ;Print time: {print_time} + ;Filament used: {filament_amount}m {filament_weight}g + ;Filament cost: {filament_cost} + ;M190 R{print_bed_temperature} ;Uncomment to add your own bed temperature line + ;M104 S{print_temperature} ;Uncomment to add your own temperature line + ;M109 T1 S{print_temperature2} ;Uncomment to add your own temperature line + ;M109 T0 S{print_temperature} ;Uncomment to add your own temperature line + G21 ;metric values + G90 ;absolute positioning + M107 ;start with the fan off + G28 X0 Y0 ;move X/Y to min endstops + G28 Z0 ;move Z to min endstops + G1 Z15.0 F{travel_speed} ;move the platform down 15mm + T2 ;Switch to the 2nd extruder + G92 E0 ;zero the extruded length + G1 F200 E10 ;extrude 10mm of feed stock + G92 E0 ;zero the extruded length again + G1 F200 E-{retraction_dual_amount} + T1 ;Switch to the 2nd extruder + G92 E0 ;zero the extruded length + G1 F200 E10 ;extrude 10mm of feed stock + G92 E0 ;zero the extruded length again + G1 F200 E-{retraction_dual_amount} + T0 ;Switch to the first extruder + G92 E0 ;zero the extruded length + G1 F200 E10 ;extrude 10mm of feed stock + G92 E0 ;zero the extruded length again + G1 F{travel_speed} + ;Put printing message on LCD screen + M117 Printing... +end3.gcode = ;End GCode + M104 T0 S0 ;extruder heater off + M104 T1 S0 ;extruder heater off + M104 T2 S0 ;extruder heater off + M140 S0 ;heated bed heater off (if you have it) + G91 ;relative positioning + G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure + G1 Z+0.5 E-5 X-20 Y-20 F{travel_speed} ;move Z up a bit and retract filament even more + G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way + M84 ;steppers off + G90 ;absolute positioning + ;{profile_string} +start4.gcode = ;Sliced at: {day} {date} {time} + ;Basic settings: Layer height: {layer_height} Walls: {wall_thickness} Fill: {fill_density} + ;Print time: {print_time} + ;Filament used: {filament_amount}m {filament_weight}g + ;Filament cost: {filament_cost} + ;M190 R{print_bed_temperature} ;Uncomment to add your own bed temperature line + ;M104 S{print_temperature} ;Uncomment to add your own temperature line + ;M109 T2 S{print_temperature2} ;Uncomment to add your own temperature line + ;M109 T1 S{print_temperature2} ;Uncomment to add your own temperature line + ;M109 T0 S{print_temperature} ;Uncomment to add your own temperature line + G21 ;metric values + G90 ;absolute positioning + M107 ;start with the fan off + G28 X0 Y0 ;move X/Y to min endstops + G28 Z0 ;move Z to min endstops + G1 Z15.0 F{travel_speed} ;move the platform down 15mm + T3 ;Switch to the 4th extruder + G92 E0 ;zero the extruded length + G1 F200 E10 ;extrude 10mm of feed stock + G92 E0 ;zero the extruded length again + G1 F200 E-{retraction_dual_amount} + T2 ;Switch to the 3th extruder + G92 E0 ;zero the extruded length + G1 F200 E10 ;extrude 10mm of feed stock + G92 E0 ;zero the extruded length again + G1 F200 E-{retraction_dual_amount} + T1 ;Switch to the 2nd extruder + G92 E0 ;zero the extruded length + G1 F200 E10 ;extrude 10mm of feed stock + G92 E0 ;zero the extruded length again + G1 F200 E-{retraction_dual_amount} + T0 ;Switch to the first extruder + G92 E0 ;zero the extruded length + G1 F200 E10 ;extrude 10mm of feed stock + G92 E0 ;zero the extruded length again + G1 F{travel_speed} + ;Put printing message on LCD screen + M117 Printing... +end4.gcode = ;End GCode + M104 T0 S0 ;extruder heater off + M104 T1 S0 ;extruder heater off + M104 T2 S0 ;extruder heater off + M104 T3 S0 ;extruder heater off + M140 S0 ;heated bed heater off (if you have it) + G91 ;relative positioning + G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure + G1 Z+0.5 E-5 X-20 Y-20 F{travel_speed} ;move Z up a bit and retract filament even more + G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way + M84 ;steppers off + G90 ;absolute positioning + ;{profile_string} +support_start.gcode = +support_end.gcode = +cool_start.gcode = +cool_end.gcode = +replace.csv = +preswitchextruder.gcode = ;Switch between the current extruder and the next extruder, when printing with multiple extruders. + ;This code is added before the T(n) +postswitchextruder.gcode = ;Switch between the current extruder and the next extruder, when printing with multiple extruders. + ;This code is added after the T(n) + diff --git a/question-question.fig b/question-question.fig new file mode 100644 index 0000000..6d4e5b9 --- /dev/null +++ b/question-question.fig @@ -0,0 +1,11 @@ +#FIG 3.2 Produced by xfig version 3.2.6a +Landscape +Center +Metric +A4 +100.00 +Single +-2 +1200 2 +1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 3780 3870 675 675 3780 3870 4455 3870 +4 0 0 34 -1 14 64 0.0000 4 645 645 3465 4185 ?\001 diff --git a/question-token.scad b/question-token.scad new file mode 100644 index 0000000..2bd7bc6 --- /dev/null +++ b/question-token.scad @@ -0,0 +1,25 @@ +// -*- C -*- + +tokenrad=13; +tokenthick=1.9; + +joinwidth=1.0; + +circlerad=15; + +module Letter() { + translate([-circlerad,-circlerad]) + import("question-question.dxf", convexity=100); +} + +module Token() { ////toplevel + rotate([0,180,0]) + linear_extrude(height=tokenthick) union(){ + difference(){ + %circle(tokenrad); + Letter(); + } + } +} + +Token(); diff --git a/read-firmware b/read-firmware new file mode 100755 index 0000000..153e803 --- /dev/null +++ b/read-firmware @@ -0,0 +1,21 @@ +#!/bin/bash + +set -ex + +if [ $# = 0 ]; then + port=/dev/ttyUSB0 +else + port="$1"; shift +fi + +ad () { + avrdude -b 38400 -v -P $port -p atmega644P -c arduino "$@" +} + +args='' +for f in flash eeprom hfuse lfuse efuse; do + args+=" -U $f:r:firmware-$f.hex:i" +done + +ad "$@" +ad "$@" $args diff --git a/reprap-objects.make b/reprap-objects.make new file mode 100644 index 0000000..33e92d6 --- /dev/null +++ b/reprap-objects.make @@ -0,0 +1,86 @@ +# reprap-objects Makefile, reuseable parts +# +# Build scripts for various 3D designs +# Copyright 2012-2016 Ian Jackson +# +# This work 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 work 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 work. If not, see . + + +HRR=/home/reprap +SLIC3R=$(HRR)/Slic3r/bin/slic3r +M4=m4 +SKEINFORGE=python $(HRR)/reprappro-software.git/skeinforge/skeinforge_application/skeinforge_utilities/skeinforge_craft.py + +CWD := $(shell pwd) +PLAY ?= $(CWD) + +AUTO_TOPLEVELS := $(foreach m,$(USING_AUTOS),$(shell $(PLAY)/toplevel-find $m)) + +AUTO_INCS += funcs.scad + +default: autoincs scads + +$(shell set -xe; $(PLAY)/commitid.scad.pl >commitid.scad.tmp; cmp commitid.scad.tmp commitid.scad || mv -f commitid.scad.tmp commitid.scad ) + +autoincs: $(AUTO_INCS) $(AUTO_STLS_INCS) +scads: $(addsuffix .auto.scad, $(AUTO_TOPLEVELS)) +stls: $(addsuffix .auto.stl, $(AUTO_TOPLEVELS)) + +%.auto.scads: %.scad + $(MAKE) $(addsuffix .auto.scad, $(shell $(PLAY)/toplevel-find $*)) +%.auto.stls: + $(MAKE) $(addsuffix .auto.stl, $(shell $(PLAY)/toplevel-find $*)) + +-include .*.d + +%.stl: %.scad $(AUTO_INCS) + openscad -d .$@.d.tmp -o $*.tmp.stl $< + @rm -f $@ + @sed -e 's/\.tmp\.stl:/.stl:/' <.$@.d.tmp >.$@.d + @rm .$@.d.tmp + mv -f $*.tmp.stl $@ + +AUTOBASE=$(shell echo $(1) | perl -pe 's/,\w+\.auto$$//') + +%: %.cpp + cpp -nostdinc -P <$< >$@.tmp && mv -f $@.tmp $@ + +funcs.scad: + +#%.gcode: %.stl +# $(SKEINFORGE) $< + +%.gcode: manual-gcode-generator %.m-g + $(PLAY)/$^ >$@.tmp && mv -f $@.tmp $@ + +%.dxf: %.eps + pstoedit -dt -f "dxf: -polyaslines -mm" $< $@ + +%: %.pl + ./$< >$@.tmp && mv -f $@.tmp $@ + +%: %.m4 + $(M4) -P >$@.tmp $< && mv -f $@.tmp $@ + +.PRECIOUS: %.auto.scad +%.auto.scad: $(PLAY)/toplevel-make Makefile $(PLAY)/toplevel-find + @echo ' write $@' + $< $@ >$@.tmp + @mv -f $@.tmp $@ + +.PRECIOUS: %.stl %.gcode %.eps %.dxf + +clean: + rm -f *~ *.stl *.auto.scad *.gcode .*.d $(AUTO_INCS) + diff --git a/ring-tests.scad b/ring-tests.scad new file mode 100644 index 0000000..c3bd34f --- /dev/null +++ b/ring-tests.scad @@ -0,0 +1,43 @@ +// -*- C -*- + +thick = 3.5; +width = 5; + +centre_dia = 21; + +// calculated + +ellipse_width = width / 0.90; + +module Profile(){ + intersection(){ + scale([thick, ellipse_width]) circle(r=0.5, $fn=50); + square([thick*2, width], center=true); + } +} + +module Ring(dia){ + rotate_extrude($fn=100){ + translate([dia/2 + thick/2, 0]){ + Profile(); + } + } +} + +//Profile(); +//Ring(centre_dia); + +module Tests(){ + min_dia = 19; + max_dia = 22; + dia_step = .25; + n_dias = (max_dia - min_dia)/dia_step; + for (i= [ 0 : n_dias ]) { + echo(i); + rotate([0,0, i*360 / (n_dias+2)]) + translate([80,0,0]) + Ring(min_dia + (max_dia-min_dia)*(i/n_dias)); + } +} + +Tests(); diff --git a/rope-adjuster.scad b/rope-adjuster.scad new file mode 100644 index 0000000..fa4f591 --- /dev/null +++ b/rope-adjuster.scad @@ -0,0 +1,77 @@ +// -*- C -*- + +include + +hole_dia = 10; +around_hole = 4; +thick = 3; +lever_len = 50; + +teeth_n = 4; +teeth_bite = 4; +teeth_pitch = 4; +teeth_gap = 3; +teeth_back = 1; +teeth_height = 12; +teeth_chamfer = 3; + +// calculated + +teeth_x_mid = lever_len/2 - hole_dia/2 - teeth_bite - teeth_gap*1.5; +teeth_height_total = teeth_height + teeth_chamfer; + +module Circles(r) { + for (x = [-1,+1] * 0.5 * lever_len) { + translate([x, 0]) + circle(r); + } +} + +module Plan() { + difference(){ + hull(){ + Circles(hole_dia/2 + around_hole); + } + Circles(hole_dia/2); + translate([ teeth_x_mid - teeth_bite - teeth_back - teeth_gap - hole_dia/2, + 0 ]) + circle(hole_dia/2); + } +} + +module TeethPlan(){ + translate([ + teeth_x_mid, + -0.5 * teeth_n * teeth_pitch, + ]) { + for (m=[0,1]) { + mirror([m,0]) { + translate([ teeth_bite + teeth_gap/2, 0 ]) + rectfromto([ -0.1, 0 ], + [ teeth_back, teeth_n * teeth_pitch ]); + for (i= [ 0: teeth_n-1 ]) { + translate([teeth_gap/2, teeth_pitch*i]) + polygon([[ 0,0 ], + [ teeth_bite, 0 ], + [ teeth_bite, teeth_pitch ]]); + } + } + } + } +} + +module Adjuster(){ + linextr(0,thick) + Plan(); + difference(){ + linextr(thick - 0.1, thick + teeth_height_total) + TeethPlan(); + translate([ teeth_x_mid, 0, thick + teeth_height_total + 1]) + linextr_y_xz(-teeth_pitch * teeth_n, + +teeth_pitch * teeth_n) + rotate(45) + square(sqrt(2) * (teeth_gap/2 + teeth_chamfer + 1), center=true); + } +} + +Adjuster(); diff --git a/rpi-mount.scad b/rpi-mount.scad new file mode 100644 index 0000000..b1b9c12 --- /dev/null +++ b/rpi-mount.scad @@ -0,0 +1,46 @@ +// -*- C -*- + +include + +pi_board_gap = 0.5; +pi_board_support_z = 2; +pi_board_support_wall = 2; + +pi_sz = [ 66.0, 30.5 ] + pi_board_gap * [1,1]; + +pi_nom_sz = [ 65, 30 ]; +pi_nom_centres_in = 3.5; +pi_solder_side_gap = 1.5 * 2; +pi_screw_hole_dia = 2.3; +pi_screw_hole_wall = 2.3; + +pi_sz_z_incl_ribbon = 18.0; + +pi_mount_z_min = 1.75; +pi_mount_z_def = 2.50; + +// calculated, output + +function pi_ribbon_top_z(pi_mount_z= pi_mount_z_def) + = pi_mount_z + pi_sz_z_incl_ribbon; + +module PiMount(pi_mount_z= pi_mount_z_def){ + sxy = pi_nom_sz/2 - [1,1] * pi_nom_centres_in; + for (mx=[0,1]) mirror([mx,0,0]) for (my=[0,1]) mirror([0,my,0]) { + difference(){ + union(){ + linextr(-0.1, pi_mount_z + pi_board_support_z, convexity=1) + rectfromto( pi_nom_sz/2 - 2 * [1,1] * pi_nom_centres_in, + pi_sz/2 + [1,1] * pi_board_support_wall); + linextr(-0.1, pi_mount_z - pi_solder_side_gap, convexity=1) + translate(sxy) + square(center=true, pi_screw_hole_dia + pi_screw_hole_wall*2); + } + linextr(pi_mount_z, pi_mount_z + 5, convexity=1) + rectfromto(-[10,10], pi_sz/2); + translate( sxy ) + linextr(-1, pi_mount_z + 10, convexity=1) + circle(r= pi_screw_hole_dia/2); + } + } +} diff --git a/salter-scale-hook.scad b/salter-scale-hook.scad new file mode 100644 index 0000000..3a8cfa3 --- /dev/null +++ b/salter-scale-hook.scad @@ -0,0 +1,108 @@ +// -*- C -*- + +include + +rod_dia = 8+2; +thick = 8; +screw_dia = 3.5 + 0.75; +screw_head_dia = 8.2 + 1.0; +rod_offset = 14 + 2; +mainheight = 25; +width = 40; +rearthick = 4; +screw_head_depth = 2; + +// calculated + +d = rod_dia/2 + thick/2; +yminc = -d; +ymin = yminc-thick/2; +ymaxc = mainheight; +ymax = mainheight+thick/2; + +cutdepth = rod_offset - rod_dia/2 - rearthick; + +cut_z0 = screw_head_dia/2; +cut_z1 = width/2 - rearthick; + +cutslopez = cutdepth * 0.5; + +module C() { + circle(r = thick/2, $fn=30); +} + +module Profile() { + e = rod_offset; + hull(){ + translate([-d, 0]) C(); + translate([-d,-d]) C(); + } + difference(){ + rectfromto([-d,ymin], [e,0]); + circle(r= rod_dia/2, $fn=50); + } + hull(){ + for (y= [-d, +mainheight]) { + translate([d, y]) C(); + rectfromto([d, y-thick/2], [e, y+thick/2]); + } + } +} + +module CutProfile(){ + hull(){ + for (x = [rod_dia/2 + thick/2, 30]) { + for (y= [yminc,ymaxc] ) { + translate([x,y]) circle(r = (thick-rearthick)/2, $fn=20); + } + } + } +} + +module ProfileDemo(){ + Profile(); + color("red") translate([0,0,1]) CutProfile(); +} + +module Cut(less){ + translate([0,0, cut_z0 + less]) + linear_extrude(height = cut_z1 - cut_z0 - less*2) + CutProfile(); +} + +module ScrewHole(){ + xd = (screw_head_dia-screw_dia)/2; + translate([0,0,-50]) + cylinder(h=100, r= screw_dia/2, $fn=20); + hull(){ + translate([0,0,-xd]) + cylinder(h=1, r= screw_dia/2, $fn=50); + cylinder(h=20, r= screw_head_dia/2, $fn=50); + } +} + +module Hook(){ + difference(){ + translate([0,0, -width/2]) + linear_extrude(height=width) Profile(); + + for (m=[0,1]) { + mirror([0,0,m]) { + hull(){ + Cut(cutslopez); + translate([cutdepth,0,0]) Cut(0); + } + } + } + + translate([rod_dia/2 + screw_head_depth, + ymaxc - screw_head_dia, + 0]) { + rotate([0,-90,0]) + ScrewHole(); + } + } +} + +//ProfileDemo(); +Hook(); diff --git a/scaffold-clamp-cleat.scad b/scaffold-clamp-cleat.scad new file mode 100644 index 0000000..69e8538 --- /dev/null +++ b/scaffold-clamp-cleat.scad @@ -0,0 +1,13 @@ +// -*- C -*- + +// Per cleat print +// VCleatA OR VCleatA +// GeneralB VCleatA +// Pin Pin +// +// These bits are compatible with scaffold-clamp-tensioner + +//// toplevels-from: +include + +module DemoA(){ VCleatARaw(); } diff --git a/scaffold-clamp-common.scad b/scaffold-clamp-common.scad new file mode 100644 index 0000000..79ed1da --- /dev/null +++ b/scaffold-clamp-common.scad @@ -0,0 +1,489 @@ +// -*- C -*- + +include + +tube_dia = 48.3; + +th = 7; + +pin_gap = 1.5; // around + +smooth_r = 15; + +bolt_dia = 5; +bolt_flat = 10 + 1; + +nbolts = 2; + +open_gap = 10; + +hinge_unit = 10; +hinge_z_gap = 1; + +hinge_units = 4; + +bolt_gap = 1.0; // total, on both sides + +// ---------- vhook ---------- + +vhook_th = 14; + +// ---------- cleat ---------- + +cleat_frames = 10; +cleat_curve_r = 200; +cleat_horn_l = 40; +cleat_horn_d_min = [10, 12]; +cleat_horn_d_max = [12, 14]; +cleat_height = 25; +cleat_stem_l = 20; + +cleat_overlap = (1-cos(60)); + +// ---------- hhook ---------- + +hhook_inside = 40; +hhook_th = 4; +hhook_l = 40; + +// ---------- linear bracket ---------- + +linear_bracket_h = 50; +linear_bracket_l = 100; +linear_bracket_t = 15; +linear_bracket_hole_offset = 20; +linear_bracket_hole_dia = 5 + 1.00; + +// ========== defaults ========== + +pin_head_th = th/2; +pin_dia = th; +pin_hole_dia = pin_dia/2; +pin_tail = pin_hole_dia + pin_head_th + hinge_z_gap*3; + +// ========== calculated ========== + +TAU = PI*2; + +hole_dia = th + pin_gap; + +bolt_hole_r = (bolt_dia + bolt_gap)/2; + +main_r = tube_dia/2 + th; + +hinge_gap = pin_gap; + +hinge_o_r = 0.5 * hole_dia + th; + +hinge_x = -0.5 * tube_dia - hinge_o_r; +bolt_x = 0.5 * tube_dia + th + bolt_flat * 0.5; +max_x = bolt_x + max(bolt_hole_r + th, 0.5 * bolt_flat/2); + +flats_y = open_gap/2 + th; + +stride_z = hinge_unit*2 + hinge_z_gap*2; +total_z = hinge_units * stride_z - hinge_z_gap; + +min_z = -total_z/2; +max_z = +total_z/2; + +pin_flatten = pin_dia/2 * (1 - cos(45)); + +bolt_stride = total_z / nbolts; + +// calculated - vhook + +vhook_inside = 15; + +vhook_theta = atan2( smooth_r, main_r ); + +vhook_y0 = -max(main_r, (tube_dia/2 + vhook_th)); +vhook_ctr = vhook_y0 - vhook_inside/2; +vhook_outer_dia = vhook_inside + vhook_th*2; + +// calculated - cleat + +cleat_horn_tl = cleat_horn_l + cleat_stem_l/2; + +vcleat_dz = max(0, + cleat_horn_tl + + cleat_horn_d_min[0]/2 + - cleat_horn_d_min[0]/2 * cleat_overlap + - total_z/2 + ); + +// calculated - hhook + +hhook_outer_dia = hhook_inside + hhook_th*2; + +hhook_ctr = -max(main_r + hhook_inside/2, + tube_dia/2 + hhook_outer_dia/2); + +$fa = 3; +$fs = 0.1; + +module SmoothPlan(){ + offset(r=-smooth_r) offset(delta=smooth_r) children(0); +} + +module TubePlan(){ circle(r = tube_dia/2); } +module MainCirclePlan(){ circle(r = main_r); } + +module PlanWeldMainCircle(){ + intersection(){ + difference(){ + SmoothPlan(){ + union(){ + MainCirclePlan(); + children(0); + } + } + TubePlan(); + } + rotate(-135) square(100); + } +} + +module MainPlan(flatten=false) { + difference(){ + SmoothPlan() + union(){ + translate([hinge_x, 0]) circle(r= hinge_o_r); + MainCirclePlan(); + rectfromto([0, -flats_y], + [max_x, +flats_y]); + } + TubePlan(); + rectfromto([0, -open_gap/2], + [max_x+1, +open_gap/2]); + translate([hinge_x, 0]) { + intersection(){ + circle(r= hole_dia/2); + if (flatten) + translate([ pin_flatten, 0 ]) + square(center=true, [hole_dia, hole_dia + 1]); + } + } + } +} + +module Portion(d=0) { + translate([hinge_x, 0]) circle(r= hinge_o_r + d); + rectfromto([hinge_x*2, 0], + [max_x+10, -(tube_dia/2+th+10)]); +} + +module MainPlanA(flatten){ + intersection(){ + MainPlan(flatten); + Portion(0); + } +} + +module MainPlanB(flatten){ + difference(){ + MainPlan(flatten); + Portion(hinge_gap); + } +} + +module HalfClampXPositive(flatten=false){ + translate([0,0, min_z]) { + linextr(0, total_z) mirror([0,1]) MainPlanB(); + for (i=[0 : hinge_units-1]) { + translate([0,0, stride_z*i]) + linextr(0, hinge_unit) MainPlanA(flatten); + } + } +} + +module HalfClampXNegative(){ + for (j=[0:nbolts-1]) { + translate([ bolt_x, 0, min_z + (j + 0.5) * bolt_stride ]) { + translate([0, -tube_dia/2, 0]) + rotate([-90,0,0]) + cylinder(r= bolt_hole_r, h= tube_dia); + translate([0, -flats_y, 0]) + rotate([90,0,0]) + cylinder(r= bolt_flat/2, h= tube_dia/2); + } + } +} + +module HalfClampX(flatten=false){ + difference(){ + HalfClampXPositive(flatten); + HalfClampXNegative(); + } +} + +// ---------- vhook ---------- + +module VHookProfile() { + translate([0, -vhook_inside/2 - vhook_th/2]) + circle(r = vhook_th/2); +} + +module VHookHookMain(outer=false){ ////toplevel + rotate([0,90,0]) + rotate_extrude(convexity=10) + rotate([0,0,90]) + hull(){ + VHookProfile(); + if (outer) { + translate([0,-vhook_outer_dia]) square(center=true, vhook_th); + } + } +} + +module VHookA(){ ////toplevel + DummyA(); + + translate([0, vhook_ctr, 0]){ + for (m=[0,1]) { + mirror([0, m, 0]) { + linextr(-0.1, vhook_outer_dia/2) + VHookProfile(); + translate([0, -vhook_inside/2 -vhook_th/2, vhook_outer_dia/2]) + sphere(r= vhook_th/2); + } + } + + intersection(){ + VHookHookMain(outer=true); + linextr_y_xz(0, vhook_outer_dia/2) hull(){ + VHookProfile(); + translate([0,-0.1]) square(center=true, [vhook_th, 0.2]); + } + } + + intersection(){ + VHookHookMain(); + translate([0,0, -vhook_outer_dia]) + cube(center=true, vhook_outer_dia*2); + } + } + + //translate([0, vhook_y0, 50]) rotate([0,0,-90]) color("black") cube(10); + // translate([0,0,-150]) rotate([0,0,180 + theta]) color("blue") cube(100); +} + +module VHookPlanDemo(){ + MainPlanA(); + translate([0, vhook_ctr, 5]) + for (m=[0,1]) { + mirror([0,m]) + color("blue") VHookProfile(); + } +} + +// ---------- cleat ---------- + +function cleat_frame_theta(s) = s * cleat_horn_tl / cleat_curve_r * 360/TAU; +function cleat_frame_z(s) = cleat_curve_r * (1 - cos(cleat_frame_theta(s))); +function cleat_frame_x(s) = cleat_curve_r * sin(cleat_frame_theta(s)); +function cleat_frame_r(s) = ( cleat_horn_d_min * s + + cleat_horn_d_max * (1-s) ) * 0.5; + +module CleatFrameSphere(r) { + scale([1, r[1]/r[0], 1]) + sphere(r= r[0]); +} + +module CleatFrame(s) { + r = cleat_frame_r(s); + translate([cleat_frame_x(s), 0, cleat_frame_z(s)]) + rotate([0, 90, 0]) + CleatFrameSphere(r); +} + + +module CleatHorn(){ + for (si=[0 : cleat_frames-2]) { + s0 = si / (cleat_frames-1); + s1 = (si+1) / (cleat_frames-1); + hull(){ + CleatFrame(s0); + CleatFrame(s1); + } + } +} + +module CleatBase(){ + frames = cleat_frames/2; + se = cleat_stem_l/2 / cleat_horn_tl; + r = cleat_frame_r(se); + + hull(){ + for (s = [-se, se]) { + for (z= [-(cleat_height + tube_dia/2), + cleat_frame_z(s)]) { + translate([cleat_frame_x(s), 0, z]) + linear_extrude(height=0.1) + scale([1, r[1]/r[0]]) + circle(r=r[0]); + } + } + } +} + +module VCleat(){ + intersection(){ + translate([0,0, vcleat_dz]){ + difference(){ + translate([0, -(main_r + cleat_height), 0]) { + rotate([0, -90, 90]) { + CleatBase(); + for (m=[0,1]) { + mirror([m,0,0]) { + CleatHorn(); + } + } + } + } + linextr(-cleat_stem_l, +cleat_stem_l) + circle(r = tube_dia/2 + 0.1); + } + } + translate([0,0, total_z * 0.5]) + cube(center=true, + (main_r + cleat_stem_l)*4 * [1,1,0] + + total_z * [0,0,2]); + } +} + +module VCleatA(){ ////toplevel + DummyA(); + VCleat(); +} + +// ---------- hhook ---------- + +module HHookHookPlan(){ + translate([0, hhook_ctr]){ + difference(){ + circle(r = hhook_outer_dia/2); + circle(r = hhook_inside/2); + rectfromto([+hhook_outer_dia, -hhook_outer_dia], + [0, +hhook_outer_dia]); + } + translate([0, -(hhook_inside/2 + hhook_th/2)]){ + hull(){ + for (x=[-0.1, hhook_l]) { + translate([x,0]) square(center=true, hhook_th); + } + } + } + } +} + +module HHookA(){ ////toplevel + DummyA(); + linextr(min_z, max_z) { + HHookHookPlan(); + } +} + +module HHookPlanDemo(){ + MainPlanA(); + HHookHookPlan(); +} + +// ---------- linear bracket ---------- + +module LinearBracketA(){ ////toplevel + difference(){ + union(){ + HalfClampXPositive(); + mirror([1,0,0]) + linextr_y_xz(-open_gap/2 - linear_bracket_t, -open_gap/2) + rectfromto([0, min_z], + [max_x + linear_bracket_l, min_z + linear_bracket_h]); + } + HalfClampXNegative(); + linextr(-1000,1000) + TubePlan(); + mirror([1,0,0]) + linextr_y_xz(-100,100) { + for (t = [ + [1,1] * linear_bracket_hole_offset, + -[1,1] * linear_bracket_hole_offset + + [linear_bracket_l, linear_bracket_h] + ]) { + translate([ max_x, min_z ] + t) + circle(r= linear_bracket_hole_dia/2); + } + } + } +} + +// ---------- misc ---------- + +module PinSitu(){ ////toplevel + difference(){ + union(){ + translate([0,0, -pin_head_th]) + cylinder(r= pin_dia/2, h = total_z + pin_head_th + pin_tail); + mirror([0,0,1]) + cylinder(r= hinge_o_r - pin_gap, h = pin_head_th); + } + translate([0,0, total_z + pin_tail/2]) + rotate([0,90,0]) + translate([0,0, -pin_dia]) + cylinder(r= pin_hole_dia/2, h=pin_dia*2); + translate([pin_dia/2 * cos(45), -50, -pin_head_th*2]) + cube([50,100, total_z*2]); + } +} + +module Pin(){ ////toplevel + rotate([0,90,0]) { + PinSitu(); + } +} + +module GeneralB(){ ////toplevel + HalfClampX(true); +} + +module DummyA(){ ////toplevel + HalfClampX(); +} + +module PlanDemo(){ ////toplevel + MainPlan(); + translate([0,0,-4]) color("red") Portion(1); + translate([0,0,-2]) color("grey") Portion(0); + + translate([0, tube_dia*1.5]) { + MainPlanB(); + MainPlanA(); + } + + translate([0, -tube_dia*1.5]) { + VHookPlanDemo(); + } + translate([tube_dia*4, 0]) { + HHookPlanDemo(); + } +// translate([max_x - hinge_x + 20, 0]) color("blue") MainPlanA(); +} + +module DemoA(){ DummyA(); } + +module Demo(){ ////toplevel + color("red") rotate([180,0,0]) GeneralB(); + color("blue") DemoA(); + color("orange") translate([hinge_x, 0, min_z - hinge_z_gap]) + rotate([0,0,180]) PinSitu(); +} + +module DemoPair(){ ////toplevel + color("red") rotate([180,0,0]) DemoA(); + color("blue") DemoA(); + color("orange") translate([hinge_x, 0, min_z - hinge_z_gap]) + rotate([0,0,180]) PinSitu(); +} + +//PlanDemo(); +//HalfClamp(); diff --git a/scaffold-clamp-linear-bracket.scad b/scaffold-clamp-linear-bracket.scad new file mode 100644 index 0000000..a5fbe24 --- /dev/null +++ b/scaffold-clamp-linear-bracket.scad @@ -0,0 +1,11 @@ +// -*- C -*- + +// Per linear bracket print +// LinearBracketA +// GeneralB +// Pin + +//// toplevels-from: +include + +module DemoA(){ LinearBracketA(); } diff --git a/scaffold-clamp-straphook.scad b/scaffold-clamp-straphook.scad new file mode 100644 index 0000000..1804be9 --- /dev/null +++ b/scaffold-clamp-straphook.scad @@ -0,0 +1,22 @@ +// -*- C -*- + +// Per gym ring strap retainer print +// HHookA +// GeneralB +// Pin + +//// toplevels-from: +include + +th = 3; +hhook_th = 3; +hinge_units = 2; +nbolts = 1; +hinge_unit = 5; +bolt_dia = 3; +bolt_flat = 7 + 1; + +hhook_inside = 35; +hhook_l = 50; + +module DemoA(){ HHookA(); } diff --git a/scaffold-clamp-tensioner.scad b/scaffold-clamp-tensioner.scad new file mode 100644 index 0000000..6207dfb --- /dev/null +++ b/scaffold-clamp-tensioner.scad @@ -0,0 +1,11 @@ +// -*- C -*- + +// Per tensioner print +// VHookA +// GeneralB +// Pin + +//// toplevels-from: +include + +module DemoA(){ VHookA(); } diff --git a/screw-recess-test-number.fig.pl b/screw-recess-test-number.fig.pl new file mode 100755 index 0000000..023b315 --- /dev/null +++ b/screw-recess-test-number.fig.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl + +my $number = shift @ARGV; +die unless $number =~ m/^\d+$/; + +my $fontsz = $number * 6 + 12; + +print <= 0 ? recessdepth_arg : -recessdepth_arg * recessdia; + +function RecessedScrewCutout_totaldepth(recessdia, + recessdepth_arg=RecessedScrewCutout_defaultrecessdepth_flat) = + RecessedScrewCutout_recessdepth(recessdia, recessdepth_arg) + + + 0.5*recessdia + 0.1; + +module RecessedScrewCutout(shaftdia, recessdia, shaftlen, + zbelow=1, + recessdepth_arg=RecessedScrewCutout_defaultrecessdepth_flat) { + // pass recessdepth_arg=-1 for the default for flat heads + // pass recessdepth_arg=-1 for the default for flat heads + recessdepth = RecessedScrewCutout_recessdepth(recessdia, recessdepth_arg); + recesstopz = RecessedScrewCutout_totaldepth(recessdia, recessdepth_arg); + + translate([0,0,-zbelow]) cylinder(r=shaftdia/2, h=shaftlen+zbelow, $fn=20); + RecessScrewCutout_RecessCylinder(recessdia,zbelow, recessdepth); + intersection(){ + cube([recessdia + 1, shaftdia + 0.1, recesstopz*2 + 1], center=true); + translate([0, -recessdia, recesstopz]) + rotate([0,135,0]) cube([recessdia, recessdia*2, 10]); + RecessScrewCutout_RecessCylinder(recessdia,zbelow, recesstopz+1); + } +} + +// nom. shaft +// shaft slop +screw_info_M2 = [2, 1.2]; +screw_info_M3 = [3, 1.2]; +screw_info_M4 = [4, 1.1]; +screw_info_M5 = [5, 1.0]; +screw_info_M6 = [6, 1.2]; + +function screw_shaft_dia_nom(info) = info[0]; +function screw_shaft_dia_use(info) = info[0] + info[1]; +function screw_recess_dia_use(info) = info[0] * 2.50 + 1.0; +function screw_recess_depth(info) = info[0] * 1.00 + 0.50; +function screw_recess_depth_allen(info) = info[0] * 1.55 + 0.50; + +function RecessedScrewCutoutStandard_totaldepth(info) = + RecessedScrewCutout_totaldepth(screw_recess_dia_use(info), + screw_recess_depth(info)); + +function RecessedScrewCutoutStandardAllen_totaldepth(info) = + RecessedScrewCutout_totaldepth(screw_recess_dia_use(info), + screw_recess_depth_allen(info)); + +module RecessedScrewCutoutStandard(info, shaftlen, zbelow=1) { + RecessedScrewCutout(screw_shaft_dia_use(info), + screw_recess_dia_use(info), + shaftlen, zbelow, + screw_recess_depth(info)); +} + +module RecessedScrewCutoutStandardAllen(info, shaftlen, zbelow=1) { + RecessedScrewCutout(screw_shaft_dia_use(info), + screw_recess_dia_use(info), + shaftlen, zbelow, + screw_recess_depth_allen(info)); +} + +tests = [ + screw_info_M2, + screw_info_M3, + screw_info_M4, +2 screw_info_M5, + screw_info_M6 + ]; + +function Test_blocksz(t) = screw_recess_dia_use(t) + 7; + +module OneTestCore(t, h, ymul, labelnumber=false){ + blocksz = Test_blocksz(t); + translate([0, ymul * (blocksz*0.5 - 1.5), 0]) { + difference(){ + translate([-blocksz/2, -blocksz/2, 0]) + cube([blocksz, blocksz, h]); + child(); + } + if (labelnumber) { + rotate([90,0,0]) + translate([-blocksz/4,blocksz/5, blocksz/2-1]) + linear_extrude(height=0.3+1) + import(file=str("screw-recess-test-number-s",t[0],".dxf"), convexity=100); + } + } +} + +module OneTest(t){ + h = RecessedScrewCutoutStandard_totaldepth(t) + 3; + ha = RecessedScrewCutoutStandardAllen_totaldepth(t) + 3; + OneTestCore(t, h, 1){ + RecessedScrewCutoutStandard(t, h+1); + } + OneTestCore(t, ha, -1, true){ + RecessedScrewCutoutStandardAllen(t, ha+1); + } +} + +function Test_x(i) = i<=0 ? 0 : + Test_x(i-1) + Test_blocksz(tests[i-1])/2 + Test_blocksz(tests[i])/2 - 3; + +module Tests(){ + for (i = [0:len(tests)-1]) { + echo(i, Test_x(i)); + translate([Test_x(i), 0, 0]) + OneTest(tests[i]); + } +} + +//OneTest(tests[1]); +Tests(); +//Hole(); +//Holes(); diff --git a/sealing-box.scad.m4 b/sealing-box.scad.m4 new file mode 100644 index 0000000..dbfb220 --- /dev/null +++ b/sealing-box.scad.m4 @@ -0,0 +1,180 @@ +// -*- C -*- + +// This file can be used in two ways: +// +// A. Rectangular boxes +// 1. include +// 2. assign() values to (xxx these should be $ variables) +// $sealingbox_wallth +// $sealingbox_sz[0] (outer dimension) +// $sealingbox_sz[1] (outer dimension) +// $sealingbox_sz[2] (inner dimension) +// $sealingbox_ceilth +// $sealingbox_floorth +// $sealingbox_wallth +// 3. use the modules +// SealingBox_RectBox +// SealingBox_RectLid +// (origin is notional outside corner, but at level of +// inside of base; box extends to positive x,y,z) +// +// B. Complicated shapes, but harder work +// 1. Be a .m4 file and m4_include sealing-box.scad.m4 +// 2. Define your own BoxDoShapeSomething like BoxDoShapeRect +// 3. Invoke BoxUseShape +// 4. Use the Box and Lid modules generated +// +// Other settings +// $sealingbox_cnrrad + +$sealingbox_cnrrad = 10; +$sealingbox_crude = false; +$sealingbox_inner_slop = 0.2; + +m4_define(`BoxLocals',` + xbox = $sealingbox_sz[0]; + ybox = $sealingbox_sz[1]; + zbox = $sealingbox_sz[2]; + wall = $sealingbox_wallth; + floorth = $sealingbox_floorth; + ceilth = $sealingbox_ceilth; + cnrrad = $sealingbox_cnrrad; + + xbox_lin = xbox - cnrrad*2; + ybox_lin = ybox - cnrrad*2; +') + +m4_define(`innertube', `(1.0 + 0.2)') +m4_define(`lidoverlap', `1.5') +m4_define(`lidoverhang', `6') +m4_define(`tubesealrad', `2.0') + +m4_define(`BoxFn',`$fn= $sealingbox_crude ? ($2) : ($1)') + +m4_dnl Box_Part($1=transl_x,$2=transl_y, $3=rot_z,$4=mirror_xy) +m4_dnl $5=kind, $6=kindargs, $7=profile(profileargsargs)) +m4_define(`Box_Part',` + translate([($1),($2)]) + rotate([0,0,($3)]) + mirror([($4),0,0]) + BoxPart_Extrude_$5($6, $7)') m4_dnl + +boxpart_d = 0.01; + +m4_dnl BoxPart_Extrude_Linear(dist, `profile(...);'); +m4_define(`BoxPart_Extrude_Linear',` + rotate([90,0,0]) + translate([0,0, -($1)]) + linear_extrude(height= boxpart_d + ($1)) { + $2 + } +') + +m4_dnl BoxPart_Extrude_Arc(x0_radius, swept_angle, `profile(...);') +m4_dnl arc starting at transl_x, transl_y, moving towards positive +m4_dnl y at first and then bending towards negative x, until +m4_dnl use negative x0_radius to inciate bending towards positive x +m4_dnl swept_angle is reached +m4_dnl x0_radius is the radius of the extruded part at x=0, not of the box +m4_define(`BoxPart_Extrude_Arc',` + translate([-($1),0,0]) + intersection(){ + translate([0,0,-500]) + linear_extrude(height=1000) + scale(500) + mirror([($1)<0, 0,0]) + FArcSegment_mask($2); + rotate_extrude(convexity=10, $fs=1, BoxFn(36,8)) + mirror([($1)<0, 0,0]) + translate([+($1),0,0]){ + $3 + } + } +') + +m4_dnl BoxDoShapeRect(`profile(profileargs)'); +m4_define(`BoxDoShapeRect',` + Box_Part(0, cnrrad, 0,0, Linear,`ybox_lin', `$1' ) + Box_Part(0, ybox-cnrrad, 0,0, Arc,`-cnrrad,90' , `$1' ) + Box_Part(cnrrad, ybox, -90,0, Linear,`xbox_lin', `$1' ) + Box_Part(xbox-cnrrad, ybox, -90,0, Arc,`-cnrrad,90' , `$1' ) + Box_Part(xbox, ybox-cnrrad, -180,0, Linear,`ybox_lin', `$1' ) + Box_Part(xbox, cnrrad, -180,0, Arc,`-cnrrad,90' , `$1' ) + Box_Part(xbox-cnrrad, 0, -270,0, Linear,`xbox_lin', `$1' ) + Box_Part(cnrrad, 0, -270,0, Arc,`-cnrrad,90' , `$1' ) +') + +m4_dnl ' + +module SealingBox_WallProfile(){ + BoxLocals + z = zbox - innertube - tubesealrad; + translate([0, -0.1]) square([wall, z]); + translate([tubesealrad, z]) circle(r=tubesealrad, BoxFn(20,6)); +} + +module SealingBox_FloorProfile(){ + BoxLocals + mirror([0,1]) square([wall, floorth]); +} + +function SealingBox_lidbigger() = lidoverlap + innertube; + +module SealingBox_LidProfile(){ + BoxLocals + rad = tubesealrad + innertube; + morex = wall; + inner_buttress_h = tubesealrad*1.5 + innertube + ceilth; + + difference(){ + translate([0, zbox + ceilth]) mirror([0,1]) { + translate([-SealingBox_lidbigger(), + 0]) + square([lidoverlap + innertube + tubesealrad, + lidoverhang + innertube + ceilth]); + square([tubesealrad*2 + innertube + lidoverlap, + inner_buttress_h]); + } + hull(){ + translate([tubesealrad, + zbox - innertube - tubesealrad]) + for (t=[ [0,0], + [0, -zbox] + ]) { + translate(t) + circle(r= tubesealrad + innertube, BoxFn(20,6)); + } + } + } + translate([tubesealrad*2 + $sealingbox_inner_slop, + zbox + ceilth]) { + mirror([0,1]) { + square([lidoverlap + innertube, + inner_buttress_h]); + } + } +} + +module SealingBox_CeilProfile(){ + BoxLocals + translate([0, zbox]) + square([wall*2, ceilth]); +} + +// BoxDoShape(Basename,BoxDoShapeSomething) +// generates modules BasenameBox and BasenameLid +m4_define(`BoxUseShape',` + module $1Box(){ + BoxLocals + $2(SealingBox_WallProfile();); + hull(){ $2(SealingBox_FloorProfile();); } + } + + module $1Lid(){ + BoxLocals + $2(SealingBox_LidProfile();); + hull(){ $2(SealingBox_CeilProfile();); } + } +') + +BoxUseShape(`SealingBox_Rect',`BoxDoShapeRect') diff --git a/secateurs-clip.scad b/secateurs-clip.scad new file mode 100644 index 0000000..bdb008d --- /dev/null +++ b/secateurs-clip.scad @@ -0,0 +1,22 @@ +// -*- C -*- + +l = 47; +d = 18; + +w = 15; +t = 10; +te = 7; + +linear_extrude(height=15, convexity=4) { + for (m=[0,1]) { + mirror([m,0]) { + polygon([[ -1, 0 ], + [ -1, -t ], + [ l/2+te, -t ], + [ l/2+te, d ], + [ l/2, d ], + [ l/2, 0 ], + ]); + } + } +} diff --git a/sewing-table-end-profile-photo.jpg b/sewing-table-end-profile-photo.jpg new file mode 100644 index 0000000..73f3a20 Binary files /dev/null and b/sewing-table-end-profile-photo.jpg differ diff --git a/sewing-table-end-profile.fig b/sewing-table-end-profile.fig new file mode 100644 index 0000000..2250e94 --- /dev/null +++ b/sewing-table-end-profile.fig @@ -0,0 +1,29 @@ +#FIG 3.2 Produced by xfig version 3.2.6a +Landscape +Center +Metric +A4 +100.00 +Single +-2 +1200 2 +2 5 0 1 0 -1 60 -1 -1 0.000 0 0 -1 0 0 5 + 0 sewing-table-end-profile-photo.jpg + 2655 6615 23743 6615 23743 12787 2655 12787 2655 6615 +2 1 0 1 1 7 50 -1 -1 0.000 0 0 -1 0 0 2 + 3780 10170 22635 9990 +2 1 0 2 9 7 50 -1 -1 0.000 0 0 -1 0 0 2 + 22671 9881 22587 6522 +2 1 0 3 14 7 50 -1 -1 0.000 0 0 -1 0 0 2 + 3780 8137 22635 7957 +2 1 0 2 9 7 50 -1 -1 0.000 0 0 -1 0 0 2 + 4090 9278 4034 6610 +2 2 0 2 28 7 50 -1 -1 0.000 0 0 -1 0 0 5 + 1818 8008 5248 8008 5248 14648 1818 14648 1818 8008 +3 1 0 1 6 7 40 -1 -1 0.000 0 0 0 17 + 8544 8080 12341 8071 16290 7965 19845 7830 22214 7727 22560 7582 + 22605 7370 22539 6869 22548 6611 12555 4725 4252 5873 4101 6534 + 4052 7107 4047 7674 4058 7812 4323 7950 4864 8005 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 diff --git a/sewing-table-front-profile-photo.jpg b/sewing-table-front-profile-photo.jpg new file mode 100644 index 0000000..d0dd7f1 Binary files /dev/null and b/sewing-table-front-profile-photo.jpg differ diff --git a/sewing-table-front-profile.fig b/sewing-table-front-profile.fig new file mode 100644 index 0000000..d318174 --- /dev/null +++ b/sewing-table-front-profile.fig @@ -0,0 +1,26 @@ +#FIG 3.2 Produced by xfig version 3.2.6a +Landscape +Center +Metric +A4 +100.00 +Single +-2 +1200 2 +2 5 0 1 0 -1 60 -1 -1 0.000 0 0 -1 0 0 5 + 0 sewing-table-front-profile-photo.jpg + 2250 2115 14794 2115 14794 8172 2250 8172 2250 2115 +2 2 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 5 + 5311 3627 1892 3627 1892 8634 5311 8634 5311 3627 +2 1 0 1 1 7 50 -1 -1 0.000 0 0 -1 0 0 2 + 3455 7525 12541 7946 +3 1 0 1 28 7 40 -1 -1 0.000 0 0 0 25 + 5678 3664 4889 3652 4306 3643 3820 3620 3256 3600 2800 3591 + 2416 3574 3055 1515 11023 1659 11041 2606 10905 2752 10663 2946 + 10504 3060 10304 3176 10113 3305 9859 3397 9581 3493 9306 3565 + 8734 3613 8367 3618 7996 3636 7520 3639 7119 3651 6713 3663 + 6299 3670 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 diff --git a/sewing-table-jig.scad b/sewing-table-jig.scad new file mode 100644 index 0000000..9302119 --- /dev/null +++ b/sewing-table-jig.scad @@ -0,0 +1,21 @@ +//// toplevels-from:sewing-table.scad +include + +JIG = true; + +tile_th=0.8; +interlock_dia=5; + +jig_pencil_rad = 1; +jig_pencil_slotlen = 10; +jig_min_th = 0.3; +jig_post_hole_slop = 0.5; + +test_tile_th = -0.1; + +test_edge = interlock_dia * 0.5 + interlock_fine + 2; +round_edge_rad = tile_th/2; +frontcurve_z_slop = 15; +rearcurve_z_slop = 20; + +interlock_fine = tile_th/8; diff --git a/sewing-table-rear-profile-photo.jpg b/sewing-table-rear-profile-photo.jpg new file mode 100644 index 0000000..34bf64d Binary files /dev/null and b/sewing-table-rear-profile-photo.jpg differ diff --git a/sewing-table-rear-profile.fig b/sewing-table-rear-profile.fig new file mode 100644 index 0000000..3a6af71 --- /dev/null +++ b/sewing-table-rear-profile.fig @@ -0,0 +1,28 @@ +#FIG 3.2 Produced by xfig version 3.2.6a +Landscape +Center +Metric +A4 +100.00 +Single +-2 +1200 2 +2 2 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 5 + 3255 -6357 -7303 -6357 -7303 18013 3255 18013 3255 -6357 +2 1 0 1 1 7 50 -1 -1 0.000 0 0 -1 0 0 2 + -2808 6102 -1101 12715 +2 5 0 1 0 -1 60 -1 -1 0.000 0 0 -1 0 0 5 + 0 sewing-table-rear-profile-photo.jpg + 11014 -9675 -5445 -9675 -5445 16370 11014 16370 11014 -9675 +2 1 0 1 14 7 50 -1 -1 0.000 0 0 -1 0 0 2 + -536 -9216 -5067 1826 +3 1 0 1 28 7 40 -1 -1 0.000 0 0 0 26 + 3330 -6390 1755 -5895 495 -5310 -630 -4590 -1440 -3825 -2115 -2790 + -2745 -1710 -3240 -450 -3555 990 -3555 2430 -3420 3780 -2970 5625 + -2610 6930 -2205 8415 -1890 9630 -1485 11160 -1125 12690 -855 14085 + -90 16020 14715 9630 9855 -6975 9270 -8550 8685 -8010 7200 -7560 + 5985 -7200 4365 -6660 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 diff --git a/sewing-table-test.scad b/sewing-table-test.scad new file mode 100644 index 0000000..14b83b9 --- /dev/null +++ b/sewing-table-test.scad @@ -0,0 +1,15 @@ +//// toplevels-from:sewing-table.scad +include +TEST = true; +test_tile_th = 0.67; +test_edge = interlock_dia * 0.5 + interlock_fine + 2; + +leg_n_fins = 2; + +leg_top_thick = 3; +leg_bot_thick = 4; +leg_top_flat_z = 0.5; +leg_fin_top_w = 2; +leg_fin_bot_w = 3; +leg_fin_bot_rad = 15; +leg_bot_mid_dia = 9; diff --git a/sewing-table.scad.m4 b/sewing-table.scad.m4 new file mode 100644 index 0000000..b71e041 --- /dev/null +++ b/sewing-table.scad.m4 @@ -0,0 +1,1193 @@ +// -*- C -*- + +include +include + +ply_th = 18; +ply_hole_dia = 15; +ply_edge_min = 10; + +ply_hole_dia_real = 12; + +tile_th = 3; +post_dia = 8; + +post_shorter = 1; + +$screw_dia = 3.2; +screw_big_dia = 3.6; +screw_big_len = 4.0; + +round_edge_rad = 2.0; + +round_cnr_rad = 10; + +interlock_dia = 10; +interlock_fine = 0.66; + +interlock_fine_slope = 1.0; +interlock_fine_lenslop = 1.0; + +demo_slop = 0.1; + +leg_height = 53.75 - 0.95; + +leg_hole_dia = 5 + 0.75; +leg_big_dia = 37; +leg_bot_dia = 15; +leg_top_flat_z = 2; +leg_top_thick = 8; + +leg_midspc_dia = 20; +leg_bot_thick = 8; +leg_bot_mid_dia = 12; + +leg_fin_top_w = 3; +leg_fin_bot_w = 5; +leg_fin_bot_rad = 30; +leg_fin_bot_flat_z = 5; + +leg_n_fins = 4; +leg_n_tubules = 4; +leg_tubule_dia = 4; + +// spacer + +spacer_ext_slop = 0.25; +spacer_int_slop = 0.25; +spacer_height = 10; + +// cutout + +machine_rear_to_front = 84 + 0.25 - 1.4; + +cutout_l_end_y_front_slop = 0.5; +cutout_l_end_y_rear_slop = 0.5; + +cutout_l_end_x = 22; +cutout_l_end_y = machine_rear_to_front; +cutout_l_end_new_x_slop = 1.4 - 1.95; +cutout_l_end_y_total = cutout_l_end_y + + cutout_l_end_y_front_slop + cutout_l_end_y_rear_slop; + +tile02_tr = [-250, 0]; +tile01_tr = [ 0, 0]; + +cutout_tile01_y = 170 - 147 + cutout_l_end_y_front_slop; +cutout_tile11_y = cutout_l_end_y_total - cutout_tile01_y; + +// front and rear curves + +rearedge_len = 170 + 0.70; +frontedge_len = 170; + +rearcurve_strt_len = 52; + +rearcurve_z_slop = -0.50; + +rearcurve_avoid_y = 35; + +rearcurve_double_inrad = 26.10 + 8.04; + +reartablet_z = 2.54; +reartablet_x = 5 + 1; +reartablet_y = 8; + +frontcurve_side_skew = 3.5 / 72; +frontcurve_avoid_y = 70; +frontcurve_z_slop = 0.75; + +frontcurve_strt_len = 50; +frontcurve_dualcurve_angle = 30; + +teststrapslots_at = [ [ 110, 70 ], [ 110, -35 ], + [ 180, 90 ], + [ 190, -80 ], // do not change index of this one + [ 0, 70 ], [ 0, -35 ], + ]; + +teststrap = [ 3, 5 ]; +teststrap_peg = [7.5, 3.5]; + +ply_edge_hole_dist_real = 14; + +// calculated + +TEST = false; +JIG = false; + +ply_edge_hole_dist = ply_edge_min + ply_hole_dia/2; + +echo(str("HOLES IN PLY ctr dist from PLY edge = ", ply_edge_hole_dist)); + +hole_slop = (ply_hole_dia - post_dia)/2; +tile_hard_edge_hole_dist = ply_edge_hole_dist + hole_slop; + +echo(str("HOLES IN PLY ctr dist from TILE HARD edge = ", + tile_hard_edge_hole_dist)); + +echo(str("HOLES IN PLY ctr dist from TILE ROUND edge = ", + tile_hard_edge_hole_dist + round_edge_rad)); + +thehd = [ tile_hard_edge_hole_dist, tile_hard_edge_hole_dist ]; +thehd_tr = thehd; +thehd_tl = [ -thehd_tr[0], thehd_tr[1] ]; +thehd_bl = -thehd_tr; +thehd_br = -thehd_tl; + +tablet_z_slop = 1.00; + +interlock_rad = interlock_dia/2; +interlock_negative_rad = interlock_rad + 0.125; + +interlock_sq_adj = 0.2; // arbitrary + +leg_fin_top_rad = sqrt( pow(leg_big_dia/2,2) - + pow(leg_fin_top_w/2,2) ); + +leg_tubule_pos_rad = leg_big_dia/2 * 0.6; + +m4_define(`POST_TCROSSSZ', + `2*( tile_hard_edge_hole_dist - test_edge + 1 )') + +module Post(){ + mirror([0,0,1]) { + if (!JIG) { + difference(){ + cylinder(r= post_dia/2, h= tile_th + ply_th - post_shorter); + translate([0,0, tile_th]) { + cylinder(r= screw_big_dia/2, h= screw_big_len); + cylinder(r= $screw_dia/2, h= ply_th, $fn=20); + } + } + } + if (TEST) { + translate([0,0, tile_th/2]) { + cube([post_dia, POST_TCROSSSZ, tile_th], center=true); + cube([POST_TCROSSSZ, post_dia, tile_th], center=true); + } + } + if (JIG) { + translate([0,0, tile_th/2]) { + cube([POST_TCROSSSZ, POST_TCROSSSZ, tile_th], center=true); + } + } + } +} + +module PostHole(){ + if (JIG) { + translate([0,0,-5]) + cylinder(r= post_dia/2 + jig_post_hole_slop, h=10); + translate([0,0, -jig_min_th]) + cylinder(r= ply_hole_dia_real/2, h = 5); + for (rot=[0:90:270]) rotate(rot) { + translate([ ply_edge_hole_dist_real, 0, 0 ]) + cube([ jig_pencil_rad*2, jig_pencil_slotlen, 20 ], center=true); + } + } +} + +module Posts(posts) { + for (p= posts) { + translate(concat(p, [0])) + Post(); + } +} +module PostHoles(posts) { + for (p= posts) { + translate(concat(p, [0])) + PostHole(); + } +} + +module TileBase(botleft, topright){ + size = topright - botleft; + botleft_post = botleft + thehd_tr; + topright_post = topright + thehd_bl; + difference(){ + mirror([0,0,1]) + translate(concat(botleft, [0])) + cube(concat(size, [tile_th])); + if (!(TEST || JIG)) { + cidsz = topright_post-botleft_post + + [-post_dia,-post_dia] + + [0, thehd[1]]; + cidszr = [ min(cidsz[0],50), min(cidsz[1],50) ]; + echo("CID",cidsz,cidszr); + translate( concat(botleft_post, [ -tile_th ]) + + 0.5 * [ post_dia, post_dia, 0 ] + + 0.5 * concat( cidsz - cidszr, [ 0 ]) ) + Commitid_BestCount_M(cidszr); + } + if ((TEST || JIG)) { + crossoff = tile_hard_edge_hole_dist + POST_TCROSSSZ/2; + cidsz = [ thehd[0], size[1] - 2*crossoff ]; + cidszr = [ cidsz[0], min(cidsz[1], 50) ]; + if (TEST) + translate( concat(botleft + [0, crossoff] + (cidsz-cidszr)/2, [0]) ) + Commitid_BestCount(cidszr); + difference(){ + mirror([0,0,1]) { + translate(concat(botleft + [test_edge,test_edge], [test_tile_th])) + cube(concat(size - [test_edge,test_edge]*2, [tile_th*2])); + translate(concat(botleft_post, [-1])) + cube(concat(topright_post-botleft_post, [tile_th+2])); + } + shufflesz = max(test_edge, tile_hard_edge_hole_dist)*2; + minkowski(){ + MachineEnvelope(); + cube(shufflesz, center=true); + } + if (JIG) { + translate([0,0,-20]) linear_extrude(height=20) { + for (diag=[[ +1, botleft ], + [ -1, [topright[0], botleft[1]] ]]) { + translate(diag[1]) + rotate(atan2(size[1], diag[0] * size[0])) + translate([0, -test_edge/2]) + square([vectorlen2d(size), test_edge]); + } + } + } + } + } + } +} + +m4_dnl R_EDGE(c,ix) +m4_dnl c is from Rectangle_corners and +m4_dnl ix is a corner number +m4_dnl expands to two comma-separated corners: +m4_dnl that denoted by ix, and the next one anticlockwise +m4_define(`R_EDGE',`$1[$2], $1[(($2)+1)%4]') + +m4_dnl R_CNR(c,ix) +m4_dnl c is from Rectangle_corners and +m4_dnl ix is a corner number +m4_dnl expands to an array of corners as for RoundCorner +m4_define(`R_CNR',`[ $1[$2], $1[(($2)+1)%4], $1[(($2)+3)%4] ]') + +m4_dnl INREFFRAME(left_cnr, right_cnr, morevars) { body; } +m4_define(`INREFFRAME',` + length_vec = ($2) - ($1); + length = dist2d([0,0], length_vec); + length_uvec = length_vec / length; + ortho_uvec = [ -length_uvec[1], length_uvec[0] ]; + m = [ [ length_uvec[0], ortho_uvec[0], 0, ($1)[0], ], + [ length_uvec[1], ortho_uvec[1], 0, ($1)[1], ], + [ 0, 0, 1, 0, ], + [ 0, 0, 0, 1, ] ]; + $3 + multmatrix(m) +') + +m4_dnl INREFFRAME(left_cnr, right_cnr, morevars) +m4_dnl INREFFRAME_EDGE { body; } +m4_define(`INREFFRAME_EDGE',` + translate([0,0, -round_edge_rad]) +') + +module RoundEdge(left_cnr, right_cnr) { + INREFFRAME(left_cnr, right_cnr) + INREFFRAME_EDGE { + difference(){ + rotate([0,90,0]) + cylinder(r= round_edge_rad, h= length, $fn=50); + translate([-1, 0, -20]) + cube([length+2, 20, 20]); + } + } +} + +m4_define(`ROUNDCORNER_VARS',` + this_cnr = ci[0]; + right_cnr = ci[1]; + left_cnr = ci[2]; + bigr= round_cnr_rad - round_edge_rad; + l_uvec = unitvector2d(left_cnr - this_cnr); + r_uvec = unitvector2d(right_cnr - this_cnr); + lp1 = left_cnr + clockwise2d(l_uvec) * bigr; + lp2 = this_cnr + clockwise2d(l_uvec) * bigr; + lp3 = this_cnr - clockwise2d(r_uvec) * bigr; + lp4 = right_cnr - clockwise2d(r_uvec) * bigr; + ctr = line_intersection_2d(lp1,lp2,lp3,lp4); + ctr3 = concat(ctr,[0]) +') + +module RoundCorner_selector(ci, adj) { + ROUNDCORNER_VARS; + intersection(){ + union(){ + INREFFRAME(ctr3,concat(lp1,[4])){ + translate([0,0,-bigr]) linear_extrude(height=bigr*2) { + translate([-bigr*2 + adj, -bigr]) + square([bigr*2, bigr*3]); + } + } + } + union(){ + INREFFRAME(ctr3,concat(lp4,[0])){ + translate([0,0,-bigr]) linear_extrude(height=bigr*2) { + translate([-bigr*2, -bigr*2]) + square([bigr*2 + adj, bigr*3]); + } + } + } + } +} + +module RoundCornerCut(ci) { + // ci should be [this_cnr, right_cnr, left_cnr] + // where right_cnr is to the right (ie, anticlockwise) + ROUNDCORNER_VARS; + difference(){ + RoundCorner_selector(ci, -0.1); + translate(ctr3) + cylinder(center=true, h=20, r= bigr); + } +} + +module RoundCornerAdd(ci) { + ROUNDCORNER_VARS; + intersection(){ + RoundCorner_selector(ci, +0.1); + INREFFRAME_EDGE { + translate(ctr3){ + rotate_extrude(convexity=10, $fn=50) + translate([bigr, 0]) + difference(){ + circle(r= round_edge_rad, $fn=50); + mirror([1,1]) + square([20,20]); + } + } + } + } +} + +module InterlockLobePlan(negative) { + r = negative ? interlock_negative_rad : interlock_rad; + ymir = negative ? 0 : 1; + + dx = sqrt(3) * r; + $fn= 80; + translate([thehd[0], 0]){ + mirror([0,ymir]){ + circle(r=r); + difference(){ + translate([-dx, -0.1]) + square([ dx*2, r/2 + 0.1 ]); + for (xi = [-1, 1]) { + translate([ xi*dx, r ]) + circle(r=r); + } + } + } + } +} + +module InterlockEdgePlan(negative, nlobes, length, dosquare=true) { + for (lobei = [ 0 : nlobes-1 ]) { + lobex = (length - thehd[0]*2) * (lobei ? lobei / (nlobes-1) : 0); + translate([lobex, 0, 0]) { + InterlockLobePlan(negative); + } + } + + if (dosquare) { + iadj = 0; + slotshorter = negative ? -0.1 : interlock_fine_lenslop; + mirror([0, negative]) + translate([slotshorter, iadj]) + square([length - slotshorter*2, interlock_fine + iadj*2]); + } +} + +module InterlockEdge(left_cnr, right_cnr, negative=0, nlobes=2) { + plusth = negative * 1.0; + protr = interlock_fine + interlock_sq_adj; + + z2 = -tile_th/2; + z1 = -tile_th/2 - protr / interlock_fine_slope; + z3 = -tile_th/2 + protr / interlock_fine_slope; + + negsign = negative ? -1 : +1; + yprotr = negsign * protr; + + INREFFRAME(left_cnr, right_cnr) { + for (vsect = [ // zs0 zs1 ys0, ys1 + [ -tile_th-plusth, plusth, 0, 0], + [ z1, z2, 0, yprotr], + [ z2, z3, yprotr, 0], + ]) { + zs0 = vsect[0]; + zs1 = vsect[1]; + zsd = zs1-zs0; + ys0 = vsect[2]; + ys1 = vsect[3]; + ysd = ys1-ys0; + sl = ysd/zsd; + m = [ [ 1,0, 0, 0 ], + [ 0,1, -sl, -ys0 + negsign*interlock_sq_adj ], + [ 0,0, 1, zs0 ], + [ 0,0, 0, 1 ] ]; + multmatrix(m) + linear_extrude(height=zsd, convexity=10) + InterlockEdgePlan(negative, nlobes, length, !!ysd); + } + } +} + +function TestPiece_holes2corners(holes) = + [ holes[0] + thehd_bl, + holes[1] + thehd_br, + holes[1] + thehd_tr, + holes[0] + thehd_tl ]; + +module TestPiece1(){ ////toplevel + holes = [ [-100, 0], + [ 0, 0] + ]; + corners = TestPiece_holes2corners(holes); + rcs = R_CNR(corners,0); + difference(){ + union(){ + TileBase(corners[0], corners[2]); + Posts(holes); + RoundEdge(corners[0], corners[1]); + RoundEdge(corners[3], corners[0]); + } + InterlockEdge(corners[1], corners[2], 1, nlobes=1); + RoundCornerCut(rcs); + PostHoles(holes); + } + RoundCornerAdd(rcs); +} + +module TestPiece2(){ ////toplevel + holes = [ [ 0, 0], + [ 50, 0] + ]; + corners = TestPiece_holes2corners(holes); + difference(){ + union(){ + TileBase(corners[0], corners[2]); + Posts(holes); + RoundEdge(corners[0], corners[1]); + InterlockEdge(corners[3], corners[0], 0, nlobes=1); + } + PostHoles(holes); + } +} + +module TestDemo(){ ////toplevel + translate([ -thehd[0], 0 ]) + color("blue") + TestPiece1(); + translate([ +thehd[0] + demo_slop, 0 ]) + TestPiece2(); +} + +module PostTestPiece(){ ////toplevel + hole_sizes = [2.8, 3.0, 3.1, 3.134, 3.168, 3.2, 3.3, 3.5]; + nholes = len(hole_sizes)*2; + nrows = 4; + stride = post_dia*1.5; + rect_sz = stride * [ nrows, + ceil(nholes/nrows) ]; + corners = Rectangle_corners(-stride * 0.5 * [1,1], rect_sz); + difference(){ + union(){ + TileBase(corners[0], corners[2]); + RoundEdge(corners[0], corners[1]); + for (i= [ 0: nholes-1 ]) { + $screw_dia = hole_sizes[ floor(i/2) ]; + translate(stride * [ (nrows-1) - (i % nrows), + floor(i / nrows), + 0 + ]) { + Posts([[0,0]]); + color("blue") + mirror([0,0,1]) + translate([post_dia/2, -post_dia/2, 1]) + cube([1, post_dia * (i / nholes), tile_th]); + } + } + } + } +} + +module Machine_NewRearProfile(){ + // figures copied out of xfig edit boxes + // best not to edit the posbox size if poss - just move it + posbox = 10 * ([7.2333,-14.1267] - [-16.2289,40.0289]); // box, Green + sideline = -10 * ([-6.2400,13.5600] - [-2.4467,28.2556]); // line, Blue + scaleline = 10 * dist2d([-1.1911,-20.4800], [-11.2600,4.0578]); // Green2 + scaleline_mm = 12+5+10+5+3; + sh = -[abs(posbox[0]), abs(posbox[1])]; + rot = atan2(-sideline[0], sideline[1]); + sc = scaleline_mm / scaleline; + //echo("SH",sh,rot,sc); + scale(sc) rotate(rot) translate(sh){ + import("sewing-table-rear-profile.dxf", convexity=10); // spline, Pink3 + } +} + +module Machine_NewFrontProfile(){ + // figures copied out of xfig edit boxes + // best not to edit the posbox size if poss - just move it + posbox = 10 * ([11.8022,8.0600] - [4.2044,19.1867]); // box, Green + refline = 10 * ([7.6778,16.7222] - [27.8689,17.6578]); // line, Blue + refline_mm = (11-1)*10; + sh = -[abs(posbox[0]), abs(posbox[1])]; + rot = atan2(-refline[0], refline[1]); + sc = refline_mm / vectorlen2d(refline); + //echo("SH",sh,rot,sc); + mirror([1,0]) scale(sc) rotate(rot+90) translate(sh){ + import("sewing-table-front-profile.dxf", convexity=10); // spline, Pink3 + } +} + +module Machine_NewEndProfile(){ + // figures copied out of xfig edit boxes + // NB that y coords are reversed - xfig origin is at bottom left + posboxs = 10 * [[4.0400,17.7956], [11.6622,32.5511]]; // box, Pink3 + refline = 10 * ([8.4000,22.6000] - [50.3000,22.2000]); // line, Blue + refline_mm = 10 * (11 - 2.5); + sidelines = 10 * [[[9.0889,20.6178], [8.9644,14.6889]], + [[50.3800,21.9578], [50.1933,14.4933]]]; // lines, Blue3 + baseline = 10 * [[8.4000,18.0822], [50.3000,17.6822]]; // line, Green2 + + rot_adj = -0.38; + + posbox = [min(posboxs[0][0],posboxs[1][0]), + max(posboxs[0][1],posboxs[1][1])]; + + m4_define(`MNEP_ELP', + `line_intersection_2d(baseline[0],baseline[1], + sidelines[$1][0],sidelines[$1][1])') + endline = [MNEP_ELP(0),MNEP_ELP(1)]; + + rot = atan2(-refline[1], -refline[0]); + sc = refline_mm / vectorlen2d(refline); + sh = (0.5 * (endline[0] + endline[1])) - posbox; + + ellen = sc * dist2d(endline[0],endline[1]); + scy = cutout_l_end_y_total / ellen; + + scale([scy,1]) scale(sc) rotate(rot + rot_adj) translate(-[sh[0],-sh[1]]){ + + mirror([0,1]){ + //%translate(1 * (posboxs[0] - posbox)) square(50); + //%translate(1 * (posboxs[1] - posbox)) square(50); +// %translate(1 * (baseline[0] - posbox)) square([50,10]); + +// %translate(1 * (endline[0] - posbox)) square([50,10]); +// %translate(1 * (endline[1] - posbox)) square([50,10]); + +// %translate(1 * (sidelines[0][0] - posbox)) square([10,50]); +// %translate(1 * (sidelines[0][1] - posbox)) square([10,50]); +// %translate(1 * (sidelines[1][0] - posbox)) square([10,50]); +// %translate(1 * (sidelines[1][1] - posbox)) square([10,50]); + } + + import("sewing-table-end-profile.dxf", convexity=10); // spline, Pink3 + } +} + +module Machine_NewEndProfileDemo(){ ////toplevel + translate([0,5,0]) Machine_NewEndProfile(); + translate([0,5,1]) color("blue") mirror([1,0]) Machine_NewEndProfile(); + mirror([0,1,0]){ + translate([0,5, 0]) Machine_NewEndProfile(); + translate([0,5,-1]) color("blue") mirror([1,0]) Machine_NewEndProfile(); + } +} + +module Machine_NewArm(){ + translate([0,0,-30]) linear_extrude(height=60) { + translate(tile01_tr + [ -cutout_l_end_x - cutout_l_end_new_x_slop, + (-cutout_tile01_y + cutout_tile11_y)/2 ]){ + rotate(-90){ + hull(){ + for (d=[0,400]) + translate([0,d]) Machine_NewEndProfile(); + } + } + } + } +} + +module Machine_NewRearCurve(){ + slant = atan2(4,210-10); + //echo("SL",slant); + translate([0,0, rearcurve_double_inrad]) rotate([slant,0,0]){ + translate([ rearcurve_double_inrad, + 0, + -rearcurve_double_inrad + 10 ]){ + rotate([180,0,0]) rotate([0,0,90]) linear_extrude(height=30){ + hull(){ + Machine_NewRearProfile(); + translate([0,-100]) Machine_NewRearProfile(); + } + } + } + rotate([0,90,0]) rotate([90,0,0]) { + intersection(){ + rotate_extrude(convexity=10, $fn=64) + rotate(90) + translate([ 0, -rearcurve_double_inrad ]) + Machine_NewRearProfile(); + translate([0,0,-500]) + cube([500,500,1000]); + } + } + translate([1,0,-rearcurve_double_inrad]) + rotate([0,-90,0]) rotate([0,0,-90]) + linear_extrude(height= rearcurve_strt_len + 1) + Machine_NewRearProfile(); + } +} + +module Machine_Curves(){ ////toplevel + translate([ tile01_tr[0] - cutout_l_end_x + rearedge_len, + cutout_tile11_y, + 0 ]){ + //%cube([20,20,20]); + translate([ -reartablet_x, + -1, + -reartablet_z + tablet_z_slop]) + mirror([0,0,1]) + cube([ reartablet_x+1, + reartablet_y+1, + 20 ]); + } + translate([ tile01_tr[0] - cutout_l_end_x + frontedge_len, + cutout_tile11_y, + frontcurve_z_slop ]){ + translate([0, -machine_rear_to_front, 0]) + multmatrix([[1, -frontcurve_side_skew, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [0, 0, 0, 1]]) + mirror([1,0,0]) rotate([0,-90,0])rotate([0,0,-90]) + linear_extrude(height= 200) + Machine_NewFrontProfile(); + } + translate([ tile01_tr[0] - cutout_l_end_x + rearedge_len, + cutout_tile11_y, + frontcurve_z_slop ]){ + translate([ rearcurve_strt_len, + 0, + rearcurve_z_slop ]){ + Machine_NewRearCurve(); + } + } +} + +module TestStrapSlots(){ + pegwidth = teststrap_peg[0]; + for (pos = teststrapslots_at) { + echo("TSS",pos); + translate(concat(pos,[0])) + for (mx = [0,1]) mirror([mx,0,0]) { + translate([ pegwidth/2, -teststrap[1]/2, -20 ]) + cube(concat(teststrap,[40])); + } + } +} + +module TestStrapPeg_any(l){ cube(concat([l],teststrap_peg)); } + +module TestStrapPeg_Short(){ ////toplevel + TestStrapPeg_any(35); +} + +module TestStrapPeg_Long(){ ////toplevel + TestStrapPeg_any(60); +} + +module PostSpacer(){ ////toplevel + $fn = 50; + difference(){ + cylinder(r= ply_hole_dia_real/2 - spacer_ext_slop, + h= spacer_height); + translate([0,0,-1]) + cylinder(r= post_dia/2 + spacer_int_slop, + h= ply_th + 2); + } +} + +module Machine(){ ////toplevel + Machine_NewArm(); + Machine_Curves(); + if (TEST) + TestStrapSlots(); +} + +module MachineEnvelope(){ + // used for testing + p_arm_bl = [-cutout_l_end_x, -cutout_tile01_y]; + y_arm_t = cutout_tile11_y; + p_crv_fl = p_arm_bl + [frontedge_len, -frontcurve_avoid_y]; + y_crv_b = y_arm_t + rearcurve_avoid_y; + + translate([0,0,-50]) linear_extrude(height= 100){ + translate(p_arm_bl) square([400, y_arm_t] - p_arm_bl); + translate(p_crv_fl) square([400, y_crv_b] - p_crv_fl); + } +} + +module Leg(){ ////toplevel + difference(){ + union(){ + hull(){ + mirror([0,0,1]) + cylinder(r= leg_big_dia/2, h=leg_top_flat_z, $fn=100); + translate([0,0, -leg_top_thick]) + cylinder(r= leg_bot_dia/2, height=1, $fn=100); + } + if (!TEST) + translate([0,0,-leg_height]) + cylinder(r= leg_bot_mid_dia/2, h=leg_bot_thick); + for (rot=[0: 360/leg_n_fins : 359]) rotate(rot) { + hull(){ + mirror([0,0,1]) translate([0, -leg_fin_top_w/2, 0]) + cube([ leg_fin_top_rad - 0.1, + leg_fin_top_w, + 1 ]) + ; + translate([0, -leg_fin_bot_w/2, -leg_height]) + cube([ leg_fin_bot_rad, + leg_fin_bot_w, + leg_fin_bot_flat_z ]); + } + } + } + mirror([0,0,1]) translate([0,0,-1]) + cylinder(r= leg_hole_dia/2, + h= (!TEST ? leg_height+2 : leg_height/2), + $fn=30); + mirror([0,0,1]) translate([0,0,leg_top_thick - 0.1]) + hull(){ + cylinder(r= (!TEST ? leg_midspc_dia/2 : 0.1), + h= leg_height - leg_top_thick - leg_bot_thick + 0.2, + $fn=30); + if (TEST) + cylinder(r= leg_midspc_dia/2, + h= leg_height - leg_top_thick - leg_bot_thick + + (!TEST ? 0.2 : -leg_midspc_dia/2), + $fn=30); + } + cid_shear = (leg_fin_bot_w - leg_fin_top_w)/2 / + (leg_height -leg_fin_bot_flat_z); + multmatrix([[ 1, 0, 0, leg_midspc_dia/2 ], + [ 0, cid_shear, + 1, -leg_fin_bot_w/2 ], + [ 0, 1, 0, -leg_height + leg_fin_bot_flat_z ], + [ 0, 0, 0, 1 ]]) + Commitid_BestCount([ leg_big_dia/2 - leg_midspc_dia/2, + leg_height - leg_fin_bot_flat_z + - leg_top_thick ]); + if (!TEST) + for (rot=[45: 360/leg_n_tubules : 359]) rotate(rot) { + mirror([0,0,1]) translate([ leg_tubule_pos_rad, 0, -1]) + cylinder(r= leg_tubule_dia/2, h=leg_height+2, $fn=20); + } + } +} + +function Rectangle_corners(c0, sz) = + // returns the corners of a rectangle from c0 to c0+sz + // if sz is positive, the corners are anticlockwise starting with c0 + [ c0 + [ 0, 0 ], + c0 + [ sz[0], 0 ], + c0 + [ sz[0], sz[1] ], + c0 + [ 0, sz[1] ] ]; + +function Rectangle_corners2posts(c) = + [ c[0] + thehd_tr, + c[1] + thehd_tl, + c[2] + thehd_bl, + c[3] + thehd_br ]; + +module Rectangle_TileBase(c) { TileBase(c[0], c[2]); } + +function Posts_interpolate_one(c0,c1) = [c0, (c0+c1)/2, c1]; + +module Tile02(){ ////toplevel + sz = [100,170]; + c0 = tile02_tr + -sz; + c = Rectangle_corners(c0, sz); + posts = Rectangle_corners2posts(c); + rcs = R_CNR(c,0); + difference(){ + union(){ + Rectangle_TileBase(c); + Posts(posts); + RoundEdge(R_EDGE(c,0)); + RoundEdge(R_EDGE(c,3)); + InterlockEdge(R_EDGE(c,2), 0); + } + InterlockEdge(R_EDGE(c,1), 1); + RoundCornerCut(rcs); + PostHoles(posts); + } + RoundCornerAdd(rcs); +} + +module Tile12(){ ////toplevel + sz = [100,250]; + c0 = tile02_tr + [-sz[0], 0]; + c = Rectangle_corners(c0, sz); + posts = Rectangle_corners2posts(c); + rcs = R_CNR(c,3); + difference(){ + union(){ + Rectangle_TileBase(c); + Posts(posts); + RoundEdge(R_EDGE(c,2)); + RoundEdge(R_EDGE(c,3)); + } + InterlockEdge(R_EDGE(c,0), 1); + InterlockEdge(R_EDGE(c,1), 1); + RoundCornerCut(rcs); + PostHoles(posts); + } + RoundCornerAdd(rcs); +} + +tile_01_11_cnr = tile01_tr + [-cutout_l_end_x, 0]; +tile_11_10_cnr = tile01_tr + [0, cutout_tile11_y]; +tile_01_00_cnr = tile01_tr - [0, cutout_tile01_y]; + +module Tile11(){ ////toplevel + sz = [250,250]; + c0 = tile01_tr + [-sz[0],0]; + c = Rectangle_corners(c0, sz); + cnr_posts = Rectangle_corners2posts(c); + posts = concat( + Posts_interpolate_one(cnr_posts[0], + cnr_posts[1] - [cutout_l_end_x, 0]), + [ cnr_posts[1] + [0, cutout_tile11_y], + cnr_posts[2], + cnr_posts[3] + ]); + difference(){ + union(){ + Rectangle_TileBase(c); + Posts(posts); + RoundEdge(R_EDGE(c,2)); + InterlockEdge(R_EDGE(c,3)); + } + InterlockEdge(c[0], tile_01_11_cnr, 1); + InterlockEdge(tile_11_10_cnr, c[2], 1); + PostHoles(posts); + Machine(); + } +} + +module Tile01(){ ////toplevel + sz = [250,170]; + c0 = tile01_tr + -sz; + c = Rectangle_corners(c0, sz); + cnr_posts = Rectangle_corners2posts(c); + posts = concat( + Posts_interpolate_one(R_EDGE(cnr_posts,0)), + [ cnr_posts[2] + [0, -cutout_tile01_y] ], + Posts_interpolate_one(cnr_posts[2] - [cutout_l_end_x, 0], + cnr_posts[3]) + ); + difference(){ + union(){ + Rectangle_TileBase(c); + Posts(posts); + RoundEdge(R_EDGE(c,0)); + InterlockEdge(tile_01_11_cnr, c[3]); + InterlockEdge(R_EDGE(c,3)); + } + PostHoles(posts); + InterlockEdge(c[1], tile_01_00_cnr, 1); + Machine(); + } +} + +module Tile10(){ ////toplevel + sz = [250,250]; + c0 = tile01_tr + [0,0]; + c = Rectangle_corners(c0, sz); + cnr_posts = Rectangle_corners2posts(c); + cty = cutout_tile11_y; + rcy = cty + rearcurve_avoid_y; + posts = [ cnr_posts[0] + [ 0, cty ], + cnr_posts[1] + [ -sz[0] + rearedge_len - cutout_l_end_x, cty ], + cnr_posts[1] + [ 0, rcy ], + cnr_posts[2], + cnr_posts[3] ]; + rcs = R_CNR(c,2); + difference(){ + union(){ + Rectangle_TileBase(c); + Posts(posts); + RoundEdge(R_EDGE(c,1)); + RoundEdge(R_EDGE(c,2)); + InterlockEdge(c[3], tile_11_10_cnr); + } + PostHoles(posts); + RoundCornerCut(rcs); + Machine(); + } + RoundCornerAdd(rcs); +} + +module Tile00(){ ////toplevel + sz = [250,170]; + c0 = tile01_tr + [0,-sz[1]]; + c = Rectangle_corners(c0, sz); + + // the edge c[1]..c[2] needs a diagonal chunk, from c1bis to c2bis + c2bis = [ -cutout_l_end_x + frontedge_len + frontcurve_strt_len, c[2][1] ]; + c1bis = [ c[1][0], + c[2][1] - + (c[2][0] - c2bis[0]) * tan(90 - frontcurve_dualcurve_angle) ]; + + cnr_posts = Rectangle_corners2posts(c); + cty = cutout_tile01_y; + rcy = cty + frontcurve_avoid_y; + posts = [ cnr_posts[0], + cnr_posts[1], + 0.5 * (cnr_posts[0] + cnr_posts[1]), + cnr_posts[2] + [ 0, -rcy ], + cnr_posts[2] + [ -sz[0] + frontedge_len - cutout_l_end_x, -cty ], + cnr_posts[3] + [ 0, -cty ] + ]; + rcs = R_CNR(c,1); + rc2 = [c1bis,c2bis,c[1]]; + difference(){ + union(){ + difference(){ + union(){ + Rectangle_TileBase(c); + Posts(posts); + RoundEdge(R_EDGE(c,0)); + RoundEdge(c[1], c1bis); + InterlockEdge(tile_01_00_cnr, c[0]); + } + RoundCornerCut(rcs); + translate([0,0,-20]) linear_extrude(height=40) { + polygon([ c1bis, c1bis + [50,0], c2bis + [50,0], c2bis ]); + } + } + RoundEdge(c1bis, c2bis); + } + Machine(); + PostHoles(posts); + RoundCornerCut(rc2); + } + RoundCornerAdd(rcs); + RoundCornerAdd(rc2); +} + +module FitTest_general(c0,sz, dobrace=false, bracexx=0){ + c = Rectangle_corners(c0, sz); + brace = [7,7,9]; + bsz = sz + [bracexx,0,0]; + difference(){ + union(){ + Rectangle_TileBase(c); + if (dobrace) { + translate(concat(c0, [-brace[2] + 0.1])){ + difference(){ + cube(concat(bsz, [brace[2]]) - [5,0,0]); + translate(brace + [0,0, -25]) + cube(concat(bsz, [50]) - brace*2 + [10,0,0]); + } + } + } + RoundEdge(R_EDGE(c,1)); + } + Machine(); + } +} + +module FitTest_PairLink(cut=false){ ////toplevel + cy0=-55; cy1=85; cx=132; + bar = [10,10]; + legrad = 12; + footrad_min = 1; footrad_max = 4; footrad_depth = 5; + strap = [3,5]; + adj_neg_slop = 1.0; + bar_z_slop = 1.75; + + // calculated + straphole_x_max = legrad/sqrt(2) + footrad_max; + dz = cut ? adj_neg_slop : 0; + + translate([cx - bar[0]/2, cy0, dz + bar_z_slop]) + cube([bar[0], cy1-cy0, bar[1] - bar_z_slop]); + + for (endy=[cy0,cy1]) { + $fn=32; + translate([cx,endy,dz]){ + // feet + for (rot=[45:90:315]) rotate(rot) { + translate([legrad,0,0]){ + hull(){ + cylinder(r= footrad_max, h=1); + translate([0,0,-footrad_depth]) + cylinder(r= footrad_min, h=1); + } + if (cut) + translate([0,0,-10]) + cylinder(r= footrad_min + + adj_neg_slop * (footrad_max-footrad_min)/footrad_depth, + h=20); + } + } + // legs + for (rot=[45,135]) rotate(rot) { + hull(){ + for (s=[-1,+1]){ + translate([s*legrad,0,0]) + cylinder(r= footrad_max, h=bar[1]); + } + } + } + // strap holes + if (cut) { + for (rot=[0,180]) rotate(rot) { + translate([ straphole_x_max - strap[0]/2, 0,0 ]) + cube(concat(strap,[20]), center=true); + } + } + } + } +} + +module FitTest_RearCurve(){ ////toplevel + difference(){ + FitTest_general([100,0], [180,100]); + FitTest_PairLink(true); + TestStrapSlots(); + } +} + +module FitTest_FrontCurve(){ ////toplevel + p0 = [100,-80]; + sz = [180,80]; + difference(){ + intersection() { + Tile00(); + translate([0,0,-8]) linear_extrude(height=18) { + translate(p0) square(sz); + translate(teststrapslots_at[3]) + scale(2* [ teststrap_peg[0], teststrap[1] ]) + circle(r=1, $fn=20); + } + } + FitTest_PairLink(true); + TestStrapSlots(); + } +} + +module FitTest_Entire(){ ////toplevel + p0 = [-33,-80]; + szrear = [263,180]; + szfront = [243,szrear[1]]; + difference(){ + FitTest_general(p0, szrear, dobrace=true, bracexx=0); + FitTest_PairLink(true); + translate(concat(p0,[0]) + [szfront[0],-10,-40]) + cube([100, -p0[1], 80]); + TestStrapSlots(); + } + intersection(){ + FitTest_RearCurve(); + translate(concat(p0,[-20])) cube(concat(szrear,[40])); + } + FitTest_FrontCurve(); +} + +module FitTest_EntireDemo(){ ////toplevel + FitTest_Entire(); + //%Tile00(); +} + +module FitTest_EndEnd(){ ////toplevel + p0 = [-30,-32]; + sz = [156,81] - p0; + sz2 = [136,68] - p0; + difference(){ + FitTest_general(p0, sz); + translate([ p0[0] -1, p0[1]+sz2[1], -10]) + cube([ sz2[0] +1, 50, 20 ]); + } +} + +module FitTest_PairDemo(){ ////toplevel + sh=[-90,-15,0]; + translate(sh){ + FitTest_PairLink(); + %FitTest_FrontCurve(); + %FitTest_RearCurve(); + } + rotate([0,0,180]){ + translate(sh){ + difference(){ + union(){ + FitTest_FrontCurve(); + FitTest_RearCurve(); + } + #FitTest_PairLink(true); + } + } + } +} + +module RoundCornerDemo_plat(cnr){ + mirror([0,0,1]) linear_extrude(height=1) polygon(cnr); +} + +module RoundCornerDemo(){ ////toplevel + cnr = [ [-2,-3], [13,-3], [-12,9] ]; + translate([0,25,0]) RoundCornerDemo_plat(cnr); + translate([25,0,0]) RoundCornerAdd(cnr); + translate([-25,0,0]) RoundCornerCut(cnr); + translate([0,-25,0]) RoundCorner_selector(cnr, 0); + difference(){ + RoundCornerDemo_plat(cnr); + RoundCornerCut(cnr); + } + RoundCornerAdd(cnr); +} + +module Demo(){ ////toplevel + translate(demo_slop*[-2,1]) color("blue") Tile12(); + translate(demo_slop*[-2,0]) color("red") Tile02(); + translate(demo_slop*[-2,1]) color("orange") Tile11(); + translate(demo_slop*[-2,0]) color("purple") Tile01(); + translate(demo_slop*[-3,1]) color("blue") Tile10(); + translate(demo_slop*[-3,0]) color("red") Tile00(); + %Machine(); + // Can also do this, to print reference sheet: + // load this into openscad + // select Ctrl-4 view, view all, scale appropriately + // import sewing-table,Demo-flat.png + // pngtopnm t.pnm + // lpr t.pnm +} + +//TestPiece1(); +//TestPiece2(); +//Demo(); + +//Machine_NewRearProfile(); +//Machine_NewRearCurve(); +//Machine_NewFrontProfile(); +//Machine_NewEndProfile(); +//Machine_NewEndProfileDemo(); +//Machine_Curves(); +//Machine(); +//FitTest(); +//MachineEnvelope(); diff --git a/shelf-label-holder.scad b/shelf-label-holder.scad new file mode 100644 index 0000000..8353d7e --- /dev/null +++ b/shelf-label-holder.scad @@ -0,0 +1,65 @@ +// -*- C -*- + +prong_nomdepth = 15; +prong_curverad = 30; +prong_thick = 0.7; +prong_maxdepth = 18; + +front_thick = 2.5; + +//nom_shelf = 14.54 + 0.5; +nom_shelf = 20.315 + 0.5; + +interference = 0.75; + +length = 60; + +// calculated + +interference_angle = atan2(interference, prong_nomdepth); + +module ProngElevationUnrotated(){ + intersection(){ + union(){ + translate([ prong_nomdepth, prong_curverad ]) + circle( prong_curverad , $fa=0.5 ); + translate([ -10, 0 ]) + square([ prong_nomdepth + 10, 10 ]); + } + translate([-5, -5]) + square([ prong_maxdepth + 5, prong_thick + 5]); + } +} + +module Elevation(){ + difference(){ + union(){ + rotate(-interference_angle) + ProngElevationUnrotated(); + translate([0, -nom_shelf]) + mirror([0,1]) + rotate(-interference_angle) + ProngElevationUnrotated(); + translate([-10, -nom_shelf - prong_thick/2]) + square([10, nom_shelf + prong_thick]); + } + mirror([1,0]) + translate([ front_thick, -100 ]) + square([ 50, 200 ]); + } +} + +module Main(){ + linear_extrude(height=length) + Elevation(); +} + +module Print(){ + rotate([0,-90,0]) + Main(); +} + +//ProngElevationUnrotated(); +//Elevation(); +Main(); +//Print(); diff --git a/simplephone-case-test.scad b/simplephone-case-test.scad new file mode 100644 index 0000000..eedb932 --- /dev/null +++ b/simplephone-case-test.scad @@ -0,0 +1,3 @@ +//// toplevels-from:sewing-table.scad +include +$test = true; diff --git a/simplephone-case.scad b/simplephone-case.scad new file mode 100644 index 0000000..2cbc5ff --- /dev/null +++ b/simplephone-case.scad @@ -0,0 +1,167 @@ +// -*- C -*- + +psz = [ + 120, + 56 + 5 - 3.75, + 15 + 3, + ]; + +thick = [ + 2, + 2, + 1.5, + ]; + +btn_x = 59.6; +btn_dia = 13; +btn_y = 14.03; + +abtn_x = 46.85; +abtn_sz = [ 11, 13 ]; + +screen_xbot = 79; +screen_sz = [ 35, 46 ]; + +thumb_xbot = 90; +thumb_dia = 25; + +vol_xbot = 86.5; +vol_xtop = 107.5; +vol_depth = 1.0; +vol_zsz = 9; +vol_zoff = 0; + +rail_ysz = 2.5; +rail_zsz = 2.5; + +stay_height = 1.49; + +case_x_less = 0; //case_x_less = 10; + +inner_cnr_rad = 4.0; + +// calculated + +btn_yprop = btn_y / psz[1]; +echo(btn_yprop); + +ym = psz[1]/2; +outer_cnr_rad = inner_cnr_rad + thick[2]; + +x_sliced = outer_cnr_rad * (1-sin(45)); + +$screen = true; + +module RoundedProfile(sz, cnr_rad){ + hull(){ + for (x=[ cnr_rad, sz[0]-cnr_rad ]) + for (y=[ cnr_rad, sz[1]-cnr_rad ]) + translate([x,y]) + circle(r= cnr_rad, $fn=20); + } +} + +module RoundedCube(sz, cnr_rad){ + if ($test) + cube(sz); + else hull(){ + for (x=[ cnr_rad, sz[0]-cnr_rad ]) + for (y=[ cnr_rad, sz[1]-cnr_rad ]) + for (z=[ cnr_rad, sz[2]-cnr_rad ]) + translate([x,y,z]) + sphere(r= cnr_rad, $fn=40); + } +} + +module Stay(xbot, xtop, width, midgap_width) { + translate([ (xbot+xtop)/2, psz[1]/2, psz[2] ]){ + difference(){ + cube([ xtop-xbot, width, stay_height*2 ], center=true); + if (midgap_width > 0) + cube([ 200, midgap_width, 10 ], center=true); + } + } +} + +module Stays(){ + Stay( 76, 82, 10, 0); + Stay(-0.1, 55, 10, 0); + Stay( 113,125, 70, 15); +} + +module Case(){ + difference(){ + mirror([1,0,0]) + translate(-thick + + - [1,0,0] * x_sliced) + RoundedCube(psz + + 2*thick + - [1,0,0] * (thick[0]) + + [1,0,0] * (x_sliced) + - [case_x_less, 0, 0], + outer_cnr_rad); + + for (yp= [ btn_yprop, 1-btn_yprop ]) + translate([ -btn_x, + yp * psz[1], + 0.5 * psz[2] ]) + cylinder(r= btn_dia/2, h=20); + + translate([ -abtn_x, + btn_yprop * psz[1], + psz[2] ]) + cube(concat(abtn_sz, [ thick[2]*3 ]), center=true); + + if ($screen) + mirror([1,0,0]) + translate([ screen_xbot, + (psz[1] - screen_sz[1])/2, + psz[2]-3 ]) + cube(concat(screen_sz, [ thick[2]+6 ])); + + hull(){ + for (x=[ thumb_xbot+thumb_dia/2, psz[0]+10 ]) + translate([ -x, + ym, + -thick[2]-1 ]) + cylinder(r= thumb_dia/2, + h= thick[2] + 2, + $fn= 20); + } + + mirror([1,0,0]) + translate([ (vol_xbot+vol_xtop)/2, 0, psz[2]/2 + vol_zoff ]) + cube([ vol_xtop-vol_xbot, vol_depth*2, vol_zsz ], center=true); + + translate([ thick[0], -10, -10 ]) + cube([ 10, psz[1]+20, psz[2]+20 ]); + + //translate([-50,-50,10]) cube([100,100,100]); + + mirror([1,0,0]) + difference(){ + RoundedCube(psz + [1,0,0], + inner_cnr_rad); + + Stays(); + + if (0) for (m=[0,1]) { + translate([0,ym,0]) mirror([0,m,0]) translate([0,-ym,0]) + translate([-1,-1, psz[2]-rail_zsz]) + cube([psz[0]+1, rail_ysz+1, rail_zsz+1]); + } + } + } +} + +module TestLoop(){ + intersection(){ + Case($screen=false); + translate([ -vol_xbot, 0,0 ]) + cube([ 4, 200,200 ], center=true); + } +} + +Case(); +//TestLoop(); +//RoundedCube(psz, inner_cnr_rad); diff --git a/size-tests.m-g b/size-tests.m-g new file mode 100644 index 0000000..fbb666b --- /dev/null +++ b/size-tests.m-g @@ -0,0 +1,213 @@ +; -*- fundamental -*- + +; slic3r originally produced this, with these comments, and then we edited: +; layer_height = 0.4 +; perimeters = 3 +; solid_layers = 3 +; fill_density = 0.4 +; perimeter_speed = 30 +; infill_speed = 60 +; travel_speed = 130 +; scale = 1 +; nozzle_diameter = 0.59 +; filament_diameter = 1.77 +; extrusion_multiplier = 1 +; single wall width = 0.71mm +; first layer single wall width = 0.60mm + +M190 S65 ; wait for bed temperature to be reached +M104 S215 ; set temperature +G28 ; home all axes +M109 S215 ; wait for temperature to be reached +G90 ; use absolute coordinates +G21 ; set units to millimeters +G92 E0 +M82 ; use absolute distances for extrusion + +!zprint=0.3 + +; "skirt" - prep extruder +!draw 5,5 100,5 101,5.5 101,6.0 100,6.5 5,6.5 + +; edge ticks for global motions sizing + +!edge_ticks(){ +!draw 20,10 10,10 10,20 +!draw 10,65 10,75 +!draw 10,120 10,130 20,130 +!draw 65,130 75,130 +!draw 120,130 130,130 130,120 +!draw 130,75 130,65 +!draw 130,20 130,10 120,10 +!draw 75,10 65,10 +!} + +;!edge_ticks() + +!outer_square(){ + !draw @0.000,@0.000 @5.000,@0.000 @5.000,@5.000 @0.000,@5.000 @0.000,@0.000 +!} +!inner_square(){ + !draw @0.500,@0.500 @4.500,@0.500 @4.500,@4.500 @0.500,@4.500 @0.500,@0.500 +!} +!outer_vlines(){ + !draw @0.000,@0.000 @0.000,@5.000 + !draw @5.000,@0.000 @5.000,@5.000 +!} +!inner_vlines(){ + !draw @0.500,@0.500 @0.500,@4.500 + !draw @4.500,@0.500 @4.500,@4.500 +!} +!outer_longrect(){ + !draw @0.000,@0.000 @5.000,@0.000 @5.000,@20.000 @0.000,@20.000 @0.000,@0.000 +!} +!inner_longrect(){ + !draw @0.500,@0.500 @4.500,@0.500 @4.500,@19.500 @0.500,@19.500 @0.500,@0.500 +!} + +!org_oblong(){ +; original test oblong + +!draw 68.498,79.498 \ +71.502,79.498 \ +71.502,82.502 \ +68.498,82.502 \ +68.498,79.588 \ +*67.899,78.899 \ +72.101,78.899 \ +72.101,83.101 \ +67.899,83.101 \ +67.899,78.989 \ +*67.300,78.300 \ +72.700,78.300 \ +72.700,83.700 \ +67.300,83.700 \ +67.300,78.390 \ + +!} + +!squares_tests(){ + +!orgy=40 + +!orgx=30 +!outer_longrect() + +!orgx=50 +!inner_longrect() +!outer_longrect() + +!orgx=90 +!inner_square() +!outer_square() + +!orgx=110 +!outer_square() + +!orgy=60 +!outer_vlines() + +!orgx=90 +!inner_vlines() +!outer_vlines() + +!orgy=80 +!outer_square() +!inner_square() + +!orgx=110 +!inner_square() + +!orgy=100 +!inner_vlines() + +!orgx=90 +!outer_vlines() +!inner_vlines() + +!orgx=50 +!orgy=80 +!outer_longrect() +!inner_longrect() + +!orgx=30 +!inner_longrect() + +!} + +!feedrate_tests(){ + +!orgx=20 +!extruderate=0.045 +!feedrate_test1() + +!orgx=30 +!extruderate=0.060 +!feedrate_test1() + +!orgx=40 +!extruderate=0.080 +!feedrate_test1() + +!orgx=50 +!extruderate=0.100 +!feedrate_test1() + +!orgx=60 +!extruderate=0.125 +!feedrate_test1() + +!orgx=70 +!extruderate=0.150 +!feedrate_test1() + +!orgx=80 +!extruderate=0.200 +!feedrate_test1() + +!} + +!feedrate_test1(){ + +!orgy=20 +!outer_longrect() + +!orgy=50 +!inner_longrect() +!outer_longrect() + +!orgy=80 +!outer_longrect() +!inner_longrect() + +!} + +!layer(){ + +;-------------------- + +;!squares_tests() +;!org_oblong() +!feedrate_tests() + +!} + +!layer() + +M104 S210 ; set temperature +M140 S60 ; set bed temperature + +!zprint=0.7 +!layer() + +!zprint=1.1 +!layer() + +M83 ; extruder relative +G1 F1000 ;1000mm/min extrusion +G1 E-10; retract +G1 X0 Y0 F10000 +G28 X0 Y0 +M104 S0 ; turn off temperature +M140 S0 ; turn off bed +M84 ; disable motors diff --git a/sleepphone-cable-box.scad b/sleepphone-cable-box.scad new file mode 100644 index 0000000..836f07d --- /dev/null +++ b/sleepphone-cable-box.scad @@ -0,0 +1,248 @@ +// -*- C -*- + +include + +wall = 0.75 * [1,1,1]; +wall_bot = 1.0; + +phone = [ 76.40, 30.96, 6.00 ]; // includes socket +phone_button_z = 6.58; +minwall = 0.50; + +expose = 4.00; + +cutout_dia = 7; +cutout_between = 5; + +button_dz = 1.35; +button_dz_centre = 1.35 + 0.75; +button_dz_outer = 1.35; + +button_dy_outer = 28.42; +button_dy_inner = 19.05; +button_dy_centre = 5.65; + +nrbutton_brace_x = 37.5; + +phone_slop = 0.5 * [1,1,0] + + 0.5 * [0,0,1]; + +led = [25.9, 9.44]; // y is from edge +led_dia = 4.4; + +// next values include slop +plug_maxw = 10.95 + 0.35; +plug_minw= 6.53 + 0.35; +plug_sllen= 6.50; +plug_totlen = 84.90 + 1.5 - 2.0; // to maxw, including phone + +plug_h = 6.5; +plug_tooth_h = 0.5; +plug_tooth_dy = 0.5; + +keeper_prong = 2; +keeper_stalk_basewidth = 12; +keeper_stalk_len = 70; +keeper_stalk_gap = 1; +keeper_stalk_thick = wall_bot; + +keeper_stalk_base_reinforce_len = 5; +keeper_stalk_base_reinforce_thick = 2.0; + +// calculated + +top_z = max( phone[2] + wall[2], + phone_button_z + minwall ) + + phone_slop[2]; + +plugkeeper_x_maxw = phone[0] - plug_totlen; + +plugkeeper_p_max = [ 0, plug_maxw/2 ]; +plugkeeper_p_min = [ -plug_sllen, plug_minw/2 ];; +plugkeeper_d_u = unitvector2d( + clockwise2d( + vecdiff2d( plugkeeper_p_max, plugkeeper_p_min ) + ) + ); + +module MainProfileInnerHalf(){ + p = phone + phone_slop; + pbc = p[2] + button_dz_centre; + pbo = p[2] + button_dz_outer; + polygon([[ -2, 0 ], + [ p[1]/2, 0 ], + [ p[1]/2, p[2] ], + [ button_dy_outer/2, p[2] ], + [ button_dy_outer/2, pbo ], + [ button_dy_inner/2, pbo ], + [ button_dy_inner/2, p[2] ], + [ button_dy_centre/2, p[2] ], + [ button_dy_centre/2, pbc ], + [ -2, pbc ]]); +} + +module MainProfile(){ + p = phone + phone_slop; + difference(){ + for (m=[0,1]) mirror([m,0]) { + minkowski(){ + translate([ -wall[1], -wall_bot ]) + square([ wall[1]*2, wall_bot + wall[2] ]); + MainProfileInnerHalf(); + } + } + for (m=[0,1]) mirror([m,0]) { + MainProfileInnerHalf(); + } + } +} + +module BraceProfileInitial(){ + p = phone + phone_slop; + pbo = p[2] + button_dz_outer; + pbc = p[2] + button_dz_centre; + polygon([[ button_dy_outer/2 + 0.2, p[2] ], + [ button_dy_outer/2 + 0.2, pbo + wall[2] ], + [ button_dy_outer/2 , pbo + wall[2] ], + [ button_dy_outer/2 , p[2] ], + ]); +} + +module BraceProfileFinal(){ + p = phone + phone_slop; + pbo = p[2] + button_dz_outer; + pbc = p[2] + button_dz_centre; + polygon([[ -1, p[2] ], + [ -1, pbc + wall[2] ], + [ 0, pbc + wall[2] ], + [ 0, p[2] ] + ]); +} + +module Brace(){ + for (m=[0,1]) mirror([0,m,0]) { + hull(){ + for (e=[0,1]) { + translate([ nrbutton_brace_x + e * phone[1]/2, + 0, 0 ]){ + rotate([ 90,0,90 ]){ + linear_extrude(height= (e==0 ? wall[0] : 0.1)){ + hull(){ + BraceProfileInitial(); + if (e==0) BraceProfileFinal(); + } + } + } + } + } + } + } +} + +module BoxMain(){ + rotate([0,0,90]) rotate([90,0,0]) { + translate([0,0, expose]) + linear_extrude(height = phone[0] + wall[0] - expose, convexity=20) + MainProfile(); + translate([0,0, phone[0]]) + linear_extrude(height = wall[0], convexity=20) + hull() MainProfile(); + } +} + +module PlugKeeperProfileHalf(){ + p_max = plugkeeper_p_max; + p_min = plugkeeper_p_min; + d = plugkeeper_d_u * keeper_prong; + + translate([ plugkeeper_x_maxw, 0 ]) { + polygon([ p_min, + p_max, + p_max + d, + p_min + d ]); + } +} + +module PlugKeeperStalkProfile(){ + hull(){ + for (m=[0,1]) mirror([0,m,0]) PlugKeeperProfileHalf(); + translate([ plugkeeper_x_maxw + keeper_stalk_len, 0,0 ]) + square([ 0.1, keeper_stalk_basewidth ], center=true); + } +} + +module PlugKeeper(){ + for (m=[0,1]) mirror([0,m,0]) { + translate([0,0, -keeper_stalk_thick]) + linear_extrude(height=plug_h + keeper_stalk_thick) + PlugKeeperProfileHalf(); + + translate([0, 0, plug_h - plug_tooth_h]) + linear_extrude(height= plug_tooth_h) + translate(plugkeeper_d_u * -plug_tooth_dy) + PlugKeeperProfileHalf(); + + } +} + +module Box(){ + sidewall_cutout_z = phone[2] + phone_slop[2] + button_dz_outer; + + difference(){ + union(){ + BoxMain(); + Brace(); + } + + translate([ led[0], phone[1]/2 - led[1], 1 ]) + rotate([0,0, 360/8/2]) + cylinder(r = led_dia/2 / cos(360/8/2), h= phone[2]*2, $fn=8); + + for (ys=[-1,+1]) { + translate([ -0.1, ys * keeper_stalk_gap, -wall[2]*2]) + linear_extrude(height = wall[2]*3) + PlugKeeperStalkProfile(); + + translate([ phone[0] + wall[0], + ys * (cutout_between/2 + cutout_dia/2), + -10 ]) + cylinder( r= cutout_dia/2, h = 50, $fn = 20 ); + + translate([expose, ys*phone[1]/2, sidewall_cutout_z/2]) + rotate([90,0,0]) + translate([0,0,-3]) + cylinder( r= sidewall_cutout_z/2 - 0.1, h=6 , $fn=20 ); + } + } + + PlugKeeper(); + + translate([0,0, -keeper_stalk_thick]) + linear_extrude(height = keeper_stalk_thick) + PlugKeeperStalkProfile(); + + translate([ plugkeeper_x_maxw + keeper_stalk_len + + -keeper_stalk_base_reinforce_len/2, + -keeper_stalk_basewidth/2, + 0 ]) + mirror([0,0,1]) + cube([ keeper_stalk_base_reinforce_len, + keeper_stalk_basewidth, + keeper_stalk_base_reinforce_thick ]); +} + +module BoxPrint(){ + // This makes' Cura's support more optimal: specifically, + // it then doesn't seem to touch the back (bottom) wall + translate([0,0,phone[0]]) + rotate([0,90,0]) + Box(); +} + +//MainProfileInnerHalf(); +//MainProfile(); +//translate([0,0,1]) color("black") BraceProfileInitial(); +//translate([0,0,1]) color("black") BraceProfileFinal(); +//Brace(); +//Box(); +BoxPrint(); diff --git a/slic3r-config.ini b/slic3r-config.ini new file mode 100644 index 0000000..c496b91 --- /dev/null +++ b/slic3r-config.ini @@ -0,0 +1,98 @@ +# generated by Slic3r 0.9.7 on Fri Dec 18 00:34:03 2015 +acceleration = 0 +bed_size = 140,140 +bed_temperature = 60 +bottom_solid_layers = 2 +bridge_fan_speed = 100 +bridge_flow_ratio = 1 +bridge_speed = 60 +brim_width = 0 +complete_objects = 0 +cooling = 1 +disable_fan_first_layers = 1 +duplicate = 1 +duplicate_distance = 6 +duplicate_grid = 1,1 +end_gcode = M83 ; extruder relative\nG1 F1000 ;1000mm/min extrusion\nG1 E-10; retract\nG1 X0 Y0 F10000\nG28 X0 Y0\nM104 S0 ; turn off temperature\nM140 S0 ; turn off bed\nM84 ; disable motors +external_perimeter_speed = 100% +extra_perimeters = 1 +extruder_clearance_height = 20 +extruder_clearance_radius = 20 +extruder_offset = 0x0 +extrusion_axis = E +extrusion_multiplier = 1.0 +extrusion_width = 0 +fan_always_on = 0 +fan_below_layer_time = 60 +filament_diameter = 1.77 +fill_angle = 45 +fill_density = 0.2 +fill_pattern = rectilinear +first_layer_bed_temperature = 60 +first_layer_extrusion_width = 200% +first_layer_height = 0.4 +first_layer_speed = 30% +first_layer_temperature = 205 +g0 = 0 +gap_fill_speed = 20 +gcode_arcs = 0 +gcode_comments = 0 +gcode_flavor = reprap +infill_acceleration = 50 +infill_every_layers = 1 +infill_extruder = 1 +infill_extrusion_width = 0 +infill_speed = 60 +layer_gcode = +layer_height = 0.4 +max_fan_speed = 100 +min_fan_speed = 35 +min_print_speed = 10 +min_skirt_length = 0 +notes = +nozzle_diameter = 0.50 +only_retract_when_crossing_perimeters = 1 +output_filename_format = [input_filename_base].gcode +perimeter_acceleration = 25 +perimeter_extruder = 1 +perimeter_extrusion_width = 100% +perimeter_speed = 30 +perimeters = 2 +post_process = +print_center = 70,70 +randomize_start = 1 +retract_before_travel = 2 +retract_length = 4.5 +retract_length_toolchange = 3 +retract_lift = 0.1 +retract_restart_extra = 0 +retract_restart_extra_toolchange = 0 +retract_speed = 30 +rotate = 0 +scale = 1 +skirt_distance = 3 +skirt_height = 1 +skirts = 2 +slowdown_below_layer_time = 15 +small_perimeter_speed = 30 +solid_fill_pattern = rectilinear +solid_infill_below_area = 1 +solid_infill_every_layers = 0 +solid_infill_speed = 60 +start_gcode = G28 ; home all axes +support_material = 0 +support_material_angle = 0 +support_material_extruder = 1 +support_material_extrusion_width = 0 +support_material_pattern = rectilinear +support_material_spacing = 2.5 +support_material_speed = 60 +support_material_threshold = 45 +temperature = 205 +threads = 8 +top_solid_infill_speed = 50 +top_solid_layers = 2 +travel_speed = 130 +use_relative_e_distances = 0 +vibration_limit = 0 +z_offset = 0 diff --git a/smallfilamentclip.scad b/smallfilamentclip.scad new file mode 100644 index 0000000..724d4cf --- /dev/null +++ b/smallfilamentclip.scad @@ -0,0 +1,40 @@ +include +include + +rad=7.7; +smrad=2.0; +h=3.5; +w=2.5; +teethw=1.5; + +looprad=2.5; +loopw=w; + +fdia=1.77; +//fdia=3; + +d=0.01; + +module FilamentClip() { + linear_extrude(height=h) { + assign($fn=80) { + FlatArc(0,0, rad-w/2,rad+w/2, 80,361); + } + assign($fn=30) { + FlatArc(0,rad+looprad+w, looprad,looprad+loopw); + } + FlatArc(0, rad-smrad, smrad-w/2,smrad+w/2, -55,91); + FlatArc(rad-smrad, 0, smrad-w/2,smrad+w/2, 145,-1); + } + + for (mir=[0,1]) { + mirror([0,mir,0]) + mirror([1,0,0]) + rotate([0,0,-56]) + translate([rad+w*0.3+teethw*0.3+fdia/2 -0.6, -1.1, 0]) + rotate([0,0,95]) + FilamentTeeth(fdia=fdia); + } +} + +FilamentClip(); diff --git a/splitpin.scad b/splitpin.scad new file mode 100644 index 0000000..9631c95 --- /dev/null +++ b/splitpin.scad @@ -0,0 +1,81 @@ +// -*- C -*- + +include + +tau = 6.28318530718; +function deg2rad(deg) = deg/360 * tau; +function rad2deg(rad) = rad/tau * 360; + +module SplitPin(w=1.5, holeminrad=2.50, thick=3, deviationrad=1.5, + mainlen=15, handlerad=20, handlelen=12) { + spare = holeminrad*2 - deviationrad - w*2; + echo("splitpin spare",spare); + %translate([0,mainlen+handlelen,0]) cylinder(r=spare, h=thick); + %translate([0,mainlen,thick/2]) rotate([90,0,0]) + cylinder(r=holeminrad, h=thick); + + bent_dx = holeminrad; + unbent_dx = bent_dx + deviationrad; + + unbent_subang = atan(unbent_dx / mainlen); + unbent_rad = mainlen / deg2rad(unbent_subang); + + corner_x = unbent_rad * (1 - cos(unbent_subang)); + corner_y = unbent_rad * sin(unbent_subang); + + main_cx = unbent_rad; + +// translate([w*1.5, 0, 0]) { +// translate([corner_x, corner_y, 10]) %cube([10,10,10]); +// translate([bent_dx, 0, 10]) %cube([10,10,10]); +// translate([unbent_dx, 5, 10]) %cube([10,10,10]); +// } + + linear_extrude(height=thick) { + for (xmir=[0,1]) mirror([xmir,0,0]) + FlatArc(0,0, w*0.5, w*1.5, 270-1,360); + translate([w*1.5, 0, 0]) { + FlatArc($fa=1, main_cx,0, unbent_rad, unbent_rad+w, + 180-unbent_subang, 180); + translate([corner_x, corner_y]) rotate([0,0,-unbent_subang]) { + rotate([0,0,10]) + translate([w*0.2,0,0]) + translate([-(w + deviationrad), -0.1]) + square(size=[w + deviationrad, w+0.1]); + FlatArc(-deviationrad + handlerad, w, + handlerad, handlerad+w, + 180-rad2deg(handlelen/handlerad), 180+rad2deg(w/handlerad), + $fa=0.25, $fn=60); + } + } + mirror([1,0,0]) translate([w*1.5, 0, 0]) + FlatArc($fa=1, main_cx,0, unbent_rad, unbent_rad+w, + 180-(unbent_subang + rad2deg((handlelen+w)/unbent_rad)), 180); + } +} + +module SplitPinCavity(w=1.5, holeminrad=2.50, thick=3, deviationrad=1.5, + mainlen=15, slop=0.5, insertby = 5) { + smallgap2 = holeminrad; + biggap2 = smallgap2 + deviationrad + slop; + toegap2 = w*1.5 + slop; + toeend = -mainlen-insertby; + + translate([0,thick/2,0]) rotate([90,0,0]) { + linear_extrude(height = thick + slop*2) { + for (xmir=[0,1]) mirror([xmir,0]) { + polygon([[-0.1, 1], + [(smallgap2+biggap2)/2, 1], + [smallgap2, -insertby], + [biggap2, -insertby], + [toegap2, toeend-1], + [-0.1, toeend-1]]); + } + } + } +} + +SplitPin(); +translate([0,15+5,-10]) + rotate([-90,0,0]) + SplitPinCavity(); diff --git a/sprinkler-spike-receptacle.scad b/sprinkler-spike-receptacle.scad new file mode 100644 index 0000000..c1ac3b5 --- /dev/null +++ b/sprinkler-spike-receptacle.scad @@ -0,0 +1,200 @@ +// -*- C -*- + +main_height = 95; + +spike_web_thick = 2.52 + 0.75; + +spike_top_width = 21.04 + 1.5; + +spike_botpos_height = 9.5; +spike_botpos_width = 11.68 + 0.00; + +topwall_width = 1.5; + +mount_dist = 20; +mount_width = 10; +mount_height = 5; +mount_hole_dia = 4.5; +mount_head_dia = 7.5; +mount_hole_th = 2.5; + +strap_height = main_height * 0.5; + +strap_width = 5.5; +strap_thick = 2.5; +strap_around = 2.5; +strap_fixing_height = 4.0; +strap_fixing_slope = 1.0; + +// calculated + +main_width = spike_top_width + topwall_width*2; + +pos_web_thick = spike_web_thick + topwall_width*2; + +module NegativePlan(){ + x4z = + (spike_top_width - spike_botpos_width) / + (main_height - spike_botpos_height); + + x0 = (spike_botpos_width - x4z * spike_botpos_height)/2; + x1 = spike_top_width/2; + z1 = main_height; + + polygon([[ x0, -5], + [ x0, 0], + [ x1, z1], + [ x1, z1+5], + [-x1, z1+5], + [-x1, z1], + [-x0, 0], + [-x0, -5]]); +} + +module SomeMidRounding(sq_size, z_extra) { + translate([0,0,-z_extra]) + linear_extrude(height= main_height + z_extra*2) + rotate(45) + square( sq_size, center=true ); +} + +module PositiveMidRounding(){ + SomeMidRounding(pos_web_thick*2, 0); +} + +module NegativeMidRounding(){ + SomeMidRounding(spike_web_thick*2.5, 5); +} + +module PositivePlan(){ + w = main_width; + translate([ -w/2, 0 ]) + square([ w, main_height ]); +} + +module MultiplySolidifyPlan(th){ + for (r=[0,90]) { + rotate([0,0,r]) + rotate([90,0,0]) + translate([0,0,-th/2]) + linear_extrude(height=th) + children(0); + } +} + +module MultiplyForFixings(){ + for (r=[0:90:270]) + rotate([0,0,r]) + children(0); +} + +module FixingsPositive(){ + // mount + translate([ -1, + -mount_width/2, + 0 ]) + cube([ mount_dist + mount_width/2 + 1, + mount_width, + mount_height ]); + + // strap + for (m=[0,1]) mirror([0,m,0]) { + translate([main_width/2, 0, strap_height]) { + hull(){ + translate([ -strap_around, + -pos_web_thick/2, + -(strap_thick + strap_around) / strap_fixing_slope ]) + cube([ strap_around, + pos_web_thick/2 - strap_width/2, + 0.5 ]); + translate([ -strap_around, + -(strap_around + strap_width/2), + 0 ]) + cube([ strap_around*2 + strap_thick, + strap_around, + strap_fixing_height ]); + } + mirror([0,1,0]) + translate([ strap_thick, + -strap_width/2, + 0 ]) + cube([ strap_around, + strap_around + strap_width, + strap_fixing_height ]); + } + } +} + +module FixingsNegative(){ + // mount hole + translate([ mount_dist, 0,0 ]) { + translate([0,0, -1]) + cylinder(r= mount_hole_dia/2, h= 20, $fn=20); + translate([0,0, mount_hole_th]) + cylinder(r = mount_head_dia/2, h=20, $fn=20); + } +} + +module Main(){ + difference(){ + union(){ + MultiplySolidifyPlan(pos_web_thick) PositivePlan(); + PositiveMidRounding(); + MultiplyForFixings() FixingsPositive(); + } + MultiplySolidifyPlan(spike_web_thick) NegativePlan(); + NegativeMidRounding(); + MultiplyForFixings() FixingsNegative(); + } +} + +module PlanTest(){ + linear_extrude(height=2.0){ + difference(){ + PositivePlan(); + NegativePlan(); + } + difference(){ + circle(r = spike_botpos_width/2 + 5); + circle(r = spike_botpos_width/2); + translate([-50, 0]) square([100,50]); + } + } + linear_extrude(height=4.0){ + difference(){ + translate([ -main_width/2, 0 ]) square([ main_width, 2 ]); + NegativePlan(); + } + } +} + +module MainFitTest(){ + for (top = [0,1]) { + translate([ top * (mount_dist*2 + mount_width), 0,0 ]){ + intersection(){ + translate([0, 0, (-main_height + 0.5) * top]) + Main(); + translate([-50,-50,0]) + cube([100,100, spike_botpos_height + 1.5]); + } + } + } +} + +module Tests(){ + translate([-mount_dist*3, 0,0]) + PlanTest(); + MainFitTest(); +} + +module StrapFixingTest(){ + intersection(){ + Main(); + translate([ -10, -10, 40 ]) + cube([ 20, 40, 15 ]); + } +} + +//Tests(); +//StrapFixingTest(); +Main(); diff --git a/startech-dell-usb-cable-retainer.scad b/startech-dell-usb-cable-retainer.scad new file mode 100644 index 0000000..122f76c --- /dev/null +++ b/startech-dell-usb-cable-retainer.scad @@ -0,0 +1,87 @@ +// -*- C -*- + +include + +body_depth = 40.15 + 4; +body_height = 16.78 + 0.50; + +back_round_depth = 2.0; +back_round_rad = 8.0; +back_above_height = 5.3; +back_thick = 3.0; + +conn_thick = 6.42 + 2.25; +wire_thick = 6.00 + 0.75; +total_depth = 63.82 - 1.0; + +body_front_overlap = 3; + +prong_higher = 1.5; +prong_depth = 5.0; +prong_width = 2.0; + +base_thick = 4; + +$fa= 3; +$fs= 0.3; + +// calculated + +epp0 = [ 0, -body_height/2 ]; +epp1 = [ 0, -conn_thick/2 ]; +epp2 = epp1 + [ -body_front_overlap, 0 ]; +epp3 = [ +body_depth -total_depth, epp2[1] ]; +epp4 = [ epp3[0], +conn_thick/2 +prong_higher ]; +epp4a = epp4 + prong_higher * [0,-1]; +epp4b = epp4 + prong_higher * [1,0]; +epp5 = epp4 + [ -prong_depth, 0 ]; +epp6 = [ epp5[0], epp0[1] -base_thick ]; +epp7 = [ epp2[0], epp6[1] ]; +epp12 = [ +body_depth +back_round_rad, 0 ]; +epp11 = [ +body_depth +back_round_depth, epp0[1] ]; +epp10 = [ epp11[0], +back_above_height ]; +epp9 = epp10 + [ +back_thick, 0 ]; +epp8 = [ epp9[0], epp7[1] ]; + +y1 = wire_thick/2; +y2 = y1 + prong_width; + +module MainElevation(){ + polygon([epp0, + epp1, + epp3, + epp4a, + epp4b, + epp5, + epp6, + epp8, + epp9, + epp10, + epp11 + ]); + intersection(){ + translate(epp12) circle(r= back_round_rad); + rectfromto(epp8, + epp10 + [-back_round_rad, 0]); + } +} + +module Retainer(){ + difference(){ + linextr_y_xz( -y2, +y2 ) { + MainElevation(); + } + linextr_y_xz( -y1, +y1 ) { + rectfromto( epp7 + [+1, -1], + epp5 + [-1, +1] ); + } + } +} + +module RetainerPrint(){ + rotate([0,0,180]) Retainer(); +} + +//MainElevation(); + +RetainerPrint(); diff --git a/steamer-handle-clip.scad b/steamer-handle-clip.scad new file mode 100644 index 0000000..5001861 --- /dev/null +++ b/steamer-handle-clip.scad @@ -0,0 +1,50 @@ +// -*- C -*- + +include +include + +width = 30 - 2; +cup = 2.5; +jaw = 32.36 - 2.00 - 2.00 - 3.00; +th = 3.0; +l = 15; + +a = cup; +b = width/2; +alpha = atan2(a, b); +c = vectorlen2d([a, b]); +r = a / (1 - cos(2*alpha)); +C = [0, a-r]; + +$fa = 1; + +module HalfBaseline() { + intersection(){ + translate(C + [0, jaw/2]) + circle(r=r); + rectfromto([ -width/2, -1, ], + [ width/2, jaw ]); + } +} + +module Baseline(){ + HalfBaseline(); + mirror([0,1]) HalfBaseline(); +} + +module Plan(){ + difference(){ + offset(delta=th) Baseline(); + Baseline(); + rectfromto([-width, -jaw/2], + [0, jaw/2]); + } +} + +module Thing(){ + linextr(0,l) Plan(); +} + +//HalfPlan(); +//Plan(); +Thing(); diff --git a/stringing-test.scad b/stringing-test.scad new file mode 100644 index 0000000..a75704d --- /dev/null +++ b/stringing-test.scad @@ -0,0 +1,15 @@ +// -*- C -*- + +height = 15; +$fn= 20; + +cylinder(r=7, h=height); + +for (r= [0:4]) { + rotate(r * 72) { + d = 10 * pow(1.5, r); + cube([d, 3, 2]); + translate([d, 0,0]) + cube([7, 7, height]); + } +} diff --git a/summit-lantern-hook.scad b/summit-lantern-hook.scad new file mode 100644 index 0000000..e91573a --- /dev/null +++ b/summit-lantern-hook.scad @@ -0,0 +1,64 @@ +// -*- C -*- + +include + +height = 60; +curl = 10; +width = 85; +sides_depth = 50; +th = 6; +th2 = 4; + +$fa = 3; +$fs = 0.3; + +// calculated + +upper_r = th/2; +upper_ctr_maj_r = curl/2 + upper_r; + +zmin = curl/2 + th; + +module UpperPlan(){ + circle(r = upper_r); +} + +module EndCurl(){ + rotate([90,0,0]) + rotate_extrude(angle=180) + translate([upper_ctr_maj_r, 0]) + UpperPlan(); + translate([-upper_ctr_maj_r, 0,0]) + sphere(r= upper_r); +} + +module Upper(){ + translate([upper_ctr_maj_r, 0, 0]) + linextr(-0.1, height + 0.1) + UpperPlan(); + translate([0, 0, height]) + EndCurl(); +} + +module Lower(){ + rotate([180,0,0]) + EndCurl(); + linextr(-zmin, -zmin + th) { + square(center=true, [th2, width]); + for (m=[0,1]) + mirror([0,m]) + hull() + { + for (x= sides_depth/2 * [-1,+1]) + translate([ x, width/2 - th2/2 ]) + circle(r= th2/2); + } + } +} + +module Hook(){ + Upper(); + Lower(); +} + +Hook(); diff --git a/svg-prep-dxf b/svg-prep-dxf new file mode 100755 index 0000000..a5ecc38 --- /dev/null +++ b/svg-prep-dxf @@ -0,0 +1,178 @@ +#!/bin/bash +us=svg-prep-dxf +usage () { cat <&2 "svg-dxf-prep: $*"; exit 1; } +badusage () { usage >&2; exit 1; } + +flatness=0.01 +# ^ this number seems to work reasonably well +# although maybe it should be adjusted? + +while true; do + case "$1" in + --flatness=*) + flatness="${1#*=}" + ;; + -*) + badusage + ;; + *) + break + ;; + esac + shift +done + +case "$#" in +2) ;; +*) badusage ;; +esac + +source=$1 +dest=$2 + +case "$source" in +*.svg) ;; +*) badusage ;; +esac + +case "$dest" in +*.dxf) ;; +*) badusage ;; +esac + +tmpdir="$(dirname "$dest")/.$(basename "$dest").tmpdir" +rm -rf -- "$tmpdir" +mkdir -- "$tmpdir" + +case "$tmpdir" in +/*) abstmpdir="$tmpdir" ;; +*) abstmpdir="$PWD/$tmpdir" ;; +esac + +cp -- "$source" "$tmpdir/t.svg" + +# startx seems to send "client" stdout/stderr somewhere hopeless +exec 4>&2 + +baseextdir=$(inkscape -x) +ourid=uk.org.greenend.chiark.ijackson.swirly.flatten + +# inkscape doesn't provide a way to specify a per-invocation +# extension directory, but it does look in $HOME. +# Anyway, we're going to want a fresh HOME for startx. +ourxd="$tmpdir"/.config/inkscape/extensions +mkdir -p "$ourxd" +mkdir -p "$tmpdir/.local/share" # inkscape complains otherwise, wtf + +# Putting the absolute path in the XML doesn't seem to work: +# inkscape complains that this "dependency" (implicit, apparently) +# is not satisfied. +# I'm not sure why this is, but this does work: +ln -s -- "$baseextdir/flatten.py" "$ourxd" + +xmlstarlet \ +ed \ + -N ie=http://www.inkscape.org/namespace/inkscape/extension \ + -u "/ie:inkscape-extension/ie:_name" -v "Our Flatten Beziers" \ + -u "/ie:inkscape-extension/ie:id" -v $ourid \ + -d '/ie:inkscape-extension/ie:dependency' \ + -u '/ie:inkscape-extension/ie:param[@name="flatness"]' -v $flatness \ + "$baseextdir"/flatten.inx \ + >"$ourxd"/our-flatten.inx +# known bugs with this approach: +# - we rely on the .inx filename +# - we rely on flatten.py being in the extensions/ directory +# and called exactly that +# - we drop the dependencies rather than editing them + +cat <<'END' >"$tmpdir/run-inkscape" +#!/bin/sh +exec >&4 2>&4 +echo +printf "running inkscape to transform and clean up..." +cd "$HOME" +inkscape \ + --with-gui \ + t.svg \ + --verb=ToolNode \ + --verb=EditSelectAll \ + --verb=SelectionUnGroup \ + --verb=EditSelectAll \ + --verb=StrokeToPath \ + --verb=ToolNode \ + --verb=EditSelectAll \ + --verb=SelectionUnion \ + --verb=EditSelectAll \ + --verb=uk.org.greenend.chiark.ijackson.swirly.flatten.noprefs \ + --verb=FileSave \ + --verb=FileQuit \ + +echo done. +echo +END +chmod +x "$tmpdir"/run-inkscape + +cat < +include + +// https://en.wikipedia.org/wiki/ISO_metric_screw_thread + +// M6 +thread_nom = 6; +thread_pitch = 1.00; +thread_act = thread_nom - 0.300; +head_size = 10; + +thread_len = 12.5; +base_th = 1.5; + +$test = false; + +// calculated + +base_dia = head_size / cos(30); + +module MachineScrew(){ + translate([0, 0, -0.1]) + render() + metric_thread(diameter=thread_act, pitch=thread_pitch, + leadin=1, internal=false, + test=$test, length=thread_len + 0.1); + linextr(-base_th, 0) + circle(r= base_dia/2, $fn=6); +} + +MachineScrew(); diff --git a/thread-internal-test.scad b/thread-internal-test.scad new file mode 100644 index 0000000..cab40b6 --- /dev/null +++ b/thread-internal-test.scad @@ -0,0 +1,46 @@ +// -*- C -*- + +include +include + +// https://en.wikipedia.org/wiki/ISO_metric_screw_thread + +// M6 +thread_nom = 4; +thread_pitch = 0.70; +thread_act = thread_nom + 0.375; +head_size = 10; + +thread_len = 12.5; +base_th = 1.5; +base_sz = [40, head_size]; + +$test = false; + +// calculated + +base_dia = head_size / cos(30); + +module ScrewThread(){ + translate([0, 0, -0.1]) + render() + metric_thread(diameter=thread_act, pitch=thread_pitch, + leadin=1, internal=true, + test=$test, length=thread_len + 0.1); +} + +module TestThread(){ + difference(){ + union(){ + linextr(-base_th, 0) + square(center=true, base_sz); + + linextr(-base_th, thread_len - 0.1) + circle(r= base_dia/2, $fn=6); + } + + ScrewThread(); + } +} + +TestThread(); diff --git a/threads.scad b/threads.scad new file mode 100644 index 0000000..b2eee23 --- /dev/null +++ b/threads.scad @@ -0,0 +1,407 @@ +/* + * ISO-standard metric threads, following this specification: + * http://en.wikipedia.org/wiki/ISO_metric_screw_thread + * + * Copyright 2020 Dan Kirshner - dan_kirshner@yahoo.com + * 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. + * + * See . + * + * Version 2.5. 2020-04-11 Leadin option works for internal threads. + * Version 2.4. 2019-07-14 Add test option - do not render threads. + * Version 2.3. 2017-08-31 Default for leadin: 0 (best for internal threads). + * Version 2.2. 2017-01-01 Correction for angle; leadfac option. (Thanks to + * Andrew Allen .) + * Version 2.1. 2016-12-04 Chamfer bottom end (low-z); leadin option. + * Version 2.0. 2016-11-05 Backwards compatibility (earlier OpenSCAD) fixes. + * Version 1.9. 2016-07-03 Option: tapered. + * Version 1.8. 2016-01-08 Option: (non-standard) angle. + * Version 1.7. 2015-11-28 Larger x-increment - for small-diameters. + * Version 1.6. 2015-09-01 Options: square threads, rectangular threads. + * Version 1.5. 2015-06-12 Options: thread_size, groove. + * Version 1.4. 2014-10-17 Use "faces" instead of "triangles" for polyhedron + * Version 1.3. 2013-12-01 Correct loop over turns -- don't have early cut-off + * Version 1.2. 2012-09-09 Use discrete polyhedra rather than linear_extrude () + * Version 1.1. 2012-09-07 Corrected to right-hand threads! + */ + +// Examples. +// +// Standard M8 x 1. +// metric_thread (diameter=8, pitch=1, length=4); + +// Square thread. +// metric_thread (diameter=8, pitch=1, length=4, square=true); + +// Non-standard: long pitch, same thread size. +//metric_thread (diameter=8, pitch=4, length=4, thread_size=1, groove=true); + +// Non-standard: 20 mm diameter, long pitch, square "trough" width 3 mm, +// depth 1 mm. +//metric_thread (diameter=20, pitch=8, length=16, square=true, thread_size=6, +// groove=true, rectangle=0.333); + +// English: 1/4 x 20. +//english_thread (diameter=1/4, threads_per_inch=20, length=1); + +// Tapered. Example -- pipe size 3/4" -- per: +// http://www.engineeringtoolbox.com/npt-national-pipe-taper-threads-d_750.html +// english_thread (diameter=1.05, threads_per_inch=14, length=3/4, taper=1/16); + +// Thread for mounting on Rohloff hub. +//difference () { +// cylinder (r=20, h=10, $fn=100); +// +// metric_thread (diameter=34, pitch=1, length=10, internal=true, n_starts=6); +//} + + +// ---------------------------------------------------------------------------- +function segments (diameter) = min (50, max (ceil (diameter*6), 25)); + + +// ---------------------------------------------------------------------------- +// diameter - outside diameter of threads in mm. Default: 8. +// pitch - thread axial "travel" per turn in mm. Default: 1. +// length - overall axial length of thread in mm. Default: 1. +// internal - true = clearances for internal thread (e.g., a nut). +// false = clearances for external thread (e.g., a bolt). +// (Internal threads should be "cut out" from a solid using +// difference ()). Default: false. +// n_starts - Number of thread starts (e.g., DNA, a "double helix," has +// n_starts=2). See wikipedia Screw_thread. Default: 1. +// thread_size - (non-standard) axial width of a single thread "V" - independent +// of pitch. Default: same as pitch. +// groove - (non-standard) true = subtract inverted "V" from cylinder +// (rather thanadd protruding "V" to cylinder). Default: false. +// square - true = square threads (per +// https://en.wikipedia.org/wiki/Square_thread_form). Default: +// false. +// rectangle - (non-standard) "Rectangular" thread - ratio depth/(axial) width +// Default: 0 (standard "v" thread). +// angle - (non-standard) angle (deg) of thread side from perpendicular to +// axis (default = standard = 30 degrees). +// taper - diameter change per length (National Pipe Thread/ANSI B1.20.1 +// is 1" diameter per 16" length). Taper decreases from 'diameter' +// as z increases. Default: 0 (no taper). +// leadin - 0 (default): no chamfer; 1: chamfer (45 degree) at max-z end; +// 2: chamfer at both ends, 3: chamfer at z=0 end. +// leadfac - scale of leadin chamfer length (default: 1.0 = 1/2 thread). +// test - true = do not render threads (just draw "blank" cylinder). +// Default: false (draw threads). +module metric_thread (diameter=8, pitch=1, length=1, internal=false, n_starts=1, + thread_size=-1, groove=false, square=false, rectangle=0, + angle=30, taper=0, leadin=0, leadfac=1.0, test=false) +{ + // thread_size: size of thread "V" different than travel per turn (pitch). + // Default: same as pitch. + local_thread_size = thread_size == -1 ? pitch : thread_size; + local_rectangle = rectangle ? rectangle : 1; + + n_segments = segments (diameter); + h = (test && ! internal) ? 0 : (square || rectangle) ? local_thread_size*local_rectangle/2 : local_thread_size / (2 * tan(angle)); + + h_fac1 = (square || rectangle) ? 0.90 : 0.625; + + // External thread includes additional relief. + h_fac2 = (square || rectangle) ? 0.95 : 5.3/8; + + tapered_diameter = diameter - length*taper; + + difference () { + union () { + if (! groove) { + if (! test) { + metric_thread_turns (diameter, pitch, length, internal, n_starts, + local_thread_size, groove, square, rectangle, angle, + taper); + } + } + + difference () { + + // Solid center, including Dmin truncation. + if (groove) { + cylinder (r1=diameter/2, r2=tapered_diameter/2, + h=length, $fn=n_segments); + } else if (internal) { + cylinder (r1=diameter/2 - h*h_fac1, r2=tapered_diameter/2 - h*h_fac1, + h=length, $fn=n_segments); + } else { + + // External thread. + cylinder (r1=diameter/2 - h*h_fac2, r2=tapered_diameter/2 - h*h_fac2, + h=length, $fn=n_segments); + } + + if (groove) { + if (! test) { + metric_thread_turns (diameter, pitch, length, internal, n_starts, + local_thread_size, groove, square, rectangle, + angle, taper); + } + } + } + + // Internal thread lead-in: take away from external solid. + if (internal) { + + // "Negative chamfer" z=0 end if leadin is 2 or 3. + if (leadin == 2 || leadin == 3) { + cylinder (r1=diameter/2, r2=diameter/2 - h*h_fac1*leadfac, h=h*h_fac1*leadfac, + $fn=n_segments); + } + + // "Negative chamfer" z-max end if leadin is 1 or 2. + if (leadin == 1 || leadin == 2) { + translate ([0, 0, length + 0.05 - h*h_fac1*leadfac]) { + cylinder (r1=tapered_diameter/2 - h*h_fac1*leadfac, h=h*h_fac1*leadfac, + r2=tapered_diameter/2, + $fn=n_segments); + } + } + } + } + + if (! internal) { + + // Chamfer z=0 end if leadin is 2 or 3. + if (leadin == 2 || leadin == 3) { + difference () { + cylinder (r=diameter/2 + 1, h=h*h_fac1*leadfac, $fn=n_segments); + + cylinder (r2=diameter/2, r1=diameter/2 - h*h_fac1*leadfac, h=h*h_fac1*leadfac, + $fn=n_segments); + } + } + + // Chamfer z-max end if leadin is 1 or 2. + if (leadin == 1 || leadin == 2) { + translate ([0, 0, length + 0.05 - h*h_fac1*leadfac]) { + difference () { + cylinder (r=diameter/2 + 1, h=h*h_fac1*leadfac, $fn=n_segments); + + cylinder (r1=tapered_diameter/2, r2=tapered_diameter/2 - h*h_fac1*leadfac, h=h*h_fac1*leadfac, + $fn=n_segments); + } + } + } + } + } +} + + +// ---------------------------------------------------------------------------- +// Input units in inches. +// Note: units of measure in drawing are mm! +module english_thread (diameter=0.25, threads_per_inch=20, length=1, + internal=false, n_starts=1, thread_size=-1, groove=false, + square=false, rectangle=0, angle=30, taper=0, leadin=0, + leadfac=1.0, test=false) +{ + // Convert to mm. + mm_diameter = diameter*25.4; + mm_pitch = (1.0/threads_per_inch)*25.4; + mm_length = length*25.4; + + echo (str ("mm_diameter: ", mm_diameter)); + echo (str ("mm_pitch: ", mm_pitch)); + echo (str ("mm_length: ", mm_length)); + metric_thread (mm_diameter, mm_pitch, mm_length, internal, n_starts, + thread_size, groove, square, rectangle, angle, taper, leadin, + leadfac, test); +} + +// ---------------------------------------------------------------------------- +module metric_thread_turns (diameter, pitch, length, internal, n_starts, + thread_size, groove, square, rectangle, angle, + taper) +{ + // Number of turns needed. + n_turns = floor (length/pitch); + + intersection () { + + // Start one below z = 0. Gives an extra turn at each end. + for (i=[-1*n_starts : n_turns+1]) { + translate ([0, 0, i*pitch]) { + metric_thread_turn (diameter, pitch, internal, n_starts, + thread_size, groove, square, rectangle, angle, + taper, i*pitch); + } + } + + // Cut to length. + translate ([0, 0, length/2]) { + cube ([diameter*3, diameter*3, length], center=true); + } + } +} + + +// ---------------------------------------------------------------------------- +module metric_thread_turn (diameter, pitch, internal, n_starts, thread_size, + groove, square, rectangle, angle, taper, z) +{ + n_segments = segments (diameter); + fraction_circle = 1.0/n_segments; + for (i=[0 : n_segments-1]) { + rotate ([0, 0, i*360*fraction_circle]) { + translate ([0, 0, i*n_starts*pitch*fraction_circle]) { + //current_diameter = diameter - taper*(z + i*n_starts*pitch*fraction_circle); + thread_polyhedron ((diameter - taper*(z + i*n_starts*pitch*fraction_circle))/2, + pitch, internal, n_starts, thread_size, groove, + square, rectangle, angle); + } + } + } +} + + +// ---------------------------------------------------------------------------- +module thread_polyhedron (radius, pitch, internal, n_starts, thread_size, + groove, square, rectangle, angle) +{ + n_segments = segments (radius*2); + fraction_circle = 1.0/n_segments; + + local_rectangle = rectangle ? rectangle : 1; + + h = (square || rectangle) ? thread_size*local_rectangle/2 : thread_size / (2 * tan(angle)); + outer_r = radius + (internal ? h/20 : 0); // Adds internal relief. + //echo (str ("outer_r: ", outer_r)); + + // A little extra on square thread -- make sure overlaps cylinder. + h_fac1 = (square || rectangle) ? 1.1 : 0.875; + inner_r = radius - h*h_fac1; // Does NOT do Dmin_truncation - do later with + // cylinder. + + translate_y = groove ? outer_r + inner_r : 0; + reflect_x = groove ? 1 : 0; + + // Make these just slightly bigger (keep in proportion) so polyhedra will + // overlap. + x_incr_outer = (! groove ? outer_r : inner_r) * fraction_circle * 2 * PI * 1.02; + x_incr_inner = (! groove ? inner_r : outer_r) * fraction_circle * 2 * PI * 1.02; + z_incr = n_starts * pitch * fraction_circle * 1.005; + + /* + (angles x0 and x3 inner are actually 60 deg) + + /\ (x2_inner, z2_inner) [2] + / \ + (x3_inner, z3_inner) / \ + [3] \ \ + |\ \ (x2_outer, z2_outer) [6] + | \ / + | \ /| + z |[7]\/ / (x1_outer, z1_outer) [5] + | | | / + | x | |/ + | / | / (x0_outer, z0_outer) [4] + | / | / (behind: (x1_inner, z1_inner) [1] + |/ | / + y________| |/ + (r) / (x0_inner, z0_inner) [0] + + */ + + x1_outer = outer_r * fraction_circle * 2 * PI; + + z0_outer = (outer_r - inner_r) * tan(angle); + //echo (str ("z0_outer: ", z0_outer)); + + //polygon ([[inner_r, 0], [outer_r, z0_outer], + // [outer_r, 0.5*pitch], [inner_r, 0.5*pitch]]); + z1_outer = z0_outer + z_incr; + + // Give internal square threads some clearance in the z direction, too. + bottom = internal ? 0.235 : 0.25; + top = internal ? 0.765 : 0.75; + + translate ([0, translate_y, 0]) { + mirror ([reflect_x, 0, 0]) { + + if (square || rectangle) { + + // Rule for face ordering: look at polyhedron from outside: points must + // be in clockwise order. + polyhedron ( + points = [ + [-x_incr_inner/2, -inner_r, bottom*thread_size], // [0] + [x_incr_inner/2, -inner_r, bottom*thread_size + z_incr], // [1] + [x_incr_inner/2, -inner_r, top*thread_size + z_incr], // [2] + [-x_incr_inner/2, -inner_r, top*thread_size], // [3] + + [-x_incr_outer/2, -outer_r, bottom*thread_size], // [4] + [x_incr_outer/2, -outer_r, bottom*thread_size + z_incr], // [5] + [x_incr_outer/2, -outer_r, top*thread_size + z_incr], // [6] + [-x_incr_outer/2, -outer_r, top*thread_size] // [7] + ], + + faces = [ + [0, 3, 7, 4], // This-side trapezoid + + [1, 5, 6, 2], // Back-side trapezoid + + [0, 1, 2, 3], // Inner rectangle + + [4, 7, 6, 5], // Outer rectangle + + // These are not planar, so do with separate triangles. + [7, 2, 6], // Upper rectangle, bottom + [7, 3, 2], // Upper rectangle, top + + [0, 5, 1], // Lower rectangle, bottom + [0, 4, 5] // Lower rectangle, top + ] + ); + } else { + + // Rule for face ordering: look at polyhedron from outside: points must + // be in clockwise order. + polyhedron ( + points = [ + [-x_incr_inner/2, -inner_r, 0], // [0] + [x_incr_inner/2, -inner_r, z_incr], // [1] + [x_incr_inner/2, -inner_r, thread_size + z_incr], // [2] + [-x_incr_inner/2, -inner_r, thread_size], // [3] + + [-x_incr_outer/2, -outer_r, z0_outer], // [4] + [x_incr_outer/2, -outer_r, z0_outer + z_incr], // [5] + [x_incr_outer/2, -outer_r, thread_size - z0_outer + z_incr], // [6] + [-x_incr_outer/2, -outer_r, thread_size - z0_outer] // [7] + ], + + faces = [ + [0, 3, 7, 4], // This-side trapezoid + + [1, 5, 6, 2], // Back-side trapezoid + + [0, 1, 2, 3], // Inner rectangle + + [4, 7, 6, 5], // Outer rectangle + + // These are not planar, so do with separate triangles. + [7, 2, 6], // Upper rectangle, bottom + [7, 3, 2], // Upper rectangle, top + + [0, 5, 1], // Lower rectangle, bottom + [0, 4, 5] // Lower rectangle, top + ] + ); + } + } + } +} + + + diff --git a/topeak-mtx-tortec-expeditionrack-adapter.scad b/topeak-mtx-tortec-expeditionrack-adapter.scad new file mode 100644 index 0000000..c751f78 --- /dev/null +++ b/topeak-mtx-tortec-expeditionrack-adapter.scad @@ -0,0 +1,502 @@ +// -*- C -*- + +// brk_*: "bracket", the Topeak MTX bracket +// rack_*: the Tortec rack +// adapt_*: the adapter, ie this file + +include + +// strength factor, set to 1 for real prints +//$strf = 0.33; +$strf = 1; + +brk_recess_actual = 5.20; + +rack_rail_dia = 10.40 + 0.30; +rack_width_inner = 115.86 - 1.0; // between insides of rails + +rear_elevation_nominal = 10.04; +// ^ top of rack to bottom of bracket, at rack cross rail (fam) +rear_to_front_distance = 230; // rack cross rail (fam) to very front end +rear_to_cross_rail = 43.05; // bolt centre to rail centre, rail to rear +rear_bolt_to_front_bolt = 155.4; +front_elevation_nominal = 0; // this parameter adjusts rear too somehow? + +cross_rail_distance = 232.09; + +general_gap_y = 1.0; +support_bridge_gap_z = 1.0; + +strap_w = 8.0 + 1.0; +strap_th = 2.5; +strap_barrel_dia = 14; +strap_guide_sz = 1; + +brk_block_xw = 68.5; +brk_block_z = 14.55 - 0.00; + +brk_bolt_dia = 5.0 + 0.5; +brk_nearbolt_recess_dia = 8.86 + 1.5; +brk_nearbolt_recess_depth = 1.09 + 0.25; + +bolt_nut_around = 5; +bolt_nut_around_y_extra = 3; + +brk_bolt_eff_len = 11.78; // inside of recess, to end of bolt +brk_bolt_len_slop = 0.5; +brk_bolt_nut_th = 3.89; +brk_bolt_nut_across_flats = 7.86 + 0.50; + +brk_overall_w = 90.07; + +fit_slope_len = 5; + +// "foreaftmaint" aka "fam" is the hook-like part that stops +// the adapter sliding forwards/backwards along the rails +foreaftmaint_r_slop = 0.0; +foreaftmaint_y_slop = -0.25; +foreaftmaint_top_block_zs = [34.0, 39.0]; // rearwards from bolt hole + +main_sz_y = $strf * 12; +grasp_sz = $strf * 6; +grasp_thin_sz = $strf * 0.5; +beside_strap_sz = $strf * 8; +main_sz_core_z = $strf * 12; + +// "length" in for-aft direction of interaction with rack rail +min_on_rail_sz_z = $strf * 18; + +// when printer produces support +support_around = 1.7; // how far does the support extend around (in XY) +support_remnant = 0.75; // how much frass remains attached (Z height) + +$fa=10; +$fs=1; + +// calculated + +bolt_z = -brk_block_z/2; + +front_to_rear_elevation_change = + rear_elevation_nominal - front_elevation_nominal; + +main_sz_rhs_z = max(min_on_rail_sz_z, beside_strap_sz*2 + strap_w); +main_sz_lhs_z = min_on_rail_sz_z; + +main_sz_x_fam = main_sz_y; + +brk_bottom_y = -brk_recess_actual; +adapt_main_top_y = brk_bottom_y - general_gap_y; + +// on LHS, so -ve +rack_rail_x = -(rack_width_inner/2 + rack_rail_dia/2); +rack_rail_outer_x = -(rack_width_inner/2 + rack_rail_dia); + +grasp_large_r = (rack_rail_dia + grasp_sz)/2; +grasp_small_r = (rack_rail_dia + grasp_thin_sz)/2; +grasp_large_x = rack_rail_outer_x + grasp_large_r; +grasp_small_x = rack_rail_outer_x + grasp_small_r; + +block_x = grasp_large_x + grasp_large_r; +block_y_min = adapt_main_top_y - main_sz_y; + +strap_barrel_x = rack_width_inner/2 + strap_barrel_dia/2; + +rack_shear_ratio = - front_to_rear_elevation_change / rear_to_front_distance; + +front_to_cross_rail = + cross_rail_distance * sqrt(1 - rack_shear_ratio * rack_shear_ratio) + - rear_bolt_to_front_bolt + - rear_to_cross_rail + - sqrt( pow( cross_rail_distance * rack_shear_ratio, 2 ) + - pow( front_to_rear_elevation_change, 2 ) ) + ; + +brk_bolt_nut_top_y = -brk_nearbolt_recess_depth + - brk_bolt_eff_len + brk_bolt_nut_th + brk_bolt_len_slop; + +brk_bolt_nut_r = brk_bolt_nut_across_flats/2 / cos(360/12); + +function elevation_of_bolt_for(z) = rear_elevation_nominal + + front_elevation_nominal + + (z - brk_block_z/2) * rack_shear_ratio; + +function rack_rail_y_of_elevation(elevation_nominal) = + brk_bottom_y - elevation_nominal - general_gap_y - rack_rail_dia/2; + +echo(rack_shear_ratio); + +module GraspElevation(){ + hull(){ + translate([ grasp_large_x, adapt_main_top_y - grasp_large_r ]) + circle(grasp_large_r); + + translate([ grasp_small_x, $rack_rail_y - rack_rail_dia/2 ]) + circle(grasp_small_r); + + translate([ rack_rail_x + grasp_large_r/2, + $rack_rail_y - rack_rail_dia/2 ]) + circle(grasp_small_r); + + translate([ grasp_large_x, $rack_rail_y + rack_rail_dia/2 ]) + circle(grasp_large_r); + + translate([ grasp_large_x + grasp_large_r/2, + $rack_rail_y + rack_rail_dia/2 ]) + circle(grasp_large_r); + } +} + +module BlockElevation(){ + hull(){ + rectfromto([ +block_x, adapt_main_top_y ], + [ -block_x, block_y_min ]); + rectfromto([ -grasp_large_x, adapt_main_top_y ], + [ +grasp_large_x, adapt_main_top_y - 0.1 ]); + } + hull(){ + rectfromto([ +block_x, adapt_main_top_y ], + [ -block_x, block_y_min ]); + rectfromto([ grasp_large_x, block_y_min ], + [ 0, block_y_min + 0.1 ]); + } +} + +module MainExtrude(z){ + linextr(0, z) + children(); +} +module RackShear(){ + s = rack_shear_ratio * $reverse_sign; + multmatrix([ [ 1, 0, 0, 0 ], + [ 0, 1, s , 0 ], + [ 0, 0, 1, 0 ], + [ 0, 0, 0, 1 ] ]) + children(); +} + +module GraspFixingElevation(){ + intersection(){ + union(){ + hull(){ + mirror([1,0]) { + GraspElevation(); + } + translate([ -block_x, block_y_min ] + [0,0.1]*1 ) + circle(0.1); + } + translate([ strap_barrel_x, $strap_barrel_y ]) + circle(strap_barrel_dia/2 + strap_guide_sz); + } + union(){ + rectfromto([0, $rack_rail_y], + [rack_width_inner, 50]); + intersection(){ + translate([ rack_rail_x, $rack_rail_y ]) + circle(r = rack_width_inner/2 - rack_rail_x); + polygon([ [ -block_x-0.1, 0 ], + [ rack_width_inner/2, 0 ], + $rail_fixing_fit_corner, + $rail_fixing_fit_corner + [-1,-1] * fit_slope_len, + [ -grasp_large_x - grasp_large_r*2, block_y_min ], + [ -block_x-0.1 -2, block_y_min +2 ]]); + } + } + } +} + +module StrapBarrelElevation(){ + translate([ strap_barrel_x, $strap_barrel_y ]) + circle(strap_barrel_dia/2); +} + +// Bracket support block, goes up inside bracket +// Z origin is bolt hole +module BrkBlock(){ + difference(){ + linextr( -brk_block_z/2, + +brk_block_z/2 ) { + rectfromto([ -brk_block_xw/2, adapt_main_top_y - 0.1 ], + [ +brk_block_xw/2, 0 ]); + } + linextr_y_xz( -50, 10 ) { + translate([ 0, brk_block_z + bolt_z ]) + square(center=true, + [ main_sz_x_fam + support_around*2, + support_remnant *2 ]); + } + } +} + +// Z origin is bolt hole +module BoltHole(){ + linextr_y_xz( -100, 10 ) + circle(brk_bolt_dia/2); + + linextr_y_xz( -brk_nearbolt_recess_depth, 10) + circle(brk_nearbolt_recess_dia/2); + + linextr_y_xz( -100, brk_bolt_nut_top_y ) { + hull() + for (dz = [0, support_bridge_gap_z]) + translate([0, dz]) + circle( r= brk_bolt_nut_r, $fn = 6 ); + } +} + +module IfFam(){ + if ($foreaftmaint_dz) { + children(); + } +} + +module FamLinextr(){ + IfFam() + linextr_x_yz(-main_sz_x_fam/2, +main_sz_x_fam/2) + rotate(-90) + children(); +} + +module FamGraspElevation(){ + difference(){ + hull(){ + ybot = $rack_rail_y - rack_rail_dia/2 + grasp_large_r + - fit_slope_len * 0.5; + for (y = [ + ybot, + adapt_main_top_y - grasp_large_r + ]) + for (dx= [/*-1,*/ +1] * rack_rail_dia/2) + translate([ -$foreaftmaint_rail_z + dx, y ]) + circle(r= grasp_large_r); + } + if ($foreaftmaint_cutoff) { + translate([ -$foreaftmaint_rail_z, 0 ]) + rectfromto([-100, -100], + [0, 100]); + } + } +} + +module FamStemElevation(){ + hull(){ + rectfromto([ -$foreaftmaint_rail_z + , adapt_main_top_y ], + [ 0, block_y_min]); + translate([ + -$foreaftmaint_rail_z, + $rack_rail_y + + rack_shear_ratio * $foreaftmaint_rail_z * $reverse_sign, + ]) + square([0.1, rack_rail_dia * 0.5], center=true); + } +} + +module Principal(){ + // calculated + $rack_rail_y = rack_rail_y_of_elevation($elevation_nominal); + + $strap_barrel_y = $rack_rail_y + rack_rail_dia/2 + strap_barrel_dia/2; + + $rail_fixing_fit_corner = [ + rack_width_inner/2, + $rack_rail_y - rack_rail_dia/2 + ]; + + $foreaftmaint_rail_z = brk_block_z/2 + $foreaftmaint_dz - foreaftmaint_y_slop; + + translate([0,0,brk_block_z/2]) + mirror([0,0, $reverse_sign > 0 ? 0 : 1]) + translate([0,0,-brk_block_z/2]) + difference(){ + union(){ + MainExtrude(main_sz_lhs_z){ + GraspElevation(); + } + RackShear() MainExtrude(main_sz_rhs_z){ + StrapBarrelElevation(); + } + translate([ 0,0, brk_block_z/2]) { + BrkBlock(); + } + + difference(){ + union(){ + MainExtrude(main_sz_core_z){ + BlockElevation(); + } + if ($strf<1) { + MainExtrude(max(brk_block_z, main_sz_rhs_z)){ + rectfromto([-8, adapt_main_top_y + 0.1], + [+8, block_y_min]); + rectfromto([-block_x -5, adapt_main_top_y], + [-grasp_large_x, block_y_min]); + } + } + RackShear() MainExtrude(main_sz_rhs_z){ + GraspFixingElevation(); + } + } + + translate([0,0, main_sz_rhs_z/2]) linextr(-strap_w/2, +strap_w/2) { + translate([ rack_width_inner/2 - strap_th, 0 ]) + rectfromto([ 0, -50 ], [ 50, 50 ]); + } + } + + FamLinextr(){ + if ($foreaftmaint_top_block) { + rectfromto([ -foreaftmaint_top_block_zs[0] + bolt_z, 0 ], + [ -foreaftmaint_top_block_zs[1] + bolt_z, block_y_min] ); + } + FamGraspElevation(); + } + intersection(){ + union(){ + RackShear() + FamLinextr() + FamGraspElevation(); + FamLinextr() + FamStemElevation(); + } + translate([ 0, + adapt_main_top_y - 50, + $foreaftmaint_rail_z ]) + cube(center=true, 100); + } + + linextr_y_xz( block_y_min - bolt_nut_around_y_extra , adapt_main_top_y ) + intersection(){ + translate([ 0, brk_block_z/2 ]) + circle(r = bolt_nut_around + brk_bolt_nut_r ); + rectfromto([-100, 0], [+100,+100]); + } + } + + RackShear() linextr(-10, main_sz_lhs_z+main_sz_rhs_z) { + for (mx=[0,1]) { + mirror([mx,0]) { + translate([ rack_rail_x, $rack_rail_y ]){ + hull(){ + for (dx = [-rack_rail_dia, 0]) + translate([dx, 0]) + circle(r= rack_rail_dia/2); + } + } + } + } + } + + RackShear() IfFam(){ + // Distance from bolt hole, in backwards direction + cr = rack_rail_dia/2 + foreaftmaint_r_slop; + translate([ 0, $rack_rail_y, $foreaftmaint_rail_z ]) + linextr_x_yz(+rack_rail_x, + -rack_rail_x) { + hull(){ + for (dy=[0,50]) { + translate([-dy,0]) + circle(r= cr); + } + } + hull(){ + for (dd=[[0,0], [-1,-1], [-1,+1]]) { + translate( + [-1, 0] * (rack_rail_dia - fit_slope_len) + + 20 * dd + ) + circle(r= cr); + } + } + } + } + + translate([ 0,0, brk_block_z/2]) BoltHole(); + } +} + +module ForRackForDemo(){ + elevation = elevation_of_bolt_for(rear_to_cross_rail); + rack_rail_y = rack_rail_y_of_elevation(elevation); + + rotate([atan( + front_to_rear_elevation_change / + cross_rail_distance + ), 0,0]) + translate([0, rack_rail_y, brk_block_z/2 + rack_rail_y*rack_shear_ratio]) + children(); +} + +module RackForDemoRails(){ + ForRackForDemo() { + for (m=[0]) mirror([m,0,0]) { + linextr(-(50 + cross_rail_distance), 50 + rear_to_cross_rail) + translate([rack_rail_x, 0]) + circle(r= rack_rail_dia/2); + } + } +} + +module RackForDemoCrosses(){ + ForRackForDemo() { + for (z = [ + rear_to_cross_rail, + rear_to_cross_rail - cross_rail_distance, + ]) { + translate([0,0,z]) + linextr_x_yz(rack_rail_x, -rack_rail_x) + circle(r= rack_rail_dia/2, $fn=8); + } + } +} + +module Front(){ ////toplevel + rotate([180,0,0]) + Principal($reverse_sign = -1, + $foreaftmaint_top_block = false, + $foreaftmaint_cutoff = true, + $elevation_nominal= + elevation_of_bolt_for(rear_to_cross_rail + rear_bolt_to_front_bolt), + $foreaftmaint_dz= front_to_cross_rail); +} + +module Rear(){ ////toplevel + Principal($reverse_sign = +1, + $foreaftmaint_top_block = true, + $foreaftmaint_cutoff = false, + $elevation_nominal= + elevation_of_bolt_for(rear_to_cross_rail), + $foreaftmaint_dz= rear_to_cross_rail); +} + +module SomeDemo(){ + rotate([90, 0, 0]){ + children(); + + color("blue") + translate([ 0, -2, -4 ]) + square(center=true, [ brk_overall_w, 1 ]); + + color("red") + translate([ 0, -brk_nearbolt_recess_depth, -4 ]) + linextr_y_xz(-brk_bolt_eff_len, 0) + circle(r = brk_bolt_dia/2); + + } +} + +module FrontDemo(){ ////toplevel + SomeDemo() rotate([180,0,0]) Front(); +} +module RearDemo(){ ////toplevel + SomeDemo() Rear(); +} +module RearRackDemo(){ ////toplevel + rotate([atan(rack_shear_ratio),0,0]) SomeDemo() { + Rear(); + translate([0, 0, -rear_bolt_to_front_bolt]) + rotate([180,0,0]) Front(); + %RackForDemoRails(); + color("blue") RackForDemoCrosses(); + } +} diff --git a/topeak-seatstay-lock.scad b/topeak-seatstay-lock.scad new file mode 100644 index 0000000..072a557 --- /dev/null +++ b/topeak-seatstay-lock.scad @@ -0,0 +1,147 @@ +// -*- C -*- + +pump_dia = 27 + 0.9; +seatstay_mindia = 14 + 0.5; +seatstay_maxdia = 19 + 0.7; +pump_seatstay_gap = 12.3; +pump_seatstay_delta = 0.1; +pump_ridge_width = 8 + 2.0; + +body_thick = 5; + +pin_workdepth = 16 - 1.0; +pin_width = 11 + 1.0; +pin_thick = 3 + 0.7; +pin_base = 25; + +lock_manouvre_thick = 3.7 + 0.6; +lock_manouvre_len = 18; +lock_hang_width = 17.5; +lock_manouvre_len_smaller = 13; + +body_depth_each = 5; +clatter_gap = 0.5; + +roof_extent = 7; +roof_thick = 2; + +// fudgeish + +cut_rotation = 2; +holes_rotation = 9; +pin_y_offset = 5.5; +pin_x_offset = 0.5; +ridge_rotation = 8.5; +lock_hang_ratio = 7; + +// computed + +body_depth = pin_width + body_depth_each*2; + +module Holes(forbody=false){ + translate([0, -pump_dia/2]); + rotate(-holes_rotation){ + translate([-(pump_seatstay_gap/2 + pump_dia/2), + 0]) { + if (!forbody) + rotate(-ridge_rotation + holes_rotation) + translate([-50, -pump_ridge_width/2]) + square([50, pump_ridge_width]); + circle(r=pump_dia/2, $fn=80); + } + translate([+(pump_seatstay_gap/2 + seatstay_mindia/2), + pump_dia/2 -seatstay_maxdia/2 -pump_seatstay_delta]) { + hull(){ + for (ud=[-1,1]) + translate([0, ud * (seatstay_maxdia-seatstay_mindia)/2]) + circle(r=seatstay_mindia/2, $fn=50); + } + } + } +} + +module BodyPlan(){ + minkowski(){ + circle(body_thick); + hull() + Holes(true); + } +} + +module Body(){ + translate([0,0,body_depth/2])mirror([0,0,1]){ + linear_extrude(height=body_depth){ + difference(){ + BodyPlan(); + Holes(); + } + } + linear_extrude(height=roof_thick){ + difference(){ + hull(){ + BodyPlan(); + translate([0,-roof_extent,0]) BodyPlan(); + } + Holes(); + } + } + } +} + +module Pin(){ + translate([pin_x_offset, pin_y_offset, 0]) rotate([0,90,0]){ + translate([0, 0, -pin_thick/2]) + linear_extrude(height=pin_thick){ + translate([-pin_base/2, 0]) square([pin_base, 50]); + translate([-pin_width/2, -100]) square([pin_width, 101]); + } + hull() for (d=[0,10]) { + translate([d*lock_hang_ratio,-d,0]) + translate([-lock_manouvre_thick/2, + -pin_workdepth-100, + -lock_manouvre_len_smaller]) + cube([lock_manouvre_thick, 100, + lock_manouvre_len + lock_manouvre_len_smaller]); + } + } +} + +module All(){ + difference(){ + Body(); + Pin(); + } +} + +module Piece(pc,interval){ + translate([0,-pc*interval,0]) + intersection(){ + rotate([0,0,pc*180-cut_rotation]) + translate([-200,clatter_gap/2,-200]) cube([400,400,400]); + All(); + } +} + +module PiecePrint(pc){ + rotate([0,0,90]) rotate([0,180,0]) + Piece(pc,4); +} + +module PiecesPrint(){ + PiecePrint(0); + PiecePrint(1); +} + +module Demo(){ + for (pc=[0,1]) + Piece(pc,0); +} + +//Holes(); +//Demo(); +//All(); +//Pin(); +//Pieces(); +PiecesPrint(); +//PiecePrint(0); +//PiecePrint(1); diff --git a/toplevel-find b/toplevel-find new file mode 100755 index 0000000..c9174c9 --- /dev/null +++ b/toplevel-find @@ -0,0 +1,28 @@ +#!/usr/bin/perl -w +use strict; +use IO::File; + +@ARGV==1 or die; +my $base = $ARGV[0]; +$base =~ m/^\-/ and die; + +sub read_file ($); +sub read_file ($) { + my ($fn) = @_; + my $f = new IO::File "$fn", '<' or die "$fn $!"; + while (<$f>) { + if (m#^//// toplevels-from:#) { + defined($_ = <$f>) or die $!; + m#^include\s+\<(\S+)>\s*$# or die; + read_file($1); + next; + } + next unless m#^\s*(?:////\s?)?module\s+(\w+)\b.*////toplevel\b#; + print "$base,$1\n" or die $!; + } + $f->error and die "$fn $!"; +} + +read_file("$base.scad"); +close STDOUT or die $!; + diff --git a/toplevel-make b/toplevel-make new file mode 100755 index 0000000..2df668b --- /dev/null +++ b/toplevel-make @@ -0,0 +1,10 @@ +#!/usr/bin/perl -w +use strict; +die unless @ARGV==1; +die unless $ARGV[0] =~ m/^(.+),(\w+)(?:\..*)?/; +my ($base,$obj) = ($1,$2); +print < +$obj(); +END +close STDOUT or die $!; diff --git a/tower-base.scad b/tower-base.scad new file mode 100644 index 0000000..0e097e9 --- /dev/null +++ b/tower-base.scad @@ -0,0 +1,152 @@ +/* -*- C -*- */ + +motorwidth=35.7; +motorheight=34.5; +totalheight=58; + +pillarthick=8; +sidethick=2.5; +archthick=6.5; +frameextra=3.5; +framesplayx=5; +framesplayy=5; +botleftgap=4.5; +botleftstand=0.75; +archoutwards=(pillarthick-archthick)/sqrt(8); + +topgluecubex=18; +topgluecubez=5; +clippairy=16; +clippairdz=-2.5; +topgluecubedy=1; + +dovebasecutcylz=4; +dovebasecutcylr=10; + +d=0.01; + +mw2=motorwidth/2; + +include + +module corner() { + $fn=30; + frameheight= motorheight + frameextra; + slopeheight= totalheight - frameheight; + slopex = (mw2 + archoutwards - framesplayx)/slopeheight; + slopey = (mw2 + archoutwards - framesplayy)/slopeheight; + echo(sqrt(slopex*slopex + slopey*slopey)); + + translate([-mw2,-mw2,0]) union(){ + difference(){ + union(){ + cylinder(r=pillarthick/2, h=frameheight); + translate([0,0,frameheight]) + sphere(r=pillarthick/2); + } + translate([d,d,-1]) + cube([mw2-1,mw2-1,frameheight+pillarthick+2]); + } + intersection(){ + multmatrix + ([ [ 1, 0, slopey, -archoutwards ], + [ 0, 1, slopex, -archoutwards ], + [ 0, 0, 1, frameheight ], + [ 0, 0, 0, 1 ]]) + translate([0,0,-frameextra]) + cylinder(r=archthick/2, + h=slopeheight+frameextra); + union() { + cylinder(r=pillarthick/2, h=frameheight); + translate([-100,-100,frameheight]) + cube([200,200,100]); + } + } + } +} + +module halfside() { + spacesz = (motorwidth - pillarthick/2*2) / 4; + panelheight = spacesz + sidethick; + panelbasez = motorheight+pillarthick/4-panelheight; + translate([0,-mw2,0]) { + translate([-mw2,-sidethick,0]) + cube([motorwidth,sidethick,sidethick]); + difference(){ + translate([-mw2,-sidethick, panelbasez]) + cube([mw2,sidethick,panelheight]); + translate([-mw2+pillarthick/3, -sidethick, panelbasez]) + rotate([0,45,0]) + translate([0,-1,0]) + cube([spacesz * sqrt(2), + sidethick+2, + spacesz * sqrt(2)]); + } + intersection(){ + for (xz=[[-mw2+pillarthick/3-sidethick, 0, + panelbasez+sidethick], + [0, 0, panelbasez + sidethick/sqrt(2)]]) { + translate(xz) + translate([0,-sidethick,0]) + rotate([0,55,0]) + translate([0,0,-sidethick]) + cube([100, sidethick, sidethick]); + } + translate([-mw2,-sidethick,0]) + cube([motorwidth,sidethick, + motorheight+pillarthick]); + } + } +} + +module towerbase() { + difference(){ + union(){ + for (mirx=[0,1]) for (miry=[0,1]) + mirror([mirx,0,0]) mirror([0,miry,0]) corner(); + for (angle=[0,90,180]) { + rotate([0,0,angle]) halfside(); + rotate([0,0,angle]) mirror([1,0,0]) halfside(); + } + } +// multmatrix([[ -1, 0, 0, -mw2 - botleftstand ], +// [ 0, 1, 0, -100 ], +// [ 1, 0, 1, -100 + botleftgap ], +// [ 0, 0, 0, 1 ] ]) +// cube([100,200,100]); + } + translate([clippairy/2,0,totalheight]) { + difference(){ + translate([-clippairy+topgluecubedy/2,-topgluecubex/2,0]) + cube([clippairy-topgluecubedy,topgluecubex,topgluecubez]); + } + translate([0,0,topgluecubez+clippairdz+DoveClip_depth()]) rotate([0,-90,0]) +// DoveClipPair(h=clippairy); + DoveClipPairSane(h=clippairy, count=3); + } +} + +if (towerbase_demo) { + intersection(){ + translate([0,0,-50]) towerbase(); + translate([-100,-100,0]) cube([200,200,32]); + } + + intersection(){ + translate([40,0,-60]) towerbase(); + translate([-100,-100,0]) cube([200,200,32]); + } + + translate([60,-90,0]) { + DoveClipPairSane(h=clippairy, count=3); + mirror([1,0,0]) translate([DoveClip_depth()-0.1,0,0]) cube([20,8,6]); + } + + for (x=[0,20,40]) { + translate([x,-50,0]) DoveClipPin(h=clippairy); + translate([x+10,-50,0]) DoveClipPin(h=clippairy/2); + translate([x+10,-30,0]) DoveClipPin(h=clippairy/2); + } +} else { + towerbase(); +} diff --git a/trackpump-mutlihead-clip.scad b/trackpump-mutlihead-clip.scad new file mode 100644 index 0000000..c5108fd --- /dev/null +++ b/trackpump-mutlihead-clip.scad @@ -0,0 +1,174 @@ +// -*- C -*- + +include + +pump_main_dia = 38; +pump_side_width = 5; +pump_side_thick = 4; +pump_shaft_dia = 14; +baseplate = 3; + +pump_protr_flat = 3; +pump_protr_slope = 0.9; + +hose_inner_dia = 20; +hose_aperture = 11; +hose_side_width = 5; +hose_base_offset = 30; + +hose_side_thick = 6; +hose_side_stalk_width = 6; + +pump_protr_protr = 3; +pump_side_height = 20; + +// calculated +pump_protr_slheight = pump_protr_protr / pump_protr_slope; + +pump_side_outer_rad = pump_side_width + pump_main_dia/2; + +baseplate_width_rad = + sqrt( pow(pump_side_outer_rad, 2) + -pow( pump_main_dia/2 - pump_protr_protr, 2) ); + +xm = baseplate + pump_main_dia/2; + +pump_side_total_height = + pump_side_thick + pump_side_height + pump_protr_slheight + pump_protr_flat; + +$fa=5; + +module PumpSidePlan() { + or = pump_side_outer_rad; + difference(){ + union(){ + intersection(){ + translate([-xm, 0]) circle(r=or); +// translate([-(xm+or), -or]) square([xm+or, or*2]); + } + } + translate([-xm-or, 0]) + square(center=true, [pump_side_width*4, pump_shaft_dia]); + } +} + +module PumpSideElevation(){ + x3 = 0; + x2 = x3 - baseplate; + x1 = x2 - pump_main_dia; + x0 = x1 - pump_side_width; + x2a = x2 - pump_protr_protr; + x4 = x2 + pump_side_width; + + z0 = 0; + z1 = z0 - pump_side_thick; + z2 = z1 - pump_side_height; + z2a = z2 - pump_protr_slheight; + z2b = z2a - pump_protr_flat; + + arcx = x2-x1; + arcy = z1-z2; + + translate([x0,z1]) square([x1-x0, z0-z1]); + + difference(){ + translate([x1,z2]) square([x3-x1, z0-z2]); + translate([x1,z2]) scale([1,arcy/arcx]) circle(r=arcx); + } + + translate([x2,z2a]) square([x4-x2, z0-z2a]); + + hull(){ + translate([x2,z2a]) square([x4-x2, z2-z2a]); + translate([x2a,z2b]) square([x3-x2a, z2a-z2b]); + } +} + +module PumpSide(){ + br = baseplate_width_rad; + brs = hose_side_stalk_width/2; + echo(brs); + + difference(){ + intersection(){ + translate([0,100,0]) + rotate([90,0,0]) + linear_extrude(height=200, convexity=10) + PumpSideElevation(); + union(){ + translate([0,0,-100]) + linear_extrude(height=200, convexity=10) + PumpSidePlan(); + // baseplate + hull(){ + mirror([0,0,1]) + translate([-xm, -brs, 0]) + cube([pump_main_dia/2 + pump_side_width, + brs*2, + 1]); + translate([-xm, -br, -pump_side_total_height]) + cube([xm, + br*2, + pump_protr_flat]); + } + } + } + translate([-(baseplate + pump_main_dia/2), 0, + -(pump_side_thick + pump_side_height)]) + cylinder(r=pump_main_dia/2, h=200); + } + rotate([0,0,180]) + mirror([0,0,1]) + translate([-0, + -br, + pump_side_total_height]) + Commitid_BestCount_M([baseplate + pump_protr_protr, + br*2]); +} + +module HoseSidePlan(){ + ro = hose_inner_dia/2 + hose_side_width; + ri = (hose_inner_dia/2); + st = hose_side_stalk_width/2; + + apx = sqrt( ri*ri - (hose_aperture*hose_aperture)/4 ); + apsq = hose_base_offset + apx - hose_aperture/2; + echo(apx,apsq); + + difference(){ + union(){ + translate([-1, -st]) square([hose_base_offset+1, st*2]); + translate([hose_base_offset, 0]) circle(r= ro); + } + translate([hose_base_offset, 0]) circle(r= hose_inner_dia/2); + translate([apsq, 0]) + rotate(-45) + square([50,50]); + } + + //%translate([hose_base_offset + apx, 0]) square([50,50]); + //%square(center=true, [100, hose_aperture]); +} + +module HoseSide(){ + mirror([0,0,1]) + linear_extrude(height=hose_side_thick, convexity=10) + HoseSidePlan(); +} + +module Clip(){ + PumpSide(); + HoseSide(); +} + +module ClipPrint(){ + rotate([180,0,0]) + Clip(); +} + +//PumpSidePlan(); +//PumpSideElevation(); +//PumpSide(); +//HoseSide(); +//Clip(); +ClipPrint(); diff --git a/trailerhubcap.scad b/trailerhubcap.scad new file mode 100644 index 0000000..4ae4c7d --- /dev/null +++ b/trailerhubcap.scad @@ -0,0 +1,80 @@ +// Copyright (C)2012 Ian Jackson +// Licenced under the GNU General Public Licence, version 3, or +// (at your option) any later version. There is NO WARRANTY. + +maindia = 29.7; +poleholeh = 5.0; +polecovth = 0.4; +poleholerad = 6; + +mainoverlap = 1.5; + +hookbasew = 5.0; +hookfullw = 7; +hookheight = 4.5; +hookwidth = 8; +hookbevelw = 0.75; +hookbevelh = 1.5; + +fingernaildepth = 5; +fingernailheight = 2.5; +fingernailwidth = 6; + +bigrad = maindia/2 + mainoverlap; +mainth = poleholeh + polecovth; +hooklessdepth = hookfullw - hookbasew; + +module base() { + rotate_extrude(convexity=10) + mirror([1,0,0]) + polygon(points=[[-bigrad, 0], + [-bigrad + mainth, -mainth], + [0, -mainth], + [0, -poleholeh], + [-poleholerad, -poleholeh], + [-poleholerad, 0]]); +} + +module fingernails() { + for (ang=[60,180,300]) + rotate([0,0,ang]) + translate([bigrad - fingernaildepth, + -fingernailwidth/2, + -fingernailheight]) + cube([fingernaildepth + 1, fingernailwidth, fingernailheight + 1]); +} + +module hookrim() { + rotate_extrude(convexity=10) + mirror([1,0,0]) + translate([-maindia/2, 0, 0]) + polygon(points=[[hooklessdepth, 0], + [hookfullw, 0], + [hookfullw*0.33, hookheight], + [hookbevelw, hookheight], + [0, hookheight-hookbevelh], + [0, hooklessdepth]]); +} + +module hooktriangles() { + for (ang=[0,120,240]) { + rotate([0,0,ang]) { + translate([0,0,-1]) { + linear_extrude(height=hookheight+2) { + polygon(points=[[0, 0], + [maindia/2 + 1, -hookwidth], + [maindia/2 + 1, +hookwidth]]); + } + } + } + } +} + +difference(){ + base(); + fingernails(); +} +intersection(){ + hookrim(); + hooktriangles(); +} diff --git a/treefoil.scad.pl b/treefoil.scad.pl new file mode 100755 index 0000000..ef9ef26 --- /dev/null +++ b/treefoil.scad.pl @@ -0,0 +1,79 @@ +#!/usr/bin/perl -w + +# Use: +# - support X/Y dist 0.5mm + +use strict; + +our $shape = <<'END'; +xyyZZYYXYxxyzYYZXzzxyXXYXXXZxxxyyXXZyyyzXXzz +zxxYYXXZXzzxyXXYZyyzxZZXZZZYzzzxxZZYxxxyZZyy +yzzXXZZYZyyzxZZXYxxyzYYZYYYXyyyzzYYXzzzxYYxx +END +# simple version (unknotted, [0,1,2]^3): +# YxxyzYYZXzzxyXXYZyyzxZZX +# +# New and less symmetric one that also fits in the 2x2x2 box: +# YXXyzzYxYXZZxzyxYzyyZXZx +# (email 8.9.2022) + +sub o { print @_ or die $!; } + +o <<'END'; +// -*- autogenerated, do not edit -*- + +module Trace() { +END + +my @p = qw(0 0 0); + +$"=','; + +while ($shape =~ s/^\s*(\w)//) { + my $ix = index('xyz', (lc $1)); + my $sign = $1 =~ /[A-Z]/ ? +1 : -1; + my @q = @p; + $q[$ix] += $sign; + o " TraceEdge([@p],[@q]);\n"; + @p = @q; +} + +die @p unless "@p" eq '0,0,0'; + +o "}\n\n"; + +while () { o $_ } + +__DATA__ + +thick = 6; +edgeu = 10; +//edgeu = 15; + +// calculated + +octa_long = thick; +octa_short = octa_long / (1 + sqrt(2)); + +module OctaThing() { + hull(){ + for (r = [[0,0,0], [90,0,0], [0,90,0]]) { + rotate(r) + cube([ octa_short,octa_short, octa_long ], center=true); + } + } +} + +module TraceEdge(p,q) { + hull(){ + for (x=[p,q]) { + translate(x * edgeu) + OctaThing(); + } + } +} + +rotate([0,0,45]) + Trace(); + + diff --git a/tube-crossdrill-jig.scad b/tube-crossdrill-jig.scad new file mode 100644 index 0000000..843a2a6 --- /dev/null +++ b/tube-crossdrill-jig.scad @@ -0,0 +1,138 @@ +// -*- C -*- + +//$fs=0.1; +//$fa=3; +$fs=0.2; +$fa=6; + +rearwallthick = 3; +basethick = 2; +mainframeendthick = 2.5; + +tubedia = 16 + 0.8; +tubetubethick=2; +tubetubetopslop=1; + +boltholedia = 6.5 + 0.5; +boltholeslotshorter = 6; +mainframeholedia = 5 + 1.0; + +// "slot" refers to the things in the base of the drill press stand +backslotedgespace = 59; +slotwidth = 11.5 - 0.5; +backslotmid2screwhole = 17; +slotplugheight = 5.5; +slotplugshorterlen =10; +slotpluglongerlen = 20; + +//slotslope = 11.0 / 18.5; +slotslope = 1 / tan(51); + +// "keepslot" refers to the screws in the wooden jig block +keepslotstartz = 20; +keepslotlen = 18; +keepslotx = backslotedgespace / 2; +keepslotwidth = 4; + +mainframeextraside = 12; +mainframeextrafront = 15; + +rearwallstrengthwidth = 10; +keepslotclear = 10; + +// computed values + +slotslopediag = sqrt(1 + slotslope*slotslope); +slotwidthx = slotwidth * slotslopediag; + +slotxperlen = slotslope / slotslopediag; +slotyperlen = 1 / slotslopediag; + +mainframeholex = backslotedgespace/2 + slotpluglongerlen * slotxperlen + + 0.5 * slotwidth * slotyperlen; + +mainframeholey = -slotpluglongerlen * slotyperlen + + 0.5 * slotwidth * slotxperlen; + +mainframemaxx = mainframeholex + mainframeextraside; +mainframeminy = mainframeholey - mainframeextrafront; +mainframemaxz = keepslotstartz + keepslotlen; + +module MainFrame(){ + for (m=[0,1]) { + mirror([m,0,0]) { + translate([-1, mainframeminy, 0]) + cube([mainframemaxx+1, -mainframeminy, basethick]); + translate([-1, -rearwallthick, 0]) + cube([mainframemaxx+1, rearwallthick, mainframemaxz]); + + for (x=[keepslotx - keepslotclear, mainframemaxx - 0.5]) { + translate([x,0,0]) + rotate([90,0,-90]) + linear_extrude(height=mainframeendthick) + polygon([[-mainframeminy, 0], + [0, mainframemaxz], + [0, 0]]); + } + + translate([backslotedgespace/2, 0, 1]) + mirror([0,0,1]) + linear_extrude(height=slotplugheight+1) + polygon([[0,0], + [slotwidthx, 0], + [slotwidthx + slotplugshorterlen * slotxperlen, + -slotplugshorterlen * slotyperlen], + [slotpluglongerlen * slotxperlen, + -slotpluglongerlen * slotyperlen]]); + translate([-1, + -rearwallthick - boltholeslotshorter + 0.2, + tubedia + tubetubetopslop + tubetubethick + 4]) + cube([keepslotx - keepslotclear + 1, + boltholeslotshorter + 0.5, + rearwallstrengthwidth]); + } + } +} + +module TubeThing(extralen, dia, extraheight, underheight){ + effheight = tubetubetopslop + extraheight + underheight; + len = -mainframeminy + extralen * 2; + translate([0, mainframeminy - extralen, -underheight]) { + translate([0,0, dia/2 + effheight]) + rotate([-90,0,0]) cylinder(h=len, r=dia/2); + translate([-dia/2, 0, 0]) + cube([dia, len, effheight + dia/2]); + } +} + +module Jig(){ + difference(){ + union(){ + MainFrame(); + TubeThing(0, tubedia+tubetubethick*2, -tubetubethick, 0); + } + union(){ + translate([0,0,-0.1]) + TubeThing(10, tubedia, 0, 5); + translate([-boltholedia/2, mainframeminy - 1, -5]) + cube([boltholedia, + -mainframeminy + 1 - rearwallthick - boltholeslotshorter, + mainframemaxz + 10]); + for (m=[0,1]) { + mirror([m,0,0]) { + translate([mainframeholex, mainframeholey, -30]) + cylinder(h=basethick+40, r=mainframeholedia/2); + translate([keepslotx - keepslotwidth/2, + -10, keepslotstartz]) + cube([keepslotwidth, 20, keepslotlen + 10]); + } + } + } + } +} + +//MainFrame(); +//TubeThing(0, tubedia); + +rotate([-90,0,0]) + Jig(); diff --git a/utils.scad b/utils.scad new file mode 100644 index 0000000..e440b5f --- /dev/null +++ b/utils.scad @@ -0,0 +1,51 @@ +// -*- C -*- + +// suitable for masking things within radius sqrt(2) only +module FArcSegment_mask(beta) { + for (i=[0 : 0.75 : 3]) { + rotate(i*beta/4) + polygon([[0, 0], + [1, 0], + [cos(beta/4), sin(beta/4)]]); + } +} + +module FArcSegment(xc,yc,inrad,outrad,alpha,delta) { + translate([xc,yc]) { + intersection() { + difference() { + circle(r=outrad, $fn=70); + circle(r=inrad, $fn=70); + } + rotate(alpha) scale(outrad*2) { + FArcSegment_mask(delta); + } + } + } +} + +module rectfromto(a,b) { + ab = b - a; + translate([min(a[0], b[0]), min(a[1], b[1])]) + square([abs(ab[0]), abs(ab[1])]); +} +module circleat(c,r) { translate(c) circle(r); } +module linextr(z0,z1, convexity=20) { + translate([0,0,z0]) + linear_extrude(height=z1-z0, convexity=convexity) + children(); +} + +module linextr_x_yz(x0,x1, convexity=20) { // XY turn into YZ + rotate([90,0,0]) + rotate([0,90,0]) + linextr(x0,x1, convexity=convexity) + children(); +} + +module linextr_y_xz(y0,y1, convexity=20) { // XY turn into YZ + rotate([0,0,180]) + rotate([90,0,0]) + linextr(y0,y1, convexity=convexity) + children(); +} diff --git a/velux-window-grip.scad b/velux-window-grip.scad new file mode 100644 index 0000000..d59a78f --- /dev/null +++ b/velux-window-grip.scad @@ -0,0 +1,138 @@ +// -*- C -*- + +include + +// MainLoop + +main_thick = 9.0; +main_in_dia = 28.9; + +horn_ext_dia = 20 - 0.5; + +horn_c_x = -4.6; +horn_c_dy= -4; + +blhook_start_ang = 45; +blhook_in_rad = 1.85; +blhook_str_len = 2.9; + +width = 20; + +// Attach + +at_bolt_into = 13.0 + 0.5; +at_tube_dia = 16.7 + 0.5; +at_prong_minw = 4; +at_rear_thick = 4.5; +at_bolt_dia = 5 + 0.5; + +at_rear_width = at_tube_dia; +at_stem_len = main_in_dia/2 * 0.3; + +at_prong_depth = at_bolt_into * 2; +at_gap_width = at_tube_dia * 0.75; + +// computed + +blhook_mid_rad = blhook_in_rad + main_thick/2; +mc_mid_rad = main_in_dia/2 + main_thick/2; + +mc_bl = circle_point([0,0], mc_mid_rad, 270-blhook_start_ang); + +at_block_x = at_tube_dia + at_prong_minw * 2; +at_block_y = at_prong_depth + at_rear_thick; +at_block_z = width; + +at_stem_yy = at_stem_len + mc_mid_rad; + +at_offset_y = at_block_y + at_stem_len + mc_mid_rad; + +$fs=0.05; + +horn_thick = main_thick; + +module MainLoop(){ + intersection(){ + difference(){ + circle(r= main_in_dia/2 + main_thick, $fn=50); + circle(r= main_in_dia/2, $fn=50); + } + polygon([[0,0], + 3*mc_bl, + [0, -100], + [100,-100], + [100,100], + [0,100]]); + } + translate(mc_bl) + circle(main_thick/2); + translate([horn_c_x, mc_mid_rad + horn_c_dy]) + intersection(){ + difference(){ + circle(horn_ext_dia/2); + intersection(){ + circle(horn_ext_dia/2 - horn_thick); + polygon([[-50,-50], + [-50,-horn_c_dy], + [50,-horn_c_dy], + [50,-50]]); + } + } + polygon([[0,0], + [-50,0], + [0,50]]); + } + translate([0,main_in_dia/2]) mirror([1,0]) + square([-horn_c_x + horn_ext_dia/2 * 0.75, main_thick]); + translate(mc_bl){ + translate([-blhook_str_len/2, 0]) + square(center=true, [blhook_str_len, main_thick]); + translate([-blhook_str_len, blhook_mid_rad]){ + intersection(){ + difference(){ + circle(r=blhook_mid_rad + main_thick/2); + circle(r=blhook_mid_rad - main_thick/2); + } + mirror([1,1]) square(50); + } + } + } +} + +module MainLoopTest(){ + linear_extrude(height=1.6) + MainLoop(); +} + +module Attach(){ + difference(){ + translate([0, at_block_y/2, 0]) + cube(center=true, [at_block_x, at_block_y, at_block_z]); + translate([0, at_prong_depth/2-1, 0]) + cube(center=true, [at_gap_width, at_prong_depth+2, at_block_z+1]); + translate([0,-1,0]) + rotate([-90,0,0]) + cylinder(r= at_tube_dia/2, h= at_prong_depth+1); + translate([-50, at_prong_depth-at_bolt_into, 0]) + rotate([0,90,0]) + cylinder(r= at_bolt_dia/2, h= 100); + } + difference(){ + translate([0, at_block_y + at_stem_yy/2 - 0.1, 0]) + cube(center=true, [at_tube_dia, at_stem_yy + 0.2, at_block_z]); + translate([0, at_offset_y, -50]) + cylinder(r = mc_mid_rad, 100); + } +} + +module Combine(){ + rotate([0,0,45]) translate([0,-main_thick/2,0]){ + linear_extrude(height=width) + translate([0,at_offset_y,0]) + MainLoop(); + translate([0,0, width/2]) + Attach(); + } +} + +Combine(); diff --git a/velux-window-grip.slic3r b/velux-window-grip.slic3r new file mode 100644 index 0000000..3a44d19 --- /dev/null +++ b/velux-window-grip.slic3r @@ -0,0 +1 @@ +solid_infill_every_layers = 11 diff --git a/wall-cable-hook.scad b/wall-cable-hook.scad new file mode 100644 index 0000000..3076265 --- /dev/null +++ b/wall-cable-hook.scad @@ -0,0 +1,40 @@ +// -*- C -*- + +circle_inner_rad = 10 + 0.5; + +thick = 3; + +tab_sz = 20; +width = 20; + +screw_hole_dia = 4.5 + 0.5; + +// calculated + +circle_outer_rad = circle_inner_rad + thick; + +module Plan() { + difference(){ + circle(r=circle_outer_rad, $fn=150); + circle(r=circle_inner_rad, $fn=150); + mirror([1,0]) square([50,50]); + } + translate([-circle_outer_rad, -0.1]) + multmatrix([[1,0,0,0], + [-1,1,0,0], + [0,0,1,0], + [0,0,0,1]]) + square([thick, tab_sz + circle_outer_rad + thick]); +} + +module Hook(){ + difference(){ + linear_extrude(height=width) Plan(); + if (false) + translate([-50, circle_outer_rad + tab_sz - width/2, width/2]) + rotate([0,90,0]) + cylinder(r= screw_hole_dia / 2, h=100, $fn=50); + } +} + +Hook(); diff --git a/wardrobe-hook.scad b/wardrobe-hook.scad new file mode 100644 index 0000000..959e967 --- /dev/null +++ b/wardrobe-hook.scad @@ -0,0 +1,192 @@ +// -*- C -*- + +include +include + +tubeslop = 0.5; +tubeheight = 30 + tubeslop; +tubewidth = 15 + tubeslop; +mainthick = 4; + +clipthick = 2; +clipang = 135; + +stemlen = 40; + +topwidth = 20; + +hookinrad = 7.5; +hookcurl = 60; +hookwidth = 4; + +tuberad = tubewidth/2; +bend = atan(tuberad/stemlen); +mainoutrad = tuberad + mainthick; +hookoutrad = hookinrad + hookwidth; +hookcy = -(stemlen - hookoutrad); + +eltop = [topwidth/2, -tuberad + tubeheight + mainthick + 0.1]; +elmid = [topwidth/2, -tuberad]; +ellow = tangent_intersect_b([0,hookcy], hookinrad, elmid); +ellowextra = 180 - tangent_intersect_beta([0,hookcy], hookinrad, elmid); + +module ClipPlan(qbend, qstemleny){ + dy = tubeheight - tuberad*2; + FArcSegment(0, dy, tuberad, mainoutrad, -1, 181); + FArcSegment(0, 0, tuberad, mainoutrad, -qbend, qbend+1); + translate([tuberad, 0]) square(center=false, size=[mainthick,dy]); + FArcSegment(0, 0, tuberad, tuberad + clipthick, 360-clipang, clipang+1); + rotate(-qbend) translate([tuberad, 0]) mirror([0,1]) + square(center=false, size=[mainthick, qstemleny/cos(qbend)]); +} + +module Plan(){ + ClipPlan(bend,stemlen); +} + +module ElevationCore(){ + FArcSegment(0, hookcy, hookinrad, hookoutrad, + 180 - ellowextra, + 90 + hookcurl + ellowextra); + translate([-hookoutrad*sqrt(0.5), + hookcy - hookoutrad*sqrt(0.5) + 0.1]) + mirror([1,0]) + square(center=false, size=[topwidth, stemlen + tubeheight + 20]); + polygon([[-hookoutrad, ellow[1]], + reflect_in_y(eltop), + eltop, + elmid, + ellow]); +} + +// after here is all 3D + +module Primary(){ + intersection(){ + translate([0,0, -(topwidth+10)/2]) + linear_extrude(height=topwidth+10) Plan(); + translate([50,0]) + rotate([0,-90,0]) + linear_extrude(height=100) + ElevationCore(); + } +} + +module PlaneAbove(){ + translate([-100,-100,0]) cube(center=false,size=[200,200,200]); +} + +taperangle = -270 + tangent_intersect_beta([-hookcy, 0], + hookoutrad, + [-eltop[1], -eltop[0]]); +module HookL(){ ////toplevel + difference(){ + rotate([taperangle,0,0]) + translate([0,-eltop[1],0]) + Primary(); + translate([0,0,topwidth/2]) + rotate([taperangle*2,0,0]) + PlaneAbove(); + translate([0,0,-topwidth/2]) + mirror([0,0,1]) PlaneAbove(0); + } +} + +// straight-on version, everything prefixed with s or S + +shookcy = -(stemlen-hookoutrad); +sstemleny = -shookcy; +sbend_raw = tangents_intersect_beta([0,0],tuberad, + [0,shookcy],hookinrad); +sbend = angle_map_range(360-sbend_raw, -180); + +module SPlan(){ + ClipPlan(sbend, sstemleny); + FArcSegment(0,shookcy, hookinrad,hookoutrad, + 270 - hookcurl, + hookcurl + 90 - sbend); +} + +module SElevation(){ + boty = shookcy - hookoutrad - 1; + polygon([[-1, tubeheight], + [topwidth, tubeheight], + [topwidth, elmid[1]], + [hookwidth, shookcy], + [hookwidth, boty], + [-1, boty]]); +} + +module SElevationPlaced(){ + rotate([0,-90,0]) translate([0,0,-100]) linear_extrude(height=200) + SElevation(); +} + +module SHookL(){ ///toplevel + intersection(){ + linear_extrude(height=topwidth) SPlan(); + SElevationPlaced(); + } +} + +// straight-on version, reversed, everything prefixed with t or T + +tjoinrad = mainoutrad * 0.7; +tstem0leny = tuberad - tjoinrad*0.5; +tjoinoutrad = tjoinrad + mainthick; + +thookcy = shookcy; + +tjoin0c = [tuberad - tjoinrad, -tstem0leny]; +tjoin1c = [0, thookcy]; + +tbend_raw = tangents_intersect_beta(tjoin0c, tjoinrad, + tjoin1c, -hookoutrad); +tbend0 = angle_map_range(tbend_raw, 0); +tbend1 = angle_map_range(tbend_raw + 180, -180); + +tbend0p = circle_point(tjoin0c, tjoinrad, tbend_raw); +tbend1p = circle_point(tjoin1c, -hookoutrad, tbend_raw); + +module TPlan(){ + ClipPlan(0, tstem0leny); + FArcSegment(tjoin0c[0],tjoin0c[1], tjoinrad,tjoinoutrad, + tbend0, 360-tbend0); + FArcSegment(0,shookcy, hookinrad,hookoutrad, + tbend1, 270+hookcurl - tbend1); + translate(tbend0p) { + rotate(tbend_raw+180) mirror([1,0]) { + translate([0,-0.1]) square(size=[mainthick, dist2d(tbend0p,tbend1p)+0.2]); + } + } +} + +module THookR(){ ///toplevel + intersection(){ + linear_extrude(height=topwidth) TPlan(); + SElevationPlaced(); + } +} + +// other toplevels etc. + +module HookR(){ ////toplevel + mirror([1,0,0]) HookL(); +} + +module SHookR(){ ////toplevel + mirror([1,0,0]) SHookL(); +} + +module THookL(){ ////toplevel + mirror([1,0,0]) THookR(); +} + +module Demo(){ ////toplevel + translate([-30,tubeheight,0]) HookL(); + translate([ 0,tubeheight,0]) HookR(); + translate([ 30, 0,0]) SHookL(); + translate([ 60, 0,0]) SHookR(); + translate([ 90, 0,0]) THookL(); + translate([120, 0,0]) THookR(); +} diff --git a/warptest.scad b/warptest.scad new file mode 100644 index 0000000..ee5b3b2 --- /dev/null +++ b/warptest.scad @@ -0,0 +1,2 @@ +//rotate([0,0,45]) +cube([3,100,25]); diff --git a/warptest2.scad b/warptest2.scad new file mode 100644 index 0000000..d6a11b8 --- /dev/null +++ b/warptest2.scad @@ -0,0 +1,8 @@ +// -*- C -*- +rotate([90,0,0]) +linear_extrude(height=50){ + polygon([[-3/2, 0], + [-11/2, 8], + [+11/2, 8], + [+3/2, 0]]); +} diff --git a/warptest3.scad b/warptest3.scad new file mode 100644 index 0000000..ee80051 --- /dev/null +++ b/warptest3.scad @@ -0,0 +1,30 @@ +// -*- C -*- + +dy= 145; +dx= 65; + +h1= 8; +h2= 14; +ratio = 0.8; + +module Plan(){ + polygon([[ -dx/2, 0 ], + [ 0, dy/2 ], + [ dx/2, 0 ], + [ 0, -dy/2 ]]); +} + +module Solid(){ + rotate([0,0, -45]) { + hull(){ + linear_extrude(height= h1) { + Plan(); + } + linear_extrude(height= h2) { + scale(ratio) Plan(); + } + } + } +} + +Solid(); diff --git a/wine-vacuum-adapter.scad b/wine-vacuum-adapter.scad new file mode 100644 index 0000000..5ce11a8 --- /dev/null +++ b/wine-vacuum-adapter.scad @@ -0,0 +1,74 @@ +// -*- C -*- + +india_nom = 27.0; +india_slop = 0.63; + +middia_nom = 31.0; +middia_slop = 0.10; + +outdia = 44.0; + +wall = 4; + +htop = 5; +hbot = 7; + +slope = 0.65; + +$fa=3; +$fs=0.1; + +// calculated + +india_use = india_nom + india_slop; +middia_use = middia_nom - middia_slop; + +//echo("MIN WALL", (middia_use - india_use)/2); + +ppA = [middia_use/2, 0]; +ppB = ppA + [0, 1] * htop; +ppC = ppB + [-1,0] * wall; +ppD = [ppC[0], ppA[1] - wall/slope]; +ppE = [india_use/2, ppD[1] - (india_use/2 - ppD[0])/slope]; +ppF = ppE + [0,-1] * (htop + hbot); +ppG = ppF + [1, 0] * wall; +ppK = [outdia/2, ppA[1]]; +ppJ = ppK + [0,-1] * wall; +ppH = [ppG[0], ppJ[1] - (ppJ[0]-ppG[0])/slope]; + +module Plan1() { + polygon([[ india_use/2, -hbot ], + [ outdia/2, -hbot ], + [ outdia/2, 0 ], + [ middia_use/2, 0 ], + [ middia_use/2, htop ], + [ india_use/2, htop ]]); +} + +module Plan3() { + p = [ ppA, + ppB, + ppC, + ppD, + ppE, + ppF, + ppG, + ppH, + ppJ, + ppK ]; + echo(p); + polygon(p); +} + +module Demo(){ + color("blue") translate([0,0,1]) Plan1(); + Plan3(); +} + +module Adapter(){ + rotate_extrude(convexity=5) + Plan1(); +} + +//Demo(); +Adapter(); diff --git a/write-firmware b/write-firmware new file mode 100755 index 0000000..ff75d4b --- /dev/null +++ b/write-firmware @@ -0,0 +1,24 @@ +#!/bin/bash +set -e + +usage () { echo 'usage: write-firmware FILE [PORT]'; } + +home=/home/reprap/play +ourfile="$home/Marlin.hex" + +infile="$1" + +case $# in +1) shift; port=/dev/ttyUSB0 ;; +2) shift; port="$1"; shift ;; +*) usage >&2; exit 1;; +esac + +ad () { + avrdude -b 38400 -v -P $port -p atmega644P -c arduino "$@" +} + +cp -v -- "$infile" "$ourfile" + +ad "$@" +ad "$@" -U flash:w:$ourfile diff --git a/xeno-drivebay-bracket.scad b/xeno-drivebay-bracket.scad new file mode 100644 index 0000000..2073e05 --- /dev/null +++ b/xeno-drivebay-bracket.scad @@ -0,0 +1,195 @@ +// -*- C -*- + +basel = 16; +basew = 24; +baset = 4.0; + +wallt = 2.5; + +wallh = 42; + +baseholesz = 3.7; +baseholeslot = 6.5; +baseholeslop = -0.5; + +holeslop = 0.5; + +webt = 2.5; + +pad = false; +padw = 12; + +padt = webt; +padl = padw; +padholesz = 3.0; + +wallholeh = 6+14+2; +wallholesz = 3.0; +wallholeslot = 4.5; + +walll = basel + webt + (pad ? padl : -0.1); + +webw = min(basew, pad ? padw : padt); + +module slothole(sz, slot, thick, csunk=true, slop=holeslop) { + hull(){ + for (y = [-slot/2,slot/2]) { + translate([0,y,-0.15]) + cylinder(r1=sz/2 + slop, + r2=sz/2 + (csunk ? thick : 0) + slop, + h=thick+0.30); + } + } +} + +module Bracket(){ + difference(){ + translate([0, -basew, 0]) + cube([basel, basew, baset]); + + translate([basel/2, -(basew+wallt)/2, 0]) + slothole(baseholesz, baseholeslot, baset, slop=baseholeslop); + } + + difference(){ + translate([0.1, 0.3, 0.1]) + rotate([90,0,0]) { + linear_extrude(height=wallt){ + polygon([[0,0], + [0, wallh/2 + wallholesz/2 + wallt + wallt], + [basel, wallh], + [walll, wallh], + [walll, wallh - padt - padt], + [basel + webt, 0]]); + } + } + + translate([basel/2, 0, wallholeh]) + rotate([90,90,0]) + slothole(wallholesz, wallholeslot, wallt, csunk=false); + } + + translate([basel-0.01, 0, 0]) { + rotate([90,0,90]) { + linear_extrude(height=webt+0.02) { + polygon([[-basew, 0], + [-basew, baset], + [-webw, wallh], + [0, wallh], + [0, 0]]); + } + } + } + + if (pad) { + translate([basel+webt, -padw, wallh-padt]) { + difference(){ + cube([padl, padw, padt]); + translate([padl/2, padw/2, -1]) + cylinder(r=padholesz/2 + holeslop, h=padt+2); + } + } + } +} + +module BracketR(){ ////toplevel + rotate([-90,0,0]) Bracket(); +} + +module BracketL(){ ////toplevel + mirror([1,0,0]) BracketR(); +} + +protinnerh = 47; +protinnerw = 53; +protd = 45; +protbaset = 4; +protwallt = 2; +protlidt = protwallt; +protwingd = 28; +protwingw = 23; + +module RearCableProtector(){ + for (x = [-protwallt, protinnerw]) { + translate([x, 0, 0]) { + cube([protwallt, protd, protinnerh+protlidt]); + } + } + translate([-(protwallt-0.1), 0, protinnerh]) + cube([protinnerw + (protwallt-0.1)*2, protd, protlidt]); + for (lr = [1,0]) { + translate([(lr ? -(protwingw + protwallt) : protinnerw), 0, 0]) { + difference(){ + translate([0, 0, 0]) + cube([protwingw, protwingd, protbaset]); + translate([protwingw/2, protwingd/2, 0]) + rotate([0,0, lr ? 45 : -45]) + slothole(baseholesz, baseholeslot, baset, slop=baseholeslop); + } + } + } +} + +module RearCableProtectorT(){ ////toplevel + rotate([90,0,0]) RearCableProtector(); +} + +chabd = 20; +chablidw = 40; +chabinnerh = 11; +chabwallt = 2; +chablidt = 2; +chabwebt = 2.5; +chabbaset = baset; +chabbasew = 20; +chabslot = 3; +chablidholed = 3; +chabwebh = 5; + +module ChannelBracket(){ + translate([0, -chabd, 0]) + cube([chabwallt, chabd, chabinnerh+chablidt]); + translate([-chablidw, -chabd, chabinnerh]) { + difference(){ + cube([chablidw + chabwallt - 0.1, chabd - 0.1, chablidt]); + translate([chablidw/2, chabd/2, -1]) + cylinder(r=chablidholed/2, h=chablidt+2, $fn=20); + } + } + translate([chabwallt-0.1, -chabd, 0]) { + difference(){ + cube([chabbasew, chabd-0.1, chabbaset]); + translate([chabbasew/2, (chabd-chabwebt)/2, 0]) + rotate([0,0,90]) + slothole(baseholesz, chabslot, baset, slop=baseholeslop); + } + } + rotate([90,0,0]) linear_extrude(height=chabwebt) { + polygon([[-chablidw, chabinnerh], + [-chablidw, chablidt+chabinnerh], + [-chabwebh, chablidt+chabinnerh+chabwebh], + [+chabwebh, chablidt+chabinnerh+chabwebh], + [+chabbasew, chabbaset], + [+chabbasew, 0], + [0, 0], + [0, chabinnerh]]); + } +} + +module ChannelBracketT(){ + rotate([-90,0,0]) ChannelBracket(); +} + +module Kit(){ ////toplevel + for (y=[0, -wallh-5]) { + translate([0,y,0]) { + translate([5,0,0]) BracketR(); + BracketL(); + } + } +} + +//Kit(); +//BracketR(); +//RearCableProtectorT(); +//ChannelBracketT(); diff --git a/y-large-axlebar-washer.scad b/y-large-axlebar-washer.scad new file mode 100644 index 0000000..de8553e --- /dev/null +++ b/y-large-axlebar-washer.scad @@ -0,0 +1,15 @@ +// -*- C -*- + +$fa=3; +$fs=0.1; + +r0 = 12 + 0.75; +r1 = 22; +h = 7.36 - 0.20; + +linear_extrude(height=h, convexity=3) { + difference(){ + circle(r = r1/2); + circle(r = r0/2); + } +} diff --git a/yubikey-5c-nano-loop.scad b/yubikey-5c-nano-loop.scad new file mode 100644 index 0000000..654e11c --- /dev/null +++ b/yubikey-5c-nano-loop.scad @@ -0,0 +1,74 @@ +// -*- C -*- + +include + +base = [ 8.4, 4.1 ]; +base_th = 0.7; +base_slope = 2.0; + +hoop_th = 2.1; +hoop_inner_dia = 3.0; + +time_square = 8; + +$fa = 3; +$fs = 0.1; + +// caclulated + +loop_post_z = hoop_inner_dia/2; +max_z = hoop_inner_dia + hoop_th; + +module Base() { + hull(){ + linextr(-base_th, -base_th + 0.01) + square(base, center=true); + linextr(-base_th, 0) { + square(base - 2 * base_th * base_slope * [1,1], center=true); + LoopPlan2(); + } + } +} + +module LoopPlan() { + translate([hoop_inner_dia/2 + hoop_th/2, 0]) + circle(r = hoop_th/2); +} + +module LoopPlan2() { + for (m=[0,1]) { + mirror([m,0,0]) LoopPlan(); + } +} + +module Loop() { + translate([0,0, loop_post_z]) { + intersection(){ + rotate([90, 0,0]){ + rotate_extrude(){ + LoopPlan(); + } + } + linextr(-0.1, hoop_inner_dia*2) + square(hoop_inner_dia*4, center=true); + } + } + linextr(0, loop_post_z) + LoopPlan2(); +} + +module UseUpTime() { + linextr(-base_th, max_z) + translate([0, base[0] * 3, 0]) + square(time_square, center=true); +} + +module Whole() { + rotate([0,0, 90]) { + Base(); + Loop(); + } + UseUpTime(); +} + +Whole();