From 2e77c0b4ce1781d87a532022d8ebaccff0fb2b17 Mon Sep 17 00:00:00 2001 From: tpearson Date: Tue, 5 Jul 2011 19:32:49 +0000 Subject: [PATCH] Added kstreamripper git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/kstreamripper@1239912 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- AUTHORS | 2 + COPYING | 340 ++++++++++++ ChangeLog | 1 + Doxyfile | 234 ++++++++ INSTALL | 84 +++ Makefile | 20 + NEWS | 1 + README | 1 + SConstruct | 234 ++++++++ TODO | 7 + admin/generic.py | 161 ++++++ admin/kde.py | 683 +++++++++++++++++++++++ doc/SConscript | 83 +++ doc/en/index.docbook | 101 ++++ kde.py | 816 ++++++++++++++++++++++++++++ kstreamripper.kdevelop | 206 +++++++ kstreamripper.kdevelop.pcs | Bin 0 -> 62876 bytes kstreamripper.kdevses | 38 ++ po/SConscript | 24 + po/messages.sh | 60 ++ scons-mini.tar.bz2 | Bin 0 -> 58214 bytes scons-mini.tar.bz2.cdbs-config_list | 0 src/SConscript | 69 +++ src/addnewstream.ui | 108 ++++ src/addnewstreamimpl.cpp | 66 +++ src/addnewstreamimpl.h | 48 ++ src/hi16-app-kstreamripper.png | Bin 0 -> 1033 bytes src/hi32-app-kstreamripper.png | Bin 0 -> 2749 bytes src/kstreamripper.cpp | 309 +++++++++++ src/kstreamripper.desktop | 16 + src/kstreamripper.h | 79 +++ src/kstreamripper.lsm | 16 + src/kstreamripperbase.ui | 337 ++++++++++++ src/kstreamripperui.rc | 8 + src/main.cpp | 66 +++ src/processcontroller.cpp | 148 +++++ src/processcontroller.h | 71 +++ src/processlistviewitem.cpp | 108 ++++ src/processlistviewitem.h | 71 +++ src/processlistviewitem_interface.h | 38 ++ templates/cpp | 19 + templates/h | 19 + unpack_local_scons.sh | 61 +++ 43 files changed, 4753 insertions(+) create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 Doxyfile create mode 100644 INSTALL create mode 100644 Makefile create mode 100644 NEWS create mode 100644 README create mode 100644 SConstruct create mode 100644 TODO create mode 100644 admin/generic.py create mode 100644 admin/kde.py create mode 100644 doc/SConscript create mode 100644 doc/en/index.docbook create mode 100644 kde.py create mode 100644 kstreamripper.kdevelop create mode 100644 kstreamripper.kdevelop.pcs create mode 100644 kstreamripper.kdevses create mode 100644 po/SConscript create mode 100755 po/messages.sh create mode 100644 scons-mini.tar.bz2 create mode 100644 scons-mini.tar.bz2.cdbs-config_list create mode 100644 src/SConscript create mode 100644 src/addnewstream.ui create mode 100644 src/addnewstreamimpl.cpp create mode 100644 src/addnewstreamimpl.h create mode 100644 src/hi16-app-kstreamripper.png create mode 100644 src/hi32-app-kstreamripper.png create mode 100644 src/kstreamripper.cpp create mode 100644 src/kstreamripper.desktop create mode 100644 src/kstreamripper.h create mode 100644 src/kstreamripper.lsm create mode 100644 src/kstreamripperbase.ui create mode 100644 src/kstreamripperui.rc create mode 100644 src/main.cpp create mode 100644 src/processcontroller.cpp create mode 100644 src/processcontroller.h create mode 100644 src/processlistviewitem.cpp create mode 100644 src/processlistviewitem.h create mode 100644 src/processlistviewitem_interface.h create mode 100644 templates/cpp create mode 100644 templates/h create mode 100755 unpack_local_scons.sh diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..d67550f --- /dev/null +++ b/AUTHORS @@ -0,0 +1,2 @@ +Michael Goettsche +William Entriken diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..5b6e7c6 --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) 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 +this service 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 make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. 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. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE 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. + + 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 +convey 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 2 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, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision 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, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This 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 Library General +Public License instead of this License. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/ChangeLog @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 0000000..23a9436 --- /dev/null +++ b/Doxyfile @@ -0,0 +1,234 @@ +# Doxyfile 1.3.3-Gideon + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = kstreamripper.kdevelop +PROJECT_NUMBER = 0.1 +OUTPUT_DIRECTORY = +OUTPUT_LANGUAGE = English +USE_WINDOWS_ENCODING = NO +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = NO +INHERIT_DOCS = YES +DISTRIBUTE_GROUP_DOC = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = YES +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = /home/tuxipuxi/Documents/cpp/kde/kstreamripper +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.C \ + *.H \ + *.tlh \ + *.diff \ + *.patch \ + *.moc \ + *.xpm \ + *.dox +RECURSIVE = yes +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = YES +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = yes +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::addtions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 1024 +MAX_DOT_GRAPH_HEIGHT = 1024 +MAX_DOT_GRAPH_DEPTH = 1000 +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::addtions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..8416e76 --- /dev/null +++ b/INSTALL @@ -0,0 +1,84 @@ +sctest REQUIREMENTS +------------------------ + +kde >= 3.2 is needed to run sctest + +To compile sctest, the kde development packages +are needed: kdelibs-devel, kdebase-devel and python + +scons is also needed http://www.scons.org +(this tool also used by Blender, ..) +Make sure scons is at least v0.96.1, otherwise +the compilation will fail. In case if you do not have +it, a minimum distribution is provided (see SCONS below) + +-> One should only have to run : +$ scons +# scons install +(do "scons install" as root - the menus may not +show up if you skip this step) + + +SCONS +----- + +-> If scons is missing, use the one bundled with PROGRAMNAME : +./unpack_local_scons.sh +python scons.py +python scons.py install +(run the last command as root) + + +-> For your convenience, a quick makefile is created : +./unpack_local_scons.sh +make +make install + + +USEFUL SCONS COMMANDS +--------------------- + +build the targets : scons +install them : scons install +clean the project : scons -c +uninstall : scons -c install +build in parallel : scons -j2 + +CONFIGURATION NOTES +------------------- + +The installation scripts are relying on the kde-config program. +The programs kde-config, qmake, uic and moc must be accesssible +through your PATH. + +Qt and kde may not be installed as expected (in QTDIR and KDEDIR) +So until kde-config is able to give that information, you may +have to give those paths. + +Here are some examples : +On Fedora/Redhat + scons configure kdeincludes=/usr/include/kde/ +On Debian + scons configure qtincludes=/usr/include/qt/ kdeinclude=/usr/include/kde/ +To install in some particular location with additional include paths + scons configure prefix=~/tmp extraincludes=/tmp/include:/usr/local/include + +For more options to tune the build look at the .py files available on +the top-level directory : +generic.py, kde.py, ... + +The build system is based on bksys, a build system that replaces +autoconf, automake and make in a row. Feel free to report your opinion +about it to the authors. + +BUILDING RPMS OR DEBS WITH CHECKINSTALL +--------------------------------------- + +With checkinstall 1.6, use +$ scons +# checkinstall --fstrans=no --nodoc scons install +# scons uninstall + +--------------------------------------- +enjoy KStreamRipper +Michael Goettsche diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8df7d48 --- /dev/null +++ b/Makefile @@ -0,0 +1,20 @@ +all: + @/usr/bin/scons -Q + +# it is also possible to use +# @/usr/bin/scons -Q -j4 + +install: + @/usr/bin/scons -Q install + +clean: + @/usr/bin/scons -Q -c + +uninstall: + @/usr/bin/scons -Q -c install + +dist: + @/usr/bin/scons -Q dist + +distclean: + @/usr/bin/scons -Q distclean diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/NEWS @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/README b/README new file mode 100644 index 0000000..638915f --- /dev/null +++ b/README @@ -0,0 +1 @@ +see INSTALL diff --git a/SConstruct b/SConstruct new file mode 100644 index 0000000..128317b --- /dev/null +++ b/SConstruct @@ -0,0 +1,234 @@ +#! /usr/bin/env python +## The kde detection is located in kde.py (have a look!) +## Delete the comments following as you see it fit + +""" +scons files are python scripts, comments begin by a "#" symbol +or are enclosed between sequences of triple quotes, so +this is a comment :) + +There is a lot of documentation and comments, but you can +remove them when you convert your program +""" + +""" +---------------------------------- +How to enjoy bksys full and plenty +(and forget about the autohell ? :) +----------------------------------- + +The program scons is usually launched as "scons" +When it is not intalled globally, one can run +"python scons.py" instead (ie : to use the local scons +that comes with bksys - try ./unpack_local_scons.sh) + +To compile the project, you will then only need to launch +scons on the top-level directory, the scripts find and +cache the proper environment automatically : +-> scons +(or python scons.py) + +To clean the project +-> scons -c +(or python scons.py -c) + +To install the project +-> scons install +(or python scons.py scons install) + +To uninstall the project +-> scons -c install + +To compile while being in a subdirectory +-> cd src; scons -u + +To (re)configure the project and give particular arguments, use ie : +-> scons configure debug=1 +-> scons configure prefix=/tmp/ita debug=full extraincludes=/usr/local/include:/tmp/include prefix=/usr/local +or -> python scons.py configure debug=1 +etc .. +The variables are saved automatically after the first run +(look at kde.cache.py, ..) + +Here is a quick list of options used (look at generic.py and kde.py) : +prefix +exec_prefix +datadir +libdir +kdeincludes +qtincludes +kdelibs +qtlibs +extraincludes (a list of paths separated by ':') + +""" + +########################################### +## Common section, for loading the tools + +## Load the builders in config +env = Environment(TARGS=COMMAND_LINE_TARGETS, ARGS=ARGUMENTS, tools=['default', 'generic', 'kde'], toolpath=['./', './admin']) +#env = Environment(TARGS=COMMAND_LINE_TARGETS, ARGS=ARGUMENTS, tools=['default', 'generic', 'kde', 'cg'], toolpath=['./']) +#env = Environment(TARGS=COMMAND_LINE_TARGETS, ARGS=ARGUMENTS, tools=['default', 'generic', 'kde', 'sound'], toolpath=['./']) +#env = Environment(TARGS=COMMAND_LINE_TARGETS, ARGS=ARGUMENTS, tools=['default', 'generic', 'kde', 'libxml'], toolpath=['./']) + +## the configuration should be done by now, quit +if 'configure' in COMMAND_LINE_TARGETS: + env.Exit(0) + +""" +Overview of the module system : + +Each module (kde.py, generic.py, sound.py..) tries to load a stored +configuration when run. If the stored configuration does not exist +or if 'configure' is given on the command line (scons configure), +the module launches the verifications and detectioins and stores +the results. Modules also call exit when the detection fail. + +For example, kde.py stores its config into kde.cache.py + +This has several advantages for both developers and users : + - Users do not have to run ./configure to compile + - The build is insensitive to environment changes + - The cache maintains the objects so the config can be changed often + - Each module adds its own help via env.Help("message") +""" + +## Use the variables available in the environment - unsafe, but moc, meinproc need it :-/ +import os +env.AppendUnique( ENV = os.environ ) + +## The target make dist requires the python module shutil which is in 2.3 +env.EnsurePythonVersion(2, 3) + +## Bksys requires scons 0.96 +env.EnsureSConsVersion(0, 96) + +""" +Explanation of the 'env = Environment...' line : +* the command line arguments and targets are stored in env['TARGS'] and env['ARGS'] for use by the tools +* the part 'tools=['default', 'generic ..' detect and load the necessary functions for doing the things +* the part "toolpath=['./']" tells that the tools can be found in the current directory (generic.py, kde.py ..) +""" + +""" +To load more configuration modules one should only have to add the appropriate tool +ie: to detect alsa and add the proper cflags, ldflags .. + a file alsa.py file will be needed, and one should then use : + env = Environment(TARGS=COMMAND_LINE_TARGETS, ARGS=ARGUMENTS, tools=['default', 'generic', 'kde', 'alsa'], toolpath=['./']) + +You can also load environments that are targetted to different platforms +ie: if os.sys.platform = "darwin": + env = Environment(... + elsif os.sys.platform = "linux": + env = Environment(... + +""" + +## Setup the cache directory - this avoids recompiling the same files over and over again +## this is very handy when working with cvs +env.CacheDir('cache') + +## Avoid spreading .sconsign files everywhere - keep this line +env.SConsignFile('scons_signatures') + +## If you need more libs and they rely on pkg-config +## ie: add support for GTK (source: the scons wiki on www.scons.org) +# env.ParseConfig('pkg-config --cflags --libs gtk+-2.0') + +""" +This tell scons that there are no rcs or sccs files - this trick +can speed up things a bit when having lots of #include +in the source code and for network file systems +""" +env.SourceCode(".", None) + +dirs = [ '.', 'src', 'po', 'doc'] + +for dir in dirs: + env.SourceCode(dir, None) + +## If we had only one program (named kvigor) to build, +## we could add before exporting the env (some kde +## helpers in kde.py need it) : +# env['APPNAME'] = 'kvigor' + +## Use this define if you are using the kde translation scheme (.po files) +env.Append( CPPFLAGS = ['-DQT_NO_TRANSLATION'] ) + +## Add this define if you want to use qthreads +#env.Append( CPPFLAGS = ['-DQT_THREAD_SUPPORT', '-D_REENTRANT'] ) + +## To use kdDebug(intvalue)<<"some trace"< + +from time import * +import SCons.Util +import string + +import os, re + +BOLD ="\033[1m" +RED ="\033[91m" +GREEN ="\033[92m" +YELLOW ="\033[1m" #"\033[93m" # unreadable on white backgrounds +CYAN ="\033[96m" +NORMAL ="\033[0m" + +# Returns the name of the shared object (i.e. libkdeui.so.4) +# referenced by a libtool archive (like libkdeui.la) +def getSOfromLA(lafile): + contents = open(lafile, 'r').read() + match = re.search("^dlname='([^']*)'$", contents, re.M) + if match: + return match.group(1) + return None + +def exists(env): + return True + +def detect_kde(env): + """ Detect the qt and kde environment using kde-config mostly """ + + prefix = env['ARGS'].get('prefix', None) + execprefix = env['ARGS'].get('execprefix', None) + datadir = env['ARGS'].get('datadir', None) + libdir = env['ARGS'].get('libdir', None) + kdeincludes= env['ARGS'].get('kdeincludes', None) + kdelibs = env['ARGS'].get('kdelibs', None) + qtincludes = env['ARGS'].get('qtincludes', None) + qtlibs = env['ARGS'].get('qtlibs', None) + + ## Detect the kde libraries + print "Checking for kde-config : ", + kde_config = os.popen("which kde-config 2>/dev/null").read().strip() + if len(kde_config): + print GREEN + "kde-config was found" + NORMAL + else: + print RED + "kde-config was NOT found in your PATH"+ NORMAL + print "Make sure kde is installed properly" + print "(missing package kdebase-devel?)" + env.Exit(1) + env['KDEDIR'] = os.popen('kde-config -prefix').read().strip() + + print "Checking for kde version : ", + kde_version = os.popen("kde-config --version|grep KDE").read().strip().split()[1] + if int(kde_version[0]) != 3 or int(kde_version[2]) < 2: + print RED + kde_version + print RED + "Your kde version can be too old" + NORMAL + print RED + "Please make sure kde is at least 3.2" + NORMAL + else: + print GREEN + kde_version + NORMAL + + ## Detect the qt library + print "Checking for the qt library : ", + qtdir = os.getenv("QTDIR") + if qtdir: + print GREEN + "qt is in " + qtdir + NORMAL + else: + libdir = os.popen('kde-config --expandvars --install lib').read().strip() + libkdeuiSO = libdir+'/'+getSOfromLA(libdir+'/libkdeui.la') + m = re.search('(.*)/lib/libqt.*', os.popen('ldd '+libkdeuiSO+' | grep libqt').read().strip().split()[2]) + if m: + qtdir = m.group(1) + print YELLOW+"qt was found as " + m.group(1) + NORMAL + else: + print RED+"qt was not found"+NORMAL + print RED+"Please set QTDIR first (/usr/lib/qt3?)"+NORMAL + env.Exit(1) + env['QTDIR'] = qtdir.strip() + + ## Find the necessary programs uic and moc + print "Checking for uic : ", + uic = qtdir + "/bin/uic" + if os.path.isfile(uic): + print GREEN+"uic was found as "+uic+NORMAL + else: + uic = os.popen("which uic 2>/dev/null").read().strip() + if len(uic): + print YELLOW+"uic was found as "+uic+NORMAL + else: + uic = os.popen("which uic 2>/dev/null").read().strip() + if len(uic): + print YELLOW+"uic was found as "+uic+NORMAL + else: + print RED+"uic was not found - set QTDIR put it in your PATH ?"+NORMAL + env.Exit(1) + env['QT_UIC'] = uic + + print "Checking for moc : ", + moc = qtdir + "/bin/moc" + if os.path.isfile(moc): + print GREEN+"moc was found as "+moc+NORMAL + else: + moc = os.popen("which moc 2>/dev/null").read().strip() + if len(moc): + print YELLOW+"moc was found as "+moc+NORMAL + elif os.path.isfile("/usr/share/qt3/bin/moc"): + moc = "/usr/share/qt3/bin/moc" + print YELLOW+"moc was found as "+moc+NORMAL + else: + print RED+"moc was not found - set QTDIR or put it in your PATH ?"+NORMAL + env.Exit(1) + env['QT_MOC'] = moc + + ## check for the qt and kde includes + print "Checking for the qt includes : ", + if qtincludes and os.path.isfile(qtincludes + "/qlayout.h"): + # The user told where to look for and it looks valid + print GREEN+"ok "+qtincludes+NORMAL + else: + if os.path.isfile(qtdir + "/include/qlayout.h"): + # Automatic detection + print GREEN+"ok "+qtdir + "/include/ "+NORMAL + qtincludes = qtdir + "/include/" + elif os.path.isfile("/usr/include/qt3/qlayout.h"): + # Debian probably + print YELLOW+"the qt headers were found in /usr/include/qt3/ "+NORMAL + qtincludes = "/usr/include/qt3" + else: + print RED+"the qt headers were not found"+NORMAL + env.Exit(1) + + print "Checking for the kde includes : ", + kdeprefix = os.popen("kde-config --prefix").read().strip() + if not kdeincludes: + kdeincludes = kdeprefix+"/include/" + if os.path.isfile(kdeincludes + "/klineedit.h"): + print GREEN+"ok "+kdeincludes+NORMAL + else: + if os.path.isfile(kdeprefix+"/include/kde/klineedit.h"): + # Debian, Fedora probably + print YELLOW+"the kde headers were found in "+kdeprefix+"/include/kde/"+NORMAL + kdeincludes = kdeprefix + "/include/kde/" + else: + print RED+"The kde includes were NOT found"+NORMAL + env.Exit(1) + + if prefix: + ## use the user-specified prefix + if not execprefix: + execprefix = prefix + if not datadir: + datadir = prefix+"/share" + if not libdir: + libdir = execprefix+"/lib" + + subst_vars = lambda x: x.replace('${exec_prefix}',execprefix).replace('${datadir}',datadir).replace('${libdir}',libdir) + env['KDEBIN'] = subst_vars(os.popen('kde-config --install exe').read().strip()) + env['KDEAPPS'] = subst_vars(os.popen('kde-config --install apps').read().strip()) + env['KDEDATA'] = subst_vars(os.popen('kde-config --install data').read().strip()) + env['KDEMODULE']= subst_vars(os.popen('kde-config --install module').read().strip()) + env['KDELOCALE']= subst_vars(os.popen('kde-config --install locale').read().strip()) + env['KDEDOC'] = subst_vars(os.popen('kde-config --install html').read().strip()) + env['KDEKCFG'] = subst_vars(os.popen('kde-config --install kcfg').read().strip()) + env['KDEXDG'] = subst_vars(os.popen('kde-config --install xdgdata-apps').read().strip()) + env['KDEMENU'] = subst_vars(os.popen('kde-config --install apps').read().strip()) + env['KDEMIME'] = subst_vars(os.popen('kde-config --install mime').read().strip()) + env['KDEICONS'] = subst_vars(os.popen('kde-config --install icon').read().strip()) + env['KDESERV'] = subst_vars(os.popen('kde-config --install services').read().strip()) + else: + # the user has given no prefix, install as a normal kde app + env['PREFIX'] = os.popen('kde-config --prefix').read().strip() + env['KDEBIN'] = os.popen('kde-config --expandvars --install exe').read().strip() + env['KDEAPPS'] = os.popen('kde-config --expandvars --install apps').read().strip() + env['KDEDATA'] = os.popen('kde-config --expandvars --install data').read().strip() + env['KDEMODULE']= os.popen('kde-config --expandvars --install module').read().strip() + env['KDELOCALE']= os.popen('kde-config --expandvars --install locale').read().strip() + env['KDEDOC'] = os.popen('kde-config --expandvars --install html').read().strip() + env['KDEKCFG'] = os.popen('kde-config --expandvars --install kcfg').read().strip() + env['KDEXDG'] = os.popen('kde-config --expandvars --install xdgdata-apps').read().strip() + env['KDEMENU'] = os.popen('kde-config --expandvars --install apps').read().strip() + env['KDEMIME'] = os.popen('kde-config --expandvars --install mime').read().strip() + env['KDEICONS'] = os.popen('kde-config --expandvars --install icon').read().strip() + env['KDESERV'] = os.popen('kde-config --expandvars --install services').read().strip() + + env['QTPLUGINS']=os.popen('kde-config --expandvars --install qtplugins').read().strip() + + ## kde libs and includes + env['KDEINCLUDEPATH']= kdeincludes + if not kdelibs: + kdelibs = os.popen('kde-config --expandvars --install lib').read().strip() + env['KDELIBPATH']= kdelibs + + ## qt libs and includes + env['QTINCLUDEPATH']= qtincludes + if not qtlibs: + qtlibs = qtdir+"/lib" + env['QTLIBPATH']= qtlibs + +def mocscan(target, source, env): + splitext = SCons.Util.splitext + + q_object_search = re.compile(r'[^A-Za-z0-9]Q_OBJECT[^A-Za-z0-9]') + + for obj in source: + + if not obj.has_builder(): + # binary obj file provided + continue + + cpp = obj.sources[0] + if not splitext(str(cpp))[1] == '.cpp': + # not a cplusplus source + continue + + # if we have a .ui file, it is automatically handled by Uic + uiname = string.split(cpp.abspath, '.cpp')[0] + ".ui" + if os.path.isfile(uiname): + continue + + hname = splitext(cpp.name)[0] + ".h" + h = SCons.Node.FS.find_file(hname, (cpp.get_dir(),) ) + + if h: + # h file with the Q_OBJECT macro found -> add .moc file + mocfile = string.split(cpp.abspath, '.cpp')[0] + ".moc" + # trick : check if the moc file already exists (avoid a scan) + if os.path.isfile(mocfile): + env.Moc(h) + elif q_object_search.search(h.get_contents()): + # FIXME : strong assumption + env.Moc(h) + + return (target, source) + +def generate(env): + + import SCons.Defaults + import SCons.Tool + env.Help(""" +"""+BOLD+ +"""*** KDE options *** +-------------------"""+NORMAL+""" +"""+BOLD+"""* prefix """+NORMAL+""": base install path, ie: /usr/local +"""+BOLD+"""* execprefix """+NORMAL+""": install path for binaries, ie: /usr/bin +"""+BOLD+"""* datadir """+NORMAL+""": install path for the data, ie: /usr/local/share +"""+BOLD+"""* libdir """+NORMAL+""": install path for the libs, ie: /usr/lib +"""+BOLD+"""* kdeincludes"""+NORMAL+""": path to the kde includes (/usr/include/kde on debian, ...) +"""+BOLD+"""* qtincludes """+NORMAL+""": same punishment, for qt includes (/usr/include/qt on debian, ...) +"""+BOLD+"""* kdelibs """+NORMAL+""": path to the kde libs, for linking the programs +"""+BOLD+"""* qtlibs """+NORMAL+""": same punishment, for qt libraries +ie: """+BOLD+"""scons configure libdir=/usr/local/lib qtincludes=/usr/include/qt +"""+NORMAL) + + CLVar = SCons.Util.CLVar + splitext = SCons.Util.splitext + Builder = SCons.Builder.Builder + + # Detect the environment - replaces ./configure implicitely + # and store the options into a cache + from SCons.Options import Options + cachefile=env['CACHEDIR']+'/kde.cache.py' + opts = Options(cachefile) + opts.AddOptions( + ( 'QTDIR', 'root of qt directory' ), + ( 'QTLIBPATH', 'path to the qt libraries' ), + ( 'QTINCLUDEPATH', 'path to the qt includes' ), + ( 'QT_UIC', 'moc directory'), + ( 'QT_MOC', 'moc executable command'), + ( 'QTPLUGINS', 'uic executable command'), + ( 'KDEDIR', 'root of kde directory' ), + ( 'KDELIBPATH', 'path to the kde libs' ), + ( 'KDEINCLUDEPATH', 'path to the kde includes' ), + + ( 'PREFIX', 'root of the program installation'), + + ( 'KDEBIN', 'installation path of the kde binaries'), + ( 'KDEMODULE', 'installation path of the parts and libs'), + ( 'KDEAPPS', ''), + ( 'KDEDATA', 'installation path of the application data'), + ( 'KDELOCALE', ''), + ( 'KDEDOC', 'installation path of the application documentation'), + ( 'KDEKCFG', 'installation path of the .kcfg files'), + ( 'KDEXDG', 'installation path of the service types'), + ( 'KDEMENU', ''), + ( 'KDEMIME', 'installation path of to the mimetypes'), + ( 'KDEICONS', ''), + ( 'KDESERV', ''), + ) + opts.Update(env) + + # reconfigure when things are missing + if 'configure' in env['TARGS'] or not env.has_key('QTDIR') or not env.has_key('KDEDIR'): + detect_kde(env) + + # finally save the configuration + opts.Save(cachefile, env) + + ## set default variables, one can override them in sconscript files + env.Append(CXXFLAGS = ['-I'+env['KDEINCLUDEPATH'], '-I'+env['QTINCLUDEPATH'] ]) + env.Append(LIBPATH = [env['KDELIBPATH'], env['QTLIBPATH'] ]) + + env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1 + + env['QT_AUTOSCAN'] = 1 + env['QT_DEBUG'] = 0 + + env['QT_UIC_HFLAGS'] = '-L $QTPLUGINS -nounload' + env['QT_UIC_CFLAGS'] = '$QT_UIC_HFLAGS -tr tr2i18n' + env['QT_LIBS'] = 'qt-mt' + + env['LIBTOOL_FLAGS'] = '--silent --mode=compile --tag=CXX' + + env['QT_UICIMPLPREFIX'] = '' + env['QT_UICIMPLSUFFIX'] = '.cpp' + env['QT_MOCHPREFIX'] = '' + env['QT_MOCHSUFFIX'] = '.moc' + env['KDE_KCFG_IMPLPREFIX'] = '' + env['KDE_KCFG_IMPL_HSUFFIX'] = '.h' + env['KDE_KCFG_IMPL_CSUFFIX'] = '.cpp' + env['KDE_SKEL_IMPL_SUFFIX'] = '.skel' + env['MEINPROC'] = 'meinproc' + env['MSGFMT'] = 'msgfmt' + + + ###### ui file processing + def uicGenerator(target, source, env, for_signature): + act=[] + act.append('$QT_UIC $QT_UIC_HFLAGS -o '+target[0].path+' '+source[0].path) + act.append('rm -f ' +target[1].path) + act.append('echo \'#include \' >> '+target[1].path) + act.append('echo \'#include \' >> '+target[1].path) + act.append('$QT_UIC $QT_UIC_CFLAGS -impl '+target[0].path+' -o '+target[1].path+'.tmp '+source[0].path) + act.append('cat '+target[1].path+'.tmp >> '+target[1].path) + act.append('rm -f '+target[1].path+'.tmp') + act.append('echo \'#include "' + target[2].name + '"\' >> '+target[1].path) + act.append('$QT_MOC -o '+target[2].path+' '+target[0].path) + return act + + def uicEmitter(target, source, env): + adjustixes = SCons.Util.adjustixes + bs = SCons.Util.splitext(str(source[0].name))[0] + bs = os.path.join(str(target[0].get_dir()),bs) + # first target is automatically added by builder (.h file) + if len(target) < 2: + # second target is .cpp file + target.append(adjustixes(bs, + env.subst('$QT_UICIMPLPREFIX'), + env.subst('$QT_UICIMPLSUFFIX'))) + if len(target) < 3: + # third target is .moc file + target.append(adjustixes(bs, + env.subst('$QT_MOCHPREFIX'), + env.subst('$QT_MOCHSUFFIX'))) + return target, source + + UIC_BUILDER = Builder( + generator = uicGenerator, + emitter = uicEmitter, + suffix = '.h', + src_suffix = '.ui' ) + + ###### moc file processing + env['QT_MOCCOM'] = ('$QT_MOC -o ${TARGETS[0]} $SOURCE') + + MOC_BUILDER = Builder( + action = '$QT_MOCCOM', + suffix = '.moc', + src_suffix = '.h' ) + + MOCCPP_BUILDER = Builder( + action = '$QT_MOCCOM', + suffix = '_moc.cpp', + src_suffix = '.h' ) + + ###### kcfg file processing + def kcfgGenerator(target, source, env, for_signature): + act=[] + act.append('kconfig_compiler -d'+str(source[0].get_dir())+' '+source[1].path+' '+source[0].path) + return act + + def kcfgEmitter(target, source, env): + adjustixes = SCons.Util.adjustixes + bs = SCons.Util.splitext(str(source[0].name))[0] + bs = os.path.join(str(target[0].get_dir()),bs) + # first target is automatically added by builder (.h file) + if len(target) < 2: + # second target is .cpp file + target.append(adjustixes(bs, env.subst('$KDE_KCFG_IMPLPREFIX'), env.subst('$KDE_KCFG_IMPL_CSUFFIX'))) + + if len(source) <2: + kcfgfilename = os.popen("cat "+str(source[0])+"|grep File|sed 's/File.*=//i'").read().rstrip() + source.append( str(source[0].get_dir())+'/'+kcfgfilename ) + return target, source + + KCFG_BUILDER = Builder( + generator = kcfgGenerator, + emitter = kcfgEmitter, + suffix = '.h', + src_suffix = '.kcfgc' ) + + ###### dcop processing + def dcopGenerator(target, source, env, for_signature): + act=[] + act.append('dcopidl '+source[0].path+' > '+target[1].path+'|| ( rm -f '+target[1].path+' ; false )') + act.append('dcopidl2cpp --c++-suffix cpp --no-signals --no-stub '+target[1].path) + return act + + def dcopEmitter(target, source, env): + bs = SCons.Util.splitext(str(source[0].name))[0] + bs = os.path.join(str(target[0].get_dir()),bs) + target.append(bs+'.kidl') + #target.append(bs+'_skel.cpp') + return target, source + + DCOP_BUILDER = Builder( + generator = dcopGenerator, + emitter = dcopEmitter, + suffix = '_skel.cpp', + src_suffix = '.h' ) + + ###### documentation (meinproc) processing + MEINPROC_BUILDER = Builder( + action = '$MEINPROC --check --cache $TARGET $SOURCE', + suffix = '.cache.bz2', + src_suffix = '.docbook' ) + + ###### translation files builder + TRANSFILES_BUILDER = Builder( + action = '$MSGFMT $SOURCE -o $TARGET', + suffix = '.gmo', + src_suffix = '.po' ) + + ###### libtool file builder + def laGenerator(target, source, env, for_signature): + act=[] + act.append('echo "dlname=\''+source[0].name+'\'" > '+target[0].path) + act.append('echo "library_names=\''+source[0].name+' '+source[0].name+' '+source[0].name+'\'" >> '+target[0].path) + act.append('echo "old_library=\'\'">> '+target[0].path) + act.append('echo "dependency_libs=\'\'">> '+target[0].path) + act.append('echo "current=0">> '+target[0].path) + act.append('echo "age=0">> '+target[0].path) + act.append('echo "revision=0">> '+target[0].path) + act.append('echo "installed=yes">> '+target[0].path) + act.append('echo "shouldnotlink=no">> '+target[0].path) + act.append('echo "dlopen=\'\'">> '+target[0].path) + act.append('echo "dlpreopen=\'\'">> '+target[0].path) + act.append('echo "libdir=\''+env['KDEMODULE']+'\'" >> '+target[0].path) + return act + + LA_BUILDER = Builder( + generator = laGenerator, + suffix = '.la', + src_suffix = '.so' ) + + ##### register the builders + env['BUILDERS']['Uic'] = UIC_BUILDER + env['BUILDERS']['Moc'] = MOC_BUILDER + env['BUILDERS']['Moccpp'] = MOCCPP_BUILDER + env['BUILDERS']['Dcop'] = DCOP_BUILDER + env['BUILDERS']['Kcfg'] = KCFG_BUILDER + env['BUILDERS']['LaFile'] = LA_BUILDER + env['BUILDERS']['Meinproc'] = MEINPROC_BUILDER + env['BUILDERS']['Transfiles'] = TRANSFILES_BUILDER + + static_obj, shared_obj = SCons.Tool.createObjBuilders(env) + static_obj.src_builder.append('Uic') + shared_obj.src_builder.append('Uic') + static_obj.src_builder.append('Kcfg') + shared_obj.src_builder.append('Kcfg') + static_obj.src_builder.append('LaFile') + shared_obj.src_builder.append('LaFile') + static_obj.src_builder.append('Meinproc') + shared_obj.src_builder.append('Meinproc') + static_obj.src_builder.append('Transfiles') + shared_obj.src_builder.append('Transfiles') + + ## find the files to moc, dcop, and link against kde and qt + env.AppendUnique(PROGEMITTER=[mocscan], SHLIBEMITTER=[mocscan], LIBEMITTER =[mocscan]) + + ########################################### + ## Handy helpers for building kde programs + ## You should not have to modify them .. + + #import SCons.Util + skel_ext = [".skel", ".SKEL"] + def KDEfiles(lenv, target, source): + """ Returns a list of files for scons (handles kde tricks like .skel) + It also makes custom checks against double includes like : ['file.ui', 'file.cpp'] + (file.cpp is already included because of file.ui) """ + + src=[] + ui_files=[] + kcfg_files=[] + skel_files=[] + other_files=[] + + # For each file, check wether it is a dcop file or not, and create the complete list of sources + for file in source: + bs = SCons.Util.splitext(file)[0] + ext = SCons.Util.splitext(file)[1] + if ext in skel_ext: + lenv.Dcop(bs+'.h') + src.append(bs+'_skel.cpp') + elif ext == ".moch": + lenv.Moccpp(bs+'.h') + src.append(bs+'_moc.cpp') + else: + src.append(file) + + if ext == '.ui': + ui_files.append(bs) + elif ext == '.kcfgc': + kcfg_files.append(bs) + elif ext == '.skel': + skel_files.append(bs) + else: + other_files.append(bs) + return src + + """ + In the future, these functions will contain the code that will dump the + configuration for re-use from an IDE + """ + import glob + def KDEinstall(lenv, restype, subdir, files): + if not 'install' in env['TARGS']: + return + basedir=env['DESTDIR'] + if len(restype)>0: + if not lenv.has_key(restype): + print RED+"unknown resource type "+restype+NORMAL + else: + basedir += lenv[restype]+'/' + #print file # <- useful to trace stuff :) + install_list = env.Install(basedir+subdir, files) + env.Alias('install', install_list) + return install_list + + def KDEinstallas(lenv, restype, destfile, file): + if not 'install' in env['TARGS']: + return + basedir=env['DESTDIR'] + if len(restype)>0: + if not lenv.has_key(restype): + print RED+"unknown resource type "+restype+NORMAL + else: + basedir += lenv[restype]+'/' + install_list = env.InstallAs(basedir+destfile, file) + env.Alias('install', install_list) + return install_list + + def KDEprogram(lenv, target, source): + """ Makes a kde program + The program is installed except if one sets env['NOAUTOINSTALL'] """ + src = KDEfiles(lenv, target, source) + program_list = lenv.Program(target, src) + if not lenv.has_key('NOAUTOINSTALL'): + KDEinstall(lenv, 'KDEBIN', '', target) + return program_list + + def KDEshlib(lenv, target, source, kdelib=0): + """ Makes a shared library for kde (.la file for klibloader) + The library is installed except if one sets env['NOAUTOINSTALL'] """ + src = KDEfiles(lenv, target, source) + library_list = lenv.SharedLibrary(target, src) + lafile_list = lenv.LaFile(target, library_list) + if not lenv.has_key('NOAUTOINSTALL'): + install_dir = 'KDEMODULE' + if kdelib==1: + install_dir = 'KDELIBPATH' + KDEinstall(lenv, install_dir, '', library_list) + KDEinstall(lenv, install_dir, '', lafile_list) + return library_list + + def KDEstaticlib(lenv, target, source): + """ Makes a static library for kde - in practice you should not use static libraries + 1. they take more memory than shared ones + 2. makefile.am needed it because of limitations + (cannot handle sources in separate folders - takes extra processing) """ + src = KDEfiles(lenv, target, source) + return lenv.StaticLibrary(target, src) + # do not install static libraries by default + + def KDEaddflags_cxx(lenv, fl): + """ Compilation flags for C++ programs """ + lenv.AppendUnique(CXXFLAGS = fl) + + def KDEaddflags_c(lenv, fl): + """ Compilation flags for C programs """ + lenv.AppendUnique(CFLAGS = fl) + + def KDEaddflags_link(lenv, fl): + """ Add link flags - Use this if KDEaddlibs below is not enough """ + lenv.AppendUnique(LINKFLAGS = fl) + + def KDEaddlibs(lenv, libs): + """ Helper function """ + lenv.AppendUnique(LIBS = libs) + + def KDEaddpaths_includes(lenv, paths): + """ Add new include paths """ + lenv.AppendUnique(CPPPATH = paths) + + def KDEaddpaths_libs(lenv, paths): + """ Add paths to libraries """ + lenv.AppendUnique(LIBPATH = paths) + + def KDElang(lenv, folder, appname): + """ Process translations (.po files) in a po/ dir """ + transfiles = glob.glob(folder+'/*.po') + for lang in transfiles: + result = lenv.Transfiles(lang) + country = SCons.Util.splitext(result[0].name)[0] + KDEinstallas(lenv, 'KDELOCALE', country+'/LC_MESSAGES/'+appname+'.mo', result) + + def KDEicon(lenv, icname): + """ Emulates the behaviour of Makefile.am to install icons + Contributed by: "Andrey Golovizin" """ + type_dic = { 'action' : 'actions', 'app' : 'apps', 'device' : + 'devices', 'filesys' : 'filesystems', 'mime' : 'mimetypes' } + dir_dic = { + 'los' :'locolor/16x16', + 'lom' :'locolor/32x32', + 'him' :'hicolor/32x32', + 'hil' :'hicolor/48x48', + 'lo16' :'locolor/16x16', + 'lo22' :'locolor/22x22', + 'lo32' :'locolor/32x32', + 'hi16' :'hicolor/16x16', + 'hi22' :'hicolor/22x22', + 'hi32' :'hicolor/32x32', + 'hi48' :'hicolor/48x48', + 'hi64' :'hicolor/64x64', + 'hi128':'hicolor/128x128', + 'hisc' :'hicolor/scalable', + 'cr16' :'crystalsvg/16x16', + 'cr22' :'crystalsvg/22x22', + 'cr32' :'crystalsvg/32x32', + 'cr48' :'crystalsvg/48x48', + 'cr64' :'crystalsvg/64x64', + 'cr128':'crystalsvg/128x128', + 'crsc' :'crystalsvg/scalable' + } + + import glob + iconfiles = [] + for ext in ['png', 'xpm', 'mng', 'svg', 'svgz']: + files = glob.glob('*-*-%s.%s' % (icname, ext)) + iconfiles += files + for iconfile in iconfiles: + tmp = iconfile.split('-') + if len(tmp) != 3: + print RED + 'WARNING: icon filename has unknown format: ' + iconfile + NORMAL + continue + [icon_dir, icon_type, icon_filename] = tmp + try: + destfile = '%s/%s/%s/%s' % (lenv['KDEICONS'], dir_dic[icon_dir], type_dic[icon_type], icon_filename) + except KeyError: + print RED + 'WARNING: unknown icon type: ' + iconfile + NORMAL + continue + ## do not use KDEinstallas here, as parsing from an ide will be necessary + if 'install' in env['TARGS']: + env.Alias('install', env.InstallAs( env['DESTDIR']+'/'+destfile, iconfile ) ) + + # Attach the functions to the environment so that sconscripts can use them + from SCons.Script.SConscript import SConsEnvironment + SConsEnvironment.KDEprogram = KDEprogram + SConsEnvironment.KDEshlib = KDEshlib + SConsEnvironment.KDEstaticlib = KDEstaticlib + SConsEnvironment.KDEinstall = KDEinstall + SConsEnvironment.KDEinstallas = KDEinstallas + SConsEnvironment.KDElang = KDElang + SConsEnvironment.KDEicon = KDEicon + + SConsEnvironment.KDEaddflags_cxx = KDEaddflags_cxx + SConsEnvironment.KDEaddflags_c = KDEaddflags_c + SConsEnvironment.KDEaddflags_link = KDEaddflags_link + SConsEnvironment.KDEaddlibs = KDEaddlibs + SConsEnvironment.KDEaddpaths_includes = KDEaddpaths_includes + SConsEnvironment.KDEaddpaths_libs = KDEaddpaths_libs diff --git a/doc/SConscript b/doc/SConscript new file mode 100644 index 0000000..c16dbb0 --- /dev/null +++ b/doc/SConscript @@ -0,0 +1,83 @@ +#! /usr/bin/env python +## This script demonstrates to build and install +## the documentation of a kde program with scons +## +## Thomas Nagy, 2005 + +## This file can be reused freely for any project (see COPYING) + +## First load the environment set in the top-level SConstruct file +Import( 'env' ) +myenv=env.Copy() + +## The following looks complicated but it is not +## We first define a function to install all files as documentation +## The documentation is of course lying in subfolders from here +## * normal files are installed under KDEDOC/destination +## * meinproc files are not installed, but processed into a single +## index.cache.bz2 which is installed afterwards + +## This is far more maintainable to have *one* file than +## having lots of almost empty SConscript in several folders + +import os +import sys +import glob +import SCons.Util + +## Define this to 1 if you are writing documentation else to 0 :) +i_am_a_documentation_writer = 0 + +## This function uses env imported above +def processfolder(folder, lang, destination=""): + # folder is the folder to process + # lang is the language + # destination is the subdirectory in KDEDOC + + docfiles = glob.glob(folder+"/???*.*") # file files that are at least 4 chars wide :) + + # warn about errors + #if len(lang) != 2: + # print "error, lang must be a two-letter string, like 'en'" + + # when the destination is not given, use the folder + if len(destination) == 0: + destination=folder + + docbook_list = [] + for file in docfiles: + + # do not process folders + if not os.path.isfile(file): + continue + # do not process the cache file + if file == 'index.cache.bz2': + continue + # ignore invalid files (TODO??) + if len( SCons.Util.splitext( file ) ) <= 1 : + continue + + ext = SCons.Util.splitext( file )[1] + + # docbook files are processed by meinproc + if ext == '.docbook': + docbook_list.append( file ) + continue + + myenv.KDEinstall('KDEDOC', lang+'/'+destination, file) + + # Now process the index.docbook files .. + if len(docbook_list) == 0: + return + if not os.path.isfile( folder+'index.docbook' ): + print "Error, index.docbook was not found in "+folder+'/index.docbook' + return + if i_am_a_documentation_writer: + for file in docbook_list: + myenv.Depends( folder+'index.cache.bz2', file ) + myenv.Meinproc( folder+'/index.cache.bz2', folder+'/index.docbook' ) + myenv.KDEinstall( 'KDEDOC', lang+'/'+destination, folder+'/index.cache.bz2' ) + +## Use processfolder for each documentation directory +processfolder('en/', 'en') + diff --git a/doc/en/index.docbook b/doc/en/index.docbook new file mode 100644 index 0000000..4826ffa --- /dev/null +++ b/doc/en/index.docbook @@ -0,0 +1,101 @@ + + + + +]> + + + + + + The KStreamRipper Handbook + + + + Michael Goettsche +
mail@tuxipuxi.de
+
+
+ date + 0.1 + + SHORT DESCRIPTION GOES HERE + + + KDE + KStreamRipper + +
+ + + Introduction + + + Features + + + + + + Installation + + + How to obtain KStreamRipper + + + + + Requirements + + + + + Compilation and Installation + + Compiling KStreamRipper is very easy. The following should do + it: +% ./configure +% make +% make install + + + That should do it! Should you run into any problems, + please report them to the author + + + + + Using KStreamRipper + + + + + Questions, Answers, and Tips + + + Frequently asked questions + + + Question 1 + + + The answer + + + + + +
+ diff --git a/kde.py b/kde.py new file mode 100644 index 0000000..b08dac1 --- /dev/null +++ b/kde.py @@ -0,0 +1,816 @@ +# Made from scons qt.py and (heavily) modified into kde.py +# Thomas Nagy, 2004, 2005 + +""" +Run scons -h to display the associated help, or look below .. +""" + +BOLD ="\033[1m" +RED ="\033[91m" +GREEN ="\033[92m" +YELLOW ="\033[1m" #"\033[93m" # unreadable on white backgrounds +CYAN ="\033[96m" +NORMAL ="\033[0m" + +import os, re + +# Returns the name of the shared object (i.e. libkdeui.so.4) +# referenced by a libtool archive (like libkdeui.la) +def getSOfromLA(lafile): + contents = open(lafile, 'r').read() + match = re.search("^dlname='([^']*)'$", contents, re.M) + if match: + return match.group(1) + return None + +def exists(env): + return True + +def detect_kde(env): + """ Detect the qt and kde environment using kde-config mostly """ + + prefix = env['ARGS'].get('prefix', None) + execprefix = env['ARGS'].get('execprefix', None) + datadir = env['ARGS'].get('datadir', None) + libdir = env['ARGS'].get('libdir', None) + libsuffix = env['ARGS'].get('libsuffix', '') + kdeincludes = env['ARGS'].get('kdeincludes', None) + kdelibs = env['ARGS'].get('kdelibs', None) + qtincludes = env['ARGS'].get('qtincludes', None) + qtlibs = env['ARGS'].get('qtlibs', None) + + if libdir: + libdir = libdir+libsuffix + + ## Detect the kde libraries + print "Checking for kde-config : ", + kde_config = os.popen("which kde-config 2>/dev/null").read().strip() + if len(kde_config): + print GREEN+"kde-config was found"+NORMAL + else: + print RED+"kde-config was NOT found in your PATH"+NORMAL + print "Make sure kde is installed properly" + print "(missing package kdebase-devel?)" + env.Exit(1) + env['KDEDIR'] = os.popen('kde-config -prefix').read().strip() + + print "Checking for kde version : ", + kde_version = os.popen("kde-config --version|grep KDE").read().strip().split()[1] + try: + env['KDEm1']=int(kde_version[0]) + except: + pass + try: + env['KDEm2']=int(kde_version[2]) + except: + pass + try: + env['KDEm3']=int(kde_version[4]) + except: + pass + if int(kde_version[0]) != 3 or int(kde_version[2]) < 2: + print RED+kde_version + print RED+"Your kde version can be too old"+NORMAL + print RED+"Please make sure kde is at least 3.2"+NORMAL + else: + print GREEN+kde_version+NORMAL + + ## Detect the qt library + print "Checking for the qt library : ", + qtdir = os.getenv("QTDIR") + if qtdir: + print GREEN+"qt is in "+qtdir+NORMAL + else: + libdir = os.popen('kde-config --expandvars --install lib').read().strip() + libkdeuiSO = libdir+'/'+getSOfromLA(libdir+'/libkdeui.la') + m = re.search('(.*)/lib/libqt.*', os.popen('ldd ' + libkdeuiSO + ' | grep libqt').read().strip().split()[2]) + if m: + qtdir = m.group(1) + print YELLOW+"qt was found as "+m.group(1)+NORMAL + else: + print RED+"qt was not found"+NORMAL + print RED+"Please set QTDIR first (/usr/lib/qt3?)"+NORMAL + env.Exit(1) + env['QTDIR'] = qtdir.strip() + + ## Find the necessary programs uic and moc + print "Checking for uic : ", + uic = qtdir + "/bin/uic" + if os.path.isfile(uic): + print GREEN+"uic was found as "+uic+NORMAL + else: + uic = os.popen("which uic 2>/dev/null").read().strip() + if len(uic): + print YELLOW+"uic was found as "+uic+NORMAL + else: + uic = os.popen("which uic 2>/dev/null").read().strip() + if len(uic): + print YELLOW+"uic was found as "+uic+NORMAL + else: + print RED+"uic was not found - set QTDIR put it in your PATH ?"+NORMAL + env.Exit(1) + env['QT_UIC'] = uic + + print "Checking for moc : ", + moc = qtdir + "/bin/moc" + if os.path.isfile(moc): + print GREEN + "moc was found as " + moc + NORMAL + else: + moc = os.popen("which moc 2>/dev/null").read().strip() + if len(moc): + print YELLOW + "moc was found as " + moc + NORMAL + elif os.path.isfile("/usr/share/qt3/bin/moc"): + moc = "/usr/share/qt3/bin/moc" + print YELLOW + "moc was found as " + moc + NORMAL + else: + print RED + "moc was not found - set QTDIR or put it in your PATH ?" + NORMAL + env.Exit(1) + env['QT_MOC'] = moc + + ## check for the qt and kde includes + print "Checking for the qt includes : ", + if qtincludes and os.path.isfile(qtincludes + "/qlayout.h"): + # The user told where to look for and it looks valid + print GREEN + "ok " + qtincludes + NORMAL + else: + if os.path.isfile(qtdir + "/include/qlayout.h"): + # Automatic detection + print GREEN + "ok " + qtdir + "/include/ " + NORMAL + qtincludes = qtdir + "/include/" + elif os.path.isfile("/usr/include/qt3/qlayout.h"): + # Debian probably + print YELLOW + "the qt headers were found in /usr/include/qt3/ " + NORMAL + qtincludes = "/usr/include/qt3" + else: + print RED + "the qt headers were not found" + NORMAL + env.Exit(1) + + print "Checking for the kde includes : ", + kdeprefix = os.popen("kde-config --prefix").read().strip() + if not kdeincludes: + kdeincludes = kdeprefix+"/include/" + if os.path.isfile(kdeincludes + "/klineedit.h"): + print GREEN + "ok " + kdeincludes + NORMAL + else: + if os.path.isfile(kdeprefix+"/include/kde/klineedit.h"): + # Debian, Fedora probably + print YELLOW + "the kde headers were found in " + kdeprefix + "/include/kde/" + NORMAL + kdeincludes = kdeprefix + "/include/kde/" + else: + print RED + "The kde includes were NOT found" + NORMAL + env.Exit(1) + + if prefix: + ## use the user-specified prefix + if not execprefix: + execprefix = prefix + if not datadir: + datadir=prefix+"/share" + if not libdir: + libdir=execprefix+"/lib"+libsuffix + + subst_vars = lambda x: x.replace('${exec_prefix}', execprefix).replace('${datadir}',datadir).replace('${libdir}', libdir) + debian_fix = lambda x: x.replace('/usr/share', '${datadir}') + env['KDEBIN'] = subst_vars(os.popen('kde-config --install exe').read().strip()) + env['KDEAPPS'] = subst_vars(os.popen('kde-config --install apps').read().strip()) + env['KDEDATA'] = subst_vars(os.popen('kde-config --install data').read().strip()) + env['KDEMODULE']= subst_vars(os.popen('kde-config --install module').read().strip()) + env['KDELOCALE']= subst_vars(os.popen('kde-config --install locale').read().strip()) + env['KDEDOC'] = subst_vars( debian_fix(os.popen('kde-config --install html').read().strip()) ) + env['KDEKCFG'] = subst_vars(os.popen('kde-config --install kcfg').read().strip()) + env['KDEXDG'] = subst_vars(os.popen('kde-config --install xdgdata-apps').read().strip()) + env['KDEXDGDIR']= subst_vars(os.popen('kde-config --install xdgdata-dirs').read().strip()) + env['KDEMENU'] = subst_vars(os.popen('kde-config --install apps').read().strip()) + env['KDEMIME'] = subst_vars(os.popen('kde-config --install mime').read().strip()) + env['KDEICONS'] = subst_vars(os.popen('kde-config --install icon').read().strip()) + env['KDESERV'] = subst_vars(os.popen('kde-config --install services').read().strip()) + else: + # the user has given no prefix, install as a normal kde app + env['PREFIX'] = os.popen('kde-config --prefix').read().strip() + env['KDEBIN'] = os.popen('kde-config --expandvars --install exe').read().strip() + env['KDEAPPS'] = os.popen('kde-config --expandvars --install apps').read().strip() + env['KDEDATA'] = os.popen('kde-config --expandvars --install data').read().strip() + env['KDEMODULE']= os.popen('kde-config --expandvars --install module').read().strip() + env['KDELOCALE']= os.popen('kde-config --expandvars --install locale').read().strip() + env['KDEDOC'] = os.popen('kde-config --expandvars --install html').read().strip() + env['KDEKCFG'] = os.popen('kde-config --expandvars --install kcfg').read().strip() + env['KDEXDG'] = os.popen('kde-config --expandvars --install xdgdata-apps').read().strip() + env['KDEXDGDIR']= os.popen('kde-config --expandvars --install xdgdata-dirs').read().strip() + env['KDEMENU'] = os.popen('kde-config --expandvars --install apps').read().strip() + env['KDEMIME'] = os.popen('kde-config --expandvars --install mime').read().strip() + env['KDEICONS'] = os.popen('kde-config --expandvars --install icon').read().strip() + env['KDESERV'] = os.popen('kde-config --expandvars --install services').read().strip() + + env['QTPLUGINS']=os.popen('kde-config --expandvars --install qtplugins').read().strip() + + ## kde libs and includes + env['KDEINCLUDEPATH']=kdeincludes + if not kdelibs: + kdelibs=os.popen('kde-config --expandvars --install lib').read().strip() + env['KDELIBPATH']=kdelibs + + ## qt libs and includes + env['QTINCLUDEPATH']=qtincludes + if not qtlibs: + qtlibs=qtdir+"/lib" + env['QTLIBPATH']=qtlibs + +def generate(env): + """"Set up the qt and kde environment and builders - the moc part is difficult to understand """ + env.Help(""" +"""+BOLD+ +"""*** KDE options *** +-------------------""" ++NORMAL+""" +"""+BOLD+"""* prefix """+NORMAL+""": base install path, ie: /usr/local +"""+BOLD+"""* execprefix """+NORMAL+""": install path for binaries, ie: /usr/bin +"""+BOLD+"""* datadir """+NORMAL+""": install path for the data, ie: /usr/local/share +"""+BOLD+"""* libdir """+NORMAL+""": install path for the libs, ie: /usr/lib +"""+BOLD+"""* libsuffix """+NORMAL+""": suffix of libraries on amd64, ie: 64, 32 +"""+BOLD+"""* kdeincludes"""+NORMAL+""": path to the kde includes (/usr/include/kde on debian, ...) +"""+BOLD+"""* qtincludes """+NORMAL+""": same punishment, for qt includes (/usr/include/qt on debian, ...) +"""+BOLD+"""* kdelibs """+NORMAL+""": path to the kde libs, for linking the programs +"""+BOLD+"""* qtlibs """+NORMAL+""": same punishment, for qt libraries +ie: """+BOLD+"""scons configure libdir=/usr/local/lib qtincludes=/usr/include/qt +"""+NORMAL) + + import SCons.Defaults + import SCons.Tool + import SCons.Util + + ui_extensions = [".ui"] + header_extensions = [".h", ".hxx", ".hpp", ".hh"] + source_extensions = [".cpp", ".cxx", ".cc"] + + def find_file(filename, paths, node_factory): + retval = None + for dir in paths: + node = node_factory(filename, dir) + if node.rexists(): + return node + return None + + class _Metasources: + """ Callable class, which works as an emitter for Programs, SharedLibraries + and StaticLibraries.""" + + def __init__(self, objBuilderName): + self.objBuilderName = objBuilderName + + def __call__(self, target, source, env): + """ Smart autoscan function. Gets the list of objects for the Program + or Lib. Adds objects and builders for the special qt files. """ + try: + if int(env.subst('$QT_AUTOSCAN')) == 0: + return target, source + except ValueError: + pass + + try: + qtdebug = int(env.subst('$QT_DEBUG')) + except ValueError: + qtdebug = 0 + + # some shortcuts used in the scanner + FS = SCons.Node.FS.default_fs + splitext = SCons.Util.splitext + objBuilder = getattr(env, self.objBuilderName) + + # some regular expressions: + # Q_OBJECT detection + q_object_search = re.compile(r'[^A-Za-z0-9]Q_OBJECT[^A-Za-z0-9]') + + # The following is kind of hacky to get builders working properly (FIXME) ?? + objBuilderEnv = objBuilder.env + objBuilder.env = env + mocBuilderEnv = env.Moc.env + env.Moc.env = env + + # make a deep copy for the result; MocH objects will be appended + out_sources = source[:] + + for obj in source: + if not obj.has_builder(): + # binary obj file provided + if qtdebug: + print "scons: qt: '%s' seems to be a binary. Discarded." % str(obj) + continue + cpp = obj.sources[0] + if not splitext(str(cpp))[1] in source_extensions: + if qtdebug: + print "scons: qt: '%s' is no cxx file. Discarded." % str(cpp) + # c or fortran source + continue + #cpp_contents = comment.sub('', cpp.get_contents()) + cpp_contents = cpp.get_contents() + + h = None + ui = None + + for ui_ext in ui_extensions: + # try to find the ui file in the corresponding source directory + uiname = splitext(cpp.name)[0] + ui_ext + ui = find_file(uiname, (cpp.get_dir(),), FS.File) + if ui: + if qtdebug: + print "scons: qt: found .ui file of header" #% (str(h), str(cpp)) + #h_contents = comment.sub('', h.get_contents()) + break + + # if we have a .ui file, do not continue, it is automatically handled by Uic + if ui: + continue + + for h_ext in header_extensions: + # try to find the header file in the corresponding source + # directory + hname = splitext(cpp.name)[0] + h_ext + h = find_file(hname, (cpp.get_dir(),), FS.File) + if h: + if qtdebug: + print "scons: qt: Scanning '%s' (header of '%s')" % (str(h), str(cpp)) + #h_contents = comment.sub('', h.get_contents()) + h_contents = h.get_contents() + break + + if not h and qtdebug: + print "scons: qt: no header for '%s'." % (str(cpp)) + if h and q_object_search.search(h_contents): + # h file with the Q_OBJECT macro found -> add .moc or _moc.cpp file + moc_cpp = None + + if env.has_key('NOMOCSCAN'): + moc_cpp = env.Moc(h) + else: + reg = '\n\s*#include\s*("|<)'+splitext(cpp.name)[0]+'.moc("|>)' + meta_object_search = re.compile(reg) + if meta_object_search.search(cpp_contents): + moc_cpp = env.Moc(h) + else: + moc_cpp = env.Moccpp(h) + moc_o = objBuilder(moc_cpp) + out_sources.append(moc_o) + if qtdebug: + print "scons: qt: found Q_OBJECT macro in '%s', moc'ing to '%s'" % (str(h), str(moc_cpp[0])) + + if cpp and q_object_search.search(cpp_contents): + print "error, bksys cannot handle cpp files with Q_OBJECT classes" + print "if you are sure this is a feature worth the effort, " + print "report this to the authors tnagyemail-mail yahoo.fr" + + # restore the original env attributes (FIXME) + objBuilder.env = objBuilderEnv + env.Moc.env = mocBuilderEnv + + return (target, out_sources) + + MetasourcesShared = _Metasources('SharedObject') + MetasourcesStatic = _Metasources('StaticObject') + + CLVar = SCons.Util.CLVar + splitext = SCons.Util.splitext + Builder = SCons.Builder.Builder + + # Detect the environment - replaces ./configure implicitely and store the options into a cache + from SCons.Options import Options + cachefile=env['CACHEDIR']+'kde.cache.py' + opts = Options(cachefile) + opts.AddOptions( + ('PREFIX', 'root of the program installation'), + + ('QTDIR', 'root of qt directory'), + ('QTLIBPATH', 'path to the qt libraries'), + ('QTINCLUDEPATH', 'path to the qt includes'), + ('QT_UIC', 'moc directory'), + ('QT_MOC', 'moc executable command'), + ('QTPLUGINS', 'uic executable command'), + ('KDEDIR', 'root of kde directory'), + ('KDELIBPATH', 'path to the kde libs'), + ('KDEINCLUDEPATH', 'path to the kde includes'), + + ('KDEBIN', 'installation path of the kde binaries'), + ('KDEMODULE', 'installation path of the parts and libs'), + ('KDEAPPS', ''), + ('KDEDATA', 'installation path of the application data'), + ('KDELOCALE', ''), + ('KDEDOC', 'installation path of the application documentation'), + ('KDEKCFG', 'installation path of the .kcfg files'), + ('KDEXDG', 'installation path of the service types'), + ('KDEXDGDIR', 'installation path of the xdg service directories'), + ('KDEMENU', ''), + ('KDEMIME', 'installation path of to the mimetypes'), + ('KDEICONS', ''), + ('KDEm1', ''), + ('KDEm2', ''), + ('KDEm3', ''), + ('KDESERV', ''), + ) + opts.Update(env) + + # reconfigure when things are missing + if 'configure' in env['TARGS'] or not env.has_key('QTDIR') or not env.has_key('KDEDIR'): + detect_kde(env) + + # finally save the configuration to the cache file + opts.Save(cachefile, env) + + ## set default variables, one can override them in sconscript files + env.Append(CXXFLAGS = ['-I'+env['KDEINCLUDEPATH'], '-I'+env['QTINCLUDEPATH'] ]) + env.Append(LIBPATH = [env['KDELIBPATH'], env['QTLIBPATH'] ]) + + env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1 + + env['QT_AUTOSCAN'] = 1 + env['QT_DEBUG'] = 0 + env['QT_UIC_HFLAGS'] = '-L $QTPLUGINS -nounload' + env['QT_UIC_CFLAGS'] = '$QT_UIC_HFLAGS -tr tr2i18n' + env['QT_LIBS'] = 'qt-mt' + env['QT_UICIMPLPREFIX'] = '' + env['QT_UICIMPLSUFFIX'] = '.cpp' + + env['QT_MOCHPREFIX'] = '' + env['QT_MOCHSUFFIX'] = '.moc' + env['KDE_KCFG_IMPLPREFIX'] = '' + env['KDE_KCFG_IMPL_HSUFFIX'] = '.h' + env['KDE_KCFG_IMPL_CSUFFIX'] = '.cpp' + env['KDE_SKEL_IMPL_SUFFIX'] = '.skel' + env['MEINPROC'] = 'meinproc' + env['MSGFMT'] = 'msgfmt' + + ## ui file processing + def uicGenerator(target, source, env, for_signature): + act=[] + act.append('$QT_UIC $QT_UIC_HFLAGS -o '+target[0].path+' '+source[0].path) + act.append('rm -f ' +target[1].path) + act.append('echo \'#include \' >> '+target[1].path) + act.append('echo \'#include \' >> '+target[1].path) + act.append('$QT_UIC $QT_UIC_CFLAGS -impl '+target[0].path+' -o '+target[1].path+'.tmp '+source[0].path) + act.append('cat '+target[1].path+'.tmp >> '+target[1].path) + act.append('rm -f '+target[1].path+'.tmp') + act.append('echo \'#include "' + target[2].name + '"\' >> '+target[1].path) + act.append('$QT_MOC -o '+target[2].path+' '+target[0].path) + return act + + def uicEmitter(target, source, env): + adjustixes = SCons.Util.adjustixes + bs = SCons.Util.splitext(str(source[0].name))[0] + bs = os.path.join(str(target[0].get_dir()),bs) + # first target is automatically added by builder (.h file) + if len(target) < 2: + # second target is .cpp file + target.append(adjustixes(bs, + env.subst('$QT_UICIMPLPREFIX'), + env.subst('$QT_UICIMPLSUFFIX'))) + if len(target) < 3: + # third target is .moc file + target.append(adjustixes(bs, + env.subst('$QT_MOCHPREFIX'), + env.subst('$QT_MOCHSUFFIX'))) + return target, source + + UIC_BUILDER = Builder( + generator = uicGenerator, + emitter = uicEmitter, + suffix = '.h', + src_suffix = '.ui') + + ## moc file processing + env['QT_MOCCOM'] = ('$QT_MOC -o ${TARGETS[0]} $SOURCE') + + MOC_BUILDER = Builder( + action = '$QT_MOCCOM', + suffix = '.moc', + src_suffix = '.h') + + MOCCPP_BUILDER = Builder( + action = '$QT_MOCCOM', + suffix = '_moc.cpp', + src_suffix = '.h') + + ## kcfg file processing + def kcfgGenerator(target, source, env, for_signature): + act=[] + act.append('kconfig_compiler -d'+str(source[0].get_dir())+' '+source[1].path+' '+source[0].path) + return act + + def kcfgEmitter(target, source, env): + adjustixes = SCons.Util.adjustixes + bs = SCons.Util.splitext(str(source[0].name))[0] + bs = os.path.join(str(target[0].get_dir()),bs) + # .h file is automatically added + if len(target) < 2: + # add .cpp file + target.append(adjustixes(bs, env.subst('$KDE_KCFG_IMPLPREFIX'), env.subst('$KDE_KCFG_IMPL_CSUFFIX'))) + + if len(source) <2: + if not os.path.isfile(str(source[0])): + print RED+'kcfg file given'+str(source[0])+' does not exist !'+NORMAL + return target, source + kfcgfilename="" + kcfgFileDeclRx = re.compile("^[fF]ile\s*=\s*(.+)\s*$") + for line in file(str(source[0]), "r").readlines(): + match = kcfgFileDeclRx.match(line.strip()) + if match: + kcfgfilename = match.group(1) + break + source.append(str(source[0].get_dir())+'/'+kcfgfilename) + return target, source + + KCFG_BUILDER = Builder( + generator = kcfgGenerator, + emitter = kcfgEmitter, + suffix = '.h', + src_suffix = '.kcfgc') + + ## dcop processing + def dcopGenerator(target, source, env, for_signature): + act=[] + act.append('dcopidl '+source[0].path+' > '+target[1].path+'|| ( rm -f '+target[1].path+' ; false)') + act.append('dcopidl2cpp --c++-suffix cpp --no-signals --no-stub '+target[1].path) + return act + + def dcopEmitter(target, source, env): + bs = SCons.Util.splitext(str(source[0].name))[0] + bs = os.path.join(str(target[0].get_dir()),bs) + target.append(bs+'.kidl') + #target.append(bs+'_skel.cpp') + return target, source + + DCOP_BUILDER = Builder( + generator = dcopGenerator, + emitter = dcopEmitter, + suffix = '_skel.cpp', + src_suffix = '.h') + + ## documentation processing + MEINPROC_BUILDER = Builder( + action = '$MEINPROC --check --cache $TARGET $SOURCE', + suffix = '.cache.bz2') + + ## translation files builder + TRANSFILES_BUILDER = Builder( + action = '$MSGFMT $SOURCE -o $TARGET', + suffix = '.gmo', + src_suffix = '.po') + + ## libtool file builder + def laGenerator(target, source, env, for_signature): + act=[] + act.append('echo "dlname=\''+source[0].name+'\'" > '+target[0].path) + act.append('echo "library_names=\''+source[0].name+' '+source[0].name+' '+source[0].name+'\'" >> '+target[0].path) + act.append('echo "old_library=\'\'">> '+target[0].path) + act.append('echo "dependency_libs=\'\'">> '+target[0].path) + act.append('echo "current=0">> '+target[0].path) + act.append('echo "age=0">> '+target[0].path) + act.append('echo "revision=0">> '+target[0].path) + act.append('echo "installed=yes">> '+target[0].path) + act.append('echo "shouldnotlink=no">> '+target[0].path) + act.append('echo "dlopen=\'\'">> '+target[0].path) + act.append('echo "dlpreopen=\'\'">> '+target[0].path) + act.append('echo "libdir=\''+env['KDEMODULE']+'\'" >> '+target[0].path) + env.Depends(target, source) + return act + LA_BUILDER = Builder( + generator = laGenerator, + suffix = '.la', + src_suffix = env['SHLIBSUFFIX']) + + ## register the builders + env['BUILDERS']['Uic'] = UIC_BUILDER + env['BUILDERS']['Moc'] = MOC_BUILDER + env['BUILDERS']['Moccpp'] = MOCCPP_BUILDER + env['BUILDERS']['Dcop'] = DCOP_BUILDER + env['BUILDERS']['Kcfg'] = KCFG_BUILDER + env['BUILDERS']['LaFile'] = LA_BUILDER + env['BUILDERS']['Meinproc'] = MEINPROC_BUILDER + env['BUILDERS']['Transfiles']= TRANSFILES_BUILDER + + static_obj, shared_obj = SCons.Tool.createObjBuilders(env) + static_obj.src_builder.append('Uic') + shared_obj.src_builder.append('Uic') + static_obj.src_builder.append('Kcfg') + shared_obj.src_builder.append('Kcfg') + static_obj.src_builder.append('LaFile') + shared_obj.src_builder.append('LaFile') + static_obj.src_builder.append('Meinproc') + shared_obj.src_builder.append('Meinproc') + static_obj.src_builder.append('Transfiles') + shared_obj.src_builder.append('Transfiles') + + ## Find the files to moc, dcop, and link against kde and qt + env.AppendUnique(PROGEMITTER = [MetasourcesStatic], SHLIBEMITTER=[MetasourcesShared], LIBEMITTER =[MetasourcesStatic]) + + ## Handy helpers for building kde programs + ## You should not have to modify them .. + + #import SCons.Util + skel_ext = [".skel", ".SKEL"] + def KDEfiles(lenv, target, source): + """ Returns a list of files for scons (handles kde tricks like .skel) + It also makes custom checks against double includes like : ['file.ui', 'file.cpp'] + (file.cpp is already included because of file.ui) """ + + src=[] + ui_files=[] + kcfg_files=[] + skel_files=[] + other_files=[] + + # For each file, check wether it is a dcop file or not, and create the complete list of sources + for file in source: + bs = SCons.Util.splitext(file)[0] + ext = SCons.Util.splitext(file)[1] + if ext in skel_ext: + lenv.Dcop(bs+'.h') + src.append(bs+'_skel.cpp') + elif ext == ".moch": + lenv.Moccpp(bs+'.h') + src.append(bs+'_moc.cpp') + else: + src.append(file) + + if ext == '.ui': + ui_files.append(bs) + elif ext == '.kcfgc': + kcfg_files.append(bs) + elif ext == '.skel': + skel_files.append(bs) + else: + other_files.append(bs) + + # Now check against typical newbie errors + for file in ui_files: + for ofile in other_files: + if ofile == file: + print RED+"WARNING: You have included "+file+".ui and another file of the same prefix"+NORMAL + print "Files generated by uic (file.h, file.cpp must not be included" + for file in kcfg_files: + for ofile in other_files: + if ofile == file: + print RED+"WARNING: You have included "+file+".kcfg and another file of the same prefix"+NORMAL + print "Files generated by kconfig_compiler (settings.h, settings.cpp) must not be included" + return src + + + """ + In the future, these functions will contain the code that will dump the + configuration for re-use from an IDE + """ + import glob + def KDEinstall(lenv, restype, subdir, files): + if not 'install' in env['TARGS']: + return + basedir=env['DESTDIR'] + if len(restype)>0: + if not lenv.has_key(restype): + print RED+"unknown resource type "+restype+NORMAL + else: + basedir += lenv[restype]+'/' + #print file # <- useful to trace stuff :) + install_list = env.Install(basedir+subdir+'/', files) + env.Alias('install', install_list) + return install_list + + def KDEinstallas(lenv, restype, destfile, file): + if not 'install' in env['TARGS']: + return + basedir=env['DESTDIR'] + if len(restype)>0: + if not lenv.has_key(restype): + print RED+"unknown resource type "+restype+NORMAL + else: + basedir += lenv[restype]+'/' + install_list = env.InstallAs(basedir+destfile, file) + env.Alias('install', install_list) + return install_list + + def KDEprogram(lenv, target, source): + """ Makes a kde program + The program is installed except if one sets env['NOAUTOINSTALL'] """ + src = KDEfiles(lenv, target, source) + program_list = lenv.Program(target, src) + if not lenv.has_key('NOAUTOINSTALL'): + KDEinstall(lenv, 'KDEBIN', '', target) + return program_list + + def KDEshlib(lenv, target, source, kdelib=0, libprefix='lib'): + """ Makes a shared library for kde (.la file for klibloader) + The library is installed except if one sets env['NOAUTOINSTALL'] """ + src = KDEfiles(lenv, target, source) + lenv['LIBPREFIX']=libprefix + library_list = lenv.SharedLibrary(target, src) + lafile_list = lenv.LaFile(target, library_list) + if not lenv.has_key('NOAUTOINSTALL'): + install_dir = 'KDEMODULE' + if kdelib==1: + install_dir = 'KDELIBPATH' + KDEinstall(lenv, install_dir, '', library_list) + KDEinstall(lenv, install_dir, '', lafile_list) + return library_list + + def KDEstaticlib(lenv, target, source): + """ Makes a static library for kde - in practice you should not use static libraries + 1. they take more memory than shared ones + 2. makefile.am needed it because of limitations + (cannot handle sources in separate folders - takes extra processing) """ + src = KDEfiles(lenv, target, source) + return lenv.StaticLibrary(target, src) + # do not install static libraries by default + + def KDEaddflags_cxx(lenv, fl): + """ Compilation flags for C++ programs """ + lenv.AppendUnique(CXXFLAGS = fl) + + def KDEaddflags_c(lenv, fl): + """ Compilation flags for C programs """ + lenv.AppendUnique(CFLAGS = fl) + + def KDEaddflags_link(lenv, fl): + """ Add link flags - Use this if KDEaddlibs below is not enough """ + lenv.AppendUnique(LINKFLAGS = fl) + + def KDEaddlibs(lenv, libs): + """ Helper function """ + lenv.AppendUnique(LIBS = libs) + + def KDEaddpaths_includes(lenv, paths): + """ Add new include paths """ + lenv.AppendUnique(CPPPATH = paths) + + def KDEaddpaths_libs(lenv, paths): + """ Add paths to libraries """ + lenv.AppendUnique(LIBPATH = paths) + + def KDElang(lenv, folder, appname): + """ Process translations (.po files) in a po/ dir """ + transfiles = glob.glob(folder+'/*.po') + for lang in transfiles: + result = lenv.Transfiles(lang) + country = SCons.Util.splitext(result[0].name)[0] + KDEinstallas(lenv, 'KDELOCALE', country+'/LC_MESSAGES/'+appname+'.mo', result) + + def KDEicon(lenv, icname): + """ Emulates the behaviour of Makefile.am to install icons + Contributed by: "Andrey Golovizin" """ + type_dic = { 'action' : 'actions', 'app' : 'apps', 'device' : + 'devices', 'filesys' : 'filesystems', 'mime' : 'mimetypes' } + dir_dic = { + 'los' :'locolor/16x16', + 'lom' :'locolor/32x32', + 'him' :'hicolor/32x32', + 'hil' :'hicolor/48x48', + 'lo16' :'locolor/16x16', + 'lo22' :'locolor/22x22', + 'lo32' :'locolor/32x32', + 'hi16' :'hicolor/16x16', + 'hi22' :'hicolor/22x22', + 'hi32' :'hicolor/32x32', + 'hi48' :'hicolor/48x48', + 'hi64' :'hicolor/64x64', + 'hi128':'hicolor/128x128', + 'hisc' :'hicolor/scalable', + 'cr16' :'crystalsvg/16x16', + 'cr22' :'crystalsvg/22x22', + 'cr32' :'crystalsvg/32x32', + 'cr48' :'crystalsvg/48x48', + 'cr64' :'crystalsvg/64x64', + 'cr128':'crystalsvg/128x128', + 'crsc' :'crystalsvg/scalable' + } + + iconfiles = [] + for ext in ['png', 'xpm', 'mng', 'svg', 'svgz']: + files = glob.glob('*-*-%s.%s' % (icname, ext)) + iconfiles += files + for iconfile in iconfiles: + tmp = iconfile.split('-') + if len(tmp)!=3: + print RED+'WARNING: icon filename has unknown format: '+iconfile+NORMAL + continue + [icon_dir, icon_type, icon_filename]=tmp + try: + destfile = '%s/%s/%s/%s' % (lenv['KDEICONS'], dir_dic[icon_dir], type_dic[icon_type], icon_filename) + except KeyError: + print RED+'WARNING: unknown icon type: '+iconfile+NORMAL + continue + ## Do not use KDEinstallas here, as parsing from an ide will be necessary + if 'install' in env['TARGS']: + env.Alias('install', env.InstallAs( env['DESTDIR']+'/'+destfile, iconfile ) ) + + # Attach the functions to the environment so that sconscripts can use them + from SCons.Script.SConscript import SConsEnvironment + SConsEnvironment.KDEprogram = KDEprogram + SConsEnvironment.KDEshlib = KDEshlib + SConsEnvironment.KDEstaticlib = KDEstaticlib + SConsEnvironment.KDEinstall = KDEinstall + SConsEnvironment.KDEinstallas = KDEinstallas + SConsEnvironment.KDElang = KDElang + SConsEnvironment.KDEicon = KDEicon + + SConsEnvironment.KDEaddflags_cxx = KDEaddflags_cxx + SConsEnvironment.KDEaddflags_c = KDEaddflags_c + SConsEnvironment.KDEaddflags_link = KDEaddflags_link + SConsEnvironment.KDEaddlibs = KDEaddlibs + SConsEnvironment.KDEaddpaths_includes = KDEaddpaths_includes + SConsEnvironment.KDEaddpaths_libs = KDEaddpaths_libs + diff --git a/kstreamripper.kdevelop b/kstreamripper.kdevelop new file mode 100644 index 0000000..d974588 --- /dev/null +++ b/kstreamripper.kdevelop @@ -0,0 +1,206 @@ + + + + Michael Goettsche + mail@tuxipuxi.de + 0.1 + KDevKDEAutoProject + C++ + + C++ + Code + Qt + KDE + + . + false + + + + + + + src/kstreamripper + default + + + src/kstreamripper + executable + / + + false + true + + + + + + + + optimized + GccOptions + GppOptions + G77Options + -O2 -g0 + + + --enable-debug=full + debug + GccOptions + GppOptions + G77Options + -O0 -g3 + + + + --prefix=/opt/kde --enable-debug=full + + + + + kdevgccoptions + kdevgppoptions + kdevpgf77options + + + + + + + + + + + + + + false + 1 + false + + + + + + + + + + + false + false + + + false + false + *.o,*.lo,CVS + + + + + gtk + gnustep + python + php + perl + + + /home/tuxipuxi/Documents/cpp/kde/kstreamripper/html/ + /home/tuxipuxi/Documents/cpp/kde/kstreamripper/html/ + + + + + + + + + libtool + + + + + + true + false + false + + + false + true + 10 + + + + + + + + + + + + + .h + .cpp + + + + + true + true + true + false + true + true + true + 250 + 400 + 250 + + + + + set + m_,_ + theValue + true + true + + + + false + false + + + 0.1 + + + + + + + + + false + false + false + 0 + false + false + false + false + + + + -f + + + + -dP + -f + -C -d -P + -u3 -p + + + diff --git a/kstreamripper.kdevelop.pcs b/kstreamripper.kdevelop.pcs new file mode 100644 index 0000000000000000000000000000000000000000..0139aa74223f7b9ffa8be299a0b9f99875b91249 GIT binary patch literal 62876 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 Udc=*1X`f-t=%m*pRH`ujKM?q(o&W#< literal 0 HcmV?d00001 diff --git a/kstreamripper.kdevses b/kstreamripper.kdevses new file mode 100644 index 0000000..da20bed --- /dev/null +++ b/kstreamripper.kdevses @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/po/SConscript b/po/SConscript new file mode 100644 index 0000000..0362e0a --- /dev/null +++ b/po/SConscript @@ -0,0 +1,24 @@ +## This script demonstrates to build and install +## a simple kde program having KconfigXT settings +## with scons +## +## Thomas Nagy, 2004, 2005 + +## This file can be reused freely for any project (see COPYING) + + +## First load the environment set in the top-level SConstruct file +#Import( "env KDElang" ) +Import('env') +myenv=env.Copy() + +## Make translations for the program "test1" in french (requires fr.po) +myenv['APPNAME'] = "kstreamripper" +#KDElang( ['fr'], myenv ) + +## NOTE1 : +# KDElang( ['fr','de','nl','pl'], myenv ) + +## NOTE2 : +## updating the translation files must be done manually +## for the moment, using the messages.sh script diff --git a/po/messages.sh b/po/messages.sh new file mode 100755 index 0000000..a36f5c9 --- /dev/null +++ b/po/messages.sh @@ -0,0 +1,60 @@ +#!/bin/sh + +# Inspired by Makefile.common from coolo +# this script is used to update the .po files + +# To update the translations, you will need a specific gettext +# patched for kde and a lot of patience, tenacity, luck, time .. + + +# I guess one should only update the .po files when all .cpp files +# are generated (after a make or scons) + +# If you have a better way to do this, do not keep that info +# for yourself and help me to improve this script, thanks +# (tnagyemail-mail tat yahoo d0tt fr) + +SRCDIR=../test1-kconfigxt # srcdir is the directory containing the source code +TIPSDIR=$SRCDIR # tipsdir is the directory containing the tips + +KDEDIR=`kde-config --prefix` +EXTRACTRC=extractrc +KDEPOT=`kde-config --prefix`/include/kde.pot +XGETTEXT="xgettext -C -ki18n -ktr2i18n -kI18N_NOOP -ktranslate -kaliasLocale -x $KDEPOT " + +## check that kde.pot is available +if ! test -e $KDEPOT; then + echo "$KDEPOT does not exist, there is something wrong with your installation!" + XGETTEXT="xgettext -C -ki18n -ktr2i18n -kI18N_NOOP -ktranslate -kaliasLocale " +fi + +> rc.cpp + +## extract the strings +echo "extracting the strings" + +# process the .ui and .rc files +$EXTRACTRC `find $SRCDIR -iname *.rc` >> rc.cpp +$EXTRACTRC `find $SRCDIR -iname *.ui` >> rc.cpp +echo -e 'i18n("_: NAME OF TRANSLATORS\\n"\n"Your names")\ni18n("_: EMAIL OF TRANSLATORS\\n"\n"Your emails")' > $SRCDIR/_translatorinfo.cpp + +# process the tips - $SRCDIR is supposed to be where the tips are living +pushd $TIPSDIR; preparetips >tips.cpp; popd + +$XGETTEXT `find $SRCDIR -name "*.cpp"` -o kdissert.pot + +# remove the intermediate files +rm -f $TIPSDIR/tips.cpp +rm -f rc.cpp +rm -f $SRCDIR/_translatorinfo.cpp + +## now merge the .po files .. +echo "merging the .po files" + +for i in `ls *.po`; do + msgmerge $i kdissert.pot -o $i || exit 1 +done + +## finished +echo "Done" + diff --git a/scons-mini.tar.bz2 b/scons-mini.tar.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..0c1ce52ebd59ae92d9a03a288b1922110cc899b8 GIT binary patch literal 58214 zcmV)3K+C^ET4*^jL0KkKS)yFZQUUsA|NsC0|NsC0|NsC0|NsC0|Ng*;fGQ*i1_4As z4FHe=h)7{PyUqwVUNPuX=XYJZlx{dZ$JC?6~8PP1t$rs0nyJ zp5J-J<)iKH;ELXDd&0Mv>~`;U?>Xpn4HshW+-Xe!61T11xqA1na*w&kPrH2@H@B_g z8Bvo$On|SR+ukwnwCBL~?f`SM+4FFFy7zh4W>r*{v{7lJW}#Iofl7*`c4Pnm0007j z00000&;a=lBhs`0D{KG&6b6mkinkZndo$UX`fja7-1PeJ`kw7Ch3?SVn_la83pb#8 zOJ@7-`Fp;)z1`c|lI+@O0*VkT-#qo>?#P0Hb^sbufCKNCXTG`X>F;CewTHLe-ah-? z?``h(M(w@hhkdo*cb)IPZteHIyVsjNo4bv^_UG5$<>uSF*IAzX9X>-K6gR!iaKX2} z^7B)VJ=eYN^4{04d8^&`yS?1z=5G6p=G6>92DiI|ynBEi@tC^tYp+7{?(IA0x{<9r z?QA=}>u$Ea>%Pp`d%gF2-48Qm+Rz#_`eEzeH@>p%?!I-D>)zfs*w;`H6aWf)vE7xx z+odap*lzgix0{3CXJ00df!iri_fpG zZrjoB)$>~&&!^qsbUGb3*bdJ?NT%JO9k)x&Fr5GZ(9o?trhDF7ceX~^SI|(+joV*S z?+c6CgWKJYVE1=k-jmu&0&Uzj&fa^|v^nnwpzVWKy0^Rl2iv%49{T_QV*9zzMw|`ZcUiSx`owMf++1a}7$1YyxU(=ee~~r_m87# zs8AYxcNhZSJDaIh7j<#P?Y36vHr*W#UhEEmoD6z800*{o`gC?D%=O=W*LH5+K>NEl zRju?lx)Pco5D*9i0Dze^OeO@$3`Ub=$xjM+)iz1yrjhBX>7yk5Q`7(e00gEYAc&e1 z5Y%KT;6{}FRDJ{n4=L&fp3;T{0LW&isL7xVKmY&$5;Y`3n2Mg!svb{N9t|Y@G!0Pw zHBTlK@{EsD)Y^fe>8a%gLuzd!Ali(Y001&H^HdUPBoILaz(7w?Df*}SDtV%9DdI<@ z*qWYE>HrT-L7?<%dV@nojRt@K009a}f&eCfm=i!ohJ`koG$u_^v6Vd3o;4@wLqkml zntqaK$lj=800004nn@C#5S~e(Q^?fHdqhuE@lQcLGHMg_gGl{E7zAJe7y!^ln3wcL%O$H^Zdp2Xq!-U@;^}2xu5)3aX?6N(o62B`Fb9 zr4b51C03PzMbDFA6oNkB|YP=q955GE0Y0!CF45)wfX9;dJh1_4?Hp?YNZ`)g$S z{r|&+P?jT zq=aoTcw{KzIVY`Y1S08p_%G*F<8p@Sz+Ny-=DcmIxtI=+PRjaBzf z%{8q& z2!)5theY3$f8$cll#rK2=K=1XnfO+m5DX49IrJu^{C^0qFtA+9ZlKQ(?*Ztq?=A>jIBJQ$F!3y~ zBFXOaQCDhs-u!1o4Ig4kugBQ?>l5F4SdcBP&3z{ItkILGnK`&lrOOtPeVpmw=0ZCr zlG9BHx@yjFPw#Yn)SWo5wc}0l&P?f{^H4gno~}tU1(2HP!r2AH=gRJN^zZd;$2ZBc zutAS<7F+6Jf={xCuQ}vA+3s*yk0h}rPPs&9Ul7hGA6I#!=+)!BWKh_qB;7omWZgP@ zxw#gV?My(V)8$_rGIEE^aJ@6*xiGGTsXa-lbt$4^0`Cr^q9qTH*NgqYsCnWCNAaXf8XE>hUH;2k| z69U;B1ldTb^C5`8yfb9y>dc6CPW9e*K@3o{?6M@&N zc9fcG5yTCX`1d(|osTRPJ?kl%9r{)Nd*@mAOLr_$}uI!@}6!@oYS?FQ3Vu91HVv2WDpZ|X* z-93BeZste}-AP76C#1SF8Lw6@3P{>kl^rF4DDyrAt}SK%BGzPw6;6S+5c z598z4c7=(I?RIdtrcs?}ap6q|koW6Z=d|4`i7I_vfbgUpT^3o65`nb zG&FSF_dl<*!oK;O76N?!tnT=1aaiigE8|F67%P_fs2tpTZQXKnB{v|3Pr)2v(2c2| zbnmuNZ}6aTCjNx^(euLJUpXW(JqhegN0!7z525ZIX|6LQ`RiE%q&9mYE?&%;n!?3F zV6iRx8Q)Tewd?7#Lm=&#V+4N(&oJQ@b!5ehMWiJVM~hL2kq)#9MUgpeQ%v!hFCLY4 ztP&M{ti7=OH}6wuU3Vo1W(75DA4OigS+?A=V;$<1ol;RD!U0nrTw;R0(v^9#utqTt zQ+r$>B1r=M4XQ}tQMlvJ3d}}+8d-DSauZ22Ii!zXQ=YmxLkG|FRGprbk>#Gz!8GeS z#HFpC8HVr*X*Vh)|HdKPsygEo1rry4|npai2hj?5&L=*FSTLm1Z zkw(JNQ(3})efWDi*4!TIw|2=%BP}f?r#FPMf)vT2BV!)bk8ACDdnQ8V$~bS0`HfcFfk2O~F45hdKR^24ea@nU2kmg;@#C?}pRQEihQVjfH7Z*Ek-w zo%-4`O<-9+Idiu0={?~N|s1UE0*YfkaHWVH2X@h>&VHN_wTzT~B;ih=HUM)`+po|t` zPopm$t@!6#Z{=#HpIeZWJRp3lHuaq(Ci>n3+I_0*Rca?gH%UAyVna;_>+eG}`Q#1! zsB*){#?Df5t9mJtbdS|1X~`L=7&;^44p{}$8c>^NgS(4~e^P7rKf7E6lSpKkuG>~K zl)~{S4OKAYu$)5JI?&wx4Ar`|O$_atRlZG6P(rj0g3t9P_`~Dry}M6bod9`n2fYYgd~4CiYEnx^?+ilZ34=u}6u zEuqy6IAvRRV7Lxh4Qy)^H%iClN|Um8Oc@kWMD^3F#;g=M8xW~ptf;KCs6M)MW|`{R zoTWa(g-DC@w9$8WorzbXL+Z>^t_`H)8X?qMV&ov|)MM&oJ!}IySZwrWwXcqiB7$nj z9@un4-55+VK2qeQ757;Y^UMy3Re+uCV!;)BYLbjmOlw{vQAI0CQhF|W!jEmKr8z;h z%4X?3`YZ)@r11Q{?WT_=UtJGe;%g^QEX6);NTMgjE4?>io=({%Z78ti#?(KB%EN9cKCc~4J-)oJhX+iR zg2-FZCB7%Z|t>jN$5Mfk?Cw~1-FXadwW zc64U%=90awA+4EU<@gPbFtHIdh0FRM(z;@*sw$g1ecxtzrr?P;XiqfxJ3i!ZF3wGA zn6qku@L|}b4D8nG=Cx~xgfd87>-yQYQ$VIUl*U#$QkE|E&g9k$RTq*J#7}-uBBEfl{(AhpCnV&A7So z?GJkoi0sKKTQ;~q#dBXM9+YA2@5~PV`^qWcl_YI1)SI)-D9?%*E^}y5(5PqEQCGQF zs;Q`mR2^L$Vy@QbcFH2~`O8OCpgO;F>~V<7+Lu($PgB z%EAnclb|aMPhQlJ-zBkL6yo3`D6l$qI z4b(6S!cigYaSRd^rAXROJd<@0*V=6$dCdt*8WBirAW`gv8EuI9aBpHC1TQoju?(py zLb6DpZ|c`~{P+@o7pR1Uh7$P6{mM;0(&t`Nu3SEOQ_bv}hG`P=~LdCQ-=d)n5OU?-E1jmf>@J}!5~*IpWPcgk(1lbT}@O5HPe)3U#IJs?`z3M|lj zX#7@HaCLDLlh(=IH!5!(H?5<2nIq`pzL=_IXJw6Jb_5|CDAnmX}dKshP=5qZmA3%ZdGT{c?E+dRFWaCQoc9dIC_N`jIgQXoJ?0wROs`FQi! zEse*~A_xQGh!6-03;f7^7u?~3A)D3bLqM()0;#mW%_0jDDu(i?ISRC*CeDc5O@DT_ z*x3%(VbU5$Za8Yf1vD^{1R#u|Mkm)~fQBF-BZspL?D5b#Ou_WP8e~ugU`h6zG$;V} zFe3;%JuQLFWY|2^+t$$aq%8FwSPFTG1Ck65sJn{PNz#-oDP+8qJdM2By6_G?v;&)q zAuWQ!wW`+ZE<>5fJUZrlzM;DL`pSI$zItFZLTA62V&dc%=#dTNuC6C-n? z|Bn{w@qBwQcE@Wr6s!@y#WkeW?NfMW{mDG}&sLKmrd4GARG80C^2;V96p87u@4;ZT z@;?9;_CMHh+(hELXbO_?SM3W1D~c#a{AhdgEW|0Vm+pVWE@4gYEW z-{O=yM&4a-B_cH_#GEogd3u_U{p^A!`C4#A>p(tWX6{dv4*Y5T= zNOQsF<3@|-hK2bgdZl))FEXC5R8)MW(6kE4ojHD&OB_#L)*mzrwS?G1@g{bcwz^_@ zOsy!=1*2hznJ6D^R*=mhH^7HUw^Uw==y4Tf-ml+UhxGn$b8%ZUhkw5hHp$sLBV|dB ze*6&J99#D$*Skn!u;b-`Y#3n4lp{DpIulK3n4srVtE%E0iWOUI5*iKxy|Z()8^owT zA+8jH!n>QbM{fyoK-n;NL%}r8;fidm`0~sR^-a*;rG(*RqZwT}Go!Io#rJy&8OHg! z`hh&=i&P9lO{9Qjz_V`0q*ek}^^5Y(5upphVMe&QVh@_JX$Et9EmEr5r8^|nYUPu;yY*9zToGb7Wtr1-{G>J|^VWuaAt2ol| z6-{3d@tYCZdGyG<{y~bK=(M|m&3>bt4(2kt|7872FSPEEKP-oYYXS2? zw7>3uA(O4{3DeLVM@QKU6BS>EFFqt2K=t~=>VCZICwVN-~uRdFnfGybbk`}Aoi;tIR>?G zz$>xD^M2Q945E`qB;H69UtHekZv~ysc;{)KG~Xu_!yg}YnzKutxEQ7f^;x5bMz$rT zvc!{PgBlR2LHrqncNpXSZJ|LOe$O6b=V@v68*hZ|B#yX{K>+?O)$bqhPBYIO8@(F% zNDAoJt;NN>UIXVNpAFo2j>A8F>Wg?8Dle6k>YBIbmw#5>;AlY7Ov%(t=T^LwRR-7> zoaSaa9W*KDQpVCvD{dNUIV6`q4slY*M;;ufer;Vz8H^=#%_Q8@5=)|bBsVrbsjhq! zFrDVI-+T=q>L}GlGSJ{vK;tCAlu3l*4RBH(1{4fhj#f76fsPHphV|=tYd!V9Y|N#o zWqHj8To4b*I? zo0uh2s;sexwi!k$qQWa>UWKg%(lu3?w$!7oYukKN)gQ?4_E4N8Js?uRQ?h!Mfh@fG zY-{&H+*vYVc3Riz_VQ?dv_$hpC9F{TGq1;9i`SpKmU{W+wS_SRLP?9rmZ9lYR;sG1 zkq6l(@}akp?<*Z8pVq5pa z`scqpTqykkB-l{(aWp1JJ)R7jdEYt)vF`b8NW8DK$O~jb>u|~_92x>blfMbE=g5{Yca%PhJ@u?KFgu8LZCW1Lx{Py>DGU(o$tEGX9?p07 zNxp1rnjSeX@Lf&c9w|PcVP2uWF(WN2W(yS^ ziPPA&SbMo8YigXxv4%u^6>0;G-t`Msous%gF!3Zdnak7~W9bjlCE4tYq` zFcM5KlK_Ow#al!Z#EaIxb#vCPRB^uV?xRx^CYxK0$2v6GkdT;>^PHE3$&%B3ES!fe zC1-uT84ptqi8mC#hHjn7mpBP-TrluXMvP~l>q}U&o4;g7Z`E!mr%6z{Tio^6- za^P^~Jt!l9<%Oecf_#VvZpT<8sA^dWbBU!z0PigX`>68!Uo+WKv^3ui=Daz?uZ7%CM+_kia zOO;!0#yhtB5}sJG(jh@F$VT#S36F06MrvP4?A3oR#OjLk=L)FA4pI`L!ZV^AhEbT6 z3}q2v@J}6lU{ekA`>($bSF2f7GyIy+m$-18$^3P!^c<}akQ75ik0lCk4TkP{_452& zlc~=#chxNDHWC`CQmT9fR*f2}$>D7XRDTaTz9t?OReubp&wDg)_^jO2mPl_IKLa%K zd%pf_OzW2r;9416IyyyR!X&*`vHIz1gIF0*(){Q!t3EUXob~4Y^J6yXm4*UI?&&io z^dDAl6ckGXgxx1188G^OD<2gvy;kQE3$vRSbK|qhMn15x8mUX&tttz0Xs*Y9C zrG>NY`8>o2LMj5?_baa2S`_-QX{xJ*z=7Q+1XGZ97f1aw3blN9g;jDJ= z(WJF*vTpIz+fh-4hie7(WIXL=>Q$zxa;3=x_H@h$U=qnyp`9Y?wk-R&-zy-YMCaRP zCXh~j|1*cFe;J%^hXhqn(eErSGB!2_Lo&pjcH7ftc=*y7hYV6EBHC70xSG`lk_19R zZ)kL?v|OAonq_m!Y=_+fRQ{}&O}QnGE$59rI8qA`O-T}$Y_()>YRXKPiV_PEF+329 zo~>+*of4!vD+Q8Pd+rAjr8G5V>X}lz%&t%vI<0f-+Mi13*CF9i7d)thX6+QqGPz37 zg;(P@(nAe&HPujzs1G@J9^0M}Hh8-En>n&Z2zn_CfpQuLUsN@E$(|~PM62w*t&}`>(XRiZq3p7ikjF}CzerIKH(X%9q z)u5w}{{2AcZ+Cb4vtvQ0&9NkS=?&+2&9*oM-Oh-l0TxspB~Qh_%`Do|puBad|>rw*T!d;iYnJXV6NMw z*Wq5S?aA#x>@xae6u# z7;UQp^)zCk!8up1F0Q;()tb#iwN@a?;qkVWAG;-^bmEtOw^i?oA~t$rAmU0pm}DUI z7fQui<~3vV@p7~W6GgkA?SYD{xH_grWI`3x+wyQqvhq1OuL>1z{g!+0V9hz!jL)(>}4#AUgZn|sb>iUvx7!U%;?S_lfgKUL_= zA_ei{>eaELkh>8P%1BnsR<6X`=|WZbmM&G?f(GG`bP&>V=(_@2sALvKB1tkdZxsBSc-Lq@do9_K4%nOjr?J2_Ab>Bqr>aY8uJh?Xv@Z&gXA8NQ8Vfkohy(Q1&}Rl+e63oA5** zWCT)~qyu`HR3 zBpK@us`5J$rFS{!0_mlgICD)Pd+iNd-3}%cWsyn0z8vP}#NWNUY~^@y@4Ga@h+wVX znj;(|-`IhBXle?LCpC}-kvGT_O!-0MUOO<&Lay;)#m@}lfe9%@5k^G!b|w;Yjzpkj z6>z(FYuhABWidvxGY62E0%fsAg%k;}c1%qndWoKROTL8y>t?T5HC{R062?<*nl^Q{ z)zOH(cN#0%6c(!&LOAiCMoi-&@l)sTS$=C_-eOfXxlLUv7LrajY?D#hhc@As3mChZ zZ}r7NQXk%1L7LvHZ-V?De58-UX!guh2t`{?*G2vO(MDP}bL7W}UL^H9S`4+!dGATm z?MniNgzhvZiHM2P8HusU*ymBY6$ZD0Etu|PqsgfaZCvk!=4aE=FHBHDEr>Wn`n7f) z4Ez{YA(<2AXIS9z>AVyFS+?X1ZqPCH6%&Z}nCy24sZH1rb= z%fv~LoYP%Mj$V$~zZA~cI%v_Py$C4QEjBV+UE=h1C&ZSrmJpyKtm0#b5rPpqO4`x1 zXsR4m7B%nRX!7qCpOEa9yE;An1}q)LHY4ghB5X4U@}u;8u#e8T?fT{2>izi5S(f&4 z49*Ydid)Rn@lN)^jbaYFkWTY%l4slB2f9_Hy}qBmagoVx_G?2Q&d|>-Jd)+UvXaPx zU-o_Rwr~1d=-qzv{!O3u`gfH-8`EQVQsW;-Po4ZKt9jI~VX5DVH@$nP9qGYTN7}v$ zqB^ABp*c-NQ6r1pQKcUfa5CrdtBDBC9XRx&X6d3kwo2fcob@62y`(yHiaBS8!6Os< z^KY_E`VZmj2lJ-9%0n7M*_n0fbJL=|Q9K#{C(^io9*-~+2tfzf<9{Aq3N=JI@Dn{o zr3GF-A*3{uN|%obTu!4f$TM`7M4PMpxPG&^eVEAcm#`zzf zTBli`wfOEoO3V8ul)mRUj(PomG4vUFcNY@=?-P!me~Vpm*VP1lzk&&fl%Kz+-X~^a zX_XMrs=sG)kNTx8Ek!Op z9QR(^+kfVZ5I;Sze)k7rzNmOfK}!Ap*RDC!r`^lYljzp@5-&tdDCErndC2##$;G44 zmK%$45>RLLpVU-S^P>K$V3QfM_iH90^8B9<$$Y#temzdT(zl{_pSdIBg0RS~M@x zxh4&N8%ct9l}sR!L2&=;pTZxft)PEdCx`TJ0EIS5kp7O%G!hZicR~8q@W;*J<>i0J z^Z$?W8}@w8&!OXVF*oYG!WyBnZJaU@%EB=vw{{`fuyooV=yIPw#*8nA zu;6Ruu$?=09h6Y4Dup7;S~jQ+X${t5twOA6C5QrA>IDG7fRi%}1Ouu;|87zLz5j#9 zO8J>jREn7e1JG<7^mgxP+Gz7$>4%YFmK#_nxsx&+qSL^-EWXK^(vaWY;$;Q2fmDED zBO*sUymX(exxex>l&u8>O)%}PCWs;h-vt+-sEgoO8T}&3MjP=-jXv5MJ6>5QXvlDd zNv+Cf(>4QyKdK2fllA|l_-Mz`{okMVXZ?fkBmT4T|62$9%&Gp5#rtXac%Q-JEus7| zzwo^Om47}@Vt1EFyxZ5Kgsnf*_F6xK(}y2SoBUe-sGs^i&qRykR+IxttPE`K&%zjx;8yM6N2 zP|**Sc-`KwQQtp87kkI7k9|4onS z?%j0L?vH=fZS0jqk;r!LdoLq$&0mrI&o8ljyd76a`8fZJT|M7)dq11_e*^s5e4FIH zCy@+$gMvQ>jUK!5B@*+AC!0IN`@R$As{dV|@comKJa;{$rt$aOkDQ3-s6;e0*U=Khx~@{?E7c z+sEeidsKL7(`Dsl`@g-$KUqS!{15vl?%Vdndc66R;&M&P+9q>h%_C|0&B>eX;!n;j zK6Qinkm_>Ol4#CbW1!x{R5e2t#scU|{#2W53Q@Ybo=L|he|&n4`3io={xlB1&H3p$PK^9@{XC<&_C9-9 zIzDXBIN8nyJ%5*lyL8IYh)gK)C0zW<`o8C8$X>;@B1EJ!b29bfX2z))h6)wd36!6! zhqfcXta@^J@jlu3YuY#nM->uB0lZlNe{;9ApJ+bRg(%2BOu~I;kGB_E!8B;iYizs! zOC&6H{-r4@Kly*!nf#jAs%m6z+Sz#QF08{m#B~-7rC5~U=6-Lv$CmuL_`6eEtuGYB zf0&I!Sq?5r%$_x^UWrIjh2jLdc8*Cuu_^?w86psYoFowF^gLa|YAz z+-d(M$Er_OhMuS4n*}F32y~Q~bXo4$sTHG?LcfH|x;AMFfl#WxRf`VFHAKd0cB^Er zxhgP&_;6-7GOW(T=tDIlrHsf;m;&@LqByUo*XQNl_nhixa!lEpIjD*0s)Vit4N#*I z<8rnc!l;$zr}^FreeuqR->$ALe}?pG8q3j@{0(!h3xoIYVl%9BWw@K*R$R+T?X>2z zRYa%wWh>VfQx+-KmB8}Evx!9UrD=-C`Rxnstsz&9EG(t2N%MQco0lrn6QTsm+`Vg? zzfPK3=Xy;{ ze-5Vh*wt?*DEHgUH%-NtHfBFAXo5y%w-Rj3Pa16leN@XeEFj{ETIPiv#Gi2{X#3eL z%Ut8EO0c>*4j0o~=AWxi-0M>_iWi*kmo~(dtx_b`;PN{+j8L(N7g{DEkuAByCd`4Y6aIP1)L{KzuiW+w!p%(oGBley%B}5y?5RzN#9=g~KNr?$3m-|^=$iWO z;?-jd`SU>NSMhjmxdpO&zC4@u@7&>|2d*8KTEQ8vq2ZkH#gQbEO1hnKekG!D&C*kc zVmP3)VP%{_w%FS((ct8U-KJ9plG!VWPeh55;Wi_RPfhBb9Av7fbL>A( zHPZ#lpyO8VZqAaa;#LcF|CbBiXxWh^SZrg<1USNxA;WS;n zzSg{4Uc5hDPF-{G*6T!yVX0#hcCF)5CiE1>fdjcvjV)_X+@z!BUC^@;{qMS+R6h`U zE5Poz!SC+~ym|fJ``1l%+~=DfSjrx=MnzClL_6}UPi7OBt`fz*ZBipvzf#qimUKiM z>q`zDWGGFI&ADK3fpZeVre8i{-PZCE(^MKg5`^Z z4W~3tKJWM2r8TaO;`ZJb2RYA2f<#Q4Ep9lOW!SWKOzbNH7MM=QMm&KclNMr|;E#HZ zbSPzedwTPLim0&@mQ)5Fjw25acQvulJW6Kao!=U;wR{z+>$&u^?B>oJ;h<-#qh{@%vk~5wLgGROmgigqe+E%^FJ8hA5 zxx4+>)Wh&W)IQFN=IOSpCiHsG5?=h(C%S19^FhlKrRL;+M-4J8;vYCS5AmZD*{xh{ zr7}`!rn%oE0nFRFyBJA1O+;b868ii~YDuovOH3+aCn-?`e}8+bU6+NF>YIESL6eou z`B<@vGy?-G$rR78-LuGn*3(xt!=XN)ZRkK`KVkJD+7_3la<;*EcYSL$xqxY#| zYbr;py{Vk7BZu!QY`;xNC6B1gR=DLqMFC)iTg4?eRIv4(AEeRiEi{taidoNWuEb*x22=N&m5WP+Bkl1xt*gz9Ovk{&JP>O#-An}=Jrcn7mu6n-lvA)o|0+a9=u_z zeG47!YzsiDv=s2M3TgQ3Mqd7QJ}=f^3xl4m`p#i~yz%;0uKV9+rwp6S&n)VstA=rs#I)5~Cj2l`jT&go>Q=K6E}v38wI)$! zju>*txS6P~nJj8K#HD>HGU&~&J?)2vT7kXpc@GB8NLg#jcXFysviRG?EpdomOwuhH zk;B;3?}b5#-vp|o7IRuf(xa(ygC}aINnTbpViJ@YpS&&G|F3><( zu$)4!)@h)*%NLTHis{|m3kL2MGj3DgTGmUcAg*FE+dTSK32&O-=yk7?eznBhD^`MT z{Aq>6GNx~Pv1f*%?&B)Uo^r^_GT7c_6wFkpv!hl^wOl@B?))6~ zrAVk_np=8492^IH7QBj0KBfV-dvtSm= z8A*{O{D>`Q9ztEwPvvyh>p|upjh8TI!~@^)Oe^E7)iJ0>c^`+Bx3TPT{XPTFG z8>F>%omJb{Gq{?r_?6Q=-S}mcs_@0Ot>Rjit_>Jhu&V=o`Z)35ixuJz=_ z80a6~mlSd5?8@A`xh*j3Y_d2d<#hb35=G;dAI?>JRp(l#oga#-;mC^C$fN%RYNdDJ zwnvAz91iuqv6SG9Q8YSo?;Fj}4zkikYbAE(gN(bk^WQ7Kb}fY^sPwFyfhXalt2uez zl9CsCc1k%Gg5oDW1~lPXXFSxdbtNu)RZ-;KeI*>9e9dIj(v$C-i-tVyZ^0Ki`7H83 zkH>9t^2bZOrv2OXcjL)dY4*utD){(Yp-*P!JfEHEX~sMFX~zaEaq;C}YyA4>>6Zs? z2S**<-Tf18iO6zj<-t-pd}dF{55aX>680>3IW>)I8Stj2!4xi6Mbh$#^WM*qoLfbl zT+(@EYD$vB*BI?YC=1N53vhkltwk*PXXIv+@OhE0F=ykqc9!ayQ@Z@)NP6yKBhp6?mg^Ni~A{xTb8xq zpS;mYLJZdb;nO|s-|m*O#({z(Tt`72NSa-D~99HR} zAtWx)Rm{y?w}vM=K~Cc`nQ4fuS`PR>21k7InP2 z+qTWhc*jY0itX8S%D75Y=ZMRGm6Kz({dSmdg`0HmrE+q4M{PHboN8H1j8k18qe$D) z5v};wS-%uZYI0c$YMS3HiO{CbXV-W z#Ct6LYZO3xbd#c!bw$@h$h(PG~}l2?r5 zHEv+-zpkgL?{Rqg`1b5A-<~UKyO^e?Qq!xG#O7mN_(7o^M?2MZiuq&Rt*LLKlCcBjxaLG1c9$v+*vazCwBNzx9?q20{dbC2hYs1r=Dpl| zqQhYgL~`erWdBEPAXD1W+@5xULKmM6Nj0;gv&qkUwPZOl1lcnt@$b{ZeyiFobpB2# z9U4Q)iA+I5!bQSwIDQJV)*AM9YX~qMqGezHb$a|hHg5VmM0)>6=T${3`Yv*LcxThR z9^S8qUzIaI2S+{+B&w-Dbk6Th=jX0CZ~u0leLL->{K?89_i2wPd%w_1sr%3npO$W>N}o%@B3O~-Sx0iB-C|ZEyQjj{RLyz&Q#Q2q<7tVuG<@=zM$WU{Mx3YR z>gQco5$T=^QR$}$f?YVX&&D}J*RX>o77>eI%PHlDD!HA6)8)amV5U{zOFi$xz1xzu z6YG()iN}|sQJp~RJ3I|^VKgA_<77hwKAJX$UVYI(+`Kop=Pl};3MN@0dofs=GZ#*9 zSbEwO&N6eCLGO z+LNhjRTZzMB2|7~SDg6r%|yOltMrlB%&!x!eQPmb==_Qx??9V+CYl{1oJIHHV)J3F zgo-Ba<&@+)W4p+D!kxS8P1d05rxenR`SO!w(`!g_JM;f7M@94OYW;fR+a6=#v_Yb! z+;y)r&$~s^+^W&Xln8wwHi3_PS>}Vyk{{s z7Ko8sM~^NXZ(60_v)yL1 zc@b)Q9KGA+!v(T0CEGhnudlJ|H2*I7M@u!4gR|3~xe|E~wxr1PS;|PaH738NZI$td zt_>G`cgw!n;?PZKgtqb?YrSRkT#3p#_sas3#x1{d(}f-|e4) ztebu}rad#>SAF7~tm}&NBDwJIF~(cdTvGa-`wwaJjd@?}?W8{)4Oc^lNew9`dt~nX z;mBC1f`Lx0K&qD!Idt8f*sWe2r)DX#G0b^KyZ`@cYGkR8s9H2hA)EB6?oL6Du9)idz!YEO1Rd_#iM@-+G7Ez zUukAyfD}83AX?{~jRbIp9hyyzkpoCHLnY@YlNIsQswHD8d=s%(xgDLb!_LTXvo-Hd zh2FwBkF4d!L^pq69GWGpZOcXv3A<@cZ>A+asfvcJ6bx$=AIFBvgYT3HwY-B9JEn6p`U=;^4Ofq zUI}+(CC7k?LmN-Cu+HuY-I>!gz6ROe*oQrCPHiQo$qAcWd|$ryq(<^-s`7GJk)ump zWehS>eZ+nPdD#?3Jsr?>w&hCpsQao_+RQXIWCu|ap_<1lmyQ|psyHsOzIr17Ee9tg zDQ>iv(@N#ROpqKfImMyd3oS{MvPx~yH4%{~Y_Ar;Xoi{CNl6v29@`Kj6LXvf?IAJ> zB+^N2bk4vns4dg4`M&FgBq$h_K65K}Dd}&sGD)F4)$)xQmG3VK%^AJ5Zy7YsM>CEN zTLwjQ+YH)F@K%!NX+T$keLzjZnEOBbsRAQD=OOCuDk`IPk*d%4GVVa0XJHfh3tBB*`Hlvmon#8&_PZM_929By>bB*;DsDC(eFcvtuC6y`jM3yIr{l zcOA;N1xBY4rR#AaB29u+O(^kIr%AcK{)#hV$8~e#(+bZ{VD@Jv;E2HGU?~i0#AnNp zjV@TNq&=k@?P=9Pw3ts=*1LwJ_XOB~u@-P5ETyl7}jo(3Xp%C{Oe zQb$XaZxh0LjD>BzSm>}V=E1D5bD=no8yjrZh=qJb5Gqf)bEQz5s9OSMIrLDloj+a{ zo!eWM;d}7uN=*p3wRAhAES8zc>k%fQ5E6~A-+Hma<8p#9Z=Wlik-#K+6bv|-EmaG5O2^5x7E zF-wI-HGYVK5|DWx)QA8jN;l~tuierkEjNyNc-ijKj~UF}rN$vL@3&YA8Q-po~rs^Equ9Lwgb%Gqj2 zLgR?5Q%=1%pi#H5L8Im+u_ZLL(>*AEYm-0%*WL=KAB@WVDqod?7Yy`3y~Xa& z)u}tD@2?d91#Y?hQOpLQ|dFbl5q9{{%cL*9m9z;Cm@HU`B9Yx}f43mW- z>wX(a-7Gm|-=9iu2GE*TRSAe;XkL<5AquIxfep^r%*4wQ8sS9)k08Woh+{p5a6z+0 zQz(Z9v`nJuP+`!32vlG`oetrof35=qZVG6L9d#xP!0539YJxgs$w)e*p(Rt135dv` z({0^`W~E0zhF&kWEWvrGv5p2ZAZGYZWmVL`?k(qR}P z7`;xezd6=QlR=~?9=F!PWSBG510?G!v{yw`s&6p{(Wr|=pmapl61tx>p_5NR2yIa$ zI)a%sP*bS+mE#Tb#+m&SW{jLBA(~0hhvSZ zhau|iE6J!V@wu;{+8gab855D(Jt1(Dw?@v*3A^N($aZ(S9Pi&_jUnmo=zDZX2q7gH zMQsO(O?FBKHdvD7l_XK{i)WE_Gwp#g5=8?oU4i?&>sdP=U0WijUdz8J!;PfTtm;!0 zQIRR}yOo^?qKW(sSF*D=H(p;JO=7j?PgHPouRZ0CH45Kea>ClK?3n7AofKIGQ(k^j z4&E=e&4Mm!@=T>Ob~>R3om`|TAaOOymX|4m(QxM|Y^o5$R5ExyO+xi64RpjO3o+*v zS0tDtE_HGyb;4#Dj<&L739ZH9q-wQ_oZARVs_g98W+l(B#Wk!q*46xb>>>9FFkteNsg%Rgj%9Zq zzRni?#3d`c0o%_qs3$p=xt0LRIa(A~*UO_~K$`UU<|2xMap#o`kvR}7o=Mpj6Q+!5 zGPPw>Qq5gbrJ`1=EQpA+4qc$vkbch7i}IxK^R+ggAB?K0`5is4D(CB=(sSC;zTTc$ z(;QDjc@ctpt96M6JG<{Lo!1()f8X?xqD9e;{1i$bCCvdk~86a%@x^WFOCNDo|aCT zx_$p$_om^&1Y5oeEQLWwx_XpASaNJ*5Jm`VonX@S=y5d;9-3!8VS=d4>QOb&aY1A~ zUD8>DK$F&3U~N~YFAZx*czgJKCWw(Diy)N?0<>nrLXjs?@od|NKuUA(S*snAbFh) z9L4WFFI`H~<&J|00$ijwNi?9z9CMwodO;-8P;eW8Db}5<$7%aJbTeW9?@PU0c3WfAf*yq(yVP*Ejv;!A%z7SCO>;v)A$eh|89TkMsYd!TbjXgZ$b1rfO;%i6%(?r$4vw_r)mw4AS{Yg#Lnw5KMpS%fAI%+ANG_B0H@#NiZk z;Uzr-v=;mDmWg?**0pW!yQGyWpq4^ls4AqPDE-!77;?DgQmjEaKWzP+-)i}5%X!TF zKbw>BCq^>$xMEd8$z_|%D?AJqcRmU)mn}{OeBw;gXj!OxJ zD8$zQp_Sfh6G9G1BGRjf~cW|I=JE;FI;fpnET38)OhIeO70(lU|qN#)qm7}p}iRO zE{U-nQ_pAez5L314-7RAB=Yj?8QcfLUchXDQV>kXG!DPE_Uq+0^sJ|y?N^woH}af% z*jK$GMS^DKXq@sRrJhdrWJmpKosi~FaS~cnF4y}c_bM7Wx2XyKnhQeuS@95$w7FM7!3@*1g-j z>9lQX=NH1^5mx%qFHeM%C2P*odAqiV2W4$!+Ora#RJG(rDME>uj8Y^gm%X-3xPFo* z3B`L1Fcsia2+u6#X;za`C+JP{?G3GR{tKMo#7JKiL#@i1zG^zUOF$>q__M3J_VnoA zd@ZA;d_=m{*?r#ivhsCX@QRD>8Gu%_h2mwvz-Mgc@{VtL%~9kv)^gjfraIvQMw02U zHBDqTixU*38iOXCnXj>w+j=Sbj4$k6xVmHWU0nTK`P566YWQc4X8v_Hf{$81uR$f3$XZP$wJhqtA}N~>%9 z5^ywa&1#||;T{pR#HO6eB6F8XQc6(ZN75I2qoVB=%JVnGzI`J$>h6fP{?=W&vtgPU z;LfQR9*o?<^tV4FH~mT*Grir0%rv;_{?l4!tqG&Upk(K(y`kNZ9h}Ib@Q1j{95AdQ z;(%;v*O#2zLKRg8czKS5jHO-b>;_p|?V8(Irp@Nfy)=@HlW_`@vwL2NvjapJG?0X! zGp=!qwR+W%yLC%#A^vEt%|{8;6cnDA=##93^4|lBNOOd@x?wWymF$ILk{nW{d8Tiy zAY-BMNJ)kG7YK?Xx@>ycJ;|JT+$50MUNfb3u?aq;yjW9lw@jDIx^E?VFQz@Q+XEf= zSp)wxF^i0lJ3DkZZOz(y(zA4$v4_`yXRUdeERcfk z<)=lRJGNR5snJQRJuc(jQIv{8<0^92ELEP!vkJZ&n^HQ1e#Q)xqK3(n0Qf<4bw z@GcY{$PMhXi{0J(XIWdDQD;i-TdOXo*eY5oL=&!4c7`(pfIK7k(@P@+Z?>f7x zZ2<@JN>E6pJLGYlFKDjNK(4s$T4NM;vnMSC2@sGgMdDqhgg~#3txoG2X{IQMh>KNz z&pr$1;_He6(1oR|?4|~EME!LP5ZnlXMeym<8^4plW<8oIir&4-Qx&-l8? zB#(dQiFae8x@1%A_~nbC8uNRk5OsYkir2d3+C+MCp#;*awh0$?ZbRsqh(`H)&&<8H zHU2l9U)RZ&tjEgqS5q=tyZK&V{Zelj{|(}@Q!(wdR%7z|cv!um>#Mh=&kT(s)|F%? zha6WhP`za3;g;t^bAnEoSkfvH1o}9l-xs^j&tSHb;Hb; zy!$9wckZ~+XkO``zikRv#Rj_Fetm?*Gz1 z`2XDw>u>WnCH`)fs^De7{Yd92Nk58V_IOR<0O1Rh!R0Rx51Y>2{%G_OhW{tV%m>(S zrP}6M#&XNoBnJm-4O*%MGaqn+*3>ZFBS~3sSizaN?gzIi)UU4{XfdvqI8y%*bdK?}@3p0E2Wi6M2P5&d}TxCZHp zC7NEx33Fp^lo}2|AY|QWWe4$py_@&YpVGp;G9TxWBMxVW>b?%xIbEm3+oNy4haOJA zeg}~!9!A=aVz+71HIPo@1oXGtKytpXtjVjwZ@((_0X;exU_lbGt5e+59{X+WxLaeu^A&^Ce*OT>(8U5esn$)4&8Kb&mn>7_@8jUdQWKnBJM=0 z(da>mR!2Q+-ptx%o9G_re=}*}orz@g=oe-xoA2J_@4oP?rV4JVAjvrGSRe5_ck0Q) zss>oRK{VoT&%oqfOn&fmV=QPEjkX?Wt+SuII#~95YCn8grOm{khgu>c-M-0a)BY=V z6jf8B-W;YLOqCVdB|9ie1g;voJD5%^&&NK&J?AH0VomO+YuM*@hg-_*^>${sn7q2V zZf_gRuP@$V?$)>`KK*O^{~j%Ea^P>HK>G@nCT@_K-qD@oIXgNj90{<*oAzF?B1}=- zsujDUTpJ~He8+^Lv>eD(H<;*&H+nT?W#}QCCA;!yuiAeZ)aZtPMU~zjljXzvFoT|! zSsOx5O8pYOD2H#-dcd4Au^8AjM^GA35LNl_*>bP%UY+uZO(R~L%^)HO z2MD)6vYO|i71vVgU$Q47Ccng-uNac8X1E6r$leuc;o!L*F<`68xMBY!ycDNA|GD4d zX|^c74|BsEE1n(IX6~=fwR&I5;?41DN--Yicbw@)ucOPX|G#(OwD7i4DC;R+6YWgq zX4=wkw%g~MQ3O z)$(RU2x2hTA8h#DSgeWJ=+38Lk+4i^$V8deoVZGq*wR811h13`<(6bihv&SmUt%vS zJ;Ab+t6CzAM?yiD2jdQPFlNR7di*W4?iD)e#K{wBm{XsOccCDW#W7v$lTENU0t+Sb zarLicWn7@-#~uEJGGvnZ?JDhO?WWb7DVQqJ0(m*Vc+J+Qr8%ez(%0l+zhveejaCI6~XT6 z#yt-l;XC_!If*YaGw`-&L%P(U?WG6BpQM`774OQmRQB(rVW#{{jcAVy=Eb`G6_XX6 zF62y?1}Ca1Tp}79Q{I=*hw;0BeXP=2uTuZaL+pM?Q(_Q(8P6p1(z$uj|}lHdJL=hGuIs+ zhu(tEYM8N0sT>hb`+mj}5L_Z#Z6RSgy6IDXS{T zrxtpIGw9rFP+aL6*B4k)p~CHp-@h-fX{ndYC9cImGkhB~crL%#FX6LhrBP^FmM zU!1eq+rKO3vzfT~Js9MTYRz2O;ZWmb`KG&p3E9pW9bOjQS3$bzVveVyUn$3At_jjO=po?7tIwyd61PJe~>E5o6o z6&KA@Pp58N%X$J!rJHeOCuGR7beU1+M`+@q1s*)iAluF#;`gccBnR#Nzo`G0U!*=f z8bkMOnZuymGv=o$=7M{&c28R6JV<;5kUbw#Wb}5PKzm_IeI3sEN9axFwW|VCl5sR@ zbDqv&LWTrH8XU>;5%e2H3R zr}lk`cmI!L#EARZHaKm*k0*KUEl@CjetGGppVr%1N%!B}8X#YVxxUUb`SK(|)g36DHLC3?;E0jV2oVSd)Jeg$I!V`;f$%3j28tAD_j2>Dm3H>t-XFnA{T* z%rlsrV0k1Bjr4sYP)G=4gMD8UO;2NUVgNcNF#2`>!DXHcM9hbW!_G zs=KrBL--WSs{2`X{x#2$B$7!8L$mK$y-wxL4s~Yc*><~+aKCkwr#C~oXK^vvvdFBw zS~2DIeIFD<#6jotGJDwFG6V9RGuGCPX1;W$UI(*NV*~0u4IrV1d7Y6>Z*e(mDqB`n zws;#uM!M=l(>L$4(GF1`NqKx<8J{F^bW&nCl*+L<_X~+HZ+<&@ubALhF9%`we1N@#(>6DH(MZcKrH&pYFiU)fx z4_BHFr0RH_(>HkZZu<`8Jwx~(rLZVH9*<|a-SOIwQ@;a7EXfr|^9%I;ye}H6*tPpR zr=?eyK^5Nk%BtV!cUEI&*k=Cf8U9F2iMZzfY@t`~+DF({Ah1=K;b53u)?67zq~*o! zXwYYeh$ zlRS={4Ttp`(eCgXq0nwF!#Xm_#BRD?Vl@;?tN+_5rYKr z&|T)-joZ_H-(P)87Y%U1qO`+OnxHvOhq_OMTxx~PdoBJY9G~0rjaT)Lkb9TI@Nka# zywu&v&qi;VuaAlOd-ity(EEQt66J8hNC}zd^pbgBO`@oIFGrU{@cge%KDZyL_5?1H z4D$$V8bp^5SGR|&Q1I;vBO5J~eqFTj^|82p0}LNAyKrNI`WP7c0ilVrY;{KSznTVU zk@jfaiC7Z`dN5?)aKVp%xHx{NxI2+UsqN~(Jp*e(b_71)G-B3|M|uwFx4YAXR)ys9 ztJ1ps6gPh_QsHv+zbFrJAWufhq1N9YLG6lsMMKsfBuV&uRerwjTFmvmKRbr|gSO+i z$7#MUC#EobQcy;avq@>CjN*&G!Mlz|#F#T*GQS^xT~a5Y_>ZMSx$ZuW?!T;khr8<9 zPcPM2>st6`Ic)o9=%)|0#@>FB{UrN4czt2sbzgh{tPib~k{acZ`Szd{T!Ej4^kSZ) ziuryl+bOeJFUPInrV7Tb*?v}UA)D!6NQP%?-=032ly5>*H%9A({f+D3-p1SH#4#7h z$z(vzZX55VJzNRpWii%d4rKW-+mWrW?r72c| zsVNF-C>XFw82L4-l`6GRtsn&}V*si!XoE=#q^dM*s~T4jtg^@~RB{A=)L*nXV)Y3f z{!ypv`rivh8maF22wAuXvK+l8r z`I(tx(1&Cou-_o3sPf*--i$w^d4&GI%Z?TLmu>ym+U1fR-J8?RW)r?kuO7So#04WB2J`d%q(~RTzl?LtaVq5wxEh&Y9zgX!7*9?;+L*oI3S5<>l-v_*cT zek|pdTN@tU`u%6(zi5Xb+ogDCTiLtt71r3P@HPy@kTZTThG&x*1#9-Fv8cluh%7*i zrG)w?9`?zxSossL!&)u(23hwK@$P_}VfTjSda%eV=o1&_eW2av-U;R<3-#}>%6qyv zCXryzBzV6d;WI|Y*Kf`HyPINcgTthyB;XrGX^jek_=Qp3V0cd$$_oB`%Ed}@nU$+0 zFsgId$D?N24BW#pcr$w^G)Qj2!I&cPyK<&EH@$vkd|tc_HqT>vDW}RTWg>lu;E_ zRAvVU)z1d|#EfzL466G1JOTHrL-=((_?(2}>-jj6ohQ)`ffSH`)r<71b?oF~KUw{Q z59$7|fNONgFLQg=iFlff+BS$>eulr&FmPayeexQiUS0){G?0t+OK(%#$wGZWl#sK^ z8re-xt)6<=ykTuErkmQIS+50E&Uze4n->0Tg2HwR9H@@!s;6Q-{7Y}>&b@zhEjw*E zKVSRE=$YBK1S6AW7gcswfd7y{i50N^bGoVy%ec&(hG=9fG5fV#?*L7j=Ea6T5OqIq zappoJg)SI%x{|}3ozIiwLVh`k#~w*RU2XWEhnhIQcdDvZJXrq!^6jnB<{9&Nr!-0H zad@+FJ|%s)F>?mZkdtAi*&MsidP!3Z!N)_#-{f+rpG-$kc7IAg55-k6I5#2?UKuF~ z2-Pw;sEBt7Kz^CcS#j6*?xL!*aAR8hL18(*Xl`BYF(7UMp00bD@|%a`V#vjXb{!Me z8!Y9D`G$~+LP8Lgr=q=1SMXMe`*}SGSe4O@9ZI|#jFNWSh&LUe?QcoD`#*=#!_~ud&3uNk8V##I1jU9Rix>`AN~0jKNT?X^fnYiVUx9QQ z4I!r#6!yYDNGILo7#rqxz4wq&@!j zU#Dw(T2SpyJHnHf_2#PKYA~uY?uI#Eb zAeCS`^|8SvJ=XZnJs{5R7=8^|G}t1I<-=OS;F}>O-NWzKJaGH!Ux1Xek7qdmQ~OKs z*3@ia6IES1dG^QQ%sOCM%9bjU#Ny&}1jLkK;b&f_5`UfU;`rm8huv^m`=x&CEfG^q zQqb7Qd@N`^QIpf@a@rec8)6n3x`)g65&)0#@be7yN<~X-@r?wFqclyXYqX+5A7ysE zs8VQilFIpKN+TAcu&*YNoAgX>NaVTW7gy2czqgr%-upa#dj`=G1W8D=L=*`~QbNd5 zAA%q<$ckE0Cf`rq^mB&UzgLR))-WiPnu+-LiNs9qJSadE_HsB#nQ=3YU!Q-j$6A&@ zzPsiA2b_}g^7qu7-DRAedVAbCrVxedamaRYIE1~B|J)^%Gd1{gZuMeXaFwv^Ng~;b%EJ4`!%-UF&{m8Qi z`Va|(GWXBAN6+y0Y~%j-^jeeuSIC88wr+X3cmCWyZ{&89;+rA-$?{DzN{Schzpl+~ zw_SU3@uQhFxO67Jd$r9sn=R^$`B{mrvy{h1=*gGrr7T7_jQv|mq1lu z_WIkG(fv0+qYNatT3^~;A7}C6yHUBOuY^-LGo&d&G*_(w(+Wz2kTk@qQQ{BuKd8L< zDK=g@e!bBRe>`ncI#Lz8W zjfgb7{X5nBE*sq7;QnQaAuow$uQlf5-nHJ7CoLl8C>O>`IuIqUa&mlM#T*-aFE$dv zqvJj_ICXpJ5+zM9TCUzN{EhLt5=f|ldnb!tY zw*KvW>1pVr&!_0a2A|pG{2Fu4>Fa9p&I!L2v+X|h7?+Qf<&wm7w1`PJDZCz4iDBw0 z=KFREyT1uFt@(2u66Ai@BBQ`;UVBX~q)xJg3Hd{P<&v9)(AgqQhOg!P|5pF#y36j! zW80yjK4Y{ZQl9CXsyeRjWt-=FK!mVT7^kv^8Tt11ozK~C9ubSB=)QamR3AOTq1DI` z%!ef84(;E&M1rWf9LIkfl&4splAW8?HaUnIh~>8kKAke)aBSKg&+`%_nMnGXL@OZV zZM;7<0twA=L9^_kl3(qS7q{HN@!>uI?Lm;ogEoT&tNf6`zQ)Kz2OPnGvs?Mw ziy4wXd4$DVpiP@6GR>*^KXV6B8BC^4kZOB|MC3?NRV6_X`jc(=e#D;y|2McY=f#aO zKKlN%jSazvm&u8Irg0tIL0Y`h4k-DakinmQ)3@wwWH?Y^VjQ6{6iAUnr)H$n3j=tlBc40)=kU)V&RhOPG57Zt-e!1;4B&F_n8$+q`J@b9jyf~#t-AMbr zhwjg6E?u$IS(NN78?lr5e0GM9#}H=fGmJ}V!@Vs^k0bCID0!s!Cds7cCxL_;?9&TO zMNZM47zSoM6J+d6PTu{K;=#q_;mtj9iE>ruVdLuVJjB!vv1bXtvHfLvHC3&p>;*b{ z2vNypsbqcGjUkQ3yx$>Jy(w40H^qz!PWKe4<)p!X(BkcBOK&R@nI zyIuz*>hU{^WxNNZ^>08FP|{bC&A)1H^`01@d+;P7DfSXo=+FctD?ZG4lW$4DdQCpq zC@7xf>sbTb2ViT~^&ay2GiTH3+~@BfQARxn6?NBBKvjpR-8;BM-4327 znX;NJn;lJnWbNXK{}nF1v+9y@&^O-5U`TcjvK>vnW9;BIQT_@-q9a(-c?^_E>=n-w zI(u!T=uP{Mb{6>`#lC5vrobd7KBUJ3liRuT+&dnZtULoYhKityEJgwy!DoT&IC^^g zxcuKXNy*mPxK&&&k{xQ_&;Aeab70E`sL8V6?3D~pz(RoDjY7;=*5acLzJX~m7 z8Q9un(V~$h!+%(5sv+$R%N_zN&z;rG+q^g)!0C5)k1{*}b|F|H=mW^zUoag$DRuO5 zf_b~e5kEagS;jSpu{}qO(c4)?&bs#9Q$=9unq?KNvn=x*VY`6VEHZc-mcF{QH(k4` zlz?Q}64>F7gqgkL88;ST8%|bwc`*}nc!8tg9p=%z`+C_F6BRL&$QuU`%kAEb8C8tfI|n)M22MP9a1L5M zrM=ojMlezEEfh*3A|fqvFCyV(MuT>-36Mk}6#YX^nu!mNKpmW2b1GY?s z7pX<|mKMU1h**j}&AB%`on5MA3+@=0d#ABae{Kg}$B|mSXEg(qPN0a-2RnLAk$c}* zI4=-898*z2&I`p@xz%md+@n{#=0@iC6LP6$LS~yJwjGh5#;1uoz~nsLk8FM*;MS;0AYuOn3nBl@%sW&!0RO)G8VJX}tMm%3t=Y>TxTgWc$&r=&L!dc)kt&Ato{rgPfL zUUU^Mgc=b7)EwAL#suwdWb7o(xXqt5l3Y#=8?PKU4>$Ix=h?23!Nt37#^MvY5zVm9 z0FMO0Q34owi_x!W_aX+!plK!;o`9(-2_l0fF(HIbK9)O8{kJG0kz#QfWA!r647QaAF}L`G<{}4^`6R)V6Emu*TK4#HK3$OcJ>DJJ2t=Ftshn26nC zi;(--B7XXxu5mS?LcgOB;u=mkH`1C6Kg^+72LlK0e|{pUni85&+mXc1x3l7T z{^EmI!b<84-teV0ejI4H6h7kxEq*s!&lBLc)oExA}{4@1;JE505zs z4Qw25qMjRfM3R0lr1cz+f`*arB>zD{6fj9a5Hb{yed1dO!_>&b>y{;T-$fK9QtZC< z<_f2*Lt#$D4e}%jY&y3;G9EHz_Q)H1MEtYN`Qn-PS+>|5Wa6=aTnu??S_n~?@S21a zng#?IKsngJT+}u&#PtqfSv1HjqEEPShM2(7%$yR2r7$Q^>l08Qeko{*dOEl&e^|o4 z{kyr9_ndVN++HQNRbv1kfmA^t47<$ zZ?Gs}AR_lDzn3264Wf~t5Ax9TsL9%Z-Y)Ye|IEorKF0?TKP2I_8FMrS*zPc7ARC1LIid-p%R7@<3 zRi{IC7zYOo&lVeu#EC!ah1>x^6!|AZgt8uHDWu=@=?!hj$QYhuK|`Aj9$#@MQX8Un z9{zt&av!u`lh4z$zgJ40r(_d!(vMh3?sX6y)9@+ISfQvXGBr_ph1yj8IQnDtce?p! zj^WLK{a$mWC<25~q)Me|SY$$A5+;yoW=2_t0j3}*1{t5BHatF`A@cin6KH&H4tp)C zHEj*jX-wa~oDo-FyF@P@%(DN<7VROLV5rxdqN*8GX7Zp{`e2ZRs=vm(?WN5KXOqNK zbC=Nq%EXeWvfER{EJ;-tnsxEaxc&bF;(Hu-d~KzSEESzel%qA7Xta?bm3gM5i6MW? z?!s>&gW}Hu^Q5O(3Hb=9r6L+ppo#)gND4%Io?Qm(=az))mGRal|3du>6G%i=15Sfw z!Y-2+5q`a^Hu}bXVv4N;-N)j0>4WG!|Q)dw3uZrnBoRReV74~ zPMJwBKWW6oj_;VkBuO+85=}%9Lct7-#P^=EIy_JwH3LWt3J-_4^rzN$Y$n-@h6d;c zzfs80FQovJzpWnH`?&^#?sswttcN$Xtq{Cn)_5YaySo}aX02lvFWwGjVlIn0u%wv4 zcS9^8VS|jSg}HMk2C^Cv*}Drx5oOy(i~(q9$}Ced7cs_a)?=BV8EGbn%0h(+vZuS$ zY;FOx;%;#;)lh0@5FZs6+7dLWG)WLNGb*7-qY$(UO2SAWZ~&f<6TgW&-cyy3I%*1& zr0KC#pe2zlr4U*OR-#?7$gIi8C!FgtN=yoS>GuZ-SW=|KF_@%ax`Ey>Wcu*V-{OAh*)iiEl@G3O{yhi^y{bw05#B*Ot^lGdQc6gaf$R>6a04;w z3yhoew~~8ZHrvbzGhV?4IPg#D5$cxeFD`Rb9LwQkwNR?CG1F9Uc15Rhc%EbYP=i3idCOD^F(NF5ixB5R9awOd_4UtL zj?J_9{@+2vZTO&gLY^`-qe?)>m|l(gO)LB&@PDY?_W>N9V4hx4Q{7SAe+Q`HX5AIoDN>lU-DBD^=#7F?Wm?cCoBtnTe5Vp`JkE|qYR+%F<7O~|{SsBWT zE|nRvh3DrGZL>*t?qQ(b>?GWmWcf#k3d6&Jodt!BhkYMz-6T#o;P^2ae(6oN@SONn zp+|?KyL4pi>N6?oZcjIp1B{{4l!2??^SvF)DQ;$HFkY63;#Owby6@%esD2(m z^GBCEt(}xf?%KC3+gJy)e1{uQ=<BneC)DvC-eNJ$`-T@rz=CS00)ew8P1;oPU3RM-MS z4np;CrFHP`f-dqPQaUH`aj+fC*I6KLNt;y6dXr=~T3~V_bde@YkpzaIEYmqg0x(nn zw#bMWGXa4ifPqw$n$2kx#2mm)RH9;ss1Q>JLl(xytZ*GutXCvT2gw82EABhz55tLS zuC0wW2yKmWAyXLw$a;2LZ?Ucxtv?ot++l zeLhNHy+H}!c_I&+La511AnB4qtWel&ni5{8EB;H%}oZ5 zFC&z8a%?d(d39l#iWjA-$s__45o(f}7S3jqw8-9xP}(!r6I7_I3i$;PJk?Yk2?LCr zlU`x{_$Jq3+ZlhegtOWHUpEf7TJ>)rlgg?{OMO)|emO){ z5t1(gI$fLq1#e2L>>J6ixw2s&N6NzohVgAmc#R~T?;7p4?a|MHw&3rAsz~hXy=rjXQXLM*ZF)`kA&@wvX?)PIs>4Vv9&lNIOI zW3QH}2`tX@)SZNcjJ|EAn2^dKr7(b`f|!Uz5Jm{anNotvTTx<#sM0i1YZoRZC`?+Y z$}k!wj3oq^V-7YLK+NRK?X%+W!Ofhw~Y3>08PG?Oqyn6AWz zA*D1pZUpKBX>u|baS5qtNeXBtCa4-IS|TZ7D2S362&NGcM4uQ#&)3@bK2*#)ZJl+f zm7Ptl731aD4~d)Pgd=Hg(C2TNB@LAo9TvNXoOMyu()vq8?I#x&0q`QUu^N0n)x}Ba zIPR!Tb*AbH)l=HYjlhS=F(pC7pKh!^R&TsyZQ1*!(rH6{a$&O_2<0-kWl(@7d43bH z?(n|Z+pk=nh~v*2FymxuOhO34Yh#?7Gjrx)ivY)lWI-t#!~~Z{I}jCM}YGgWjY9Wr+i*2i0LoI*o~mSBY)`9i~l4p>7#ki-eIupX16WYmXKsXmB2oYa&ylZrNI#8M6_`HR6v2>Jqni zObaWayK1QZbbHsS%|bBB>+)giFJAO>>qYbBycn&LI_y-2!8|CGq}`PT655_cX-=H^ z=BKx8!N*C(vTB-IbfM?lNfNs%d$Q`ZX={q`k-*z5>sQd7+i6`jnq4GM5_O!ZRPqUk z=s_SLb`RFm5fYNX!kZOUQJ4lpp(bQT8ccD;;GR5ogrYYJb~X(pNbyJ*b|eJ>x)#%3 zueCaevV1gPHyI5KCT84-I`o0L z;6NB1z@2cWe|eAJ!_bMTQ{JgeDe1iG-AZOqQ@kT@sO?#b*IbK)?!n`sQ32Fc{%ZXz#vV?JEOMuWn2- zNI;TAtQ15A4Fv@h6tNUd6hTxp6ja1bRRcvy9Ojj3I2aiKQ&o|XNU;`T5}>OTM2l%u z6j4f&6~w|rQJ{jDs3@kYq6XBsRWLyeIRSZNq6oDCNkNoj12BytPzRK;%6)4(ftcb-zUJ0Gf8lCs8ONcK^M)g zgjk>}IOwGriQygH5Hd)UX&@Shb2p3)2}I}eMy-@iG{oOn%}_Uq>pz#TJFriLf%7N5 zgzn5R453972`fNyWs$TB3=tM)P$A0|1Xw3{>7Hre38q3A3|++zFxDEaBsr`08g?pRFXU+!o_EwT>_- zv1qJ^v3({x2KnkP^SAwvf+^S@@&!4(W4#PK{*}?W;pTD7yfNRgmk)WXg6Ql*T~cQ5 zAZ{(TpOp_8mQhb^vuz&?0KiGW+Z#lLQ!p0&fKzZp0BE{0ka+M9odYU3(j1Y2=(6e zbdk3cWV*4kWr3ov9o-nA$03ZSO@djosGUb}|w~RVXaI-Z# zTr1m4YlT%7u}OEkK@~mHl-+6MA4vwPqH3Tcbxif=j4W#xjh0ICI^&*+*4AG9n!EO4 zSRMGGlW^ZqIv#eSizJAy2zYul-;7ow7m2*_>uLoh4_qOK|sq1ze)XkX=5T&&!#GnMFgTpV83<-??;oK5-( z)){uLirrUC(doY(Z19x5nZ4L=mX-?5D(26G@>(lSCRY|BFI(NwYLwcOYbQ^n=DjtS z*!tb`VJRUTa=9RQt?vs`hrRC>aA|8$La$DOI>V*H7ox2dIODvf#l^#z$GNGbx36RF z^Sjo~+UB~1ORnL;9}x4&X_hlo3_?cv3pT6Dt6X&YEt^^ydgs%cH%jsex;=R2Y}2Z> zt_GuuxJkEsUD_h;8##Jx-fo!~l>_M2rB;#AhRdsHeI}KwXMx;DQ!P<#qpo$BJkYY! zYZmJn)pR`5sEwA&z-E6vS+k(*Wk)ZaqIu9A8Nz2Sn2>~BD^@gSd$>*|LO~ndBTK$C zHF0LGXtmb$SBIcp5HTA(ac7`rZ9Y+^KLa-5$wJT~8%@syo$1`o$-F2-cE)j<>w&&N zC3GPM0w%`(GpRJ1;7+{5g+%bw$=NRr52O(Yqg={x7=UG-VRqelW7v4A%CAeT5Th9` z?}TM!!c#huR?j;)r9mrg#!58Q(Sf?U#0rvl&hCXu=!T)Ol&igT3gdk4@*SPkoKMP8 zio|AyhHNGQxUv$O-)pHm!fG@NqFHAOc+Q7V!W*$YPNRaV$z^s?~?1jVD-P3ZZJ2H;y_`Y;%*snn?2}5Xu`xARO<;0vhw0C zmx)*shN#aSN+P;=YCz{Ht~S9~a|E$N+;A5VTWNRKT3uSSmdl_*x1IEW6o{f@pXcX(EaUs3>9wbJ#%H=5dF9_;>gBcgB|xH*M+h z-8bU2UeZT7V2!aHI#t48aw1IH8Dde9B|MbZ9fz4b`>gus7R2++o^;NKjiS6GuSKeK zfkQDV3|5Zy={si}&K~uw)Xc1^Lyu{Ae7B=ia@Qs4AAPc~(GCl}Pb@wPDb3mKNY@_Dk~KPQ6rNz4)dIOtczCdB{1x0)akJ8QBZ3wH6g!R9pE_V>`Al^z)XU6 zg_$x2pmBQ?avjkOSjYy;Z}Z%c7#Sdg352WpH4sn`VnCQ;3LKz-Kd^-`?v;6xhwvv@ z25%6ecA#K?g?kcNK-dm1;*gOtU?-R`9SG=7u|c_y_Iu-_2L_byLqvsC*-B;#3=t7= z0?8S~h8v*}1lG(I62wjc$rOC%`Z)Iaf%;9JhG1*+YzXO>cRYe1#2bN(mdh zj1n;;TySoVw;IyG?82E8EX*+!MB1lnb+y*97I&Z~JRrF*I_ovb)2JQByyJNF zr8!y6@*~8!YJrr@p#@z+h(=>UfD>*MW*h_vOf=gzuzAvin5gUzS0rAsJkN;r5Bd26 z#2zs~fDFQ_!w;0q!79)~j3U4hB9Tjn#1z}49gx^WIWQOygh5H*cLom9?b!zK20*xA z&LM;^iaT{LpdVkfi>x#9&uPs_gNTTPhur!1v_@}aK70~7M7fGNMN-PeV}@s)b&CMV zw6gh{VU|6;%;gAp0pBN&%Scc~LJ~}c z+JJvt1u#(r)K4CVXYU;Y)SMoDhd(_GvYXpwI$Hw~QH*lR3{?TQ>D9|J`$_c$8a@i4)9A@c?tQx|hP{dIa0|b&q1R<$h zT^0qUSzKUMNL(p`3ZXS+4L1^kh=w#6qLV@K@2u9$SR)ZqDTre$&d)(;)gc+6K;7Jh z7D+u-{$zBc5lU}&F0(D?*Nsgawv8r1<~7^=lQpT+uYgXSG;pzU)m2o`R!z3Jn#l@k zs5EO(wQUJ7S8f4ltVK0NX@+T3pR=ncC08-V>)5iV#_61bJ|KT;%K8xbdIK6#By2Dq zg9OAhr_!1OK7fK#^FYM0Dri2vscC{pWvMEHP&7Ls7|BT$1Nx8&4ghgOKpNuDh551q zl`W+k_wEX5vNqbPOl^@K75tM#36qg+);X6NVZ{Oo15x zRb%GBKT@#G$@Rf7BrpM7N{Vd$*K@qhA`}$lBuB~ zaE2{pF}tR1sgbS(GkvO#CaBXXR+u1E4lKE%+r3H!p&Atgt4u`#0_dx%w?t4Gc{H=#dYi1E0e~+9G-kPr$3-KDD+mHMRz9--aJn+MhP&!Y_oAp!(9teS_>W zX_YQpXliKD8E06Y!Ibt8Ll8~SL;%sM3Prnm@ZQU zE>K+DdN@utVu7U2IX7f2g(Xz%x#4R9=|nM&ai!Mzy0ctITUQHv;Oe&(Z*k+&#?CZ^ zDC?qi)4w6l93z-C=~2}}`=!yXEhOu{_=T{?LLSv2BrhrS0pK|<^+?`o%-}X1D=r%$ z!QS<8%>ijD$tw3bhL03;!LqdYUJT;fb=@lF8U)G7&TiG~GlQdB;i|}ztz?L}Ly8fI z>D6a9doPTQn4LJ6T|5%DW}fVB=yl4*Gf1%sb<{R(TDOLULOcIJs1lBbamPkpT3u*O znsbWSYPu7LMNLH)Y@|bb$iWspT-}q9DLw;cUiK z`QLGdTMu$Tu@YvAgsGB~c*2;Z+^M0)Q$lIThLsk<%o1r!Mg}tGA&AtFKt$9;kq_%Q z2FwW2Rf&bM7LdYds{kl~B1D4{EfkD3QZ+!4Gcy4Yu>g?-$Pkp0qXiWtwNoS|)DP34 zeQF-1P0jnkfx~uUB=z{5`%s%__@y{hCg`K~ww8qNfz%ac zYfjBmdO@oHWfg%s*G{($0v%N|!09kJ=gs#5wf=vx6l3{x&m*!$HjRadP(?ho=czOd zs70ZTw_rU*e2cC**8@gViMYUfPkw2&yxJ`2vk;<^Dh!RqgvrNMVro&vw#o|=1DaiP zMVNmDMva(jlVQM>2e@oAil@Q-Apf=(PfrN7cYRMxyekLKZ}3=j;0C-}BZ2 z%u2xhd-D1HIx=Kfq=%Mya8QobB1DP8P~gaFGDiz6fR$M&0HFpzfdrtWLXjA=1;q*q zcIVH1jp>g#F9@u^>i5QbLH&Tjk*DPe?}{`uPK_O=%hJThAC7P+J<`TVWPvLl1GfF zykQe)GkgkDR;5>o0x75j^gyoAfbRfpD)h>(NUqQkDM(U95P+osq4AVy6g^(p!~i++ z#ZCmPKmrPCpJzJw-$T6hiQ@p0Z#j_SenY7g-a_Tt z_L2L+8!!4v5X0E8pg%9ezh#dv2FsG-E-~ZC2A|9CUI>ma^~#tYZoudc_h|I5gZ_?a zu8kkkAem)2se|8MBb7j%F<_$y&c=B$}?-4P_W(BYipfn>X_`E zbw#OWyQ5^mEITJ+HgbAnDq2P#T+HFMZ99|LYnLE>4C)!x7_>^xvX&Vp|BT<*oA1*n z?Q6j%Y|@AC(w!JySZ2p(Ju1VdGdR~n9ryHRleZoHVbe&ikr^LV3{_4m6^#03?Uv<4 z30BPmrgx%*A+%)2CJ*G(IgiBLf~IL&p(q+;ii#>Ak_aduiG(Skf*6W|sw%0fq==#> zqKc>~5)x(xyG4p76OOHth3-6=g0#3=jyI8IbG7Le)rVSe`O#KXUN><%Wxw30F%(L-n9h#scF5Bvl<=SoOpl=*z z$Yf--p}2|{%`piID-up+#>-OZ(yNzL!2}gk9gBs7mN@83`F1mD+IH&P3}pSN%st3@ z9tRC?eJ)CrufQNU@bX=ZcN3?tIS$M6A>>$_xt+RT-DnmmNcRer2lc8BVM1OIDaEGZ zu01p?nGnns&O@+ttUcT@m`ViTL6w-iY+HGDIOD`Zt4rQ>{NsVim0WT%DmYlJ@MyC! z+T`Ez=#xV!kl2)pmVl?oJ%|LtW9be+Lt%`_)Bgo5N%Ba$#?6Kz$cTaf8 z-48L(a;U81R$0BPgO)(rDgHOvfx0k1W^cw&NPcu|yP(n&@%Be_heoAf*iCv_VYY;u zzKIVR==NcZ;5d$Gr4-3Lvh2F05n3cZQ@+81#|syMn2yrqA-Pz^lwu%EbdW&+VyZNT ztrelP+o;x3I3=LQbyZ~%VEV4kP+!k2fCmT@` zYc|oMW1B-7NPEDwfvOXsEVfvJ0w~*f$FxP*o&*jM5)AIZV8G+F3}#!PX*Q~tK;X)n zNl?+~Iu4Gm|3ANQ->FV)zR04(+B-K@3=7FNog$pGF97j_EU_^{$(ps>iVQ>r#nJ`Bq8EKIt zaA_JCOOz$HQmWusN}@(0Gfrf7xCm_^U9eC#fsmHM)lCo>AbbZFV&@zIRx%9gOA=wG zK3g6lOqhKw1YZXaMb;bKhBDTp+dckm`kkoG84xF|6c6_prJ!0Mi_PcZ$KjMY=LRJ? zJ{fMk7#; zZHd*ohp=9KM_$vl3u}o7ISQ!*7h&mqc3)#@}w_~OUfM0~+e@uNu@VgP|Q?jC2 zk!3RwaNvFp?0=?>)b0CBJM z4+o=UH%#3O5eRo+4S;Wn1!hFU7Rx65-x0nF4A%cXe2pO73zy(2?j5RGouEW*3 zA-XG>Zqi0ET~CL;*4;m0jej2+yEsa}#2_Ek2eu-R`;XWulAp;Wl2VeuZQwi&2FOAt zz$>iS(Ha#rsQn*Mm`MF7Vj%xQzdz^t(Jret#46vGlVWlbwQbHAE#|&gprCdf@ zFmWH`80P`5J9h>c5%k6^WLu%d2_y(pwLZc-flu(_frlYO+J_Igl0$O?5y0{)i2{7s zsbf$UECE3K$tSPa@VDywzfQhU+SBn|l*ga6;bmGCZmiYZ7vl$3^g6=L-KTVxD=!jP zmxfcQhEOf)pF7sJ2?EimOtM*W#oD^gS&orSWt2^mOmqTbKdM-Xz9z3AhnB^5EvIym ztgy$G7E)J#oV-Rm$knA*TpUDdCl^7*%+{i{a?|4UjR{yLI(o}ABqCysAtYlKoT#yy zF5v95T|@REdt25mSaH*oI1%9knn`wx$V8%1nrb5HXZUiETEz%9OFeGd42J zR9v@ID5^FO2;C7d3dEyfWIJn(W| zs}?OGHajlv%$QnN7?kBWCesU4f$9*x8Jlm!&Go^%!O~Kn8&lUOX%9RBouu@W(W1zE zs|q%gBM}DJgAs-hta33R(6ZSjCXz!(1ij%opas|k0fF@O`p1*~1^uUjn<9QBiv*&i0q#TXgknhuh6aR~5@14+S(Okd0D(w$U-M8!5Y1>PhzcZ# zVkG(E>0pW*FvMb{pr|FBTN5yFCW)#UqG%#Q8j7#*4Yzk`7+LZ#);145{u1eHf<-&l8;+la-LnbaYy@ysj#xf=S)@9yq)d)Ng<)*wO-O0bn{*U(BMhADbg#LmW zBsn1R2WEnX0Q@_N^@}R)?>ac^pFWD)Uy1amHWSiEqGB0?3H@xF5)n|+C#~q7W%)Fj z5m}hP%@KxWGK;1A|0H|;xN`V!v$my5r&iyPD`q9(Y_xtUc1haC-@4~T(fq-k6L?l1 zmvapS(F9>Ta99F>DJDVaHM`tLbNo^X5d;8N&bsSu`M zDNv#z8i}E*2!xUNlt7_k5MofI7HSb`Rw$tf8bM-ELV$hW ztmBA(QHc^4upAxM1q0Ok1pVn|5Tu!cN~(yeiixHwii(C|DoH4bf(U{NVvweq5Qw57 zBhi=@G$9fMRYH(SK@mtL0F@grua2C?%F6gn%eW zsc0pFkSHr9TtKM-#EMrW8dQ~rA{GpWerI}OAoO>V2XahDez@QU5rZJJ*uc@NzSU%C zHXOIiN@0{d1XrcNLjywN_M!)w5Is*9kbM#w0dlOAFsCXEWICTbRKfOr0l<=-dMEqs!Cn z19$?7g#d|Fjqp71$WXQvYCx=q5ZA^}6#S>Mkn%&^;yc0z&wMor`8{SLef1;~lnsA<;K(^;a#Xq67DDuz-iY1F7NK?f*OxDlc4jDkg) zX;_iOB@|^?J^N>4PT?cSAi|jh^9K?RQ*65;aR_mUV0Z^g7zxmSJ@Y-xA>1!60%QY? zxxdlN=)gxh?QmMUS$LvQor!_(x%4F`j0rbGzPLT~OBR)r48|@nZ7Ttk%$Tw&0!1)m z`OoJVa(fOpq!b{DSpw+bo>11ule{Yk?}E>l!wk4w4uleY5Kdg>&yXtzSa8&$gITn( zMI(z7lT9`eAPg`D?G40kBGoY7Lj^&Bw_Q`nCG3t2v>>r)D2&Xx3NVu&S~&<5M&$%A zW!gExaILJ()H1y>RJD%@MmFB{zLgu`X>(M#B6oJZ`X5CVJKu@|&KW8uk!njyrrBhq zj<3nG8{0wffuW?Dq6!F;b65_|1;Dj#MzL~Wf@zox#Gspq{B^UTO!CQft`kxyU~b$k zR@91(Y9npqA>G02U@H=x>cL)Y?9VOi4VWpr(TIkP?AF#7ViAbNL2{6ba+ImIp>y@( zlu#D8R52@zaRN2obI*udDZohS+ZSjAR!r?kY-t4v$uCh|mF%!xyXF9_V;pRp5jYu( z=X-n0;BfB@@U%pf;~qrt2uuR!Z*L}C0zyd+froK0p&Gd??VL>Tb)!bSx7?DX1pRGkaBSh4VlIv52!=tf#ne=H?DPl$@h;;vt}eMwh&ZpH3=x1ZOwyXp5Ney9)+)8+^{pBfREwyMHIu?(dh+ z{Di|$&_Y8H;D@i+Q|}kB`*f@CJ9YDAQDFlh4Oh^TpfPjF75|s#%h)_;P@osUA!*ElD5^;>TmdhKb zA8>7e&9u11DXGbcbv2T8*yCZALqJm<GSF7_5|GmQ+O89 zzw7%*79vuk1Q0>{zrN=6vgt5wb57M$UeAt)^sycD;iFm%)KP_$h^b>l8)`}Jr6DQ^ zl0-x=1rC$Me!qbje?7Q}f}hw4@jnjq@b~jJ_F#G@Gi$l?2;gbf&v=uvnZwlmJ5y-jz=5q=y`!C04T`#iDNed_TTxHWfp z`=(KuT0bpsDGRmUJz(2@AB!YPtfaAawI!uQUdYcm=I)o}b8-e{Yl^ZT2RQ3W>zt9i zo6x#gi?<1#c3HkMvcGB+To_@#12)YaHX52^^VOa_fj$f8A8f%r6T&qJeQ|+C#gNia zFi9CM5NL%QLO>sw%l@$gqihYV2}k689E-5`Xb)ohQ5*SLkO>J49-R49EDm{?VSx6_ z*doOT`1`}hL?=(*zVlEf3KEQg1G*J7OClN$(9)U~UOaG7Hxs!PB}I3A!}LSh#Qp$-z=h~GJ;ycT{h&ex z1tM2i{aEL-j}F=1)9IR|O*yJbJXZ>{8MOIt$7f8-i&?rcn}XW&Zc0`O&VF7ELtx!$Yf(QY{G4VG?mWd67`}_T`r_=A**0XFA*&1-gVi)b$ zzT)3=L49w5o#8*ma%yAH-P@ z;mlsCD5M~mf{G{zU{kN20j5fZA_$5If`X9>27nqylm>*LTdac+kbt6C86hbeZLu7Y zq-CXs7(g!6eW!qEKF79!+t-=$^I*nF;~F$YfK?I&l9XiZK=y1N$=b!IWH9XL@sMZd z2hfrcrXV_7D@h`Fmje+r!VsB#Vr~@K=(;oaJ_>%2l$L;qlwvy09-#B8$1t!-7=Hh- zVaYpnG^1dmIBv}hnKhFz=t`{(pTqc8W6ay6imRoUbr>SVg+k^XK7F(Ychjecxuuh#-KlwX$6{5SdDhil7LqIiwC5fQ>OSZy5A&%|z~CE-5qxCQcP2 zRHV}zjA2V!%%g@YlJH@vmqS5VZK^2*iIIpcA;HxQ6I)g@^TgSMPQ*(jL{L=|Q9&4G zg5p3BK`n%|VPqN2#=$5uiV&(;sF|dLoMLPi5;UMg5m3xQ0K^MR0W~nv6b({TQzI-C z6ePiFa@q7l#kpIM6n)=j8~ zcL9$$y*95}yCk6;j9|BwM4=NP6qv~uE;Uq$Hq;ehAUG(3!Dhvkh81A4mH|aG6}ZWo zrYb55#6@F_X<}IpH_grSgN?WY5*wz00_H;vRgG4Yf-=ZaKxqtM%4(RvB{&<=J2{!TJmdBD)C98 zBE(R{g0&z9XPeQyAaKNnEl0MufM)dAnRcxe0h2Baj3+_u(;3wJ--kS1up*jk49^ph zFI5~3`^-h;!aeN7CJ>fc}1cBHRdRg0$;}D-cj0DkPKww!oC6dh?v@-x?L_{Sb zbV%%y7-_;ZP6_e;-W#HH^$ zt+#Ci-1_Dj_JbydA@yrNhx2}h(`7g0!w;KzN78a6wJ-c4x{Jb2BbTVcngbDxb!9CN zHuTd3WkjEXs!<4299vJ zjY1UL#HmwCtZE~K4*nwkna6%Ok|^3;&Au~qYSXc_o_R57gk5vHufA|TAt^g^@6Pjc zCrxfm&IJ9A2skTnabe)(K?6}|At2a?BWNc(hH|&*r`_gVsqHs3!?GrhGt3{ghp!+ z!eRs>1c@~vLNqIqVuAJ!?xC_s8t0$nH;KF(vEk|V^7W@iK;R2;0`yG=X&zZfCMf1TgVElv(fBMb4T z1rpAq#HC~Dl0p2EhjN~FMuLP21R?>zFFc@;WR#f*U`a}WLWW4tp_1WJ5=97s3;>w| zNU{zB8GY}T%Bea9&qBVT{;$~j-VC6eSXJS`;wT4Khkk_(Lr8}E(Jase&PNt!c6G>) zXLz21<^pOo=OUn0s%jk5pptwO`lcmUVNgF=-Na8=Ul;m3!+H%r6MAg_is>{nIf!HA z?#;~wiGYxGu$Whn-q@An#6pE!Dy^Ct6&j=lQpD4}lKVcZ_GO0Zpsi*7Jm_fSVv9Lz zvTTw+#)AKDPI{c(eb(_9{8qJob$ymz8>!7#T%V%etZH1d9jWI73d8z%GAt1m5V^8s zh#l1Lx?ki*BAiniHBm2FIB2`gS6thkr!bx1WcAbF5c@=gq}bk~BPl@Wb2=Lxq>BFZ z532j6nIM*cp`kr84{?`-(L$LKdeOrn@6bH`KNb6w{DI+8-*nK-3nv;) zFwDm=4yH4Quo=0gma+KZS2l$D{7zctmOz}6ewK8@>%xAIvXgC~2ks+L4uwZ%Z{!PZ z&ASbL4R8sQ2M@3@zzH`X#zHWJ{qSHX`{K*~ulf@P2&csHuY7p6urMPB2m?Wwhu`;_ zKLcRqb5;Uq9(}1FGFnvB<~-v?NhY~dwY`*BM@+5m~k){6grhZi@{Mo?zm6m>+`|- zUr(6P_(=fyFo2{B@@LIG?Lfp_eMP+fm(_Y#SjcUqV7z7}{l;dl?7OtT=g`YMPXXuH&p!cLGJ?r$+6A^ryx_T17NScDQ8W8O7EK zvs5Gl4eF=&c&n+mE?@(3X>dW*-fH6KefJM?mj=g!Loq!6tr^+v(SjcNl14S%eySwN1gbm z%Ag`z7=WZ=0i)6EC_Yv!&~YKi%j7sFCK#9N+eFl6g2_1g4Z{;_31|UobB#8+~fjfor zeBmdOBJTPT5&I+s`UI9?3_*YoBsoCDvZiJklQVD_I~_;lb>-pLq#a7kw2KHsqC=dz zEDJKTjjo+CMUYrQ1W2_HlV$*{YgUy2t&EGsAzAsEMFnA;E*`lLxA&Czgc?e5ocLty z5SPA_=^#8AKTolK=s-U_q5;+pn*ww(t4N=aJuW}E6S(f|W>k`22s?NOOrP|>j4qCl zkD>U7yhrT$B7C01wmWR~zajp{2&hPss8OI)qLE1=0!3(v1^q{rLV5x7x6b7veJ~mx zZ&3Acy(Z4Jb@I{h&uV?OD?>p3ABP^URu+GIXy`u;Y|dvoIUBbfVKMp>!`t*P!dOZS z3Q`e=i0VKy&+{Umi0!Y^Ha1lk)@1`;$01~xMRhB{i^C?3AJ!R>uh&NEgybU}mGgIf z@L9Sor0`S_gDF;8F&L`BG#&M)0GecXHB?J%-(v!73kfjRhp)vORqs|uP($M`?6ptL zu(Ia^cZ-!ou_S&-+uifPtrw|-SWvN?#_IdlvbFq{QxJKC{2ij{$XvT{HtTm8)ibua znIIPv^7!JiqP83+hoY;U=#TB6Erxl%OJ{VjUPL&3ei9`kC>3y5K&sc(V9w2gq=362 zt!J?fj+7?mNFZ%AL@=Ri6cWLQJ%#}2-1-}d`!jh#EP;(6po9GWWe7>;{vS7)FY{4Z zV$z7JdNi!E{#Jalj<#9>0w`?Q#@bke#jN~@79DXIKjAR_?x!2JLa^mi1f$M&^r`ue z8}^jjWv%kcBBKD?S#egw*dd=t=ZJ7JE4iw;(X_H%T07c|)7T9$Of~DuaF*uAmr9we z$d*l6X@SfsCc`$#Lou*bu{bJKY(+dhKU~c6CL|!xF&A655GUvfOizYqTdBs-<$4EG zhF;Bsf#6*vN+D3%DovWseyzU)Oc7S4TGS459}^*^^WDD^vvsbA1S*^|Qc$@^!E)U- zf$C`X)nR6c(}k$&I@6_i9mqaFd=NjJiU*&#=dZ;2VwL)($v=`!FzQyDSf()Hn1ujB zKvEijas@HKaSy!dezr)4LKo^&fN%C9JOBXfkr*VRijjMe{&~S&os}fyJOmAcw@yv! z8NRQjybfnlr9p$NY{>93bhw=v2BQZwc<%J|23nij?ddpe(s8d9L!>=O&uaM+=~0C1 zl?fn1W%G&I%hS$)ssO4MAzzs8ARF)5_xZa)HtpNmbtr?^0ZOAyM2ACxfsO*;oIJn< zdV0>@_%%PdUaCxNGoM#3UwH|~@fp8pm|+MKN&pCvsDv6}pGh@ILnA7%`pNK6Irc$E zUs`p$Yi+ zvXv~Y{4wSm72>@*yFTK^ueAdZkbxjaN8@j@TqPZ^;g7~vhcEEq9rM#~f$5F+*LtlQ z(}0N~DoFxHHsF^?eXZj-=kjX*MQ|g@)#L~1=??7j-}jO{jW11Cqz=UkJF7XvYZj=O z%iP0qe%`Co^zesjr69Vie1z%YY*6bu$9MHCVRkYHgp+FB%% z3978sQy=6u3{5IYiH0J?5TuZ@PSZNOLL1GB!GvQH$^}phL?R@Ru&N9z5I0PbFqN$= z3ef>^BqGRW2+@I>6)Z`RX@DTfnjxXg0{~eG2!%{kM2ZRmz(m|BKB-VhCpcDe&avPFXKP505ub^@erg=84fN)`ghqL5G`z(feU+}nC) zI&xXGz*1$g0D^>$SptYfAp;OD6saKlb)aP>7`Qsf*X;)&x`xbN#(3CXA(iI_U+}|p zVQNsDrzKSwT685u9Z4}TnQEfqh-GNzM=4vBZB`QXxHA$BD?>1bQkbl@YUwa47D%p} zM@>aDGYC^KLm<- z2rYo9m7$WB+C@bsinfJ@wl0Nsp;DM8V1>BWK_2>ncIz#OS#X1-lwwUS>PktW>5xoM zLspo&8!E}8Fsqo5!NUgJz_$p6NetncHK!qqG6+{G*C$=5 zS3$Kwj25&WWyye%O{6X>HGzh$V45tUfJ9)B7+D(8u&>|s`)1n|F32*8V)bZoIOM@1 zi5W9%P{UTnM5K_2F;))X-O4GFwkI~gFk&5A0j9DnG?*(g(P6q~f{=!pFhhzNm37BUuFr$C3p z;o*kKy(|to;hK@MCuO9GLKxqo9ay=>wRf0a6`!hT!mvU}ZfLS0p##S9Ed(R}b=5Moe|jKpRoNSU1u) z=RnB~4Kvs2?DAh+(2~pBK0UyG6Zb}H*E*1d+Ee0W*FK+n=6O8;e83;Xfk)z}##SK#DGF#s+CW~^Og03-@^E^(y}u4ZF;p=p$k zD2``szAxw|5pW`E#Q zWactBI{;(>Fo!oE)6}qZp5w1tBLiph<6vO~7|i;RJXAVfJ%}&J{xO|10<#^&_6o2Z z5=jQXCIN}~ocHkjFOHs8o~~Gna>hAe41)migrAqZ?m8T^PM8pz!uvZH<#XXo{5Obl zrw<)Tkq1mQx>Jwl1vna+p8lTmBMHGVrh$k^1`|Qu9|;el90bsd+L!Zq(~Sr*6bipf znB9-5&z^1HaY+v_Y4eA{4nZ5vDZu$LA#Ye*<~_iTCMFg?EB-fw!R zge3&BMF9aMA^HIxXo1*sIs@$LQ4~IxVdc(<0hc0Z-I66J2<(2(0ebuI=}1VbfeL7h z!yw(X10Xs^no>v!B}pX;ScVuPRRWM25CW8F5~8Alk*Q?_sU4VE3fP1%x62`;P{Rx< zp)^A&Q6*V&l`=86D%d$e5Ls+B2tzQ#Mrvs-%+ai)ts|AND-i_Db*#2B$Zs+Z42W*V zDmqS&SGCxFzd&6B-Q&xk(GYthexX2lsSL8jsKF?^$r50}gp*Z7ArcI*U<8gt!AM4f ztU&gXgiyzE(DWI5K<=9DI!I0(2u@+s1c;SsV5$XJghT|nG|3d?;!zPz1q{_QQDkJZ zRKz5)S)RjAF${#zQWPyBQlUtqQYA53j3CHJlL-kYsYoTopYg7pwg|@=h6WA5;2*`+ z?APbNAE#{heGyH%xZsXj6_m6_Jp3|ZdjB!~-nt(ylaE{Sdv89@k7>M4obw?2sq5dQ zF&f}K@P{Z&Y2$=7=1JV%E>E5zf84hAwj z+`D0aZ*!QAIX+PSZis$JFpQ9!L_*4rO4P%TLO*l~h*I%13rc6(JafGUdYU((bQ$7S7i%3YU)Ud^D+nvVK>tc~PW7$aboC(GZtO zNEAy`zC(qS=Rt07QjnreMw3km>9g#j=9HL93TX|~LBm=++d`v{SJt^%HChqQ^)C)h zUcD)G!?nW-WxL$(F8vk3T||{tRw{y?NU%hU3=(DAC1BjcYiF=d-qBXn{@h(vf$rco zshOK;Fd}-Q!jwia^vaA~mM84>g{EO)He9aegCxw5)tVrzBb5rO%%?4UwS}~juSxc9 z@g1sX4CvX)%NuPR1D$og*Xh{ca>|?%l}fQhWu?Q9lQY|#JvUvIJJ8pc@)bP;D?zEk zu=nZIT2Ahy$_XVF!?zkS^|#G}-U-_$J^OZen*;Yqt@26C9v5tpSN3FRPO1_TLvC?) zvSLb?gxVXBGJJEuj?jD6Yj4@tGf}n2hi1Hd`?9^-7`!vgb?@#{6$RU>Ha}raI%|e? zt0VH!oUr_v($>;v3$@o=#QB`R=Fh<{_rC34cH*GUqg`?7N)w)2OCe=iK5}?xs>LyD z2*w>nc-vZh?~A`)?iiN6(nZJo6Ovii*!6FDZ^l0D{PtvIwJHdUkoCf+TGu>!^loV; zydOz7M}tXQhViGa_LguYVRYJUo8GS~!`d8YXm?JC3wvry5@*7-yLq8CU2iiDL1~GX zs9MMIj;~THbtD~;wI1oIP}57r6qD}onpx$XHS#}1>ez1ewX2*{Q+3oJvSZOb!O&f9 zm}6qooQ%mjy$4A>c2wREBQY7m9W~gy95ZC$P*#-^wl!nL6TN3O?lndHTCI0i=^3wo z!rIK3wd)~mGU;UGmWhX9SSD#H>uR&KiM83gu*IuHvfCRzL3YuPuZ$e^B>S>8& z;V}NCUv|R6sQCzMehz?z6?H1Qb{19|aU4QLY(ss;!co{2cML(>9XqzS4H2Y8!dJ>u z4hF=UMj-=32t&bm0ijc5+d-pb7DWb{24;|gnmZ82=#f318pB!Hr%@djJ{6+O7e6}_ zkfbKOiZO|bg&V8C-+C}W?a^;WTkdjIPY8<<7%c=31CgUWU3Vnq<0&#M0x<(*FpID| z3`v`Y;QI+6Li?&V!cj2JIbrcQ4TZtxn|wTt2dlf#Wo3ZWzs zATn%+7(rP9aU+b$jM~#)dD;mXw2L-Sb0?of^wj3;&07>_YQCn@=33TFDge#bp7R1} zD8|X%$A_y9P+-ACz`^$!HbNOLlzs45bvf335p#I2e)Ch)Ul>ws1feokBaKtEanrPx zha>lImED=g9{zC|Og;O_b;4RDKF^kOK6G|sC0x10(1pFNDI!`+GLyzE%?gio7;(kk zyH%RJ-0Rz?FT4;+>>+YeB$hn24j@AB6gbmS=_@%c~yq)%KLuKx5oE<#fBp7m0{8;qpoB% zxcT^uM78W$ahhE(Mmwszm*)maq}Iwtq^O&nOT`3myrD8UA3+66@FA$u(Kf_7&t*(e z^vwGUcE^^I%1@%;G+fF>iAm(vnC$MBbbV7rcr(E>drOl~rvg(W7^zZjaoP?OmYZ}O zmsPqnei}YgVlOCUNuTH3b6LCaIdLbYF@}KW?{j)g;?`?Tyx=R!&}q=eS2$7^N!7Rs zq~eP?UXK4?zUNV0AcbY`%3LA=%;F90l*_@lWF(9?xx)GEIOlW-u15 zxf(Mt)dsPfCc8^v-R(MDP1AwEIGYCOZV+~kgvNGUHel1cBh-7j5X2NgMHLnN__$P2 z7L@vU1NP{Xp%WjLoUR7O>-D~e|9xKf(dPQz*Qeh2{q8>B zcja}v-NJV%;?hcb&^x`-($PJSMVt+enew}tc#az3n)Nk#Yv*f!@cVPP$czrTdD2(B(tzA@=HBQJL&Q_B<5>d2k&!R>AKs+-)ui~tzT#Kn7J*O<{#6d z(TIPJX#{9cvd1!e*{rPC*`o>t)&3a4wu-TrG6O0Nq-bpF?_l*t&AVZ7_S^Aa?86Dr%m9k+*Zdc zk{WfXXk3#@W2kD)I2w*-riX%fs?gF>e9J7eW}cQaElSv3I-?6)$7>TXgdpmYvqmGH z59@%Nj`>{dT%4qfQ7a5%r-2K`=M70J)uQ#1wPB)`O34SKT1MLv8yTjOFx9B)|ElbKccp^7&h*MG7S9FqYn`7R!r$i;AROqb}M^`f`i6CP*Zo^nu z#dZy+4K|EqSj1Rb9LzQ~T{hXHYcSBZniR8i-fYLk&L*|J7E+t=b*RN=fti*r9nwi? ztpujQiHt!828jrgNlfJ}%d}`hRd$VRLd;S_0a|xedwR;et0(Nm;4#UFRdtXmP92w%L?)VO z#D#^uJ3$2Lyvp7M)C^I|!IqMPdydCeLDB?b3re9{hSmnWE*t}9a1NN7W{vfjv5_^a zrzk{@Vr92Z$0{gP(3@%lm7GgeNg7K+W|I-EGe)Z!DrGv6QhLc&V=@JqN~O_s)WYnk zFsv!%Vl%weQo`}Z=uBxOS{oBajZCGK)g@gcd)bpZE*NccV4Rf8RLx!;r4F}!X&WZp z=xGcQMIxgmW5!#ndLtbVWxK*`4iL1En1WQ@$DxU_3JwkY9BjV)1-Ms;ZY2d~^Kc-gSy zeOVB&r|=<%(i4qGfzY3B5+0p9zaKthN*=dT_q{73PR!)%+gN%8b%40M%^)%Q=KoF|9g%%cr#5~EQXY1224Brzssd4t4y3>i=&o#ah@SNqdJ_m z;;+EMpZLv+jl4O22G)#3nlaY|pesXng?yTIzA4!>&Tvp*ueaQ=>T*xv!`=HVrh2-yL|^WZeF%1PxVcTAXsTBi zL4)YxQ?(b_(xLx6*{%pPRF5?Fy}R!tPF1|o{qvyU2cHhubX zDv2%}Kib2accJL3O1)b+TRHtP+usyk(n!S4W(qS+BG_BuG6?U?_yP4mfkMAxc+mu?L(R2*%RzwT1&I$aOV9 z%k1uG(;&x!lsu9sV8W0XN@;MyS;7v~oDGMe=?)Gi5Ya%0%#50vmSHp=N0*pV)5AR7 z4ET#d8cJy9N7h)NPl(Jcm|;o7f+Wnt6EU+41z<(jpI7!aS#7y7gX+UN1%nJb24X$7 z^lNwH(u^d*Y&(|C`|_80u1A6AjU4obAEs9mQiS+?&!#5 z=P&3Aiz^)n)Smg<-Iz%r1EU?x&D0yNMvbY%mmeX6aM)=A`Wp_-Cs zMl*pVFSm1mj#yK(AX)Fu0z}a21S!Ll7~DoBfCAKDVb{9W+EF_9>v_+>=3&A}_Pe3u z2ov0F6Vg1JC%*7AURKERMgiZoNO+thMNHTZX)ha$6qKFyAJ+}olglwJ1OI$mZ> z%T}wob#C{nHY&WvnW-?*uh&Op@$LD45d421_CIUa%_Jc9#6lF3O&=)l_R%TnDc9pi zPfT0Vw8bYo4kj(%1~N_aG+b{JeCb0X5$}x6GrdK#T|MkqOfua*?9c6PZ$fSowO6CZ zj+U8R9~6`6r%pl7W1D0?JIzj-<(Ef3aAqL0Mcb_CO)3wM9qiByNTIAOAqYbNs;rQR z6oeWOlmO-sFqF#47zhvW;bY(k8(YQe*Fn1|A7ctCTS^MUm0_EbjyCn9aE@?q2bU#z0IS?wnJWD!#7=&T2&&dIV9z?Mh7aWvp5M*;Vkr; zYf2tdj6#PgHoF6AhSb%W(nDFVm4Rxixf-Du=9-1rNqSfSU{XR8+>lPGRapE=;Re^D z3{+Jbw_325Wp3%6uxJXw+Nc16r-6-f_HfNrBio|`jdZgJ>61{-B5Ogx+&uUZqs!U< zWME5_;MGV;5I-h(mYU6|`x@zd@3j>ig^QGfvFA-~*xB9I#xqWtv9xxw7GSJISfSgk z^DkGU%5%L(SqvGQWpt=w8g`wW*$y{aN~${CRB%$Di^Xpp&wX;l95CS&5ttlKdFNfX zi($zrd8AswdUWDt8OB&m9gjtqj-c(S*8?pM*%euG7^u+Xb}|}V!>)HmmDZ^Xj-b>+ zrA8w5@0{V?S}9jJ`;Vxs(=%Q7!`C{5y^fZVh~Vn`n7S)`5}}s$QRXfaF2Q3iilb)i zyN%r}P0+$~tlVTYX7Br(O|mtqq%H(Av7IQDE?aG{y$^fIsa|w67s^i*=}1nG8QHFm zc+BlfFRo|Vd8E~LwKX@(<#4!daQ!)YcC)!L?dOa#K3_`weVp~TxxLq1uPkfQ?)%BB zHl6jBJDI#Pqpd?-TQu-VAzGs=%|AS|T#butVY3+1n8)mz-mg6+ zN+%gC*@%(_PYk&{%PM9llb#DBezUntZoNFU$-W&{z2|(xj`v;VDuUXBdJHC_x|~mKMs=P024X z+7niY>|8zGT0IA+e=b>=goK^hI5_UYHbtWv^N4#DXU%GR&&bMhTYn z+%{s|)Fz;vf9Zeku~fU21umpWNqlzY7d0&Trl{UcTLdBQLcU0A-ET_6ZHtH8A3QpVC~n;d z>vwt2W_4I9Gp>rV-6cW+1$2qbogK1OBq0SOFBGgr`WjTXrtJA?#Ca0Z>#hY}6=Dt7 z2;zf8-n=4ajo-U^qf3f?I)7tmx?-_FZ-G!N2gcm4uR5&CCmxnW2MyO*vJHc-)plC( z%-3eCv$N3R%~zwPUQSfxzHu7#WZi9hvIA9|apqW)UKbr^*w01mve>hz^OU8*Jn6w0 znNx8$Mj)#w#!4GIosptAD+6Gd9F#$aiDfu2H!$4zZw@Ac?S!Oo6vxC4^yX|y#CVIG zY6-%EB6*rzUDsik4ToUZIUT{e90b^`!qOdUk+C>gMPZTYQSwAVNh=R(7!Wlf%GEnC z9MM({U9Q3wxkmz%yQHEgBjAd*kf!q{K}AuuY}iaV+p$(abd!vM<--v=)&d3+9w2gJ z;enV_fwVdl)ZS2_$ajW7*vU0JLxTbbpPmNGuyIy6CN7;XMA)^HkdY?glCiRfFc3X6 zG>?XWrSwOaRX>>WTD8+ER($PDjSa!m?XmJG;jdX#5#wA#7&ub ztWi|6lTyJEWZdAh0hS#n8wP-PWKA+J0cAJ|K_jy>!QJ7^*qrdGs>Lk4LQH~=gKkw* zKynQ00OIZ<2U;ucF_-1d6zxOG4r?D8V_gf$;HmGbVG2PL$B(?v!=JhH`ol&BSlLR#@2^c{jka+Q$Q&&Y_wGC@*4aOKG5HHJn8+ahq3-f4UV!BiES5fRs8;Obnd$D;iA|FQ>|K*Un&Ur|6=Z!+dkbw%CX&28~Wy2^N z3T=8d&!3>d4K|UfpA?g%X9^)_60VUgG~UBG#cAOkA_?iK5|H!&Lca(ZP=#Q9Xm+PC z<;>}wy0d$y=g-`%FIP|_Lec?G%=Vk1RJcgiW(G7HHyKfr5=c?Gk#Pk8TWY|TTBDG; zl7gz?e6$*l4PjD)HA)F7hC>2^uogsNF~rhn79`X;h6N+GXwYO7lsHOau#})n5RAE{ z)PR)O21sjPKJ=>m=iL)+psNMjS|+w8)bx`eTR{$SMVJFmca0Zyc=|P&HB<2Y( z(t>%Qo!!w11F`5g){h*;AI#D5**goetlc+&h$XNF$QNM5#R9vsqB0=_mSr5cWsGn@ z?X(05vpi15NKaYPla%zLAv~p^!5c~*W6QsgdYVe#6!rom>9pOpYcf*yc_x`L4AKg% zts5FTh|(3iqC>V#ZD8UDy@d$pMDdzVk^;@EC117njiL>)odS0keK zXA~Fe;`wMWjF7?=9Z1juG}A~@DM^fjkcr1ZDfm=@xC3kjvgl9D8V^BkkC+{W_ifkX zz<$XJ0Hsek^g|OEfb|c8`?>)?Vh^2x8DSBnPgmhB9gE_4K<&o!uNFFC$HYAfIWikq zI}MZHCqwUd?eHkUfl7XUL&q_jVYc@3fZYr`4X`&Nh)9}9BYeQbjDlLGV8asth(<(I zMp{@D*eifsK(R$nDKHWhAchu{A|la=g&2V@5REL8Nk~zdkuVZdQb9n$G{{R%1xN-& zQ6j(?43IeL{yW>eL(K6xk7Nn&>sh+Z2D!ulCSPQl65o=+tnS+}8g>;yjDISRQsKhIrxEOkVCzz;%BC3b9TUf$WveOK6EV5X}913WP zA(Ex!BKlR@s*xz5rKy6HC`TtDLog>F&)eVb?(gglu7jaEf$hbLVqqu+k}5j?y)QvU?)8v*mo};` zr%Oz{WO=uu-m_RC7Tz|IY{F3pQ&iJwI*=ofZfQ;L4cwcnZuF$n30Q}DEzQQJ7G+i@ ziBEE7vnsT&3W%yyiq-E-vqCl^uDbp$4*=+12Hic}_Cuf^2%+)e@r{I2{?ft{sL4ZA zT?ZqP@b+_gQOQ&{1yo^Pr0G{n5X8i!$+O?CW=C=L8>jb=efi_v-A=54vWx33FyDLy zFv(bV2A!sWpx24za@%-#+2M$3FSZ@ne>nZWMvj9&I4{zB1I(+`KQP1!L1vN)0bu&E zI#7$pCzLQpXv8f2A}Au=dQh%*7g1|&lb1_Cgj{)ITA z{{aAr(L+E)uyl@v9p(P$q$o(Cs98X&pbAMuC4!0|A|#rsYAA>z8IY7IYD%afh-rzW zs6rH=3IBiSL`|8hvlAV(!S*XC5U6cn({ zO-)P`5`|GK0aF7&LX5&MG(WheaRXFHr42w&2U0KUwmjk--}At9kNV7nuz34D{fd97 zB?w>&C?%ReckEB4_s;v2NdOd!NkI~k;-mkgerEwWKNsZ8{I`1R%rDZKg6Tx=UtlMg z|9G1kHmAG01`;YXrBOgs4x$)wgjFCu>?a1eHmFN!5?q1)=y4!>*&x7X@b&zqCTQmQ z)OytSgD5Ip3EdP#0YI{F3`0I{og#p{C;U(m2yc)WqA=L7MxuhzsCzu;$<`N|Yh8z= zzoOUMob_J^8(KLpSN;@-n10~;Q2D}tY*4fPD1iauAKZD0prn!yygv9AOk-t18bnwP zs?yO51I9Hr4+)Z3mL$SSRA+V<19x>h@OBXF;+jtYHbF2SioTdn!hgOVa55+#I$TfH zK-q^W@n8bLSZqDhF?i`UCZIv8m_Nf0IpGNKg$|Ae05=|51YPP>_DCF0+k$@I*S`&v z5c*g{iTEZ9+8ulokL#>jHv;&ZH!!d_qz09b04+0%xLs0zl!&fBtrWHDNGo;YO9)Z6hrDB%GKY(PL zWHjfW7O`1rMT!bzZSrvhk(n%%V#1L{KKF-Co?rQESl4&OqKSFyrre{UC=0Qw8=?yn z>cB$}~1C0$nd!OS<=vq#9leO**Z6%Vw336%=ZaXdYg%Maa|MNL^X zFrGROY4`rmqwA?g*Wl(IN@Fl(j5U-oXj%#=#A#ewR#H$?A(Jx;1TlP(gd15#K{RLr z)6coN^MfE8kn{BXw;mHK4$0wVHa%T+wyCirbEpS09O9M`4*DBW6jojp8Ma5LZ>_SE z;u$7%8v)pPZvARXtlLgVGz&^lqe=2?ErT#qV+@s+;*%Lt7`?;8)nTXsp*W<61h|9} z65|2gqrq?vfZ`+5r46~)mXOmbXf$e_j5}di2*f=wI?l6{?I6VMqcChHXc);$igt{j zS2+FniuF97fS`wXa+7nHE;#!)*Zdw}@Zc`bW^+Tidy;vdX$j8l;s4I_G$ zF5RAmM^KbN^m?yY2Ld-mcmdH{R z`r)I0W@<7A)g95e9ZWpUawh28*G|TEuM`OgG-y#1{wk7Sg{YuLl%N(Mq@aiI-DX6F34{)ikyJhZgdy}OADspF_TE{amzE_Ow+_rd zIjncJbViTTXBU67gZtONC}Z2%R#^jmb9ivsaZPg1xj2kI&$|QXb3oc@gV((|l2IV) zAsZ78j-nY7>0`Jw44`U}p}pE&i&%GNzz7!17hiyl!l=-2nQL;NT70o3c_OuRuBq+c1*)_IQ{J9 z99Jx?O#v)*{D`mRtm3A&ftO>WNDZO^|2$`ZO7)yT1Fr_~hmoMnm|;>22T3HGhT|CE z8gw!y9ggDe?sIR&^EAe5jAt|9&L{w~%sCnTqX{z~y3C3MkH|0)1Qe7}EXc7fEEK@Y z2*8BWp(h?7Z`R89hA8C%gh;HoVoL`nm$%i$lg$I@c%FnGygs4kba3EZV7gsQ z%zr@nHw6qoxBZ$-hLQ>ZDFfJoQjqr95AperEc7S9dLQfH9uJ4E*XeT~7r1b~Z%wq| zQZy&`*&(G=GoU{*A;(MpC$r)2gCIr+MKut?`EvZeQ`$fw|KjdQrwS4jOPNYQUOIW- literal 0 HcmV?d00001 diff --git a/scons-mini.tar.bz2.cdbs-config_list b/scons-mini.tar.bz2.cdbs-config_list new file mode 100644 index 0000000..e69de29 diff --git a/src/SConscript b/src/SConscript new file mode 100644 index 0000000..5d40432 --- /dev/null +++ b/src/SConscript @@ -0,0 +1,69 @@ +#! /usr/bin/env python +## This script demonstrates how to build and install +## a simple kde program having KconfigXT settings +## with scons +## +## Thomas Nagy, 2004, 2005 + +## This file can be reused freely for any project (see COPYING) + +############################ +## load the config + +## Use the environment and the tools set in the top-level +## SConstruct file (set with 'Export') - this is very important + +Import( 'env' ) +myenv=env.Copy() + +############################# +## the programs to build + +# The sources for our program - only .ui, .skel and .cpp are accepted +kstreamripper_sources = """ +addnewstreamimpl.cpp +addnewstream.ui +kstreamripperbase.ui +kstreamripper.cpp +main.cpp +processcontroller.cpp +processlistviewitem.cpp +""".split() + +# Our main program +# KDEprogram add the file to the install targets automatically, +# so you do not need to write KDEinstall('KDEBIN', '', test1, myenv) +myenv.KDEprogram( "kstreamripper", kstreamripper_sources ) + +############################ +## Customization + +## Additional include paths for compiling the source files +## Always add '../' (top-level directory) because moc makes code that needs it +myenv.KDEaddpaths_includes( ['./', '../'] ) + +## Necessary libraries to link against +myenv.KDEaddlibs( ['qt-mt', 'kio', 'kdeui'] ) +if env['KDEm2']>3: myenv.KDEaddlibs( ['kdnssd']) +############################# +## Data to install + +## The ui.rc file and the tips go into datadir/appname/ +myenv.KDEinstall( 'KDEDATA', 'kstreamripper', 'kstreamripperui.rc' ) + +## The kcfg file is installed in a global kcfg directory +#myenv.KDEinstall( 'KDEKCFG', '', 'test1.kcfg' ) + +## Warning : there is a difference between the normal destop file used for the menu +## and the servicetype desktop file, so they go in different directories +## you will find more information in 'test3' +myenv.KDEinstall( 'KDEMENU', 'Utilities', 'kstreamripper.desktop') + +## Use this when you need to install a mimetype file +#myenv.KDEinstall( 'KDEMIME', 'application', 'x-test1.desktop' ) + +## Installing icons is easy (hi-16-app-test1.png, hi-22-app-test1.png) +## do not forget that this is a python script so loops are allowed here :) +myenv.KDEicon( 'hi16-app-kstreameripper.png') +myenv.KDEicon( 'hi32-app-kstreameripper.png') + diff --git a/src/addnewstream.ui b/src/addnewstream.ui new file mode 100644 index 0000000..5b46733 --- /dev/null +++ b/src/addnewstream.ui @@ -0,0 +1,108 @@ + +AddNewStream + + + AddNewStream + + + + 0 + 0 + 383 + 287 + + + + Add Stream.... + + + TabFocus + + + + unnamed + + + + frame3 + + + StyledPanel + + + Raised + + + + unnamed + + + + d_nameLabel + + + Name: + + + + + d_descriptionLabel + + + Description: + + + + + d_nameEdit + + + + + d_urlEdit + + + + + d_descEdit + + + + + d_urlLabel + + + Url of Stream: + + + + + + + d_okButton + + + TabFocus + + + &Ok + + + Alt+O + + + + + d_cancelButton + + + &Cancel + + + Alt+C + + + + + + diff --git a/src/addnewstreamimpl.cpp b/src/addnewstreamimpl.cpp new file mode 100644 index 0000000..033e44e --- /dev/null +++ b/src/addnewstreamimpl.cpp @@ -0,0 +1,66 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by Michael Goettsche * + * mail@tuxipuxi.org * + * * + * 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 2 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, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include + +#include +#include + +#include "addnewstreamimpl.h" + + +AddNewStreamImpl::AddNewStreamImpl( QWidget* parent, const char* name ) + : AddNewStream( parent,name, true ) +{ + connect( d_okButton, SIGNAL( clicked()), this, SLOT( okButtonClicked()) ); + connect( d_cancelButton, SIGNAL( clicked()), this, SLOT( cancelButtonClicked()) ); +} + + +AddNewStreamImpl::~AddNewStreamImpl() +{ +} + + +//SLOTS + + +void AddNewStreamImpl::okButtonClicked() +{ + if( d_nameEdit->text() != "" && d_urlEdit->text() != "") + { + emit finished( this ); + this->close(); + } + else + { + KMessageBox::error( this, "You forgot to fill out one or more fields, please do it now.", + "Missing Information" ); + } +} + + +void AddNewStreamImpl::cancelButtonClicked() +{ + this->close(); +} + + + diff --git a/src/addnewstreamimpl.h b/src/addnewstreamimpl.h new file mode 100644 index 0000000..30bcb49 --- /dev/null +++ b/src/addnewstreamimpl.h @@ -0,0 +1,48 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by Michael Goettsche * + * mail@tuxipuxi.org * + * * + * 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 2 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, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef ADDNEWSTREAMIMPL_H +#define ADDNEWSTREAMIMPL_H + +#include "addnewstream.h" + +class AddNewStreamImpl : public AddNewStream +{ + Q_OBJECT + +public: + + AddNewStreamImpl( QWidget* parent = 0, const char* name = 0 ); + ~AddNewStreamImpl(); + +protected: + +protected slots: + + void okButtonClicked(); + void cancelButtonClicked(); + +signals: + + void finished( AddNewStreamImpl* ); +}; + +#endif + diff --git a/src/hi16-app-kstreamripper.png b/src/hi16-app-kstreamripper.png new file mode 100644 index 0000000000000000000000000000000000000000..4ed606c1a4a05d54879e6b8caf97297158b9ca36 GIT binary patch literal 1033 zcmV+k1or!hP)T z7)>@8B@P?o4HvlJ68{4=(F;wyT8!~#&bT=;K(h^&=`weeY=%KQz;+#zV=0FYTq&%D z7B6fGM)q9)p3jrt_xXOG6rNM|jQm)-#ipq}bf9X=H#WKu{(EwDZFT(WtzU|OB_O`> zeadE#Vtesg>Go1&S;05yLo&)#SJjiI)3Okqh?JZ zg~RwBK4#K4fhg&St*nx&(~_|z3*5W}+yv~sHJdzPaSZd|&_?TfcK zd+Iypp3Jeg?iECx7R97+^qr$vZRyUNzg_o7>4EJOAQ(zJ3`TUD7t%2!)pePdQW-}h|BSwZsm>mfaiADevKoIOD+h-+3 zwgty$um9!cno9 zm6wSiq+(Kyh@uv=s?yu{fC=vyUEywamhWO_EWpFNgZStCI=~K00nudEG=S|;bwj|Q z%G5X1@xbtLHoV6DEBE;3^vR^Kp~Upm#HRW;W^H5oHGm9ga;!NMHj_m)tY)ejOELQK900000NkvXXu0mjf DUF_&? literal 0 HcmV?d00001 diff --git a/src/hi32-app-kstreamripper.png b/src/hi32-app-kstreamripper.png new file mode 100644 index 0000000000000000000000000000000000000000..45ae1a1134f1afc27bd093068a3275e39c416262 GIT binary patch literal 2749 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 DHls?L literal 0 HcmV?d00001 diff --git a/src/kstreamripper.cpp b/src/kstreamripper.cpp new file mode 100644 index 0000000..9641df2 --- /dev/null +++ b/src/kstreamripper.cpp @@ -0,0 +1,309 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by Michael Goettsche * + * mail@tuxipuxi.org * + * * + * 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 2 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, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kstreamripper.h" +#include "addnewstreamimpl.h" +#include "processlistviewitem.h" +#include "processcontroller.h" + + + +KStreamRipper::KStreamRipper( QWidget* parent, const char* name ) + : KStreamRipperBase( parent,name ) +#if KDE_IS_VERSION(3,3,90) + , m_browser("_shoutcast._tcp",0,true) +#endif +{ + m_destEdit->setText( QDir::homeDirPath() ); + + m_streamsListView->addColumn( "Name" ); + m_streamsListView->addColumn( "Status" ); + m_streamsListView->addColumn( "Size" ); + + //app config + KConfig *appConfig = KGlobal::config(); + + m_destEdit->setText( appConfig->readEntry( "Destination" , "" ) ); + m_timeEdit->setText( appConfig->readEntry( "Riptime", "0" )); + m_tuneInEdit->setText( appConfig->readEntry( "Command", "xmms " )); + m_id3Checkbox->setChecked( appConfig->readBoolEntry( "Id3Tag", 1 )); + + //listview entrys + QStringList nameList,urlList,descList; + + nameList = appConfig->readListEntry( "names" ); + urlList = appConfig->readListEntry( "urls" ); + descList = appConfig->readListEntry( "descs" ); + QStringList::iterator iter1, iter2, iter3; + iter1 = nameList.begin(); + iter2 = urlList.begin(); + iter3 = descList.begin(); + + for( ; iter1 != nameList.end() && iter2 != urlList.end() && iter3 != descList.end(); ++iter1, ++iter2, ++iter3 ) + { + ProcessListViewItem * proc = new ProcessListViewItem( m_streamsListView, *iter1, "", ""); + proc->setRenameEnabled(0, true); + proc->getProcessController()->setUrl( *iter2 ); + proc->getProcessController()->setDescription( *iter3 ); + } + + //CONNECTS + + //clicks + connect(m_addStreamButton, SIGNAL(clicked()), this, SLOT(addStreamButtonClicked())); + connect(m_deleteStreamButton, SIGNAL(clicked()), this, SLOT(deleteStreamButtonClicked())); + connect(m_tuneInButton, SIGNAL(clicked()), this, SLOT(tuneInButtonClicked())); + connect(m_ripButton, SIGNAL(clicked()), this, SLOT(ripButtonClicked())); + connect(m_stopRipButton, SIGNAL(clicked()), this, SLOT(stopRipButtonClicked())); + connect(m_browseButton, SIGNAL(clicked()), this, SLOT(browseButtonClicked())); + connect(m_aboutButton, SIGNAL(clicked()), this, SLOT(aboutButtonClicked())); + connect(m_quitButton, SIGNAL(clicked()), this, SLOT(quitButtonClicked())); + + //other + connect( m_streamsListView, SIGNAL(selectionChanged()), this, SLOT( selectedNewListItem()) ); + connect( m_DescriptionEdit, SIGNAL(textChanged(const QString&)), this, SLOT( descriptionChanged()) ); + connect( m_UrlEdit, SIGNAL(textChanged(const QString&)), this, SLOT( urlChanged()) ); + + // zeroconf +#if KDE_IS_VERSION(3,3,90) + connect(&m_browser, SIGNAL(serviceAdded(DNSSD::RemoteService::Ptr)), this, + SLOT(serviceAdded(DNSSD::RemoteService::Ptr))); + connect(&m_browser, SIGNAL(serviceRemoved(DNSSD::RemoteService::Ptr)), this, + SLOT(serviceRemoved(DNSSD::RemoteService::Ptr))); + m_browser.startBrowse(); +#endif +} + + +KStreamRipper::~KStreamRipper() +{ +} + + +void KStreamRipper::closeEvent( QCloseEvent *e ) +{ + KConfig *appConfig = KGlobal::config(); + + appConfig->writeEntry( "Destination", m_destEdit->text()); + appConfig->writeEntry( "Riptime", m_timeEdit->text()); + appConfig->writeEntry( "Command", m_tuneInEdit->text()); + appConfig->writeEntry( "Id3Tag", m_id3Checkbox->isChecked()); + + //save the listview entrys + + QStringList nameList,urlList,descList; + QListViewItemIterator iter( m_streamsListView ); + + while( iter.current() ) + { + ProcessListViewItem * ProcItem = (ProcessListViewItem*)iter.current(); + if(ProcItem->getProcessController()->getAutomatic()) continue; + + nameList.append( iter.current()->text( 0 )); + urlList.append( ProcItem->getProcessController()->getUrl() ); + descList.append( ProcItem->getProcessController()->getDescription() ); + ++iter; + } + + appConfig->writeEntry( "names", nameList ); + appConfig->writeEntry( "urls" , urlList ); + appConfig->writeEntry( "descs", descList ); + + appConfig->sync(); + + e->accept(); +} + + +//SLOTS +void KStreamRipper::addStreamButtonClicked() +{ + AddNewStreamImpl *test = new AddNewStreamImpl( this ); + connect( test, SIGNAL( finished( AddNewStreamImpl* )), this, SLOT( addStreamFinished( AddNewStreamImpl* )) ); + + test->show(); +} + +void KStreamRipper::deleteStreamButtonClicked() +{ + ProcessListViewItem * ProcItem = (ProcessListViewItem*)m_streamsListView->currentItem(); + stopRipButtonClicked(); + delete ProcItem; +} + +void KStreamRipper::tuneInButtonClicked() +{ + if( m_streamsListView->currentItem() ) + { + QString command = m_tuneInEdit->text().replace( "", m_UrlEdit->text() ); + + QStringList commands = QStringList::split( " ", command ); + + QProcess *process = new QProcess( this ); + process->setArguments( commands ); + + process->start(); + } + else ; +} + +#if KDE_IS_VERSION(3,3,90) +void KStreamRipper::serviceAdded(DNSSD::RemoteService::Ptr srv) +{ + ProcessListViewItem * proc = new ProcessListViewItem( m_streamsListView, srv->serviceName(), "", ""); + proc->getProcessController()->setUrl( QString("http://%1:%2%3").arg(srv->hostName()).arg(srv->port()).arg(srv->textData()["path"]) ); + proc->getProcessController()->setDescription( i18n("found by Zeroconf") ); + proc->getProcessController()->setAutomatic(true); + proc->getProcessController()->setService(srv); + +} +void KStreamRipper::serviceRemoved(DNSSD::RemoteService::Ptr srv) +{ + QListViewItemIterator iter( m_streamsListView ); + + while( iter.current() ) { + ProcessListViewItem * ProcItem = (ProcessListViewItem*)iter.current(); + if (ProcItem->getProcessController()->getAutomatic() && + srv==ProcItem->getProcessController()->getService()) { + delete ProcItem; + return; + } + ++iter; + } + +} +#endif + +void KStreamRipper::ripButtonClicked() +{ + if (KStandardDirs::findExe("streamripper")) { + ProcessListViewItem * ProcItem = (ProcessListViewItem*)m_streamsListView->currentItem(); + ProcItem->getProcessController()->startRip(m_destEdit->text(), m_timeEdit->text()); + m_ripButton->setEnabled( false ); + m_stopRipButton->setEnabled( true ); + } else { + KMessageBox::error(this, "The streamripper executable wasn't found. Make sure " + "it's in your path.", "streamripper not found"); + } +} + +void KStreamRipper::stopRipButtonClicked() +{ + ProcessListViewItem * ProcItem = (ProcessListViewItem*)m_streamsListView->currentItem(); + ProcItem->getProcessController()->stopRip(); + m_ripButton->setEnabled( true ); + m_stopRipButton->setEnabled( false ); +} + +void KStreamRipper::browseButtonClicked() +{ + QString openDest = KFileDialog::getExistingDirectory( QDir::homeDirPath(), + this, + "Select Destination..." ); + m_destEdit->setText( openDest ); +} + +void KStreamRipper::aboutButtonClicked() +{ + KAboutApplication *aboutApp = new KAboutApplication(); + aboutApp->show(); +} + +void KStreamRipper::quitButtonClicked() +{ + this->close(); +} + +void KStreamRipper::selectedNewListItem() +{ + if ( !m_streamsListView->selectedItem() ) { + m_deleteStreamButton->setEnabled( false ); + m_tuneInButton->setEnabled( false ); + m_ripButton->setEnabled( false ); + m_DescriptionEdit->setText( QString::null ); + m_DescriptionEdit->setEnabled(false); + m_UrlEdit->setEnabled(false); + m_UrlEdit->setText( QString::null ); + return; + } + ProcessController * ProcCtl = ((ProcessListViewItem*)m_streamsListView->currentItem())->getProcessController(); + + // reconfigure what the user is allowed to do based on if this process is ripping + m_ripButton->setEnabled( !ProcCtl->getStatus() ); + m_stopRipButton->setEnabled( ProcCtl->getStatus() ); + m_tuneInButton->setEnabled( true ); + m_deleteStreamButton->setEnabled( !ProcCtl->getAutomatic() ); + + m_DescriptionEdit->setText(ProcCtl->getDescription()); + m_DescriptionEdit->setEnabled(true); + m_UrlEdit->setText(ProcCtl->getUrl()); + m_UrlEdit->setEnabled( !ProcCtl->getAutomatic() ); + + + // maybe these are more elegant than the next two functions, assuming the slots are implemented in ProcessController + //connect(m_DescriptionEdit, SIGNAL(textChanged(const QString&)), (ProcessListViewItem*)m_streamsListView->currentItem()->getProcessController(), SIGNAL(descriptionChanged(const QString&)) + //connect(m_UrlEdit, SIGNAL(textChanged(const QString&)), (ProcessListViewItem*)m_streamsListView->currentItem()->getProcessController(), SIGNAL(urlChanged(const QString&)) +} + +void KStreamRipper::descriptionChanged() +{ + // maybe this should be deleted and the communication would be through a slot + ProcessListViewItem * ProcItem = (ProcessListViewItem*)m_streamsListView->currentItem(); + ProcItem->getProcessController()->setDescription(m_DescriptionEdit->text()); +} + +void KStreamRipper::urlChanged() +{ + // maybe this should be deleted and the communication would be through a slot + ProcessListViewItem * ProcItem = (ProcessListViewItem*)m_streamsListView->currentItem(); + ProcItem->getProcessController()->setUrl(m_UrlEdit->text()); +} + + +void KStreamRipper::addStreamFinished( AddNewStreamImpl *e ) +{ + ProcessListViewItem * proc = new ProcessListViewItem( m_streamsListView, e->d_nameEdit->text(), "", ""); + proc->getProcessController()->setUrl( e->d_urlEdit->text() ); + proc->getProcessController()->setDescription( e->d_descEdit->text() ); +} + diff --git a/src/kstreamripper.desktop b/src/kstreamripper.desktop new file mode 100644 index 0000000..3810f9f --- /dev/null +++ b/src/kstreamripper.desktop @@ -0,0 +1,16 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=KStreamRipper +Name[xx]=xxKStreamRipperxx +Exec=kstreamripper +Icon=kstreamripper +Type=Application +Comment=A simple KDE Application +Comment[da]=Et simpelt KDE program +Comment[es]=Una aplicación de KDE sencilla +Comment[hu]=Egyszerű KDE-alkalmazás +Comment[pt]=Uma aplicação KDE simples +Comment[pt_BR]=Um simples Aplicativo do KDE +Comment[sl]=Preprost program za KDE +Comment[sv]=Ett enkelt KDE-program +Comment[xx]=xxA simple KDE Applicationxx diff --git a/src/kstreamripper.h b/src/kstreamripper.h new file mode 100644 index 0000000..f1a5192 --- /dev/null +++ b/src/kstreamripper.h @@ -0,0 +1,79 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by Michael Goettsche * + * mail@tuxipuxi.org * + * * + * 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 2 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, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef KSTREAMRIPPER_H +#define KSTREAMRIPPER_H + +#include +#include "kstreamripperbase.h" +#if KDE_IS_VERSION(3,3,90) +#include +#include +#else +// damned moc will create slots regardless of #if macro +// this is hack to avoid undefined type +namespace DNSSD { namespace RemoteService { typedef int Ptr; } } +#endif + + +class AddNewStreamImpl; +class QString; + +class KStreamRipper : public KStreamRipperBase +{ + Q_OBJECT + +public: + + KStreamRipper( QWidget* parent = 0, const char* name = 0 ); + ~KStreamRipper(); + + virtual void closeEvent( QCloseEvent* ); +#if KDE_IS_VERSION(3,3,90) + DNSSD::ServiceBrowser m_browser; +#endif + +protected slots: + + void addStreamButtonClicked(); + void deleteStreamButtonClicked(); + void tuneInButtonClicked(); + void ripButtonClicked(); + void stopRipButtonClicked(); + void browseButtonClicked(); + void aboutButtonClicked(); + void quitButtonClicked(); + + void selectedNewListItem(); + void descriptionChanged(); + void urlChanged(); + + void addStreamFinished( AddNewStreamImpl* ); +#if KDE_IS_VERSION(3,3,90) + void serviceAdded(DNSSD::RemoteService::Ptr srv); + void serviceRemoved(DNSSD::RemoteService::Ptr srv); +#else + void serviceAdded(DNSSD::RemoteService::Ptr) {}; + void serviceRemoved(DNSSD::RemoteService::Ptr) {}; +#endif +}; + +#endif + diff --git a/src/kstreamripper.lsm b/src/kstreamripper.lsm new file mode 100644 index 0000000..0dbae01 --- /dev/null +++ b/src/kstreamripper.lsm @@ -0,0 +1,16 @@ +Begin3 +Title: KStreamRipper -- Some description +Version: 0.1 +Entered-date: +Description: +Keywords: KDE Qt +Author: Michael Goettsche +Maintained-by: Michael Goettsche +Home-page: +Alternate-site: +Primary-site: ftp://ftp.kde.org/pub/kde/unstable/apps/utils + xxxxxx kstreamripper-0.1.tar.gz + xxx kstreamripper-0.1.lsm +Platform: Linux. Needs KDE +Copying-policy: GPL +End diff --git a/src/kstreamripperbase.ui b/src/kstreamripperbase.ui new file mode 100644 index 0000000..fc87901 --- /dev/null +++ b/src/kstreamripperbase.ui @@ -0,0 +1,337 @@ + +KStreamRipperBase + + + KStreamRipperBase + + + + 0 + 0 + 749 + 782 + + + + KStreamRipper V. 0.3.4 + + + + unnamed + + + + spacer1 + + + Horizontal + + + Expanding + + + + 31 + 20 + + + + + + m_favoriteLabel + + + Your Radio Streams: + + + + + layout10 + + + + unnamed + + + + m_aboutButton + + + About + + + + + m_quitButton + + + &Quit + + + + + + + spacer5 + + + Horizontal + + + Expanding + + + + 421 + 21 + + + + + + m_streamsGroup + + + Stream Options + + + + unnamed + + + + m_addStreamButton + + + &Add Stream + + + Alt+A + + + + + m_deleteStreamButton + + + false + + + &Delete Stream + + + Alt+D + + + + + m_stopRipButton + + + false + + + &Stop Rip + + + Alt+S + + + false + + + + + m_tuneInButton + + + false + + + &Tune in + + + Alt+T + + + + + m_ripButton + + + false + + + &Rip Stream + + + Alt+R + + + + + + + m_streamsListView + + + true + + + AllColumns + + + Reject + + + + + m_settingsGroup + + + false + + + Settings + + + + unnamed + + + + m_pathLabel + + + Destination: + + + + + m_timeToRip + + + Time to Rip: + + + + + m_id3Label + + + Add ID3 Tag: + + + + + m_id3Checkbox + + + + + + true + + + + + m_tuneInLabel + + + Tune in Command: + + + + + m_secondsLabel + + + seconds + + + + + m_browseButton + + + .... + + + + + m_tuneInEdit + + + xmms <url> + + + + + m_timeEdit + + + 0 + + + + + m_destEdit + + + Choose a directory + + + + + + + m_Details + + + Details + + + + unnamed + + + + m_StreamDesc + + + Description: + + + + + m_StreamURL + + + URL: + + + + + m_UrlEdit + + + false + + + true + + + + + m_DescriptionEdit + + + false + + + + + + + + diff --git a/src/kstreamripperui.rc b/src/kstreamripperui.rc new file mode 100644 index 0000000..850885b --- /dev/null +++ b/src/kstreamripperui.rc @@ -0,0 +1,8 @@ + + + + C&ustom + + + + diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..81d8846 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,66 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by Michael Goettsche * + * mail@tuxipuxi.org * + * * + * 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 2 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, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include +#include +#include + +#include "kstreamripper.h" + + +int main( int argc, char *argv[] ) +{ + KAboutData aboutApp( "KStreamRipper", I18N_NOOP( "KStreamRipper" ), "0.3.4", + "KStreamRipper is a Frontend to Streamripper. Visit Homepage for more Info.", + KAboutData::License_GPL, "(C) 2003-2005 Michael Goettsche", 0, + "http://kstreamripper.tuxipuxi.org", "mail@tuxipuxi.org" ); + + aboutApp.addAuthor( "Michael Goettsche", "Maintainer, Initial version", "mail@tuxipuxi.org" ); + aboutApp.addAuthor( "William Entriken", "Concurrent Ripping, Major UI improvements", "william.entriken@villanova.edu" ); + aboutApp.addCredit( "Kevin Krammer", "Assistance"); + aboutApp.addCredit( "Jakub Stachowski", "bksys migration, crash fix" ); + KCmdLineArgs::init( argc, argv, &aboutApp ); + + KApplication app; + + KStreamRipper *mainWidget = new KStreamRipper(); + + app.setMainWidget( mainWidget ); + mainWidget->show(); + + mainWidget->resize( 700, 600 ); + + return app.exec(); +} + + + + + + + + + + + + + + + diff --git a/src/processcontroller.cpp b/src/processcontroller.cpp new file mode 100644 index 0000000..f0dfb6c --- /dev/null +++ b/src/processcontroller.cpp @@ -0,0 +1,148 @@ +/*************************************************************************** + * Copyright (C) 2005 by Will Entriken * + * william.entriken@villanova.edu * + * * + * 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 2 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, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + + +#include "processcontroller.h" +#include "processlistviewitem.h" + +ProcessController::ProcessController(ProcessListViewItem * parent) + : QObject((QObject *)parent), myParent(parent), myStatus(false), myAutomatic(false), myProcess(new QProcess(this)) +{ + connect (myProcess, SIGNAL( readyReadStdout() ), (ProcessController *) this, SLOT( readStdout()) ); + // connect (myProcess, SIGNAL( destroyed() ), myProcess, SLOT( kill()) ); + // this should work, according to http://doc.trolltech.com/3.2/qobject.html#~QObject but it doesn't +} + +ProcessController::~ProcessController() +{ + myProcess->kill(); +} + +void ProcessController::readStdout() +{ + QString tempOutput = myProcess->readStdout(); + + if( tempOutput.contains( "ripping..." )) + { + QString songname = tempOutput.mid( tempOutput.find( "]" )+1, tempOutput.findRev( "[" ) - tempOutput.find( "]" ) - 1); + myParent->setText( 1, songname.stripWhiteSpace() ); + + QString bytesR = tempOutput.mid( tempOutput.findRev( "[" )+1, tempOutput.findRev( "]" ) - tempOutput.findRev( "[" ) - 1); + myParent->setText( 2, bytesR.stripWhiteSpace() ); + } + + if( tempOutput.contains( "Connecting..." )) + { + myParent->setText( 1, "Connecting..." ); + myParent->setText( 2, "" ); + } + + if( tempOutput.contains( "buffering" )) + { + myParent->setText( 1, "Buffering..." ); + myParent->setText( 2, "" ); + } + + if( tempOutput.contains( "Time to stop is here" )) + { + myParent->setText( 1, "Complete" ); + myParent->setText( 2, "" ); + //QTimer::singleShot( 1500, myParent, SLOT( setEmptyText(3) )); + } +} + + +void ProcessController::startRip(QString destination, QString time) +{ + myStatus = true; + myParent->setText( 1, "Ripping" ); + + myProcess->clearArguments(); + myProcess->addArgument( "streamripper" ); + myProcess->addArgument( myUrl ); + myProcess->addArgument( "-d " ); + myProcess->addArgument( destination ); + if( time.toInt() ) + { + myProcess->addArgument( "-l " ); + myProcess->addArgument( time ); + } + + myProcess->setCommunication( QProcess::Stdout | QProcess::Stderr | QProcess::DupStderr ); + myProcess->start(); +} + + +void ProcessController::stopRip() +{ + myStatus = false; + myParent->setText( 1, "" ); + myParent->setText( 2, "" ); + + myProcess->tryTerminate(); + QTimer::singleShot( 2000, myProcess, SLOT( kill() ) ); +} + + +bool ProcessController::getStatus() +{ + return myStatus; +} + +QString ProcessController::getUrl() +{ + return myUrl; +} + +void ProcessController::setAutomatic(bool a) +{ + myAutomatic = a; +} + +bool ProcessController::getAutomatic() +{ + return myAutomatic; +} +#if KDE_IS_VERSION(3,3,90) +void ProcessController::setService(DNSSD::RemoteService::Ptr service) +{ + myService = service; +} + +DNSSD::RemoteService::Ptr ProcessController::getService() +{ + return myService; +} +#endif + +QString ProcessController::getDescription() +{ + return myDescription; +} + +void ProcessController::setUrl(QString Url) +{ + myUrl = Url; +} + +void ProcessController::setDescription(QString Description) +{ + myDescription = Description; +} diff --git a/src/processcontroller.h b/src/processcontroller.h new file mode 100644 index 0000000..22183df --- /dev/null +++ b/src/processcontroller.h @@ -0,0 +1,71 @@ +/*************************************************************************** + * Copyright (C) 2005 by Will Entriken * + * william.entriken@villanova.edu * + * * + * 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 2 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, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef PROCESSCONTROLLER_H +#define PROCESSCONTROLLER_H + +#include +#include +#include +#include +#include +#if KDE_IS_VERSION(3,3,90) +#include +#endif + +class ProcessListViewItem; + +class ProcessController : public QObject +{ + Q_OBJECT +public: + ProcessController(ProcessListViewItem * parent); + ~ProcessController(); + + bool getStatus(); + bool getAutomatic(); + void setAutomatic(bool a); +#if KDE_IS_VERSION(3,3,90) + DNSSD::RemoteService::Ptr getService(); + void setService(DNSSD::RemoteService::Ptr service); +#endif + void setUrl(QString Url); + void setDescription(QString Description); + QString getUrl(); + QString getDescription(); + void startRip(QString destination, QString time); + void stopRip(); + +protected slots: + void readStdout(); + +private: + ProcessListViewItem * myParent; + bool myStatus; + bool myAutomatic; +#if KDE_IS_VERSION(3,3,90) + DNSSD::RemoteService::Ptr myService; +#endif + QProcess * myProcess; + QString myUrl; + QString myDescription; +}; + +#endif diff --git a/src/processlistviewitem.cpp b/src/processlistviewitem.cpp new file mode 100644 index 0000000..d2c88cc --- /dev/null +++ b/src/processlistviewitem.cpp @@ -0,0 +1,108 @@ +/*************************************************************************** + * Copyright (C) 2005 by Will Entriken * + * william.entriken@villanova.edu * + * * + * 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 2 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, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + + +#include "processlistviewitem.h" + +#include "processlistviewitem.h" +#include "processcontroller.h" + +ProcessListViewItem::ProcessListViewItem( QListView * parent ) + : QListViewItem(parent), myProcessController(new ProcessController(this)) +{ +} + +ProcessListViewItem::ProcessListViewItem( QListViewItem * parent ) + : QListViewItem(parent), myProcessController(new ProcessController(this)) +{ +} + +ProcessListViewItem::ProcessListViewItem( QListView * parent, QListViewItem * after ) + : QListViewItem(parent, after), myProcessController(new ProcessController(this)) +{ +} + +ProcessListViewItem::ProcessListViewItem( QListViewItem * parent, QListViewItem * after ) + : QListViewItem(parent, after), myProcessController(new ProcessController(this)) +{ +} + +ProcessListViewItem::ProcessListViewItem( QListView * parent, + QString label1, + QString label2, + QString label3, + QString label4, + QString label5, + QString label6, + QString label7, + QString label8 ) + : QListViewItem(parent, label1, label2, label3, label4, label5, label6, label7, label8), myProcessController(new ProcessController(this)) +{ +} + +ProcessListViewItem::ProcessListViewItem( QListViewItem * parent, + QString label1, + QString label2, + QString label3, + QString label4, + QString label5, + QString label6, + QString label7, + QString label8 ) + : QListViewItem(parent, label1, label2, label3, label4, label5, label6, label7, label8), myProcessController(new ProcessController(this)) +{ +} + +ProcessListViewItem::ProcessListViewItem( QListView * parent, QListViewItem * after, + QString label1, + QString label2, + QString label3, + QString label4, + QString label5, + QString label6, + QString label7, + QString label8 ) + : QListViewItem(parent, after, label1, label2, label3, label4, label5, label6, label7, label8), + myProcessController(new ProcessController(this)) +{ +} + +ProcessListViewItem::ProcessListViewItem( QListViewItem * parent, QListViewItem * after, + QString label1, + QString label2, + QString label3, + QString label4, + QString label5, + QString label6, + QString label7, + QString label8 ) + : QListViewItem(parent, after, label1, label2, label3, label4, label5, label6, label7, label8), + myProcessController(new ProcessController(this)) +{ +} + +ProcessListViewItem::~ProcessListViewItem() +{ +} + +ProcessController * ProcessListViewItem::getProcessController() +{ + return myProcessController; +} diff --git a/src/processlistviewitem.h b/src/processlistviewitem.h new file mode 100644 index 0000000..aaa3e74 --- /dev/null +++ b/src/processlistviewitem.h @@ -0,0 +1,71 @@ +/*************************************************************************** + * Copyright (C) 2005 by Will Entriken * + * william.entriken@villanova.edu * + * * + * 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 2 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, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + + +#ifndef PROCESSLISTVIEWITEM_H +#define PROCESSLISTVIEWITEM_H + +#include +#include +#include + +class ProcessController; + +class ProcessListViewItem : public QObject, public QListViewItem +{ + Q_OBJECT +public: + + ProcessListViewItem( QListView * parent ); + ProcessListViewItem( QListViewItem * parent ); + ProcessListViewItem( QListView * parent, QListViewItem * after ); + ProcessListViewItem( QListViewItem * parent, QListViewItem * after ); + + ProcessListViewItem( QListView * parent, + QString, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null ); + ProcessListViewItem( QListViewItem * parent, + QString, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null ); + + ProcessListViewItem( QListView * parent, QListViewItem * after, + QString, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null ); + ProcessListViewItem( QListViewItem * parent, QListViewItem * after, + QString, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null ); + + ~ProcessListViewItem(); + + ProcessController * getProcessController(); + +private: + ProcessController * myProcessController; +}; + +#endif diff --git a/src/processlistviewitem_interface.h b/src/processlistviewitem_interface.h new file mode 100644 index 0000000..49385fa --- /dev/null +++ b/src/processlistviewitem_interface.h @@ -0,0 +1,38 @@ +/*************************************************************************** + * Copyright (C) 2005 by Will Entriken * + * william.entriken@villanova.edu * + * * + * 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 2 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, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + + +#ifndef __PROCESSLISTVIEWITEM_INTERFACE_H +#define __PROCESSLISTVIEWITEM_INTERFACE_H + +class ProcessListViewItemInterface +{ +public: + ProcessListViewItemInterface() {} + virtual ~ProcessListViewItemInterface() {} + + +private: + ProcessListViewItemInterface( const ProcessListViewItemInterface& source ); + void operator = ( const ProcessListViewItemInterface& source ); +}; + + +#endif // __PROCESSLISTVIEWITEM_INTERFACE_H diff --git a/templates/cpp b/templates/cpp new file mode 100644 index 0000000..1ad574e --- /dev/null +++ b/templates/cpp @@ -0,0 +1,19 @@ +/*************************************************************************** + * Copyright (C) 2003 by Michael Goettsche * + * mail@tuxipuxi.de * + * * + * 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 2 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, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ diff --git a/templates/h b/templates/h new file mode 100644 index 0000000..1ad574e --- /dev/null +++ b/templates/h @@ -0,0 +1,19 @@ +/*************************************************************************** + * Copyright (C) 2003 by Michael Goettsche * + * mail@tuxipuxi.de * + * * + * 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 2 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, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ diff --git a/unpack_local_scons.sh b/unpack_local_scons.sh new file mode 100755 index 0000000..a1266fc --- /dev/null +++ b/unpack_local_scons.sh @@ -0,0 +1,61 @@ +#!/bin/sh + +BOLD="\033[1m" +RED="\033[91m" +GREEN="\033[92m" +YELLOW="\033[93m" +CYAN="\033[96m" +NORMAL="\033[0m" + +#bunzip2 scons-mini.tar.bz2 +#tar xvf scons-mini.tar + +# if kde is there a recent tar should be too +tar xjvf scons-mini.tar.bz2 + +cat > Makefile << EOF +## Makefile automatically generated by unpack_local_scons.sh + +### To use scons when installed globally use +#SCONS=scons +### To run the local version instead, define +SCONS=./scons + +# scons : compile +# scons -c : clean +# scons install : install +# scons -c install : uninstall and clean + +# default target : use scons to build the programs +all: + \$(SCONS) -Q + +### There are several possibilities to help debugging : +# scons --debug=explain, scons --debug=tree .. +# +### To optimize the runtime, use +# scons --max-drift=1 --implicit-deps-unchanged +debug: + \$(SCONS) -Q --debug=tree + +clean: + \$(SCONS) -c + +install: + \$(SCONS) install + +uninstall: + \$(SCONS) -c install + +## this target creates a tarball of the project +dist: + \$(SCONS) dist +EOF + + +echo "" +echo -e $GREEN"A minimum scons distribution has been unpacked right here" +echo -e $GREEN"you can now run : "$NORMAL +echo -e $BOLD"./scons"$NORMAL +echo -e $BOLD"./scons install$NORMAL (as root probably)" +