bobcat-5.09.01/a2x/0000755000175000017500000000000014050437223012576 5ustar frankfrankbobcat-5.09.01/a2x/a2x1.f0000644000175000017500000000015514050437223013521 0ustar frankfrankinline A2x::A2x(char const *txt) // initialize from text : std::istringstream(txt) {} bobcat-5.09.01/a2x/data.cc0000644000175000017500000000007614050437223014021 0ustar frankfrank#include "a2x.ih" thread_local bool A2x::s_lastFail = false; bobcat-5.09.01/a2x/to.f0000644000175000017500000000017414050437223013371 0ustar frankfranktemplate inline Type A2x::to() { Type t; return (s_lastFail = (*this >> t).fail()) ? Type() : t; } bobcat-5.09.01/a2x/lastfail.f0000644000175000017500000000006714050437223014547 0ustar frankfrankinline bool A2x::lastFail() { return s_lastFail; } bobcat-5.09.01/a2x/opis2.f0000644000175000017500000000012414050437223013776 0ustar frankfrankinline A2x &A2x::operator=(A2x const &other) { return operator=(other.str()); } bobcat-5.09.01/a2x/a2x.ih0000644000175000017500000000007214050437223013611 0ustar frankfrank#include "a2x" using namespace std; using namespace FBB; bobcat-5.09.01/a2x/a2x0000644000175000017500000000205214050437223013212 0ustar frankfrank#ifndef INCLUDED_BOBCAT_A2X_ #define INCLUDED_BOBCAT_A2X_ #include #include namespace FBB { class A2x: public std::istringstream { static bool thread_local s_lastFail; public: A2x() = default; explicit A2x(char const *txt); // 1.f initialize from text explicit A2x(std::string const &str); // 2.f A2x(A2x const &other); // 3.f A2x(A2x &&tmp); // 4.f template operator Type(); // .f template Type to(); // .f A2x &operator=(char const *txt); // 1.cc A2x &operator=(std::string const &str); // 1.f A2x &operator=(A2x const &other); // 2.f static bool lastFail(); // .f }; #include "a2x1.f" #include "a2x2.f" #include "a2x3.f" #include "a2x4.f" #include "to.f" #include "optype.f" #include "opis1.f" #include "opis2.f" #include "lastfail.f" } // FBB #endif bobcat-5.09.01/a2x/opis.cc0000644000175000017500000000047014050437223014060 0ustar frankfrank#include "a2x.ih" A2x &A2x::operator=(char const *txt) { clear(); // very important!!! If a previous conversion // failed, the object will remain useless // until executing this statement str(txt); return *this; } bobcat-5.09.01/a2x/optype.f0000644000175000017500000000012014050437223014256 0ustar frankfranktemplate inline A2x::operator Type() { return to(); } bobcat-5.09.01/a2x/a2x4.f0000644000175000017500000000010714050437223013521 0ustar frankfrankinline A2x::A2x(A2x &&tmp) : std::istringstream(std::move(tmp)) {} bobcat-5.09.01/a2x/a2x2.f0000644000175000017500000000012114050437223013513 0ustar frankfrankinline A2x::A2x(std::string const &str) : std::istringstream(str.c_str()) {} bobcat-5.09.01/a2x/a2x3.f0000644000175000017500000000011314050437223013515 0ustar frankfrankinline A2x::A2x(A2x const &other) : std::istringstream(other.str()) {} bobcat-5.09.01/a2x/opis1.f0000644000175000017500000000014614050437223014001 0ustar frankfrankinline A2x &A2x::operator=(std::string const &str) { return operator=(str.c_str()); } bobcat-5.09.01/a2x/driver/0000755000175000017500000000000014050437223014071 5ustar frankfrankbobcat-5.09.01/a2x/driver/build0000755000175000017500000003553514050437223015131 0ustar frankfrank#!/usr/bin/icmake -qt/tmp/driver // script generated by the C++ icmake script version 2.13 /* Configurable defines for the build script: CLASSES: string of directory-names under which sources of classes are found. E.g., CLASSES = "class1 class2" All class-names must be stored in one string. If classes are removed from the CLASSES definition or if the names in the CLASSES definition are reordered, the compilation should start again from scratch. */ string CLASSES; void setClasses() { // ADD ADDITIONAL DIRECTORIES CONTAINING SOURCES OF CLASSES HERE // Use the construction `CLASSES += "classname1 classname2";' etc. CLASSES += " "; } /* Default values for the following variables are found in $IM/default/defines.im BUILD_LIBRARY: define this if you want to create a library for the object modules. Undefined by default: so NO LIBRARY IS BUILT. This links ALL object files to a program, which is a faster process than linking to a library. But it can bloat the executable: all o-modules, rather than those that are really used, become part of the program's code. BUILD_PROGRAM: define if a program is to be built. If not defined, library maintenance is assumed (default: defined). COMPILER: The compiler to use. COPT: C-options used by COMPILER ECHO_REQUEST: ON (default) if command echoing is wanted, otherwise: set to OFF GDB: define if gdb-symbolic debug information is wanted (not defined by default) LIBS: Extra libraries used for linking LIBPATH: Extra library-searchpaths used for linking QT: Define this (default: to "qt") if the unthreaded QT library is used. Define as "qt-mt" if the threaded QT library is used. If set, header files are grepped for the occurrence of the string '^[[:space:]]*Q_OBJECT[[:space:]]*$'. If found, moc -o moc.cc .h is called if the moc-file doesn't exist or is older than the .h file. Also, if defined the proper QT library is linked, assuming that the library is found in the ld-search path (E.g., see the environment variable $LIBRARY_PATH). Note that namespaces are NOT part of the build-script: they are only listed below for convenience. When they must be altered, the defaults must be changed in $IM/default/defines.im RELINK: Defined by default, causing a program to be relinked every time the script is called. Do not define it if relinking should only occur if a source is compiled. No effect for library maintenance. Current values: */ //#define BUILD_LIBRARY #define BUILD_PROGRAM #define COMPILER "g++" #define COPT "-Wall" #define ECHO_REQUEST 1 //#define GDB "-g" #define LIBS "bobcat" #define LIBPATH "" // local namespace is: FBB // using-declarations generated for: std:FBB // qt-mt can be used to select the threaded QT library //#define QT "qt" // NO CONFIGURABLE PARTS BELOW THIS LINE /* V A R S . I M */ string // contain options for cwd, // current WD libs, // extra libs, e.g., "-lrss -licce" libpath, // extra lib-paths, eg, "-L../rss" copt, // Compiler options lopt, // Linker options libxxx, // full library-path ofiles, // wildcards for o-files sources, // sources to be used current; // contains name of current dir. int nClasses, // number of classes/subdirectories program; // 1: program is built list classes; // list of classes/directories /* parser.im */ void parser() { #ifdef GRAMBUILD chdir("parser/gramspec"); system("grambuild"); chdir(".."); if ( exists("grammar") && "grammar" younger "parser.cc" ) // new parser needed { exec("bison++", "-d", "-o", "parser.cc", "grammar"); printf("Note: the compilation of parser.cc may produce " "several compiler warnings.\n"); } chdir(".."); #endif } /* S C A N N E R . I M */ void scanner() { string interactive; #ifdef INTERACTIVE interactive = "-I"; #endif #ifdef GRAMBUILD chdir("scanner"); if ( // new lexer needed exists("lexer") && ( "lexer" younger "yylex.cc" || "../parser/parser.h" younger "yylex.cc" ) ) { exec("flex++", interactive, "-oyylex.cc", "lexer"); printf("Note: the compilation of yylex.cc may produce " "several compiler warnings.\n"); } chdir(".."); #endif } /* I N I T I A L . I M */ void initialize() { echo(ECHO_REQUEST); sources = "*.cc"; ofiles = "o/*.o"; // std set of o-files copt = COPT; #ifdef GDB copt += " " + GDB; #endif #ifdef BUILD_PROGRAM program = 1; #else program = 0; #endif; cwd = chdir("."); #ifdef GRAMBUILD CLASSES = "parser scanner "; if (exists("parser")) // subdir parser exists parser(); if (exists("scanner")) // subdir scannerexists scanner(); #endif setClasses(); // remaining classes classes = strtok(CLASSES, " "); // list of classes nClasses = sizeof(classes); } /* M O C . I M */ void moc(string class) { string hfile; string mocfile; int ret; hfile = class + ".h"; mocfile = "moc" + class + ".cc"; if ( hfile younger mocfile // no mocfile or younger h file && // and Q_OBJECT found in .h file !system(P_NOCHECK, "grep '^[[:space:]]*Q_OBJECT[;[:space:]]*$' " + hfile) ) // then call moc. system("moc -o " + mocfile + " " + hfile); } /* O B J F I L E S . I M */ list objfiles(list files) { string file, objfile; int i; for (i = 0; i < sizeof(files); i++) { file = element(i, files); // determine element of the list objfile = "./o/" + change_ext(file, "o"); // make obj-filename if (objfile younger file) // objfile is younger { files -= (list)file; // remove the file from the list i--; // reduce i to test the next } } return (files); } /* A L T E R E D . I M */ list altered(list files, string target) { int i; string file; for (i = 0; i < sizeof(files); i++) // try all elements of the list { file = element(i, files); // use element i of the list if (file older target) // a file is older than the target { files -= (list)file; // remove the file from the list i--; // reduce i to inspect the next } // file of the list } return (files); // return the new list } /* F I L E L I S T . I M */ list file_list(string type, string library) { list files; files = makelist(type); // make all files of certain type #ifdef BUILD_LIBRARY files = altered(files, library); // keep all files newer than lib. #endif files = objfiles(files); // remove if younger .obj exist return (files); } /* L I N K . I M */ void link(string library, string exe) { printf("\n"); exec(COMPILER, "-o", exe, #ifdef BUILD_LIBRARY "-l" + library, #else ofiles, #endif libs, #ifdef GRAMBUILD "-lfl", #endif #ifdef QT "-l" + QT, #endif "-L.", libpath, lopt #ifndef GDB , "-s" #endif ); printf("ok: ", exe, "\n"); } /* P R E F I X C L . I M */ void prefix_class(string class_id) { list o_files; string o_file; int i; chdir("o"); o_files = makelist("*.o"); for (i = 0; o_file = element(i, o_files); i++) exec("mv", o_file, class_id + o_file); chdir(".."); } /* R M C L A S S P . I M */ #ifdef BUILD_LIBRARY string rm_class_id(string class_id, string ofile) { string ret; int index, n; n = strlen(ofile); for (index = strlen(class_id); index < n; index++) ret += element(index, ofile); return ret; } #endif void rm_class_prefix(string class_id) { #ifdef BUILD_LIBRARY list o_files; string o_file; int i; chdir("o"); o_files = makelist("*.o"); for (i = 0; o_file = element(i, o_files); i++) exec("mv", o_file, rm_class_id(class_id, o_file)); chdir(".."); #endif } /* C C O M P I L E . I M */ void c_compile(list cfiles) { string nextfile; int i; if (!exists("o")) system("mkdir o"); if (sizeof(cfiles)) // files to compile ? { printf("\ncompiling: ", current, "\n\n"); // compile all files separately for (i = 0; nextfile = element(i, cfiles); i++) exec(COMPILER, "-c -o o/" + change_ext(nextfile, "o"), copt, nextfile); printf("\n"); } printf("ok: ", current, "\n"); } /* U P D A T E L I . I M */ void updatelib(string library) { #ifdef BUILD_LIBRARY list arlist, objlist; string to, from; objlist = makelist("o/*.o"); if (!sizeof(objlist)) return; printf("\n"); exec("ar", "rvs", library, "o/*.o"); exec("rm", "o/*.o"); printf("\n"); #endif } /* S T D C P P . I M */ void std_cpp(string library) { list cfiles; cfiles = file_list(sources, library); // make list of all cpp-files c_compile(cfiles); // compile cpp-files } /* C P P M A K E . C CPP files are processed by stdmake. Arguments of CPPMAKE: cpp_make( string mainfile, : name of the main .cpp file, or "" for library maintenance string library, : name of the local library to use/create (without lib prefix or .a/.so suffix (E.g., use `main' for `libmain.a') string exe, : (path) name of the exe file to create ) Both mainfile and library MUST be in the current directory */ void cpp_make(string mainfile, string library, string exe) { int index; string class; if (nClasses) ofiles += " */o/*.o"; // set ofiles for no LIBRARY use // make library name #ifdef BUILD_LIBRARY libxxx = chdir(".") + "lib" + library + ".a"; #endif // first process all classes for (index = 0; index < nClasses; index++) { class = element(index, classes); // next class to process chdir(class); // change to directory current = "subdir " + class; #ifdef QT moc(class); // see if we should call moc #endif std_cpp(libxxx); // compile all files chdir(cwd); // go back to parent dir } current = "auxiliary " + sources + " files"; std_cpp(libxxx); // compile all files in current dir #ifdef BUILD_LIBRARY // prefix class-number for .o files for (index = 0; index < nClasses; index++) { current = element(index, classes); // determine class name chdir( current); // chdir to a class directory. prefix_class((string)index); updatelib(libxxx); chdir(cwd); // go back to parent dir } current = ""; // no class anymore updatelib(libxxx); // update lib in current dir #endif if (mainfile != "") // mainfile -> do link { link(library, exe); printf ( "\nProgram construction completed.\n" "\n" ); } } /* S E T L I B S . I M */ void setlibs() { #ifdef LIBS int n, index; list cut; cut = strtok(LIBS, " "); // cut op libraries n = sizeof(cut); for (index = 0; index < n; index++) libs += " -l" + element(index, cut); #ifdef GRAMBUILD libs += " -lfl"; #endif cut = strtok(LIBPATH, " "); // cut up the paths n = sizeof(cut); for (index = 0; index < n; index++) libpath += " -L" + element(index, cut); #endif } void main() { initialize(); setlibs(); #ifdef BUILD_PROGRAM cpp_make ( "driver.cc", // program source "driver", // static program library "driver" // binary program ); #else cpp_make ( "", "driver", // static- or so-library "" ); #endif } bobcat-5.09.01/a2x/driver/driver.cc0000644000175000017500000000117114050437223015673 0ustar frankfrank/* driver.cc */ #include #include "../a2x" using namespace std; using namespace FBB; int main(int argc, char **argv) { int x = A2x("12"); cout << x << endl; cout << x << endl; A2x a2x("12.50"); double d; d = a2x; cout << d << endl; A2x("12.345") >> d; cout << d << endl; cout << "Again: " << A2x("12.345").to() << endl; a2x = "err"; d = a2x; // d now 0 cout << d << endl; a2x = " a"; char c = a2x; // c now 'a' cout << c << endl; } /* Output: 12 12.5 12.345 0 a */ bobcat-5.09.01/align/0000755000175000017500000000000014050437223013176 5ustar frankfrankbobcat-5.09.01/align/col.f0000644000175000017500000000006714050437223014125 0ustar frankfrankinline size_t Align::col() const { return d_col; } bobcat-5.09.01/align/setmanip.f0000644000175000017500000000011014050437223015155 0ustar frankfrankinline void Align::setManip(Manipulator manip) { d_manip = manip; } bobcat-5.09.01/align/align0.cc0000644000175000017500000000020314050437223014652 0ustar frankfrank#include "align.ih" Align::Align(int row, size_t col, Manipulator manip) : d_row(row), d_col(col), d_manip(manip) {} bobcat-5.09.01/align/hasrow.f0000644000175000017500000000007614050437223014653 0ustar frankfrankinline bool Align::hasRow() const { return d_row != -1; } bobcat-5.09.01/align/setwidth.f0000644000175000017500000000007714050437223015204 0ustar frankfrankinline void Align::setWidth(size_t size) { d_col = size; } bobcat-5.09.01/align/opsizet.f0000644000175000017500000000007414050437223015043 0ustar frankfrankinline Align::operator size_t() const { return d_col; } bobcat-5.09.01/align/align0000644000175000017500000000206114050437223014212 0ustar frankfrank#ifndef INCLUDED_BOBCAT_ALIGN_ #define INCLUDED_BOBCAT_ALIGN_ #include namespace FBB { typedef std::ios_base &(*Manipulator)(std::ios_base &); #include "center.f" class Align { int d_row; // -1 or the row index to align size_t d_col; // acts as field width when setting the width of // an element. Manipulator d_manip; public: Align(int row, size_t column, Manipulator manip); Align(size_t col = 0, Manipulator manip = std::right); explicit Align(Manipulator manip); bool hasRow() const; operator size_t() const; // .f size_t col() const; // .f size_t row() const; // .f Manipulator manip() const; // .f void setWidth(size_t width); // .f void setManip(Manipulator manip); // .f }; #include "opsizet.f" #include "col.f" #include "row.f" #include "hasrow.f" #include "manip.f" #include "setmanip.f" #include "setwidth.f" } // FBB #endif bobcat-5.09.01/align/align2.cc0000644000175000017500000000015214050437223014657 0ustar frankfrank#include "align.ih" Align::Align(Manipulator manip) : d_row(-1), d_col(0), d_manip(manip) {} bobcat-5.09.01/align/manip.f0000644000175000017500000000010014050437223014440 0ustar frankfrankinline Manipulator Align::manip() const { return d_manip; } bobcat-5.09.01/align/row.f0000644000175000017500000000006714050437223014157 0ustar frankfrankinline size_t Align::row() const { return d_row; } bobcat-5.09.01/align/align.ih0000644000175000017500000000007414050437223014613 0ustar frankfrank#include "align" using namespace std; using namespace FBB; bobcat-5.09.01/align/center.f0000644000175000017500000000011314050437223014620 0ustar frankfrankinline std::ios_base ¢er(std::ios_base &stream) { return stream; } bobcat-5.09.01/align/align1.cc0000644000175000017500000000017114050437223014657 0ustar frankfrank#include "align.ih" Align::Align(size_t col, Manipulator manip) : d_row(-1), d_col(col), d_manip(manip) {} bobcat-5.09.01/arg/0000755000175000017500000000000014050437223012655 5ustar frankfrankbobcat-5.09.01/arg/option3.cc0000644000175000017500000000111214050437223014552 0ustar frankfrank#include "arg.ih" size_t Arg__::option(size_t idx, string *value, int optChar) const { ISVMapIterator it = d_optv.find(optChar); if (it == d_optv.end()) return 0; size_t ret = it->second.size(); // size of the value-vector if (idx < ret && value) // if the idx is within range and *value = it->second[idx]; // value requested, return it. return ret; // return this option count. } size_t Arg::option(size_t idx, string *value, int optChar) const { return d_ptr->option(idx, value, optChar); } bobcat-5.09.01/arg/option4.cc0000644000175000017500000000054114050437223014560 0ustar frankfrank#include "arg.ih" size_t Arg__::option(size_t *idx, string *value, int optChar) const { ISVMapIterator it = d_optv.find(optChar); if (it == d_optv.end()) return 0; return firstNonEmpty(idx, value, it->second); } size_t Arg::option(size_t *idx, string *value, int optChar) const { return d_ptr->option(idx, value, optChar); } bobcat-5.09.01/arg/instance.cc0000644000175000017500000000022514050437223014767 0ustar frankfrank#include "arg.ih" Arg &Arg::instance() { if (!s_arg) throw Exception{} << "Arg::instance(): not yet initialized"; return *s_arg; } bobcat-5.09.01/arg/longoption1.cc0000644000175000017500000000022014050437223015427 0ustar frankfrank#include "arg.ih" LongOption__::LongOption__(char const *name, Type type) : d_name(name), d_type(type), d_optionChar(0) {} bobcat-5.09.01/arg/data.cc0000644000175000017500000000032614050437223014076 0ustar frankfrank#include "arg.ih" Arg *Arg::s_arg; string Arg__::s_dirsep("/"); char Arg__::s_optChar[] = " "; char const Arg::s_alreadyInitialized[] = "Arg::initialize(): already initialized"; bobcat-5.09.01/arg/longoption2.cc0000644000175000017500000000023614050437223015437 0ustar frankfrank#include "arg.ih" LongOption__::LongOption__(char const *name, int optionChar) : d_name(name), d_type(AsCharOption), d_optionChar(optionChar) {} bobcat-5.09.01/arg/arg2.cc0000644000175000017500000000675114050437223014030 0ustar frankfrank#include "arg.ih" // accept: use -'accept' instead of -- // opstring[0] == '+': accept undefined options namespace { char dashes[] = "--"; } Arg__::Arg__(int accept, char const *optstring, LongOption const *const begin, LongOption const *const end, int argc, char **argv) : d_argv0(argv[0]), d_argPointer(0) { string dashesArg; if (accept == 0) d_dashes = find(argv, argv + argc, string{ "--" } ) - argv; else { char acceptOpt[] = { '-', static_cast(accept), 0 }; d_dashes = find_if(argv, argv + argc, [&](string const &arg) { return arg.find(acceptOpt) == 0; } ) - argv; if (d_dashes != argc) { dashesArg = argv[d_dashes]; argv[d_dashes] = dashes; } } setBasename(); bool acceptUnspecified = *optstring == '+'; // accept unspecified opts if (acceptUnspecified) // and skip over the '+' ++optstring; string opts(*optstring == ':' ? "" : ":"); // ensure initial char is ':' // (returns : when a required argument is // missing) opts += optstring; OptStructArray optStructs(end - begin + 1); // create array of n + 1 // structs for long options fillLongOptions(optStructs.get(), optstring, begin, end); int longOptionIndex; // receives the index of the long options opterr = 0; // prevent getopt() msgs to stderr while (true) { d_getOpt = getopt_long(argc, argv, opts.c_str(), optStructs.get(), &longOptionIndex); switch (d_getOpt) { case -1: { d_dashes += (d_dashes != argc) - optind; copy(argv + optind, argv + optind + d_dashes, back_inserter(d_argv)); size_t idx = d_argv.size(); if (not dashesArg.empty()) d_argv.push_back(dashesArg); copy(argv + optind + d_dashes, argv + argc, back_inserter(d_argv)); d_dashes = idx; } return; case ':': s_optChar[0] = optopt; d_msg = (optopt ? s_optChar : argv[optind - 1]); return; case '?': if (acceptUnspecified) { if (optopt == 0) d_argv.push_back(argv[optind - 1]); else d_argv.push_back( string{ '-', static_cast(optopt) } ); break; } s_optChar[0] = optopt; d_msg = (optopt ? s_optChar : argv[optind - 1]); return; case 0: if (plainLongOption(begin[longOptionIndex])) break; [[fallthrough]]; // FALLING THROUGH IF LONG OPTION IS ALSO SHORT CHAR OPTION // in which case d_getOpt is set to the corresponding short // char option default: addCharOption(); break; } } } bobcat-5.09.01/arg/initialize2.cc0000644000175000017500000000040714050437223015410 0ustar frankfrank#include "arg.ih" Arg &Arg::initialize(int accept, char const *optstring, int argc, char **argv) { if (s_arg) throw Exception{} << s_alreadyInitialized; s_arg = new Arg(accept, optstring, 0, 0, argc, argv); return *s_arg; } bobcat-5.09.01/arg/opindex.f0000644000175000017500000000016214050437223014471 0ustar frankfrankinline char const *Arg__::operator[](size_t idx) const { return (idx >= nArgs()) ? 0 : d_argv[idx].c_str(); } bobcat-5.09.01/arg/operatorindex.cc0000644000175000017500000000014014050437223016042 0ustar frankfrank#include "arg.ih" char const *Arg::operator[](size_t idx) const { return (*d_ptr)[idx]; } bobcat-5.09.01/arg/beyonddashes.f0000644000175000017500000000012114050437223015466 0ustar frankfrank//inline int Arg__::beyondDashes() const //{ // return d_beyondDashes; //} // bobcat-5.09.01/arg/initialize1.cc0000644000175000017500000000034614050437223015411 0ustar frankfrank#include "arg.ih" Arg &Arg::initialize(char const *optstring, int argc, char **argv) { if (s_arg) throw Exception{} << s_alreadyInitialized; s_arg = new Arg(0, optstring, 0, 0, argc, argv); return *s_arg; } bobcat-5.09.01/arg/nlongoptions.f0000644000175000017500000000010214050437223015546 0ustar frankfrankinline size_t Arg__::nLongOptions() const { return d_nOptv; } bobcat-5.09.01/arg/plainlongoption.cc0000644000175000017500000000065414050437223016405 0ustar frankfrank#include "arg.ih" bool Arg__::plainLongOption(Arg__::LongOption const &longOption) { addLongOption(longOption.d_name); // calls 1.cc if (!longOption.d_optionChar) // it's a plain long option. return true; d_getOpt = longOption.d_optionChar; return false; // not a plain long option: // it's also a simple option. } bobcat-5.09.01/arg/initialize3.cc0000644000175000017500000000053214050437223015410 0ustar frankfrank#include "arg.ih" Arg &Arg::initialize(char const *optstring, LongOption const *const begin, LongOption const *const end, int argc, char **argv) { if (s_arg) throw Exception{} << s_alreadyInitialized; s_arg = new Arg(0, optstring, begin, end, argc, argv); return *s_arg; } bobcat-5.09.01/arg/end.cc0000644000175000017500000000015014050437223013726 0ustar frankfrank#include "arg.ih" vector::const_iterator Arg::end() const { return d_ptr->d_argv.end(); } bobcat-5.09.01/arg/argpointers2.cc0000644000175000017500000000013714050437223015604 0ustar frankfrank#include "arg.ih" char const **Arg::argPointers() const { return d_ptr->argPointers(); } bobcat-5.09.01/arg/filllongoptions.cc0000644000175000017500000000056014050437223016407 0ustar frankfrank#include "arg.ih" void Arg__::fillLongOptions(OptStruct *optStruct, std::string const &optString, LongOption const * const begin, LongOption const * const end) { for (LongOption const *it = begin; it != end; ++it, ++optStruct) addLongOption(optStruct, optString, *it); } bobcat-5.09.01/arg/longname.f0000644000175000017500000000012014050437223014615 0ustar frankfrankinline std::string const &LongOption__::longName() const { return d_name; } bobcat-5.09.01/arg/arg0000644000175000017500000001046714050437223013361 0ustar frankfrank#ifndef INCLUDED_BOBCAT_ARG_ #define INCLUDED_BOBCAT_ARG_ /* Singleton Class built around getopt() and getopt_long() (3) */ #include #include #include namespace FBB { class ArgTypes__ { protected: typedef struct option OptStruct; typedef std::vector StringVector; public: enum Type { None = 0, Required = 1, Optional = 2, AsCharOption, }; }; class LongOption__: public ArgTypes__ { friend class Arg__; friend class ArgConfig; std::string d_name; Type d_type; int d_optionChar; public: explicit LongOption__(char const *name); LongOption__(char const *name, Type type); LongOption__(char const *name, int optionChar); std::string const &longName() const; // .f int optionChar() const; // .f }; class Arg__; class Arg: public ArgTypes__ { friend class ArgConfig; // accesses the constructors and // longOption() Arg__ *d_ptr; // pointer to the implementation static Arg *s_arg; // points to Singleton Arg static char const s_alreadyInitialized[]; public: Arg(Arg const &other) = delete; typedef FBB::LongOption__ LongOption; typedef std::vector> OptVect; // 1 static Arg &initialize(char const *optstring, int argc, char **argv); static Arg &initialize(int accept, // 2 char const *optstring, int argc, char **argv); static Arg &initialize(char const *optstring, // 3 LongOption const *const begin, LongOption const *const end, int argc, char **argv); static Arg &initialize(int accept, char const *optstring, // 4 LongOption const *const begin, LongOption const *const end, int argc, char **argv); static Arg &instance(); std::string const &argv0() const; std::string const &basename() const; void help() const; size_t nArgs() const; size_t beyondDashes() const; std::vector const &args() const; std::vector::const_iterator begin() const; std::vector::const_iterator end() const; // total number of specified short (and combined long) options size_t nOptions() const; // total numer of long-only options specified size_t nLongOptions() const; size_t option(int option) const; // 1 size_t option(std::string const &optchars) const; // 2 size_t option(size_t idx, std::string *value, int option) const; // 3 size_t option(size_t *idx, std::string *value, int option) const; // 4 size_t option(size_t idx, std::string *value, char const *longOption) const; // 5 size_t option(size_t *idx, std::string *value, char const *longOption) const; // 6 size_t option(std::string *value, int optChar) const; // 1.f // 2.f size_t option(std::string *value, char const *longOption) const; char const *operator[](size_t idx) const; void versionHelp(void (*usage)(std::string const &progname), char const *version, size_t minArgs, int helpFlag = 'h', int versionFlag = 'v') const; char const **argPointers(); // 1.cc char const **argPointers() const; // 2.cc protected: Arg(int accept, char const *optstring, // 1 LongOption const *const begin, LongOption const *const end, int argc, char **argv); }; #include "longname.f" #include "optionchar.f" #include "option1.f" #include "option2.f" } // FBB #endif bobcat-5.09.01/arg/addcharoption.cc0000644000175000017500000000017014050437223016001 0ustar frankfrank#include "arg.ih" void Arg__::addCharOption() { d_optv[d_getOpt].push_back(optarg ? optarg : ""); ++d_nOptv; } bobcat-5.09.01/arg/begin.cc0000644000175000017500000000015314050437223014247 0ustar frankfrank#include "arg.ih" vector::const_iterator Arg::begin() const { return d_ptr->d_argv.begin(); } bobcat-5.09.01/arg/noptions.cc0000644000175000017500000000012314050437223015031 0ustar frankfrank#include "arg.ih" size_t Arg::nOptions() const { return d_ptr->nOptions(); } bobcat-5.09.01/arg/basename.cc0000644000175000017500000000014014050437223014732 0ustar frankfrank#include "arg.ih" std::string const &Arg::basename() const { return d_ptr->basename(); } bobcat-5.09.01/arg/initialize4.cc0000644000175000017500000000055314050437223015414 0ustar frankfrank#include "arg.ih" Arg &Arg::initialize(int accept, char const *optstring, LongOption const *const begin, LongOption const *const end, int argc, char **argv) { if (s_arg) throw Exception{} << s_alreadyInitialized; s_arg = new Arg(accept, optstring, begin, end, argc, argv); return *s_arg; } bobcat-5.09.01/arg/setoptiontype.cc0000644000175000017500000000103214050437223016106 0ustar frankfrank#include "arg.ih" int Arg__::setOptionType(string const &optString, LongOption const &longOption) { string::size_type pos = optString.find_first_of(longOption.d_optionChar); if (pos == string::npos) throw Exception(EINVAL) << "Arg__::setOptionType()" << ": short option `" << static_cast(longOption.d_optionChar) << "' not found"; return optString[pos + 1] == ':' ? Required : None; } bobcat-5.09.01/arg/help.cc0000644000175000017500000000033514050437223014115 0ustar frankfrank#include "arg.ih" void Arg__::help() const { if (d_usage == 0) throw Exception{} << "Arg::help() called, but no usage available"; (*d_usage)(basename()); } void Arg::help() const { d_ptr->help(); } bobcat-5.09.01/arg/optionchar.f0000644000175000017500000000011114050437223015163 0ustar frankfrankinline int LongOption__::optionChar() const { return d_optionChar; } bobcat-5.09.01/arg/arg1.cc0000644000175000017500000000054214050437223014017 0ustar frankfrank#include "arg.ih" // accept: use -'accept' instead of -- // opstring[0] == '+': accept undefined options Arg::Arg(int accept, char const *optstring, LongOption const * const begin, LongOption const * const end, int argc, char **argv) : d_ptr(new Arg__(accept, optstring, begin, end, argc, argv)) { d_ptr->verify(); } bobcat-5.09.01/arg/argpointers1.cc0000644000175000017500000000013114050437223015575 0ustar frankfrank#include "arg.ih" char const **Arg::argPointers() { return d_ptr->argPointers(); } bobcat-5.09.01/arg/nargs.cc0000644000175000017500000000011514050437223014273 0ustar frankfrank#include "arg.ih" size_t Arg::nArgs() const { return d_ptr->nArgs(); } bobcat-5.09.01/arg/basename.f0000644000175000017500000000011114050437223014570 0ustar frankfrankinline std::string const &Arg__::basename() const { return d_base; } bobcat-5.09.01/arg/beyonddashes.cc0000644000175000017500000000012514050437223015632 0ustar frankfrank#include "arg.ih" size_t Arg::beyondDashes() const { return d_ptr->d_dashes; } bobcat-5.09.01/arg/noptions.f0000644000175000017500000000007614050437223014700 0ustar frankfrankinline size_t Arg__::nOptions() const { return d_nOptv; } bobcat-5.09.01/arg/firstnonempty.cc0000644000175000017500000000073214050437223016107 0ustar frankfrank#include "arg.ih" size_t Arg__::firstNonEmpty(size_t *idx, string *value, StringVector const &sv) const { StringVector::const_iterator sit = find_if(sv.begin(), sv.end(), bind2nd(not_equal_to(), "")); if (sit == sv.end()) *idx = sv.size(); else { *idx = sit - sv.begin(); if (value != 0) *value = *sit; } return sv.size(); } bobcat-5.09.01/arg/option2.cc0000644000175000017500000000045514050437223014562 0ustar frankfrank#include "arg.ih" size_t Arg__::option(std::string const &optchars) const { size_t count = 0; for (char const *cp = optchars.c_str(); *cp; ++cp) count += option(*cp); return count; } size_t Arg::option(std::string const &optchars) const { return d_ptr->option(optchars); } bobcat-5.09.01/arg/option1.f0000644000175000017500000000020014050437223014405 0ustar frankfrankinline size_t Arg::option(std::string *value, int optChar) const { return option(static_cast(0), value, optChar); } bobcat-5.09.01/arg/option2.f0000644000175000017500000000021614050437223014415 0ustar frankfrankinline size_t Arg::option(std::string *value, char const *longOption) const { return option(static_cast(0), value, longOption); } bobcat-5.09.01/arg/argpointers3.cc0000644000175000017500000000023614050437223015605 0ustar frankfrank#include "arg.ih" char const **Arg__::argPointers() const { if (!d_argPointer) d_argPointer = String::argv(d_argv); return d_argPointer; } bobcat-5.09.01/arg/option6.cc0000644000175000017500000000057014050437223014564 0ustar frankfrank#include "arg.ih" size_t Arg__::option(size_t *idx, string *value, char const *longOpt) const { SSVMapIterator it = d_longOptv.find(longOpt); if (it == d_longOptv.end()) return 0; return firstNonEmpty(idx, value, it->second); } size_t Arg::option(size_t *idx, string *value, char const *longOpt) const { return d_ptr->option(idx, value, longOpt); } bobcat-5.09.01/arg/nlongoptions.cc0000644000175000017500000000013314050437223015712 0ustar frankfrank#include "arg.ih" size_t Arg::nLongOptions() const { return d_ptr->nLongOptions(); } bobcat-5.09.01/arg/argv0.cc0000644000175000017500000000013214050437223014177 0ustar frankfrank#include "arg.ih" std::string const &Arg::argv0() const { return d_ptr->d_argv0; } bobcat-5.09.01/arg/addlongoption2.cc0000644000175000017500000000132414050437223016107 0ustar frankfrank#include "arg.ih" /* called by fillLongOption() to create the array of `struct option' (OptStruct) elements to be interpreted by getopt_long() */ void Arg__::addLongOption(OptStruct *optStruct, string const &optString, LongOption const &longOption) { static int notUsed; optStruct->name = longOption.d_name.c_str(); if (longOption.d_optionChar) // existing option { optStruct->has_arg = setOptionType(optString, longOption); optStruct->flag = 0; optStruct->val = longOption.d_optionChar; } else { optStruct->has_arg = longOption.d_type, optStruct->flag = ¬Used; } } bobcat-5.09.01/arg/args.cc0000644000175000017500000000013114050437223014113 0ustar frankfrank#include "arg.ih" vector const &Arg::args() const { return d_ptr->d_argv; } bobcat-5.09.01/arg/longoption0.cc0000644000175000017500000000020514050437223015431 0ustar frankfrank#include "arg.ih" LongOption__::LongOption__(char const *name) : d_name(name), d_type(None), d_optionChar(0) {} bobcat-5.09.01/arg/versionhelp.cc0000644000175000017500000000131614050437223015523 0ustar frankfrank#include "arg.ih" void Arg__::versionHelp(void (*usage)(string const &progname), char const *version, size_t minArgs, int helpFlag, int versionFlag) const { d_usage = usage; if (option(helpFlag)) { usage(basename()); throw 0; } if (option(versionFlag)) { cout << basename() << " V" << version << '\n'; throw 0; } if (nArgs() < minArgs) { usage(basename()); throw 1; } } void Arg::versionHelp(void (*usage)(string const &progname), char const *version, size_t minArgs, int helpFlag, int versionFlag) const { return d_ptr->versionHelp(usage, version, minArgs, helpFlag, versionFlag); } bobcat-5.09.01/arg/option5.cc0000644000175000017500000000122214050437223014556 0ustar frankfrank#include "arg.ih" size_t Arg__::option(size_t idx, string *value, char const *longOption) const { SSVMapIterator it = d_longOptv.find(longOption); if (it == d_longOptv.end()) return 0; size_t ret = it->second.size(); // size of the value-vector if (idx < ret && value) // if the idx is within range and *value = it->second[idx]; // value requested, return it. return ret; // return this option count. } size_t Arg::option(size_t idx, string *value, char const *longOption) const { return d_ptr->option(idx, value, longOption); } bobcat-5.09.01/arg/arg.ih0000644000175000017500000001264714050437223013762 0ustar frankfrank#include "arg" #include #include #include #include #include #include "../exception/exception" #include "../string/string" #include "../iuo/iuo" namespace FBB { class Arg__: public ArgTypes__ { friend Arg; typedef FBB::LongOption__ LongOption; typedef struct option OptStruct; typedef std::vector StringVector; typedef std::unordered_map IntStringVectorMap; typedef IntStringVectorMap::const_iterator ISVMapIterator; typedef std::unordered_map StringStringVectorMap; typedef StringStringVectorMap::const_iterator SSVMapIterator; std::string d_argv0; std::string d_base; mutable char const **d_argPointer; std::vector d_argv; // remaining arguments // after removing the // options IntStringVectorMap d_optv; // short (and associated // long options). // 1st value: option char; // 2nd value: optionvalue // or empty string. size_t d_nOptv; // count of ALL of the // previous options StringStringVectorMap d_longOptv; // specified long options size_t d_nLongOptions; // count of ALL of the // following options char const *d_msg; // info about erroneous opt. int d_getOpt; // value returned by getopt() int d_dashes; // idx of the -- or // d_argv.size() mutable void (*d_usage)(std::string const &) = 0; static std::string s_dirsep; static char s_optChar[]; // used by the constructors public: std::vector const &argv() const; // remaining arguments // after removing the // options int beyondDashes() const; // .i std::string const &basename() const; // .i void help() const; size_t nArgs() const; // .i // total number of specified short (and combined long) options size_t nOptions() const; // .i // total numer of long-only options specified size_t nLongOptions() const; // .i size_t option(int option) const; // 1 size_t option(std::string const &optchars) const; // 2 size_t option(size_t idx, std::string *value, int option) const; // 3 size_t option(std::string *value, int optChar) const; size_t option(size_t *idx, std::string *value, int option) const; // 4 size_t option(size_t idx, std::string *value, char const *longOption) const; // 5 //size_t option(std::string *value, char const *longOption) const; size_t option(size_t *idx, std::string *value, char const *longOption) const; // 6 char const *operator[](size_t idx) const; void versionHelp(void (*usage)(std::string const &progname), char const *version, size_t minArgs, int helpFlag = 'h', int versionFlag = 'v') const; char const **argPointers() const; // 3.cc private: Arg__(Arg__ const &other) = delete; Arg__ &operator=(Arg const &other) = delete; friend class ArgConfig; // accesses the constructors and // longOption() Arg__(int accept, char const *optstring, // 2 LongOption const * const begin, LongOption const * const end, int argc, char **argv); void addCharOption(); // in d_getOpt void addLongOption(std::string const &longName); // 1 void addLongOption(OptStruct *optStructs, // 2 std::string const &optString, LongOption const &longOption); void verify(); size_t firstNonEmpty(size_t *idx, std::string *value, StringVector const &sv) const; void setBasename(); void fillLongOptions( OptStruct *optStructs, std::string const &optString, LongOption const * const begin, LongOption const * const end); bool plainLongOption(LongOption const &longOption); int setOptionType(std::string const &optString, LongOption const &longOption); }; //#include "beyonddashes.f" #include "basename.f" #include "nargs.f" #include "nlongoptions.f" #include "noptions.f" #include "opindex.f" } // FBB using namespace FBB; using namespace std; bobcat-5.09.01/arg/option1.cc0000644000175000017500000000036214050437223014556 0ustar frankfrank#include "arg.ih" size_t Arg__::option(int optChar) const { ISVMapIterator it = d_optv.find(optChar); return it == d_optv.end() ? 0 : it->second.size(); } size_t Arg::option(int optChar) const { return d_ptr->option(optChar); } bobcat-5.09.01/arg/verify.cc0000644000175000017500000000051514050437223014471 0ustar frankfrank#include "arg.ih" void Arg__::verify() { switch (d_getOpt) { case ':': throw Exception{1} << "ArgData::ArgData(): missing value for option: " << d_msg; case '?': throw Exception{1} << "ArgData::ArgData(): unknown option: " << d_msg; default: return; } } bobcat-5.09.01/arg/driver/0000755000175000017500000000000014050437223014150 5ustar frankfrankbobcat-5.09.01/arg/driver/build0000755000175000017500000000135714050437223015203 0ustar frankfrank#!/bin/bash ln -sf ../arg . ln -sf ../arg.ih . tput clear case $1 in (b) rm arg arg.ih g++ -DBOBCAT --static `cat ../../c++std` -I../../tmp -o driver driver.cc \ -L../../tmp/lib -lbobcat -s ;; (o) g++ `cat ../../c++std` -o driver *.cc ../tmp/o/*.o -lbobcat # -s ;; (c) g++ `cat ../../c++std` -o driver *.cc -lbobcat -s ;; (w) rm arg arg.ih g++ `cat ../../c++std` -I.. -o driver *.cc -L../tmp -larg -lbobcat -s ;; (*) echo $0 b links to bobcat built by 'build libraries all' echo $0 o links to the files in ../tmp/o echo $0 c links to the files in the current dir only echo $0 w links to libarg.a and the existing bobcat library ;; esac bobcat-5.09.01/arg/driver/driver.cc0000644000175000017500000000654314050437223015762 0ustar frankfrank/* driver.cc */ #include #include #include #include #ifdef BOBCAT #include #else #include "arg" #endif using namespace std; using namespace FBB; void optcheck(char c) { Arg &arg = Arg::instance(); if (size_t count = arg.option(c)) cout << "Saw option " << c << " " << count << " times" << '\n'; if (string("def").find(c) != string::npos) { string value; size_t idx; idx = arg.option(&value, c); cout << idx << " returned by option() for " "option " << c << ", which has value `" << value << "'\n"; size_t count = arg.option(&idx, &value, c); cout << count << " times option " << c << '\n'; if (idx == count) cout << "No non-empty option values" << '\n'; else { cout << "First non-empty option at " << idx << '\n'; for (size_t ix = 0; ix < count; ++ix) { arg.option(ix, &value, c); cout << ix << ": " << value << '\n'; } } } cout << '\n'; } void longopt(char const *longOpt) { string value; Arg &arg = Arg::instance(); size_t opt = arg.option(&value, longOpt); if (!opt) return; cout << longOpt << " " << opt << " times:\t" << (value.length() ? value : "-- no arg--") << '\n'; } void usage(string const &progname) { cout << "Usage: " << progname << " arg options\n" "where:\n" " arg: any argument\n" " options: any option from abcd:e:f:hv\n" " try options requiring arguments without specifying an " "argument\n" " try other options too. -h provides this help,\n" " -v provides the version\n" "Available long options:\n" " --optional, --extra (+ arg), --file (as -f),\n" " --version (as -v), --add (as -a)\n"; } namespace { } int main(int argc, char **argv) try { Arg::LongOption lo[] = { {"optional", Arg::Optional}, {"extra", Arg::Required}, {"none", Arg::None}, {"file", 'f'}, {"version", 'v'}, {"add", 'a'} }; try { Arg::initialize('t', "+abcd:e:f:hvt", lo, lo + 6, argc, argv); Arg &arg = Arg::instance(); cout << "dashed options start at index " << arg.beyondDashes() << endl; arg.versionHelp(usage, "0.00", 1); for_each("abcdefg", "abcdefg" + 7, optcheck) ; for (size_t idx = 0; idx < arg.nArgs(); idx++) cout << "Argument " << idx << " = " << arg[idx] << '\n'; cout << '\n'; cout << "Long options:\n" << dec; longopt("optional"); longopt("extra"); longopt("file"); longopt("add"); longopt("none"); } catch (exception const &e) { cout << e.what() << '\n'; } } catch (int x) { cout << "int exception caught, value = " << x << '\n'; return x; } catch (exception const &e) { cout << "Exception caught: " << e.what() << '\n'; return 1; } catch (...) { cout << "Unexpected exception caught, shouldn't happen\n"; return 1; } bobcat-5.09.01/arg/driver/l0000755000175000017500000000007714050437223014335 0ustar frankfrank#!/bin/bash g++ -o driver driver.o -L../tmp -larg -lbobcat -s bobcat-5.09.01/arg/driver/getoptlong/0000755000175000017500000000000014050437223016332 5ustar frankfrankbobcat-5.09.01/arg/driver/getoptlong/build0000755000175000017500000003555314050437223017372 0ustar frankfrank#!/usr/bin/icmake -qt/tmp/getoptlong // script generated by the C++ icmake script version 2.13 /* Configurable defines for the build script: CLASSES: string of directory-names under which sources of classes are found. E.g., CLASSES = "class1 class2" All class-names must be stored in one string. If classes are removed from the CLASSES definition or if the names in the CLASSES definition are reordered, the compilation should start again from scratch. */ string CLASSES; void setClasses() { // ADD ADDITIONAL DIRECTORIES CONTAINING SOURCES OF CLASSES HERE // Use the construction `CLASSES += "classname1 classname2";' etc. CLASSES += " "; } /* Default values for the following variables are found in $IM/default/defines.im BUILD_LIBRARY: define this if you want to create a library for the object modules. Undefined by default: so NO LIBRARY IS BUILT. This links ALL object files to a program, which is a faster process than linking to a library. But it can bloat the executable: all o-modules, rather than those that are really used, become part of the program's code. BUILD_PROGRAM: define if a program is to be built. If not defined, library maintenance is assumed (default: defined). COMPILER: The compiler to use. COPT: C-options used by COMPILER ECHO_REQUEST: ON (default) if command echoing is wanted, otherwise: set to OFF GDB: define if gdb-symbolic debug information is wanted (not defined by default) LIBS: Extra libraries used for linking LIBPATH: Extra library-searchpaths used for linking QT: Define this (default: to "qt") if the unthreaded QT library is used. Define as "qt-mt" if the threaded QT library is used. If set, header files are grepped for the occurrence of the string '^[[:space:]]*Q_OBJECT[[:space:]]*$'. If found, moc -o moc.cc .h is called if the moc-file doesn't exist or is older than the .h file. Also, if defined the proper QT library is linked, assuming that the library is found in the ld-search path (E.g., see the environment variable $LIBRARY_PATH). Note that namespaces are NOT part of the build-script: they are only listed below for convenience. When they must be altered, the defaults must be changed in $IM/default/defines.im RELINK: Defined by default, causing a program to be relinked every time the script is called. Do not define it if relinking should only occur if a source is compiled. No effect for library maintenance. Current values: */ //#define BUILD_LIBRARY #define BUILD_PROGRAM #define COMPILER "g++" #define COPT "-Wall" #define ECHO_REQUEST 1 //#define GDB "-g" #define LIBS "" #define LIBPATH "" // local namespace is: FBB // using-declarations generated for: std:FBB // qt-mt can be used to select the threaded QT library //#define QT "qt" // NO CONFIGURABLE PARTS BELOW THIS LINE /* V A R S . I M */ string // contain options for cwd, // current WD libs, // extra libs, e.g., "-lrss -licce" libpath, // extra lib-paths, eg, "-L../rss" copt, // Compiler options lopt, // Linker options libxxx, // full library-path ofiles, // wildcards for o-files sources, // sources to be used current; // contains name of current dir. int nClasses, // number of classes/subdirectories program; // 1: program is built list classes; // list of classes/directories /* parser.im */ void parser() { #ifdef GRAMBUILD chdir("parser/gramspec"); system("grambuild"); chdir(".."); if ( exists("grammar") && "grammar" younger "parser.cc" ) // new parser needed { exec("bison++", "-d", "-o", "parser.cc", "grammar"); printf("Note: the compilation of parser.cc may produce " "several compiler warnings.\n"); } chdir(".."); #endif } /* S C A N N E R . I M */ void scanner() { string interactive; #ifdef INTERACTIVE interactive = "-I"; #endif #ifdef GRAMBUILD chdir("scanner"); if ( // new lexer needed exists("lexer") && ( "lexer" younger "yylex.cc" || "../parser/parser.h" younger "yylex.cc" ) ) { exec("flex++", interactive, "-oyylex.cc", "lexer"); printf("Note: the compilation of yylex.cc may produce " "several compiler warnings.\n"); } chdir(".."); #endif } /* I N I T I A L . I M */ void initialize() { echo(ECHO_REQUEST); sources = "*.cc"; ofiles = "o/*.o"; // std set of o-files copt = COPT; #ifdef GDB copt += " " + GDB; #endif #ifdef BUILD_PROGRAM program = 1; #else program = 0; #endif; cwd = chdir("."); #ifdef GRAMBUILD CLASSES = "parser scanner "; if (exists("parser")) // subdir parser exists parser(); if (exists("scanner")) // subdir scannerexists scanner(); #endif setClasses(); // remaining classes classes = strtok(CLASSES, " "); // list of classes nClasses = sizeof(classes); } /* M O C . I M */ void moc(string class) { string hfile; string mocfile; int ret; hfile = class + ".h"; mocfile = "moc" + class + ".cc"; if ( hfile younger mocfile // no mocfile or younger h file && // and Q_OBJECT found in .h file !system(P_NOCHECK, "grep '^[[:space:]]*Q_OBJECT[;[:space:]]*$' " + hfile) ) // then call moc. system("moc -o " + mocfile + " " + hfile); } /* O B J F I L E S . I M */ list objfiles(list files) { string file, objfile; int i; for (i = 0; i < sizeof(files); i++) { file = element(i, files); // determine element of the list objfile = "./o/" + change_ext(file, "o"); // make obj-filename if (objfile younger file) // objfile is younger { files -= (list)file; // remove the file from the list i--; // reduce i to test the next } } return (files); } /* A L T E R E D . I M */ list altered(list files, string target) { int i; string file; for (i = 0; i < sizeof(files); i++) // try all elements of the list { file = element(i, files); // use element i of the list if (file older target) // a file is older than the target { files -= (list)file; // remove the file from the list i--; // reduce i to inspect the next } // file of the list } return (files); // return the new list } /* F I L E L I S T . I M */ list file_list(string type, string library) { list files; files = makelist(type); // make all files of certain type #ifdef BUILD_LIBRARY files = altered(files, library); // keep all files newer than lib. #endif files = objfiles(files); // remove if younger .obj exist return (files); } /* L I N K . I M */ void link(string library, string exe) { printf("\n"); exec(COMPILER, "-o", exe, #ifdef BUILD_LIBRARY "-l" + library, #else ofiles, #endif libs, #ifdef GRAMBUILD "-lfl", #endif #ifdef QT "-l" + QT, #endif "-L.", libpath, lopt #ifndef GDB , "-s" #endif ); printf("ok: ", exe, "\n"); } /* P R E F I X C L . I M */ void prefix_class(string class_id) { list o_files; string o_file; int i; chdir("o"); o_files = makelist("*.o"); for (i = 0; o_file = element(i, o_files); i++) exec("mv", o_file, class_id + o_file); chdir(".."); } /* R M C L A S S P . I M */ #ifdef BUILD_LIBRARY string rm_class_id(string class_id, string ofile) { string ret; int index, n; n = strlen(ofile); for (index = strlen(class_id); index < n; index++) ret += element(index, ofile); return ret; } #endif void rm_class_prefix(string class_id) { #ifdef BUILD_LIBRARY list o_files; string o_file; int i; chdir("o"); o_files = makelist("*.o"); for (i = 0; o_file = element(i, o_files); i++) exec("mv", o_file, rm_class_id(class_id, o_file)); chdir(".."); #endif } /* C C O M P I L E . I M */ void c_compile(list cfiles) { string nextfile; int i; if (!exists("o")) system("mkdir o"); if (sizeof(cfiles)) // files to compile ? { printf("\ncompiling: ", current, "\n\n"); // compile all files separately for (i = 0; nextfile = element(i, cfiles); i++) exec(COMPILER, "-c -o o/" + change_ext(nextfile, "o"), copt, nextfile); printf("\n"); } printf("ok: ", current, "\n"); } /* U P D A T E L I . I M */ void updatelib(string library) { #ifdef BUILD_LIBRARY list arlist, objlist; string to, from; objlist = makelist("o/*.o"); if (!sizeof(objlist)) return; printf("\n"); exec("ar", "rvs", library, "o/*.o"); exec("rm", "o/*.o"); printf("\n"); #endif } /* S T D C P P . I M */ void std_cpp(string library) { list cfiles; cfiles = file_list(sources, library); // make list of all cpp-files c_compile(cfiles); // compile cpp-files } /* C P P M A K E . C CPP files are processed by stdmake. Arguments of CPPMAKE: cpp_make( string mainfile, : name of the main .cpp file, or "" for library maintenance string library, : name of the local library to use/create (without lib prefix or .a/.so suffix (E.g., use `main' for `libmain.a') string exe, : (path) name of the exe file to create ) Both mainfile and library MUST be in the current directory */ void cpp_make(string mainfile, string library, string exe) { int index; string class; if (nClasses) ofiles += " */o/*.o"; // set ofiles for no LIBRARY use // make library name #ifdef BUILD_LIBRARY libxxx = chdir(".") + "lib" + library + ".a"; #endif // first process all classes for (index = 0; index < nClasses; index++) { class = element(index, classes); // next class to process chdir(class); // change to directory current = "subdir " + class; #ifdef QT moc(class); // see if we should call moc #endif std_cpp(libxxx); // compile all files chdir(cwd); // go back to parent dir } current = "auxiliary " + sources + " files"; std_cpp(libxxx); // compile all files in current dir #ifdef BUILD_LIBRARY // prefix class-number for .o files for (index = 0; index < nClasses; index++) { current = element(index, classes); // determine class name chdir( current); // chdir to a class directory. prefix_class((string)index); updatelib(libxxx); chdir(cwd); // go back to parent dir } current = ""; // no class anymore updatelib(libxxx); // update lib in current dir #endif if (mainfile != "") // mainfile -> do link { link(library, exe); printf ( "\nProgram construction completed.\n" "\n" ); } } /* S E T L I B S . I M */ void setlibs() { #ifdef LIBS int n, index; list cut; cut = strtok(LIBS, " "); // cut op libraries n = sizeof(cut); for (index = 0; index < n; index++) libs += " -l" + element(index, cut); #ifdef GRAMBUILD libs += " -lfl"; #endif cut = strtok(LIBPATH, " "); // cut up the paths n = sizeof(cut); for (index = 0; index < n; index++) libpath += " -L" + element(index, cut); #endif } void main() { initialize(); setlibs(); #ifdef BUILD_PROGRAM cpp_make ( "getoptlong.cc", // program source "getoptlong", // static program library "getoptlong" // binary program ); #else cpp_make ( "", "getoptlong", // static- or so-library "" ); #endif } bobcat-5.09.01/arg/driver/getoptlong/getoptlong.ih0000644000175000017500000000015214050437223021034 0ustar frankfrank#include "getoptlong.h" #include #include using namespace std; using namespace FBB; bobcat-5.09.01/arg/driver/getoptlong/getoptlong.h0000644000175000017500000000020014050437223020655 0ustar frankfrank#ifndef INCLUDED_GETOPTLONG_H_ #define INCLUDED_GETOPTLONG_H_ #include #include namespace FBB { } #endif bobcat-5.09.01/arg/driver/getoptlong/getoptlong.cc0000644000175000017500000000221314050437223021021 0ustar frankfrank#include "getoptlong.h" #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) { int value; opterr = 0; struct option longopts [] = { {"a-opt", 0, 0, 'a'}, {"one", 0, &value, 100}, {"two", 0, &value, 200}, {0, } }; while (true) { int c = getopt_long(argc, argv, "abc", longopts, 0); char ch = c; char co = optopt; switch (c) { case EOF: cout << "All processed\n"; return 0; case ':': cout << "ArgData::ArgData(): missing option value" << endl; break; case '?': cout << "ArgData::ArgData(): unknown option" << optopt << " (" << co << ")" << endl; break; case 0: cout << "0 return. val = " << value << endl; break; default: cout << "Default return. c = " << ch << ", optopt = " << optopt << endl; break; } } } bobcat-5.09.01/arg/driver/driver.ih0000644000175000017500000000014614050437223015766 0ustar frankfrank#include "driver.h" #include #include using namespace std; using namespace FBB; bobcat-5.09.01/arg/driver/c0000755000175000017500000000006714050437223014323 0ustar frankfrank#!/bin/bash g++ `cat ../../c++std` -I.. -c driver.cc bobcat-5.09.01/arg/addlongoption1.cc0000644000175000017500000000023114050437223016102 0ustar frankfrank#include "arg.ih" void Arg__::addLongOption(string const &longName) { d_longOptv[longName].push_back(optarg ? optarg : ""); ++d_nLongOptions; } bobcat-5.09.01/arg/nargs.f0000644000175000017500000000010114050437223014126 0ustar frankfrankinline size_t Arg__::nArgs() const { return d_argv.size(); } bobcat-5.09.01/arg/setbasename.cc0000644000175000017500000000025514050437223015455 0ustar frankfrank#include "arg.ih" void Arg__::setBasename() { string::size_type idx = d_argv0.rfind(s_dirsep); d_base = idx == string::npos ? d_argv0 : d_argv0.substr(idx + 1); } bobcat-5.09.01/argconfig/0000755000175000017500000000000014050437223014043 5ustar frankfrankbobcat-5.09.01/argconfig/option3.cc0000644000175000017500000000105714050437223015750 0ustar frankfrank#include "argconfig.ih" // same as Arg::option's equivalent size_t ArgConfig::option(string *value, int optChar) { static size_t const zero = 0; // prevents amd64 ambiguities where size_t ret = Arg::option(zero, value, optChar); // (size_t)0 != 0U if (ret != 0) return ret; auto iterators = findLongOption(optChar); if (iterators.second == iterators.first) return 0; if (value) *value = findKeyTail(d_ptr->find(optChar)->second + ":?", 1); return iterators.second - iterators.first; } bobcat-5.09.01/argconfig/option4.cc0000644000175000017500000000057514050437223015755 0ustar frankfrank#include "argconfig.ih" size_t ArgConfig::option(string *value, char const *longOption) { size_t ret = Arg::option(value, longOption); if (ret != 0) return ret; auto iterators = longConfigOpt(longOption); ret = iterators.second - iterators.first; if (value && ret != 0) *value = findKeyTail(string(longOption) + ":?", 1); return ret; } bobcat-5.09.01/argconfig/instance.cc0000644000175000017500000000027114050437223016156 0ustar frankfrank#include "argconfig.ih" ArgConfig &ArgConfig::instance() { if (!s_argconfig) throw Exception{} << "ArgConfig::instance(): not yet initialized"; return *s_argconfig; } bobcat-5.09.01/argconfig/data.cc0000644000175000017500000000026414050437223015265 0ustar frankfrank#include "argconfig.ih" ArgConfig *ArgConfig::s_argconfig; char const ArgConfig::s_alreadyInitialized[] = "ArgConfig::initialize(): already initialized"; bobcat-5.09.01/argconfig/initialize2.cc0000644000175000017500000000116114050437223016574 0ustar frankfrank#include "argconfig.ih" // no accept, no long options, file, // static ArgConfig &ArgConfig::initialize(char const *optstring, int argc, char **argv, std::string const &fname, Comment cType, SearchCasing sType, Indices iType) { if (s_argconfig) throw Exception{} << s_alreadyInitialized; s_argconfig = new ArgConfig(0, optstring, 0, 0, argc, argv, fname, cType, sType, iType); return *s_argconfig; } bobcat-5.09.01/argconfig/opindex.f0000644000175000017500000000014014050437223015653 0ustar frankfrankinline char const *ArgConfig::operator[](size_t idx) const { return Arg::operator[](idx); } bobcat-5.09.01/argconfig/initialize6.cc0000644000175000017500000000117714050437223016607 0ustar frankfrank#include "argconfig.ih" // accept, no long options, file, // static ArgConfig &ArgConfig::initialize(int accept, char const *optstring, int argc, char **argv, std::string const &fname, Comment cType, SearchCasing sType, Indices iType) { if (s_argconfig) throw Exception{} << s_alreadyInitialized; s_argconfig = new ArgConfig(accept, optstring, 0, 0, argc, argv, fname, cType, sType, iType); return *s_argconfig; } bobcat-5.09.01/argconfig/argconfig2.cc0000644000175000017500000000070214050437223016372 0ustar frankfrank#include "argconfig.ih" ArgConfig::ArgConfig(int accept, char const *optstring, LongOption const *begin, LongOption const *const end, int argc, char **argv, string const &fname, Comment cType, SearchCasing sType, Indices iType) : Arg(accept, optstring, begin, end, argc, argv), ConfigFile(fname, cType, sType, iType), d_ptr(new ArgConfig__(begin, end)) {} bobcat-5.09.01/argconfig/argconfig1.cc0000644000175000017500000000062214050437223016372 0ustar frankfrank#include "argconfig.ih" ArgConfig::ArgConfig(int accept, char const *optstring, LongOption const *const begin, LongOption const *const end, int argc, char **argv, Comment cType, SearchCasing sType, Indices iType) : Arg(accept, optstring, begin, end, argc, argv), ConfigFile(cType, sType, iType), d_ptr(new ArgConfig__(begin, end)) {} bobcat-5.09.01/argconfig/initialize1.cc0000644000175000017500000000073414050437223016600 0ustar frankfrank#include "argconfig.ih" // no accept, no long options, no file ArgConfig &ArgConfig::initialize(char const *optstring, int argc, char **argv, Comment cType, SearchCasing sType, Indices iType) { if (s_argconfig) throw Exception{} << s_alreadyInitialized; s_argconfig = new ArgConfig(0, optstring, 0, 0, argc, argv, cType, sType, iType); return *s_argconfig; } bobcat-5.09.01/argconfig/initialize3.cc0000644000175000017500000000111214050437223016571 0ustar frankfrank#include "argconfig.ih" // no accept, long options, no file, // static ArgConfig &ArgConfig::initialize(char const *optstring, LongOption const *begin, LongOption const *const end, int argc, char **argv, Comment cType, SearchCasing sType, Indices iType) { if (s_argconfig) throw Exception{} << s_alreadyInitialized; s_argconfig = new ArgConfig(0, optstring, begin, end, argc, argv, cType, sType, iType); return *s_argconfig; } bobcat-5.09.01/argconfig/argconfig.ih0000644000175000017500000000156614050437223016334 0ustar frankfrank#include "argconfig" #include #include #include #include "../string/string" #include "../exception/exception" #include "../iuo/iuo" namespace FBB { class ArgConfig__ { // find long options given short // option char std::unordered_map d_longOption; public: ArgConfig__(LongOption__ const *begin, LongOption__ const *const end); std::unordered_map::const_iterator find(int optChar) const; // .i std::unordered_map::const_iterator findEnd() const; // .i }; #include "find.f" #include "findend.f" } // FBB using namespace FBB; using namespace std; bobcat-5.09.01/argconfig/argconfig0000644000175000017500000001175214050437223015733 0ustar frankfrank#ifndef INCLUDED_BOBCAT_ARGCONFIG_ #define INCLUDED_BOBCAT_ARGCONFIG_ #include #include #include #include namespace FBB { class ArgConfig__; class ArgConfig: public Arg, public ConfigFile { static ArgConfig *s_argconfig; // points to Singleton ArgConfig static char const s_alreadyInitialized[]; ArgConfig__ *d_ptr; public: ArgConfig(ArgConfig const &other) = delete; // no accept, no long options, no file static ArgConfig &initialize(char const *optstring, // 1 int argc, char **argv, Comment cType = KeepComment, SearchCasing sType = SearchCaseSensitive, Indices iType = IgnoreIndices); // no accept, no long options, file, static ArgConfig &initialize(char const *optstring, // 2 int argc, char **argv, std::string const &fname, Comment cType = KeepComment, SearchCasing sType = SearchCaseSensitive, Indices iType = IgnoreIndices); // no accept, long options, no file, static ArgConfig &initialize(char const *optstring, // 3 LongOption const *begin, LongOption const *const end, int argc, char **argv, Comment cType = KeepComment, SearchCasing sType = SearchCaseSensitive, Indices iType = IgnoreIndices); // no accept, long options, file, static ArgConfig &initialize(char const *optstring, // 4 LongOption const *begin, LongOption const *const end, int argc, char **argv, std::string const &fname, Comment cType = KeepComment, SearchCasing sType = SearchCaseSensitive, Indices iType = IgnoreIndices); // accept, no long options, no file static ArgConfig &initialize(int accept, char const *optstring, // 5 int argc, char **argv, Comment cType = KeepComment, SearchCasing sType = SearchCaseSensitive, Indices iType = IgnoreIndices); // accept, no long options, file, static ArgConfig &initialize(int accept, char const *optstring, // 6 int argc, char **argv, std::string const &fname, Comment cType = KeepComment, SearchCasing sType = SearchCaseSensitive, Indices iType = IgnoreIndices); // accept, long options no file, static ArgConfig &initialize(int accept, char const *optstring, // 7 LongOption const *begin, LongOption const *const end, int argc, char **argv, Comment cType = KeepComment, SearchCasing sType = SearchCaseSensitive, Indices iType = IgnoreIndices); // accept, long options, file, static ArgConfig &initialize(int accept, char const *optstring, // 8 LongOption const *begin, LongOption const *const end, int argc, char **argv, std::string const &fname, Comment cType = KeepComment, SearchCasing sType = SearchCaseSensitive, Indices iType = IgnoreIndices); static ArgConfig &instance(); size_t option(int option); // 1 size_t option(std::string const &optchars); // 2 size_t option(std::string *value, int optChar); // 3 size_t option(std::string *value, char const *longOption); // 4 size_t option(size_t idx, // 1.f std::string *value, int option) const; size_t option(size_t *idx, // 2.f std::string *value, int option) const; size_t option(size_t idx, std::string *value, // 3.f char const *longOption) const; size_t option(size_t *idx, std::string *value, // 4.f char const *longOption) const; char const *operator[](size_t idx) const; // Arg's [] .f std::string const &line(size_t idx) const; // ConfigFile's [] .f private: ArgConfig(int accept, char const *optstring, // 1 LongOption const *begin, LongOption const *const end, int argc, char **argv, Comment cType, SearchCasing sType, Indices iType); ArgConfig(int accept, char const *optstring, // 2 LongOption const *begin, LongOption const *const end, int argc, char **argv, std::string const &fname, Comment cType, SearchCasing sType, Indices iType); RE_iteratorPair findLongOption(int optChar); RE_iteratorPair longConfigOpt(std::string const &longOpt); }; #include "option1.f" #include "option2.f" #include "option3.f" #include "option4.f" #include "opindex.f" #include "line.f" } // FBB #endif bobcat-5.09.01/argconfig/option3.f0000644000175000017500000000027714050437223015613 0ustar frankfrankinline size_t ArgConfig::option(size_t idx, std::string *value, char const *longOption) const { return Arg::option(idx, value, longOption); } bobcat-5.09.01/argconfig/initialize5.cc0000644000175000017500000000100514050437223016574 0ustar frankfrank#include "argconfig.ih" // accept, no long options, no file ArgConfig &ArgConfig::initialize(int accept, char const *optstring, int argc, char **argv, Comment cType, SearchCasing sType, Indices iType) { if (s_argconfig) throw Exception{} << s_alreadyInitialized; s_argconfig = new ArgConfig(accept, optstring, 0, 0, argc, argv, cType, sType, iType); return *s_argconfig; } bobcat-5.09.01/argconfig/initialize7.cc0000644000175000017500000000113014050437223016575 0ustar frankfrank#include "argconfig.ih" // accept, long options, no file, // static ArgConfig &ArgConfig::initialize(int accept, char const *optstring, LongOption const *begin, LongOption const *const end, int argc, char **argv, Comment cType, SearchCasing sType, Indices iType) { if (s_argconfig) throw Exception{} << s_alreadyInitialized; s_argconfig = new ArgConfig(accept, optstring, begin, end, argc, argv, cType, sType, iType); return *s_argconfig; } bobcat-5.09.01/argconfig/initialize4.cc0000644000175000017500000000120514050437223016575 0ustar frankfrank#include "argconfig.ih" // no accept, long options, file, // static ArgConfig &ArgConfig::initialize(char const *optstring, LongOption const *begin, LongOption const *const end, int argc, char **argv, string const &fname, Comment cType, SearchCasing sType, Indices iType) { if (s_argconfig) throw Exception{} << s_alreadyInitialized; s_argconfig = new ArgConfig(0, optstring, begin, end, argc, argv, fname, cType, sType, iType); return *s_argconfig; } bobcat-5.09.01/argconfig/argconfig5.cc0000644000175000017500000000037714050437223016405 0ustar frankfrank#include "argconfig.ih" ArgConfig__::ArgConfig__(LongOption__ const *begin, LongOption__ const *const end) { while (begin != end) { d_longOption[begin->optionChar()] = begin->longName(); ++begin; } } bobcat-5.09.01/argconfig/option4.f0000644000175000017500000000027214050437223015607 0ustar frankfrankinline size_t ArgConfig::option(size_t *idx, std::string *value, char const *longOpt) const { return Arg::option(idx, value, longOpt); } bobcat-5.09.01/argconfig/option2.cc0000644000175000017500000000035514050437223015747 0ustar frankfrank#include "argconfig.ih" size_t ArgConfig::option(std::string const &optchars) { size_t count = 0; char const *cp = optchars.c_str(); while (*cp) { count += option(*cp); ++cp; } return count; } bobcat-5.09.01/argconfig/longconfigopt.cc0000644000175000017500000000027714050437223017230 0ustar frankfrank#include "argconfig.ih" ArgConfig::RE_iteratorPair ArgConfig::longConfigOpt(string const &longOpt) { string pattern = "^\\s*" + longOpt + ":?(\\s|$)"; return beginEndRE(pattern); } bobcat-5.09.01/argconfig/initialize8.cc0000644000175000017500000000122314050437223016601 0ustar frankfrank#include "argconfig.ih" // accept, long options, file, // static ArgConfig &ArgConfig::initialize(int accept, char const *optstring, LongOption const *begin, LongOption const *const end, int argc, char **argv, string const &fname, Comment cType, SearchCasing sType, Indices iType) { if (s_argconfig) throw Exception{} << s_alreadyInitialized; s_argconfig = new ArgConfig(accept, optstring, begin, end, argc, argv, fname, cType, sType, iType); return *s_argconfig; } bobcat-5.09.01/argconfig/option1.f0000644000175000017500000000027114050437223015603 0ustar frankfrankinline size_t ArgConfig::option(size_t idx, std::string *value, int optChar) const { return Arg::option(idx, value, optChar); } bobcat-5.09.01/argconfig/option2.f0000644000175000017500000000027214050437223015605 0ustar frankfrankinline size_t ArgConfig::option(size_t *idx, std::string *value, int optChar) const { return Arg::option(idx, value, optChar); } bobcat-5.09.01/argconfig/option1.cc0000644000175000017500000000027214050437223015744 0ustar frankfrank#include "argconfig.ih" size_t ArgConfig::option(int optChar) { auto iterators = findLongOption(optChar); return Arg::option(optChar) + (iterators.second - iterators.first); } bobcat-5.09.01/argconfig/findlongoption.cc0000644000175000017500000000101014050437223017373 0ustar frankfrank#include "argconfig.ih" // return ConfigFile's RE_iterator to the configfile's long option ArgConfig::RE_iteratorPair ArgConfig::findLongOption(int optChar) { // find the long option given the short option char auto optIt = d_ptr->find(optChar); return optIt == d_ptr->findEnd() ? // not found, beginEndRE() : // else return an iter to the longConfigOpt(optIt->second); // option's line. } bobcat-5.09.01/argconfig/findend.f0000644000175000017500000000020114050437223015612 0ustar frankfrankinline std::unordered_map::const_iterator ArgConfig__::findEnd() const { return d_longOption.end(); } bobcat-5.09.01/argconfig/find.f0000644000175000017500000000022114050437223015125 0ustar frankfrankinline std::unordered_map::const_iterator ArgConfig__::find(int optChar) const { return d_longOption.find(optChar); } bobcat-5.09.01/argconfig/driver/0000755000175000017500000000000014050437223015336 5ustar frankfrankbobcat-5.09.01/argconfig/driver/build0000755000175000017500000000054414050437223016366 0ustar frankfrank#!/bin/bash case $1 in (b) g++ `cat ../../c++std` -o driver *.cc -lbobcat -s ;; (a) g++ `cat ../../c++std` -o driver *.cc -L../tmp -largconfig -lbobcat -s ;; (*) echo $0 a links to the files in the current dir, ../tmp/libargconfig echo and bobcat echo $0 b links to the installed bobcat library ;; esac bobcat-5.09.01/argconfig/driver/driver.cc0000644000175000017500000000461514050437223017146 0ustar frankfrank#include #include #include "../argconfig" #include #include #include using namespace std; using namespace FBB; namespace { ArgConfig::LongOption lo[] = { ArgConfig::LongOption("option", 'o'), ArgConfig::LongOption("option-value", 'v') }; } class X { ArgConfig &d_arg; public: X(); void function(); }; X::X() : d_arg(ArgConfig::instance()) {} void X::function() { if (d_arg.nArgs() == 0) throw Exception() << "Provide the name of a config file as 1st arg"; cout << "Counting " << d_arg.option('o') << " instances of -o or " "--option\n" "Counting " << d_arg.option('v') << " instances of -v or " "--option-value\n" "\n" "Now opening config file `" << d_arg[0] << "'\n"; d_arg.open(d_arg[0]); // Now open the config file explicitly // (alternatively: use a constructor expecting // a file name) cout << "\n" "ALL LINES IN THE CONFIG FILE:\n"; copy(d_arg.begin(), d_arg.end(), ostream_iterator(cout, "\n")); cout << "\n" "Counting " << d_arg.option('o') << " instances of -o or " "--option\n"; string optval; size_t count = d_arg.option(&optval, 'v'); cout << "\n" "Counting " << count << " instances of -v or --option-value\n" "The first one having value `" << optval << "'\n" "Here are all their values:\n"; auto iters = d_arg.beginEndRE("option-value"); Pattern pattern( R"(^option-value:?\s+(.*)\s*$)" ); for (auto &line: ranger(iters.first, iters.second)) { cout << line << "\n"; if (pattern << line) cout << "Tail: " << pattern[1] << '\n'; } } int main(int argc, char **argv) try { ArgConfig &arg = ArgConfig::initialize("cov:", lo, lo + 2, argc, argv); if (arg.option('c')) { cout << "Comment lines are removed from the config file\n\n"; arg.setCommentHandling(ArgConfig::RemoveComment); } X x; x.function(); } catch (exception const &err) { cout << "Terminating " << err.what() << endl; return 1; } bobcat-5.09.01/argconfig/driver/config0000644000175000017500000000043514050437223016530 0ustar frankfrank# these options are also defined by driver.cc option option-value: \#x\\yz \\ option-value: #xyz option-value without colon this line \ continues over \ multiple lines # other lines may also be provided, lines starting with # are comment a line not containing an option bobcat-5.09.01/argconfig/driver/driver.rc0000644000175000017500000000051714050437223017162 0ustar frankfrank# This is the configuration file used with the ArgConfig driver program # This will result in a count of 3 of the check for -o: option anything in between is ok option 12 # Options may have values associated with them. The 'value-option' should # produce such a value: value-option this is a value specified with `value-option' bobcat-5.09.01/argconfig/driver/driver.ih0000644000175000017500000000014614050437223017154 0ustar frankfrank#include "driver.h" #include #include using namespace std; using namespace FBB; bobcat-5.09.01/argconfig/line.f0000644000175000017500000000015014050437223015135 0ustar frankfrankinline std::string const &ArgConfig::line(size_t idx) const { return ConfigFile::operator[](idx); } bobcat-5.09.01/base64bufbase/0000755000175000017500000000000014050437223014520 5ustar frankfrankbobcat-5.09.01/base64bufbase/data.cc0000644000175000017500000000031414050437223015736 0ustar frankfrank#include "base64bufbase.ih" string const Base64BufBase::s_tabStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/"; bobcat-5.09.01/base64bufbase/doencrypt.cc0000644000175000017500000000015214050437223017034 0ustar frankfrank#include "base64bufbase.ih" void Base64BufBase::doEncrypt() { d_action = &Base64BufBase::encrypt; } bobcat-5.09.01/base64bufbase/encrypt.cc0000644000175000017500000000151314050437223016513 0ustar frankfrank #include "base64bufbase.ih" bool Base64BufBase::encrypt() { while (true) { int c0 = d_in.get(); if (!d_in) return d_buffer.size(); int c1 = d_in.get(); int c2 = d_in.get(); d_buffer.push_back(s_tabStr[ bits<2, 6>(c0) ]); d_buffer.push_back(s_tabStr[ bits<0, 2, 4>(c0) | bits<4, 4>(c1) ]); if (c1 == EOF) { d_buffer += "==\n"; return true; } d_buffer.push_back(s_tabStr[ bits<0, 4, 2>(c1) | bits<6, 2>(c2) ]); if (c2 == EOF) { d_buffer += "=\n"; return true; } d_buffer.push_back(s_tabStr[ bits<0, 6>(c2)]); if (d_buffer.size() == 76) { d_buffer.push_back('\n'); return true; } } } bobcat-5.09.01/base64bufbase/bits.f0000644000175000017500000000026414050437223015632 0ustar frankfranktemplate inline int Base64BufBase::bits(int value) { return value == EOF ? 0 : (value & ((1 << (from + size)) - 1)) >> from << shl; } bobcat-5.09.01/base64bufbase/indexof.cc0000644000175000017500000000033014050437223016457 0ustar frankfrank#include "base64bufbase.ih" size_t Base64BufBase::indexOf(int ch) { size_t ret = s_tabStr.find(ch); if (ret == string::npos) throw Exception{} << "Input file not base64 encoded"; return ret; } bobcat-5.09.01/base64bufbase/base64bufbase.ih0000644000175000017500000000017414050437223017460 0ustar frankfrank#include "base64bufbase" #include "../exception/exception" using namespace std; using namespace FBB; using namespace IUO; bobcat-5.09.01/base64bufbase/base64bufbase1.cc0000644000175000017500000000021214050437223017517 0ustar frankfrank#include "base64bufbase.ih" Base64BufBase::Base64BufBase(std::istream &in, size_t bufSize) : IFilterBuf(bufSize), d_in(in) {} bobcat-5.09.01/base64bufbase/filter.cc0000644000175000017500000000052614050437223016317 0ustar frankfrank#include "base64bufbase.ih" #include bool Base64BufBase::filter(char const **srcBegin, char const **srcEnd) { if (d_allDone) return false; d_buffer.clear(); d_allDone = (this->*d_action)() == false; *srcBegin = d_buffer.data(); *srcEnd = *srcBegin + d_buffer.size(); return d_buffer.size(); } bobcat-5.09.01/base64bufbase/dodecrypt.cc0000644000175000017500000000017514050437223017027 0ustar frankfrank#include "base64bufbase.ih" void Base64BufBase::doDecrypt() { d_action = &Base64BufBase::decrypt; // setBuffer(); } bobcat-5.09.01/base64bufbase/decrypt.cc0000644000175000017500000000424214050437223016503 0ustar frankfrank#include "base64bufbase.ih" #include bool Base64BufBase::decrypt() { // reading blocks of 4 characters. // If the first byte is \n then reread it (from the next line). // Stop if the first character is not in the set of accepted base64 // characters while (true) { int b0 = d_in.get(); // first of 4 if (b0 == '\n') // is a \n: read the next b0 = d_in.get(); // returns 0xff on failure if (s_tabStr.find(b0) == string::npos) // b0 is not in the set of { // base64 chars d_in.unget(); return false; // signal 'done' } int b1 = d_in.get(); // continue: there must be int b2 = d_in.get(); // at least 4 characters int b3 = d_in.get(); b0 = indexOf(b0); // convert chars to indices: b1 = indexOf(b1); // their bit patterns are // stored in max, 3 decrypted // characters d_buffer.push_back( (b0 << 2) // 6 bits of b0 become bits 2..7 | bits<4, 2>(b1) // bits 4,5 of b1 become bits 0..1 ); if (b2 == '=') // encountered '==': only one output char return false; b2 = indexOf(b2); d_buffer.push_back( bits<0, 4, 4>(b1) // bits 0..3 become bits 4..7 | bits<2, 4>(b2) // bits 2..5 become bits 0..3 ); if (b3 == '=') // encountered '==': two output chars return false; d_buffer.push_back( bits<0, 2, 6>(b2) // bits 0..1 become bits 6..7 | indexOf(b3) // all 6 bits of b3 ); if (d_buffer.size() > 100) // flush if the buffer is full return true; } } bobcat-5.09.01/base64bufbase/base64bufbase0000644000175000017500000000633014050437223017061 0ustar frankfrank#ifndef INCLUDED_BOBCAT_BASE64BUFBASE_ #define INCLUDED_BOBCAT_BASE64BUFBASE_ // See also https://en.wikipedia.org/wiki/Base64 // And https://www.ietf.org/rfc/rfc4648.txt // // // Table 1: The Base 64 Alphabet // // Value Encoding Value Encoding Value Encoding Value Encoding // 0 A 17 R 34 i 51 z // 1 B 18 S 35 j 52 0 // 2 C 19 T 36 k 53 1 // 3 D 20 U 37 l 54 2 // 4 E 21 V 38 m 55 3 // 5 F 22 W 39 n 56 4 // 6 G 23 X 40 o 57 5 // 7 H 24 Y 41 p 58 6 // 8 I 25 Z 42 q 59 7 // 9 J 26 a 43 r 60 8 // 10 K 27 b 44 s 61 9 // 11 L 28 c 45 t 62 + // 12 M 29 d 46 u 63 / // 13 N 30 e 47 v // 14 O 31 f 48 w (pad) = // 15 P 32 g 49 x // 16 Q 33 h 50 y // // // Bit offset | 7 0 | 7 0 | 7 0 | // Text content | M | a | n | // ASCII | 77 (0x4d) | 97 (0x61) | 110 (0x6e) | // Bit pattern | 0 1 0 0 1 1 | 0 1 | 0 1 1 0 | 0 0 0 1 | 0 1 | 1 0 1 1 1 0 | // Index | 19 | 2 | 5 | 46 | // Base64 | T | W | F | u | // Variables | b0 | b1 | b2 | b3 | // // If the last group of four ends in '==' (i.e., b2 equals '=') then only one // char is written; // If the last group of four ends in '=' (i.e., b3 equals '=') then only two // chars are written; #include #include #include namespace FBB { namespace IUO // the facilities defined here are not further documented: { // the Base64BufBase class defined below should be // used by IBase64Buf only. class Base64BufBase: public FBB::IFilterBuf { std::istream &d_in; // stream to read bool (Base64BufBase::*d_action)(); // encrypting or decrypting size_t d_bufSize; std::string d_buffer; bool d_allDone = false; static std::string const s_tabStr; // conversion characters public: Base64BufBase(std::istream &in, size_t bufSize); protected: void doEncrypt(); void doDecrypt(); private: bool filter(char const **srcBegin, char const **srcEnd) override; bool encrypt(); // false means: don't call again, but there // may still be input waiting in d_buffer bool decrypt(); template static int bits(int value); static size_t indexOf(int ch); }; #include "bits.f" } // IUO } // FBB #endif bobcat-5.09.01/bigint/0000755000175000017500000000000014050437223013360 5ustar frankfrankbobcat-5.09.01/bigint/opshris.f0000644000175000017500000000011714050437223015215 0ustar frankfrankinline BigInt &BigInt::operator>>=(size_t nBits) { return rshift(nBits); } bobcat-5.09.01/bigint/opsub.cc0000644000175000017500000000023214050437223015014 0ustar frankfrank#include "bigint.ih" namespace FBB { BigInt operator-(BigInt const &lhs, BigInt const &rhs) { BigInt tmp(lhs); tmp -= rhs; return tmp; } } bobcat-5.09.01/bigint/pseudorand.cc0000644000175000017500000000034614050437223016036 0ustar frankfrank#include "bigint.ih" BigInt BigInt::pseudoRand(size_t size, Msb msb, Lsb lsb) { BigInt ret; if (BN_pseudo_rand(ret.d_bn, size, msb, lsb) != 1) throw Exception{} << "BigInt::pseudoRand() failed"; return ret; } bobcat-5.09.01/bigint/opxoris.cc0000644000175000017500000000147214050437223015376 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::operator^=(BigInt const &rhs) { setNegative(isNegative() ^ rhs.isNegative()); size_t nMin = min(sizeInBytes(), rhs.sizeInBytes()); size_t nMax = max(sizeInBytes(), rhs.sizeInBytes()); unsigned char small[nMin]; unsigned char large[nMax]; BIGNUM const *bSmall; BIGNUM const *bLarge; if (sizeInBytes() < rhs.sizeInBytes()) { bSmall = d_bn; bLarge = rhs.d_bn; } else { bLarge = d_bn; bSmall = rhs.d_bn; } BN_bn2bin(bSmall, small); BN_bn2bin(bLarge, large); unsigned char *largePtr = large + nMax - nMin; for (size_t idx = 0; idx != nMin; ++idx) // XOR bytes 0 to nMin largePtr[idx] ^= small[idx]; BN_bin2bn(large, nMax, d_bn); return *this; } bobcat-5.09.01/bigint/opisequal.f0000644000175000017500000000014414050437223015530 0ustar frankfrankinline bool operator==(BigInt const &lhs, BigInt const &rhs) { return lhs.compare(rhs) == 0; } bobcat-5.09.01/bigint/setword.cc0000644000175000017500000000132714050437223015361 0ustar frankfrank#include "bigint.ih" void BigInt::setWord(size_t index, BigInt::Word word) { nWordsCheck(index); BigInt dest{rshiftc((index + 1) * BN_BYTES)}; // keep the most // significant part dest.rshift(8 * BN_BYTES); // make room for 'word' dest |= BigInt(word); // put 'word' at [0] if (index > 0) { dest.rshift(index * BN_BYTES); // room for the least // significant part (LSP) dest |= maskBits(index * BN_BYTES); // put in the LSP } swap(dest); // use the computed value } bobcat-5.09.01/bigint/submodc.cc0000644000175000017500000000023714050437223015325 0ustar frankfrank#include "bigint.ih" BigInt BigInt::subModc(BigInt const &rhs, BigInt const &mod) const { BigInt ret(*this); ret.subMod(rhs, mod); return ret; } bobcat-5.09.01/bigint/opgreaterequal.f0000644000175000017500000000014314050437223016545 0ustar frankfrankinline bool operator>=(BigInt const &lhs, BigInt const &rhs) { return lhs.compare(rhs) >= 0; } bobcat-5.09.01/bigint/at.cc0000644000175000017500000000033614050437223014275 0ustar frankfrank#include "bigint.ih" BigInt::Word BigInt::at(size_t index) const { nWordsCheck(index); BigInt dest{*this}; dest.rshift(index * BN_BYTES); return (dest &= BigInt{static_cast(WordMask)}).ulong(); } bobcat-5.09.01/bigint/lshift1.cc0000644000175000017500000000024114050437223015236 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::lshift() { if (!BN_lshift1(d_bn, d_bn)) throw Exception{} << "BigInt::lshift() failed"; return *this; } bobcat-5.09.01/bigint/lshiftc1.cc0000644000175000017500000000016414050437223015405 0ustar frankfrank#include "bigint.ih" BigInt BigInt::lshiftc() const { BigInt ret(*this); ret.lshift(); return ret; } bobcat-5.09.01/bigint/isqrtc.cc0000644000175000017500000000016014050437223015171 0ustar frankfrank#include "bigint.ih" BigInt BigInt::isqrtc() const { BigInt ret(*this); ret.isqrt(); return ret; } bobcat-5.09.01/bigint/bitoperatorxoris.cc0000644000175000017500000000021614050437223017305 0ustar frankfrank#include "bigint.ih" BigInt::Bit &BigInt::Bit::operator^=(bool rhs) { d_bi.setBit(d_idx, rhs ^ d_bi.hasBit(d_idx)); return *this; } bobcat-5.09.01/bigint/bit1.cc0000644000175000017500000000014214050437223014523 0ustar frankfrank#include "bigint.ih" BigInt::Bit::Bit(BigInt &bi, size_t idx) : d_bi(bi), d_idx(idx) {} bobcat-5.09.01/bigint/setbitc.cc0000644000175000017500000000020314050437223015317 0ustar frankfrank#include "bigint.ih" BigInt BigInt::setBitc(size_t index) const { BigInt ret(*this); ret.setBit(index); return ret; } bobcat-5.09.01/bigint/opindexc.f0000644000175000017500000000011414050437223015334 0ustar frankfrankinline int BigInt::operator[](size_t idx) const { return hasBit(idx); } bobcat-5.09.01/bigint/bigint6.cc0000644000175000017500000000015514050437223015232 0ustar frankfrank#include "bigint.ih" BigInt::BigInt(BIGNUM const *bignum) : d_bn(BN_new()) { copy(d_bn, *bignum); } bobcat-5.09.01/bigint/oporis.cc0000644000175000017500000000147414050437223015210 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::operator|=(BigInt const &rhs) { if (rhs.isNegative()) setNegative(true); size_t nMin = min(sizeInBytes(), rhs.sizeInBytes()); size_t nMax = max(sizeInBytes(), rhs.sizeInBytes()); unsigned char small[nMin]; unsigned char large[nMax]; BIGNUM const *bSmall; BIGNUM const *bLarge; if (sizeInBytes() < rhs.sizeInBytes()) { bSmall = d_bn; bLarge = rhs.d_bn; } else { bLarge = d_bn; bSmall = rhs.d_bn; } BN_bn2bin(bSmall, small); BN_bn2bin(bLarge, large); unsigned char *largePtr = large + nMax - nMin; for (size_t idx = 0; idx != nMin; ++idx) // OR bytes 0 to nMin largePtr[idx] |= small[idx]; BN_bin2bn(large, nMax, d_bn); return *this; } bobcat-5.09.01/bigint/tildebits.cc0000644000175000017500000000054514050437223015656 0ustar frankfrank#include "bigint.ih" // toggles all bits and sign BigInt &BigInt::tildeBits() { size_t nBytes = sizeInBytes(); unsigned char buf[nBytes]; bool sign = isNegative(); BN_bn2bin(d_bn, buf); for (size_t idx = nBytes; idx--; ) buf[idx] = ~buf[idx]; BN_bin2bn(buf, nBytes, d_bn); setNegative(!sign); return *this; } bobcat-5.09.01/bigint/bitoperatororis.cc0000644000175000017500000000021714050437223017116 0ustar frankfrank#include "bigint.ih" BigInt::Bit &BigInt::Bit::operator|=(bool rhs) { d_bi.setBit(d_idx, rhs || d_bi.hasBit(d_idx)); return *this; } bobcat-5.09.01/bigint/rshift1.cc0000644000175000017500000000024114050437223015244 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::rshift() { if (!BN_rshift1(d_bn, d_bn)) throw Exception{} << "BigInt::rshift() failed"; return *this; } bobcat-5.09.01/bigint/opdivide.cc0000644000175000017500000000023214050437223015467 0ustar frankfrank#include "bigint.ih" namespace FBB { BigInt operator/(BigInt const &lhs, BigInt const &rhs) { BigInt tmp(lhs); tmp /= rhs; return tmp; } } bobcat-5.09.01/bigint/bitoperatorandis.cc0000644000175000017500000000021714050437223017240 0ustar frankfrank#include "bigint.ih" BigInt::Bit &BigInt::Bit::operator&=(bool rhs) { d_bi.setBit(d_idx, rhs && d_bi.hasBit(d_idx)); return *this; } bobcat-5.09.01/bigint/exp.cc0000644000175000017500000000031614050437223014463 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::exp(BigInt const &exponent) { BNCTX ctx; if (!BN_exp(d_bn, d_bn, exponent.d_bn, ctx)) throw Exception{} << "BigInt exp() failed"; return *this; } bobcat-5.09.01/bigint/opmod.cc0000644000175000017500000000023214050437223015002 0ustar frankfrank#include "bigint.ih" namespace FBB { BigInt operator%(BigInt const &lhs, BigInt const &rhs) { BigInt tmp(lhs); tmp %= rhs; return tmp; } } bobcat-5.09.01/bigint/isone.f0000644000175000017500000000010214050437223014635 0ustar frankfrankinline bool BigInt::isOne() const { return BN_is_one(d_bn); } bobcat-5.09.01/bigint/addmod.f0000644000175000017500000000017514050437223014762 0ustar frankfrankinline BigInt &BigInt::addMod(BigInt const &rhs, BigInt const &mod) { return checked2(BN_mod_add, rhs, mod, "addMod"); } bobcat-5.09.01/bigint/opgreater.f0000644000175000017500000000014214050437223015514 0ustar frankfrankinline bool operator>(BigInt const &lhs, BigInt const &rhs) { return lhs.compare(rhs) > 0; } bobcat-5.09.01/bigint/sizeofword.f0000644000175000017500000000010314050437223015714 0ustar frankfranksize_t constexpr BigInt::sizeOfWord() { return sizeof(Word); } bobcat-5.09.01/bigint/bnctx.f0000644000175000017500000000006414050437223014645 0ustar frankfrankinline BNCTX::BNCTX() { d_ctx = BN_CTX_new(); } bobcat-5.09.01/bigint/submod.f0000644000175000017500000000017514050437223015023 0ustar frankfrankinline BigInt &BigInt::subMod(BigInt const &rhs, BigInt const &mod) { return checked2(BN_mod_sub, rhs, mod, "subMod"); } bobcat-5.09.01/bigint/negatec.cc0000644000175000017500000000016314050437223015275 0ustar frankfrank#include "bigint.ih" BigInt BigInt::negatec() const { BigInt ret(*this); ret.negate(); return ret; } bobcat-5.09.01/bigint/setbitc2.cc0000644000175000017500000000022614050437223015406 0ustar frankfrank#include "bigint.ih" BigInt BigInt::setBitc(size_t index, bool value) const { BigInt ret(*this); ret.setBit(index, value); return ret; } bobcat-5.09.01/bigint/tildebitsc.cc0000644000175000017500000000017014050437223016013 0ustar frankfrank#include "bigint.ih" BigInt BigInt::tildeBitsc() const { BigInt ret(*this); ret.tildeBits(); return ret; } bobcat-5.09.01/bigint/opindex.f0000644000175000017500000000013714050437223015176 0ustar frankfrankinline BigInt::Bit BigInt::operator[](size_t idx) { Bit bit(*this, idx); return bit; } bobcat-5.09.01/bigint/opinsert.f0000644000175000017500000000015014050437223015366 0ustar frankfrankinline std::ostream &operator<<(std::ostream &out, BigInt const &bn) { return bn.insertInto(out); } bobcat-5.09.01/bigint/adddigit.cc0000644000175000017500000000067114050437223015444 0ustar frankfrank#include "bigint.ih" bool BigInt::addDigit(char ch, BigInt &ret, BigInt const &radix, int (*pConv)(int)) { if (not (*pConv)(static_cast(ch))) return true; // true means: character outside of expected range // which will end find_if. ret *= radix; ret += isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10; return false; } bobcat-5.09.01/bigint/sqrmod.f0000644000175000017500000000014514050437223015034 0ustar frankfrankinline BigInt &BigInt::sqrMod(BigInt const &mod) { return checked4(BN_mod_sqr, mod, "sqrMod"); } bobcat-5.09.01/bigint/randrange.cc0000644000175000017500000000034714050437223015634 0ustar frankfrank#include "bigint.ih" BigInt BigInt::randRange(BigInt const &max) { BigInt ret; if (BN_rand_range(ret.d_bn, const_cast(max.d_bn)) != 1) throw Exception{} << "BigInt::randRange() failed"; return ret; } bobcat-5.09.01/bigint/negate.cc0000644000175000017500000000016314050437223015132 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::negate() { BN_set_negative(d_bn, not isNegative()); return *this; } bobcat-5.09.01/bigint/opxor.cc0000644000175000017500000000024114050437223015033 0ustar frankfrank#include "bigint.ih" namespace FBB { BigInt operator^(BigInt const &lhs, BigInt const &rhs) { BigInt tmp(lhs); tmp ^= rhs; return tmp; } } // FBB bobcat-5.09.01/bigint/checked1.cc0000644000175000017500000000045314050437223015340 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::checked1( int (*BN_op)(BIGNUM *, const BIGNUM *, const BIGNUM *), BigInt const &rhs, char const *op) { if ((*BN_op)(d_bn, d_bn, rhs.d_bn) != 1) throw Exception{} << "BigInt " << op << " failed"; return *this; } bobcat-5.09.01/bigint/rshiftc2.cc0000644000175000017500000000020314050437223015406 0ustar frankfrank#include "bigint.ih" BigInt BigInt::rshiftc(size_t nBits) const { BigInt ret(*this); ret.rshift(nBits); return ret; } bobcat-5.09.01/bigint/sqrmodc.cc0000644000175000017500000000020614050437223015335 0ustar frankfrank#include "bigint.ih" BigInt BigInt::sqrModc(BigInt const &mod) const { BigInt ret(*this); ret.sqrMod(mod); return ret; } bobcat-5.09.01/bigint/prime.cc0000644000175000017500000000070314050437223015003 0ustar frankfrank#include "bigint.ih" BigInt BigInt::prime(size_t nBits, BigInt const *mod, BigInt const *rem, PrimeType primeType) { BigInt ret; bool useArgs = mod != 0 && rem != 0; if ( BN_generate_prime_ex(ret.d_bn, nBits, primeType, useArgs ? mod->d_bn : 0, useArgs ? rem->d_bn : 0, 0) == 0 ) throw Exception{} << "BigInt::prime() failed"; return ret; } bobcat-5.09.01/bigint/opinsertbit.cc0000644000175000017500000000024414050437223016231 0ustar frankfrank#include "bigint.ih" namespace FBB { ostream &operator<<(ostream &out, BigInt::Bit const &bit) { return out << (bit.d_bi.hasBit(bit.d_idx) ? '1' : '0'); } } bobcat-5.09.01/bigint/sqr.cc0000644000175000017500000000025514050437223014476 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::sqr() { BNCTX ctx; if (BN_sqr(d_bn, d_bn, ctx) != 1) throw Exception{} << "BigInt sqr() failed"; return *this; } bobcat-5.09.01/bigint/lshiftc2.cc0000644000175000017500000000020514050437223015402 0ustar frankfrank#include "bigint.ih" BigInt BigInt::lshiftc(size_t nBits) const { BigInt ret(*this); ret.lshift(nBits); return ret; } bobcat-5.09.01/bigint/isqrt.cc0000644000175000017500000000164114050437223015033 0ustar frankfrank#include "bigint.ih" /* Newton's algorithm: x[i+1] = (x[i] + value / x[i]) / 2 until convergence. the returned value is the biggest int `ret' for which ret * ret <= value With integral values the algorithm may be trapped in an endless loop where the next value exceeds the previous value (this happens, e.g., with value = 15). This is handled by testing for this condition, rather than convergence. Initially x[0] = value */ BigInt &BigInt::isqrt() { BigInt org(*this); BigInt tmp; BigInt *step = this; BigInt *next = &tmp; if (isZero() || isNegative()) throw Exception{1} << "BigInt::isqrt: BigInt must be positive"; while (true) { *next = *step + org / *step; next->rshift(); if (*next >= *step) break; std::swap(step, next); } if (this != step) *this = *step; return *this; } bobcat-5.09.01/bigint/opbnctxptr.f0000644000175000017500000000007014050437223015727 0ustar frankfrankinline BNCTX::operator BN_CTX *() { return d_ctx; } bobcat-5.09.01/bigint/bigint5.cc0000644000175000017500000000020114050437223015221 0ustar frankfrank#include "bigint.ih" BigInt::BigInt(BIGNUM const &bignum) : d_bn(BN_new()) { // BN_init(d_bn); copy(d_bn, bignum); } bobcat-5.09.01/bigint/bn2oct.cc0000644000175000017500000000204314050437223015055 0ustar frankfrank#include "bigint.ih" char *BigInt::bn2oct(BIGNUM const *bn) { size_t nBits = (((BN_num_bits(bn)) + 2) / 3) * 3; char *ret = new char[nBits + 3]; // 1 for the -, 1 for the 0 // 1 for the asciiZ char *cp = ret; if (BN_is_negative(bn)) *cp++ = '-'; *cp++ = '0'; // initial 0 indicating octal for (; nBits; ) // proceed until 1st value != 0 { nBits -= 3; if (int value = (BN_is_bit_set(bn, nBits + 2) << 2) + (BN_is_bit_set(bn, nBits + 1) << 1) + BN_is_bit_set(bn, nBits)) { *cp++ = '0' + value; break; } } for (; nBits; ) // do the rest { nBits -= 3; *cp++ = '0' + (BN_is_bit_set(bn, nBits + 2) << 2) + (BN_is_bit_set(bn, nBits + 1) << 1) + BN_is_bit_set(bn, nBits); } *cp = 0; return ret; } bobcat-5.09.01/bigint/opshlis.f0000644000175000017500000000011714050437223015207 0ustar frankfrankinline BigInt &BigInt::operator<<=(size_t nBits) { return lshift(nBits); } bobcat-5.09.01/bigint/checked2.cc0000644000175000017500000000064514050437223015344 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::checked2( int (*BN_op)(BIGNUM *, BIGNUM const *, BIGNUM const *, BIGNUM const *, BN_CTX *), BigInt const &rhs, BigInt const &mod, char const *op) { BNCTX ctx; if ((*BN_op)(d_bn, d_bn, rhs.d_bn, mod.d_bn, ctx) != 1) throw Exception{} << "BigInt " << op << " failed"; return *this; } bobcat-5.09.01/bigint/bigint7.f0000644000175000017500000000013214050437223015066 0ustar frankfrankinline BigInt::BigInt(BIGNUM *bignum) : BigInt(const_cast(bignum)) {} bobcat-5.09.01/bigint/hasbit.f0000644000175000017500000000014014050437223014774 0ustar frankfrankinline bool BigInt::hasBit(size_t index) const { return BN_is_bit_set(this->d_bn, index); } bobcat-5.09.01/bigint/insertinto.cc0000644000175000017500000000161414050437223016067 0ustar frankfrank#include "bigint.ih" #include ostream &BigInt::insertInto(ostream &out) const { int flags = out.flags(); char *cp = // call function to use ( flags & ios::hex ? BN_bn2hex : flags & ios::oct ? bn2oct : BN_bn2dec )(d_bn); bool isNegative = (*cp == '-'); char *skipZeroes = cp + isNegative; while (*skipZeroes == '0') // cut off leading zeros ++skipZeroes; if ((flags & ios::oct) || *skipZeroes == 0) // if just 1 char or oct: --skipZeroes; // keep 1 '0' if (isNegative) *--skipZeroes = '-'; // restore the '-' out << skipZeroes; // insert the value if (flags & ios::oct) delete[] cp; else OPENSSL_free(cp); return out; } bobcat-5.09.01/bigint/opinc.cc0000644000175000017500000000015714050437223015002 0ustar frankfrank#include "bigint.ih" BigInt BigInt::operator++(int) { BigInt tmp(*this); ++*this; return tmp; } bobcat-5.09.01/bigint/rand.cc0000644000175000017500000000032314050437223014611 0ustar frankfrank#include "bigint.ih" BigInt BigInt::rand(size_t size, Msb msb, Lsb lsb) { BigInt ret; if (BN_rand(ret.d_bn, size, msb, lsb) != 1) throw Exception{} << "BigInt::rand() failed"; return ret; } bobcat-5.09.01/bigint/bigendian.cc0000644000175000017500000000027214050437223015610 0ustar frankfrank#include "bigint.ih" char *BigInt::bigEndian() const { char *ret = new char[sizeInBytes()]; BN_bn2bin(d_bn, reinterpret_cast(ret)); return ret; } bobcat-5.09.01/bigint/pseudorandrange.cc0000644000175000017500000000037214050437223017052 0ustar frankfrank#include "bigint.ih" BigInt BigInt::pseudoRandRange(BigInt const &max) { BigInt ret; if (BN_pseudo_rand_range(ret.d_bn, const_cast(max.d_bn)) != 1) throw Exception{} << "BigInt::pseudoRandRange() failed"; return ret; } bobcat-5.09.01/bigint/oprshift.cc0000644000175000017500000000023114050437223015521 0ustar frankfrank#include "bigint.ih" namespace FBB { BigInt operator>>(BigInt const &lhs, size_t nBits) { BigInt tmp(lhs); tmp >>= nBits; return tmp; } } bobcat-5.09.01/bigint/tildeint.cc0000644000175000017500000000016614050437223015506 0ustar frankfrank#include "bigint.ih" // neg = toggle + 1 -> toggle = neg - 1 BigInt &BigInt::tildeInt() { return --negate(); } bobcat-5.09.01/bigint/opinc.f0000644000175000017500000000007714050437223014643 0ustar frankfrankinline BigInt &BigInt::operator++() { return *this += 1; } bobcat-5.09.01/bigint/opmodis.cc0000644000175000017500000000017514050437223015344 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::operator%=(BigInt const &rhs) { checked3(0, d_bn, rhs, "%="); return *this; } bobcat-5.09.01/bigint/bigint1.cc0000644000175000017500000000007714050437223015230 0ustar frankfrank#include "bigint.ih" BigInt::BigInt() : d_bn(BN_new()) {} bobcat-5.09.01/bigint/setbigendian.cc0000644000175000017500000000034114050437223016321 0ustar frankfrank#include "bigint.ih" BigInt BigInt::setBigEndian(std::string const &bytes) { BigInt tmp; BN_bin2bn(reinterpret_cast(bytes.data()), bytes.length(), tmp.d_bn); return tmp; } bobcat-5.09.01/bigint/bitoperatoris.cc0000644000175000017500000000017014050437223016553 0ustar frankfrank#include "bigint.ih" BigInt::Bit &BigInt::Bit::operator=(bool rhs) { d_bi.setBit(d_idx, rhs); return *this; } bobcat-5.09.01/bigint/lshift2.cc0000644000175000017500000000027114050437223015242 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::lshift(size_t nBits) { if (!BN_lshift(d_bn, d_bn, nBits)) throw Exception{} << "BigInt::lshift(size_t) failed"; return *this; } bobcat-5.09.01/bigint/checked4.cc0000644000175000017500000000061614050437223015344 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::checked4(int (*BN_op)(BIGNUM *, BIGNUM const *, BIGNUM const *, BN_CTX *), BigInt const &rhs, char const *op) { BNCTX ctx; if ((*BN_op)(d_bn, d_bn, rhs.d_bn, ctx) != 1) throw Exception{} << "BigInt " << op << " failed"; return *this; } bobcat-5.09.01/bigint/setbit2.cc0000644000175000017500000000020414050437223015237 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::setBit(size_t index, bool value) { return value ? setBit(index) : clearBit(index); } bobcat-5.09.01/bigint/opdec.cc0000644000175000017500000000015714050437223014764 0ustar frankfrank#include "bigint.ih" BigInt BigInt::operator--(int) { BigInt tmp(*this); --*this; return tmp; } bobcat-5.09.01/bigint/sqrc.cc0000644000175000017500000000015414050437223014637 0ustar frankfrank#include "bigint.ih" BigInt BigInt::sqrc() const { BigInt ret(*this); ret.sqr(); return ret; } bobcat-5.09.01/bigint/diophantus1.cc0000644000175000017500000000101014050437223016116 0ustar frankfrank#include "bigint.ih" // static long long BigInt::diophantus(long long *factor1, long long *factor2, long long const &value1, long long const &value2) { if (long long modulo = value1 % value2) { long long nestedFactor1; long long gcd = diophantus(&nestedFactor1, factor2, value2, modulo); *factor1 = *factor2; *factor2 = nestedFactor1 - (value1 / value2) * *factor2; return gcd; } *factor1 = 0; *factor2 = 1; return value2; } bobcat-5.09.01/bigint/mulmodc.cc0000644000175000017500000000023714050437223015331 0ustar frankfrank#include "bigint.ih" BigInt BigInt::mulModc(BigInt const &rhs, BigInt const &mod) const { BigInt ret(*this); ret.mulMod(rhs, mod); return ret; } bobcat-5.09.01/bigint/opmul.cc0000644000175000017500000000023214050437223015020 0ustar frankfrank#include "bigint.ih" namespace FBB { BigInt operator*(BigInt const &lhs, BigInt const &rhs) { BigInt tmp(lhs); tmp *= rhs; return tmp; } } bobcat-5.09.01/bigint/opmovis.cc0000644000175000017500000000014314050437223015361 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::operator=(BigInt &&tmp) { swap(tmp); return *this; } bobcat-5.09.01/bigint/bigint0000644000175000017500000002574014050437223014567 0ustar frankfrank#ifndef INCLUDED_BOBCAT_BIGINT_ #define INCLUDED_BOBCAT_BIGINT_ #include #include #include namespace FBB { class BigInt { friend std::ostream &operator<<(std::ostream &out, BigInt const &bn); BIGNUM *d_bn; enum { WordMask = (1 << BN_BYTES) - 1 }; public: typedef BN_ULONG Word; enum Msb { MSB_UNKNOWN = -1, MSB_IS_ONE, TOP_TWO_BITS_ONE }; enum Lsb { EVEN, ODD, }; enum PrimeType { ANY = false, SAFE = true }; BigInt(); // 1 BigInt(BigInt const &other); // 2 BigInt(BigInt &&tmp); // 3 template // promotion OK 4.f BigInt(Type value); explicit BigInt(BIGNUM const &bignum); // 5 explicit BigInt(BIGNUM const *bignum); // 6 // 7.f explicit BigInt(BIGNUM *bignum); // .f (avoids selection of // the template) BigInt(char const *bigEndian, size_t length, bool negative = false); // 8 explicit BigInt(std::string const &bigEndian, bool negative = false); // 9 ~BigInt(); BigInt &operator=(BigInt const &other); // opis.cc BigInt &operator=(BigInt &&tmp); // opmovis.cc BigInt operator-() const; BigInt &negate(); BigInt negatec() const; BigInt &setNegative(bool negative); BigInt setNegativec(bool negative) const; bool isNegative() const; // .f BigInt &tildeBits(); BigInt tildeBitsc() const; BigInt &tildeInt(); BigInt tildeIntc() const; BigInt &operator--(); // opdec.f BigInt operator--(int); BigInt &operator++(); // opinc.f BigInt operator++(int); class Bit; Bit operator[](size_t idx); // opindex.f // non-const BigInts: // distinguishes lhs/rhs int operator[](size_t idx) const; // opindexc.f // only rhs for const BigInts class Bit { friend Bit BigInt::operator[](size_t idx); friend std::ostream &operator<<(std::ostream &out, Bit const &bit); BigInt &d_bi; size_t d_idx; public: operator bool() const; Bit &operator=(bool rhs); // assign a bit Bit &operator&=(bool rhs); // bit_and a bit Bit &operator|=(bool rhs); // bit_or a bit Bit &operator^=(bool rhs); // bit_xor a bit private: Bit(BigInt &bi, size_t idx); }; char *bigEndian() const; BigInt &operator+=(BigInt const &rhs); // opaddis.f BigInt &addMod(BigInt const &rhs, BigInt const &mod); // .f BigInt addModc(BigInt const &rhs, BigInt const &mod) const; BigInt &operator-=(BigInt const &rhs); // opsubis.f BigInt &subMod(BigInt const &rhs, BigInt const &mod); // .f BigInt subModc(BigInt const &rhs, BigInt const &mod) const; BigInt &operator*=(BigInt const &rhs); BigInt &mulMod(BigInt const &rhs, BigInt const &mod); // .f BigInt mulModc(BigInt const &rhs, BigInt const &mod) const; BigInt &operator%=(BigInt const &rhs); BigInt &operator/=(BigInt const &rhs); // integer division, // integer division, also // returning remainder BigInt &div(BigInt *remainder, BigInt const &rhs); BigInt divc(BigInt *remainder, BigInt const &rhs) const; BigInt &sqr(); BigInt sqrc() const; BigInt &sqrMod(BigInt const &mod); // .f BigInt sqrModc(BigInt const &mod) const; BigInt &operator&=(BigInt const &rhs); BigInt &operator|=(BigInt const &rhs); BigInt &operator^=(BigInt const &rhs); bool isZero() const; // .f bool isOne() const; // .f bool isOdd() const; // .f unsigned long ulong() const; // .f BIGNUM const &bignum() const; // .f size_t sizeInBytes() const; // .f size_t size() const; // .f size_t nWords() const; // .f static size_t constexpr sizeOfWord(); // .f Word at(size_t index) const; void setWord(size_t index, Word value); int compare(BigInt const &other) const; // .f int uCompare(BigInt const &other) const; // .f BigInt &exp(BigInt const &exponent); BigInt expc(BigInt const &exponent) const; BigInt &expMod(BigInt const &exponent, BigInt const &mod); BigInt expModc(BigInt const &exponent, BigInt const &mod) const; BigInt &gcd(BigInt const &rhs); BigInt gcdc(BigInt const &rhs) const; BigInt &inverseMod(BigInt const &mod); BigInt inverseModc(BigInt const &mod) const; BigInt &isqrt(); BigInt isqrtc() const; static long long diophantus(long long *factor1, long long *factor2, long long const &value1, long long const &value2); static BigInt diophantus(BigInt *factor1, BigInt *factor2, BigInt const &value1, BigInt const &value2); static BigInt rand(size_t bitsSize, Msb msb = MSB_IS_ONE, Lsb lsb = ODD); static BigInt randRange(BigInt const &max); static BigInt setBigEndian(std::string const &bytes); static BigInt pseudoRand(size_t bitsSize, Msb msb = MSB_IS_ONE, Lsb lsb = ODD); static BigInt pseudoRandRange(BigInt const &max); static BigInt prime(size_t nBits, BigInt const *add = 0, BigInt const *rem = 0, PrimeType primeType = ANY); static BigInt fromText(std::string const &text, int mode = 0); BigInt &clearBit(size_t index); BigInt clearBit(size_t index) const; bool hasBit(size_t index) const; // .f BigInt &maskBits(size_t lowerNBits); BigInt maskBitsc(size_t lowerNBits) const; BigInt &setBit(size_t index); BigInt setBitc(size_t index) const; BigInt &setBit(size_t index, bool value); BigInt setBitc(size_t index, bool value) const; BigInt &lshift(); BigInt lshiftc() const; BigInt &lshift(size_t nBits); BigInt lshiftc(size_t nBits) const; BigInt &operator<<=(size_t nBits); // opshlis.f BigInt &rshift(); BigInt rshiftc() const; BigInt &rshift(size_t nBits); BigInt rshiftc(size_t nBits) const; BigInt &operator>>=(size_t nBits); // opshris.f void swap(BigInt &other); private: void mod_inverse(BigInt *ret, BigInt const &mod) const; std::ostream &insertInto(std::ostream &out) const; static char *bn2oct(BIGNUM const *bn); void copy(BIGNUM *lhs, BIGNUM const &rhs); void nWordsCheck(size_t index) const; BigInt &checked1( int (*BN_op)(BIGNUM *, BIGNUM const *, BIGNUM const *), BigInt const &rhs, char const *op); BigInt &checked2(int (*BN_op)(BIGNUM *, BIGNUM const *, BIGNUM const *, BIGNUM const *, BN_CTX *), BigInt const &rhs, BigInt const &mod, char const *op); void checked3(BIGNUM *div, BIGNUM *rem, BigInt const &rhs, char const *op) const; BigInt &checked4(int (*BN_op)(BIGNUM *, BIGNUM const *, BIGNUM const *, BN_CTX *), BigInt const &rhs, char const *op); static void primeCallback(int reason, int primeNr, void *primeBase); static bool addDigit(char ch, BigInt &ret, BigInt const &radix, int (*pConv)(int)); }; #include "bigint4.f" #include "bigint7.f" #include "nwords.f" #include "addmod.f" #include "bignum.f" #include "compare.f" #include "hasbit.f" #include "isnegative.f" #include "isodd.f" #include "isone.f" #include "iszero.f" #include "mulmod.f" #include "opaddis.f" #include "opbool.f" #include "opdec.f" #include "opinc.f" #include "opindex.f" #include "opindexc.f" #include "opshlis.f" #include "opshris.f" #include "opsubis.f" #include "size.f" #include "sizeinbytes.f" #include "sizeofword.f" #include "sqrmod.f" #include "submod.f" #include "ulong.f" #include "ucompare.f" // Free functions BigInt operator*(BigInt const &lhs, BigInt const &rhs); BigInt operator/(BigInt const &lhs, BigInt const &rhs); BigInt operator%(BigInt const &lhs, BigInt const &rhs); BigInt operator+(BigInt const &lhs, BigInt const &rhs); BigInt operator-(BigInt const &lhs, BigInt const &rhs); BigInt operator>>(BigInt const &lhs, size_t rhs); BigInt operator<<(BigInt const &lhs, size_t rhs); BigInt operator|(BigInt const &lhs, BigInt const &rhs); BigInt operator&(BigInt const &lhs, BigInt const &rhs); BigInt operator^(BigInt const &lhs, BigInt const &rhs); BigInt gcd(BigInt const &lhs, BigInt const &rhs); BigInt inverseMod(BigInt const &lhs, BigInt const &mod); std::istream &operator>>(std::istream &out, BigInt &bn); int isoctdigit(int ch); // convert to spaceship operator use? #include "opisequal.f" // == #include "opisunequal.f" // != #include "opgreater.f" // > #include "opgreaterequal.f" // >= #include "opless.f" // < #include "oplessequal.f" // <= #include "opinsert.f" // ostream << } // namespace FBB #endif bobcat-5.09.01/bigint/nwordscheck.cc0000644000175000017500000000043414050437223016202 0ustar frankfrank#include "bigint.ih" void BigInt::nWordsCheck(size_t index) const { size_t count; if (index >= (count = nWords())) throw Exception{} << "BigInt: word index " << index << " exceeds " << count; } bobcat-5.09.01/bigint/opand.cc0000644000175000017500000000024114050437223014765 0ustar frankfrank#include "bigint.ih" namespace FBB { BigInt operator&(BigInt const &lhs, BigInt const &rhs) { BigInt tmp(lhs); tmp &= rhs; return tmp; } } // FBB bobcat-5.09.01/bigint/bigint4.f0000644000175000017500000000037114050437223015070 0ustar frankfranktemplate BigInt::BigInt(Type value) : d_bn(BN_new()) { bool negative = value < 0; if (negative) value = -value; BN_set_word(d_bn, static_cast(value)); if (negative) negate(); } bobcat-5.09.01/bigint/opless.f0000644000175000017500000000014214050437223015031 0ustar frankfrankinline bool operator<(BigInt const &lhs, BigInt const &rhs) { return lhs.compare(rhs) < 0; } bobcat-5.09.01/bigint/addmodc.cc0000644000175000017500000000023714050437223015264 0ustar frankfrank#include "bigint.ih" BigInt BigInt::addModc(BigInt const &rhs, BigInt const &mod) const { BigInt ret(*this); ret.addMod(rhs, mod); return ret; } bobcat-5.09.01/bigint/iszero.f0000644000175000017500000000010414050437223015035 0ustar frankfrankinline bool BigInt::isZero() const { return BN_is_zero(d_bn); } bobcat-5.09.01/bigint/inversemodc.cc0000644000175000017500000000022114050437223016200 0ustar frankfrank#include "bigint.ih" BigInt BigInt::inverseModc(BigInt const &mod) const { BigInt ret(*this); mod_inverse(&ret, mod); return ret; } bobcat-5.09.01/bigint/gcdc.cc0000644000175000017500000000020014050437223014557 0ustar frankfrank#include "bigint.ih" BigInt BigInt::gcdc(BigInt const &rhs) const { BigInt ret(*this); ret.gcd(rhs); return ret; } bobcat-5.09.01/bigint/expc.cc0000644000175000017500000000021214050437223014621 0ustar frankfrank#include "bigint.ih" BigInt BigInt::expc(BigInt const &exponent) const { BigInt ret(*this); ret.exp(exponent); return ret; } bobcat-5.09.01/bigint/modinverse.cc0000644000175000017500000000034014050437223016037 0ustar frankfrank#include "bigint.ih" void BigInt::mod_inverse(BigInt *ret, BigInt const &mod) const { BNCTX ctx; if (BN_mod_inverse(ret->d_bn, d_bn, mod.d_bn, ctx) == 0) throw Exception{} << "BigInt::inverseMod failed"; } bobcat-5.09.01/bigint/rshiftc1.cc0000644000175000017500000000016414050437223015413 0ustar frankfrank#include "bigint.ih" BigInt BigInt::rshiftc() const { BigInt ret(*this); ret.rshift(); return ret; } bobcat-5.09.01/bigint/size.f0000644000175000017500000000010514050437223014475 0ustar frankfrankinline size_t BigInt::size() const { return BN_num_bits(d_bn); } bobcat-5.09.01/bigint/setnegative.cc0000644000175000017500000000017514050437223016210 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::setNegative(bool negative) { BN_set_negative(d_bn, negative); return *this; } bobcat-5.09.01/bigint/rshift2.cc0000644000175000017500000000030514050437223015246 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::rshift(size_t nBits) { if (!BN_rshift(this->d_bn, this->d_bn, nBits)) throw Exception{} << "BigInt::rshift(size_t) failed"; return *this; } bobcat-5.09.01/bigint/opsubis.f0000644000175000017500000000014014050437223015206 0ustar frankfrankinline BigInt &BigInt::operator-=(BigInt const &rhs) { return checked1(BN_sub, rhs, "-"); } bobcat-5.09.01/bigint/expmod.cc0000644000175000017500000000036214050437223015164 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::expMod(BigInt const &exponent, BigInt const &mod) { BNCTX ctx; if (BN_mod_exp(d_bn, d_bn, exponent.d_bn, mod.d_bn, ctx) == 0) throw Exception{} << "BigInt sqr() failed"; return *this; } bobcat-5.09.01/bigint/setbit.cc0000644000175000017500000000026114050437223015160 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::setBit(size_t index) { if (!BN_set_bit(this->d_bn, index)) throw Exception{} << "BigInt::setBit failed"; return *this; } bobcat-5.09.01/bigint/mulmod.f0000644000175000017500000000017514050437223015027 0ustar frankfrankinline BigInt &BigInt::mulMod(BigInt const &rhs, BigInt const &mod) { return checked2(BN_mod_mul, rhs, mod, "mulMod"); } bobcat-5.09.01/bigint/destructor.f0000644000175000017500000000006314050437223015724 0ustar frankfrankinline BNCTX::~BNCTX() { BN_CTX_free(d_ctx); } bobcat-5.09.01/bigint/bigint3.cc0000644000175000017500000000014514050437223015226 0ustar frankfrank#include "bigint.ih" BigInt::BigInt(BigInt &&tmp) : d_bn(tmp.d_bn) { tmp.d_bn = BN_new(); } bobcat-5.09.01/bigint/destructor.cc0000644000175000017500000000007714050437223016071 0ustar frankfrank#include "bigint.ih" BigInt::~BigInt() { BN_free(d_bn); } bobcat-5.09.01/bigint/opdivis.cc0000644000175000017500000000017514050437223015347 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::operator/=(BigInt const &rhs) { checked3(d_bn, 0, rhs, "/="); return *this; } bobcat-5.09.01/bigint/opis.cc0000644000175000017500000000020214050437223014633 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::operator=(BigInt const &other) { BigInt tmp(other); swap(tmp); return *this; } bobcat-5.09.01/bigint/oplessequal.f0000644000175000017500000000014314050437223016062 0ustar frankfrankinline bool operator<=(BigInt const &lhs, BigInt const &rhs) { return lhs.compare(rhs) <= 0; } bobcat-5.09.01/bigint/isodd.f0000644000175000017500000000010214050437223014622 0ustar frankfrankinline bool BigInt::isOdd() const { return BN_is_odd(d_bn); } bobcat-5.09.01/bigint/gcd.cc0000644000175000017500000000016514050437223014426 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::gcd(BigInt const &rhs) { checked4(BN_gcd, rhs, "gcd"); return *this; } bobcat-5.09.01/bigint/swap.cc0000644000175000017500000000012514050437223014637 0ustar frankfrank#include "bigint.ih" void BigInt::swap(BigInt &other) { fswap(*this, other); } bobcat-5.09.01/bigint/opandis.cc0000644000175000017500000000147314050437223015331 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::operator&=(BigInt const &rhs) { setNegative(isNegative() && rhs.isNegative()); size_t nMin = min(sizeInBytes(), rhs.sizeInBytes()); size_t nMax = max(sizeInBytes(), rhs.sizeInBytes()); unsigned char small[nMin]; unsigned char large[nMax]; BIGNUM const *bSmall; BIGNUM const *bLarge; if (sizeInBytes() < rhs.sizeInBytes()) { bSmall = d_bn; bLarge = rhs.d_bn; } else { bLarge = d_bn; bSmall = rhs.d_bn; } BN_bn2bin(bSmall, small); BN_bn2bin(bLarge, large); unsigned char *largePtr = large + nMax - nMin; for (size_t idx = 0; idx != nMin; ++idx) // AND bytes 0 to nMin small[idx] &= largePtr[idx]; BN_bin2bn(small, nMin, d_bn); return *this; } bobcat-5.09.01/bigint/opaddis.f0000644000175000017500000000014014050437223015145 0ustar frankfrankinline BigInt &BigInt::operator+=(BigInt const &rhs) { return checked1(BN_add, rhs, "+"); } bobcat-5.09.01/bigint/opbool.f0000644000175000017500000000011514050437223015016 0ustar frankfrankinline BigInt::Bit::operator bool() const { return d_bi.hasBit(d_idx); } bobcat-5.09.01/bigint/bigint8.cc0000644000175000017500000000036014050437223015232 0ustar frankfrank#include "bigint.ih" BigInt::BigInt(char const *bigEndian, size_t length, bool negative) : d_bn(BN_new()) { BN_bin2bn(reinterpret_cast(bigEndian), length, d_bn); setNegative(negative); } bobcat-5.09.01/bigint/opextract.cc0000644000175000017500000000157614050437223015711 0ustar frankfrank#include "bigint.ih" namespace FBB { std::istream &operator>>(std::istream &in, BigInt &bn) { string value; int flags = in.flags(); int (*charType)(int) = flags & ios::dec ? ::isdigit : flags & ios::hex ? ::isxdigit : FBB::isoctdigit; char c; in >> c; // skip ws in.putback(c); if (in.peek() == '-') { in.ignore(1); value = '-'; } bool validInput = false; while (true) { int ch = static_cast(in.peek()); if (not (*charType)(ch)) { if (!validInput) { in.setstate(ios::failbit); return in; } break; } in.get(); value += ch; validInput = true; } bn = BigInt::fromText(value, flags); return in; } } bobcat-5.09.01/bigint/setnegativec.cc0000644000175000017500000000022114050437223016343 0ustar frankfrank#include "bigint.ih" BigInt BigInt::setNegativec(bool negative) const { BigInt ret(*this); ret.setNegative(negative); return ret; } bobcat-5.09.01/bigint/bignum.f0000644000175000017500000000010214050437223015001 0ustar frankfrankinline BIGNUM const &BigInt::bignum() const { return *d_bn; } bobcat-5.09.01/bigint/maskbits.cc0000644000175000017500000000027214050437223015505 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::maskBits(size_t lowerNBits) { if (!BN_mask_bits(d_bn, lowerNBits)) throw Exception{} << "BigInt::maskBits failed"; return *this; } bobcat-5.09.01/bigint/nwords.f0000644000175000017500000000013014050437223015035 0ustar frankfrankinline size_t BigInt::nWords() const { return (size() + BN_BYTES - 1) / BN_BYTES; } bobcat-5.09.01/bigint/ucompare.f0000644000175000017500000000014114050437223015336 0ustar frankfrankinline int BigInt::uCompare(BigInt const &other) const { return BN_ucmp(d_bn, other.d_bn); } bobcat-5.09.01/bigint/compare.f0000644000175000017500000000013714050437223015156 0ustar frankfrankinline int BigInt::compare(BigInt const &other) const { return BN_cmp(d_bn, other.d_bn); } bobcat-5.09.01/bigint/bigint9.cc0000644000175000017500000000021514050437223015232 0ustar frankfrank#include "bigint.ih" BigInt::BigInt(string const &bigEndian, bool negative) : BigInt(bigEndian.data(), bigEndian.length(), negative) {} bobcat-5.09.01/bigint/opmulis.cc0000644000175000017500000000031414050437223015355 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::operator*=(BigInt const &rhs) { BNCTX ctx; if (BN_mul(d_bn, d_bn, rhs.d_bn, ctx) == 0) throw Exception{} << "BigInt *= failed"; return *this; } bobcat-5.09.01/bigint/bigint2.cc0000644000175000017500000000020514050437223015222 0ustar frankfrank#include "bigint.ih" BigInt::BigInt(BigInt const &other) : d_bn(BN_new()) { // BN_init(d_bn); copy(d_bn, *other.d_bn); } bobcat-5.09.01/bigint/isoctdigit.cc0000644000175000017500000000015514050437223016032 0ustar frankfrank#include "bigint.ih" namespace FBB { int isoctdigit(int ch) { return strchr("01234567", ch) != 0; } } bobcat-5.09.01/bigint/ulong.f0000644000175000017500000000011514050437223014650 0ustar frankfrankinline unsigned long BigInt::ulong() const { return BN_get_word(d_bn); } bobcat-5.09.01/bigint/opadd.cc0000644000175000017500000000023214050437223014753 0ustar frankfrank#include "bigint.ih" namespace FBB { BigInt operator+(BigInt const &lhs, BigInt const &rhs) { BigInt tmp(lhs); tmp += rhs; return tmp; } } bobcat-5.09.01/bigint/checked3.cc0000644000175000017500000000041314050437223015336 0ustar frankfrank#include "bigint.ih" void BigInt::checked3(BIGNUM *div, BIGNUM *rem, BigInt const &rhs, char const *op) const { BNCTX ctx; if (BN_div(div, rem, d_bn, rhs.d_bn, ctx) != 1) throw Exception{} << "BigInt " << op << " failed"; } bobcat-5.09.01/bigint/expmodc.cc0000644000175000017500000000025014050437223015323 0ustar frankfrank#include "bigint.ih" BigInt BigInt::expModc(BigInt const &exponent, BigInt const &mod) const { BigInt ret(*this); ret.expMod(exponent, mod); return ret; } bobcat-5.09.01/bigint/opisunequal.f0000644000175000017500000000014314050437223016072 0ustar frankfrankinline bool operator!=(BigInt const &lhs, BigInt const &rhs) { return lhs.compare(rhs) != 0; } bobcat-5.09.01/bigint/isnegative.f0000644000175000017500000000012214050437223015660 0ustar frankfrankinline bool BigInt::isNegative() const { return BN_is_negative(this->d_bn); } bobcat-5.09.01/bigint/bigint.ih0000644000175000017500000000174014050437223015160 0ustar frankfrank#include "bigint" #include #include #include #include #include "../exception/exception" #include "../fswap/fswap" #if OPENSSL_VERSION_NUMBER < 0x10100000L inline BIGNUM *BN_generate_prime_ex(BIGNUM *ret, int num, int safe, BIGNUM *add, BIGNUM *rem, void (*callbackNotUsed)(int, int, void *)) { return BN_generate_prime(ret, num, safe, add, rem, callbackNotUsed, 0); } #endif namespace FBB { class BNCTX { BN_CTX *d_ctx; public: BNCTX(); // .f ~BNCTX(); // destructor.f void verify(); operator BN_CTX *(); // opbnctxptr.f private: BNCTX(BNCTX const &other) = delete; BNCTX &operator=(BNCTX const &other) = delete; }; #include "bnctx.f" #include "destructor.f" #include "opbnctxptr.f" } // namespace FBB using namespace std; using namespace FBB; bobcat-5.09.01/bigint/div.cc0000644000175000017500000000023014050437223014444 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::div(BigInt *remainder, BigInt const &rhs) { checked3(d_bn, remainder->d_bn, rhs, "div"); return *this; } bobcat-5.09.01/bigint/divc.cc0000644000175000017500000000026714050437223014621 0ustar frankfrank#include "bigint.ih" BigInt BigInt::divc(BigInt *remainder, BigInt const &rhs) const { BigInt ret(*this); checked3(ret.d_bn, remainder->d_bn, rhs, "div"); return ret; } bobcat-5.09.01/bigint/opnegate.cc0000644000175000017500000000016514050437223015473 0ustar frankfrank#include "bigint.ih" BigInt BigInt::operator-() const { BigInt tmp(*this); tmp.negate(); return tmp; } bobcat-5.09.01/bigint/tildeintc.cc0000644000175000017500000000016614050437223015651 0ustar frankfrank#include "bigint.ih" BigInt BigInt::tildeIntc() const { BigInt ret(*this); ret.tildeInt(); return ret; } bobcat-5.09.01/bigint/fromtext.cc0000644000175000017500000000265314050437223015545 0ustar frankfrank#include "bigint.ih" // conversion stops at the first character outside of the expected range of // characters. BigInt BigInt::fromText(string const &text, int mode) { BigInt ret; // determine the mode from text unless the conversion // mode was explicitly specified if ((mode & (ios::hex | ios::oct | ios::dec)) == 0) mode = text.find_first_of("abcdefABCDEF") != string::npos ? ios::hex : text.find_first_of("89") == string::npos && text[0] == '0' ? ios::oct : ios::dec; BigInt radix(mode & ios::oct ? 8 : mode & ios::hex ? 16 : 10); bool negative = text[0] == '-'; int (*isFunction)(int) = mode & ios::oct ? isoctdigit : mode & ios::hex ? ::isxdigit : ::isdigit; auto iter = find_if( text.begin() + negative, text.end(), [&, isFunction](char ch) { return addDigit(ch, ret, radix, isFunction); } ); if (iter - (text.begin() + negative) == 0) throw Exception{} << "fromText: text does not represent a BigInt value"; if (negative) ret.negate(); return ret; } bobcat-5.09.01/bigint/clearbit.cc0000644000175000017500000000016314050437223015454 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::clearBit(size_t index) { BN_clear_bit(d_bn, index); return *this; } bobcat-5.09.01/bigint/oplshift.cc0000644000175000017500000000023114050437223015513 0ustar frankfrank#include "bigint.ih" namespace FBB { BigInt operator<<(BigInt const &lhs, size_t nBits) { BigInt tmp(lhs); tmp <<= nBits; return tmp; } } bobcat-5.09.01/bigint/opdec.f0000644000175000017500000000007714050437223014625 0ustar frankfrankinline BigInt &BigInt::operator--() { return *this -= 1; } bobcat-5.09.01/bigint/sizeinbytes.f0000644000175000017500000000011514050437223016074 0ustar frankfrankinline size_t BigInt::sizeInBytes() const { return BN_num_bytes(d_bn); } bobcat-5.09.01/bigint/opor.cc0000644000175000017500000000023214050437223014643 0ustar frankfrank#include "bigint.ih" namespace FBB { BigInt operator|(BigInt const &lhs, BigInt const &rhs) { BigInt tmp(lhs); tmp |= rhs; return tmp; } } bobcat-5.09.01/bigint/inversemod.cc0000644000175000017500000000016614050437223016045 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::inverseMod(BigInt const &mod) { mod_inverse(this, mod); return *this; } bobcat-5.09.01/bigint/clearbitc.cc0000644000175000017500000000022114050437223015612 0ustar frankfrank#include "bigint.ih" BigInt BigInt::clearBit(size_t index) const { BigInt ret(*this); BN_clear_bit(ret.d_bn, index); return ret; } bobcat-5.09.01/bigint/driver/0000755000175000017500000000000014050437223014653 5ustar frankfrankbobcat-5.09.01/bigint/driver/build0000755000175000017500000000121514050437223015677 0ustar frankfrank#!/bin/bash tput clear LIBS=" -lbobcat -lcrypto" GPP="g++ `cat ../../c++std`" # WHEN LINKING TO A STATIC LIBRARY DON'T FORGET TO LINK AGAINST # crypto (-lcrypto) # link against ../tmp/libbigint.a CMD="$GPP -o driver -Wall -I../ driver.cc -L../tmp -lbigint ${LIBS} -s" # CMD="$GPP -o driver -Wall -I../../tmp driver.cc -L../../tmp/lib ${LIBS} -s" # CMD="$GPP -o driver -Wall -I../ driver.cc -L../tmp ${LIBS} -s" # link against object files in .. # CMD="$GPP -o driver -Wall -I../ driver.cc ../*.o ${LIBS} -s" # link against the standard bobcat library # CMD="$GPP -o driver -Wall *.cc ${LIBS} -s" echo $CMD $CMD || exit 1 echo Ready... driver bobcat-5.09.01/bigint/driver/driver.cc0000644000175000017500000001266414050437223016466 0ustar frankfrank#include #include #include #include "../bigint" #include using namespace std; using namespace FBB; void binary(BigInt const &bi) { cerr << bi.size() << " bits: "; for (size_t idx = bi.sizeInBytes() * 8 ; idx--; ) cerr << bi[idx]; cerr << '\n'; } int main(int argc, char **argv) try { if (argc == 1) throw Exception(1) << "Provide h (hex), o (oct), or d (dec) argument"; // BigInt value; // // int mode = argv[1][0]; // // cin >> // (mode == 'h' ? hex : mode == 'o' ? oct : dec) >> // value; // // if (cin.fail()) // cerr << "Input failed\n"; // else // cerr << '\n' << // value << '\n' << // oct << value << '\n' << // hex << value << '\n'; BigInt zero; // default construction of a BigInt cerr << "Defaults to zero: " << zero << '\n'; BigInt other{zero}; // Copycons cerr << "Copying zero: " << other << '\n'; BigInt five(5); // Member template cerr << "Member template constructs 5: " << five << '\n'; cerr << "five.operator-(): " << -five << '\n'; cerr << "five.negate(): " << five.negate() << '\n'; cerr << "five.isNegative(): " << five.isNegative() << '\n'; five.setNegative(false); cerr << "five.setNegative(false): negative? " << five.isNegative() << '\n'; cerr << "five: " << five << ". "; binary(five); cerr << "five.tildeBits(): " << five.tildeBits() << ". "; binary(five); five = 5; cerr << "five.tildeInt(): " << five.tildeInt() << ". "; binary(five); cerr << "++ --zero: " << ++ --zero << " (zero = " << zero << ")\n"; BigInt zeroOrg(zero--); cerr << "zeroOrg(zero--): zeroOrg: " << zeroOrg << ", zero: " << zero << '\n'; five = 5; cerr << "five: " << five << ". "; binary(five); cerr << "five[1]: " << five[1] << '\n'; five[1] |= 1; cerr << "five[1] |= 1: " << five[1] << '\n'; cerr << "five: " << five << ". "; binary(five); five[1] ^= 1; cerr << "five[1] ^= 1: " << five[1] << '\n'; cerr << "five: " << five << ". "; binary(five); cerr << "five[0] &= 1: " << (five[0] &= 1) << '\n'; cerr << "five: " << five << ". "; binary(five); BigInt large(0x123456); cerr << hex << "0x" << large << '\n'; char *bigEndian = large.bigEndian(); for (size_t idx = 0; idx < large.sizeInBytes(); ++idx) cerr << "byte[" << idx << "]: 0x" << static_cast(static_cast(bigEndian[idx])) << '\n'; swap(bigEndian[0], bigEndian[large.sizeInBytes()-1]); string newValue(bigEndian, bigEndian + large.sizeInBytes()); delete[] bigEndian; large = BigInt::setBigEndian(newValue); cerr << "Swapped lowest and highest bytes: 0x" << large << dec << '\n'; cerr << "large = five: " << (large = five) << '\n'; cerr << "large += large: " << (large += large) << '\n'; cerr << "large.addMod(five, 13) : " << large.addMod(five, 13) << '\n'; large = 123456789; cerr << "large (= 123456789) / 1234 = " << (large /= 1234) << '\n'; large = 123456789; BigInt remainder; large.div(&remainder, 1234); cerr << "Remainder of the division: " << remainder << '\n'; cerr << "GCD of " << large << " and 123 is: " << large.gcd(123) << '\n'; cerr << "large.sqr(): " << large.sqr() << '\n'; cerr << "large.sqrmod(" << "12345): " << large.sqrMod(12345) << '\n'; cerr << "Binary |, & and ^ operations:\n"; large = 0x123; binary(large); binary(large | 0x111); binary(large ^ 0x111); binary(large & 0x111); cerr << large << " == " << large << "? " << (large == large) << '\n'; cerr << large << " != " << large << "? " << (large != large) << '\n'; cerr << large << " < " << five << "? " << (large < five) << '\n'; cerr << large << " <= " << five << "? " << (large <= five) << '\n'; cerr << large << " > " << five << "? " << (large > five) << '\n'; cerr << large << " >= " << five << "? " << (large >= five) << '\n'; large = 123456789; cerr << large << ".exp(4) = "; cerr << large.expc(4) << '\n'; cerr << large << ".expModc(123, 169) = "; cerr << large.expModc(123, 169) << '\n'; BigInt invmod(large.inverseModc(169)); cerr << "large.inverseMod(169) = invmod = " << invmod << '\n'; cerr << large << ".mulModc(invmod, 169): "; cerr << large.mulModc(invmod, 169) << '\n'; cerr << "as: (large * invmod) % 169: " << (large * invmod) % 169 << '\n'; cerr << "Illustrating encryption using xor operations:\n"; string orig("This is the secret message"); cerr << "original text: " << orig << '\n'; BigInt origNr; origNr = BigInt::setBigEndian(orig); BigInt randnr(BigInt::rand(origNr.size())); cerr << "orig text in hex: " << hex << origNr << dec << '\n'; cerr << "same nr of random nrs: " << hex << randnr << dec << '\n'; cerr << hex; cerr << "orig txt ^ random nrs: " << (origNr ^= randnr) << '\n'; cerr << "orig txt ^ random nrs: " << (origNr ^= randnr) << dec << '\n'; cerr << "retrieved text: "; char *txt = origNr.bigEndian(); cerr.write(txt, origNr.sizeInBytes()) << '\n'; } catch(exception const &err) { cerr << err.what() << '\n'; return 1; } bobcat-5.09.01/bigint/diophantus2.cc0000644000175000017500000000101014050437223016117 0ustar frankfrank#include "bigint.ih" // static BigInt BigInt::diophantus(BigInt *factor1, BigInt *factor2, BigInt const &value1, BigInt const &value2) { BigInt modulo = value1 % value2; if (not modulo.isZero()) { BigInt nestedFactor1; BigInt gcd = diophantus(&nestedFactor1, factor2, value2, modulo); *factor1 = *factor2; *factor2 = nestedFactor1 - (value1 / value2) * *factor2; return gcd; } *factor1 = 0; *factor2 = 1; return value2; } bobcat-5.09.01/bigint/maskbitsc.cc0000644000175000017500000000022214050437223015643 0ustar frankfrank#include "bigint.ih" BigInt BigInt::maskBitsc(size_t lowerNBits) const { BigInt ret(*this); ret.maskBits(lowerNBits); return ret; } bobcat-5.09.01/bigint/copy.cc0000644000175000017500000000024714050437223014644 0ustar frankfrank#include "bigint.ih" void BigInt::copy(BIGNUM *lhs, BIGNUM const &rhs) { if (!BN_copy(lhs, &rhs)) throw Exception{} << "BigInt: copying BigInt failed"; } bobcat-5.09.01/binarysearch/0000755000175000017500000000000014050437223014556 5ustar frankfrankbobcat-5.09.01/binarysearch/binarysearch2.f0000644000175000017500000000070614050437223017464 0ustar frankfranktemplate Iterator binary_search(Iterator begin, Iterator end, Type const &value, Comparator comparator) { // note: the comparator's lhs parameter is an element in // the begin..end range, its rhs parameter is 'value' auto iter = std::lower_bound(begin, end, value, comparator); return not (iter == end) and not (value < *iter) ? iter : end; } bobcat-5.09.01/binarysearch/binarysearch0000644000175000017500000000043214050437223017152 0ustar frankfrank#ifndef INCLUDED_BOBCAT_BINARYSEARCH_ #define INCLUDED_BOBCAT_BINARYSEARCH_ #include namespace FBB { #include "binarysearch1.f" // Iterator begin, Iterator end, Type const &value #include "binarysearch2.f" // (... same ...), Comparator comparator } // FBB #endif bobcat-5.09.01/binarysearch/binarysearch1.f0000644000175000017500000000036014050437223017457 0ustar frankfranktemplate Iterator binary_search(Iterator begin, Iterator end, Type const &value) { auto iter = std::lower_bound(begin, end, value); return not (iter == end) and not (value < *iter) ? iter : end; } bobcat-5.09.01/binarysearch/driver/0000755000175000017500000000000014050437223016051 5ustar frankfrankbobcat-5.09.01/binarysearch/driver/build0000755000175000017500000000004314050437223017073 0ustar frankfrank#!/bin/sh g++ -o driver driver.cc bobcat-5.09.01/binarysearch/driver/driver.cc0000644000175000017500000000224514050437223017656 0ustar frankfrank#include #include #include "../binarysearch" using namespace std; string words[] = { "eight", // alphabetically sorted number-names "five", "four", "nine", "one", "seven", "six", "ten", "three", "two" }; bool compFun(string const &left, string const &right) { return left < right; } int main() { string *ret = FBB::binary_search(words, words + 10, "five"); if (ret != words + 10) cout << "five is at offset " << (ret - words) << endl; ret = FBB::binary_search(words, words + 10, "grandpa"); if (ret == words + 10) cout << "grandpa is not the name of a number\n"; ret = FBB::binary_search(words, words + 10, "five", [&](string const &element, string const &value) { return element < value; } ); if (ret != words + 10) cout << "five is at offset " << (ret - words) << endl; ret = FBB::binary_search(words, words + 10, "grandpa", compFun); // or use: Comparator() if (ret == words + 10) cout << "grandpa is not the name of a number\n"; } bobcat-5.09.01/binarysearch/driver/driver2.cc0000644000175000017500000000151714050437223017741 0ustar frankfrank#include #include #include "../binarysearch" using namespace std; struct Words { string str; int value; }; bool operator<(Words const &word, string const &str) { return word.str < str; } bool operator<(string const &str, Words const &word) { return str < word.str; } Words words[] = { { "eight", 0 }, // alphabetically sorted number-names { "five", 0 }, { "four", 0 }, { "nine", 0 }, { "one", 0 }, { "seven", 0 }, { "six", 0 }, { "ten", 0 }, { "three", 0 }, { "two", 0 } }; int main() { auto ret = FBB::binary_search(words, words + 10, "five", [&](Words const &element, string const &value) { return element < value; } ); cout << (ret != words + 10 ? "found it" : "not present") << '\n'; } bobcat-5.09.01/binops/0000755000175000017500000000000014050437223013376 5ustar frankfrankbobcat-5.09.01/binops/opmod1.f0000644000175000017500000000016614050437223014747 0ustar frankfranktemplate inline Class operator%(Class &&lhs, Class const &rhs) { return std::move(lhs %= rhs); } bobcat-5.09.01/binops/opbitand1.f0000644000175000017500000000016614050437223015431 0ustar frankfranktemplate inline Class operator&(Class &&lhs, Class const &rhs) { return std::move(lhs &= rhs); } bobcat-5.09.01/binops/opbitxor2.f0000644000175000017500000000040114050437223015470 0ustar frankfranktemplate inline typename FBB::Use::type operator^(LHS const &lhs, RHS const &rhs) { typename FBB::Use::type tmp(lhs); tmp ^= rhs; return tmp; } bobcat-5.09.01/binops/opbitxor1.f0000644000175000017500000000016614050437223015477 0ustar frankfranktemplate inline Class operator^(Class &&lhs, Class const &rhs) { return std::move(lhs ^= rhs); } bobcat-5.09.01/binops/opadd1.f0000644000175000017500000000016614050437223014720 0ustar frankfranktemplate inline Class operator+(Class &&lhs, Class const &rhs) { return std::move(lhs += rhs); } bobcat-5.09.01/binops/optimes1.f0000644000175000017500000000016614050437223015311 0ustar frankfranktemplate inline Class operator*(Class &&lhs, Class const &rhs) { return std::move(lhs *= rhs); } bobcat-5.09.01/binops/opbitand2.f0000644000175000017500000000040114050437223015422 0ustar frankfranktemplate inline typename FBB::Use::type operator&(LHS const &lhs, RHS const &rhs) { typename FBB::Use::type tmp(lhs); tmp &= rhs; return tmp; } bobcat-5.09.01/binops/binops0000644000175000017500000000260314050437223014614 0ustar frankfrank#ifndef INCLUDED_BOBCAT_BINOPS_ #define INCLUDED_BOBCAT_BINOPS_ // This header file requires the separate inclusion of // // // The templates in this file were not defined in the namespace FBB to enhance // their usability. If you want to declare them in a namespace of your own // include them in your namespace-block, like this: // namespace YOUR_NAMESPACE // { // #include // } #include "opadd1.f" // Class && + Class #include "opadd2.f" // LHS + RHS #include "opbitand1.f" // Class && & Class #include "opbitand2.f" // LHS & RHS #include "opbitor1.f" // Class && | Class #include "opbitor2.f" // LHS | RHS #include "opbitxor1.f" // Class && ^ Class #include "opbitxor2.f" // LHS ^ RHS #include "opdiv1.f" // Class && / Class #include "opdiv2.f" // LHS / RHS #include "opmod1.f" // Class && % Class #include "opmod2.f" // LHS % RHS #include "opshl1.f" // Class && << Class #include "opshl2.f" // LHS << RHS #include "opshr1.f" // Class && >> Class #include "opshr2.f" // LHS >> RHS #include "opsub1.f" // Class && - Class #include "opsub2.f" // LHS - RHS #include "optimes1.f" // Class && * Class #include "optimes2.f" // LHS * RHS #endif bobcat-5.09.01/binops/opshr2.f0000644000175000017500000000040314050437223014757 0ustar frankfranktemplate inline typename FBB::Use::type operator>>(LHS const &lhs, RHS const &rhs) { typename FBB::Use::type tmp(lhs); tmp >>= rhs; return tmp; } bobcat-5.09.01/binops/opdiv2.f0000644000175000017500000000040114050437223014743 0ustar frankfranktemplate inline typename FBB::Use::type operator/(LHS const &lhs, RHS const &rhs) { typename FBB::Use::type tmp(lhs); tmp /= rhs; return tmp; } bobcat-5.09.01/binops/optimes2.f0000644000175000017500000000040114050437223015302 0ustar frankfranktemplate inline typename FBB::Use::type operator*(LHS const &lhs, RHS const &rhs) { typename FBB::Use::type tmp(lhs); tmp *= rhs; return tmp; } bobcat-5.09.01/binops/opbitor1.f0000644000175000017500000000016614050437223015307 0ustar frankfranktemplate inline Class operator|(Class &&lhs, Class const &rhs) { return std::move(lhs |= rhs); } bobcat-5.09.01/binops/opdiv1.f0000644000175000017500000000016614050437223014752 0ustar frankfranktemplate inline Class operator/(Class &&lhs, Class const &rhs) { return std::move(lhs /= rhs); } bobcat-5.09.01/binops/opshr1.f0000644000175000017500000000017014050437223014757 0ustar frankfranktemplate inline Class operator>>(Class &&lhs, Class const &rhs) { return std::move(lhs >>= rhs); } bobcat-5.09.01/binops/opsub1.f0000644000175000017500000000016614050437223014761 0ustar frankfranktemplate inline Class operator-(Class &&lhs, Class const &rhs) { return std::move(lhs -= rhs); } bobcat-5.09.01/binops/opsub2.f0000644000175000017500000000040114050437223014752 0ustar frankfranktemplate inline typename FBB::Use::type operator-(LHS const &lhs, RHS const &rhs) { typename FBB::Use::type tmp(lhs); tmp -= rhs; return tmp; } bobcat-5.09.01/binops/opshl2.f0000644000175000017500000000040314050437223014751 0ustar frankfranktemplate inline typename FBB::Use::type operator<<(LHS const &lhs, RHS const &rhs) { typename FBB::Use::type tmp(lhs); tmp <<= rhs; return tmp; } bobcat-5.09.01/binops/opmod2.f0000644000175000017500000000040114050437223014740 0ustar frankfranktemplate inline typename FBB::Use::type operator%(LHS const &lhs, RHS const &rhs) { typename FBB::Use::type tmp(lhs); tmp %= rhs; return tmp; } bobcat-5.09.01/binops/opshl1.f0000644000175000017500000000017014050437223014751 0ustar frankfranktemplate inline Class operator<<(Class &&lhs, Class const &rhs) { return std::move(lhs <<= rhs); } bobcat-5.09.01/binops/driver/0000755000175000017500000000000014050437223014671 5ustar frankfrankbobcat-5.09.01/binops/driver/build0000755000175000017500000000010214050437223015707 0ustar frankfrank#!/bin/bash g++ `cat ../../c++std` -Wall -o driver driver.cc -s bobcat-5.09.01/binops/driver/driver.cc0000644000175000017500000000151214050437223016472 0ustar frankfrank#include #include #include "../../typetrait/typetrait" #include "../binops" class Demo { friend std::ostream &operator<<(std::ostream &out, Demo const &demo); int d_value; public: Demo(int value = 0) : d_value(value) {} Demo(Demo const &other) : d_value(other.d_value) { std::cout << "Demo CC called\n"; } Demo &operator+=(Demo const &rhs) { d_value += rhs.d_value; return *this; } }; std::ostream &operator<<(std::ostream &out, Demo const &demo) { return out << demo.d_value; } using namespace std; int main() { Demo four(4); Demo five(5); cout << four + five << '\n' << four + 5 << '\n' << 4 + five << '\n'; } bobcat-5.09.01/binops/opbitor2.f0000644000175000017500000000040114050437223015300 0ustar frankfranktemplate inline typename FBB::Use::type operator|(LHS const &lhs, RHS const &rhs) { typename FBB::Use::type tmp(lhs); tmp |= rhs; return tmp; } bobcat-5.09.01/binops/opadd2.f0000644000175000017500000000040114050437223014711 0ustar frankfranktemplate inline typename FBB::Use::type operator+(LHS const &lhs, RHS const &rhs) { typename FBB::Use::type tmp(lhs); tmp += rhs; return tmp; } bobcat-5.09.01/binopsbase/0000755000175000017500000000000014050437223014231 5ustar frankfrankbobcat-5.09.01/binopsbase/sub.f0000644000175000017500000000076214050437223015176 0ustar frankfrank template Derived &operator-=(BinopsBase &lhs, Rhs const &rhs) { Derived tmp{ Derived{der(lhs)} -= rhs }; tmp.swap(der(lhs)); return der(lhs); } template Derived operator-(BinopsBase &&lhs, Rhs const &rhs) { return der(std::move(lhs)) -= rhs; } template Derived operator-(BinopsBase const &lhs, Rhs const &rhs) { return Derived{der(lhs)} -= rhs; } bobcat-5.09.01/binopsbase/or.f0000644000175000017500000000076214050437223015025 0ustar frankfrank template Derived &operator|=(BinopsBase &lhs, Rhs const &rhs) { Derived tmp{ Derived{der(lhs)} |= rhs }; tmp.swap(der(lhs)); return der(lhs); } template Derived operator|(BinopsBase &&lhs, Rhs const &rhs) { return der(std::move(lhs)) |= rhs; } template Derived operator|(BinopsBase const &lhs, Rhs const &rhs) { return Derived{der(lhs)} |= rhs; } bobcat-5.09.01/binopsbase/binopsbase0000644000175000017500000000140414050437223016300 0ustar frankfrank#ifndef INCLUDED_BINOPSFREE_ #define INCLUDED_BINOPSFREE_ #include #include #include namespace FBB { template class BinopsBase { template friend std::ostream &operator<<(std::ostream &out, BinopsBase const &rhs); template friend std::istream &operator>>(std::istream &in, BinopsBase &rhs); void eWrap(std::istream &in); void iWrap(std::ostream &out) const; }; #include "der.f" #include "mul.f" #include "div.f" #include "mod.f" #include "add.f" #include "sub.f" #include "shl1.f" #include "shr1.f" #include "and.f" #include "or.f" #include "xor.f" #include "extract.f" #include "insert.f" } // FBB #endif bobcat-5.09.01/binopsbase/shl1.f0000644000175000017500000000075714050437223015260 0ustar frankfrank template Derived &operator<<=(BinopsBase &lhs, Rhs const &rhs) { Derived tmp{ Derived{der(lhs)} <<= rhs }; tmp.swap(der(lhs)); return der(lhs); } template Derived operator<<(BinopsBase &&lhs, Rhs const &rhs) { return der(std::move(lhs)) <<= rhs; } template Derived operator<<(BinopsBase const &lhs, Rhs const &rhs) { return Derived{der(lhs)} <<= rhs; } bobcat-5.09.01/binopsbase/shr1.f0000644000175000017500000000077014050437223015261 0ustar frankfrank template Derived &operator>>=(BinopsBase &lhs, Rhs const &rhs) { Derived tmp{ Derived{der(lhs)} >>= rhs }; tmp.swap(der(lhs)); return der(lhs); } template Derived operator>>(BinopsBase &&lhs, Rhs const &rhs) { return der(std::move(lhs)) >>= rhs; } template Derived operator>>(BinopsBase const &lhs, Rhs const &rhs) { return Derived{der(lhs)} >>= rhs; } bobcat-5.09.01/binopsbase/der.f0000644000175000017500000000060214050437223015150 0ustar frankfranktemplate constexpr Derived &der(BinopsBase &rhs) { return static_cast(rhs); } template constexpr Derived const &der(BinopsBase const &rhs) { return static_cast(rhs); } template constexpr Derived &&der(BinopsBase &&rhs) { return static_cast(rhs); } bobcat-5.09.01/binopsbase/extract.f0000644000175000017500000000040414050437223016050 0ustar frankfranktemplate inline void BinopsBase::eWrap(std::istream &in) { der(*this).extract(in); } template inline std::istream &operator>>(std::istream &in, BinopsBase &rhs) { rhs.eWrap(in); return in; } bobcat-5.09.01/binopsbase/mul.f0000644000175000017500000000076214050437223015202 0ustar frankfrank template Derived &operator*=(BinopsBase &lhs, Rhs const &rhs) { Derived tmp{ Derived{der(lhs)} *= rhs }; tmp.swap(der(lhs)); return der(lhs); } template Derived operator*(BinopsBase &&lhs, Rhs const &rhs) { return der(std::move(lhs)) *= rhs; } template Derived operator*(BinopsBase const &lhs, Rhs const &rhs) { return Derived{der(lhs)} *= rhs; } bobcat-5.09.01/binopsbase/insert.f0000644000175000017500000000042414050437223015704 0ustar frankfranktemplate inline void BinopsBase::iWrap(std::ostream &out) const { der(*this).insert(out); } template inline std::ostream &operator<<(std::ostream &out, BinopsBase const &rhs) { rhs.iWrap(out); return out; } bobcat-5.09.01/binopsbase/mod.f0000644000175000017500000000076214050437223015164 0ustar frankfrank template Derived &operator%=(BinopsBase &lhs, Rhs const &rhs) { Derived tmp{ Derived{der(lhs)} %= rhs }; tmp.swap(der(lhs)); return der(lhs); } template Derived operator%(BinopsBase &&lhs, Rhs const &rhs) { return der(std::move(lhs)) %= rhs; } template Derived operator%(BinopsBase const &lhs, Rhs const &rhs) { return Derived{der(lhs)} %= rhs; } bobcat-5.09.01/binopsbase/xor.f0000644000175000017500000000076214050437223015215 0ustar frankfrank template Derived &operator^=(BinopsBase &lhs, Rhs const &rhs) { Derived tmp{ Derived{der(lhs)} ^= rhs }; tmp.swap(der(lhs)); return der(lhs); } template Derived operator^(BinopsBase &&lhs, Rhs const &rhs) { return der(std::move(lhs)) ^= rhs; } template Derived operator^(BinopsBase const &lhs, Rhs const &rhs) { return Derived{der(lhs)} ^= rhs; } bobcat-5.09.01/binopsbase/and.f0000644000175000017500000000076214050437223015147 0ustar frankfrank template Derived &operator&=(BinopsBase &lhs, Rhs const &rhs) { Derived tmp{ Derived{der(lhs)} &= rhs }; tmp.swap(der(lhs)); return der(lhs); } template Derived operator&(BinopsBase &&lhs, Rhs const &rhs) { return der(std::move(lhs)) &= rhs; } template Derived operator&(BinopsBase const &lhs, Rhs const &rhs) { return Derived{der(lhs)} &= rhs; } bobcat-5.09.01/binopsbase/add.f0000644000175000017500000000075114050437223015133 0ustar frankfrank template Derived &operator+=(BinopsBase &lhs, Rhs const &rhs) { Derived tmp{ Derived{der(lhs)} += rhs }; tmp.swap(der(lhs)); return der(lhs); } template Derived operator+(BinopsBase &&lhs, Rhs const &rhs) { return der(std::move(lhs)) += rhs; } template Derived operator+(BinopsBase const &lhs, Rhs const &rhs) { return Derived{der(lhs)} += rhs; } bobcat-5.09.01/binopsbase/driver/0000755000175000017500000000000014050437223015524 5ustar frankfrankbobcat-5.09.01/binopsbase/driver/driver.cc0000644000175000017500000000475514050437223017341 0ustar frankfrank#include #include class Demo1: public FBB::BinopsBase { friend FBB::BinopsBase; // for insert/extract public: void swap(Demo1 &other) {} Demo1 &&operator+=(Demo1 const &rhs) && { std::cout << "adding two Demo1 objects\n"; return std::move(*this); } // Explicit definitions take precedence over functions templates // instantiated from definitions in bobcat/binopsbase. // Demo1 &operator+=(Demo1 const &rhs) & // { // std::cout << "adding (self-defined) two Demo1 objects\n"; // return *this; // } Demo1 &&operator-=(Demo1 const &rhs) && { std::cout << "subtracting two Demo1 objects\n"; return std::move(*this); } Demo1 &&operator<<=(Demo1 const &rhs) && { std::cout << "shiftleft on two Demo1 objects\n"; return std::move(*this); } Demo1 &&operator<<=(size_t rhs) && { std::cout << "shiftleft Demo1 object size_t bits\n"; return std::move(*this); } void insert(std::ostream &out) const // requires friend { out << "inerting a Demo1 object\n"; } void extract(std::istream &in) // requires friend { std::cout << "extracting a Demo1 object\n"; } }; class Demo2: public FBB::BinopsBase { public: void swap(Demo2 &other) {} Demo2 &&operator+=(Demo2 const &rhs) && { std::cout << "adding two Demo2 objects\n"; return std::move(*this); } Demo2 &operator+=(Demo2 const &rhs) & { std::cout << "adding (self-defined) two Demo2 objects"; return *this; } Demo2 &&operator^=(Demo2 const &rhs) && { std::cout << "xor-ing two Demo2 objects\n"; return std::move(*this); } Demo2 &&operator|=(Demo2 const &rhs) && { std::cout << "or-ing two Demo2 objects\n"; return std::move(*this); } }; int main() { Demo1 d1a, d1b; Demo1 d1c = d1a + d1b; d1a += d1b; d1c = Demo1{} + d1b; std::cout << "Here we are " << d1c << '\n'; std::cin >> d1c; d1a <<= d1a; d1a <<= 5; Demo2 d2a, d2b; Demo2 d2c = d2a + d2b; d2a ^= d2b; d2c = Demo2{} ^ d2b; d2c = d2c | d2b; } bobcat-5.09.01/binopsbase/driver/README0000644000175000017500000000025114050437223016402 0ustar frankfrank * Self-defined binary operators take priority over the template instantiations: it's always possible to outguess/outperform the template definitions. bobcat-5.09.01/binopsbase/div.f0000644000175000017500000000076214050437223015167 0ustar frankfrank template Derived &operator/=(BinopsBase &lhs, Rhs const &rhs) { Derived tmp{ Derived{der(lhs)} /= rhs }; tmp.swap(der(lhs)); return der(lhs); } template Derived operator/(BinopsBase &&lhs, Rhs const &rhs) { return der(std::move(lhs)) /= rhs; } template Derived operator/(BinopsBase const &lhs, Rhs const &rhs) { return Derived{der(lhs)} /= rhs; } bobcat-5.09.01/binopsbase0/0000755000175000017500000000000014050437223014311 5ustar frankfrankbobcat-5.09.01/binopsbase0/shl.f0000644000175000017500000000175514050437223015256 0ustar frankfranktemplate struct Shl { Derived &operator<<=(Derived const &rhs) &; Derived &&operator<<=(Derived const &rhs) &&; }; template Derived &Shl::operator<<=(Derived const &rhs) & { Derived tmp{static_cast(*this)}; tmp.shlWrap(rhs); static_cast(*this).swap(tmp); return static_cast(*this); } template Derived &&Shl::operator<<=(Derived const &rhs) && { static_cast(*this).shlWrap(rhs); return std::move(static_cast(*this)); } template Derived operator<<(Derived const &lhs, Derived const &rhs) { Derived ret{lhs}; ret.shlWrap(rhs); return ret; } template Derived operator<<(Derived &&lhs, Derived const &rhs) { lhs.shlWrap(rhs); return std::move(lhs); } template class BinopsBase0 : public BinopsBase0, public Shl {}; bobcat-5.09.01/binopsbase0/sub.f0000644000175000017500000000175414050437223015260 0ustar frankfranktemplate struct Sub { Derived &operator-=(Derived const &rhs) &; Derived &&operator-=(Derived const &rhs) &&; }; template Derived &Sub::operator-=(Derived const &rhs) & { Derived tmp{static_cast(*this)}; tmp.subWrap(rhs); static_cast(*this).swap(tmp); return static_cast(*this); } template Derived &&Sub::operator-=(Derived const &rhs) && { static_cast(*this).subWrap(rhs); return std::move(static_cast(*this)); } template Derived operator-(Derived const &lhs, Derived const &rhs) { Derived ret{lhs}; ret.subWrap(rhs); return ret; } template Derived operator-(Derived &&lhs, Derived const &rhs) { lhs.subWrap(rhs); return std::move(lhs); } template class BinopsBase0 : public BinopsBase0, public Sub {}; bobcat-5.09.01/binopsbase0/or.f0000644000175000017500000000173714050437223015110 0ustar frankfranktemplate struct Or { Derived &operator|=(Derived const &rhs) &; Derived &&operator|=(Derived const &rhs) &&; }; template Derived &Or::operator|=(Derived const &rhs) & { Derived tmp{static_cast(*this)}; tmp.orWrap(rhs); static_cast(*this).swap(tmp); return static_cast(*this); } template Derived &&Or::operator|=(Derived const &rhs) && { static_cast(*this).orWrap(rhs); return std::move(static_cast(*this)); } template Derived operator|(Derived const &lhs, Derived const &rhs) { Derived ret{lhs}; ret.orWrap(rhs); return ret; } template Derived operator|(Derived &&lhs, Derived const &rhs) { lhs.orWrap(rhs); return std::move(lhs); } template class BinopsBase0 : public BinopsBase0, public Or {}; bobcat-5.09.01/binopsbase0/binopsbase0000644000175000017500000000246214050437223016365 0ustar frankfrank#ifndef INCLUDED_BOBCAT_BINOPSBASE_ #define INCLUDED_BOBCAT_BINOPSBASE_ #include #include #include namespace FBB { // The recursively defined BinopsBase0 class: receives so a static // cast becomes available to reach the basic arithmetic classes // The general declaration: // template class BinopsBase0; // The terminating definition: // template class BinopsBase0 {}; #include "mul.f" #include "div.f" #include "mod.f" #include "add.f" #include "sub.f" #include "shl.f" #include "shr.f" #include "and.f" #include "or.f" #include "xor.f" #include "insert.f" #include "extract.f" // The class BinopsBase befriends all arithmetic classes, and implements // wrappers for the arithmetic functions potentially defined in // Derived. // The arithmetic classes call BinopsBase' functions, which in turn call // Derived's functions. This way Derived only needs to implement the // necessary functions. Since the other functions aren't called, they // arent't instantiated so there are no linker-errors // template class BinopsBase: public BinopsBase0 { #include "friends.f" #include "wraps.f" }; #include "inlines.f" } // FBB #endif bobcat-5.09.01/binopsbase0/shr.f0000644000175000017500000000175514050437223015264 0ustar frankfranktemplate struct Shr { Derived &operator>>=(Derived const &rhs) &; Derived &&operator>>=(Derived const &rhs) &&; }; template Derived &Shr::operator>>=(Derived const &rhs) & { Derived tmp{static_cast(*this)}; tmp.shrWrap(rhs); static_cast(*this).swap(tmp); return static_cast(*this); } template Derived &&Shr::operator>>=(Derived const &rhs) && { static_cast(*this).shrWrap(rhs); return std::move(static_cast(*this)); } template Derived operator>>(Derived const &lhs, Derived const &rhs) { Derived ret{lhs}; ret.shrWrap(rhs); return ret; } template Derived operator>>(Derived &&lhs, Derived const &rhs) { lhs.shrWrap(rhs); return std::move(lhs); } template class BinopsBase0', ops...> : public BinopsBase0, public Shr {}; bobcat-5.09.01/binopsbase0/binopsbase.ih0000644000175000017500000000002614050437223016756 0ustar frankfrank#include "binopsbase" bobcat-5.09.01/binopsbase0/wraps.f0000644000175000017500000000074414050437223015621 0ustar frankfrank void mulWrap(Derived const &rhs); void divWrap(Derived const &rhs); void modWrap(Derived const &rhs); void addWrap(Derived const &rhs); void subWrap(Derived const &rhs); void shlWrap(Derived const &rhs); void shrWrap(Derived const &rhs); void andWrap(Derived const &rhs); void orWrap(Derived const &rhs); void xorWrap(Derived const &rhs); std::istream &extractWrap(std::istream &in); std::ostream &insertWrap(std::ostream &out) const; bobcat-5.09.01/binopsbase0/inlines.f0000644000175000017500000000502414050437223016122 0ustar frankfranktemplate inline std::ostream &BinopsBase::insertWrap( std::ostream &out) const { static_cast( static_cast const &>(*this) ).insert(out); return out; } template inline std::istream &BinopsBase::extractWrap( std::istream &in) { static_cast( static_cast const &>(*this) ).extract(in); return in; } template inline void BinopsBase::addWrap(Derived const &rhs) { static_cast( static_cast &>(*this) ).add(rhs); } template inline void BinopsBase::mulWrap(Derived const &rhs) { static_cast( static_cast &>(*this) ).mul(rhs); } template inline void BinopsBase::divWrap(Derived const &rhs) { static_cast( static_cast &>(*this) ).div(rhs); } template inline void BinopsBase::modWrap(Derived const &rhs) { static_cast( static_cast &>(*this) ).mod(rhs); } template inline void BinopsBase::subWrap(Derived const &rhs) { static_cast( static_cast &>(*this) ).sub(rhs); } template inline void BinopsBase::shlWrap(Derived const &rhs) { static_cast( static_cast &>(*this) ).shl(rhs); } template inline void BinopsBase::shrWrap(Derived const &rhs) { static_cast( static_cast &>(*this) ).shr(rhs); } template inline void BinopsBase::andWrap(Derived const &rhs) { static_cast( static_cast &>(*this) ).and_(rhs); } template inline void BinopsBase::orWrap(Derived const &rhs) { static_cast( static_cast &>(*this) ).or_(rhs); } template inline void BinopsBase::xorWrap(Derived const &rhs) { static_cast( static_cast &>(*this) ).xor_(rhs); } bobcat-5.09.01/binopsbase0/friends.f0000644000175000017500000000403414050437223016113 0ustar frankfrank friend Mul; friend Div; friend Mod; friend Add; friend Sub; friend Shl; friend Shr; friend And; friend Or; friend Xor; friend Insert; friend Extract; friend Derived operator*(Derived const &lhs, Derived const &rhs); friend Derived operator*(Derived &&lhs, Derived const &rhs); friend Derived operator/(Derived const &lhs, Derived const &rhs); friend Derived operator/(Derived &&lhs, Derived const &rhs); friend Derived operator%(Derived const &lhs, Derived const &rhs); friend Derived operator%(Derived &&lhs, Derived const &rhs); friend Derived operator+(Derived const &lhs, Derived const &rhs); friend Derived operator+(Derived &&lhs, Derived const &rhs); friend Derived operator-(Derived const &lhs, Derived const &rhs); friend Derived operator-(Derived &&lhs, Derived const &rhs); friend Derived operator<<(Derived const &lhs, Derived const &rhs); friend Derived operator<<(Derived &&lhs, Derived const &rhs); friend Derived operator>>(Derived const &lhs, Derived const &rhs); friend Derived operator>>(Derived &&lhs, Derived const &rhs); friend Derived operator&(Derived const &lhs, Derived const &rhs); friend Derived operator&(Derived &&lhs, Derived const &rhs); friend Derived operator|(Derived const &lhs, Derived const &rhs); friend Derived operator|(Derived &&lhs, Derived const &rhs); friend Derived operator^(Derived const &lhs, Derived const &rhs); friend Derived operator^(Derived &&lhs, Derived const &rhs); friend std::istream &operator>>(std::istream &in, Derived &rhs); friend std::ostream &operator<<(std::ostream &out, Derived const &rhs); bobcat-5.09.01/binopsbase0/extract.f0000644000175000017500000000047414050437223016137 0ustar frankfranktemplate struct Extract {}; template std::istream &operator>>(std::istream &in, Derived &rhs) { return rhs.extractWrap(in); } template class BinopsBase0 : public BinopsBase0, public Extract {}; bobcat-5.09.01/binopsbase0/mul.f0000644000175000017500000000175014050437223015260 0ustar frankfranktemplate struct Mul { Derived &operator*=(Derived const &rhs) &; Derived &&operator*=(Derived const &rhs) &&; }; template Derived &Mul::operator*=(Derived const &rhs) & { Derived tmp{static_cast(*this)}; tmp.mulWrap(rhs); static_cast(*this).swap(tmp); return static_cast(*this); } template Derived &&Mul::operator*=(Derived const &rhs) && { static_cast(*this).mulWrap(rhs); return std::move(static_cast(*this)); } template Derived operator*(Derived const &lhs, Derived const &rhs) { Derived ret{lhs}; ret.mulWrap(rhs); return ret; } template Derived operator*(Derived &&lhs, Derived const &rhs) { lhs.mulWrap(rhs); return std::move(lhs); } template class BinopsBase0 : public BinopsBase0, public Mul {}; bobcat-5.09.01/binopsbase0/insert.f0000644000175000017500000000050114050437223015760 0ustar frankfranktemplate struct Insert {}; template std::ostream &operator<<(std::ostream &out, Derived const &rhs) { return rhs.insertWrap(out); } template class BinopsBase0 : public BinopsBase0, public Insert {}; bobcat-5.09.01/binopsbase0/mod.f0000644000175000017500000000174714050437223015250 0ustar frankfranktemplate struct Mod { Derived &operator%=(Derived const &rhs) &; Derived &&operator%=(Derived const &rhs) &&; }; template Derived &Mod::operator%=(Derived const &rhs) & { Derived tmp{static_cast(*this)}; tmp.modWrap(rhs); static_cast(*this).swap(tmp); return static_cast(*this); } template Derived &&Mod::operator%=(Derived const &rhs) && { static_cast(*this).modWrap(rhs); return std::move(static_cast(*this)); } template Derived operator%(Derived const &lhs, Derived const &rhs) { Derived ret{lhs}; ret.modWrap(rhs); return ret; } template Derived operator%(Derived &&lhs, Derived const &rhs) { lhs.modWrap(rhs); return std::move(lhs); } template class BinopsBase0 : public BinopsBase0, public Mod {}; bobcat-5.09.01/binopsbase0/xor.f0000644000175000017500000000174714050437223015301 0ustar frankfranktemplate struct Xor { Derived &operator^=(Derived const &rhs) &; Derived &&operator^=(Derived const &rhs) &&; }; template Derived &Xor::operator^=(Derived const &rhs) & { Derived tmp{static_cast(*this)}; tmp.xorWrap(rhs); static_cast(*this).swap(tmp); return static_cast(*this); } template Derived &&Xor::operator^=(Derived const &rhs) && { static_cast(*this).xorWrap(rhs); return std::move(static_cast(*this)); } template Derived operator^(Derived const &lhs, Derived const &rhs) { Derived ret{lhs}; ret.xorWrap(rhs); return ret; } template Derived operator^(Derived &&lhs, Derived const &rhs) { lhs.xorWrap(rhs); return std::move(lhs); } template class BinopsBase0 : public BinopsBase0, public Xor {}; bobcat-5.09.01/binopsbase0/and.f0000644000175000017500000000174714050437223015233 0ustar frankfranktemplate struct And { Derived &operator&=(Derived const &rhs) &; Derived &&operator&=(Derived const &rhs) &&; }; template Derived &And::operator&=(Derived const &rhs) & { Derived tmp{static_cast(*this)}; tmp.andWrap(rhs); static_cast(*this).swap(tmp); return static_cast(*this); } template Derived &&And::operator&=(Derived const &rhs) && { static_cast(*this).andWrap(rhs); return std::move(static_cast(*this)); } template Derived operator&(Derived const &lhs, Derived const &rhs) { Derived ret{lhs}; ret.andWrap(rhs); return ret; } template Derived operator&(Derived &&lhs, Derived const &rhs) { lhs.andWrap(rhs); return std::move(lhs); } template class BinopsBase0 : public BinopsBase0, public And {}; bobcat-5.09.01/binopsbase0/add.f0000644000175000017500000000175314050437223015216 0ustar frankfranktemplate struct Add { Derived &operator+=(Derived const &rhs) &; Derived &&operator+=(Derived const &rhs) &&; }; template Derived &Add::operator+=(Derived const &rhs) & { Derived tmp{static_cast(*this)}; tmp.addWrap(rhs); static_cast(*this).swap(tmp); return static_cast(*this); } template Derived &&Add::operator+=(Derived const &rhs) && { static_cast(*this).addWrap(rhs); return std::move(static_cast(*this)); } template Derived operator+(Derived const &lhs, Derived const &rhs) { Derived ret{lhs}; ret.addWrap(rhs); return ret; } template Derived operator+(Derived &&lhs, Derived const &rhs) { lhs.addWrap(rhs); return std::move(lhs); } template class BinopsBase0 : public BinopsBase0, public Add {}; bobcat-5.09.01/binopsbase0/frame.f0000644000175000017500000000005314050437223015550 0ustar frankfrank#include "binopsbase.ih" BinopsBase:: { } bobcat-5.09.01/binopsbase0/driver/0000755000175000017500000000000014050437223015604 5ustar frankfrankbobcat-5.09.01/binopsbase0/driver/driver.cc0000644000175000017500000000231514050437223017407 0ustar frankfrank#include "../binopsbase" //#include #include using namespace std; class Demo1: public FBB::BinopsBase { friend FBB::BinopsBase; public: void swap(Demo1 &other) {} private: void add(Demo1 const &rhs) { cout << "adding two Demo1 objects\n"; } void sub(Demo1 const &rhs) { cout << "subtracting two Demo1 objects\n"; } void insert(ostream &out) const { out << "inserting a Demo1 object"; } }; class Demo2: public FBB::BinopsBase { friend FBB::BinopsBase; public: void swap(Demo2 &other) {} private: void add(Demo2 const &rhs) { cout << "adding two Demo2 objects\n"; } void xor_(Demo2 const &rhs) { cout << "xor-ing two Demo2 objects\n"; } }; int main() { Demo1 d1a, d1b; Demo1 d1c = d1a + d1b; d1a += d1b; d1c = Demo1{} + d1b; cout << d1a << '\n'; Demo2 d2a, d2b; Demo2 d2c = d2a + d2b; d2a ^= d2b; d2c = Demo2{} ^ d2b; } bobcat-5.09.01/binopsbase0/div.f0000644000175000017500000000174714050437223015253 0ustar frankfranktemplate struct Div { Derived &operator/=(Derived const &rhs) &; Derived &&operator/=(Derived const &rhs) &&; }; template Derived &Div::operator/=(Derived const &rhs) & { Derived tmp{static_cast(*this)}; tmp.divWrap(rhs); static_cast(*this).swap(tmp); return static_cast(*this); } template Derived &&Div::operator/=(Derived const &rhs) && { static_cast(*this).divWrap(rhs); return std::move(static_cast(*this)); } template Derived operator/(Derived const &lhs, Derived const &rhs) { Derived ret{lhs}; ret.divWrap(rhs); return ret; } template Derived operator/(Derived &&lhs, Derived const &rhs) { lhs.divWrap(rhs); return std::move(lhs); } template class BinopsBase0 : public BinopsBase0, public Div {}; bobcat-5.09.01/build0000755000175000017500000001743714065620551013151 0ustar frankfrank#!/usr/bin/icmake -t. #include "INSTALL.im" #define LIBRARY "bobcat" list g_classes; // list of classes/directories, listed in CLASSES int g_echo = ON; int g_nClasses; // number of classes/subdirectories int g_all = 1; // if 0: only compile the classes not requiring // additional libaries. see icmake/special int g_test; // run in testing mode string g_logPath, g_cwd, // current WD, ends in /. g_file, // used to store the name of a file from a list g_copt, // compiler options g_cxx, // compiler used g_sources, // sources to be used g_version, // The library's version from the file VERSION g_tmpliba, // Static Library compilation target g_tmplibso, // Shared Library compilation target g_tmphdr, // Class header target g_tmpbin, // Binary target g_sharedLibReq; // libraries required by the shared lib #include "icmake/cuteoln" #include "icmake/backtick" #include "icmake/run" #include "icmake/md" #include "icmake/getenv" #include "icmake/clean" #include "icmake/addclasses" #include "icmake/special" #include "icmake/findall" #include "icmake/loginstall" #include "icmake/logrecursive" #include "icmake/logzip" #include "icmake/uninstall" #include "icmake/man" #include "icmake/man1" #include "icmake/gitlab" #include "icmake/library" #include "icmake/libraries" #include "icmake/install" void main(int argc, list argv) { string option; string all; string strip; int keepPch = 0; int idx; for (idx = listlen(argv); idx--; ) { if (argv[idx] == "-q") { g_echo = OFF; argv -= (list)"-q"; } else if (argv[idx] == "-P") { g_gch = 0; argv -= (list)"-P"; } else if (argv[idx] == "-p") { keepPch = 1; argv -= (list)"-p"; } else if (strfind(argv[idx], "LOG:") == 0) { g_logPath = argv[idx]; argv -= (list)g_logPath; g_logPath = substr(g_logPath, 4, strlen(g_logPath)); } } echo(g_echo); g_cwd = chdir("."); g_tmpliba = "tmp/liba"; g_tmplibso = "tmp/libso"; g_tmphdr = "tmp/" LIBRARY "/"; g_tmpbin = "tmp/bin"; g_cxx = setOpt(CXX, "CXX"); g_copt = setOpt(CXXFLAGS, "CXXFLAGS"); option = argv[1]; if (option == "test") g_test = 1; if (option == "clean" || option == "distclean") clean(); if (option == "light" || g_test) { option = "libraries"; g_all = 0; libraries(keepPch, "bobcat", 1, argv[2] == "strip", 0, 0); } if (option == "select") { if (!exists("CLASSES.bak")) exec("cp CLASSES CLASSES.bak"); string subset; idx = 2; if (argv[2] == "strip") ++idx; for (int elem = listlen(argv); elem-- != idx; ) (subset += argv[elem]) += ' '; system("icmake/subset.sh " + subset + "> CLASSES"); libraries(keepPch, "bobcat", 0, idx == 3, 1, 0); } // 'all': all libraries unconditionally // not 'all': ask for the inclusion of additional libraries // g_light: do not consider the additional libraries if (option == "libraries") { all = argv[2]; // maybe 'all' or 'strip' or empty if (all == "all") // all -> specify strip from [3] strip = argv[3]; else // not all: defines 'strip' strip = all; libraries(keepPch, "bobcat", all == "all", strip == "strip", 0, 0); } if (option == "l") { system(P_NOCHECK, "tput clear"); libraries(keepPch, "bobcat", 1, 0, 0, 0); } if (option == "h") { system(P_NOCHECK, "tput clear"); libraries(keepPch, "bobcat", 1, 0, 0, 1); exit(0); } if (option == "mantest") { g_test = 1; option = "man"; } if (option == "man") man(); if (option == "man1") man1(argv[2]); if (option == "gitlab") gitlab(); if (option == "install") install(argv[2], argv[3]); if (option == "uninstall") uninstall(argv[2]); if (option == "dep") { system("dependencies/store"); exit(0); } printf("Usage: build [-h -q -p -P] what\n" "Where\n" " [-q]: run quietly, do not show executed commands\n" " [-p]: used with build light, build libraries and build l\n" " when specified, the precompiled headers are kept after\n" " constructing the libraries\n" " [-P]: do not use precompiled headers\n" "`what' is one of:\n" " clean - clean up remnants of previous compilations\n" " distclean - same as clean\n" " man - build the manual page (requires Yodl)\n" " light [strip] - build the bobcat(-dev) libraries without\n" " the classes requiring the Milter, X11, SSL " "and\n" " Readline libraries\n" " libraries [all] [strip] - build the bobcat(-dev) libraries\n" " (optionally add optional classes,\n" " optionally strip the libraries)\n" " l - same as 'libraries all', but clearing the\n" " screen before starting the compilation\n" " select [strip] class ... - build libbobcat for the class(es)\n" " listed at 'class ...'. The original " "CLASSES\n" " file is saved as CLASSES.bak\n" " install [LOG:path] selection [base] -\n" " to install the software in the locations " "defined \n" " in the INSTALL.im file, optionally below " "base.\n" " LOG:path is optional: if specified `path' " "is the\n" " logfile on which the installation log is " "written.\n" " selection can be\n" " x, to install all components,\n" " or a combination of:\n" " d (documentation),\n" " h (header files),\n" " l (libraries),\n" " m (man-pages)\n" " uninstall logfile - remove files and empty directories listed\n" " in the file 'logfile'\n" "\n" "internal use only:\n" " dep - refresh the class-dependencies overview\n" " gitlab - prepare gitlab's web-pages update\n" " h - only create the headers in .../tmp/bobcat\n" " man1 .yo-file - build one man-page file (in /tmp)\n" " mantest - build a small subset of man-pages for\n" " testing purposes\n" " test - build one class (align) for testing\n" " purposes\n" ); } bobcat-5.09.01/cerrextractor/0000755000175000017500000000000014050437223014773 5ustar frankfrankbobcat-5.09.01/cerrextractor/cerrextractor.ih0000644000175000017500000000015414050437223020204 0ustar frankfrank#include "cerrextractor" #include #include using namespace std; using namespace FBB; bobcat-5.09.01/cerrextractor/cerrextractor2.cc0000644000175000017500000000022414050437223020251 0ustar frankfrank#include "cerrextractor.ih" CerrExtractor::CerrExtractor(StdMode mode, size_t bufSize) : IUO::ExtractorBase(bufSize), d_modeFun(close) {} bobcat-5.09.01/cerrextractor/cerrextractor1.cc0000644000175000017500000000021014050437223020243 0ustar frankfrank#include "cerrextractor.ih" CerrExtractor::CerrExtractor(size_t bufSize) : IUO::ExtractorBase(bufSize), d_modeFun(noClose) {} bobcat-5.09.01/cerrextractor/cerrextractor0000644000175000017500000000067514050437223017615 0ustar frankfrank#ifndef INCLUDED_BOBCAT_CERREXTRACTOR_ #define INCLUDED_BOBCAT_CERREXTRACTOR_ #include namespace FBB { class CerrExtractor: public IUO::ExtractorBase { void (*d_modeFun)(); public: CerrExtractor(size_t bufSize = 100); CerrExtractor(StdMode mode, size_t bufSize = 100); private: void childRedirections() override; static void close(); }; } // namespace FBB #endif bobcat-5.09.01/cerrextractor/close.cc0000644000175000017500000000043414050437223016410 0ustar frankfrank#include "cerrextractor.ih" void CerrExtractor::close() // static { ::close(STDIN_FILENO); // close and reopen std file descriptors ::close(STDOUT_FILENO); ::open("/dev/null", O_RDONLY); // reopen stdin ::open("/dev/null", O_WRONLY); // reopen cout } bobcat-5.09.01/cerrextractor/childredirections.cc0000644000175000017500000000027414050437223021003 0ustar frankfrank#include "cerrextractor.ih" void CerrExtractor::childRedirections() { (*d_modeFun)(); // optionally close STDIN and STDOUT childOutPipe().writtenBy(STDERR_FILENO); } bobcat-5.09.01/cerrextractor/driver/0000755000175000017500000000000014050437223016266 5ustar frankfrankbobcat-5.09.01/cerrextractor/driver/build0000755000175000017500000000017414050437223017315 0ustar frankfrank#!/bin/bash g++ -Wall -odriver driver.cc -L../../extractorbase/tmp -lextractorbase \ -L../tmp -Lcoutextractor -lbobcat bobcat-5.09.01/cerrextractor/driver/driver.cc0000644000175000017500000000065714050437223020100 0ustar frankfrank#include #include using namespace std; using namespace FBB; int main() { CerrExtractor extractor; extractor.execute("/bin/cat driver.cc"); cout << extractor.rdbuf(); cerr << "Returning: " << extractor.ret() << "\n" "again:\n"; extractor.execute("/bin/cat driver.cc"); cout << extractor.rdbuf(); cerr << "Returning: " << extractor.ret() << '\n'; } bobcat-5.09.01/cgi/0000755000175000017500000000000014050437223012646 5ustar frankfrankbobcat-5.09.01/cgi/chartoken.cc0000644000175000017500000000024614050437223015135 0ustar frankfrank#include "cgi.ih" size_t CGIFSA::charToken() { char c; if (!d_in.get(c)) throw END; d_buffer = c; return static_cast(c); } bobcat-5.09.01/cgi/post.cc0000644000175000017500000000042614050437223014144 0ustar frankfrank#include "cgi.ih" void CGI::post() { if (!d_boundary.length()) // POSTed forms not using multipart/form-data { get(); // offer GET-like data via cin return; } multipartFormData(); // process the multipart/form-data } bobcat-5.09.01/cgi/setfsa.cc0000644000175000017500000000050414050437223014441 0ustar frankfrank#include "cgi.ih" void CGIFSA::setFsa(Record const &record) { Transition transition = {record.token, record.action, record.next}; s_fsa[record.current].push_back(transition); if (record.token == DEFAULT) // default contains ptr to tokenizer s_tokenizer[record.current] = record.tokenizer; } bobcat-5.09.01/cgi/get.cc0000644000175000017500000000027014050437223013733 0ustar frankfrank#include "cgi.ih" void CGI::get() { vector words; String::split(&words, d_query, "&"); // split the q-string for (auto &word: words) addParam(word); } bobcat-5.09.01/cgi/escape.cc0000644000175000017500000000037614050437223014423 0ustar frankfrank#include "cgi.ih" string CGI::escape(string const &text) { string ret = text; for (size_t idx = ret.length(); idx--; ) { if (d_escape[static_cast(ret[idx])]) ret.insert(idx, "\\"); } return ret; } bobcat-5.09.01/cgi/method.f0000644000175000017500000000010014050437223014264 0ustar frankfrankinline CGI::Method CGI::method() const { return d_method; } bobcat-5.09.01/cgi/opinsert2.cc0000644000175000017500000000064514050437223015107 0ustar frankfrank#include "cgi.ih" CGI &CGI::operator<<(std::pair range) { if (!d_activated) { for(auto &target: ranger( d_escape + static_cast(range.first), d_escape + static_cast(range.second) + 1 ) ) target = d_escapeValue; d_escape['\\'] = true; } return *this; } bobcat-5.09.01/cgi/acceptall.cc0000644000175000017500000000025014050437223015102 0ustar frankfrank#include "cgi.ih" void CGIFSA::acceptAll() { while (d_stack.size()) { char top = d_stack.top(); setEscape(top); d_stack.pop(); } } bobcat-5.09.01/cgi/setquery.cc0000644000175000017500000000116414050437223015040 0ustar frankfrank#include "cgi.ih" void CGI::setQuery() { switch (d_method) { case GET: if (char const *cp = (*this)["QUERY_STRING"]) d_query = cp; break; case POST: if (d_boundary.length() == 0) { unique_ptr cp(new char[d_contentLength]); if (!cin.read(cp.get(), d_contentLength)) d_status = "invalid CONTENT_LENGTH in POSTed form"; else d_query.assign(cp.get(), d_contentLength); } break; default: break; } } bobcat-5.09.01/cgi/accept.cc0000644000175000017500000000035214050437223014414 0ustar frankfrank#include "cgi.ih" void CGIFSA::accept() { for (auto iter = d_buffer.rbegin(), end = d_buffer.rend(); iter != end; ++iter) d_stack.push(*iter); acceptAll(); d_stack.push(*d_buffer.rbegin()); } bobcat-5.09.01/cgi/cgifsa.cc0000644000175000017500000000044714050437223014416 0ustar frankfrank#include "cgi.ih" CGIFSA::CGIFSA(bool *escape, std::istream &in, bool setEscape) : d_escape(escape), d_setEscape(setEscape), d_state(START), d_in(in) { if (!s_installed) { std::for_each(s_fsaRawData, s_fsaRawDataEnd, setFsa); s_installed = true; } } bobcat-5.09.01/cgi/opindex.f0000644000175000017500000000014514050437223014463 0ustar frankfrankinline char const *CGI::operator[](std::string const &key) const { return getenv(key.c_str()); } bobcat-5.09.01/cgi/last.f0000644000175000017500000000011414050437223013754 0ustar frankfrankinline std::string Cidr::last() const { return binary2dotted(d_last); } bobcat-5.09.01/cgi/run.cc0000644000175000017500000000104514050437223013761 0ustar frankfrank#include "cgi.ih" // Characters are retrieved from d_in by the tokenizer. They are stored on // the stack by the tokenizers, and retrieved from the stack by the // action functions. All characters are interpreted as unsigned chars, and // pushed as size_t values void CGIFSA::run() try { d_state = START; while (true) // throws exception after processing all chars { (this->*s_fsa[d_state][tokenIdx()].action)(); d_state = s_fsa[d_state][d_tokenIdx].next; } } catch(Token end) { acceptAll(); } bobcat-5.09.01/cgi/unpercent.cc0000644000175000017500000000160014050437223015155 0ustar frankfrank#include "cgi.ih" std::string CGI::unPercent(std::string const &text) { string ret(text); string::size_type pos = 0; string sub; char replacement[2] = {0, 0}; while (true) { pos = ret.find_first_of("+%", pos); if (pos == string::npos) // none found break; if (ret[pos] == '+') // convert '+' ret[pos] = ' '; // // viable % found else if ((sub = ret.substr(pos + 1, 2)).length() == 2) { istringstream convert(sub); size_t value; if (convert >> hex >> value) // successfully converted { replacement[0] = value; ret.replace(pos, 3, replacement); } } ++pos; // next char } return ret; } bobcat-5.09.01/cgi/maxuploadsize.f0000644000175000017500000000012514050437223015700 0ustar frankfrankinline unsigned long long CGI::maxUploadSize() const { return d_maxUploadSize; } bobcat-5.09.01/cgi/query.f0000644000175000017500000000010514050437223014156 0ustar frankfrankinline std::string const &CGI::query() const { return d_query; } bobcat-5.09.01/cgi/opinsert3.cc0000644000175000017500000000031114050437223015076 0ustar frankfrank#include "cgi.ih" CGI &CGI::operator<<(int ch) { if (!d_activated) { d_escape[static_cast(ch)] = d_escapeValue; d_escape['\\'] = true; } return *this; } bobcat-5.09.01/cgi/opinsert1.cc0000644000175000017500000000040214050437223015075 0ustar frankfrank#include "cgi.ih" CGI &CGI::operator<<(string const &accept) { if (!d_activated) { istringstream in(accept); CGIFSA fsa(d_escape, in, d_escapeValue); fsa.run(); d_escape['\\'] = true; } return *this; } bobcat-5.09.01/cgi/report.cc0000644000175000017500000000032614050437223014471 0ustar frankfrank#include "cgi.ih" void CGI::report() const { if (d_status.length() == 0) return; cout << "FBB::CGI: " << d_status << endl; throw Exception{1} << "FBB::CGI: Error(s) in uploaded form data"; } bobcat-5.09.01/cgi/first.f0000644000175000017500000000012414050437223014141 0ustar frankfrankinline std::string Cidr::first() const { return binary2dotted(d_iter->first); } bobcat-5.09.01/cgi/multipartformdata.cc0000644000175000017500000000164614050437223016723 0ustar frankfrank#include "cgi.ih" void CGI::multipartFormData() try { string line; next(&line); // enter while with the next // available line while (true) { switch (typeOf(line)) // handle the line-type { case END_BOUNDARY: return; default: // no boundary, try the next next(&line); continue; case BOUNDARY: next(&line); // line beyound the boundary if (isFile(line)) upload(&line); // upload a file else readPart(&line); // handle a plain part break; // upload() and readPart() return the next line to process } } } catch (...) {} bobcat-5.09.01/cgi/dos2unix.cc0000644000175000017500000000041614050437223014731 0ustar frankfrank#include "cgi.ih" string CGI::dos2unix(string const &text) { string ret(text); string::size_type pos = 0; while (true) { pos = ret.find("\r\n", pos); if (pos == string::npos) return ret; ret.erase(pos, 1); } } bobcat-5.09.01/cgi/wordtoken.cc0000644000175000017500000000155114050437223015173 0ustar frankfrank#include "cgi.ih" size_t CGIFSA::wordToken() { d_buffer.clear(); while (islower(d_in.peek())) // read all lowercase chars d_buffer += d_in.get(); if (!d_buffer.size()) // if none read, return the next char return charToken(); // look for a character class name PairCPPFunP const *ret = find_if( s_charClass, s_charClassEnd, [&](PairCPPFunP const &cClass) { return d_buffer == cClass.first; } ); if (ret == s_charClassEnd) // no character class found return static_cast(*d_buffer.rbegin()); d_setIdx = ret - s_charClass; // charclass found return SET; // return `set found' } bobcat-5.09.01/cgi/cgi0000644000175000017500000000775314050437223013347 0ustar frankfrank#ifndef INCLUDED_BOBCAT_CGI_ #define INCLUDED_BOBCAT_CGI_ #include #include #include #include #include #include #include namespace FBB { class CGI { friend std::ostream &operator<<(std::ostream &out, CGI const &cgi); public: typedef std::unordered_map > MapStringVector; enum Method { UNDETERMINED, GET, POST }; enum Create { DONT_CREATE_PATH, CREATE_PATH }; private: enum Boundary // see multipartFormData() { NO_BOUNDARY, BOUNDARY, END_BOUNDARY }; Method d_method; bool d_escapeValue; bool d_escape[256]; // initially all d_defaultEscape MapStringVector d_param; std::string d_query; std::string d_boundary; // boundary of the multipart/form-data forms // empty if POST produces GET-like info on // stdin. unsigned long long d_contentLength; std::string d_filePath; // uploaded files are named std::string d_filePrefix; // d_filePath / d_filePrefix d_fileNr++ size_t d_fileNr; Pattern d_contentDisposition; Pattern d_contentFile; std::string d_status; bool d_activated; unsigned long long d_maxUploadSize; static std::vector s_empty; enum: size_t { s_uploadBlock = 8000, // upload.cc s_nTries = 100 }; public: explicit CGI(bool defaultEscape = true, char const *header = "Content-type: text/html", std::ostream &out = std::cout); CGI(CGI &&tmp); void swap(CGI &other); CGI &operator=(CGI const &rhs) = default; CGI &operator=(CGI &&tmp); CGI &operator<<(std::string const &set); CGI &operator<<(std::pair range); CGI &operator<<(int ch); void setFileDestination(std::string const &path, std::string const &prefix = "", Create create = CREATE_PATH); void setMaxUploadSize(size_t maxUploadSize, int unit = 'M'); void report() const; // also called by param() // accessors: char const *operator[](std::string const &key) const; // opindex.f unsigned long long maxUploadSize() const; // .f Method method() const; // .f std::string const &query() const; // .f // empty with multipart/form-data std::vector const ¶m(std::string const &variable); MapStringVector::const_iterator begin(); // .f MapStringVector::const_iterator end(); // .f std::string param1(std::string const &variable); // static members: // unpercent also does the '+' to ' ' // conversion static std::string unPercent(std::string const &text); static std::string dos2unix(std::string const &text); private: void setQuery(); void get(); void post(); void addParam(std::string const ¶m); void init(bool &target); std::string escape(std::string const &text); void next(std::string *line); void multipartFormData(); Boundary typeOf(std::string const &line) const; bool isFile(std::string const &line); void readPart(std::string *line); void setMethod(); void setParam(); void upload(std::string *line); }; #include "opindex.f" #include "query.f" #include "method.f" #include "begin.f" #include "end.f" #include "maxuploadsize.f" } // namespace #endif bobcat-5.09.01/cgi/cgi.ih0000644000175000017500000000444214050437223013736 0ustar frankfrank#include "cgi" #include #include #include #include #include #include #include #include #include #include //#include "../a2x/a2x" //#include "../x2a/x2a" #include "../exception/exception" #include "../string/string" #include "../stat/stat" #include "../fswap/fswap" #include "../ranger/ranger" using namespace std; using namespace FBB; namespace FBB { typedef pair PairCPPFunP; class CGIFSA { enum Token { DEFAULT = 256, SET, END, }; enum State // change data.cc s_stateName when this changes { START, CHECKSET, DEFINESET, OPENBRACKET, LEFTCOLON, SETNAME, RIGHTCOLON, N_STATES_, STOP = N_STATES_, }; struct Record { State current; size_t token; void (CGIFSA::*action)(); State next; size_t (CGIFSA::*tokenizer)(); }; stack d_stack; bool *d_escape; bool d_setEscape; State d_state; size_t d_tokenIdx; string d_buffer; size_t d_setIdx; istream &d_in; struct Transition { size_t token; void (CGIFSA::*action)(); State next; }; static vector s_fsa[]; static size_t (CGIFSA::*s_tokenizer[])(); static Record const s_fsaRawData[]; static Record const *const s_fsaRawDataEnd; static PairCPPFunP const s_charClass[]; static PairCPPFunP const *const s_charClassEnd; static bool s_installed; static char const *s_stateName[]; static string s_cgi; public: CGIFSA(bool *escape, istream &in = cin, bool setEscape = false); void run(); private: void push(); void accept(); void charRange(); void charClass(); void acceptAll(); // all elements on the stack size_t tokenIdx(); void setEscape(size_t idx); // .i size_t charToken(); size_t wordToken(); static void setFsa(Record const &record); static int iscgi(int ch); // .i }; #include "iscgi.f" #include "setescape.f" } // namespace bobcat-5.09.01/cgi/next.cc0000644000175000017500000000024514050437223014134 0ustar frankfrank#include "cgi.ih" void CGI::next(string *line) { if (!getline(cin, *line)) { d_status = "Invalid multipart/form-data"; throw false; } } bobcat-5.09.01/cgi/charclass.cc0000644000175000017500000000060014050437223015114 0ustar frankfrank#include "cgi.ih" void CGIFSA::charClass() // saw: [ : charclass : ] { while (true) { char c = d_stack.top(); d_stack.pop(); if (c == '[') break; } int (*predicate)(int) = s_charClass[d_setIdx].second; for (int idx = 0; idx < 255; ++idx) { if ((*predicate)(idx)) setEscape(idx); } } bobcat-5.09.01/cgi/begin.f0000644000175000017500000000015114050437223014076 0ustar frankfrankinline CGI::MapStringVector::const_iterator CGI::begin() { setParam(); return d_param.begin(); } bobcat-5.09.01/cgi/addparam.cc0000644000175000017500000000036514050437223014732 0ustar frankfrank#include "cgi.ih" void CGI::addParam(string const ¶m) try { static Pattern pattern("([^=]*)=(.*)"); pattern.match(param); d_param[pattern[1]].push_back(escape(unPercent(pattern[2]))); } catch (std::exception const &exc) {} bobcat-5.09.01/cgi/iscgi.f0000644000175000017500000000012014050437223014104 0ustar frankfrankinline int CGIFSA::iscgi(int ch) { return s_cgi.find(ch) != string::npos; } bobcat-5.09.01/cgi/mask.f0000644000175000017500000000013114050437223013743 0ustar frankfrankinline std::string Cidr::mask() const { return to_string(d_iter->second); // X2a } bobcat-5.09.01/cgi/end.f0000644000175000017500000000014514050437223013563 0ustar frankfrankinline CGI::MapStringVector::const_iterator CGI::end() { setParam(); return d_param.end(); } bobcat-5.09.01/cgi/charrange.cc0000644000175000017500000000067714050437223015121 0ustar frankfrank#include "cgi.ih" void CGIFSA::charRange() { size_t end = static_cast(d_buffer[0]); d_stack.pop(); // hyphen size_t begin = static_cast(d_stack.top()); d_stack.pop(); // first char if (begin <= end) { for(++end; begin != end; ++begin) setEscape(begin); } acceptAll(); // unescape any remaining chars } bobcat-5.09.01/cgi/readpart.cc0000644000175000017500000000076414050437223014766 0ustar frankfrank#include "cgi.ih" void CGI::readPart(string *line) { next(line); // empty line following Content-Disposition while (true) { next(line); // either a boundary or a field value if (typeOf(*line) != NO_BOUNDARY) // it's a boundary break; // (i.e., NOT no boundary) // otherwise it's a field value d_param[d_contentDisposition[1]].push_back(escape(*line)); } } bobcat-5.09.01/cgi/opinsert0.cc0000644000175000017500000000055614050437223015106 0ustar frankfrank#include "cgi.ih" namespace FBB { std::ostream &operator<<(std::ostream &out, CGI const &cgi) { for (int idx = 0; idx < 256; ++idx) { if (cgi.d_escape[idx]) { if (isprint(idx)) out << "'" << static_cast(idx) << "'\n"; else out << idx << endl; } } return out; } } bobcat-5.09.01/cgi/cgidata.cc0000644000175000017500000000655514050437223014564 0ustar frankfrank#include "cgi.ih" vector CGI::s_empty; bool CGIFSA::s_installed(false); vector CGIFSA::s_fsa[N_STATES_]; size_t (CGIFSA::*CGIFSA::s_tokenizer[N_STATES_])(); // a buffer is filled with the read character(s). push will push them // L to R onto the charstack // accept will pop all characters and accept them, except for the last // char, that is pushed CGIFSA::Record const CGIFSA::s_fsaRawData[] = { // -------------------------------------------------------------------- // cur. state token action next state tokenizer // -------------------------------------------------------------------- {START, '[', &CGIFSA::push, OPENBRACKET, 0}, {START, DEFAULT, &CGIFSA::push, CHECKSET, &CGIFSA::charToken}, {CHECKSET, '-', &CGIFSA::push, DEFINESET, 0}, {CHECKSET, '[', &CGIFSA::accept, OPENBRACKET, 0}, {CHECKSET, DEFAULT, &CGIFSA::accept, CHECKSET, &CGIFSA::charToken}, {DEFINESET, DEFAULT, &CGIFSA::charRange, START, &CGIFSA::charToken}, {OPENBRACKET, '-', &CGIFSA::push, DEFINESET, 0}, {OPENBRACKET, '[', &CGIFSA::accept, OPENBRACKET, 0}, {OPENBRACKET, ':', &CGIFSA::push, LEFTCOLON, 0}, {OPENBRACKET, DEFAULT, &CGIFSA::accept, CHECKSET, &CGIFSA::charToken}, {LEFTCOLON, SET, &CGIFSA::push, SETNAME, 0}, {LEFTCOLON, '-', &CGIFSA::push, DEFINESET, 0}, {LEFTCOLON, DEFAULT, &CGIFSA::accept, CHECKSET, &CGIFSA::wordToken}, {SETNAME, ':', &CGIFSA::push, RIGHTCOLON, 0}, {SETNAME, DEFAULT, &CGIFSA::accept, CHECKSET, &CGIFSA::charToken}, {RIGHTCOLON, ']', &CGIFSA::charClass, START, 0}, {RIGHTCOLON, '-', &CGIFSA::push, DEFINESET, 0}, {RIGHTCOLON, DEFAULT, &CGIFSA::accept, CHECKSET, &CGIFSA::charToken}, // -------------------------------------------------------------------- }; CGIFSA::Record const *const CGIFSA::s_fsaRawDataEnd = CGIFSA::s_fsaRawData + sizeof(CGIFSA::s_fsaRawData) / sizeof(CGIFSA::Record); PairCPPFunP const CGIFSA::s_charClass[] = { PairCPPFunP("alnum", &isalpha), PairCPPFunP("alpha", &isalpha), PairCPPFunP("cntrl", &iscntrl), PairCPPFunP("digit", &isdigit), PairCPPFunP("graph", &isgraph), PairCPPFunP("lower", &islower), PairCPPFunP("print", &isprint), PairCPPFunP("punct", &ispunct), PairCPPFunP("space", &isspace), PairCPPFunP("upper", &isupper), PairCPPFunP("xdigit", &isxdigit), PairCPPFunP("cgi", &iscgi), // extension to std char classes }; string CGIFSA::s_cgi("\"'`;\\"); PairCPPFunP const *const CGIFSA::s_charClassEnd = CGIFSA::s_charClass + sizeof(CGIFSA::s_charClass) / sizeof(PairCPPFunP); char const *CGIFSA::s_stateName[] = // change when enum State changes { "START", "CHECKSET", "DEFINESET", "OPENBRACKET", "LEFTCOLON", "SETNAME", "RIGHTCOLON", "STOP", }; bobcat-5.09.01/cgi/typeof.cc0000644000175000017500000000040614050437223014463 0ustar frankfrank#include "cgi.ih" CGI::Boundary CGI::typeOf(string const &line) const { if (line.find(d_boundary) != 0) return NO_BOUNDARY; if (line.substr(d_boundary.length(), 2) == "--") // end of data return END_BOUNDARY; return BOUNDARY; } bobcat-5.09.01/cgi/operatorassign.cc0000644000175000017500000000012714050437223016215 0ustar frankfrank#include "cgi.ih" CGI &CGI::operator=(CGI &&tmp) { swap(tmp); return *this; } bobcat-5.09.01/cgi/isfile.cc0000644000175000017500000000064714050437223014437 0ustar frankfrank#include "cgi.ih" bool CGI::isFile(string const &line) try { d_contentDisposition.match(line); // match the content disposition try { d_contentFile.match(d_contentDisposition.beyond()); return true; } catch(...) { return false; // no file upload } } catch (...) { d_status = "Content-Disposition not recognized in: " + line; throw false; } bobcat-5.09.01/cgi/setmethod.cc0000644000175000017500000000221114050437223015145 0ustar frankfrank#include "cgi.ih" void CGI::setMethod() { char const *cp = (*this)["REQUEST_METHOD"]; if (cp) { string meth(cp); if (meth == "GET") { d_method = GET; return; } if (meth == "POST") { if ((cp = (*this)["CONTENT_LENGTH"])) d_contentLength = stoull(cp); if ((cp = (*this)["CONTENT_TYPE"]) != 0) { string type(cp); string::size_type pos; if ( type.find("multipart/form-data") == 0 && (pos = type.find("boundary=")) != string::npos ) { // don't count trailing \0 d_boundary = type.substr(pos + sizeof("boundary=") - 1); d_boundary.insert(0, "--"); // actual boundary has two // additional - chars } } d_method = POST; return; } } d_status = "GET/POST REQUEST_METHOD not found"; } bobcat-5.09.01/cgi/swap.cc0000644000175000017500000000041214050437223014124 0ustar frankfrank#include "cgi.ih" void CGI::swap(CGI &rhs) { fswap(*this, rhs, d_param, d_query, d_boundary, d_filePath, d_filePrefix, d_contentDisposition, d_contentFile, d_status ); } bobcat-5.09.01/cgi/cgi1.cc0000644000175000017500000000140414050437223013777 0ustar frankfrank#include "cgi.ih" CGI::CGI(bool defaultEscape, char const *header, std::ostream &out) : d_method(UNDETERMINED), d_escapeValue(defaultEscape), d_contentLength(0), d_filePath("/tmp/"), d_fileNr(1), d_contentDisposition("^Content-Disposition: form-data; name=\"([^\"]+)\""), d_contentFile("; filename=\"([^\"]+)\""), d_activated(false), d_maxUploadSize(100ULL * 1024 * 1024) { for (auto &target: ranger(d_escape, sizeof(d_escape) / sizeof(bool))) target = d_escapeValue; d_escapeValue = !d_escapeValue; // all changes will now change the // default setMethod(); if (d_status.length() == 0) setQuery(); if (header) out << header << "\r\n\r\n"; } bobcat-5.09.01/cgi/param.cc0000644000175000017500000000036414050437223014260 0ustar frankfrank#include "cgi.ih" std::vector const &CGI::param(std::string const &variable) { setParam(); MapStringVector::const_iterator iter = d_param.find(variable); return iter == d_param.end() ? s_empty : iter->second; } bobcat-5.09.01/cgi/setescape.f0000644000175000017500000000011714050437223014770 0ustar frankfrankinline void CGIFSA::setEscape(size_t idx) { d_escape[idx] = d_setEscape; } bobcat-5.09.01/cgi/setmaxuploadsize.cc0000644000175000017500000000101614050437223016554 0ustar frankfrank#include "cgi.ih" void CGI::setMaxUploadSize(size_t maxUploadSize, int unit) { unsigned long long newSize = maxUploadSize; switch (unit) { case 'G': case 'g': newSize <<= 10; [[fallthrough]]; case 'M': case 'm': newSize <<= 10; [[fallthrough]]; case 'K': case 'k': newSize <<= 10; [[fallthrough]]; default: d_maxUploadSize = newSize; break; } } bobcat-5.09.01/cgi/cgi2.cc0000644000175000017500000000121314050437223013776 0ustar frankfrank#include "cgi.ih" CGI::CGI(CGI &&tmp) : d_method(tmp.d_method), d_escapeValue(tmp.d_escapeValue), d_param( move(tmp.d_param) ), d_query( move(tmp.d_query) ), d_boundary( move(tmp.d_boundary) ), d_contentLength(tmp.d_contentLength), d_filePath( move(tmp.d_filePath) ), d_filePrefix( move(tmp.d_filePrefix) ), d_fileNr(tmp.d_fileNr), d_contentDisposition( move(tmp.d_contentDisposition) ), d_contentFile( move(tmp.d_contentFile) ), d_status( move(tmp.d_status) ), d_activated(tmp.d_activated), d_maxUploadSize(tmp.d_maxUploadSize) { memcpy(d_escape, tmp.d_escape, sizeof(d_escape)); } bobcat-5.09.01/cgi/param1.cc0000644000175000017500000000030314050437223014332 0ustar frankfrank#include "cgi.ih" std::string CGI::param1(std::string const &variable) { auto &vect = param(variable); string ret; if (not vect.empty()) ret = vect[0]; return ret; } bobcat-5.09.01/cgi/address.f0000644000175000017500000000011214050437223014434 0ustar frankfrankinline std::string const &Cidr::address() const { return d_matched; } bobcat-5.09.01/cgi/setparam.cc0000644000175000017500000000050114050437223014765 0ustar frankfrank#include "cgi.ih" void CGI::setParam() { if (d_activated || d_status.length() != 0) return; switch (d_method) { case GET: get(); break; case POST: post(); break; default: break; } report(); d_activated = true; } bobcat-5.09.01/cgi/upload.cc0000644000175000017500000000726714050437223014455 0ustar frankfrank#include "cgi.ih" namespace { char const content_Type[] = "Content-Type: "; } void CGI::upload(string *line) { next(line); // Content-Type if (line->find(content_Type) != 0) { d_status = "Content-Type not found for file-field " + d_contentDisposition[1]; throw false; } string contentType = line->substr(sizeof(content_Type) - 1); string destName; // try s_nTries times to find an available // file for (size_t end = d_fileNr + s_nTries; d_fileNr < end; ++d_fileNr) { destName = d_filePath + d_filePrefix + to_string(d_fileNr); // X2a(d_fileNr).str(); if (!Stat(destName)) // path does not exist break; } ofstream dest(destName.c_str()); if (!dest) { d_status = "Can't open a file to write an uploaded file"; throw false; } string previous; unique_ptr buffer(new char[s_uploadBlock]); next(line); // skip the blank line following the // content-type unsigned long long uploadSize = 0; while (true) { cin.getline(buffer.get(), s_uploadBlock); size_t nRead = cin.gcount(); // may include the \n, but the \n is // then stored as 0, since it is // removed from the input and an // \0 is appended to the read line if (!nRead) // none read: shouldn't happen { d_status = "multipart/form-data: no end-boundary found"; throw false; } if (cin.fail()) // on fail() no \n was encountered cin.clear(); else // no fail: change the \0 into \n (buffer.get())[nRead - 1] = '\n'; // the line that was read contains \r\n characters, so a boundary // can only be encountered if nRead exceeds the boundary length // if so, and the buffer's boundary length characters are equal to the // boundary then a boundary was found. // If the boundary is found, then the previously captured line ends in // a \r\n, which does not belong to the uploaded file but is added by // the browser's form-handling software which is therefore not // included in the uploaded file (hence `- 2', below). Then, the // boundary is copied to the line parameter and the function returns. if ( nRead > d_boundary.length() && d_boundary.compare(0, d_boundary.length(), buffer.get(), d_boundary.length()) == 0 ) { uploadSize += previous.length() - 2; if (uploadSize <= d_maxUploadSize) dest.write(previous.c_str(), previous.length() - 2); line->assign(buffer.get(), nRead); break; } if (uploadSize <= d_maxUploadSize) { uploadSize += previous.length(); dest.write(previous.c_str(), previous.length()); previous.assign(buffer.get(), nRead); } } // store the info about this file into d_param vector ¶m = d_param[d_contentDisposition[1]]; param.push_back(escape(destName)); param.push_back(escape(d_contentFile[1])); param.push_back(escape(contentType)); param.push_back(uploadSize <= d_maxUploadSize ? "OK" : "truncated"); } bobcat-5.09.01/cgi/setfiledestination.cc0000644000175000017500000000176414050437223017062 0ustar frankfrank#include "cgi.ih" void CGI::setFileDestination(std::string const &path, std::string const &prefix, Create create) { d_filePath = path; if (*d_filePath.rbegin() != '/') d_filePath += "/"; Stat destPath(d_filePath); if (!destPath.isType(Stat::DIRECTORY) && create == CREATE_PATH) { string::size_type pos = 0; while (true) { pos = path.find('/', pos); if ( pos == string::npos || mkdir(path.substr(0, pos).c_str(), 0750) ) break; ++pos; // skip the directory separator } } if (!destPath.isType(Stat::DIRECTORY)) throw Exception{1} << "FBB::CGI: can't create file destination " "directory " << destPath.path(); d_filePrefix = prefix; } bobcat-5.09.01/cgi/driver/0000755000175000017500000000000014050437223014141 5ustar frankfrankbobcat-5.09.01/cgi/driver/build0000755000175000017500000000203414050437223015165 0ustar frankfrank#!/bin/bash rm -f driver case $1 in (tmp) for x in *.cc do NAME=`echo $x | sed 's/\..*//'` if [ ! -s ${NAME}.o -o ${NAME}.cc -nt ${NAME}.o ] then echo "g++ -c $x" g++ `cat ../../c++std` -I../../tmp -o ${NAME}.o -c $x || exit 1 fi done g++ `cat ../../c++std` -o driver *.o -L../../tmp/lib -lbobcat ;; (lib) for x in *.cc do NAME=`echo $x | sed 's/\..*//'` if [ ! -s ${NAME}.o -o ${NAME}.cc -nt ${NAME}.o ] then echo "g++ -c $x" g++ `cat ../../c++std` -o ${NAME}.o -c $x || exit 1 fi done g++ -o driver *.o -lbobcat ;; (*) echo " Usage: build tmp - build the driver using the shared library created in ../../tmp/lib build lib - build the driver using the shared bobcat library installed in the standard location for shared libs " exit 1 ;; esac bobcat-5.09.01/cgi/driver/driver.cc0000644000175000017500000000350314050437223015744 0ustar frankfrank#include "main.ih" void showParam(CGI::MapStringVector::value_type const &mapValue) { cout << "Param: " << mapValue.first << '\n'; for (auto &str: mapValue.second) cout << " " << CGI::dos2unix(str) << "\n" " "; cout << '\n'; } int main(int argc, char **argv) try { Arg &arg = Arg::initialize("evhm:", argc, argv); // usage and version are in the source archive in .../cgi/driver // arg.versionHelp(usage, version, 2); ifstream in(arg[0]); string line; while (getline(in, line)) { size_t pos = line.find('='); if (pos == string::npos) continue; // set environment vars simulating // a GET form if (setenv(line.substr(0, pos).c_str(), line.substr(pos + 1).c_str(), true) == 0) { if (arg.option('e')) cout << line.substr(0, pos).c_str() << '=' << line.substr(pos + 1).c_str() << '\n'; } else cout << "FAILED: setenv " << line << '\n'; } CGI cgi(false); // chars are not escaped cgi << arg[1]; if (arg.option(&line, 'm')) cgi.setMaxUploadSize(stoul(line), *line.rbegin()); cout << "Max upload size (b): " << cgi.maxUploadSize() << '\n'; CGI::Method method = cgi.method(); cout << "To escape:\n" << cgi << "\n" "Method: " << (method == CGI::GET ? "GET" : "POST") << '\n'; cout << "Query string: " << cgi.query() << '\n'; cout << "Submit string: `" << cgi.param1("submit") << "'\n"; for (auto &mapElement: cgi) showParam(mapElement); cout << "END OF PROGRAM\n"; } catch (exception const &err) { cout << err.what() << '\n'; return 1; } catch (...) { return 1; } bobcat-5.09.01/cgi/driver/usage.cc0000644000175000017500000000222514050437223015555 0ustar frankfrank// usage.cc #include "main.ih" namespace { Pattern pattern("([^=]*)=(.*)"); } void usage(std::string const &progname) { cout << "\n" << progname << " by " << Icmbuild::author << "\n" << progname << " V" << Icmbuild::version << " " << Icmbuild::year << "\n" "\n" "Usage: " << progname << " [options] arg to-escape < arg.cin\n" "Where:\n" " [options] - optional arguments (short options between parentheses):\n" " -e - show the environment variables that were set\n" " -m[bkmg] - max uploadsize to use\n" " -h - provide this help\n" " -v - show version information and terminate\n" " arg - file defining envvars\n" " (see, e.g., `get' and `post1')\n" " to-escape - RE defining characters to escape.\n" " (e.g., '[:cgi:]')\n" " < arg.cin - file to read, simulating form-output\n" " (e.g., post1.cin)\n" " For the 'get' method the input redirection is not used/required\n" "\n"; } bobcat-5.09.01/cgi/driver/post10000644000175000017500000000036014050437223015131 0ustar frankfrankINFO=This is an abbreviated set of environment variables CONTENT_TYPE=application/x-www-form-urlencoded CONTENT_LENGTH=182 SERVER_ADMIN=f.b.brokken@rug.nl GATEWAY_INTERFACE=CGI/1.1 SERVER_PROTOCOL=HTTP/1.1 REQUEST_METHOD=POST QUERY_STRING= bobcat-5.09.01/cgi/driver/get0000644000175000017500000000032114050437223014637 0ustar frankfrankINFO=This is an abbreviated set of environment variables SERVER_ADMIN=f.b.brokken@rug.nl GATEWAY_INTERFACE=CGI/1.1 SERVER_PROTOCOL=HTTP/1.1 REQUEST_METHOD=GET QUERY_STRING=hidden=hidval&submit=Submit+%20Query bobcat-5.09.01/cgi/driver/post20000644000175000017500000000044514050437223015136 0ustar frankfrankINFO=This is an abbreviated set of environment variables CONTENT_TYPE=multipart/form-data; boundary=---------------------------8463851424774285061082711556 CONTENT_LENGTH=1223 SERVER_ADMIN=f.b.brokken@rug.nl GATEWAY_INTERFACE=CGI/1.1 SERVER_PROTOCOL=HTTP/1.1 REQUEST_METHOD=POST QUERY_STRING= bobcat-5.09.01/cgi/driver/post2.cin0000644000175000017500000000231014050437223015677 0ustar frankfrank-----------------------------8463851424774285061082711556 Content-Disposition: form-data; name="hidden" hidval -----------------------------8463851424774285061082711556 Content-Disposition: form-data; name="text" some text -----------------------------8463851424774285061082711556 Content-Disposition: form-data; name="password" -----------------------------8463851424774285061082711556 Content-Disposition: form-data; name="c1" one -----------------------------8463851424774285061082711556 Content-Disposition: form-data; name="c1" three -----------------------------8463851424774285061082711556 Content-Disposition: form-data; name="radio" 1 -----------------------------8463851424774285061082711556 Content-Disposition: form-data; name="file"; filename="demo.pim" Content-Type: application/octet-stream #demo.im string a = "a/*" ; -----------------------------8463851424774285061082711556 Content-Disposition: form-data; name="textarea" Enter your text here And over multitple rows is OK -----------------------------8463851424774285061082711556 Content-Disposition: form-data; name="submit" Submit Query -----------------------------8463851424774285061082711556-- bobcat-5.09.01/cgi/driver/post1.cin0000644000175000017500000000026714050437223015707 0ustar frankfrankhidden=hidval&text=text+input&password=&c1=one&radio=1§ions=FAQ+Archives§ions=Tools&textarea=Enter+your+text+here%0D%0AAnd+over+multitple+rows+is+OK%0D%0A&submit=Submit+Query bobcat-5.09.01/cgi/driver/version.cc0000644000175000017500000000031414050437223016133 0ustar frankfrank// version.cc #include "main.ih" namespace Icmbuild { char version[] = "0.00"; char year[] = "2007"; char author[] = "Frank B. Brokken (f.b.brokken@rug.nl)"; } bobcat-5.09.01/cgi/driver/main.ih0000644000175000017500000000055214050437223015411 0ustar frankfrank#include #include #include #include #include #include #include namespace Icmbuild { extern char version[]; extern char year[]; extern char author[]; }; void usage(std::string const &progname); using namespace std; using namespace FBB; using namespace Icmbuild; bobcat-5.09.01/cgi/push.cc0000644000175000017500000000015414050437223014134 0ustar frankfrank#include "cgi.ih" void CGIFSA::push() { for (auto &element: d_buffer) d_stack.push(element); } bobcat-5.09.01/cgi/tokenidx.cc0000644000175000017500000000115614050437223015005 0ustar frankfrank#include "cgi.ih" size_t CGIFSA::tokenIdx() { size_t token = (this->*s_tokenizer[d_state])(); // get the next token vector::iterator ret = // look it up find_if( s_fsa[d_state].begin(), s_fsa[d_state].end(), [=](Transition const &transition) { return token == transition.token; } ); d_tokenIdx = ret - s_fsa[d_state].begin(); // determine the index if (d_tokenIdx == s_fsa[d_state].size()) --d_tokenIdx; return d_tokenIdx; // return it } bobcat-5.09.01/changelog0000644000175000017500000027406514067262767014015 0ustar frankfrankbobcat (5.09.01) * DateTime::Zone::initialize was called to initialize a static data member which is used by DateTime constructors. When a DateTime object is statically constructed initialize may not yet have been called. Fixed in this release * The -q option was removed from the 'build' script. * Leftover .tar.gz extensions were removed from the man-pages -- Frank B. Brokken Thu, 01 Jul 2021 08:46:33 +0200 bobcat (5.09.00) * unreleased: DateTime fixes (see 5.09.01) were incorrect. -- Frank B. Brokken Mon, 28 Jun 2021 15:32:14 +0200 bobcat (5.08.01) * Fixed missing assignment of argv[0] to Arg__'s d_argv0 data member -- Frank B. Brokken Mon, 17 May 2021 10:17:20 +0200 bobcat (5.08.00) * Added new members to Arg and ArgConfig, optionally handling non-options as arguments and accessors returning arguments as iterators or as vectors of strings. * The member DateTime::Zone::thisZoneShift was not implemented: added to this release. * Minor changes to the DateTime man-page. * Changed A2x calls to corresponding std::string calls, updated man-pages accordingly. -- Frank B. Brokken Sat, 15 May 2021 12:10:47 +0200 bobcat (5.07.03) * The 'build light' command failed to complete because of a missing -pthread compiler flag: fixed in this release. * The concept Insertable in fmt/fmt still causes issues, and is for the time being no longer used. -- Frank B. Brokken Thu, 12 Mar 2021 10:48:16 +0100 bobcat (5.07.02) * The concept Insertable, defined in fmt/fmt, is temporarily not used: g++-11's version 11.0.0 doesn't handle it correctly, but the next release (g++ 11.0.1, cf. https://godbolt.org/z/P6hxcv) does (Thanks, Wiebe-Marten Wijnja, you saved my day ;-) -- Frank B. Brokken Thu, 04 Mar 2021 13:42:38 +0100 bobcat (5.07.01) * Cosmetic changes required by g++-11, among which a redefinition of the Insertable concept in fmt/fmt -- Frank B. Brokken Wed, 03 Mar 2021 20:33:17 +0100 bobcat (5.07.00) * Arg::argPointers() can also be used with Arg const & reference variables. * Updated the Arg man-page's description of Arg::argPointers() and Arg::versionHelp() (thows 0 when the help or version flags are specified, and throws 1 if fewer than the required number of arguments are specified). * Updated the Process and Pipe man-pages. * Added a description of the member `ostream &stream()' to CSVTable's man-page. * Added constructor CSVTable(std::ofstream &&tmp, std::string const &sep) and member void stream(std::ofstream &&tmp) to CSVTable. * Removed -x.tar.gz from the last lines of the man-pages -- Frank B. Brokken Thu, 24 Dec 2020 14:38:06 +0100 bobcat (5.06.01) * Extended the facilities of CSVTable -- Frank B. Brokken Fri, 11 Dec 2020 15:16:31 +0100 bobcat (5.06.00) * Added the class CSVTable constructing tables row-by-row * Added the move constructor and the move assignment operator to BigInt -- Frank B. Brokken Mon, 07 Dec 2020 20:10:31 +0100 bobcat (5.05.00) * Redefined FBB::binary_search, and updated its man-page * Added the class FBB::Config, deprecating FBB::ConfigFile. * Added the class template FBB::Field allowing retrieval and modifications of offset-based fields in numeric values of configurable number systems. * Added descriptions of the members Arg::LongOption::longName and Arg::LongOption::optionChar to the FBB::Arg man-page * Fixed a bug in DateTime that broke rfc2822() and rfc3329() when DST was acitve. -- Frank B. Brokken Sat, 23 May 2020 15:25:17 +0200 bobcat (5.04.01) * Stupid mistake: forgot to remove the Process header file included ../pipe/pipe -- Frank B. Brokken Wed, 04 Mar 2020 14:39:28 +0100 bobcat (5.04.00) * The Stat and Glob classes received new members and constructors allowing its objects to distinguish file types (like regular files and symbolic links) that cannot be distinguished when merely applying the `bitor' operator to their Type values. Their man-pages were updated accordingly. * The build-scripts (in the /driver directories) use the C++ standard that is defined int the file ./c++std -- Frank B. Brokken Tue, 03 Mar 2020 21:28:54 +0100 bobcat (5.03.00) * Simplfied the PerlSetFSA s_stateTransitions FSA used by Pattern to a mere five states. * Updated the Stat, Pipe, and Process man-pages. * Pipe has several new members (e.g., for closing pipes); its d_fd array of file descriptors is now a private data member. * Process defines its own 'waitForChild' instead of simply calling the member inherited from 'Fork'. * Process avoids open pipes after completing child-processes. -- Frank B. Brokken Fri, 28 Feb 2020 17:51:53 +0100 bobcat (5.02.00) * Added the member 'on' to the class 'Log'. * The member Log::off suppresses logging. Suppression can be undone by calling 'on'. The member 'setLevel' cannot be used anymore to reactivate logging. * Added the enumeration 'Active' to 'LogBuf' allowing derived classes to deactivate or suppress logging information. * Added the member 'LogBuf::empty' returning 'true' if the object's buffer is empty. * Added the member 'LogBuf::setActive(Active)'. -- Frank B. Brokken Wed, 11 Dec 2019 11:06:34 +0100 bobcat (5.01.00) * Fixed a bug in the conversion mode recognition in BigInt::fromText * Added User(size_t uid) and User(string const &name) constructors to the class User. * Added the missing copy constructor and copy assignment operator to the class User. -- Frank B. Brokken Sat, 30 Nov 2019 09:06:43 +0100 bobcat (5.00.03) * Suppressed SF cerr stmnt in digestbuf/eoi.cc * Added missing ; to [[fallthrough]] attributes -- Frank B. Brokken Sun, 08 Sep 2019 17:00:50 +0200 bobcat (5.00.02) * Fixed an error in SyslogBuf's constructor: it now correctly defines the logged message head as SyslogBuf's first argument. * LogBuf's member `active' now (de)activates logging until another `active' call. -- Frank B. Brokken Mon, 03 Jun 2019 16:35:26 +0200 bobcat (5.00.01) * Changed overlooked references to ...bobcat4 into ...bobcat5 -- Frank B. Brokken Wed, 01 May 2019 20:38:19 +0200 bobcat (5.00.00) * All classes derived from std::streambuf are now called ...Buf: Base64StreambufBase -> Base64BufBase IBase64Streambuf -> IBase64Buf IFdStreambuf -> IFdBuf IFilterStreambuf -> IFilterBuf IOStreambuf -> IOBuf IQuotedPrintableStreambuf -> IQuotedPrintableBuf LogBuffer -> LogBuf MultiStreambuf -> MultiBuf OFdStreambuf -> OFdBuf OFilterStreambuf -> OFilterBuf OFoldStreambuf -> OFoldBuf OHexStreambuf -> OHexBuf QPStreambufBase -> QPBufBase Randbuffer -> RandBuf SharedStreambuf -> SharedBuf Syslogbuf -> SyslogBuf * New members replacing old ones: - in all classes previously offering a pSync member: - pSync() is replaced by sync() * ConfigFile: - removed deprecated members: beginRE(std::string const &re); endRE() const; - fixed a (potentially occurring) segfault in ConfigFile * CSV: removed, use CSV4180 instead. * DateTime: - The TriVal type is not used anymore. Instead, `true' (DST is used for the object's time) and `false' (DST is not used) are used. - DateTime(int zoneMinutes) is replaced by DateTime(std::chrono::minutes zoneMinutes) operator@(DateTime const &obj, time_t seconds) is replaced by operator@(DateTime const &obj, std::chrono::seconds seconds) (where @ is + or -) operator@(time_t seconds) is replaced by operator@(std::chrono::seconds seconds) (where @ is += or -=) - setTime() is replaced by setUTCseconds() - time() is replaced by utcSeconds() - setFields(tm const &ts, int fields) is replaced by setFields(tm const &ts, TimeFields fields) - Members expecting or returning size_t values now expect or return unsigned values - Members returning bool values are now void members - Discontinued: The TriVal enum DateTime(int zoneMinutes, DSTSpec const &dstSpec) DateTime(time_t time, int zoneMinutes, DSTSpec const &dstSpec) DateTime(tm const &ts, int zoneMinutes) DateTime(tm const &ts, int zoneMinutes, DSTSpec const &dstSpec) DateTime(std::string const &timeStr, int zoneMinutes) DateTime(std::string const &timeStr, int zoneMinutes, DSTSpec const &dstSpec) DateTime(std::istream &in, int zoneMinutes) DateTime(std::istream &in, int zoneMinutes, DSTSpec const &dstSpec) localTime() to() displayZoneShift() valid() operator bool() error() setValid() - Discontinued static members: zoneMinutes, addZone, defaultZoneMinutes, minutes, readZones zoneTxt * DecryptBuf: - Discontinued: done() setIV() - Discontinued static member: lastOK() - done() is replaced by eoi(), alternatively the eoi manipulator can be inserted into DecryptBuf's std::ostream * DigestBuf: - open() is replaced by reset() - close() is replaced by eoi(), alternatively the eoi manipulator can be inserted into DigestBuf's std::ostream * EncryptBuf: - Discontinued: setKey() setIV() * Glob: - verify(): discontinued * HMacBuf: - open() is replaced by reset() - close() is replaced by eoi(), alternatively the eoi manipulator can be inserted into HMacBuf's std::ostream * IFdBuf: - open() is replaced by reset() * IFilterBuf: - overriding members no longer are declared `final' - pbackfail() inserts (if storage space is available) a character at the beginning of the object's internally used buffer. * IOBuf: - pXsputn() is replaced by xsputn() - open() is replaced by reset() * IRandStream expects a size_t seed (used to be: long seed); * OFdBuf: - open() is replaced by reset() - close() is replaced by eoi(), alternatively the eoi manipulator can be inserted into OFdStreambuf's std::ostream * OFilterBuf: - open() is replaced by reset() - close(): discontinued * OFoldStream: - constructor parameter `char const *fname' is replaced by `std::string const &fname' - open() is replaced by reset() - close() discontinued * OFoldBuf: - constructor parameter `char const *fname' is replaced by `std::string const &fname' * OHexBuf: - added an extra parameter to its constructor: std::string const &separator, by default initialized to an empty string. It defines the separator inserted between hexadecimal character values. - added members `separator' to redefine or reset the currently used separator. - added member `setWidth' to modify the maximum width of lines written to the ostream initialized with an OHexStreambuf object. - close() is replaced by eoi(), alternatively the eoi manipulator can be inserted into OHexStreambuf's std::ostream * OMutexStream: new class offering mutex protected ostream operations. * ProcessData: Internal class previously used by Process to store the Pimpl-data. Now discontinued. * Process: - The class was redesigned so the pimpl idiom (implemented in bobcat 3.19.00) is no longer required. - The mode parameter defined for the second through fourth constructor must be a Process::IOMode value. The same applies to the function call operator previously accespting a size_t argument. - cerr() is replaced by childErrStream() - the eoi() member calls eoi_(). Alternatively the eoi manipulator can be inserted into Process objects to indicate the process's end-of-information. - the eoi manipulator, defined for Process only, is superfluous and is discontinued. Existing code now uses the Eoi-manipulator after recompilation. Changes to the source code are not required. - the std::ostream &operator<<(std::ostream &(*pf)(std::ostream &)) is superfluous and is discontinued. * RandBuf: - expects a size_t seed (used to be: long seed); - fixed a memory leak * Selector: - wait() returns 0 when its read, write and except file descriptor sets are empty. * SyslogBuf: - disontinued the Syslogbuf(char const *, ... ) constructor - open() is replaced by reset() - close() is replaced by eoi(), alternatively the eoi manipulator can be inserted into Syslogbuf's std::ostream * SyslogStream: - disontinued the SyslogStream(char const *, ... ) constructor * Fixed flaw in Log's FBB::fnl handling -- Frank B. Brokken Fri, 26 Apr 2019 15:30:50 +0200 bobcat (4.09.00) * The class Log unconditionally inserts level-free messages; level objects may be inserted anywhere in insertion statements. * The Log and level man pages were updated accordingly. * The class DateTime was completely rewritten, using a Pimpl approach using the this-pointer instead of a separate data member. * The members 'int pSync()', defined in IOStreambuf, LogBuffer, MultiStreambuf, OFdStreambuf, OFoldStreambuf, OHexStreambuf, Syslogbuf, and TableBuf are superfluous. They still exists (as private members), but throw an FBB::Exception{ 1 } when called, and are removed at the next major bobcat release. Man-pages were updated accordingly. * The member `std::streamsize pXsputn(...)' defined in IOStreambuf is superfluous. * Overridding members declared as 'virtual' are now declared as 'override'. * Added the overriding members `xsputn' to OfdStreambuf and Syslogbuf * Updated the Pattern man-page * Internal headers include bobcat headers using "../classname/classname" instead of . -- Frank B. Brokken Tue, 22 Jan 2019 20:59:27 +0100 bobcat (4.08.06) * Added Exception::factory members returning stream objects, added Exception::open members accepting two ios::openmode arguments. * Repaired flaws in man-pages. -- Frank B. Brokken Mon, 17 Dec 2018 09:44:20 +0100 bobcat (4.08.05) * [[fallthrough]] requires a final semicolon (cf. C++ std 20, 10.6.5). Bobcat's code is fixed accordingly. * The BigInt::diophantus members do not require a BigInt object, and are now defined as static members. * Stat declares a default copy constructor, as it defines a move constructor. * Superfluous 'return 0;' statements removed from source files and man-pages. -- Frank B. Brokken Wed, 26 Sep 2018 13:33:52 +0200 bobcat (4.08.04) * Migrated from Github to Gitlab. -- Frank B. Brokken Sun, 17 Jun 2018 14:16:16 +0530 bobcat (4.08.03) * Compilation requires c++17 * LinearMap does not define the Alloc template parameter anymore: no longer required and producing a compilation error with g++8 * Various cosmetic changes * The `build' script has new options: `test', building one class only (align) and `mantest', building a subset of the man-pages. These options were added for (internal) testing purposes only to test Debian package construction -- Frank B. Brokken Sat, 05 May 2018 07:09:00 +0200 bobcat (4.08.02) * CSV4180 supports configurable field separator characters. * Fixed a flaw in the CSV4180 man-page. * Added new member 'release()' to the class CSV4180. * CSV4180's member clear by default resets the number of required fields to 0. * Members in ConfigFile received const modifiers according to the ConfigFile man-page. -- Frank B. Brokken Sun, 16 Sep 2017 10:14:41 +0200 bobcat (4.08.01) * Fixed a bug in fswap due to which fswap could not swap plain pointers. * The String class header file now includes cstring instead of strings.h -- Frank B. Brokken Thu, 31 Aug 2017 11:14:11 +0200 bobcat (4.08.00) * Added new classes IQuotedPrintableStream and IQuotedPrintableStreambuf. * Added new class CSV4180, the class CSV is now deprecated and should no longer be used. Use CSV4180 instead. * Added new variants of the split members, as well as new members join, unescape, urlEncode and urlDecode to the class String. -- Frank B. Brokken Fri, 25 Aug 2017 14:15:46 +0200 bobcat (4.07.00) * The 'build' script now supports a command 'build select [strip] class ...' where 'class ...' is a set of bobcat class names. 'build select' creates a reduced bobcat library only containing the classes (and the classes on which they recursively depend) specified after 'build select [strip]. See also the file INSTALL. * The class 'BinopsBase' as defined in version 4.06.01 was rewritten and further simplified, following suggestions offered by Wiebe-Marten Wijnja. * The file exception/protection.cc no longer uses bobcat/stat, removing a circular dependency. * Dependencies on A2x and X2a were removed, as their facilities are by now provided by std::string. -- Frank B. Brokken Sun, 12 Feb 2017 13:58:03 +0100 bobcat (4.06.01) * The class BinopsBase was simplified. Operator-specifications must now be provided to make the requested overloaded operators available. * The class BinopsBase now also accepts operator specifications 'i' (implementing the insertion operator) and 'e' (implementing the extraction operator. -- Frank B. Brokken Tue, 31 Jan 2017 19:53:19 +0100 bobcat (4.06.00) * The support classes Mul, Div, Mod, ..., Xor, used by BinopsBase declared a Binops parameter, which was nowhere used. This parameter has been removed from BinopsBase's support classes. * All html man-pages were rebuilt by Yodl 3.08.02 (fixing cosmetic errors). -- Frank B. Brokken Sun, 29 Jan 2017 14:43:28 +0100 bobcat (4.05.00) * Added classes Exec, CinInserter, CerrExtractor, CoutExtractor, and StdExtractor, executing child processes. These classes are simplified specializations of Process. Exec simply executes a child process, and waits until its completion; CinInserter acts similarly, but insertions into a CinInserter object are forwarded to the child process; extractions from CerrExtractor read the information that is written to the child process's standard error stream, extractions from CoutExtractor read the information that is written to the child process's standard output stream while extractions from StdExtractor read the information that is written to the child process's standard output and standard error streams. * The fwap function was redesigned, to allow fast swapping for classes of which some members (or their base class(es)) cannot be fast-swapped. Thus far, this only involves classes having std::string members. * All Bobcat classes using fswap have been updated where necessary. They are: CGI, Cidr, CmdFinderBase, CmdFinder, Glob, Hostent, MailHeaders, Pattern, SharedMemory, Stat, TableSupport, and User. * A member `swap' was added to the classes CGI, Cidr, CmdFinder, and CmdFinderBase. * -lpthread was removed from INSTALL.im: it is already available for required classes (see icmake/special), and causes problems on some operating systems/distributions when it is additionally specified in INSTALL.im. -- Frank B. Brokken Sat, 17 Dec 2016 11:17:00 +0100 bobcat (4.04.00) * Added new class template 'BinopsBase' implementing binary operators. The class Binops can also be used, but sometimes causes namespace problems which do not occur when using BinopsBase. * Added missing 'inline' declarations to the definitions in ibase64streabuf1.f and ibase64streabuf2.f. * Replaced return *gptr() by return static_cast(*gptr()) in underflow members of (i)streambuf classes to prevent promotions of characters 0xff to -1, which is EOF. * Added missing DateTime::timeStruct (inline) implementation to DateTime. * Since the global errno variable is used by too much code, Exception{x} constructors now also store x in a thread_local int FBB::g_errno variable. * GetHostent was rebuilt using getaddrinfo and getnameinfo. * Glob received two new flags: NO_FLAG and NOMATCH (refer to its man-page for details). * Added member Arg::help() calling the usage function that was passed to Arg::versionHelp (refer to its man-page for details). * Added member int exitStatus() to Process returning the child process's exit status after calling eoi() or inserting the eoi manipulator. The eoi() member now also returns the child process's exit status. * Removed 'class' from 'friend class' where possible -- Frank B. Brokken Thu, 24 Nov 2016 16:59:06 +0100 bobcat (4.03.00) * Prepared all classes depending on the OpenSSL libraries for OpenSSL1.1.0 Note that the new library requires linking to the crypto library as well (refer to the man-pages for details). Bobcat's release 4.03.00 also compiles OK with the current (1.0.2) OpenSSL version. * Programs using DiffieHellman should be recompiled. * The class Signal now uses 'sigaction' instead of the (deprecated) function 'signal' * IRandStream uses type 'long' for its seed argument to match time(0)'s return type * Various cosmetic code cleanups were performed (e.g., changing Exception() constructions into Exception{} constructions) -- Frank B. Brokken Wed, 17 Aug 2016 07:56:10 +0200 bobcat (4.02.00) * Added the member template template void wait(Fun fun, Args &&...args); // wait # available to the class Semaphore. See 'man -e bobcat semaphore' for details. * Updated documentation for yodl 3.07.01 * Updated 'required': yodl >= 3.07.01, icmake >= 8.01.00 -- Frank B. Brokken Tue, 26 Apr 2016 10:38:48 +0530 bobcat (4.01.04) * build script updated to icmake >= 8.00.04 * 'build install' supports an optional LOG: argument: the (relative or absolute) path to an installation log file. The environment variable BOBCAT is no longer used. * Modified the procedure to install files at their final destinations. -- Frank B. Brokken Sat, 12 Dec 2015 13:21:43 +0100 bobcat (4.01.03) * Kevin Brodsky observed that the installation scripts used 'chdir' rather than 'cd'. Fixed in this release. * Kevin Brodsky also observed that the combined size of all precompiled headers might exceed some disks capacities. The option -P was added to the ./build script to prevent the use of precompiled headers. -- Frank B. Brokken Mon, 05 Oct 2015 20:42:08 +0200 bobcat (4.01.02) * Classes pf_iterator and pf_iteratorstream are BigInt dependent, and are now ignored when running 'build light'. * The arguments and working of './build install' and './build uninstall' was changed. Call ./build for a short description, or read INSTALL. -- Frank B. Brokken Wed, 30 Sep 2015 22.05:58 +0200 bobcat (4.01.01) * Reverted back to using .ih header files again. No additional changes. -- Frank B. Brokken Thu, 24 Sep 2015 13:29:19 +0200 bobcat (4.01.00) * Moved primefactors from CLASSES to SSLCLASSES as the class PrimeFactors depends on BigInt, which in turn depends on the SSL library. * Added 'build uninstall'. This command only works if, when calling one of the 'build install' alternatives and when calling 'build uninstall' the environment variable BOBCAT contains the (preferably absolute) filename of a file on which installed files and directories are logged. Note that 'build (dist)clean' does not remove the file pointed at by the BOBCAT environment variable, unless that file happpens to be in a directory removed by 'build (dist)clean'. See also the file INSTALL. Defining the BOBCAT environment variable as ~/.bobcat usually works well. * In addition to the classes mentioned at 4.00.00 the struct LC (bobcat/lc) was also removed, as it is now superfluous because of the availability of lambda functions: LC (lambda functions) * The .ih internal headers were renamed to .hh, allowing g++ to autimatically recognize them as header files, so they could be converted to precompiled headers, following a suggestion by Bram Neijt. The build script now creates the precompiled headers. They are removed again at the end of the library construction process unless the option -p is provided with 'build libraries'. They are also removed by './build distclean'. -- Frank B. Brokken Wed, 23 Sep 2015 12:11:09 +0200 bobcat (4.00.00) * Major release upgrade needed because of the ABI change of the libc++ libraries introduced by the upgrade to g++ 5.* * Classes, deprecated for quite some time, were removed from Bobcat. The following classes were removed (alternatives are provided between parentheses): AutoPtr (std::shared_ptr, std::unique_ptr) Errno (FBB::Exception) FnWrap (lambda functions) for_each (lambda functions) Msg (FBB::Mstream) RefCount (std::shared_ptr, std::unique_ptr) -- Frank B. Brokken Mon, 03 Aug 2015 15:58:34 +0200 bobcat (3.25.02) * Added the missing implementation of the member function BigInt::ulong() -- Frank B. Brokken Thu, 11 Jun 2015 11:45:05 +0200 bobcat (3.25.01) * Fixed overlooked minor bug in Mbuf -- Frank B. Brokken Sun, 15 Feb 2015 08:08:09 +0100 bobcat (3.25.00) * Added new member 'size()' and 'remove()' to MultiStreambuf * Defined manipulators 'noid' and 'noidl' for Mstream objects which do not show the objects' IDs when throwing exceptions. * Cosmetic changes to several man-pages * Fixed compilation errors that emerged with g++-5, reported by Matthias Klose. -- Frank B. Brokken Thu, 12 Feb 2015 17:00:57 +0100 bobcat (3.24.01) * Added missing 'throw' clause to log/open.cc -- Frank B. Brokken Mon, 09 Feb 2015 13:03:37 +0100 bobcat (3.24.00) * Added new class Semaphore, implementing Dijkstra's (1962) Semaphore data type. * Added the file 'required' to the source distribution summarizing the required software for building bobcat. * LocalServerSocket objects now by default unlink their unix domain sockets. -- Frank B. Brokken Thu, 29 Jan 2015 09:13:35 +0100 bobcat (3.23.01) * Using (s)random instead of (s)rand in Randbuffer * Log(Buffer) now also supports FBB::UTCTIMESTAMPS to show timestamps in UTC. * Fixed several flaws in man-pages -- Frank B. Brokken Sun, 24 Aug 2014 11:42:38 +0200 bobcat (3.23.00) * Added class SharedCondition, which is used to define a condition variable inside a shared memory segment. * Added class Tty, controlling echoing of characters entered at the terminal (/dev/tty). * Log objects are now active by default (except for the Log object constructed by its default constructor) * The default Log constructor no longer has a default argument, as providing an explicit argument may be confused with the constructor expecting a std::string as its first argument. * Added new member `prepareDaemon(string const &out, string const &err, mode_t mode) const' to the class Fork, allowing automatic redirection of stdandard output and standard error messages to files. * Added new member `install' to the class SharedMemory, using placement new to construct an object in shared memory. * Added the description of the enum SizeUnit to the man-pages of all classes using FBB::SharedEnum::SizeUnit. * SharedStreambuf: extractions (also insertions ?) sometimes failed to operate correctly. Fixed by adding setg() and setp() calls to constructors and underflow. Also added sharedstreambuf/driver. * Added SharedReadme (7bobcat) and associated figures describing how the Shared Memory classes were implemented. * Fixed incomplete deletion of shared memory segments by SharedMemory::kill() and SharedMemory::clear() * Fixed unbalanced parentheses in the man-pages -- Frank B. Brokken Wed, 04 Jun 2014 17:38:42 +0200 bobcat (3.22.01) * Hurd-i386 architectures do not (completely?) implement the POSIX standard, requiring the definition of some specific macro definitions. These macros are now added where required: to stat/path.cc and signal/verify.cc * Iterator's implementation now follows the design described in the C++ Annotations -- Frank B. Brokken Mon, 03 Mar 2014 21:28:03 +0100 bobcat (3.22.00) * Added new class CSV, handling comma separated values * Learned something new: in order to define a const reverse iterator, define Type const &reference in the iterator class, and define Type const &operator*() const. The use of shared_ptr (see git commit 1215566b78...) is not required. * Applied several cosmetic changes -- Frank B. Brokken Fri, 28 Feb 2014 19:44:52 +0100 bobcat (3.21.01) * Oops, 3.21.00 lacked the 'iterator' header file that provides Iterator and ReverseIterator. -- Frank B. Brokken Sat, 15 Feb 2014 15:25:58 +0100 bobcat (3.21.00) * Added the class templates Iterator and ReverseIterator -- Frank B. Brokken Sat, 15 Feb 2014 12:25:07 +0100 bobcat (3.20.01) * Added the LinearMap(initializer_list) constructor to the class template LinearMap. -- Frank B. Brokken Sat, 18 Jan 2014 16:55:32 +0100 bobcat (3.20.00) * Added the class template LinearMap implementing an associative array using linear searching. * Fixed a bug in ArgConfig's option(string *dest, char const *key). The current version conforms to ArgConfig's man-page, stating that a key's trailing colon (:) in a configuration file is ignored if a key without a colon is passed as an argument to this member. -- Frank B. Brokken Sat, 18 Jan 2014 12:40:13 +0100 bobcat (3.19.01) * Fixed Process's d_closedByChild initialization (used by FreeBSD systems). -- Frank B. Brokken Mon, 30 Dec 2013 11:17:50 +0100 bobcat (3.19.00) * Added Signal::remove, removing a previously added signal handling object. * Redesigned Process so that it (partially) uses the pimpl idiom. Also added the eoi manipulator and several new member functions. * Updated man-pages for Pipe, Redirector, Process, and Signal, -- Frank B. Brokken Sat, 28 Dec 2013 11:16:20 +0100 bobcat (3.18.01) * Fixed a mismatch between SharedMemory::read's declared and defined return type. * Fixed erroneous #include directives in several Shared* class headers -- Frank B. Brokken Fri, 22 Nov 2013 09:15:24 +0100 bobcat (3.18.00) * Added several new classes handling shared memory: ISharedStream, OSharedStream, SharedBlock, SharedMemory, SharedMutex, SharedPos, SharedSegment, SharedStream, and SharedStreambuf * Moved, where possible, nested struct/class definitions not required in the public interface to the internal headers. * The nested class MailHeaders::const_hdr_iterator is used in the public interface: it is now declared in the public interface as well. -- Frank B. Brokken Mon, 18 Nov 2013 12:26:47 +0100 bobcat (3.17.00) * New split members added to the String class, removing the private split facility from Process, which are now superfluous, as they are covered by String's split facilities. * The class BigInt has received several new members and defines a type: - BigInt::Word, is equal to the OpenSSL BN_ULONG type, defining the unsigned long type that is used for storing BIGNUM values; - sizeOfWord() returning the size in bytes of a BigInt::Word; - nWords() returning the number of Words used by the current BigInt value; new at() member; - Word at(size_t index) returns the Word at 'index'. * The source header file of classes defining function templates and inline-members now have their template definitions in .f files, one .f file per function. This change was implemented to simplify function template and inline function maintenance, and to have source clas header files representing class interfaces as cleanly as possible. * Removed the man-page of the deprecated class Errno * All class-specific icmconf files were standardized (and cleaned) * NOTE: the way the linker handles required libraries has changed See, e.g., http://fedoraproject.org/wiki/UnderstandingDSOLinkChange Due to this change programs depending on the bobcat may now require explicit specifications of libraries. Most likely the linke will come with a suggestion. The library libcrypto is a likely candidate for explicit inclusion. If so, use -lcrypto when linking such depending programs. -- Frank B. Brokken Wed, 09 Oct 2013 17:50:04 +0200 bobcat (3.16.00) * Re-implemented process/analyzecommand.cc, improving the wait it handles escaped characters and quoted and double quoted strings. * Added additional demos to the process man-page. * Added the static member Exception::protection to the Exception class. * Gzipped files in the provided documentation no longer contain internal time-stamps. -- Frank B. Brokken Fri, 13 Sep 2013 15:53:51 +0200 bobcat (3.15.00) * Added class IFilterStreambuf, implementing filtering like, e.g., openSSL BIOs. * Added class ISymCryptStreambuf and its base class SymCryptStreambufBase, implementing SSL-provided symmetric encryption and decryption using the IFilterStreambuf design pattern. * Added class IBase64Streambuf and its base class Base64StreambufBase, implementing base64 encoding and decoding, using the IFilterStreambuf design pattern. * Added class IBase64Stream, using a IBase64Streambuf for its std::streambuf. * Added class ISymCryptStream, using a ISymCryptStreambuf for its std::streambuf. * Added class DiffieHellman, implementing Diffie-Hellman shared key computations. * Added the internal use only class FBB, to contain structs, enums, etc. that are used by other Bobcat classes. * Added new constructors to BigInt initializing BigInt values from a series of characters or from a std::string. -- Frank B. Brokken Mon, 26 Aug 2013 15:16:13 +0200 bobcat (3.14.00) * Syslogbuf and SyslogStream received an overhaul, adding several new members. -- Frank B. Brokken Fri, 10 May 2013 11:30:50 +0200 bobcat (3.13.00) * Added new member CGI::param1 * Updated CGI documentation -- Frank B. Brokken Thu, 25 Apr 2013 16:42:05 +0200 bobcat (3.12.00) * Added class Exception, obsoleting class Errno. * All occurrences of Errno in Bobcat were replaced by Exception * The class tt(BigInt) received several new member diophantus (for long long values and BigInt values). See the bigint(3bobcat) man page for details. * Added new class PrimeFactors, factorizing BigInt values. * Added missing OFdStreambuf::pSync member. -- Frank B. Brokken Sun, 24 Feb 2013 13:09:38 +0100 bobcat (3.11.01) * Repaired incorrect #include "../gs/gs" in glob/glob -- Frank B. Brokken Sat, 27 Oct 2012 16:02:58 +0200 bobcat (3.11.00) * Added OFdStreambuf constructor and open member expecting a std::string const & defining the name of the stream to receive the filtered information. * Glob offers an additional constructor allowing users to specify the type of directory entries they are interested in (e.g., DIRECTORY, REGULAR_FILE, or any bitor-ed combination. The flags defined in Bobcat's Stat class are identical to those that are available in Glob. * Glob now uses the pimpl design with all its public members. * Several man-pages were updated, mostly textual corrections. -- Frank B. Brokken Sat, 27 Oct 2012 12:14:35 +0200 bobcat (3.10.01) * Library constrction scripts cleanup so it supports environment variables: LDFLAGS, CPPFLAGS, CXXFLAGS and CXX -- Frank B. Brokken Sun, 22 Jul 2012 13:58:01 +0200 bobcat (3.10.00) * Added class Signal, allowing context to be used by programs receiving signals. * Added to the class User members (egroupid, euserid) to retrieve the effective group and user-ids and a member (inGroup) to determine whether the user is a member of a specified group. * Added to the class Stat a member (access) returning true if specified read, write and/or execute permissions are granted for a provided FBB::User object. -- Frank B. Brokken Thu, 28 Jun 2012 22:29:46 +0200 bobcat (3.01.00) * Repaired a bug in DateTime: its dstCorrection(bool *ok) member failed to set the ok boolean to true if the localime_r performed correctly. * According to the man-page localtime_r does not assume that tzset(3) has been called, but leaves this to the calling program. Localtime_r's man-page states: For portable code tzset should be called before localtime_r(). DateTime::dstCorrection(bool *) now calls tzset before calling localtime_r. -- Frank B. Brokken Mon, 14 May 2012 11:43:08 +0200 bobcat (3.00.02) * Cosmetic split of configile/beginre.cc into two sources, one holding the deprecated member ConfigFile::begin, the other one holding ConfigFile__::begin. * All classes that may throw Bobcat's Errno exceptions now include bobcat/errno in their class-level header files. -- Frank B. Brokken Thu, 10 May 2012 13:50:36 +0200 bobcat (3.00.01) * Re-added deprecated classes and members that were removed in 3.00.00 * Old references to ...bobcat2 in icmake files replaced by references to ...bobcat3 -- Frank B. Brokken Mon, 07 May 2012 17:08:51 +0200 bobcat (3.00.00) * Functionality deprecated in Bobcat < 3.00.00 has been removed. This includes the classes Msg (Use Mstream or Errno), the FnWrap* and ForEach templates (use lamda functions), and AutoPtr / RefCount (use std::shared_ptr or std::unique_ptr) * Arg/ConfigFile/ArgConfig now use the Bridge Design Pattern. Note that this requires (only once) all programs using Arg, ConfigFile or ArgConfig to be recompiled. * Added member int Arg::beyondDashes() returning the index of the first argument beyond a -- argument (or -1) * The 'repeat' function template was improved, now perfectly forwarding arguments to (member) functions repeatedly called by `repeat'. * Replaced climits constants by limits const-expressions * Added TempStream creating a temporary fstream * NOTE: programs depending on the Bobcat shared library most likely must be recompiled. Minor code modifications may be necessary if a program still used Bobcat's deprecated facilities, which are now removed from Bobcat. -- Frank B. Brokken Sat, 05 May 2012 16:50:58 +0200 bobcat (2.22.00) * Repaired bug in ArgConfig: following load() options in the config. file were (sometimes) not found. * ArgConfig option specifications may now have an optional : appended to them. * ConfigFile (and ArgConfig) may use \# in configuration files to specify a literal #. The \ is removed from the configuration line. * Code-cleanup of ArgConfig, adapted argconfig/driver's build script and provided an example config file. * Added missing parameters to ArgConfig's constructors in its man-page. -- Frank B. Brokken Mon, 16 Apr 2012 11:50:40 +0200 bobcat (2.21.01) * Replaced for_each calls by range-based for-loops -- Frank B. Brokken Sat, 21 Jan 2012 16:52:00 +0100 bobcat (2.21.00) * Added new classes: Ranger and PtrIter, see their man-pages for details * Repaired a flaw in hash/hash, appearing with g++-4.7 -- Frank B. Brokken Sat, 07 Jan 2012 13:27:57 +0100 bobcat (2.20.02) * Using rang-based for loops where appropriate; minor cosmetic code changes -- Frank B. Brokken Wed, 04 Jan 2012 13:20:29 +0100 bobcat (2.20.01) * Repaired bug in ReadLineBuf: object was incompletely initialized resulting in intermittendly occurring segfaults. -- Frank B. Brokken Sun, 04 Dec 2011 21:31:12 +0100 bobcat (2.20.00) * Redefined the implementations of the templates in bobcat/binops. -- Frank B. Brokken Thu, 03 Nov 2011 18:42:27 +0100 bobcat (2.19.01) * Repaired bug in BigInt::isqrt * BigInt's destructor called BN_clear, but should have called BN_free. Now repaired. -- Frank B. Brokken Mon, 10 Oct 2011 10:29:08 +0200 bobcat (2.19.00) * The 'BigInt' man-page was adapted to match the actual member and function prototypes mentioned in * Repaired a bug in size-test in BigInt::fromText * The 'binary_search' template was inadvertently dropped from Bobcat's classes and has been added again. * Environment variable name CPPFLAGS changed to CXXFLAGS * Updated README.class-setup overview of classes -- Frank B. Brokken Thu, 22 Sep 2011 20:57:58 +0200 bobcat (2.18.00) * Added missing Stat::operator=(Stat const &other) member. * FnWrap* calls removed from the bobcat library: they are now superfluous as compilers support lambda functions. The FnWrap* classes remain available. * George Danchev observed that static const numeric datamembers (e.g., size_t) using in-class initialization values cause compilation errors when all optimizations are switched off (-O0). These static const data members were replaced by enum values. * Added IfElse and LpromotesR class templates to bobcat/typetrait * The arithmetic operator function templates defined in bobcat/binops now support promotions for classes defining constructors allowing promotions. -- Frank B. Brokken Fri, 17 Jun 2011 10:32:38 +0200 bobcat (2.17.00) * In accordance with C++0x's prototype of move members Bobcat's move constructors and move assignment operators now all use 'Class &&tmp' parameter definitions (where Class should be replaced by the actual class name). Previously defined members specifying 'Class const &&tmp' were retained for backward compatibility, but also generate a `deprecated' warning when used from, e.g., a dynamic library. If such a warning is generated the program dynamically linking to the bobcat library only needs to be recompiled to get rid of the message. * Added new series of function templates in the bobcat/binops header file, making available all binary arithmetic operators for classes already defining (a subset of) the binary assignment operators. The command `man -e bobcat binops' provides the details. -- Frank B. Brokken Mon, 06 Jun 2011 14:35:52 +0200 bobcat (2.16.00) * Removed obsolete bobcatlcgen * All previously inline implemented virtual members are now defined as non-inline members, which should solve an issue with compilers on armel architecture which don't handle inline virtual members correctly. * The 'build' script now uses the -g option by default (set in INSTALL.im). To modify the g++ compilation options change the #define CPPOPT in INSTALL.im. By default it is set to "-O2 -g". To modify the flags `on the fly' set the environment variable CPPFLAGS to the compiler options to use. The options "-isystem tmp -Wall" are always used and should not be altered. bobcat (2.15.02) * Replaced the auto_ptr in Log by a unique_ptr. Since both have equal sizes and are only used in compiled sources (not in inline functions) no recompilation of programs dynamically linking to bobcat is required wrt this change. * The Pattern static data members in the class Cidr are in some situations not properly initialized with g++-4.6. This, e.g., already happens when an empty main() function is linked against the Bobcat library. Although the Pattern objects are not properly initialized, their destructors are nonetheless called when the program ends, causing a segfault. Static object initialization is a known protential source of problems, see, e.g., to cause problem. See also http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.15 In the case of Cidr the problem was easily solved. Each of the two static Pattern members is only used in a single Cidr-member. Removing the static data members from the interface and defining them as static local objects in the member functions using them solves the problem. -- Frank B. Brokken Wed, 11 May 2011 14:26:49 +0200 bobcat (2.15.01) * Repaired flaw in fnwrap, emerging while compiling bisonc++ -- Frank B. Brokken Thu, 05 May 2011 09:35:15 +0200 bobcat (2.15.00) * New version repairs some flaws that became apparent with g++ 4.6. * Re-implemented FnWrap: its size has been halved, FnWrap::unary and FnWrap::binary act identically and are now in fact superseded by the function FBB::context(). * Added README.fnwrap to the set of README files, explaining the FnWrap's inner workings -- Frank B. Brokken Mon, 02 May 2011 19:53:04 +0200 bobcat (2.14.00) * New class: Cidr verifying whether an IP4 address belongs to an IP4 Classless Inter-Domain Routing (CIDR) address block. * New class: StringLine doing line instead of word extraction with operator>>. * Repaired bug in ConfigLine detected by Kees Visser on amd64 architectures causing string to throw an exeption with empty configuration file lines -- Frank B. Brokken Sat, 05 Feb 2011 12:02:08 +0100 bobcat (2.13.00) * Repaired bug in Arg detected by George Danchev sometimes causing segfaults when an undefined long option is specified. * This line added after tagging, but part of 2.13.00: using std::unordered_map instead of std::map with Arg. * Moved public MailHeaders::const_hdr_iterator members from mailheaders.ih back to mailheaders * Cosmetic corrections to man-pages -- Frank B. Brokken Wed, 02 Feb 2011 18:39:50 +0100 bobcat (2.12.00) * FreeBSD flavors lack the fntl flag F_DUPFD_CLOEXEC, so Process::operator| must use a work-around for that flag. The work-around is compiled into Process objects/code when the BOBCAT_DIY_CLOEXEC_ identifier has been defined. It is defined by default in process/process when the identifiers __FreeBSD_kernel__ or __FreeBSD__ are defined. As F_DUPFD_CLOEXEC has been defined by POSIX since 2008 it is possible that it will soon be defined by FreeBSD systems as well. The work-around adds an additional data member to the Process class. Since the data member is the last data member of Process objects it can easily be removed at a later stage when F_DUPFD_CLOEXEX becomes available for FreeBSD systems. * Lacking descriptions of some FBB::CGI members were added to the cgi(3bobcat) man-page. * The CGI class now uses a std::unordered_map, rather than a std::map * Process now supports IOMode::DIRECT * The file README.process-pipe (and support files process-pipe.odp and process-pipe.pdf) were added tot Bobcat's root direcory, describing the inner workings of Process's operator|. -- Frank B. Brokken Sun, 30 Jan 2011 14:51:48 +0100 bobcat (2.11.00) * Repaired bug in Process due to which single quoted process arguments were not correctly passed on to the child process * When using Process::IGNORE_ALL in combination with other Process:IOMode flags an std::invalid_argument exception is thrown * Removed all Errno insertable/throwable manipulator calls from Bobcat * Removed empty source file bigint/checked5.cc * IOStream(istream &, ostream &)'s constructor now also opens the IOStream object (as it always should have done) * OFdStreambuf and IFdStreambuf have a new member (int fd()) returning the File Descriptor. Their descructors are not defined inline anymore (but their implementations have not changed) and they have a new member (close()) closing the streambuf. Closed OFdStreambuf and IFdStreambuf objects can again be opened using open() * Updated several man-pages bobcat (2.10.03) * Matthias Klose detected several bugs/omissions in Bobcat's shared library construction. Now fixed. -- Frank B. Brokken Wed, 29 Dec 2010 17:14:06 +0100 bobcat (2.10.02) * ConfigFile's size() member was missing. Now repaired. -- Frank B. Brokken Sat, 25 Dec 2010 11:02:02 +0100 bobcat (2.10.01) * TableLines' default and move constructor and move assignment operator were accidentally put in the private section of their class. Now public. * Configfile's overloaded assignment operator used non const & argument. Repaired. * CmdFinderBase's overloaded assignment operator cannot be defaulted as it lives in the class's protected section. Added explicit implementation of the overloaded assignment operator. -- Frank B. Brokken Sun, 19 Dec 2010 21:29:26 +0100 bobcat (2.10.00) * Reorganized the class ConfigFile. It used inheritance the wrong way (it inherited to reuse its base class rather than the base class being reused (cf. Herb Sutter's Exceptional C++)) and it suffered from several other flaws. ConfigFile now also supports a move constructor and move overloaded assignment operator. * Repaired ArgConfig::longConfigOpt(string const &longOpt). It checked for the longOpt\b pattern, but \b matches also the - character as a word delimiter. Therefore, pattern xyz-pqr is matched when looking for pattern xyz. It's now using (\s|$) rather than \b. * Reorganized the class MailHeaders. It used inheritance the wrong way (see ConfigFile above). * In addition to the classes that have already been made move-aware, the following classes are now also move-aware: CmdFinderBase, CmdFinder, CGI. Hash, MailHeaders, Stat, TableSupport, TableLines, User (see also README.immovable). * The hash-containers (defined in bobcat/hash) now also support initialization by initializer lists. * The class Milter now uses an unordered_map instead of a map. * The -O3 compilation optimization flag is changed to -O2. G++ for the armel architecture produces an incomplete symbol table when -O3 is used. -- Frank B. Brokken Fri, 17 Dec 2010 14:18:33 +0100 bobcat (2.09.04) * Repaired ArgConfig::option(string *value, ...) members which didn't check for 0-pointers to the string receiving the option's value. -- Frank B. Brokken Mon, 06 Dec 2010 23:38:44 +0100 bobcat (2.09.03) * Repaired Arg::firstNonEmpty which didn't check for 0-pointers to the string receiving the option's value. * Reorganized man-pages to comply with include requirements of Yodl 3.00.0 -- Frank B. Brokken Sun, 05 Dec 2010 19:20:46 +0100 bobcat (2.09.02) * No 'virtual ~Mbuf() = default': destructor removed from Mbuf. -- Frank B. Brokken Thu, 04 Nov 2010 12:45:40 +0100 bobcat (2.09.01) * Mstream::id() now returns a long, rather than an int. See http://developers.sun.com/solaris/articles/ILP32toLP64Issues.html -- Frank B. Brokken Wed, 03 Nov 2010 11:55:17 +0100 bobcat (2.09.00) * Added new classes ReadLineBuf and ReadLineStream reading the standard input using the Gnu readline library, wrapped inside, respectively, a streambuf and an istream. These classes require linkage to libreadline. The class ReadLineBuf is a singleton class. * Added new class ReadLineHistory allowing easy handling of the history accumulated by the ReadLineBuf class. The class ReadLineHistory is a singleton class. * Virtual members of classes derived from std::streambuf were move to the the private section of the classes, making these classes more compliant with Liskov's Substitution Principle. * The 'sync' members of classes derived from std::streambuf can be called from derived classes using a protected 'pSync' member. The IOStreambuf class offers comparable protected 'pSeekoff' and 'pSeekpos' and 'pXsputn', allowing the seek and put operations to be performed on request by classes derived from IOStreambuf. * NOTE: Errno's virtual member what() will be moved to Errno's private section in a future release. The new public member 'why' should be used instead, or std::exception::what() should be used. * The class Msg is now deprecated. Classes Mstream (Message stream) and Mbuf (Message buf) have replaced Msg, and Msg's open members have moved to Errno. Msg will remain in Bobcat for a while, but will eventualy be removed. An error message is displayed (once) if Msg::msg() and Msg::open() are used. -- Frank B. Brokken Thu, 28 Oct 2010 20:17:50 +0200 bobcat (2.08.01) * Checked in overlooked repairs of hostent/destroy.cc and TableSupport::setCols. -- Frank B. Brokken Wed, 05 May 2010 11:13:47 +0200 bobcat (2.08.00) * >>>NOTE<<<: Due to a changed organization of the Table classes all software using the 2.07.04 shared library's Table and TableSupport classes needs to be recompiled. * Added new class TableBuf. A streambuf class allowing table constructions using std::ostream objects * Added new class (only used internally by Bobcat): TableBase, containing the common to TableBuf and Table * Added new class TableLines derived from TableSupport setting separating lines across rows/columns of tables * Reorganized the class TableSupport, moving members erroneously placed in in tablesupport.ih back to the tablesupport header file -- Frank B. Brokken Tue, 04 May 2010 12:14:30 +0200 bobcat (2.07.04) * Virtual destructors cannot have default implementations. Added Fork::~Fork and TableSupport::~TableSupport * Repaired compilation problem in fnwrap/fnwrap appearing with g++-4.5 (using Debian 4.5-20100404-1) * fnwrap/fnwrap needs std::move calls where lvalue references are passed to rvalue references, as templates do not automatically perform the conversion from lvalue refs to rvalue refs. -- Frank B. Brokken Fri, 09 Apr 2010 08:58:49 +0200 bobcat (2.07.03) * Repaired additional bugs in String::unescape; unescape only allows \x, \X is no longer accepted (and was not according to the standard), \0 not followed by octal numbers is now recognized as a 0-byte. * Multi-parameter constructors of Arg::LongOption no longer use default arguments to allow the use of initializer lists, added the explicit constructor Arg::LongOption(char const *name) * Added missing #include to localsocketbase/localsocketbase.ih * Pattern now defines the default end pattern (pattern/pattern0.cc) as "\\b" for the benefit of MAC users who otherwise suffer from the `empty sub-expression' error. This affects ConfigFile and (by implication) programs like XD. It has no known effect on Debian systems. -- Frank B. Brokken Fri, 19 Mar 2010 15:37:02 +0100 bobcat (2.07.02) * Repaired a bug in converting escaped hexadecimal characters in String::unescape, reported by Richard Berendsen. * The FnWrap example is now about FnWrap, not anymore about FnWrap2c -- Frank B. Brokken Wed, 24 Feb 2010 08:33:51 +0100 bobcat (2.07.01) * Minimized class FnWrap's member access rights. FnWrap's inner organization improved. Instead of creating nested FnWrap1 and FnWrap2 objects inheritance is used. Also, all function template implementations were moved to below the class interface. -- Frank B. Brokken Mon, 15 Feb 2010 12:42:49 +0100 bobcat (2.07.00) * TypeTrait now supports tests for rvalue reference types. * FBB::insertable and FBB::throwable are no longer required when using Errno * The gptr() < egptr() checks in underflow() functions (IFdStreambuf and Randbuffer) are superfluous and have been removed. * DateTime's man-page contains a caveat for setMonth. * Fswap's man-page BUGS section is augmented with a warning against swapping streams. * Bobcat's main man-page received an entry referring to the TypeTrait class template. * Repaired cgi/push.cc and cgi/accept.cc * New class: FBB::FnWrap, easier to use than and providing all the features of FnWrap[12]c?. See its man-page for details. * Not-implemented constructors and functions, previously flagged with the // NI comment, are now using '= delete'. Likewise, implementaitions of explicitly implemented empty default constructors were removed and replaced by '= default'. Some con- and destructors were kept due to non-public access. The added destructors were defined in source files, and not in-line to localize the class's Vtables with the destructor's source files. * Compilation of, e.g., Glob::operatorassign.cc produces a warning in g++-4.4. This warning disappears with g++-4.5 and is therefore ignored. * Sources also compile fine with g++-4.5 -- Frank B. Brokken Sat, 13 Feb 2010 15:30:43 +0100 bobcat (2.06.00) * Added BigInt::isqrt (integral sqrt computation) * Added BigInt::swap (swapping the current BigInt object's value with another BigInt object's value * BigInt's members not modifying the current object are now const-correct. * In addition to members modifying a BigInt object new members were added not modifying the current object but returning a temporary BigInt const object holding the result of the computation. All members returning a BigInt const object have an additional c added to their names (e.g. `div' modifies the current object, `divc' does not). As a result of this name standardization the names of several members were modified: `gcd' now modifies the current object, `gcdc' returns a BigInt const. `inverseMod' now modifies the current object, `inverseModc' returns a BigInt const. * Added template function fswap, performing fast swapping operations. * The class Glob is now move-aware (offers move constructor and move assignment operator. In addition it offers a swap member. * Move members in Pattern expect 'Pattern const &&', Pattern offers swap. * Hostent now is now move-aware and offers a member swap. Included Hostent in the namespace FBB. -- Frank B. Brokken Fri, 27 Nov 2009 08:49:24 +0100 bobcat (2.05.00) * BigInt values inserted into streams do not show leading zeroes anymore, except for octal values. * BigInt values can be assigned a value from a textual representation * BigInt values can be extracted from std::istream objects. * BigInt::inverseMod() and BigInt::gcd() are now member functions rather than free functions. * BigInt::setBigEndian() is now a static member function. In general: all members returning a BigInt computed from a set of arguments and not requiring an existing BigInt object are defined as static members. * Added MD_CTX initialization and cleanup calls to DigestBuf * Added MD_CTX initialization call to HMacBuf -- Frank B. Brokken Wed, 23 Sep 2009 15:32:48 +0200 bobcat (2.04.02) * DateTime: DST updated by setXXX() members as well. * EncryptBuf/DecryptBuf now correctly set keylength * EncryptBuf's manpage shows key/block sizes in bytes and provides an illustration showing how to discard initial bytes (commonly used with RC4) * DecryptBuf's requirement of non-empty IV vector has been dropped * Repaired Debian bug #546374, reported by Stefan Ebner -- Frank B. Brokken Sun, 13 Sep 2009 11:38:18 +0200 bobcat (2.04.01) * Some OpenSSL functions (HMAC, Digest) needed unsigned 'int *'s. They got 'size_t *s' causing problems on 64-bit archs (e.g. amd64). Now fixed. -- Frank B. Brokken Fri, 04 Sep 2009 23:48:22 +0200 bobcat (2.04.00) * BigInt has been enhanced and extended. Many members have received new prototypes. * New Class: OHexStreambuf, streambuf derived class writing characters received by it as hex numbers to a specified std::ostream. * New Class: DigestBuf, streambuf derived class computing various types of message digests of the characters received by it. * New Class: HMacBuf, streambuf derived class computing a HMAC hashvalue of the characters received by it. * New Class: EncryptBuf, streambuf derived class encrypting the characters received by it, writing the encrypted information to a specified std::ostream. * New Class: DecryptBuf, streambuf derived class decrypting the encrypted information received by it, writing the decrypted information to a specified std::ostream. -- Frank B. Brokken Wed, 02 Sep 2009 20:41:06 +0200 bobcat (2.03.00) * Bobcat is compiled by g++ --std=c++0x. * Stat::modeStr() bug repaired due to which it always showed rwxrwxrwx * Removed deprecated getPid() member from Fork * Removed deprecated get...Fd() members from Pipe * Removed deprecated get...Fd() members from Selector * Selector's setAlarm() member performs a validity check on the specified alarm time * Selector's wait() member handles no-alarm specifications correctly (i.e., according to the description in the select(2) man-page. * Redirector has a new member: through() * IFdStreambuf::xsgetn() was reimplemented to allow unformated reads from std::istream (and IFdStream) objects without referring to underflow. * InetAddress has new members sockaddr_inPtr() returning pointers to its sockaddr_in data member. * Repaired bugs in DateTime constructors accepting strings, redefined many of DateTime's functionality, see its man page. * (Almost) all unary argument constructors now `explicit' * Constructors that can safely throw exceptions, rather than using `verify' do so from now on. The `verify' member remains, albeit empty, available in the class interfaces. Affected classes: Glob, OneKey, User, Pipe, SocketBase, XPointer * Classes for which a move constructor is useful received a move constructor. Currently: AutoPtr, Glob, Pattern, * insert and extraction operators (operator<<, operator>>) are now defined within the namespace FBB and no longer in the std namespace (except for operator<< defined int msg/msg which is in std::) * Added BigInt as the first (optionally added) class depending on OpenSSL. The plan is to add more openssl-based classes in the (near) future. BigInt wraps OpenSSL's unlimited precision number feature implemented by OpenSSL's BN_ functions. -- Frank B. Brokken Wed, 22 Jul 2009 17:37:27 +0200 bobcat (2.02.03) * Missed another EOF in MultiStreambuf. Now repaired. -- Frank B. Brokken Wed, 06 May 2009 10:36:22 +0200 bobcat (2.02.02) * Repaired incomplete initialization bug in SocketBase * Added Fork::prepareDaemon() performing common actions when starting a daemon child process. * Repaired DST and extraction bugs in DateTime * OFoldStreambuf's inheritance tree now places the OFilterStreambuf ahead of the std::ostream class to prevent strange run-time problems on Macs. * New (static) members: OFoldStream(buf)::leftMargin(), OFoldStream(buf)::rightMargin() * OFoldStream::open() members do not close the foldstream (actually, they didn't do that, but the man-page wrongly suggested they did close the stream). * Cosmetic changes to INSTALL, INSTALL.im and icmake/install * Replaces and extends intermediate release 2.02.01 only made available at SourceForge -- Frank B. Brokken Fri, 03 Apr 2009 16:29:47 +0200 bobcat (2.01.1) * The manipulator FBB::FATAL (cf. man -e bobcat log) now throws an Errno exception (Errno(1)) as per the log man-page, and doesn't call exit(1) anymore. bobcat (2.01.0) * Included cstdio in all .ih files of classes using EOF (required for g++ 4.4) * Moved Table::Element's constructor back to the header file (required for Table::push_back()). * Added Log member level() retrieving the currently set loglevel. * Added Log member instance() as a (preferred) alternative for getInstance(). * LogBuffer::overflow() now has protected access rights. * Stat's lastAccess(), lastChange(), and lastModification() members now return DateTime objects representing the times in UTC. * New class: LC, template class to define and/or declare Local Context structs to be used with the FnWrap[12]c classes (cf man -e bobcat lc as well as the FnWrap[12]c man pages) * Added program `bobcatlcgen' generating a file defining the template class LC for a configurable maximum number of fields of the local context structs (cf. man -e bobcatlcgen) * New class: OFilterStreambuf, std::streambuf specialization implementing an ostream filtering design pattern (cf man -e bobcat ofilterstreambuf) * New class: OFoldStreambuf, OFilterStreambuf specialization folding long lines to lines having configurable left and right margins (cf man -e bobcat ofoldstreambuf) * New class: OFoldStream, wrapper class around OFoldStreambuf (cf man -e bobcat ofoldstream) * New class: lm, implementing a manipulator for OFoldStreams setting their left margin (number of indented blanks) (cf. man -e bobcat lm) * New class: mlm, implementing a manipulator for OFoldStreams modifying their left margin (cf. man -e bobcat mlm) bobcat (2.00.1) * George Danchev detected a compilation problem in ArgConfig's option3.cc: On amd64 size_t doesn't match the U postfix for numeric constants (e.g. 0U) It was repaired by defining a static size_t const zero = 0; bobcat (2.00.0) * Upgrading to version 2.00.0 as many classes have over time received API and ABI changes. * Repaired flaws in and extended/rebuilt the class DateTime. Consult its man-page for the current API. * Deprecated members from other classes (see bobcat's 1.21.1 changelog) were removed. * `build install' no longer zip-compresses the html versions of the man pages, as per the Debian debhelper dh_compress man page. * Hm.... ArgConfig was added to the source tree in 1.21.1, but apparently I forgot to add it to the library. Now repaired. bobcat (1.21.1) * Several man-pages were updated/modified (Config, Log, Process, User, X2a) * ConfigFile: added `std::string const &operator[](size_t idx) const' to the interface offering a basic protection against accidentally modifying the configuration file's lines by clients; added member std::string findKeyTail(std::string key, size_t idx = 1) returning the contents beyond key of the idx-th line containing key. * Process: this class received an extensive overhaul resulting in multiple new members. See the Process man-page for details. Several of its former constructors and members are now deprecated and will be removed in a future release. Existing sources defining Process objects and the shared Bobcat library must be recompiled as the data member organization of Process has substantially been changed. Again consult the Process man-page for details. * Msg: added member open(ofstream &out, std::string const &name, size_t protection) opening an ofstream using a specified protection mode. * DateTime: TriVal's UNKNOWN value was changed; rfc2822() now correctly represents the difference between UTC and local time, allowing for DST. * The deprecated Arg::getInstance() member was removed. Arg::instance() should be used instead. * Added the new class ArgConfig combining the facilities of the Arg and Config classes. -- Frank B. Brokken Sun, 26 Oct 2008 15:46:42 +0100 bobcat (1.20.1) * Removed left-over cout stmnts from DateTime members bobcat (1.20.0) * Removed deprecated members from String, removed the std::string base class from String * Moved inline private members to their internal header files where possible. Users of those classes will never need these inline members, so they can be used from the class interface, thus speeding up compilations. * Removed exception thrown from constructors of the following classes: Arg, Glob, OneKey, Pipe, ServerSocket, SocketBase, User, Xpointer Except for the classes Arg and ServerSocket these classes now define a public member 'verify()' which should be called following the construction of objects of these classes before using any other of their members. The verify() member throws the Errno exception if the object could not properly be constructed. As a safeguard verify() is also called from the classes' destructors, but in some programs that might be rather late, causing surprise for the program's users. The man-pages are updated accordingly. EXISTING PROGRAMS using the classes Arg, Glob, OneKey, Pipe, SocketBase, or User should be recompiled, as the data-organization of objects of these classes has changed. Xpointer's data organization was not altered. To find all source (text) files using the above classes the script scripts/check1.20.0 could be used. * Added missing namespace declarations to glob/driver/driver.cc * Repaired reporting the argv-argument before an undefined option instead of the undefined option itself as in, e.g., tmp/bin/xd --verbose -tm ArgData::ArgData(): unknown option: --verbose or: tmp/bin/xd -tm ArgData::ArgData(): unknown option: tmp/bin/xd * Removed 'throw()' lists from various functions and man-pages (except from several Errno members, as their throw() lists are required by Errno's std::exception base class * Removed inline in inline virtual ~Errno() (needed because of a previous bug in g++, which has now been repaired) * Added missing mode() and specialMode() functions to Stat, and added info to the stat manpage indicating what fields of the 'struct stat' are returned by specific accessor members. * Added DayTime::setWeekday() member to DateTime to alter dates based on the day of the week. DateTime's man-page adapted accordingly. bobcat (1.19.0) * Added the template function binary_search that returning iterator to the location of a found element rather than a bool value (as returned by the std::binary_search algorithm) telling its caller whether the searched for element is present or not * The Process class was given additional functionality allowing better control over the way child processes are started and the Process man-page was updated accordingly * The description of the member `header()' in the man-page of the class Milter was improved * CGI's man-page now contains a common organization of a program using a CGI object bobcat (1.18.1) * Repaired a flaw in Pattern due to which a segfault could occur becasue of a failure to initialize the Finite State Automaton processing Perl-like character-set abbreviations. Also the HANDLING OF BACKSLASHES by Pattern objects was modified: to specify a literal backslash is must now be specified twice. NOTE that this change *may* require some maintenance of patterns that were hard-coded in programs already using the Pattern class. See the `pattern' man-page for details. * Removed all left-over redundant include guards * Renamed all identifiers (macro defines, etc.) that started with _ into names not starting with _. This only affects include-guard identifiers and symbols used internally, so programs using Bobcat should not be affected by this modification. * Added the files README.X11 and README.milter * Several members of FBB::State were not documented in the bobcat/stat man-page: missing documentation is now included (TODO). * Added the class CGI processing forms submitted using the Common Gateway Interface * Added for_each() and repeat() function templates (and their man-pages) * Reorganized the main bobcat man-page, adding a categorization of Bobcat's classes bobcat (1.17.2) * Arg's constructors changed in accordance with the new (?) getopt() function: missing option arguments are now properly recognized and no longer confused with `unknown options' * The Table man-page incorrectly listed `Table const &' as its second argument. The modifier `const' is incorrect as the insertion may imply the addition of empty elements to the table in order to make it rectangular. The `const' modifier was removed from the man-page. bobcat (1.17.1) * Removed Wrap* wrappers from Bisonc++. Use FnWrap* instead. * Added member rfc2822() to DateTime returning the time according to RFC 2822 (e.g., as displayed by the `date -R' command. * Partial construction and installation of the Bobcat library is now supported via #defines in INSTALL.im * Minor modifications to satify g++4-3's #include requirements * TEMPORARILY suppressed the `deprecated header warning' resulting from using ext/hash_map in bobcat/hash. The fix is a kludge: the warning is suppressed by defining the backward warning include guard identifier just prior to including ext/hash_map and by undefining it thereafter. bobcat (1.17.0) * Repaired double free bug in Pattern * Changed the implementation and interface of MailHeaders. See 'man -e bobcat mailheaders' for details * Process::init() member removed. setCommand() added, and constructors no longer call the process start() member. They shouldn't as start() forks, and forking an object that isn't constructed yet seems to be inappropriate. The open() call in init() is now placed in start(). Therefore the correct sequence becomes: Process(), start(), ...(insert/extract)..., stop(). Process::operator=() now performs: stop(), setCommand(), start(). Multiple stops() could be given, so ... stop(), operator=(), ... is acceptable. The Process man-page is updated accordingly. * The DateTime class has been enlarged. It now contains members to reassign individual time components as well as members to compare the (in)equality of the times represented by two DateTime objects. Trailing \n is not inserted anymore if a DateTime object is inserted into an ostream. Operators +, -, += and -= for DateTime rvalues removed, since a date is an interval scaled data type. It is, however, possible to add or subtract seconds (or even struct tm structs) and to add/set values to individual DateTime components. * Implemented lastFail() members in A2x and X2a. See the respective man-pages. bobcat (1.16.1) * The `build' script `library' command bow has an additional optional argument `strip' to strip the shared library. By default the library is not stripped. bobcat (1.16.0) * Leftover `String' in string/unescape replaced by `std::string'. * Added missing A2x.to() member template to A2x (cf. C++ Annotations). bobcat (1.15.0) * The Glob constructor no longer requires a static_cast when multiple flags are specified for its second argument. * The TableSupport class's vline(col) member now writes separator[col] to the output stream if it is available. If it is not available, no action is performed. Similarly, vline() now writes the trailing separator as well as a newline character. This is a more natural default behavior of TableSupport. * The Milter class interface was adapted to libmilter-dev 8.14.1-2, affecting milter/milter and milter/initialize.cc. bobcat (1.14.2) * Added (still) missing headers to glob.ih, log.ih and tablesupport.ih required for proper compilation with g++ 4.3 * The ServerSocket is created with the option SO_REUSEADDR, allowing servers to be restarted immediately following a shutdown of the server. -- Frank B. Brokken Fri, 13 Apr 2007 12:05:11 +0200 bobcat (1.14.1) * Member function template implementations consisting of a single line of code were given the `inline' specification. * The classes Table and TableSupport were redesigned. Their public and protected interfaces changed substantially. * Classes TableSpec, EqualWidth and ColumnWidth were developed for use with the Table class only. They are obsolete and were removed from the Bobcat library. * Added a new class Align allowing users to specify alignment of columns or elements of Table objects. * Added a support script contrib/c_conf contributed by Karel Kubat (karel at e dash unity dot org) * Included several missing header files fixing gcc/g++ 4.3 problems -- Frank B. Brokken Wed, 28 Mar 2007 14:22:16 +0200 bobcat (1.13.1) * All function/member/constructor throw() specifications removed, following Sutter & Alexandrescu's suggestions (except where required by external classes, like std::exception. * RefCount's header missed `public:'. Repaired, thus making relase() et al. public members, conform the RefCount manual page. * Added template class `AutoPtr' * Added template classes FnWrap1, FnWrap1c, FnWrap2, FnWrap2c, obsoleting Wrap1, Wrap1c, Wrap2, Wrap2c. Classes previously depending on the Wrap* classes were modified accordingly: they now use FnWrap* bobcat (1.12.1) * inline virtual destructors have an explicit `inline' mentioned in their class interfaces to prevent compilation problems caused by a small g++ (4.1.2) bug. -- Frank B. Brokken Thu, 30 Nov 2006 13:26:52 +0100 bobcat (1.12.0) * All classes have their inline-functions moved out of the interface. They are now implemented inline below the interface itself. X2a now has a copy constructor and an overloaded assignment operator A2x now has a copy constructor (which was announced in the man-page, but was never implemented). Table's functionality has been enlarged. Consult its manpage for details Redirector's `accessVia' member is now deprecated. Instead `swallow' should be used. The String class's object member functions are now deprecated. Instead static member functions have been defined offering the same functionality. -- Frank B. Brokken Wed, 15 Nov 2006 19:25:49 +0100 bobcat (1.11.0) * The classes Wrap1c, Wrap2 and Wrap2c were fully generalized, now accepting any combination of reference, pointer, const reference or const pointer argument types for both the function called from their operator()() function call operator and (with Wrap1c and Wrap2c) the local context struct. Since this results in an extension of the class's API, I upgraded to the next subversion. Since the Wrap* classes are templated classes, the library hasn't changed, and all programes previously compiled against libbobcat1 should continue to run without any required maintenance. The man-pages were updated accordingly. The icmake-script was updated so that it runs on both icmake 6.xx and the upcoming icmake 7.xx release. Started to move inline definitions of members to below the class interface. Done for a2x and datetime. -- Frank B. Brokken Sat, 14 Oct 2006 14:47:37 +0200 bobcat (1.10.2) * Andreas Jochens noted a build-problem for xpointer/get.cc on amd architectures and kindly provided a patch changing the definition size_t keys into unsigned int keys. His patch was applied to this bobcat version. * Added the file README.optimization describing why the compiler option -O3 is used. * INSTALL.im redefines default DOC and DEVDOC locations to, resp. BASE = "/usr"; DOC = BASE + "/share/doc/libbobcat1"; DOCDEV = BASE + "/share/doc/libbobcat1-dev"; * Removed installation of `lintian overrides' from icmake/install -- Frank B. Brokken Thu, 31 Aug 2006 15:18:45 +0200 bobcat (1.10.1) * Some leftover Academic Free License references were replaced by GPL references. The previously used scripts below make/ are obsolete and were removed from this and future distributions. Icmake should be used instead, for which a top-level script (build) and support scripts in the ./icmake/ directory are available. Icmake is available on a great many architectures. See the file INSTALL (and INSTALL.im, replacing the previously used INSTALL.cf) for further details. Various source adaptations were realized (SF: superfluous): All plain `unsigned' variables were changed to `size_t' datetime: changed include time.h into include ctime removed SF include iostream from datetime/operatorminusis2.cc datetime/operatorminusis3.cc datetime/operatorminusis.cc datetime/operatorplusis2.cc datetime/operatorplusis3.cc fork: changed int d_pid into pid_t pid, various files, manpage adapted gethostent: changed `hostent *' into `struct hostent *' in gethostent.cc iostream: removed SF #include iostream from clear1.cc localclientsocket/localclientsocket: datamember SF localclientsocket/localclientsocket.ih: added includes for connect(2) localserversocket/localserversocket.ih: updated required includes mailheaders/read.cc: removed SF include iostream multistreambuf/multistreambuf: removed SF include iostream pattern/convert.cc: removed SF includes iostream and iomanip process/parentredirections.cc,stop.cc: removed SF include iostream selector/selector: including sys/select.h according to POSIX rather than includes using earlier standards. -- Frank B. Brokken Tue, 26 Jul 2006 18:16:42 -0800 bobcat (1.10.0-1) unstable; urgency=low * License changed to the GNU GENERAL PUBLIC LICENSE. See the file `copyright'. Introduced George Danchev as uploader CmdFinder now properly clears beyond() when using mode USE_FIRST From now on this file will contain the `upstream' changes. The Debian related changes are in changelog.Debian.gz -- Frank B. Brokken Tue, 18 Jul 2006 21:38:21 +0200 bobcat (1.9.0) unstable; urgency=low * Following suggestions made by George Danchev, this version was compiled by the unstable's g++ compiler (version >= 4.1), which unveiled several flaws in the library's class header files. These flaws were removed (i.e., repaired). In order to facilitate compiler selection, the compiler to use is defined in the INSTALL.cf file. The debian control-files (i.e., all files under the debian subdirectory) were removed from the source distribution, which is now also named in accordance with the Debian policy. A diff.gz file was added. At the contents level: the class ConfigFile was extended with two overloaded members index(), returning line offset of the original configuration file associated with a particular line that may be retrieved from the ConfigFile object itself. -- Frank B. Brokken Tue, 4 Jul 2006 21:17:56 +0200 bobcat (1.8.0) unstable; urgency=low * make/install script slightly modified: header files are copied before the compilation starts to prevent unavailable header files. Added the following classes: * CmdFinder and CmdFinderBase: CmdFinder is a class handling command-lookup and command-function associations * OneKey: Objects of the class OneKey allow single-keystroke input (not requiring `Enter' to be pressed. * RefCount: Base class allowing its derived classes to share their memory, using reference counting. Modified the layout and contents of the file README.class-setup to improve the current class organization's representation. -- Frank B. Brokken Mon, 26 Jun 2006 08:42:18 +0200 bobcat (1.7.1) unstable; urgency=low * Bobcat now `lintianized'. The libraries are now in the libbobcat1 and libbocat1-dev packages. The package's info has been upgraded. Note that packages depending on bobcat (e.g., stealth and bisonc++) require an upgrade as well. -- Frank B. Brokken Fri, 26 May 2006 15:02:22 +0200 bobcat (1.7.0) unstable; urgency=low * milter and xpointer are included optionally. `make/library all' includes them automatically New class Indent and associated manipulators implementing indentation defined. ofdstreambuf and ifdstreambuf constructors have additional parameters to either close or keep open the file descriptor that is passed to the constructor. The default situation is for ofdstreambuf to close the file descriptor and for ifdstreambuf to keep de file descriptor open. Thus the new implementation is backward compatible with earlier bobcat versions. Msg has a new free function msgstream() returning the not-cleared msg() stream. This allows certain STL algorithms to be used, see `man -e bobcat msg' wrap1c and wrap2c now also accept const contexts; see, e.g., `man -e bobcat wrap1c'. Errors in wrap2c's template definition repaired. ConfigFile now has additional members beginRE() and endRE(), allowing iterators to produce all lines matching a RE. Repaired ConfigFile in accordance with the man-page: initial ws are now removed from the stored lines, find(target): `target' may be found anywhere within a configuration line. -- Frank B. Brokken Tue, 2 May 2006 19:31:02 +0200 bobcat (1.6.0) unstable; urgency=low * minor repair in Pattern- and Selector manpages added MultiStrambuf, IOStreambuf, IOStream: see the manpages for details. redesigned Process: insertions insert to the child process, extractions extract from the child process. STDOUT and STDERR can or cannot be merged. See the man-page for details. redesigned Arg: same functionality as before, but allows for multiple specifications of options, also those having arguments. When multiple options having arguments are specified, each individual argument is retrievable. added string::escape() `get...' accessors removed from all classes, (Arg, Fork and Pipe) Old names are kept for the time being. -- Frank B. Brokken Mon, 26 Dec 2005 19:04:24 +0100 bobcat (1.5.0) unstable; urgency=low * The general bobcat manpage did not have links to wrap1c and wrap2c. Now Repaired. The Log-class interface is modified. See the man -e bobcat log manpage for details. The main difference is that a static initialize() member is now used to define the static Log-object. Also, logs may be written to stdout using a simpler specification than before. The Log class also supports an open() member, allowing you to open a local Log object after its construction. Added the class Milter, offering a C++ interface to the (sendmail) libmilter API. This class uses the `virtual constructor' Design Pattern to prevent the need for saving and accessing private connection based data using the libmilter api smfi_setpriv() and smfi_getpriv(). See `man -e bobcat milter' for details. Added the class Xpointer, setting and retrieving the X-windows pointer coordinates. With the shared object library, functions from both libmilter and libX11 must be available before a program can be fully linked. To prevent unnessary linking to these libraries, required dummy C functions were added to the bobcat library. When using libmilter and/or libX11, that these libraries should be mentioned to the linker before libbobcat. -- Frank B. Brokken Thu, 8 Dec 2005 20:52:44 +0100 bobcat (1.4.0) unstable; urgency=low * 1.4.0 and beyond: compiled with g++-4.0 compiler series. Minor modifications in the log/log and level/level header files: ::operator<<() changed into operator<<() Further support of the 1.2.x series is discontinued -- Frank B. Brokken Fri, 18 Nov 2005 21:44:13 +0100 bobcat (1.2.1) unstable; urgency=low * added missing constructor description in the Pattern manpage removed leftover cerr insertion from localserversocket::listen() defined default localsocketbase constructor. added /bobcat/localsocketbase/open.cc defined default localserversocket constructor. removed /bobcat/localserversocket/localserversocket1.cc added /bobcat/localserversocket/open.cc defined default localclientsocket constructor. defined LocalClientSocket::open() Pattern missed some throwlists in its implementations. Repaired. -- Frank B. Brokken Thu, 17 Nov 2005 14:05:26 +0100 bobcat (1.2.0) unstable; urgency=low * Added the following classes: localsocketbase - base class for unix domain sockets localserversocket - defines server for unix domain sockets localclientsocket - defined client for unix domain sockets randbuffer - std::streambuf producing random numbers irandstream - istream producing random numbers mailheaders - handles SMTP mail message headers Repaired incorrect header inclusion in datetime. -- Frank B. Brokken Fri, 11 Nov 2005 16:47:31 +0100 bobcat (1.1.2) unstable; urgency=low * Repaired -I statement in make/parameters, and changed tmp/inc into tmp/bobcat (repairs resulting from feedback by Vincent Hecht) Changed the ordering of the classes tablesupport and tablespec in CLASSES -- Frank B. Brokken Thu, 8 Sep 2005 19:40:43 +0200 bobcat (1.1.1) unstable; urgency=low * Removed the compilation dependency on `icmake'. See INSTALL for instructions about how to compile and install bobcat yourself, rather than using the binary distribution -- Frank B. Brokken Sat, 3 Sep 2005 16:47:24 +0200 bobcat (1.1.0) unstable; urgency=low * Added the following classes: FBB::ClientSocket: a socket for tcp-communication with a server. FBB::columnWidth: Manipulator class for the class Table. FBB::DateTime: Manipulations with date and time values. FBB::equalWidth: Manipulator class for the class Table. FBB::GetHostent: Obtains hostent struct from hostname or -address. FBB::Glob: Obtain a list of files matching a certain pattern. FBB::Hostent: Wrapper around the hostent struct. FBB::Hostname: Derived from Hostent, allows the initialization from a FBB::IFdStream: stream extracting information from a device whose file FBB::IFdStreambuf: Input stream buffer initialized by a file descrip- FBB::InetAddress: Base class (no public constructor) for objects repre- FBB::level: Manipulator setting the log-level of FBB::Log objects. FBB::Log: std::ostream handling log messages. FBB::LogBuffer: std::streambuf handling log messages. FBB::OFdStream: stream inserting information into a device whose file FBB::OFdStreambuf: Output stream buffer initialized by a file descrip- tor. FBB::Process: Runs child processes, piping output to parents. FBB::ServerSocket: defines a socket to which clients can connect. FBB::SocketBase: Base class for ClientSocket and ServerSocket. FBB::Stat: Determines file characteristics. FBB::Syslogbuf: streambuf to Buffer generating syslog(3) messages. FBB::SyslogStream: stream to Output stream inserting syslog(3) mes- sages. FBB::Table: Display tables row- or column-wise. FBB::TableSpec: Base class for the class Table. FBB::TableSupport: Support class for the class Table. FBB::User: Determines the current user's parameters from /etc/passwd. Added an examples directory under /usr/share/doc/bobcat-dev Added a contrib directory under /usr/share/doc/bobcat-dev, currently containing the `solib' script making shared libraries o The minor release number will be incremented when new information (classes, documentation, etc.) is added, o The subrelease number will be incremented at bugfixes. o I don't know yet when I'll upgrade the major release number -- Frank B. Brokken Wed, 31 Aug 2005 12:57:03 +0200 bobcat (1.0.0-1) unstable; urgency=low * Initial Release. -- Frank B. Brokken Mon, 15 Aug 2005 11:32:09 +0200 bobcat-5.09.01/cidr/0000755000175000017500000000000014050437223013025 5ustar frankfrankbobcat-5.09.01/cidr/cidr2.cc0000644000175000017500000000011214050437223014331 0ustar frankfrank#include "cidr.ih" Cidr::Cidr(istream &fin) { setCidr(fin); } bobcat-5.09.01/cidr/cidr3.cc0000644000175000017500000000025014050437223014335 0ustar frankfrank#include "cidr.ih" Cidr::Cidr(Cidr &&tmp) : d_cidr(move(tmp.d_cidr)), d_iter(move(tmp.d_iter)), d_matched(move(tmp.d_matched)), d_last(tmp.d_last) {} bobcat-5.09.01/cidr/compare.cc0000644000175000017500000000110614050437223014760 0ustar frankfrank#include "cidr.ih" bool Cidr::compare(MaskPair const &mp, string const &address) { size_t binary = dotted2binary(address); // ~0: all 1s, // << moves in 0s over the masked bits // ~() toggles 1s/0s // | sets the masked bits to 1 in last. size_t last = mp.first | ~(~0 << (32 - mp.second)); if (mp.first <= binary && binary <= last) { d_matched = address; d_last = last; return true; } return false; } bobcat-5.09.01/cidr/match2.cc0000644000175000017500000000013114050437223014505 0ustar frankfrank#include "cidr.ih" bool Cidr::match(string const &line) { return matchLine(line); } bobcat-5.09.01/cidr/match1.cc0000644000175000017500000000054314050437223014513 0ustar frankfrank#include "cidr.ih" bool Cidr::match(istream &in) { auto end = istream_iterator(); return end != find_if( istream_iterator(in), end, [this](string const &line) { return this->matchLine(line); } ); } bobcat-5.09.01/cidr/parse.cc0000644000175000017500000000114614050437223014450 0ustar frankfrank#include "cidr.ih" Cidr::MaskPair Cidr::parse(string const &cidr) { static Pattern sl_empty("^\\s*(#.*)?$"); MaskPair ret {0, 0}; if (sl_empty << cidr) // empty line or comment return ret; ret = MaskPair{dotted2binary(cidr), 32}; size_t pos = cidr.find_first_of('/'); if (pos != string::npos) try { ret.second = stoul(cidr.substr(pos + 1)); ret.first = ret.first >> (32 - ret.second) << (32 - ret.second); } catch (...) { throw Exception{1} << "Cidr: " << "invalid CIDR: `" << cidr << '\''; } return ret; } bobcat-5.09.01/cidr/last.f0000644000175000017500000000011414050437223014133 0ustar frankfrankinline std::string Cidr::last() const { return binary2dotted(d_last); } bobcat-5.09.01/cidr/first.f0000644000175000017500000000012414050437223014320 0ustar frankfrankinline std::string Cidr::first() const { return binary2dotted(d_iter->first); } bobcat-5.09.01/cidr/mask.f0000644000175000017500000000014114050437223014123 0ustar frankfrankinline std::string Cidr::mask() const { return std::to_string(d_iter->second); // X2a } bobcat-5.09.01/cidr/dotted2binary.cc0000644000175000017500000000071214050437223016106 0ustar frankfrank#include "cidr.ih" size_t Cidr::dotted2binary(std::string const &dotted) { size_t ret = 0; istringstream in(dotted); for (size_t idx = 0; idx != 4; ++idx) { size_t byte; if (!(in >> byte)) throw Exception{1} << "Cidr: " << "invalid address: `" << dotted << '\''; ret <<= 8; ret += byte; in.ignore(); } return ret; } bobcat-5.09.01/cidr/binary2dotted.cc0000644000175000017500000000042414050437223016106 0ustar frankfrank#include "cidr.ih" string Cidr::binary2dotted(size_t binary) { ostringstream out; out << (binary >> 24 & 0xff) << '.' << (binary >> 16 & 0xff) << '.' << (binary >> 8 & 0xff) << '.' << (binary & 0xff); return out.str(); } bobcat-5.09.01/cidr/pushcidr.cc0000644000175000017500000000024414050437223015155 0ustar frankfrank#include "cidr.ih" void Cidr::pushCidr(string const &cidrPattern) { MaskPair spec = parse(cidrPattern); if (spec.second) d_cidr.push_back(spec); } bobcat-5.09.01/cidr/setcidr2.cc0000644000175000017500000000061014050437223015050 0ustar frankfrank#include "cidr.ih" void Cidr::setCidr(istream &fin) { d_cidr.clear(); for (auto &cidrPattern: ranger( istream_iterator(fin), istream_iterator()) ) pushCidr(cidrPattern); if (d_cidr.empty()) throw Exception{1} << "Cidr: " << "no CIDR patterns found on " "cidr-specifications stream"; } bobcat-5.09.01/cidr/cidr1.cc0000644000175000017500000000013614050437223014336 0ustar frankfrank#include "cidr.ih" Cidr::Cidr(std::string const &cidrPattern) { pushCidr(cidrPattern); } bobcat-5.09.01/cidr/cidr0000644000175000017500000000467214050437223013702 0ustar frankfrank#ifndef _INCLUDED_BOBCAT_CIDR_ #define _INCLUDED_BOBCAT_CIDR_ #include #include #include //#include namespace FBB { class Pattern; class Cidr { typedef std::pair MaskPair; // 1st address, mask value typedef std::vector VectorMaskP; VectorMaskP d_cidr; VectorMaskP::const_iterator d_iter; std::string d_matched; // address matched last size_t d_last; // last address in CIDR public: Cidr() = default; Cidr(std::string const &cidrPattern); // 1 one pattern to check Cidr(std::istream &cidrStream); // 2 stream of patterns Cidr(Cidr &&tmp); // 3 Cidr &operator=(Cidr const &rhs) = default; Cidr &operator=(Cidr &&tmp); void swap(Cidr &rhs); // all lines of 'in' are inspected for ip addresses matching // any cidr-specification in d_cidr bool match(std::istream &in); // 1 true means: match found bool match(std::string const &line); // 2 match a single line void setCidr(std::string const &cidrPattern); // 1 void setCidr(std::istream &cidrStream); // 2 // following a successful match the following members return // dotted decimal addresses / maskvalues as strings std::string cidr() const; // CIDR containing address() std::string const &address() const; // .f the address matching a CIDR std::string mask() const; // .f the mask used by cidr() std::string first() const; // .f the 1st address in cidr() std::string last() const; // .f the last address in cidr() // convert "a.b.c.d" to // 32-bits value static size_t dotted2binary(std::string const &dotted); // reverse operation static std::string binary2dotted(size_t binary); private: bool matchLine(std::string const &line); MaskPair parse(std::string const &cidrPattern); void pushCidr(std::string const &cidrPattern); bool compare(MaskPair const &mp, std::string const &address); }; #include "address.f" #include "mask.f" #include "first.f" #include "last.f" } // namespace FBB #endif bobcat-5.09.01/cidr/operatorassign.cc0000644000175000017500000000016314050437223016374 0ustar frankfrank#include "cidr.ih" #include "../iuo/iuo" Cidr &Cidr::operator=(Cidr &&tmp) { swap(tmp); return *this; } bobcat-5.09.01/cidr/swap.cc0000644000175000017500000000012514050437223014304 0ustar frankfrank#include "cidr.ih" void Cidr::swap(Cidr &rhs) { fswap(*this, rhs, d_matched); } bobcat-5.09.01/cidr/matchline.cc0000644000175000017500000000151514050437223015302 0ustar frankfrank#include "cidr.ih" // Here we get one line, and want to obtain all its elements matching // the pattern. // Return true once a match is found, else false bool Cidr::matchLine(string const &line) //, Cidr &cidr) { static Pattern sl_pattern("\\b\\d+\\.\\d+\\.\\d+\\.\\d+\\b"); string inspect(line); auto end = d_cidr.end(); while (sl_pattern << inspect) // find the first match in 'inspect' { string const &matched = sl_pattern.matched(); d_iter = find_if( d_cidr.begin(), end, [&, this](MaskPair const &mp) { return this->compare(mp, matched); } ); if (d_iter != end) return true; inspect = sl_pattern.beyond(); } return false; } bobcat-5.09.01/cidr/setcidr1.cc0000644000175000017500000000017314050437223015053 0ustar frankfrank#include "cidr.ih" void Cidr::setCidr(std::string const &cidrPattern) { d_cidr.clear(); pushCidr(cidrPattern); } bobcat-5.09.01/cidr/cidr.ih0000644000175000017500000000044714050437223014275 0ustar frankfrank#include "cidr" #include #include #include #include #include "../stringline/stringline" #include "../pattern/pattern" #include "../fswap/fswap" #include "../ranger/ranger" #include "../exception/exception" using namespace std; using namespace FBB; bobcat-5.09.01/cidr/address.f0000644000175000017500000000011214050437223014613 0ustar frankfrankinline std::string const &Cidr::address() const { return d_matched; } bobcat-5.09.01/cidr/driver/0000755000175000017500000000000014050437223014320 5ustar frankfrankbobcat-5.09.01/cidr/driver/build0000755000175000017500000000112214050437223015341 0ustar frankfrank#!/bin/bash ln -sf ../cidr . ln -sf ../cidr.ih . case $1 in (b) rm cidr cidr.ih g++ -DBOBCAT `cat ../../c++std` -I../../tmp -o driver driver.cc \ -lbobcat -L../../tmp/lib -s ;; (o) g++ `cat ../../c++std` -o driver *.cc ../tmp/o/*.o -lbobcat -s ;; (c) g++ `cat ../../c++std` -o driver *.cc -lbobcat -s ;; (*) echo $0 b links to bobcat built by 'build libraries all' echo $0 o links to the files in ../tmp/o echo $0 c links to the files in the current dir only rm -f driver ;; esac rm -f cidr cidr.ih bobcat-5.09.01/cidr/driver/driver.cc0000644000175000017500000000437514050437223016133 0ustar frankfrank #include #include #include #ifdef BOBCAT #include #else #include "cidr" #endif using namespace std; using namespace FBB; int main(int argc, char **argv) { enum Spec { NONE, FILE, CIN }; Spec spec = CIN; ifstream in; if (argc > 1) { Exception::open(in, argv[1]); // file containing cidr-specs spec = FILE; } while (true) { string cidrSpec; if (spec == CIN) { cout << "Specify cidr (empty to quit): "; if (!getline(cin, cidrSpec) || cidrSpec.empty()) break; } try { Cidr cidr; switch (spec) { case NONE: return 0; case FILE: cidr.setCidr(in); spec = NONE; break; case CIN: cidr.setCidr(cidrSpec); } while (true) { cout << "Specify address to test (empty to " << (spec == CIN ? "respec. CIDR" : "quit") << "): "; string address; if (!getline(cin, address) || address.empty()) break; if (!cidr.match(address)) { cout << "Address " << address << " not in "; if (spec == CIN) cout << cidrSpec << '\n'; else cout << "specifications in " << argv[1] << '\n'; } else cout << "Address " << address << " in " << cidr.cidr() << "\n" "Lowest address: " << cidr.first() << "\n" "Highest address: " << cidr.last() << "\n" "CIDR mask: " << cidr.mask() << "\n" "Address: " << cidr.address() << '\n'; } } catch (exception const &err) { cout << "Oops... " << err.what() << "\n" "Try again...\n"; } } } bobcat-5.09.01/cidr/driver/cidrspecs0000644000175000017500000000017714050437223016227 0ustar frankfrank 1.2.3.4/8 # a line with comment 129.125.1.1/16 192.168.1.1/16 Private range (remaining info on a line is ignored). bobcat-5.09.01/cidr/cidr.cc0000644000175000017500000000024114050437223014252 0ustar frankfrank#include "cidr.ih" string Cidr::cidr() const { ostringstream out; out << binary2dotted(d_iter->first) << '/' << d_iter->second; return out.str(); } bobcat-5.09.01/cininserter/0000755000175000017500000000000014050437223014431 5ustar frankfrankbobcat-5.09.01/cininserter/parentprocess.cc0000644000175000017500000000010014050437223017617 0ustar frankfrank#include "cininserter.ih" void CinInserter::parentProcess() {} bobcat-5.09.01/cininserter/execute1.cc0000644000175000017500000000034314050437223016463 0ustar frankfrank#include "cininserter.ih" void CinInserter::execute(string const &cmd) { stop(); // stop any previously running child d_oChildInPipe = Pipe{}; Exec::execute(cmd); d_stopped = false; } bobcat-5.09.01/cininserter/stop.cc0000644000175000017500000000023514050437223015725 0ustar frankfrank#include "cininserter.ih" int CinInserter::stop() { if (d_stopped) return ret(); flush(); eoi(); return setRet(waitForChild()); } bobcat-5.09.01/cininserter/cininserter.ih0000644000175000017500000000022714050437223017301 0ustar frankfrank#include "cininserter" #include #include #include #include using namespace std; using namespace FBB; bobcat-5.09.01/cininserter/cininserter2.cc0000644000175000017500000000023314050437223017345 0ustar frankfrank#include "cininserter.ih" CinInserter::CinInserter(StdMode mode, size_t bufSize) : ostream(this), d_bufSize(bufSize), d_modeFun(stdClose) {} bobcat-5.09.01/cininserter/close.cc0000644000175000017500000000043714050437223016051 0ustar frankfrank#include "cininserter.ih" void CinInserter::stdClose() // static { ::close(STDOUT_FILENO); // close and reopen std file descriptors ::close(STDERR_FILENO); ::open("/dev/null", O_RDONLY); // reopen stdout ::open("/dev/null", O_WRONLY); // reopen stderr } bobcat-5.09.01/cininserter/childredirections.cc0000644000175000017500000000016014050437223020433 0ustar frankfrank#include "cininserter.ih" void CinInserter::childRedirections() { d_oChildInPipe.readFrom(STDIN_FILENO); } bobcat-5.09.01/cininserter/parentredirections.cc0000644000175000017500000000027514050437223020650 0ustar frankfrank#include "cininserter.ih" void CinInserter::parentRedirections() { reset(d_oChildInPipe.writeOnly(), OFdBuf::CLOSE_FD, d_bufSize); // open(d_oChildInPipe.writeOnly(), d_bufSize); } bobcat-5.09.01/cininserter/destructor.cc0000644000175000017500000000010714050437223017134 0ustar frankfrank#include "cininserter.ih" CinInserter::~CinInserter() { stop(); } bobcat-5.09.01/cininserter/cininserter0000644000175000017500000000232314050437223016701 0ustar frankfrank#ifndef INCLUDED_BOBCAT_CININSERTER_ #define INCLUDED_BOBCAT_CININSERTER_ #include #include #include #include #include #include #include #include #include #include using namespace std; namespace FBB { class CinInserter: public IUO::CloseMode, private Exec, private OFdBuf, public std::ostream { size_t d_bufSize; Pipe d_oChildInPipe = Pipe{ false }; // cin to be read by the CHILD void (*d_modeFun)(); bool d_stopped = true; public: CinInserter(size_t bufSize = 100); CinInserter(StdMode mode, size_t bufSize = 100); ~CinInserter() override; void execute(std::string const &cmd); bool execute(std::string const &cmd, std::string const &txt); int stop(); using Exec::ret; protected: Pipe &childInPipe(); private: void childRedirections() override; void parentRedirections() override; void parentProcess() override; static void stdClose(); }; inline Pipe &CinInserter::childInPipe() { return d_oChildInPipe; } } // namespace FBB #endif bobcat-5.09.01/cininserter/execute2.cc0000644000175000017500000000031514050437223016463 0ustar frankfrank#include "cininserter.ih" bool CinInserter::execute(string const &cmd, string const &txt) { stop(); d_oChildInPipe = Pipe{}; Exec::execute(cmd); *this << txt; return stop() == 0; } bobcat-5.09.01/cininserter/driver/0000755000175000017500000000000014050437223015724 5ustar frankfrankbobcat-5.09.01/cininserter/driver/build0000755000175000017500000000012314050437223016745 0ustar frankfrank#!/bin/bash g++ -pthread -Wall -odriver driver.cc -L../tmp -lcininserter -lbobcat bobcat-5.09.01/cininserter/driver/driver.cc0000644000175000017500000000136714050437223017535 0ustar frankfrank//#include #include "../cininserter" #include #include using namespace std; using namespace FBB; int main() { CinInserter inserter; inserter.execute("/bin/cat"); ifstream in("build"); inserter << in.rdbuf(); cout << "child returns: " << inserter.stop() << '\n'; inserter.execute("/bin/cat"); in.seekg(0); // reset to the beginning inserter << in.rdbuf(); // when immediately followed by another execute, 'stop' is optional inserter.execute("/bin/cat", "a simple text\n"); inserter.execute("/bin/cat", "a simple text\n"); bool bret = inserter.execute("/bin/cat", "a simple text\n"); cout << "direct string insertion: " << bret << '\n'; } bobcat-5.09.01/cininserter/cininserter1.cc0000644000175000017500000000021414050437223017343 0ustar frankfrank#include "cininserter.ih" CinInserter::CinInserter(size_t bufSize) : ostream(this), d_bufSize(bufSize), d_modeFun(noClose) {} bobcat-5.09.01/CLASSES0000644000175000017500000000221314050437223013122 0ustar frankfrank# Classes compiled from icmake/special: xpointer, milter, ssl, readline a2x align arg argconfig base64bufbase binarysearch binops binopsbase cerrextractor cininserter coutextractor cgi cidr clientsocket cmdfinder cmdfinderbase config configfile csvtabdef csvtabins csvtable csv4180 datetime exception exec extractorbase fbb field fmt fork fswap gethostent glob gs hash hostent hostname ibase64stream ibase64buf ifdstream ifdbuf ifilterbuf indent inetaddress iostream iobuf iquotedprintablestream iquotedprintablebuf irandstream isharedstream iterator iuo level linearmap localclientsocket localserversocket localsocketbase log logbuf mailheaders mbuf mstream multibuf omutexstream ofdstream ofdbuf ofilterbuf ofoldstream ofoldbuf ohexbuf onekey osharedstream pattern pipe process processenums ptriter qpbufbase randbuf ranger redirector repeat selector semaphore serversocket sep sharedblock sharedcondition sharedmemory sharedmutex sharedpos sharedsegment sharedstream sharedbuf signal socketbase stat stdextractor string stringline syslogbuf syslogstream table tablebase tablebuf tablelines tablesupport tempstream tty typetrait user x2a cryptbuf eoibuf eoi bobcat-5.09.01/clientsocket/0000755000175000017500000000000014050437223014573 5ustar frankfrankbobcat-5.09.01/clientsocket/clientsocket0000644000175000017500000000064214050437223017207 0ustar frankfrank#ifndef INCLUDED_BOBCAT_CLIENTSOCKET_ #define INCLUDED_BOBCAT_CLIENTSOCKET_ #include #include namespace FBB { class ClientSocket: public SocketBase { public: // host may be address or name ClientSocket(std::string const &host, uint16_t port); int connect(); // returns fd (socket) to talk to the server }; } // FBB #endif bobcat-5.09.01/clientsocket/clientsocket.ih0000644000175000017500000000024614050437223017606 0ustar frankfrank#include "clientsocket" #include #include #include #include "../exception/exception" using namespace std; using namespace FBB; bobcat-5.09.01/clientsocket/clientsocket1.cc0000644000175000017500000000017214050437223017652 0ustar frankfrank#include "clientsocket.ih" ClientSocket::ClientSocket(string const &host, uint16_t port) : SocketBase(host, port) {} bobcat-5.09.01/clientsocket/connect.cc0000644000175000017500000000033014050437223016527 0ustar frankfrank#include "clientsocket.ih" int ClientSocket::connect() { if (::connect(socket(), sockaddrPtr(), size()) < 0) throw Exception{} << "ClientSocket::connect(): " << errnodescr; return socket(); } bobcat-5.09.01/clientsocket/driver/0000755000175000017500000000000014050437223016066 5ustar frankfrankbobcat-5.09.01/clientsocket/driver/build0000755000175000017500000000017114050437223017112 0ustar frankfrank#!/bin/bash tput clear GPP="g++ `cat ../../c++std`" CMD="$GPP -o client -Wall client.cc -lbobcat -s" echo $CMD $CMD bobcat-5.09.01/clientsocket/driver/client.cc0000644000175000017500000000356414050437223017663 0ustar frankfrank#include #include #include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) try { if (argc == 1) { cerr << "Provide servername and port number\n"; return 1; } size_t port = stoul(argv[2]); ClientSocket client(argv[1], port); int fd = client.connect(); string line; unsigned long addr = const_cast(client).sockaddr_inPtr()-> sin_addr.s_addr; cout << "Connecting to socket " << fd << endl << "address = " << client.dottedDecimalAddress() << ", (" << addr << ")\n" "communication through port " << client.port() << endl; IFdStream in(fd); // stream to read from OFdStream out(fd); // stream to write to unsigned long sPort; in >> sPort; in.ignore(100, '\n'); // get the port used by the server sPort ^= addr; cout << "Server uses port " << sPort << '\n'; while (true) { // Ask for a textline, stop if empty / none cout << "? "; if (!getline(cin, line) || line.length() == 0) return 0; cout << "Line read: " << line << endl; // Return the line to the server out << line.c_str() << endl; cout << "wrote line\n"; // Wait for a reply from the server getline(in, line); cout << "Answer: " << line << endl; } } catch (exception const &err) { cerr << err.what() << "\n" << "Can't connect to " << argv[1] << ", port " << argv[2] << endl; return 1; } bobcat-5.09.01/cmdfinder/0000755000175000017500000000000014050437223014037 5ustar frankfrankbobcat-5.09.01/cmdfinder/cmdfinder1.f0000644000175000017500000000026414050437223016224 0ustar frankfranktemplate CmdFinder::CmdFinder(Entry const *begin, Entry const *end, size_t mode) : CmdFinderBase(mode), d_count(0), d_begin(begin), d_end(end) {} bobcat-5.09.01/cmdfinder/cmdfinder2.f0000644000175000017500000000025514050437223016225 0ustar frankfranktemplate CmdFinder::CmdFinder(CmdFinder &&tmp) : CmdFinderBase(move(tmp)), d_count(tmp.d_count), d_begin(tmp.d_begin), d_end(tmp.d_end) {} bobcat-5.09.01/cmdfinder/swap.f0000644000175000017500000000021014050437223015151 0ustar frankfranktemplate void CmdFinder::swap(CmdFinder &rhs) { CmdFinderBase::swap(rhs); fswap(&d_count, *this, rhs); } bobcat-5.09.01/cmdfinder/match.f0000644000175000017500000000017414050437223015304 0ustar frankfranktemplate inline bool CmdFinder::match(std::string const &key) const { return (this->*d_match)(key); } bobcat-5.09.01/cmdfinder/findcmd.f0000644000175000017500000000115014050437223015607 0ustar frankfranktemplate FP CmdFinder::findCmd(std::string const &cmd) { (this->*d_useCmd)(cmd); // store the cmd to use FunctionPtr fp; MatchKey matchKey(&fp, this); // create an object matching // a cmd with a key // count the number of occurrences d_count = std::count_if(d_begin, d_end, matchKey); return d_count == 1 ? fp // return fp if cmd found : // otherwise return the last fptr (d_end - 1)->second; } bobcat-5.09.01/cmdfinder/cmdfinder0000644000175000017500000000334714050437223015724 0ustar frankfrank#ifndef INCLUDED_BOBCAT_CMDFINDER_ #define INCLUDED_BOBCAT_CMDFINDER_ #include #include #include #include namespace FBB { template class CmdFinder: public CmdFinderBase { size_t d_count; protected: typedef FP FunctionPtr; // define template type // as a named type // elements of the array // of keys/f-ptrs typedef std::pair Entry; private: Entry const *d_begin; Entry const *d_end; protected: CmdFinder(Entry const *begin, Entry const *end, // 1 size_t mode = 0); CmdFinder(CmdFinder &&tmp); // 2 CmdFinder &operator=(CmdFinder const &rhs) = default; CmdFinder &operator=(CmdFinder &&tmp); // opis1 FP findCmd(std::string const &cmd); size_t count() const; void swap(CmdFinder &rhs); private: class MatchKey { FP *d_fp; CmdFinder *d_cmdFinder; public: MatchKey(FunctionPtr *fp, CmdFinder *cmdFinder); // 1 bool operator()(CmdFinder::Entry const &entry); // opfun }; bool match(std::string const &key) const; friend MatchKey; }; #include "cmdfinder1.f" #include "cmdfinder2.f" #include "count.f" #include "findcmd.f" #include "opis1.f" #include "swap.f" #include "match.f" #include "matchkey1.f" #include "opfun.f" } // FBB #endif bobcat-5.09.01/cmdfinder/count.f0000644000175000017500000000013214050437223015332 0ustar frankfranktemplate inline size_t CmdFinder::count() const { return d_count; } bobcat-5.09.01/cmdfinder/opfun.f0000644000175000017500000000031714050437223015336 0ustar frankfranktemplate bool CmdFinder::MatchKey::operator()(CmdFinder::Entry const &entry) { if (!d_cmdFinder->match(entry.first)) return false; *d_fp = entry.second; return true; } bobcat-5.09.01/cmdfinder/matchkey1.f0000644000175000017500000000022214050437223016070 0ustar frankfranktemplate CmdFinder::MatchKey::MatchKey(FunctionPtr *fp, CmdFinder *cmdFinder) : d_fp(fp), d_cmdFinder(cmdFinder) {} bobcat-5.09.01/cmdfinder/opis1.f0000644000175000017500000000017414050437223015243 0ustar frankfranktemplate inline CmdFinder &CmdFinder::operator=(CmdFinder &&tmp) { swap(tmp); return *this; } bobcat-5.09.01/cmdfinder/driver/0000755000175000017500000000000014050437223015332 5ustar frankfrankbobcat-5.09.01/cmdfinder/driver/build0000755000175000017500000000012714050437223016357 0ustar frankfrank#!/bin/sh # g++ driver.cc ../../cmdfinderbase/*.cc -lbobcat g++ driver.cc -lbobcat bobcat-5.09.01/cmdfinder/driver/driver.cc0000644000175000017500000000567414050437223017150 0ustar frankfrank#include #include #include using namespace std; using namespace FBB; // Define a class `Command' in which the array s_action defines the // command-function associations. Command is derived from CmdFinder, // specifying the prototype of the member functions to be called class Command: public CmdFinder { static Entry s_action[]; bool add() const // some member functions { cout << "add called: command was `" << cmd() << "'\n"; if (beyond().length()) cout << "Beyond " << cmd() << " `" << beyond() << "'\n"; return true; } bool error() const { cout << "unrecognized command: `" << cmd() << "' called\n" << count() << " matching alternatives found\n"; return true; } bool quit() const { cout << "quit called: quitting this series\n"; return false; } public: Command(); // Declare the default constructor bool run(std::string const &cmd) // run a command { return (this->*findCmd(cmd))(); // execute the command matching // 'cmd' } }; // Define command-function associations. Note that the last is given an empty // command-text. This is not required, a command text could have been // specified for the last command as well. Command::Entry Command::s_action[] = { Entry("add", &Command::add), Entry("quit", &Command::quit), Entry("", &Command::error), }; // Define the default constructor Command::Command() // Define the default constructor : // Note the use of `FunctionPtr' CmdFinder(s_action, s_action + sizeof(s_action) / sizeof(Entry)) {} void run(Command &cmd, char const *descr, size_t mode = 0) { if (mode) cmd.setMode(mode); cout << "Enter 5 x a command using " << descr << ".\n"; for (size_t idx = 0; idx++ < 5; ) { cout << "Enter command " << idx << ": "; string text; getline(cin, text); if (!cmd.run(text)) // run a command break; } } int main() { Command cmd; // define a command // enter 5 commands using the default mode run (cmd, "the default mode"); run (cmd, "abbreviated commands", Command::UNIQUE); run (cmd, "abbreviated case-insensitive commands", Command::UNIQUE | Command::INSENSITIVE); run (cmd, "abbreviated command lines", Command::USE_FIRST | Command::UNIQUE); run (cmd, "abbreviated case-insensitive command lines", Command::USE_FIRST | Command::UNIQUE | Command::INSENSITIVE); } bobcat-5.09.01/cmdfinderbase/0000755000175000017500000000000014050437223014672 5ustar frankfrankbobcat-5.09.01/cmdfinderbase/index2.f0000644000175000017500000000015614050437223016234 0ustar frankfrankinline size_t ConfigFile__::index(const_iterator const &iterator) { return d_index[iterator - begin()]; } bobcat-5.09.01/cmdfinderbase/findkeytail.f0000644000175000017500000000023114050437223017340 0ustar frankfrankinline string ConfigFile__::findKeyTail(string const &keyPattern, size_t count) { return searchFor("^\\s*" + keyPattern + "\\s+(.*)\\s*$", count); } bobcat-5.09.01/cmdfinderbase/index1.f0000644000175000017500000000012114050437223016223 0ustar frankfrankinline size_t ConfigFile__::index(size_t lineNr) { return d_index[lineNr]; } bobcat-5.09.01/cmdfinderbase/usefirstcmd.cc0000644000175000017500000000044214050437223017531 0ustar frankfrank#include "cmdfinderbase.ih" void CmdFinderBase::useFirstCmd(std::string const &cmd) { istringstream in(cmd); d_beyond.erase(); // clear any old remaining `beyond' info in >> d_cmd >> d_beyond; string trailer; getline(in, trailer); d_beyond += trailer; } bobcat-5.09.01/cmdfinderbase/opindex.f0000644000175000017500000000014114050437223016503 0ustar frankfrankinline std::string const &ConfigFile__::operator[](size_t idx) const { return d_line[idx]; } bobcat-5.09.01/cmdfinderbase/finder.f0000644000175000017500000000020514050437223016305 0ustar frankfrankinline bool ConfigFile__::finder(string const &haystack, string const &needle) { return haystack.find(needle) != string::npos; } bobcat-5.09.01/cmdfinderbase/endre.f0000644000175000017500000000017214050437223016136 0ustar frankfrankinline ConfigFile__::const_RE_iterator ConfigFile__::endRE() const { return RE_iterator(d_vsIter, d_vsIter.size()); } bobcat-5.09.01/cmdfinderbase/setsearchcasing.f0000644000175000017500000000016414050437223020210 0ustar frankfrankinline void ConfigFile__::setSearchCasing(SearchCasing type) { d_caseSensitive = type == SearchCaseSensitive; } bobcat-5.09.01/cmdfinderbase/casefinder.f0000644000175000017500000000027214050437223017145 0ustar frankfrankinline bool ConfigFile__::casefinder(string const &haystack, string const &needle) { return strcasestr(haystack.c_str(), needle.c_str()) != 0; } bobcat-5.09.01/cmdfinderbase/beyond.f0000644000175000017500000000012414050437223016316 0ustar frankfrankinline std::string const &CmdFinderBase::beyond() const { return d_beyond; } bobcat-5.09.01/cmdfinderbase/cmdfinderbase1.f0000644000175000017500000000011014050437223017700 0ustar frankfrankinline CmdFinderBase::CmdFinderBase(size_t mode) { setMode(mode); } bobcat-5.09.01/cmdfinderbase/begin.f0000644000175000017500000000013714050437223016126 0ustar frankfrankinline ConfigFile__::const_iterator ConfigFile__::begin() const { return d_line.begin(); } bobcat-5.09.01/cmdfinderbase/matchuniqueinsensitive.cc0000644000175000017500000000033114050437223022002 0ustar frankfrank#include "cmdfinderbase.ih" bool CmdFinderBase::matchUniqueInsensitive(std::string const &key) const { return d_cmd.length() && String::lc(key).find(String::lc(d_cmd)) != string::npos; } bobcat-5.09.01/cmdfinderbase/setcommenthandling.f0000644000175000017500000000015014050437223020720 0ustar frankfrankinline void ConfigFile__::setCommentHandling(Comment type) { d_rmComment = type == RemoveComment; } bobcat-5.09.01/cmdfinderbase/opstar.f0000644000175000017500000000013214050437223016345 0ustar frankfrankinline std::string const &RE_iterator::operator*() const { return *d_vsIter[d_idx]; } bobcat-5.09.01/cmdfinderbase/opneg.f0000644000175000017500000000015314050437223016150 0ustar frankfrankinline int operator-(RE_iterator const &lhs, RE_iterator const &rhs) { return lhs.d_idx - rhs.d_idx; } bobcat-5.09.01/cmdfinderbase/cmd.f0000644000175000017500000000011314050437223015577 0ustar frankfrankinline std::string const &CmdFinderBase::cmd() const { return d_cmd; } bobcat-5.09.01/cmdfinderbase/end.f0000644000175000017500000000013314050437223015604 0ustar frankfrankinline ConfigFile__::const_iterator ConfigFile__::end() const { return d_line.end(); } bobcat-5.09.01/cmdfinderbase/findkey.f0000644000175000017500000000022214050437223016466 0ustar frankfrankinline string ConfigFile__::findKey(string const &keyPattern, size_t count) { return searchFor("^\\s*" + keyPattern + "\\s+(\\S+)", count); } bobcat-5.09.01/cmdfinderbase/setmode.cc0000644000175000017500000000145514050437223016646 0ustar frankfrank#include "cmdfinderbase.ih" void CmdFinderBase::setMode(size_t mode) { if (mode & ~s_all) throw Exception{1} << "CmdFinder: " << "mode 0x" << hex << mode << " not recognized (allowed bits: 0x" << s_all << ")"; d_useCmd = mode & USE_FIRST ? &CmdFinderBase::useFirstCmd : &CmdFinderBase::useCmd; switch (mode & (UNIQUE | INSENSITIVE)) { case 0: d_match = &CmdFinderBase::matchExact; break; case UNIQUE: d_match = &CmdFinderBase::matchUnique; break; case INSENSITIVE: d_match = &CmdFinderBase::matchInsensitive; break; default: d_match = &CmdFinderBase::matchUniqueInsensitive; break; } } bobcat-5.09.01/cmdfinderbase/cmdfinderbase.ih0000644000175000017500000000035114050437223020001 0ustar frankfrank#include "cmdfinderbase" #include #include "../string/string" #include "../exception/exception" using namespace std; using namespace FBB; #include "matchexact.f" #include "matchunique.f" #include "matchinsensitive.f" bobcat-5.09.01/cmdfinderbase/matchexact.f0000644000175000017500000000015614050437223017164 0ustar frankfrankinline bool CmdFinderBase::matchExact(string const &key) const { return d_cmd == key && d_cmd.length(); } bobcat-5.09.01/cmdfinderbase/size.f0000644000175000017500000000010714050437223016011 0ustar frankfrankinline size_t ConfigFile__::size() const { return d_line.size(); } bobcat-5.09.01/cmdfinderbase/swap.cc0000644000175000017500000000021314050437223016147 0ustar frankfrank#include "cmdfinderbase.ih" void CmdFinderBase::swap(CmdFinderBase &rhs) { d_cmd.swap(rhs.d_cmd); d_beyond.swap(rhs.d_beyond); } bobcat-5.09.01/cmdfinderbase/oparrow.f0000644000175000017500000000016114050437223016530 0ustar frankfrankinline std::string const *RE_iterator::operator->() const { return &*d_vsIter[d_idx]; } bobcat-5.09.01/cmdfinderbase/matchinsensitive.f0000644000175000017500000000024214050437223020414 0ustar frankfrankinline bool CmdFinderBase::matchInsensitive(string const &key) const { return String::casecmp(d_cmd, key) == 0 && d_cmd.length(); } bobcat-5.09.01/cmdfinderbase/matchunique.f0000644000175000017500000000020214050437223017356 0ustar frankfrankinline bool CmdFinderBase::matchUnique(string const &key) const { return key.find(d_cmd) != string::npos && d_cmd.length(); } bobcat-5.09.01/cmdfinderbase/opneq.f0000644000175000017500000000015014050437223016157 0ustar frankfrankinline bool operator!=(RE_iterator const &lhs, RE_iterator const &rhs) { return not (lhs == rhs); } bobcat-5.09.01/cmdfinderbase/cmdfinderbase1.cc0000644000175000017500000000024014050437223020044 0ustar frankfrank//#include "cmdfinderbase.hh" // //CmdFinderBase::CmdFinderBase(CmdFinderBase &&tmp) //: // d_cmd(move(tmp.d_cmd)), // d_beyond(move(tmp.d_beyond)) //{} bobcat-5.09.01/cmdfinderbase/usecmd.cc0000644000175000017500000000017314050437223016462 0ustar frankfrank#include "cmdfinderbase.ih" void CmdFinderBase::useCmd(std::string const &cmd) { d_beyond.erase(); d_cmd = cmd; } bobcat-5.09.01/cmdfinderbase/cmdfinderbase0000644000175000017500000000412514050437223017405 0ustar frankfrank#ifndef INCLUDED_BOBCAT_CMDFINDERBASE_ #define INCLUDED_BOBCAT_CMDFINDERBASE_ #include namespace FBB { // Key: the textual elements in the char */function * arrays (e.g., help) // Cmd: what is entered interactively (e.g., h, hel, or help) class CmdFinderBase { enum: size_t // mask testing the Mode-validity { s_all = (1 << 3) - 1 }; std::string d_cmd; std::string d_beyond; public: // The default is: // Use the key as provided // Match case sensitively and exactly // The last function is the catch-all enum Mode { USE_FIRST = 1 << 0, // Use/rm the first word from the key UNIQUE = 1 << 1, // Unique cmd abbreviations are OK INSENSITIVE = 1 << 2, // Key-cmd matched case insensitively }; void setMode(size_t mode); // to change the mode afterwards protected: explicit CmdFinderBase(size_t mode = 0); // 1.f std::string const &beyond() const; // .f info beyond the command std::string const &cmd() const; // .f the used command // returns true if the cmd represents the // key bool (CmdFinderBase::*d_match)(std::string const &key) const; // stores the command to use void (CmdFinderBase::*d_useCmd)(std::string const &cmd); void swap(CmdFinderBase &rhs); private: void useCmd(std::string const &key); void useFirstCmd(std::string const &key); bool matchExact(std::string const &key) const; // .f // the command is found in the key bool matchUnique(std::string const &key) const; // .f bool matchInsensitive(std::string const &key) const; bool matchUniqueInsensitive(std::string const &key) const; }; #include "cmdfinderbase1.f" #include "beyond.f" #include "cmd.f" } // FBB #endif bobcat-5.09.01/config/0000755000175000017500000000000014050437223013351 5ustar frankfrankbobcat-5.09.01/config/rmcommentandescapes.cc0000644000175000017500000000207614050437223017715 0ustar frankfrank#include "config.ih" bool CF_Pimpl::rmCommentAndEscapes(string &line) { size_t pos = 0; size_t lastBackslash = 0; while (true) { size_t hit; // change \\ to one backslash if ((hit = line.find("\\\\", pos)) != string::npos) line.erase(lastBackslash = hit, 1); else if ((hit = line.find("\\#", pos)) != string::npos) line.replace(hit, 2, "#"); // replace by # else { if ((hit = line.find('#', pos)) != string::npos) { lastBackslash = string::npos; line.erase(hit); // erase comment } if (line.length() > lastBackslash + 1 && *line.rbegin() == '\\') { line.resize(line.length() - 1); return true; } return false; } pos = hit + 1; // try again beyond the // last-checked character } } bobcat-5.09.01/config/cfline1.f0000644000175000017500000000015214050437223015037 0ustar frankfrankinline CF_Line::CF_Line(uint16_t lineNr, std::string const &line) : d_nr(lineNr), d_line(line) {} bobcat-5.09.01/config/load2.f0000644000175000017500000000014714050437223014523 0ustar frankfrankinline void Config::load(std::istream &stream, uint16_t firstNr) { d_ptr->load(stream, firstNr); } bobcat-5.09.01/config/obs/0000755000175000017500000000000014050437223014134 5ustar frankfrankbobcat-5.09.01/config/obs/beginendid2.f0000644000175000017500000000045214050437223016456 0ustar frankfrankinline CF_Types::CIVectIteratorPair CF_Pimpl::beginEndID(std::string const &re) { return beginEnd(re, &CF_Pimpl::findID); } inline Config::CIVectIteratorPair Config::beginEndID( std::string const &id) const { return d_ptr->beginEndID(id); } bobcat-5.09.01/config/cfpimpl2.cc0000644000175000017500000000026714050437223015401 0ustar frankfrank#include "config.ih" CF_Pimpl::CF_Pimpl(istream &stream, uint16_t lineNr, Casing sType, Comment cType) : CF_Pimpl(sType, cType) { load(stream, lineNr); } bobcat-5.09.01/config/opassign2.cc0000644000175000017500000000022014050437223015557 0ustar frankfrank#include "config.ih" Config &Config::operator=(Config const &rhs) { Config tmp(rhs); swap(d_ptr, tmp.d_ptr); return *this; } bobcat-5.09.01/config/find2.cc0000644000175000017500000000136014050437223014662 0ustar frankfrank#include "config.ih" Config::const_iterator CF_Pimpl::find(string const &needle, const_iterator const &from) const { bool (*finder)(std::string const &haystack, std::string const &needle); string const *needlePtr; string needleLow; if (d_caseSensitive) { needlePtr = &needle; finder = caseSensitive; } else { needleLow = String::lc(needle); needlePtr = &needleLow; finder = caseInsensitive; } return find_if( from, end(), [&](CF_Line const &haystack) { return finder(haystack.line(), *needlePtr); } ); } bobcat-5.09.01/config/config3.f0000644000175000017500000000020214050437223015042 0ustar frankfrankinline Config::Config(std::istream &stream, Casing sType, Comment cType) : d_ptr(new CF_Pimpl(stream, 1, sType, cType)) {} bobcat-5.09.01/config/findre1.f0000644000175000017500000000050114050437223015044 0ustar frankfrankinline Config::const_iterator Config::findRE( std::string const &id, const_iterator const &from) const { return d_ptr->findRE(id, from); } inline Config::const_iterator Config::findRE( std::string const &id) const { return findRE(id, begin()); } bobcat-5.09.01/config/clear2.cc0000644000175000017500000000051114050437223015025 0ustar frankfrank//#define XERR #include "config.ih" void CF_Pimpl::clear() { d_line.clear(); // clear the vector d_CIvect.clear(); // clear iterators to matching lines d_rawNumber = 0; // re-initialize the line-number count // of the original file } bobcat-5.09.01/config/opindex.f0000644000175000017500000000026314050437223015167 0ustar frankfrankinline CF_Line const &CF_Pimpl::operator[](size_t idx) const { return d_line[idx]; } inline CF_Line const &Config::operator[](size_t idx) const { return (*d_ptr)[idx]; } bobcat-5.09.01/config/nextline.cc0000644000175000017500000000071514050437223015511 0ustar frankfrank#include "config.ih" bool CF_Pimpl::nextLine(istream &inStream, string &dest) { dest.erase(); string line; while (getline(inStream, line)) { ++d_rawNumber; // at the next line trimLeft(line); bool appendNext = rmCommentAndEscapes(line); trimRight(line, appendNext); dest += line; if (not appendNext) return true; } return dest.length(); } bobcat-5.09.01/config/beginend.cc0000644000175000017500000000112114050437223015426 0ustar frankfrank//#define XERR #include "config.ih" CF_Types::CIVectIteratorPair CF_Pimpl::beginEnd( std::string const &re, const_iterator (CF_Pimpl::*find)(std::string const &, const_iterator const &) const ) { d_CIvect.clear(); auto beyond = end(); auto from = begin(); while (true) { from = (this->*find)(re, from); if (from == beyond) break; d_CIvect.push_back(from); ++from; } return CIVectIteratorPair{ d_CIvect.cbegin(), d_CIvect.cend() }; } bobcat-5.09.01/config/findkey1.f0000644000175000017500000000054214050437223015233 0ustar frankfrankinline Config::const_iterator Config::findKey( std::string const &id, const_iterator const &from) const { return d_ptr->findKey(id, from); } inline Config::const_iterator Config::findKey( std::string const &id) const { return findKey(id, begin()); } bobcat-5.09.01/config/findre2.cc0000644000175000017500000000033114050437223015206 0ustar frankfrank#include "config.ih" Config::const_iterator CF_Pimpl::findRE( string const &re, const_iterator const &from) const { d_pattern.setPattern(re, d_caseSensitive); return findRE(from); } bobcat-5.09.01/config/load4.cc0000644000175000017500000000041114050437223014657 0ustar frankfrank#include "config.ih" void CF_Pimpl::load(istream &stream, uint16_t lineNr) { clear(); d_rawNumber = lineNr - 1; string line; while (nextLine(stream, line)) // add the lines to d_line d_line.push_back({ d_rawNumber, std::move(line) }); } bobcat-5.09.01/config/config5.f0000644000175000017500000000016614050437223015055 0ustar frankfrankinline Config::Config(std::istream &&stream, Casing sType, Comment cType) : Config(stream, 1, sType, cType) {} bobcat-5.09.01/config/config2.f0000644000175000017500000000024714050437223015052 0ustar frankfrankinline Config::Config(std::string const &fname, Casing sType, Comment cType) : Config(FBB::Exception::factory(fname), sType, cType) {} bobcat-5.09.01/config/setcasing.f0000644000175000017500000000024514050437223015501 0ustar frankfrankinline void CF_Pimpl::setCasing(Casing type) { d_caseSensitive = type == UseCase; } inline void Config::setCasing(Casing type) { d_ptr->setCasing(type); } bobcat-5.09.01/config/framep0000644000175000017500000000006414050437223014546 0ustar frankfrank//#define XERR #include "config.ih" CF_Pimpl:: { } bobcat-5.09.01/config/findid2.cc0000644000175000017500000000163114050437223015200 0ustar frankfrank#include "config.ih" Config::const_iterator CF_Pimpl::findID( string const &id, const_iterator const &from) const { auto strIter = find_if(id.begin(), id.end(), // find 1st non-ID char [&](int ch) { return not idChar(ch); } ); // use id's ID-chars until string const &key = // the first non-ID char strIter == id.end()? id : id.substr(0, strIter - id.begin()); return find_if(from, end(), [&](CF_Line const &elem) { // the key must start at return elem.line().find(key) == 0 // line[0] and // and no ID char next not idChar(elem.line()[key.length()]); } ); } bobcat-5.09.01/config/findre3.cc0000644000175000017500000000076514050437223015222 0ustar frankfrank#include "config.ih" Config::const_iterator CF_Pimpl::findRE( const_iterator const &from) const { return find_if(from, end(), [&](CF_Line const &elem) { try { d_pattern.match(elem.line()); return true; } catch (...) { return false; } } ); } bobcat-5.09.01/config/trimleft.cc0000644000175000017500000000037614050437223015514 0ustar frankfrank#include "config.ih" void CF_Pimpl::trimLeft(string &line) { // remove initial ws. string::size_type pos = line.find_first_not_of(" \t"); if (pos != string::npos) line.erase(0, pos); } bobcat-5.09.01/config/config4.f0000644000175000017500000000025614050437223015054 0ustar frankfrankinline Config::Config(std::istream &stream, uint16_t lineNr, Casing sType, Comment cType) : d_ptr(new CF_Pimpl(stream, lineNr, sType, cType)) {} bobcat-5.09.01/config/begin.f0000644000175000017500000000025714050437223014610 0ustar frankfrankinline CF_Pimpl::const_iterator CF_Pimpl::begin() const { return d_line.begin(); } inline Config::const_iterator Config::begin() const { return d_ptr->begin(); } bobcat-5.09.01/config/findid1.f0000644000175000017500000000047614050437223015045 0ustar frankfrankinline Config::const_iterator Config::findID( std::string const &id, const_iterator from) const { return d_ptr->findID(id, from); } inline Config::const_iterator Config::findID( std::string const &id) const { return findID(id, begin()); } bobcat-5.09.01/config/config0000644000175000017500000002005614050437223014544 0ustar frankfrank#ifndef INCLUDED_BOBCAT_CONFIG_ #define INCLUDED_BOBCAT_CONFIG_ // Lines are stored with initial WS removed. // If a line ends in \, then the next line (initial WS removed) // is appended to the current line. // Information at and beyond the first # on individual lines is removed // if the rmComment flag is set to true // Then, lines containing only blanks and tabs are not stored #include #include #include #include #include #include #include namespace FBB { class CF_Line { uint16_t d_nr = 0; std::string d_line; public: CF_Line() = default; CF_Line(uint16_t lineNr, std::string const &line); std::string const &line() const; std::string key() const; std::string value() const; std::string tail() const; uint16_t lineNr() const; private: size_t next(size_t pos) const; // .f size_t tailPos() const; }; #include "cfline1.f" #include "line.f" #include "linenr.f" #include "next.f" #include "cflineopinsert.f" struct CF_Types { enum Comment { KeepComment, NoComment, }; enum Casing { UseCase, NoCase, }; typedef std::vector LineVect; typedef std::vector::const_iterator const_iterator; typedef std::vector CIVect; typedef std::pair CIVectIteratorPair; }; class CF_Pimpl: public CF_Types { uint16_t d_rawNumber; LineVect d_line; bool d_rmComment; bool d_caseSensitive; CIVect d_CIvect; mutable Pattern d_pattern; public: explicit CF_Pimpl(Casing sType, Comment cType); // 1 explicit CF_Pimpl(std::istream &stream, // 2 uint16_t lineNr, Casing sType, Comment cType); void setCasing(Casing type); // .f void setComment(Comment type); // .f void load(std::istream &stream, uint16_t lineNr); // 4 void clear(); // 2 const_iterator begin() const; // .f const_iterator end() const; // .f const_iterator find(std::string const &target, // 2 const_iterator const &from) const; const_iterator findID(std::string const &id, // 2 const_iterator const &from) const; const_iterator findKey(std::string const &key, // 2 const_iterator const &from) const; const_iterator findRE(std::string const &re, // 2 const_iterator const &from) const; CIVectIteratorPair beginEndRE(std::string const &re); // .f CIVectIteratorPair beginEndID(std::string const &id); // .f CF_Line const &operator[](size_t idx) const; // .f size_t size() const; // .f private: bool nextLine(std::istream &inStream, std::string &dest); bool rmCommentAndEscapes(std::string &line); const_iterator findRE(const_iterator const &from) const; // 3 CIVectIteratorPair beginEnd( std::string const &re, const_iterator (CF_Pimpl::*find)( std::string const &, const_iterator const &) const ); static void trimLeft(std::string &line); static void trimRight(std::string &line, bool appendNext); static bool idChar(int ch); // .f static bool caseSensitive(std::string const &haystack, // .f std::string const &needle); // needle is guaranteed lowercase static bool caseInsensitive(std::string const &haystack, // .f std::string const &needle); }; #include "idchar.f" #include "casesensitive.f" #include "caseinsensitive.f" class Config: public CF_Types { CF_Pimpl *d_ptr; public: explicit Config(Casing sType = UseCase, // 1.f Comment cType = NoComment); explicit Config(std::string const &fname, // 2.f Casing sType = UseCase, Comment cType = NoComment); explicit Config(std::istream &stream, // 3.f Casing sType = UseCase, Comment cType = NoComment); explicit Config(std::istream &stream, uint16_t lineNr, // 4.f Casing sType = UseCase, Comment cType = NoComment); explicit Config(std::istream &&stream, // 5.f Casing sType = UseCase, Comment cType = NoComment); explicit Config(std::istream &&stream, uint16_t lineNr, // 6.f Casing sType = UseCase, Comment cType = NoComment); Config(Config &&tmp); // 7.f Config(Config const &rhs); // 8.f ~Config(); Config &operator=(Config &&tmp); // 1 Config &operator=(Config const &rhs); // 2 CF_Line const &operator[](size_t idx) const; // 1.f void setCasing(Casing type); // .f void setComment(Comment type); // .f void load(std::string const &fname); // 1.f void load(std::istream &stream, uint16_t firstNr = 1); // 2.f void load(std::istream &&stream, uint16_t firstNr = 1); // 3.f void clear(); // 1.f const_iterator begin() const; // .f const_iterator end() const; // .f const_iterator find(std::string const &needle) const; // 1.f const_iterator find(std::string const &needle, // 1.f const_iterator const &from) const; const_iterator findID(std::string const &id) const; // 1.f const_iterator findID(std::string const &id, // 1.f const_iterator from) const; const_iterator findKey(std::string const &key) const; // 1.f const_iterator findKey(std::string const &key, // 1.f const_iterator const &from) const; const_iterator findRE(std::string const &re) const; // 1.f const_iterator findRE(std::string const &re, // 1.f const_iterator const &from) const; CIVectIteratorPair beginEndRE(std::string const &re) const; // .f CIVectIteratorPair beginEndID(std::string const &id) const; // .f size_t size() const; // .f }; #include "begin.f" #include "beginendid.f" #include "beginendre.f" #include "config1.f" #include "config2.f" #include "config3.f" #include "config4.f" #include "config5.f" #include "config6.f" #include "config7.f" #include "config8.f" #include "clear1.f" #include "end.f" #include "find1.f" #include "findid1.f" #include "findkey1.f" #include "findre1.f" #include "load1.f" #include "load2.f" #include "load3.f" #include "opindex.f" #include "setcasing.f" #include "setcomment.f" #include "size.f" } // FBB #endif bobcat-5.09.01/config/tailpos.cc0000644000175000017500000000040214050437223015327 0ustar frankfrank//#define XERR #include "config.ih" size_t CF_Line::tailPos() const { size_t pos = next(0); // beyond the key return pos == string::npos? pos : d_line.find_first_not_of(" \t\r", pos); } bobcat-5.09.01/config/value.cc0000644000175000017500000000032614050437223014775 0ustar frankfrank//#define XERR #include "config.ih" string CF_Line::value() const { size_t pos = tailPos(); string ret; if (pos != string::npos) ret = d_line.substr(pos, next(pos) - pos); return ret; } bobcat-5.09.01/config/linenr.f0000644000175000017500000000007514050437223015011 0ustar frankfrankinline uint16_t CF_Line::lineNr() const { return d_nr; } bobcat-5.09.01/config/end.f0000644000175000017500000000024714050437223014271 0ustar frankfrankinline CF_Pimpl::const_iterator CF_Pimpl::end() const { return d_line.end(); } inline Config::const_iterator Config::end() const { return d_ptr->end(); } bobcat-5.09.01/config/key.cc0000644000175000017500000000032114050437223014444 0ustar frankfrank//#define XERR #include "config.ih" string CF_Line::key() const { string ret; if (size_t pos = next(0); pos != string::npos) // key available ret = d_line.substr(0, pos); return ret; } bobcat-5.09.01/config/clear1.f0000644000175000017500000000006414050437223014667 0ustar frankfrankinline void Config::clear() { d_ptr->clear(); } bobcat-5.09.01/config/size.f0000644000175000017500000000020514050437223014467 0ustar frankfrankinline size_t CF_Pimpl::size() const { return d_line.size(); } inline size_t Config::size() const { return d_ptr->size(); } bobcat-5.09.01/config/load3.f0000644000175000017500000000014114050437223014516 0ustar frankfrankinline void Config::load(std::istream &&stream, uint16_t firstNr) { load(stream, firstNr); } bobcat-5.09.01/config/config.ih0000644000175000017500000000012414050437223015135 0ustar frankfrank#include "config" #include using namespace std; using namespace FBB; bobcat-5.09.01/config/config8.f0000644000175000017500000000012214050437223015050 0ustar frankfrankinline Config::Config(Config const &rhs) : d_ptr(new CF_Pimpl(*rhs.d_ptr)) {} bobcat-5.09.01/config/findkey2.cc0000644000175000017500000000036514050437223015377 0ustar frankfrank#include "config.ih" Config::const_iterator CF_Pimpl::findKey( string const &key, const_iterator const &from) const { d_pattern.setPattern("^\\s*" + key + "\\s+(\\S+)", d_caseSensitive); return findRE(from); } bobcat-5.09.01/config/setcomment.f0000644000175000017500000000025014050437223015673 0ustar frankfrankinline void CF_Pimpl::setComment(Comment type) { d_rmComment = type == NoComment; } inline void Config::setComment(Comment type) { d_ptr->setComment(type); } bobcat-5.09.01/config/cflineopinsert.f0000644000175000017500000000015114050437223016541 0ustar frankfrankinline std::ostream &operator<<(std::ostream &out, CF_Line const &cfl) { return out << cfl.line(); } bobcat-5.09.01/config/destructor.cc0000644000175000017500000000007614050437223016061 0ustar frankfrank#include "config.ih" Config::~Config() { delete d_ptr; } bobcat-5.09.01/config/load1.f0000644000175000017500000000016314050437223014520 0ustar frankfrankinline void Config::load(std::string const &fname) { load(FBB::Exception::factory(fname), 1); } bobcat-5.09.01/config/opassign1.cc0000644000175000017500000000016114050437223015562 0ustar frankfrank#include "config.ih" Config &Config::operator=(Config &&tmp) { swap(d_ptr, tmp.d_ptr); return *this; } bobcat-5.09.01/config/caseinsensitive.f0000644000175000017500000000030214050437223016707 0ustar frankfrank//static inline bool CF_Pimpl::caseInsensitive(std::string const &lhs, std::string const &rhs) { return caseSensitive(String::lc(lhs), rhs); } bobcat-5.09.01/config/trimright.cc0000644000175000017500000000034114050437223015667 0ustar frankfrank#include "config.ih" void CF_Pimpl::trimRight(string &line, bool appendNext) { if (appendNext) return; size_t pos = line.find_last_not_of(" \t"); if (pos != string::npos) line.resize(pos + 1); } bobcat-5.09.01/config/beginendre.f0000644000175000017500000000045214050437223015623 0ustar frankfrankinline CF_Types::CIVectIteratorPair CF_Pimpl::beginEndRE(std::string const &re) { return beginEnd(re, &CF_Pimpl::findRE); } inline Config::CIVectIteratorPair Config::beginEndRE( std::string const &re) const { return d_ptr->beginEndRE(re); } bobcat-5.09.01/config/beginendid.f0000644000175000017500000000045214050437223015611 0ustar frankfrankinline CF_Types::CIVectIteratorPair CF_Pimpl::beginEndID(std::string const &re) { return beginEnd(re, &CF_Pimpl::findID); } inline Config::CIVectIteratorPair Config::beginEndID( std::string const &id) const { return d_ptr->beginEndID(id); } bobcat-5.09.01/config/config1.f0000644000175000017500000000013714050437223015047 0ustar frankfrankinline Config::Config(Casing sType, Comment cType) : d_ptr(new CF_Pimpl(sType, cType)) {} bobcat-5.09.01/config/config6.f0000644000175000017500000000024214050437223015051 0ustar frankfrankinline Config::Config(std::istream &&stream, uint16_t lineNr, Casing sType, Comment cType) : Config(stream, lineNr, sType, cType) {} bobcat-5.09.01/config/idchar.f0000644000175000017500000000011614050437223014750 0ustar frankfrankinline bool CF_Pimpl::idChar(int ch) { return isalnum(ch) or ch == '_'; } bobcat-5.09.01/config/find1.f0000644000175000017500000000046314050437223014524 0ustar frankfrankinline Config::const_iterator Config::find(std::string const &needle, const_iterator const &from) const { return d_ptr->find(needle, from); } inline Config::const_iterator Config::find(std::string const &needle) const { return find(needle, begin()); } bobcat-5.09.01/config/next.f0000644000175000017500000000017514050437223014501 0ustar frankfrankinline size_t CF_Line::next(size_t pos) const { return d_line.find_first_of(" \t\r", pos); // first ws sep from 'pos' } bobcat-5.09.01/config/config7.f0000644000175000017500000000013214050437223015050 0ustar frankfrankinline Config::Config(Config &&tmp) : d_ptr( new CF_Pimpl(std::move(*tmp.d_ptr) )) {} bobcat-5.09.01/config/casesensitive.f0000644000175000017500000000031514050437223016364 0ustar frankfrank//static inline bool CF_Pimpl::caseSensitive(std::string const &haystack, std::string const &needle) { return haystack.find(needle) != std::string::npos; } bobcat-5.09.01/config/cfpimpl1.cc0000644000175000017500000000020614050437223015371 0ustar frankfrank#include "config.ih" CF_Pimpl::CF_Pimpl(Casing sType, Comment cType) : d_rmComment(cType == NoComment) { setCasing(sType); } bobcat-5.09.01/config/tail.cc0000644000175000017500000000040414050437223014607 0ustar frankfrank//#define XERR #include "config.ih" string CF_Line::tail() const { size_t pos = tailPos(); string ret; if (pos != string::npos) // there is a tail ret = d_line.substr(pos); // assign it to ret return ret; } bobcat-5.09.01/config/driver/0000755000175000017500000000000014050437223014644 5ustar frankfrankbobcat-5.09.01/config/driver/build0000755000175000017500000000132014050437223015665 0ustar frankfrank#!/bin/bash ln -sf .. configdir case $1 in (b) rm config config.ih g++ -DBOBCAT --static --std=c++2a -I../../tmp driver.cc \ -L../../tmp/lib -lbobcat -s ;; (o) g++ --std=c++2a *.cc ../tmp/o/*.o -lbobcat -s ;; (c) g++ --std=c++2a *.cc -lbobcat -s ;; (l) g++ --std=c++2a -Iconfigdir *.cc \ -L../tmp -lconfig -lbobcat -s ;; (*) echo $0 b links to bobcat built by 'build libraries all' echo $0 o links to the files in ../tmp/o echo $0 c links to the files in the current dir only echo $0 l links to \*.cc, ../libconfig.a and std bobcat rm -f driver ;; esac rm -f configdir bobcat-5.09.01/config/driver/driver.cc0000644000175000017500000000772514050437223016461 0ustar frankfrank#include #include #include #ifdef BOBCAT #include #else #include "configdir/config" #endif using namespace std; using namespace FBB; int main(int argc, char **argv) try { if (argc == 1) { cout << "Need name of configfile\n"; return 1; } Config cf(argv[1], Config::NoCase, Config::NoComment); cout << "opened: " << argv[1] << '\n'; cout << "Got " << cf.size() << " lines\n\n"; #if 0 cf.open(argv[1]); cout << "opened again: " << argv[1] << "\n" "Got " << cf.size() << " lines\n" << cf[0] << " from line " << cf.index(0) << "\n" "================\n"; #endif #if 1 cout << "all lines using iterators:\n"; copy(cf.begin(), cf.end(), ostream_iterator(cout, "\n")); #endif #if 0 while (true) { cout << "Enter literal to search for (or just Enter): "; string param; if (!getline(cin, param) || !param.length()) break; auto it = cf.find(param); if (it != cf.end()) cout << *it << ": at index " << cf.index(it) << '\n'; else cout << " < not found > " << '\n'; } cout.put('\n'); #endif #if 0 while (true) { cout << "Enter ID to search for (or just Enter): "; string param; if (!getline(cin, param) || !param.length()) break; auto it = cf.findID(param); if (it != cf.end()) cout << *it << ": at index " << cf.index(it) << '\n'; else cout << " < not found > " << '\n'; } cout.put('\n'); #endif #if 0 while (true) { cout << "Enter Key to search for (or just Enter): "; string param; if (!getline(cin, param) || !param.length()) break; auto it = cf.findKey(param); if (it == cf.end()) cout << " < not found > " << '\n'; else cout << *it << ": at index " << cf.index(it) << "\n" "parts:\n" " line nr: " << it->lineNr() << "\n" " key: " << it->key() << "\n" " value: " << it->value() << "\n" " tail: " << it->tail() << "\n" " next Nr: " << (++it)->lineNr() << '\n'; } cout.put('\n'); #endif #if 1 while (true) { cout << "Finding all lines matching an ID.\n" "Enter the ID (or just Enter): "; string param; if (!getline(cin, param) || !param.length()) return 0; auto [begin, end] = cf.beginEndID(param); cout << "Counting: " << (end - begin) << " matches\n"; while (begin != end) { auto it = *begin++; cout << *it << ":\n" "parts:\n" " line nr: " << it->lineNr() << "\n" " key: " << it->key() << "\n" " value: " << it->value() << "\n" " tail: " << it->tail() << "\n"; } } #endif #if 0 while (true) { cout << "Finding all lines matching a RE.\n" "Enter the RE (or just Enter): "; string param; if (!getline(cin, param) || !param.length()) return 0; auto [begin, end] = cf.beginEndRE(param); cout << "Counting: " << (end - begin) << " matches\n"; while (begin != end) { auto it = *begin++; cout << *it << ": at index " << cf.index(it) << "\n" "parts:\n" " line nr: " << it->lineNr() << "\n" " key: " << it->key() << "\n" " value: " << it->value() << "\n" " tail: " << it->tail() << "\n"; } } #endif } catch (exception const &e) { cout << "Fatal: " << e.what() << '\n'; return 1; } bobcat-5.09.01/config/driver/config0000644000175000017500000000100014050437223016023 0ustar frankfrank# these options are also defined by driver.cc option option-value: \#xyz option-value: #xyz # other lines may also be provided, lines starting with # are comment a line not containing an option # this is ignored noline: this one too line: this is found this is not a line containing line: at the beginning of the line line: this one is line: what about this one? \ it's extending over multiple lines indent: indented content. and there may, of course, be more lines in this file bobcat-5.09.01/config/driver/driver.rc0000644000175000017500000000033414050437223016465 0ustar frankfrank# This is comment hello (at idx 1) # void rematch one multiple \ lines (starts at idx 2) another \ \ set of \ lines (starts at idx 4) rematch two # comment only history history-one two bobcat-5.09.01/config/line.f0000644000175000017500000000010714050437223014445 0ustar frankfrankinline std::string const &CF_Line::line() const { return d_line; } bobcat-5.09.01/configfile/0000755000175000017500000000000014050437223014211 5ustar frankfrankbobcat-5.09.01/configfile/index2.f0000644000175000017500000000015514050437223015552 0ustar frankfrankinline size_t ConfigFile_::index(const_iterator const &iterator) { return d_index[iterator - begin()]; } bobcat-5.09.01/configfile/find.cc0000644000175000017500000000074714050437223015450 0ustar frankfrank#include "configfile.ih" vector::const_iterator ConfigFile_::find(string const &target) const { return find_if( begin(), end(), [&](string const &haystack) { return (d_caseSensitive ? finder : casefinder) (haystack, target); } ); } vector::const_iterator ConfigFile::find(string const &target) const { return d_ptr->find(target); } bobcat-5.09.01/configfile/build0000755000175000017500000003470214050437223015244 0ustar frankfrank#!/usr/bin/icmake -qt/tmp/hostname // script generated by the C++ icmake script version 2.02 string CLASSES; void setClasses() { // ADD ADDITIONAL DIRECTORIES CONTAINING SOURCES OF CLASSES HERE // Use the construction `CLASSES += "classname1 classname2";' etc. CLASSES += " "; } /* Default values for the following variables are found in $IM/default/defines.fm BUILD_LIBRARY: define this if you want to create a library for the object modules. Undefined by default: so NO LIBRARY IS BUILT. This links ALL object files to a program, which is a faster process than linking to a library. But it can bloat the executable: all o-modules, rather than those that are really used, become part of the program's code. When defined as an EMPTY STRING, the static library libXXX.a is created: all programs linked to this library will themselves contain the code of the required object modules. This will result in code duplication over different programs linked to this library. When defined as a VERSION STRING, e.g., 1.0.4, a shared library libXXX.so.VERSION is constructed, as well as the links libXXX.so.MAINVERSION and libXXX.so (e.g. 1.0.0 creates libXXX.so.1.0.0, libXXX.so.1 and libXXX.so). Note that with a shared library, the library is always constructed fresh from the compiled object files. But programs linked to this library will SHARE the code stored in the shared library. These programs will therefore tend to be relatively small. Also note that `ldconfig -v' might be required after installing a shared library (libXXX.so) for the first time, so that the linker knows of its existence (in ld.so.cache) BUILD_PROGRAM: define if a program is to be built. If not defined, library maintenance is assumed (default: defined). COMPILER: The compiler to use. COPT: C-options used by COMPILER ECHO_REQUEST: ON (default) if command echoing is wanted, otherwise: set to OFF GDB: define if gdb-symbolic debug information is wanted (not defined by default) LIBS: Extra libraries used for linking LIBPATH: Extra library-searchpaths used for linking LOCAL_NAMESPACE:The namespace that you, the programmer, use yourself. USING: List of :-separated namespaces to be used in sources and .fh files, appearing in `using' directives. USING does NOT automatically include LOCAL_NAMESPACE: add your LOCAL_NAMESPACE name to this list if want a `using' directive for your own namespace as well. Note that namespaces are NOT part of the build-script: they are only listed below for convenience. When they must be altered, the defaults must be changed in $IM/default/defines.fm RELINK: Defined by default, causing a program to be relinked every time the script is called. Do not define it if relinking should only occur if a source is compiled. No effect for library maintenance. Current values: */ #define BUILD_LIBRARY "" // #define BUILD_PROGRAM #define COMPILER "g++" #define COPT "-Wall --std=c++0x" #define ECHO_REQUEST 1 //#define GDB "-g" #define ICMAKE "/usr/bin/icmake" #define LIBS "" #define LIBPATH "" // local namespace is: FBB // using-declarations generated for: std:FBB // NO CONFIGURABLE PARTS BELOW THIS LINE /* V A R S . I M */ string // contain options for cwd, // current WD libs, // extra libs, e.g., "-lrss -licce" libpath, // extra lib-paths, eg, "-L../rss" copt, // Compiler options lopt, // Linker options libxxx, // full library-path libso, // symbolic link to so.major library path libsomajor, // lib.so.major path ofiles, // wildcards for o-files sources, // sources to be used current; // contains name of current dir. int nClasses, // number of classes/subdirectories program, // 1: program is built so_lib; // 1: so_lib is built list classes; // list of classes/directories /* I N I T I A L . I M */ void initialize() { echo(ECHO_REQUEST); sources = "*.cc"; ofiles = "o/*.o"; // std set of o-files copt = COPT; program = 0; #ifdef BUILD_LIBRARY if (strlen(BUILD_LIBRARY)) so_lib = !program; else so_lib = 0; #else if (!program) { printf("no program, no library ?\n"); exit(1); } #endif if (so_lib) copt += " -fPIC"; cwd = chdir("."); setClasses(); // remaining classes classes = strtok(CLASSES, " "); // list of classes nClasses = sizeof(classes); } /* O B J F I L E S . I M */ list objfiles(list files) { string file, objfile; int i; for (i = 0; i < sizeof(files); i++) { file = element(i, files); // determine element of the list objfile = "./o/" + change_ext(file, "o"); // make obj-filename if (objfile younger file) // objfile is younger { files -= (list)file; // remove the file from the list i--; // reduce i to test the next } } return (files); } /* A L T E R E D . I M */ list altered(list files, string target) { int i; string file; for (i = 0; i < sizeof(files); i++) // try all elements of the list { file = element(i, files); // use element i of the list if (file older target) // a file is older than the target { files -= (list)file; // remove the file from the list i--; // reduce i to inspect the next } // file of the list } return (files); // return the new list } /* F I L E L I S T . I M */ list file_list(string type, string library) { list files; files = makelist(type); // make all files of certain type #ifdef BUILD_LIBRARY if (!so_lib) // keep all files with so libs files = altered(files, library);// keep all files newer than lib. #endif files = objfiles(files); // remove if younger .obj exist return (files); } /* P R E F I X C L . I M */ void prefix_class(string class_id) { list o_files; string o_file; int i; chdir("o"); o_files = makelist("*.o"); for (i = 0; o_file = element(i, o_files); i++) exec("mv", o_file, class_id + o_file); chdir(".."); } /* R M C L A S S P . I M */ #ifdef BUILD_LIBRARY string rm_class_id(string class_id, string ofile) { string ret; int index, n; n = strlen(ofile); for (index = strlen(class_id); index < n; index++) ret += element(index, ofile); return ret; } #endif void rm_class_prefix(string class_id) { #ifdef BUILD_LIBRARY list o_files; string o_file; int i; chdir("o"); o_files = makelist("*.o"); for (i = 0; o_file = element(i, o_files); i++) exec("mv", o_file, rm_class_id(class_id, o_file)); chdir(".."); #endif } /* L I N K S O . I M */ void link_solib(string library) { string gdb; #ifdef GDB gdb = GDB; #endif #ifdef BUILD_LIBRARY int index; list sofiles, version; version = strtok(BUILD_LIBRARY, "."); libso = "lib" + library + ".so"; libxxx = libso + "."; libsomajor = libxxx + element(0, version); libxxx += BUILD_LIBRARY; for (index = 0; index < nClasses; index++) { current = element(index, classes); // determine class name chdir(current); // chdir to a class directory. prefix_class((string)index); chdir(cwd); // go back to parent dir } if (!makelist("o/*.o")) ofiles = "*/o/*.o"; printf("\n"); exec(COMPILER, gdb, "-shared", "-Wl,-soname," + libsomajor, "-o", libxxx, ofiles, libs, "-L.", libpath, lopt ); printf("ok: ", libxxx, "\n"); for (index = 0; index < nClasses; index++) { current = element(index, classes); // determine class name chdir(current); // chdir to a class directory. rm_class_prefix((string)index); chdir(cwd); // go back to parent dir } exec("ln", "-sf", libxxx, libsomajor); printf("ok: ", libsomajor, "\n"); exec("ln", "-sf", libsomajor, libso); printf("ok: ", libso, "\n"); #endif } /* C C O M P I L E . I M */ void c_compile(list cfiles) { string nextfile; int i; if (!exists("o")) system("mkdir o"); if (sizeof(cfiles)) // files to compile ? { printf("\ncompiling: ", current, "\n\n"); // compile all files separately for (i = 0; nextfile = element(i, cfiles); i++) exec(COMPILER, "-c -o o/" + change_ext(nextfile, "o"), copt, nextfile); printf("\n"); } printf("ok: ", current, "\n"); } /* U P D A T E L I . I M */ void updatelib(string library) { #ifdef BUILD_LIBRARY list arlist, objlist; string to, from; objlist = makelist("o/*.o"); if (!sizeof(objlist)) return; printf("\n"); exec("ar", "rvs", library, "o/*.o"); exec("rm", "o/*.o"); printf("\n"); #endif } /* S T D C P P . I M */ void std_cpp(string library) { list cfiles; cfiles = file_list(sources, library); // make list of all cpp-files c_compile(cfiles); // compile cpp-files } /* C P P M A K E . C CPP files are processed by stdmake. Arguments of CPPMAKE: cpp_make( string mainfile, : name of the main .cpp file, or "" for library maintenance string library, : name of the local library to use/create (without lib prefix or .a/.so suffix (E.g., use `main' for `libmain.a') string exe, : (path) name of the exe file to create ) Both mainfile and library MUST be in the current directory */ void cpp_make(string mainfile, string library, string exe) { int index; if (nClasses) ofiles += " */o/*.o"; // set ofiles for no LIBRARY use // make library name #ifdef BUILD_LIBRARY if (!so_lib) libxxx = chdir(".") + "lib" + library + ".a"; #endif // first process all classes for (index = 0; index < nClasses; index++) { current = element(index, classes); // next class to process chdir(current); // change to directory current = "subdir " + current; std_cpp(libxxx); // compile all files chdir(cwd); // go back to parent dir } current = "auxiliary " + sources + " files"; std_cpp(libxxx); // compile all files in current dir #ifdef BUILD_LIBRARY if (!so_lib) { // prefix class-number for .o files for (index = 0; index < nClasses; index++) { current = element(index, classes); // determine class name chdir( current); // chdir to a class directory. prefix_class((string)index); updatelib(libxxx); chdir(cwd); // go back to parent dir } current = ""; // no class anymore updatelib(libxxx); // update lib in current dir } else { link_solib(library); // separate processing for so-lib return; } #endif } /* S E T L I B S . I M */ void setlibs() { #ifdef LIBS int n, index; list cut; cut = strtok(LIBS, " "); // cut op libraries n = sizeof(cut); for (index = 0; index < n; index++) libs += " -l" + element(index, cut); #ifdef GRAMBUILD libs += " -lfl"; #endif cut = strtok(LIBPATH, " "); // cut up the paths n = sizeof(cut); for (index = 0; index < n; index++) libpath += " -L" + element(index, cut); #endif } void main() { initialize(); setlibs(); cpp_make ( "", "configfile", // static- or so-library "" ); } bobcat-5.09.01/configfile/findkeytail.f0000644000175000017500000000031714050437223016664 0ustar frankfrankinline std::string ConfigFile_::findKeyTail(std::string const &keyPattern, size_t count) { return searchFor("^\\s*" + keyPattern + "\\s+(.*)\\s*$", count); } bobcat-5.09.01/configfile/index2.cc0000644000175000017500000000017314050437223015712 0ustar frankfrank#include "configfile.ih" size_t ConfigFile::index(const_iterator const &iterator) { return d_ptr->index(iterator); } bobcat-5.09.01/configfile/ignoreindex.cc0000644000175000017500000000007514050437223017035 0ustar frankfrank#include "configfile.ih" void ConfigFile_::ignoreIndex() {} bobcat-5.09.01/configfile/index1.f0000644000175000017500000000012014050437223015541 0ustar frankfrankinline size_t ConfigFile_::index(size_t lineNr) { return d_index[lineNr]; } bobcat-5.09.01/configfile/setcommenthandling.cc0000644000175000017500000000016614050437223020406 0ustar frankfrank#include "configfile.ih" void ConfigFile::setCommentHandling(Comment type) { d_ptr->setCommentHandling(type); } bobcat-5.09.01/configfile/size.cc0000644000175000017500000000013014050437223015464 0ustar frankfrank#include "configfile.ih" size_t ConfigFile::size() const { return d_ptr->size(); } bobcat-5.09.01/configfile/beginendre2.cc0000644000175000017500000000022514050437223016703 0ustar frankfrank#include "configfile.ih" ConfigFile::RE_iteratorPair ConfigFile::beginEndRE() const { return RE_iteratorPair(d_ptr->endRE(), d_ptr->endRE()); } bobcat-5.09.01/configfile/opindex.f0000644000175000017500000000014014050437223016021 0ustar frankfrankinline std::string const &ConfigFile_::operator[](size_t idx) const { return d_line[idx]; } bobcat-5.09.01/configfile/nextline.cc0000644000175000017500000000072314050437223016350 0ustar frankfrank#include "configfile.ih" bool ConfigFile_::nextLine(istream &inStream, string &dest) { dest.erase(); string line; while (getline(inStream, line)) { ++d_rawIndex; // at the next line trimLeft(line); bool appendNext = rmCommentAndEscapes(line); trimRight(line, appendNext); dest += line; if (not appendNext) return true; } return dest.length(); } bobcat-5.09.01/configfile/configfile1.cc0000644000175000017500000000101614050437223016704 0ustar frankfrank#include "configfile.ih" ConfigFile_::ConfigFile_(Comment cType, SearchCasing sType, Indices iType) : d_rmComment(cType == RemoveComment), d_caseSensitive(sType == SearchCaseSensitive), d_rawIndices(iType == StoreIndices ? &ConfigFile_::storeIndex : &ConfigFile_::ignoreIndex) {} ConfigFile::ConfigFile(Comment cType, SearchCasing sType, Indices iType) : d_ptr(new ConfigFile_(cType, sType, iType)) {} bobcat-5.09.01/configfile/configfile0000644000175000017500000000753414050437223016252 0ustar frankfrank#ifndef INCLUDED_BOBCAT_CONFIGFILE_ #define INCLUDED_BOBCAT_CONFIGFILE_ // Lines are stored with initial WS removed. // If a line ends in \, then the next line (initial WS removed) // is appended to the current line. // Information at and beyond the first # on individual lines is removed // if the rmComment flag is set to true // Then, lines containing only blanks and tabs are not stored #include #include #include namespace FBB { class RE_iterator: public std::iterator { friend class ConfigFile_; friend int operator-(RE_iterator const &lhs, // opneg.f RE_iterator const &rhs); friend bool operator==(RE_iterator const &lhs, RE_iterator const &rhs); // contains iterators to lines matching REs typedef std::vector::const_iterator VsIterator; typedef std::vector VsIterVector; VsIterVector const &d_vsIter; size_t d_idx; public: RE_iterator &operator++(); std::string const &operator*() const; // opstar.f std::string const *operator->() const; // oparrow.f private: RE_iterator(VsIterVector const &vsIter, size_t idx); }; struct CFEnums_ { typedef RE_iterator const_RE_iterator; typedef std::vector::const_iterator const_iterator; typedef std::pair RE_iteratorPair; enum Comment { KeepComment, RemoveComment }; enum SearchCasing { SearchCaseSensitive, SearchCaseInsensitive }; enum Indices { IgnoreIndices, StoreIndices }; }; class ConfigFile_; class ConfigFile: public CFEnums_ { ConfigFile_ *d_ptr; public: explicit ConfigFile(Comment cType = KeepComment, // 1 SearchCasing sType = SearchCaseSensitive, Indices iType = IgnoreIndices); // 2 explicit ConfigFile(std::string const &fname, // config file name Comment cType = KeepComment, SearchCasing sType = SearchCaseSensitive, Indices iType = IgnoreIndices); ConfigFile(ConfigFile &&tmp); // 3 ConfigFile(ConfigFile const &rhs); // 4 ~ConfigFile(); ConfigFile &operator=(ConfigFile &&tmp); ConfigFile &operator=(ConfigFile const &rhs); // 2 void open(std::string const &fname); void setCommentHandling(Comment type); void setSearchCasing(SearchCasing type); const_iterator begin() const; const_iterator end() const; RE_iteratorPair beginEndRE(std::string const &re) const; // 1 RE_iteratorPair beginEndRE() const; // 2 const_iterator find(std::string const &target) const; const_iterator findRE(std::string const &re) const; std::string findKey(std::string const &key, size_t count = 1) const; std::string findKeyTail(std::string const &key, size_t count = 1) const; size_t index(size_t lineNr); // 1 size_t index(const_iterator const &iterator); // 2 std::string const &operator[](size_t idx) const; size_t size() const; }; #include "opstar.f" #include "oparrow.f" // Free members: bool operator==(RE_iterator const &lhs, RE_iterator const &rhs); #include "opneq.f" // RE_iterator != RE_iterator #include "opsub.f" // RE_iterator - RE_iterator } // FBB #endif bobcat-5.09.01/configfile/finder.f0000644000175000017500000000020414050437223015623 0ustar frankfrankinline bool ConfigFile_::finder(string const &haystack, string const &needle) { return haystack.find(needle) != string::npos; } bobcat-5.09.01/configfile/endre.f0000644000175000017500000000017014050437223015453 0ustar frankfrankinline ConfigFile_::const_RE_iterator ConfigFile_::endRE() const { return RE_iterator(d_vsIter, d_vsIter.size()); } bobcat-5.09.01/configfile/setsearchcasing.f0000644000175000017500000000016314050437223017526 0ustar frankfrankinline void ConfigFile_::setSearchCasing(SearchCasing type) { d_caseSensitive = type == SearchCaseSensitive; } bobcat-5.09.01/configfile/operatorindex.cc0000644000175000017500000000016414050437223017404 0ustar frankfrank#include "configfile.ih" std::string const &ConfigFile::operator[](size_t idx) const { return (*d_ptr)[idx]; } bobcat-5.09.01/configfile/README0000644000175000017500000000300514050437223015067 0ustar frankfrankAll lines are stored in the vector base class. When StoreIndices was specified the 0-based line indices of lines were stored in d_index. The member open clears the current contents and reinitializes all with the info read from the new file. At construction time comment handling (keep comment / remove comment), case-sensitive searching (sensitive / insensitive) and index storage (store / don't store) can be specified. It can't be modified with the open member, but overloaded assignment is supported and comment and letter case handling can be modified by set-members. The begin() and end() members return the iterators into the vector of configuration file lines (with continuation lines merged, and comment optionally removed). find(target): To find an element `target' in a configuration file find(target) can be used. It it handles case insensitive searches and uses findRE after replacing each character in target by an escape character. This turns the special RE characters into normal characters so findRE can be used fo the matching. findRE(target): here an RE is used to perform the match. It visits alle stored lines of the configuration file returning the first line for which the regular expression matched (using the `match' function in configfile.fh). findKey(key, count): find the value of the `count-th' occurrence of 'key value'. It calls searchFor to find the count-th occurrence of key. findKeyTail acts similarly, but doesn't allow anything to appear beyond value. searchfor(key, pattern, count): bobcat-5.09.01/configfile/open.cc0000644000175000017500000000144114050437223015461 0ustar frankfrank#include "configfile.ih" void ConfigFile_::open(string const &fname) { ifstream stream; Exception::open(stream, fname); d_line.clear(); // clear the vector d_index.clear(); // clear the line indices d_vsIter.clear(); // clear iterators to matching lines d_re.clear(); // clear a previously set search RE d_rawIndex = 0; // re-initialize the line-index of the // original file string line; while (nextLine(stream, line)) // add the lines to d_line { (this->*d_rawIndices)(); // maybe update the raw indices d_line.push_back(line); } } void ConfigFile::open(string const &fname) { d_ptr->open(fname); } bobcat-5.09.01/configfile/opsub.f0000644000175000017500000000015314050437223015507 0ustar frankfrankinline int operator-(RE_iterator const &lhs, RE_iterator const &rhs) { return lhs.d_idx - rhs.d_idx; } bobcat-5.09.01/configfile/operatorassign2.cc0000644000175000017500000000024414050437223017642 0ustar frankfrank#include "configfile.ih" ConfigFile &ConfigFile::operator=(ConfigFile const &rhs) { ConfigFile tmp(rhs); swap(d_ptr, tmp.d_ptr); return *this; } bobcat-5.09.01/configfile/casefinder.f0000644000175000017500000000027014050437223016462 0ustar frankfrankinline bool ConfigFile_::casefinder(string const &haystack, string const &needle) { return strcasestr(haystack.c_str(), needle.c_str()) != 0; } bobcat-5.09.01/configfile/end.cc0000644000175000017500000000015614050437223015270 0ustar frankfrank#include "configfile.ih" ConfigFile::const_iterator ConfigFile::end() const { return d_ptr->end(); } bobcat-5.09.01/configfile/trimleft.cc0000644000175000017500000000040514050437223016345 0ustar frankfrank#include "configfile.ih" void ConfigFile_::trimLeft(string &line) { // remove initial ws. string::size_type pos = line.find_first_not_of(" \t"); if (pos != string::npos) line.erase(0, pos); } bobcat-5.09.01/configfile/configfile.ih0000644000175000017500000000774614050437223016656 0ustar frankfrank#include "configfile" #include #include #include #include "../pattern/pattern" #include "../exception/exception" #include "../iuo/iuo" using namespace std; using namespace FBB; // Lines are stored with initial WS removed. // If a line ends in \, then the next line (initial WS removed) // is appended to the current line. // Information at and beyond the first # on individual lines is removed // if the rmComment flag is set to true (\# is converted to a #-character) // Then, lines containing only blanks and tabs are not stored namespace FBB { class ConfigFile_: public CFEnums_ { std::vector d_line; bool d_rmComment; bool d_caseSensitive; void (ConfigFile_::*d_rawIndices)(); size_t d_rawIndex; size_t d_nextIndex; std::vector d_index; // contains iterators to lines matching REs typedef std::vector::const_iterator VsIterator; typedef std::vector VsIterVector; VsIterVector d_vsIter; std::string d_re; mutable Pattern d_pattern; public: explicit ConfigFile_(Comment cType = KeepComment, SearchCasing sType = SearchCaseSensitive, Indices iType = IgnoreIndices); // Name of the config file explicit ConfigFile_(std::string const &fname, Comment cType = KeepComment, SearchCasing sType = SearchCaseSensitive, Indices iType = IgnoreIndices); ConfigFile_(ConfigFile_ const &rhs) = default; ConfigFile_(ConfigFile_ &&tmp) = default; ConfigFile_ &operator=(ConfigFile_ &&tmp) = default; ConfigFile_ &operator=(ConfigFile_ const &rhs) = default; void setCommentHandling(Comment type); // .i void setSearchCasing(SearchCasing type); // .i void open(std::string const &fname); const_iterator begin() const; // .i const_iterator end() const; // .i const_RE_iterator beginRE(std::string const &re); const_RE_iterator endRE() const; // .i std::pair beginEndRE(std::string const &re); const_iterator find(std::string const &target) const; const_iterator findRE(std::string const &re) const; std::string findKey(std::string const &key, size_t count); // .i std::string findKeyTail(std::string const &key, size_t count); // .i size_t index(size_t lineNr); // 1.i size_t index(const_iterator const &iterator); // 2.i std::string const &operator[](size_t idx) const; // opindex.i size_t size() const; // .i private: static void trimLeft(std::string &line); static void trimRight(std::string &line, bool appendNext); bool rmCommentAndEscapes(std::string &line); bool nextLine(std::istream &inStream, std::string &dest); void resetVsIter(std::string const &re); void storeIndex(); // called via d_rawIndices void ignoreIndex(); std::string searchFor(std::string const &keyPattern, size_t count); static bool finder(std::string const &haystack, // .i std::string const &needle); static bool casefinder(std::string const &haystack, // .i std::string const &needle); }; } // FBB #include "begin.f" #include "casefinder.f" #include "end.f" #include "endre.f" #include "finder.f" #include "findkey.f" #include "findkeytail.f" #include "index1.f" #include "index2.f" #include "opindex.f" #include "setcommenthandling.f" #include "setsearchcasing.f" #include "size.f" bobcat-5.09.01/configfile/begin.f0000644000175000017500000000013514050437223015443 0ustar frankfrankinline ConfigFile_::const_iterator ConfigFile_::begin() const { return d_line.begin(); } bobcat-5.09.01/configfile/reoperatorinc.cc0000644000175000017500000000014414050437223017373 0ustar frankfrank#include "configfile.ih" RE_iterator &RE_iterator::operator++() { ++d_idx; return *this; } bobcat-5.09.01/configfile/setcommenthandling.f0000644000175000017500000000014714050437223020245 0ustar frankfrankinline void ConfigFile_::setCommentHandling(Comment type) { d_rmComment = type == RemoveComment; } bobcat-5.09.01/configfile/configfile4.cc0000644000175000017500000000016414050437223016712 0ustar frankfrank#include "configfile.ih" ConfigFile::ConfigFile(ConfigFile const &rhs) : d_ptr(new ConfigFile_(*rhs.d_ptr)) {} bobcat-5.09.01/configfile/opstar.f0000644000175000017500000000013214050437223015664 0ustar frankfrankinline std::string const &RE_iterator::operator*() const { return *d_vsIter[d_idx]; } bobcat-5.09.01/configfile/reiterator1.cc0000644000175000017500000000020514050437223016756 0ustar frankfrank#include "configfile.ih" RE_iterator::RE_iterator(VsIterVector const &vsIter, size_t idx) : d_vsIter(vsIter), d_idx(idx) {} bobcat-5.09.01/configfile/rmcommandandescapes.cc0000644000175000017500000000210514050437223020522 0ustar frankfrank#include "configfile.ih" bool ConfigFile_::rmCommentAndEscapes(string &line) { size_t pos = 0; size_t lastBackslash = 0; while (true) { size_t hit; // change \\ to one backslash if ((hit = line.find("\\\\", pos)) != string::npos) line.erase(lastBackslash = hit, 1); else if ((hit = line.find("\\#", pos)) != string::npos) line.replace(hit, 2, "#"); // replace by # else { if ((hit = line.find('#', pos)) != string::npos) { lastBackslash = string::npos; line.erase(hit); // erase comment } if (line.length() > lastBackslash + 1 && *line.rbegin() == '\\') { line.resize(line.length() - 1); return true; } return false; } pos = hit + 1; // try again beyond the // last-checked character } } bobcat-5.09.01/configfile/end.f0000644000175000017500000000013114050437223015121 0ustar frankfrankinline ConfigFile_::const_iterator ConfigFile_::end() const { return d_line.end(); } bobcat-5.09.01/configfile/setsearchcasing.cc0000644000175000017500000000016514050437223017670 0ustar frankfrank#include "configfile.ih" void ConfigFile::setSearchCasing(SearchCasing type) { d_ptr->setSearchCasing(type); } bobcat-5.09.01/configfile/configfile2.cc0000644000175000017500000000061114050437223016705 0ustar frankfrank#include "configfile.ih" ConfigFile_::ConfigFile_(string const &fname, Comment cType, SearchCasing sType, Indices iType) : ConfigFile_(cType, sType, iType) { open(fname); } ConfigFile::ConfigFile(string const &fname, Comment cType, SearchCasing sType, Indices iType) : d_ptr(new ConfigFile_(fname, cType, sType, iType)) {} bobcat-5.09.01/configfile/beginre.cc0000644000175000017500000000026714050437223016140 0ustar frankfrank#include "configfile.ih" ConfigFile_::const_RE_iterator ConfigFile_::beginRE(string const &re) { if (re != d_re) resetVsIter(re); return RE_iterator(d_vsIter, 0); } bobcat-5.09.01/configfile/findkey.f0000644000175000017500000000022114050437223016004 0ustar frankfrankinline string ConfigFile_::findKey(string const &keyPattern, size_t count) { return searchFor("^\\s*" + keyPattern + "\\s+(\\S+)", count); } bobcat-5.09.01/configfile/begin.cc0000644000175000017500000000016214050437223015603 0ustar frankfrank#include "configfile.ih" ConfigFile::const_iterator ConfigFile::begin() const { return d_ptr->begin(); } bobcat-5.09.01/configfile/size.f0000644000175000017500000000010614050437223015327 0ustar frankfrankinline size_t ConfigFile_::size() const { return d_line.size(); } bobcat-5.09.01/configfile/findkeytail.cc0000644000175000017500000000050614050437223017024 0ustar frankfrank#include "configfile.ih" // findKeyTail("key:") - // trimmed text following key. initial ws before // key should not be specified: skipped by findKeyTail. string ConfigFile::findKeyTail(string const &keyPattern, size_t count) const { return d_ptr->findKeyTail(keyPattern, count); } bobcat-5.09.01/configfile/destructor.cc0000644000175000017500000000011214050437223016710 0ustar frankfrank#include "configfile.ih" ConfigFile::~ConfigFile() { delete d_ptr; } bobcat-5.09.01/configfile/operatorassign.cc0000644000175000017500000000020414050437223017554 0ustar frankfrank#include "configfile.ih" ConfigFile &ConfigFile::operator=(ConfigFile &&tmp) { *d_ptr = move(*tmp.d_ptr); return *this; } bobcat-5.09.01/configfile/index1.cc0000644000175000017500000000015014050437223015704 0ustar frankfrank#include "configfile.ih" size_t ConfigFile::index(size_t lineNr) { return d_ptr->index(lineNr); } bobcat-5.09.01/configfile/oparrow.f0000644000175000017500000000016114050437223016047 0ustar frankfrankinline std::string const *RE_iterator::operator->() const { return &*d_vsIter[d_idx]; } bobcat-5.09.01/configfile/findkey.cc0000644000175000017500000000045414050437223016154 0ustar frankfrank#include "configfile.ih" // findKey("key:") - first ws-delimited field following key. initial ws before // key should not be specified: skipped by findKey. string ConfigFile::findKey(string const &keyPattern, size_t count) const { return d_ptr->findKey(keyPattern, count); } bobcat-5.09.01/configfile/storeindex.cc0000644000175000017500000000014014050437223016677 0ustar frankfrank#include "configfile.ih" void ConfigFile_::storeIndex() { d_index.push_back(d_rawIndex); } bobcat-5.09.01/configfile/opneq.f0000644000175000017500000000015014050437223015476 0ustar frankfrankinline bool operator!=(RE_iterator const &lhs, RE_iterator const &rhs) { return not (lhs == rhs); } bobcat-5.09.01/configfile/trimright.cc0000644000175000017500000000035014050437223016527 0ustar frankfrank#include "configfile.ih" void ConfigFile_::trimRight(string &line, bool appendNext) { if (appendNext) return; size_t pos = line.find_last_not_of(" \t"); if (pos != string::npos) line.resize(pos + 1); } bobcat-5.09.01/configfile/beginendre.cc0000644000175000017500000000043414050437223016623 0ustar frankfrank#include "configfile.ih" ConfigFile::RE_iteratorPair ConfigFile::beginEndRE(std::string const &re) const { auto begin = d_ptr->beginRE(re); RE_iteratorPair ret(begin, d_ptr->endRE()); return ret; } bobcat-5.09.01/configfile/resetvsiter.cc0000644000175000017500000000050114050437223017073 0ustar frankfrank#include "configfile.ih" void ConfigFile_::resetVsIter(string const &re) { d_vsIter.clear(); d_re = re; d_pattern.setPattern(re, d_caseSensitive); for(auto start = begin(), stop = end(); start != stop; ++start) { if (d_pattern << *start) d_vsIter.push_back(start); } } bobcat-5.09.01/configfile/searchfor.cc0000644000175000017500000000113014050437223016467 0ustar frankfrank#include "configfile.ih" // The keyPat *must* have a (...) subexpression, defining what to return string ConfigFile_::searchFor(string const &keyPat, size_t count) { string ret; if (count == 0) throw Exception{} << "findKey/-Tail: count must be > 0"; beginRE(keyPat); if (count <= d_vsIter.size()) // at least 'count' lines { // are required d_pattern << *d_vsIter[count - 1]; // if so, return the tail of ret = d_pattern[d_pattern.end() - 1]; // line[count - 1] } return ret; } bobcat-5.09.01/configfile/findre.cc0000644000175000017500000000070414050437223015770 0ustar frankfrank#include "configfile.ih" vector::const_iterator ConfigFile_::findRE(string const &re) const { d_pattern.setPattern(re, d_caseSensitive); return find_if( begin(), end(), [&](string const &str) { return d_pattern << str; } ); } vector::const_iterator ConfigFile::findRE(string const &re) const { return d_ptr->findRE(re); } bobcat-5.09.01/configfile/configfile3.cc0000644000175000017500000000016714050437223016714 0ustar frankfrank#include "configfile.ih" ConfigFile::ConfigFile(ConfigFile &&tmp) : d_ptr( new ConfigFile_(move(*tmp.d_ptr) )) {} bobcat-5.09.01/configfile/driver/0000755000175000017500000000000014050437223015504 5ustar frankfrankbobcat-5.09.01/configfile/driver/build0000755000175000017500000000140414050437223016530 0ustar frankfrank#!/bin/bash ln -sf .. configdir case $1 in (b) rm configfile configfile.ih g++ -DBOBCAT --static --std=c++2a -I../../tmp -o driver driver.cc \ -L../../tmp/lib -lbobcat -s ;; (o) g++ --std=c++2a -o driver *.cc ../tmp/o/*.o -lbobcat -s ;; (c) g++ --std=c++2a -o driver *.cc -lbobcat -s ;; (l) g++ --std=c++2a -o driver -Iconfigdir *.cc \ -L../tmp -lconfigfile -lbobcat -s ;; (*) echo $0 b links to bobcat built by 'build libraries all' echo $0 o links to the files in ../tmp/o echo $0 c links to the files in the current dir only echo $0 l links to \*.cc, ../libconfig.a and std bobcat rm -f driver ;; esac rm -f configdir bobcat-5.09.01/configfile/driver/driver.cc0000644000175000017500000000435514050437223017315 0ustar frankfrank#include #include #include #ifdef BOBCAT #include #else #include "configdir/configfile" #endif using namespace std; using namespace FBB; int main(int argc, char **argv) try { if (argc == 1) { cout << "Need name of configfile\n"; return 1; } ConfigFile cf(argv[1], ConfigFile::RemoveComment, ConfigFile::SearchCaseInsensitive, ConfigFile::StoreIndices); cout << "opened: " << argv[1] << '\n'; cout << "Got " << cf.size() << " lines\n"; cf.open(argv[1]); cout << "opened again: " << argv[1] << "\n" "Got " << cf.size() << " lines\n" << cf[0] << " from line " << cf.index(0) << "\n" "================\n"; copy(cf.begin(), cf.end(), ostream_iterator(cout, "\n")); while (true) { cout << "Enter literal to search for (or just Enter): "; string param; if (!getline(cin, param) || !param.length()) break; auto it = cf.find(param); if (it != cf.end()) cout << *it << ": at index " << cf.index(it) << '\n'; else cout << " < not found > " << '\n'; } while (true) { cout << "Enter RE to search for (or just Enter): "; string param; if (!getline(cin, param) || !param.length()) break; auto it = cf.findRE(param); if (it != cf.end()) cout << *it << ": at index " << cf.index(it) << '\n'; else cout << " < not found > " << '\n'; } while (true) { cout << "Finding all lines matching a RE.\n" "Enter the RE (or just Enter): "; string param; if (!getline(cin, param) || !param.length()) return 0; auto [begin, end] = cf.beginEndRE(param); cout << "Counting: " << (end - begin) << " matches\n"; while (begin != end) { cout << *begin << '\n'; ++begin; } cout << "value of findKey: " << cf.findKey(param) << '\n'; } } catch (exception const &e) { cout << "Fatal: " << e.what() << '\n'; return 1; } bobcat-5.09.01/configfile/driver/config0000644000175000017500000000074114050437223016676 0ustar frankfrank# these options are also defined by driver.cc option option-value: \#xyz option-value: #xyz # other lines may also be provided, lines starting with # are comment a line not containing an option # this is ignored noline: this one too line: this is found this is not a line containing line: at the beginning of the line line: this one is line: what about this one? \ it's extending over multiple lines and there may, of course, be more lines in this file bobcat-5.09.01/configfile/driver/driver.rc0000644000175000017500000000033414050437223017325 0ustar frankfrank# This is comment hello (at idx 1) # void rematch one multiple \ lines (starts at idx 2) another \ \ set of \ lines (starts at idx 4) rematch two # comment only history history-one two bobcat-5.09.01/configfile/operatoreqre.cc0000644000175000017500000000026514050437223017233 0ustar frankfrank#include "configfile.ih" namespace FBB { bool operator==(RE_iterator const &lhs, RE_iterator const &rhs) { return lhs.d_idx == rhs.d_idx && lhs.d_vsIter == rhs.d_vsIter; } } bobcat-5.09.01/contrib/0000755000175000017500000000000014050437223013544 5ustar frankfrankbobcat-5.09.01/contrib/realpath.c0000644000175000017500000000161414050437223015512 0ustar frankfrank#include #include #include #include int main(int argc, char **argv) { char *cp; if (argc == 1) /* no arguments: give usage info */ { printf("Provide %s with a (relative or absolute) path name: its " "absolute\n" "path is written to the std. output stream (and the program\n" "returns 0)\n" "an empty string is written if the path could not be " "determined\n" "in which case the program returns realpath(3)'s error " "code\n", argv[0]); return 0; } cp = realpath(argv[1], 0); if (cp == 0) return errno; printf("%s\n", cp); free(cp); return 0; } bobcat-5.09.01/contrib/c-conf0000755000175000017500000002771114050437223014647 0ustar frankfrank#!/usr/bin/perl use strict; use Getopt::Std; # Globals my $VER = "1.05"; # 1.05 [KK 2006-09-28] Flag -s (silent) implemented. Usage text updated. # 1.04 [KK 2006-09-05] C-compilers: gcc/g++ get selected first, instead of # cc/c++. Helps HP-UX ports. [Thanks, Bernd Krumboeck.] # 1.03 [KK 2006-07-19] 'subfiles' keeps track of visited dirs incase of # recursion. Testing is now by inode, used to be by name. # 1.02 [KK 2006-06-01] 'findbin' searches for .exe too now, for Cygwin support # 1.01 [KK 2005-09-29] Implemented context-sensitive help via -h. # Action 'header' implemented. # 1.00 [KK 2005-09-28] First version # Configuration my @def_headerdirs = ('/usr/include', '/usr/local/include', "$ENV{HOME}/include", ); my @def_libdirs = ('/usr/lib', '/usr/local/lib', '/usr/ucblib', "$ENV{HOME}/lib", ); my @c_compilers = ('gcc', 'cc'); my @cpp_compilers = ('g++', 'c++'); # Globals my %opts; my $base; my @warnings; my $printed; my @headerdirs; my @libdirs; # Show usage and croak sub usage { die <<"ENDUSAGE" This is c-conf, the C compilation configuration helper V$VER Copyright (c) e-tunity. Contact for information. Usage: $base [flags] header FILE.H [FILE.H...] Searches for directories containing the named header(s), returns appropriate -I flags. $base [flags] headerdir DIR [DIR...]: Searches for directory containing headers, returns appropriate -I flags. $base [flags] ifheader FILE.H DEFINE Searches for the named header. If found, a compilation flag -DDEFINE is returned, indicating that the header is found. $base [flags] libfunction FUNC DEFINE Creates a small program that tries to use FUNC. If this succeeds, a -DDEFINE=1 flag is returned. $base [flags] lib NAME [NAME...]: Searches for libNAME.{a,so,...}, returns appropriate -L and -l flags. $base [flags] so-name NAME: Returns filename of a shared-object for NAME, e.g. libNAME.so $base [flags] so-cflags: Returns compilation flags to build shared objects $base [flags] so-lflags: Returns linkage flags to produce a shared-object library $base [flags] c-compiler: Returns name of C compiler $base [flags] c++-compiler: Returns name of C++ compiler Optional flags: -h: to show short help for an action, e.g. try '$base -h so-name' -s: to suppress showing of warnings -v: to show verbose messages -I DIR[,DIR..]: to add DIR(s) to the searchpath for headers, default searchpath is @headerdirs -L DIR[,DIR..]: to add DIR(s) to the searchpath for libraries, default searchpath is @libdirs Meaningful output is returned on stdout. Verbose messages, warnings and errors go to stderr. ENDUSAGE } # Issue a warning sub warning { push (@warnings, "@_"); } # Show a message sub msg { return unless ($opts{v}); print STDERR ("$base: ", @_); } # Show help info if -h was given sub checkhelp { return unless ($opts{h}); print STDERR (@_); exit (1); } # Basename / dirname of a file. sub basename ($) { my $name = shift; $name =~ s{.*/}{}; return ($name); } sub dirname ($) { my $name = shift; return (undef) unless ($name =~ /\//); $name =~ s{/[^/]$}{}; return ($name); } # Get the uname. sub uname() { my $ret = `uname`; chomp ($ret); msg ("uname: $ret\n"); return ($ret); } # Find a binary along the path. sub findbin($) { my $bin = shift; msg ("Looking for executable '$bin'\n"); foreach my $d (split (/:/, $ENV{PATH})) { if (-x "$d/$bin" or -f "$d/bin.exe") { msg ("Found as '$d/$bin'\n"); return ("$d/$bin"); } } msg ("Not found!\n"); } # Recursively determine the files under a given dir. my %_dir_visited; sub subfiles ($$$) { my ($dir, $mask, $recursive) = @_; %_dir_visited = () unless ($recursive); my ($dev, $ino) = stat($dir) or return (undef); my $tag = sprintf ("%d-%d", $dev, $ino); if ($_dir_visited{$tag}) { msg ("Path '$dir' was already visited (as $_dir_visited{$tag})\n"); return (undef); } $_dir_visited{$tag} = $dir; msg ("Scanning for '$mask' under '$dir'\n"); if (! -d $dir) { msg ("Scan path ends, '$dir' is not an accessible directory\n"); return (undef); } my @ret = (); foreach my $f (glob ("$dir/$mask")) { if (-f $f) { push (@ret, $f); msg ("Found a hit as '$f'\n"); } msg ("Hits so far: ", $#ret + 1, "\n") if ($#ret > -1); } foreach my $d (glob ("$dir/*")) { next unless (-d $d); msg ("Recursing from '$dir' into '$d'\n"); my @subret = subfiles ("$d", $mask, 1); my $added = 0; foreach my $f (@subret) { if (-f $f) { push (@ret, $f); $added++; } } msg ("Added ", $added, " hits from '$d'\n") if ($added); } if ($#ret > -1) { msg ("Found ", $#ret + 1, " entries matching '$mask' under '$dir'\n"); return (@ret); } else { # msg ("No entries matching '$mask' under '$dir' found\n"); return (undef); } } # Output stuff sub output { print (' ') if ($printed++); print (@_); } # Find a header, output a define if found. sub if_header { checkhelp <<"ENDHELP"; 'ifheader' tries to find a header file in the 'include' directories. When found, a define-flag for the C compiler is returned. E.g.: $base ifheader malloc.h HAVE_MALLOC_H (may return -DHAVE_MALLOC_H) Use in a Makefile as in: CFLAGS = \$(CFLAGS) \$(shell c-conf ifheader malloc.h HAVE_MALLOC_H Then in a C source as: #ifdef HAVE_MALLOC_H #include #endif ENDHELP usage() if ($#_ != 1); my ($h, $def) = @_; msg ("Looking for '$h'\n"); foreach my $d (@headerdirs) { if (-f "$d/$h") { output ("-D$def"); return; } } } # Find a header sub header { checkhelp <<"ENDHELP"; 'header' locates one or more C headers in the 'include' directories. E.g.: $base header e-lib.h stdio.h (may return -I/usr/include -I/usr/e/include) Use in a Makefile as in: CFLAGS = -C -Wall \$(shell c-conf header e-lib.h) Then in a C source as: #include ENDHELP usage() if ($#_ == -1); foreach my $h (@_) { msg ("Looking for '$h'\n"); my $found = 0; foreach my $d (@headerdirs) { msg ("Trying '$d/$h'\n"); if (-f "$d/$h") { $found++; msg ("Found\n"); output ("-I$d"); last; } } warning ("Failed to locate header '$h' in @headerdirs\n") unless ($found); } } # Find a header directory sub headerdir { checkhelp <<"ENDHELP"; 'headerdir' locates directories under which (in steps) C headers are E.g.: $base headerdir libxml2 (may return '-I/usr/include/libxml2') Use in a Makefile as in: CFLAGS = -C -Wall \$(shell c-conf headerdir libxml2) Then in a C source as: #include ENDHELP usage() if ($#_ == -1); foreach my $headerdir (@_) { msg ("Looking for header dir '$headerdir'\n"); my $found = 0; foreach my $d (@headerdirs) { msg ("Trying as '$d/$headerdir'\n"); my $target = "$d/$headerdir"; if (subfiles ($target, '*.h', 0)) { output ("-I$target"); $found++; } } warning ("Header dir '$headerdir' not found\n") unless ($found); } } # Find a library sub lib { checkhelp <<"ENDHELP"; 'lib' generates the linkage flags for a given library name. The name is bare, without 'lib' and '.so' and the like. E.g.: $base lib xml2 (may return '-L/usr/lib -lxml2') Use in a Makefile as in: LDFLAGS = \$(shell c-conf lib xml2) ENDHELP usage() if ($#_ == -1); foreach my $lib (@_) { msg ("Looking for lib '$lib'\n"); my $found = 0; foreach my $d (@libdirs) { msg ("Trying under '$d'\n"); my $hit = (subfiles ($d, "lib$lib.*", 0))[0]; if ($hit) { msg ("Found as '$hit'\n"); $found++; $hit =~ s{/[^/]*$}{}; output ("-L$hit -l$lib"); } } warning ("Library '$lib' not found\n") unless ($found); } } # Compilation flags to make a so-ready object. sub so_cflags { checkhelp <<"ENDHELP"; 'so-cflags' returns the compilation flags that are necessary when building objects for a shared library. E.g.: $base so-cflags (may return '-fPIC') Use in a Makefile as in: CFLAGS = -c -g -Wall \$(shell c-conf so-cflags) ENDHELP usage() if ($#_ > -1); if (uname() eq 'Darwin') { output ('-fPIC'); } elsif (uname() eq 'Linux') { output ('-fpic'); } } # Linkage flags to make an so. sub so_lflags { checkhelp << "ENDHELP"; 'so-lflags' returns the linkage flags that are necessary when combining objects into a shared library. E.g.: $base so-lflags (may return '-dynamiclib -Wl,-single_module') Use in a Makefile as in: MY_SO = \$(shell c-conf so-name my) \$(MY_SO): *.o \$(CC) -o \$(MY_SO) \$(shell c-conf so-lflags) *.o ENDHELP usage() if ($#_ > -1); my $lib = shift; if (uname() eq 'Darwin') { output ("-dynamiclib -Wl,-single_module"); } else { output ("-shared"); } } # Get the C compiler sub c_compiler { checkhelp <<"ENDHELP"; 'c-compiler' tries to find a C compiler and returns its (bare) name. E.g.: $base c-compiler -> gcc ENDHELP usage() if ($#_ > -1); foreach my $c (@c_compilers) { if (findbin ($c)) { output ($c); return; } } warning ("No C compiler found\n"); } # Get the C++ compiler sub cpp_compiler { checkhelp <<"ENDHELP"; 'c++-compiler' tries to find a C++ compiler and returns its (bare) name. E.g.: $base c++-compiler -> g++ ENDHELP usage() if ($#_ > -1); foreach my $c (@cpp_compilers) { if (findbin ($c)) { output ($c); return; } } warning ("No C++ compiler found\n"); } # Get the name for an SO. sub so_name { checkhelp <<"ENDHELP"; 'so-name' returns the filename of a shared library, based on the LIB argument. E.g.: $base so-name test -> libtest.so ENDHELP usage() if ($#_ != 0); my $name = shift; my $dir = dirname ($name); my $base = basename ($name); my $dest; if (uname() eq 'Darwin') { $dest = "lib$base.dylib"; } else { $dest = "lib$base.so"; } if ($dir ne '') { output ("$dir/$dest"); } else { output ("$dest"); } } # Check that a libfunction is present. sub libfunction { checkhelp <<"ENDHELP"; 'libfunction' checks whether a library function is present. There are two arguments: the function to check, and a define to output when the function is found. The output is a -D flag for the compiler commandline. E.g.: $base libfunction printf HAVE_PRINTF -> -DHAVE_PRINTF=1 $base libfunction foo_bar HAVE_FOOBAR -> (nothing) ENDHELP usage() if ($#_ != 1); my ($func, $def) = @_; # Create a temp .c file. my $src = "/tmp/$$.c"; my $dst = "/tmp/$$.out"; open (my $of, ">$src") or die ("Cannot write $src: $!\n"); print $of ("main () {\n", " void $func (void);\n", " $func();\n", "}\n"); close ($of); my $cc; foreach my $c (@c_compilers) { if (findbin ($c)) { $cc = $c; last; } } die ("Failed to locate C compiler\n") if ($cc eq ''); my $ret = system ("$cc -o $dst $src >/dev/null 2>&1"); unlink ($src, $dst); output ("-D$def=1") if ($ret == 0); } # Main starts here $base = $0; $base =~ s{.*/}{}; usage () unless (getopts ('vhI:L:s', \%opts)); foreach my $d (split (/,/, $opts{L})) { push (@libdirs, $d); } foreach my $d (split (/,/, $opts{I})) { push (@headerdirs, $d); } push (@libdirs, @def_libdirs); push (@headerdirs, @def_headerdirs); my $action = shift (@ARGV); if ($action eq 'header') { header (@ARGV); } elsif ($action eq 'headerdir') { headerdir (@ARGV); } elsif ($action eq 'lib') { lib (@ARGV); } elsif ($action eq 'so-cflags') { so_cflags (@ARGV); } elsif ($action eq 'so-lflags') { so_lflags (@ARGV); } elsif ($action eq 'c-compiler') { c_compiler(@ARGV); } elsif ($action eq 'c++-compiler') { cpp_compiler(@ARGV); } elsif ($action eq 'so-name') { so_name (@ARGV); } elsif ($action eq 'ifheader') { if_header (@ARGV); } elsif ($action eq 'libfunction') { libfunction (@ARGV); } else { usage (); } print ("\n") if ($printed); if ($#warnings > -1) { foreach my $w (@warnings) { print STDERR ("$base WARNING: $w") unless ($opts{s}); } exit (1); } exit (0); bobcat-5.09.01/coutextractor/0000755000175000017500000000000014050437223015012 5ustar frankfrankbobcat-5.09.01/coutextractor/coutextractor2.cc0000644000175000017500000000022414050437223020307 0ustar frankfrank#include "coutextractor.ih" CoutExtractor::CoutExtractor(StdMode mode, size_t bufSize) : IUO::ExtractorBase(bufSize), d_modeFun(close) {} bobcat-5.09.01/coutextractor/coutextractor0000644000175000017500000000067514050437223017653 0ustar frankfrank#ifndef INCLUDED_BOBCAT_COUTEXTRACTOR_ #define INCLUDED_BOBCAT_COUTEXTRACTOR_ #include namespace FBB { class CoutExtractor: public IUO::ExtractorBase { void (*d_modeFun)(); public: CoutExtractor(size_t bufSize = 100); CoutExtractor(StdMode mode, size_t bufSize = 100); private: void childRedirections() override; static void close(); }; } // namespace FBB #endif bobcat-5.09.01/coutextractor/close.cc0000644000175000017500000000043614050437223016431 0ustar frankfrank#include "coutextractor.ih" void CoutExtractor::close() // static { ::close(STDIN_FILENO); // close and reopen std file descriptors ::close(STDERR_FILENO); ::open("/dev/null", O_RDONLY); // reopen stdin ::open("/dev/null", O_WRONLY); // reopen stderr } bobcat-5.09.01/coutextractor/childredirections.cc0000644000175000017500000000027414050437223021022 0ustar frankfrank#include "coutextractor.ih" void CoutExtractor::childRedirections() { (*d_modeFun)(); // optionally close STDIN and STDERR childOutPipe().writtenBy(STDOUT_FILENO); } bobcat-5.09.01/coutextractor/coutextractor.ih0000644000175000017500000000015414050437223020242 0ustar frankfrank#include "coutextractor" #include #include using namespace std; using namespace FBB; bobcat-5.09.01/coutextractor/coutextractor1.cc0000644000175000017500000000021014050437223020301 0ustar frankfrank#include "coutextractor.ih" CoutExtractor::CoutExtractor(size_t bufSize) : IUO::ExtractorBase(bufSize), d_modeFun(noClose) {} bobcat-5.09.01/coutextractor/driver/0000755000175000017500000000000014050437223016305 5ustar frankfrankbobcat-5.09.01/coutextractor/driver/build0000755000175000017500000000017414050437223017334 0ustar frankfrank#!/bin/bash g++ -Wall -odriver driver.cc -L../../extractorbase/tmp -lextractorbase \ -L../tmp -Lcoutextractor -lbobcat bobcat-5.09.01/coutextractor/driver/driver.cc0000644000175000017500000000065714050437223020117 0ustar frankfrank#include #include using namespace std; using namespace FBB; int main() { CoutExtractor extractor; extractor.execute("/bin/cat driver.cc"); cout << extractor.rdbuf(); cerr << "Returning: " << extractor.ret() << "\n" "again:\n"; extractor.execute("/bin/cat driver.cc"); cout << extractor.rdbuf(); cerr << "Returning: " << extractor.ret() << '\n'; } bobcat-5.09.01/cryptbuf/0000755000175000017500000000000014050437223013742 5ustar frankfrankbobcat-5.09.01/cryptbuf/cryptbuf.ih0000644000175000017500000000027414050437223016125 0ustar frankfrank#include "cryptbuf" //#include //#define XERR std::cerr << __FILE__": " #include #include "../exception/exception" using namespace std; using namespace FBB; bobcat-5.09.01/cryptbuf/md.f0000644000175000017500000000011514050437223014506 0ustar frankfrank// static inline EVP_CIPHER const *CryptBuf::md() const { return d_md; } bobcat-5.09.01/cryptbuf/cryptbuf1.cc0000644000175000017500000000054514050437223016174 0ustar frankfrank#include "cryptbuf.ih" CryptBuf::CryptBuf(char const *type, size_t bufSize) : EoiBuf(bufSize) { OpenSSL_add_all_ciphers(); d_md = EVP_get_cipherbyname(type); if (!d_md) { if (type == 0) type = "** unspecified cipher type **"; throw Exception{ 1 } << "CryptBuf `" << type << "' not available"; } } bobcat-5.09.01/cryptbuf/cryptbuf0000644000175000017500000000061114050437223015521 0ustar frankfrank#ifndef INCLUDED_BOBCAT_CRYPTBUF_ #define INCLUDED_BOBCAT_CRYPTBUF_ #include #include namespace FBB { class CryptBuf: public EoiBuf { EVP_CIPHER const *d_md; protected: CryptBuf(char const *type, size_t bufSize); EVP_CIPHER const *md() const; // .f }; #include "md.f" } // FBB #endif bobcat-5.09.01/c++std0000644000175000017500000000001414050437223013105 0ustar frankfrank--std=c++2a bobcat-5.09.01/csv4180/0000755000175000017500000000000014050437223013214 5ustar frankfrankbobcat-5.09.01/csv4180/tocr.cc0000644000175000017500000000020514050437223014467 0ustar frankfrank#include "csv4180.ih" bool CSV4180::toCr() { //cerr << __FILE__ "\n"; ++d_begin; d_state = CRSTATE; return true; } bobcat-5.09.01/csv4180/read1.cc0000644000175000017500000000033614050437223014521 0ustar frankfrank#include "csv4180.ih" istream &CSV4180::read1(istream &in) { d_state = START; d_in = ∈ if (not nextLine()) return in; while ((this->*s_fsa[d_state][peek()])()) ; return in; } bobcat-5.09.01/csv4180/adddq1.cc0000644000175000017500000000021714050437223014661 0ustar frankfrank#include "csv4180.ih" bool CSV4180::addDq1() { //cerr << __FILE__ "\n"; d_field += *d_begin++; d_state = DQ1; return true; } bobcat-5.09.01/csv4180/data.cc0000644000175000017500000000135114050437223014434 0ustar frankfrank#include "csv4180.ih" bool (CSV4180::*CSV4180::s_fsa[][nCharTypes])() = { // EOLN CR CHAR DQUOTE FIELDSEP { &CSV4180::end, &CSV4180::toCr, &CSV4180::addCh, &CSV4180::toDq1, &CSV4180::field }, // START { &CSV4180::end, &CSV4180::err, &CSV4180::err, &CSV4180::err, &CSV4180::err, }, // CRSTATE { &CSV4180::end, &CSV4180::toCr, &CSV4180::addCh, &CSV4180::err, &CSV4180::field }, // CHARSTATE { &CSV4180::req, &CSV4180::addDq1, &CSV4180::addDq1, &CSV4180::toDq2, &CSV4180::addDq1 }, // DQ1 { &CSV4180::end, &CSV4180::toCr, &CSV4180::err, &CSV4180::addDq1, &CSV4180::field }, // DQ2 }; bobcat-5.09.01/csv4180/header.f0000644000175000017500000000012214050437223014606 0ustar frankfrankinline CSV4180::StrVector const &CSV4180::header() const { return d_header; } bobcat-5.09.01/csv4180/release.f0000644000175000017500000000012014050437223014774 0ustar frankfrankinline CSV4180::DataVector CSV4180::release() { return std::move(d_data); } bobcat-5.09.01/csv4180/nextline.cc0000644000175000017500000000032414050437223015350 0ustar frankfrank#include "csv4180.ih" bool CSV4180::nextLine() { //cerr << __FILE__ "\n"; if (not getline(*d_in, d_str)) return false; d_begin = d_str.begin(); d_end = d_str.end(); return true; } bobcat-5.09.01/csv4180/read.cc0000644000175000017500000000107214050437223014436 0ustar frankfrank#include "csv4180.ih" size_t CSV4180::read(istream &in, size_t nLines) { size_t idx = 0; if (nLines == 0) nLines = ~0; for (; idx != nLines; ++idx) // read all required lines or stop { // once reading fails. if (not read1(in)) break; } if (nLines == static_cast(~0)) // at undetermined # lines: in.clear(); // reset `in' as it may contain // additional info return d_data.size(); } bobcat-5.09.01/csv4180/csv41800000644000175000017500000000741014050437223014251 0ustar frankfrank#ifndef INCLUDED_BOBCAT_CSV4180_ #define INCLUDED_BOBCAT_CSV4180_ // See RFC 4180: Common Format and MIME Type for CSV Files #include #include #include namespace FBB { class CSV4180 { typedef std::vector StrVector; typedef std::vector DataVector; enum State { START, CRSTATE, CHARSTATE, DQ1, DQ2, }; enum CharType { EOS, CR, // carriage return (\r) CHAR, DQUOTE, FIELDSEP, nCharTypes }; int d_fieldSep; size_t d_nRequired; bool (CSV4180::*d_verifyTypes)() = &CSV4180::nop; // data lines bool (CSV4180::*d_dropFields)() = &CSV4180::nop; // header fields bool d_setHeader = false; StrVector d_header; State d_state; std::string d_specs; std::string d_str; std::string::iterator d_begin; std::string::iterator d_end; std::string d_field; // the current field (complete or isn) StrVector d_last; // the fields of the last line DataVector d_data; // StrVectors of all processed lines std::istream *d_in; static bool (CSV4180::*s_fsa[][nCharTypes])(); public: // 1: determine nFields from the // 1st line or specify the // # required fields explicit CSV4180(size_t nFields = 0, bool header = false, char fieldSep = ','); // 2: specs specify requirements // of fields. X-fields must be // present but are omitted from // d_data lines and // d_header. Throws exception if // unsopported specification is // encountered. explicit CSV4180(std::string const &specs, bool header = false, char fieldSep = ','); // Copy and move operations are implicitly available std::istream &read1(std::istream &in); // in.fail(): error in input // data size_t read(std::istream &in, size_t nLines = 0); // read all csv // lines or specify the // # lines to read. size_t nValues() const; // # CSVs (available after // reading at least one line) StrVector const &header() const; // the header (or empty) std::string const &lastLine() const; // the most recently read // line from the istream DataVector const &data() const; // all csv lines DataVector release(); // release all csv lines void clear(size_t nFields = 0); // clear d_data, reset nFields private: void setSpecs(std::string const &specs); bool nop(); bool dropFields(); bool verifyTypes(); bool nextLine(); CharType peek(); bool addCh(); // s_fsa functions bool addDq1(); bool end(); bool err(); bool field(); bool req(); bool toCr(); bool toDq1(); bool toDq2(); }; #include "opextract.f" #include "nvalues.f" #include "header.f" #include "data.f" #include "release.f" #include "lastline.f" } // FBB #endif bobcat-5.09.01/csv4180/field.cc0000644000175000017500000000060314050437223014605 0ustar frankfrank#include "csv4180.ih" bool CSV4180::field() { //cerr << __FILE__ "\n"; ++d_begin; // skip the comma d_last.push_back(move(d_field)); // add the field to d_last, // preparing d_field for the next // field d_state = START; return true; } bobcat-5.09.01/csv4180/csv41801.cc0000644000175000017500000000024514050437223014715 0ustar frankfrank#include "csv4180.ih" CSV4180::CSV4180(size_t nFields, bool header, char fieldSep) : d_fieldSep(fieldSep), d_nRequired(nFields), d_setHeader(header) {} bobcat-5.09.01/csv4180/verifytypes.cc0000644000175000017500000000231714050437223016117 0ustar frankfrank#include "csv4180.ih" bool CSV4180::verifyTypes() try { // first element to inspect string::const_iterator indicator = d_specs.begin(); StrVector::iterator dest = d_last.begin(); // dest: points at next el. in d_header to keep, // src, indicator: point at next element to inspect in resp. d_header // and d_spec for ( StrVector::iterator src = dest, end = d_last.end(); src != end; ++indicator, ++src ) { switch (*indicator) { case 'X': // omit continue; // continue with the next src item case 'I': stoll(*src); break; case 'D': stold(*src); break; default: // accept all other (just 'S') as-is break; } *dest++ = *src; // accept this element } d_last.resize(dest - d_last.begin()); // remove superfluous entries return true; } catch (...) { d_in->setstate(ios::failbit); return false; } bobcat-5.09.01/csv4180/README0000644000175000017500000000550714050437223014103 0ustar frankfrank RFC 4180 Common Format and MIME Type for CSV Files October 2005 (https://www.ietf.org/rfc/rfc4180.txt) Text copied from the rfc4180.txt file: 2. Definition of the CSV Format While there are various specifications and implementations for the CSV format, there is no formal specification in existence, which allows for a wide variety of interpretations of CSV files. This section documents the format that seems to be followed by most implementations: 1. Each record is located on a separate line, delimited by a line break (CRLF). For example: aaa,bbb,ccc CRLF zzz,yyy,xxx CRLF 2. The last record in the file may or may not have an ending line break. For example: aaa,bbb,ccc CRLF zzz,yyy,xxx 3. There maybe an optional header line appearing as the first line of the file with the same format as normal record lines. This header will contain names corresponding to the fields in the file and should contain the same number of fields as the records in the rest of the file (the presence or absence of the header line should be indicated via the optional "header" parameter of this MIME type). For example: field_name,field_name,field_name CRLF aaa,bbb,ccc CRLF zzz,yyy,xxx CRLF 4. Within the header and each record, there may be one or more fields, separated by commas. Each line should contain the same number of fields throughout the file. Spaces are considered part of a field and should not be ignored. The last field in the record must not be followed by a comma. For example: aaa,bbb,ccc 5. Each field may or may not be enclosed in double quotes (however some programs, such as Microsoft Excel, do not use double quotes at all). If fields are not enclosed with double quotes, then double quotes may not appear inside the fields. For example: "aaa","bbb","ccc" CRLF zzz,yyy,xxx 6. Fields containing line breaks (CRLF), double quotes, and commas should be enclosed in double-quotes. For example: "aaa","b CRLF bb","ccc" CRLF zzz,yyy,xxx 7. If double-quotes are used to enclose fields, then a double-quote appearing inside a field must be escaped by preceding it with another double quote. For example: "aaa","b""bb","ccc" The ABNF grammar [2] appears as follows: file = [header CRLF] record (CRLF record)* [CRLF] header = name (FIELDSEP name)* record = field (FIELDSEP field)* name = field field = (escaped / non-escaped) escaped = DQUOTE (TEXTDATA / FIELDSEP / CR / LF / 2DQUOTE)* DQUOTE non-escaped = TEXTDATA* FIELDSEP = %x2C CR = %x0D DQUOTE = %x22 LF = %x0A CRLF = CR LF TEXTDATA = %x20-21 / %x23-2B / %x2D-7E bobcat-5.09.01/csv4180/setspecs.cc0000644000175000017500000000137014050437223015355 0ustar frankfrank#include "csv4180.ih" void CSV4180::setSpecs(string const &specs) { istringstream in(specs); while (true) { char ch; if (not (in >> ch)) // skips blanks break; ch = toupper(ch); if (ch == '-') ch = 'X'; else if (string("SIDX").find(ch) == string::npos) throw Exception{} << "CSV4180: specification `" << ch << "' not supported"; size_t repeat; if (not (in >> repeat)) { in.clear(); repeat = 1; } d_specs.append(repeat, ch); } d_verifyTypes = &CSV4180::verifyTypes; d_dropFields = &CSV4180::dropFields; } bobcat-5.09.01/csv4180/csv41802.cc0000644000175000017500000000036014050437223014714 0ustar frankfrank#include "csv4180.ih" CSV4180::CSV4180(string const &specs, bool header, char fieldSep) : d_fieldSep(fieldSep), d_setHeader(header) { setSpecs(specs); d_nRequired = d_specs.length(); // required # fields per line } bobcat-5.09.01/csv4180/csv4180.ih0000644000175000017500000000024014050437223014642 0ustar frankfrank#include "csv4180" // #include #include #include #include "../exception/exception" using namespace std; using namespace FBB; bobcat-5.09.01/csv4180/end.cc0000644000175000017500000000125114050437223014270 0ustar frankfrank#include "csv4180.ih" bool CSV4180::end() { //cerr << __FILE__ "\n"; d_last.push_back(move(d_field)); if (d_nRequired == 0) d_nRequired = d_last.size(); else if (d_last.size() != d_nRequired) { d_in->setstate(ios::failbit); d_setHeader = false; return false; } if (not d_setHeader) { if ( (this->*d_verifyTypes)() ) d_data.push_back(move(d_last)); } else { d_header = move(d_last); // setting the header clears // d_last (this->*d_dropFields)(); d_setHeader = false; } return false; } bobcat-5.09.01/csv4180/dropfields.cc0000644000175000017500000000171514050437223015662 0ustar frankfrank#include "csv4180.ih" bool CSV4180::dropFields() { size_t pos = d_specs.find('X'); if (pos == string::npos) // no fields to remove return true; // first element to keep StrVector::iterator dest = d_header.begin() + pos; // indicator beyond 1st X string::const_iterator indicator = d_specs.begin() + pos + 1; // dest: points at next el. in d_header to keep, // src, indicator: point at next element to inspect in resp. d_header // and d_spec for ( StrVector::iterator src = dest + 1, end = d_header.end(); src != end; ++indicator, ++src ) { if (*indicator != 'X') // keep this element *dest++ = *src; } d_header.resize(dest - d_header.begin()); // remove superfluous entries return true; } bobcat-5.09.01/csv4180/peek.cc0000644000175000017500000000043014050437223014444 0ustar frankfrank#include "csv4180.ih" CSV4180::CharType CSV4180::peek() { if (d_begin == d_end) return EOS; switch (int ch = *d_begin) { case '\r': return CR; case '"': return DQUOTE; default: return ch == d_fieldSep ? FIELDSEP : CHAR; } } bobcat-5.09.01/csv4180/nop.cc0000644000175000017500000000010014050437223014306 0ustar frankfrank#include "csv4180.ih" bool CSV4180::nop() { return true; } bobcat-5.09.01/csv4180/clear.cc0000644000175000017500000000022714050437223014612 0ustar frankfrank#include "csv4180.ih" void CSV4180::clear(size_t nFields) { d_nRequired = nFields; d_data.clear(); d_header.clear(); d_str.clear(); } bobcat-5.09.01/csv4180/addch.cc0000644000175000017500000000022414050437223014564 0ustar frankfrank#include "csv4180.ih" bool CSV4180::addCh() { //cerr << __FILE__ "\n"; d_field += *d_begin++; d_state = CHARSTATE; return true; } bobcat-5.09.01/csv4180/data.f0000644000175000017500000000011714050437223014273 0ustar frankfrankinline CSV4180::DataVector const &CSV4180::data() const { return d_data; } bobcat-5.09.01/csv4180/opextract.f0000644000175000017500000000013614050437223015374 0ustar frankfrankinline std::istream &operator>>(std::istream &in, CSV4180 &csv) { return csv.read1(in); } bobcat-5.09.01/csv4180/req.cc0000644000175000017500000000046614050437223014320 0ustar frankfrank#include "csv4180.ih" bool CSV4180::req() { //cerr << __FILE__ "\n"; if (not nextLine()) // continue at the next line return false; d_field += '\n'; // indicate continuation by adding // '\n' return true; } bobcat-5.09.01/csv4180/err.cc0000644000175000017500000000020114050437223014304 0ustar frankfrank#include "csv4180.ih" bool CSV4180::err() { //cerr << __FILE__ "\n"; d_in->setstate(ios::failbit); return false; } bobcat-5.09.01/csv4180/nvalues.f0000644000175000017500000000010314050437223015032 0ustar frankfrankinline size_t CSV4180::nValues() const { return d_nRequired; } bobcat-5.09.01/csv4180/todq1.cc0000644000175000017500000000020214050437223014545 0ustar frankfrank#include "csv4180.ih" bool CSV4180::toDq1() { //cerr << __FILE__ "\n"; ++d_begin; d_state = DQ1; return true; } bobcat-5.09.01/csv4180/lastline.f0000644000175000017500000000011214050437223015170 0ustar frankfrankinline std::string const &CSV4180::lastLine() const { return d_str; } bobcat-5.09.01/csv4180/todq2.cc0000644000175000017500000000020214050437223014546 0ustar frankfrank#include "csv4180.ih" bool CSV4180::toDq2() { //cerr << __FILE__ "\n"; ++d_begin; d_state = DQ2; return true; } bobcat-5.09.01/csv4180/driver/0000755000175000017500000000000014050437223014507 5ustar frankfrankbobcat-5.09.01/csv4180/driver/build0000755000175000017500000000162314050437223015536 0ustar frankfrank#!/bin/bash rm -f driver case $1 in (tmp) echo "g++ -c driver.cc" g++ -I../../tmp -c driver.cc || exit 1 g++ -o driver driver.o -L../../tmp/lib -lbobcat ;; (lib) echo "g++ -c driver.cc" g++ -I../../tmp -o driver.o -c driver.cc || exit 1 g++ -o driver driver.o -lbobcat ;; (loc) echo "g++ -c driver.cc" g++ -Wall -I. -o driver.o -c driver.cc || exit 1 g++ -o driver driver.o -L../tmp -lcsv4180 -lbobcat ;; (*) echo " Usage: build tmp - build the driver using the shared library created in ../../tmp/lib build lib - build the driver using the shared bobcat library installed in the standard location for shared libs build loc - build the driver using the css4180 library in ../tmp and the standard bobcat library " exit 1 ;; esac bobcat-5.09.01/csv4180/driver/driver.cc0000644000175000017500000000212514050437223016311 0ustar frankfrank//man1 #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) { //= // if (argc == 1) // cout << "arg1: file containing csv lines\n"; // CSV4180 csv{ "SXS" }; // CSV4180 csv{ "SXS", true }; //man2 CSV4180 csv; // this processes 'input' //= // CSV4180 csv{0, false, ';'}; // uncomment this to process 'semicols' // CSV4180 csv{3}; // CSV4180 csv{3, true}; // cout << "? "; // if (not csv.read1(cin)) // { // cerr << "Error in input line\n"; // return 0; // } //man3 size_t nLines = csv.read(cin); cerr << nLines << " lines were read\n"; if (not csv.header().empty()) { cerr << "header: " << '\n'; for (auto const &field: csv.header()) cerr << " `" << field << "'\n"; } cerr << "# CSV values: " << csv.nValues() << '\n'; for (auto const &line: csv.data()) { cerr << "Line:\n"; for (auto const &entry: line) cerr << " `" << entry << "'\n"; } } //= bobcat-5.09.01/csv4180/driver/input0000644000175000017500000000002214050437223015563 0ustar frankfranka,b,c d,e,f g,h,i bobcat-5.09.01/csv4180/driver/bobcat0000777000175000017500000000000014050437223016017 2..ustar frankfrankbobcat-5.09.01/csv4180/driver/semicols0000644000175000017500000000002214050437223016242 0ustar frankfranka;b;c d;e;f g;h;i bobcat-5.09.01/csvtabdef/0000755000175000017500000000000014050437223014045 5ustar frankfrankbobcat-5.09.01/csvtabdef/csvtabdef.ih0000644000175000017500000000021314050437223016324 0ustar frankfrank#include "csvtabdef" #include "../xerr/xerr.ih" #include #include using namespace std; using namespace FBB; bobcat-5.09.01/csvtabdef/csvtabdef1.cc0000644000175000017500000000021714050437223016376 0ustar frankfrank//#define XERR #include "csvtabdef.ih" CSVTabDef::CSVTabDef(std::vector &format, unsigned idx) : d_idx(idx), d_format(format) {} bobcat-5.09.01/csvtabdef/split.cc0000644000175000017500000000033614050437223015511 0ustar frankfrank//#define XERR #include "csvtabdef.ih" void CSVTabDef::split(string const &fields) { for (auto const &pair: String::split(fields, String::STR, ",")) add(pair.first); // add trimmed fields } bobcat-5.09.01/csvtabdef/opinsert2.f0000644000175000017500000000026714050437223016146 0ustar frankfrankinline CSVTabDef &operator<<(CSVTabDef &tab, FMT const &fmt) { return tab.insert(fmt); } inline CSVTabDef &operator<<(CSVTabDef &&tab, FMT const &fmt) { return tab << fmt; } bobcat-5.09.01/csvtabdef/insert2.cc0000644000175000017500000000134414050437223015744 0ustar frankfrank#define XERR #include "csvtabdef.ih" CSVTabDef &CSVTabDef::insert(FMT const &fmt) { if (fmt.d_nCols != 1) throw Exception{} << "table column definitions cannot span multiple columns (col. " << d_idx << ')'; if (FMT::lrcFun(fmt.d_align) == 0) throw Exception{} << "table column alignments must be " "left, right or center (col. " << d_idx << ')'; if (d_idx == d_format.size()) d_format.push_back(fmt); else { // keep the larger width unsigned width = max(d_format[d_idx].d_width, fmt.d_width); (d_format[d_idx] = fmt).d_width = width; } ++d_idx; return *this; } bobcat-5.09.01/csvtabdef/insert1.f0000644000175000017500000000025314050437223015601 0ustar frankfranktemplate CSVTabDef &CSVTabDef::insert(Type const &value) { std::ostringstream str; str << value; add(str.str()); return *this; } bobcat-5.09.01/csvtabdef/add2.cc0000644000175000017500000000073614050437223015174 0ustar frankfrank//#define XERR #include "csvtabdef.ih" void CSVTabDef::add(unsigned width) { if (d_idx == d_format.size()) // new format field d_format.push_back( // R-aligned, 'width' FMT{ FMT::RIGHT, width, ~0U }); // characters // keep the format, enlarge the width else if (FMT &fmt = d_format[d_idx]; width > fmt.d_width) fmt.d_width = width; ++d_idx; } bobcat-5.09.01/csvtabdef/destructor.cc0000644000175000017500000000012314050437223016546 0ustar frankfrank//#define XERR #include "csvtabdef.ih" CSVTabDef::~CSVTabDef() { d_idx = 0; } bobcat-5.09.01/csvtabdef/opinsert1.f0000644000175000017500000000036414050437223016143 0ustar frankfranktemplate inline CSVTabDef &operator<<(CSVTabDef &tab, Type const &value) { return tab.insert(value); } template inline CSVTabDef &operator<<(CSVTabDef &&tab, Type const &value) { return tab << value; } bobcat-5.09.01/csvtabdef/csvtabdef0000644000175000017500000000272214050437223015734 0ustar frankfrank#ifndef INCLUDED_BOBCAT_CSVTABDEF_ #define INCLUDED_BOBCAT_CSVTABDEF_ #include #include #include #include #include #include namespace FBB { class CSVTabDef { friend class CSVTable; template friend CSVTabDef &operator<<(CSVTabDef &tab, Type const &value); // 1.f friend CSVTabDef &operator<<(CSVTabDef &tab, FMT const &fmt); // 2.f unsigned d_idx; std::vector &d_format; public: CSVTabDef(CSVTabDef const &other) = delete; ~CSVTabDef(); private: CSVTabDef(std::vector &format, unsigned idx); // split the string into // words, add their // lengths as R-aligned void split(std::string const &fields); // columns void add(std::string const &field); // add one column 1.f // add R-aligned col, void add(unsigned width); // width characters 2.cc template CSVTabDef &insert(Type const &value); // 1.f CSVTabDef &insert(FMT const &fmt); // 2.cc }; #include "add1.f" #include "insert1.f" #include "opinsert1.f" #include "opinsert2.f" } // FBB #endif bobcat-5.09.01/csvtabdef/add1.f0000644000175000017500000000014014050437223015020 0ustar frankfrankinline void CSVTabDef::add(std::string const &field) { add(String::trim(field).length()); } bobcat-5.09.01/csvtabins/0000755000175000017500000000000014050437223014100 5ustar frankfrankbobcat-5.09.01/csvtabins/opinsert5.f0000644000175000017500000000026514050437223016202 0ustar frankfrankinline CSVTabIns &operator<<(CSVTabIns &tab, Sep const &sep) { return tab.sep(sep); } inline CSVTabIns &operator<<(CSVTabIns &&tab, Sep const &sep) { return tab << sep; } bobcat-5.09.01/csvtabins/csvtabins0000644000175000017500000000766714050437223016037 0ustar frankfrank#ifndef INCLUDED_BOBCAT_CSVTABINS_ #define INCLUDED_BOBCAT_CSVTABINS_ #include #include #include #include #include #include #include #include namespace FBB { // CSVTabIns objects are returned by members of CSVTable, and // allow for insertions into a line of the table. When the insertions // end CSVTabIns's destructor is called, ending the line. Its operator() // member is called by CSVTable's operator(). class CSVTabIns { friend class CSVTable; // insert values of insertable types template friend CSVTabIns &operator<<(CSVTabIns &tab, Type const &value); // 1.f // insert FMTs specifying LEFT, RIGHT, or CENTER friend CSVTabIns &operator<<(CSVTabIns &tab, FMT const &fmt); // 2.f // insert FBB::left, FMT::right, FMT::center in the next col friend CSVTabIns &operator<<(CSVTabIns &tab, FMT::Align align); // 3.f // writes a hline in the next column (calls hline()) friend CSVTabIns &operator<<(CSVTabIns &tab, FMT::FMTHline); // 4.f // change the separator while inserting (calls sep()) friend CSVTabIns &operator<<(CSVTabIns &tab, Sep const &sep); // 5.f // insert manipulators like std::left and std::right friend CSVTabIns &operator<<(CSVTabIns &tab, // 6.f std::ios_base &(*func)(std::ios_base &)); unsigned *d_tabIdx; unsigned d_idx; std::ostream *d_out; std::vector const &d_format; std::string d_sep; FMT d_extraFMT; bool d_useExtraFMT; // use d_extraFMT instead of d_format bool d_more; public: CSVTabIns(CSVTabIns const &other) = delete; ~CSVTabIns(); private: CSVTabIns(unsigned *idx, std::ostream &out, std::vector const &format, unsigned startIdx, std::string const &sep, bool more); // inserts 1 row, via void operator()(std::string const &text); // CSVTable.operator() template std::string centered(FMT const &fmt, // .f unsigned fieldWidth, Type const &value); // total width incluing seps // (not using end's sep) from cols unsigned width(unsigned begin, unsigned end) const; // 1.cc unsigned width(FMT const &fmt) const; // see README 2.cc template // also updates d_idx void insertFormatted(FMT const &fmt, // .f Type const &value); template CSVTabIns &insert(Type const &value); // 1.f CSVTabIns &sep(Sep const &sep); // .f CSVTabIns &hline(FMT const &fmt); // insert hline over fmt.nCols() // inserting FMT in col. d_idx means: if nCols() == 1: use the // FMT's width as precision, then use d_format[d_idx]'s width, and // set that format at d_extraFMT if nCols > 1: use the combined // width of the next nCols columns as width. CSVTabIns &insert(FMT const &fmt); // 2.cc CSVTabIns &insert(FMT::Align align); // 3.cc CSVTabIns &insert(std::ios_base &(*func)(std::ios_base &)); // 6.cc }; #include "sep.f" #include "insert1.f" #include "centered.f" #include "insertformatted.f" #include "opinsert1.f" #include "opinsert2.f" #include "opinsert3.f" #include "opinsert4.f" #include "opinsert5.f" #include "opinsert6.f" } // FBB #endif bobcat-5.09.01/csvtabins/sep.f0000644000175000017500000000013014050437223015030 0ustar frankfrankinline CSVTabIns &CSVTabIns::sep(Sep const &sep) { d_sep = sep; return *this; } bobcat-5.09.01/csvtabins/opfun.cc0000644000175000017500000000034214050437223015535 0ustar frankfrank//#define XERR #include "csvtabins.ih" void CSVTabIns::operator()(string const &text) { for (auto const &pair: String::split(text, String::STR, ",")) insert(String::trim(pair.first)); // insert1.f } bobcat-5.09.01/csvtabins/insert6.cc0000644000175000017500000000111714050437223016001 0ustar frankfrank//#define XERR #include "csvtabins.ih" // insert manipulators like left and right CSVTabIns &CSVTabIns::insert(ios_base &(*func)(ios_base &)) { if ( FMT::Align align = func == std::left ? FMT::LEFT : func == std::right ? FMT::RIGHT : FMT::UNUSED; align == FMT::UNUSED ) // manipulators other than left/right *d_out << func; // are directly inserted else *this << align; // or handle LEFT and RIGHT return *this; } bobcat-5.09.01/csvtabins/hline.cc0000644000175000017500000000152714050437223015513 0ustar frankfrank//#define XERR #include "csvtabins.ih" CSVTabIns &CSVTabIns::hline(FMT const &fmt) { unsigned nCols = min( // idx beyond the last col. to fill d_idx + static_cast(fmt.nCols()), d_format.size() ) - d_idx; // nCols: #columns to fill if (nCols == 0) return *this; char fill = d_out->fill(); // set fill character // write the line *d_out << setfill('-') << setw(width(d_idx, d_idx + nCols)) << '-'; d_idx += nCols; if (d_idx < d_format.size()) // sep. unless the last *d_out << d_sep; // column *d_out << setfill(fill); // reset the fill char. return *this; } bobcat-5.09.01/csvtabins/opinsert3.f0000644000175000017500000000030014050437223016166 0ustar frankfrankinline CSVTabIns &operator<<(CSVTabIns &tab, FMT::Align align) { return tab.insert(align); } inline CSVTabIns &operator<<(CSVTabIns &&tab, FMT::Align align) { return tab << align; } bobcat-5.09.01/csvtabins/insertformatted.f0000644000175000017500000000206214050437223017461 0ustar frankfranktemplate void CSVTabIns::insertFormatted(FMT const &fmt, Type const &value) { if (d_idx == d_format.size()) // beyond the last column: { unsigned width = d_out->width(); // get the current width // insert 'value' as-is *d_out << std::setw(0) << d_sep << std::setw(width) << value; return; } // before the last column unsigned fieldWidth = width(fmt); // determine the field width // when centering: plain insertion if (fmt.align() == FMT::CENTER) // because centered fills the full *d_out << centered(fmt, fieldWidth, value); // field width else { *d_out << (fmt.align() == FMT::RIGHT ? std::right : std::left); if (fmt.precision() < fieldWidth) d_out->precision(fmt.precision()); *d_out << std::setw(fieldWidth) << value; } d_idx += fmt.nCols(); if (d_idx != d_format.size()) *d_out << d_sep; } bobcat-5.09.01/csvtabins/README0000644000175000017500000000366414050437223014771 0ustar frankfranktemplate CSVTabIns &CSVTabIns::insert(Type const &value): If d_idx == d_format.size() ignore formats and insert value as is determine the FMT to use (extraFMT or d_format): FMT: left: use left, setw, setpos and insert right: use right, setw, setpos and insert center: configure an ostringstream with width and position and insert value. Then trim value -> length. if length < width: pre- and append spaces insert value with setw(width) ------------------------------------------------------------------------------ CSVTabIns &operator<<(CSVTabIns &tab, FMT const &fmt) if FMT align == HLINE: insert the hline according to fmt otherwise: cp fmt to d_extraFMT and set d_useExtraFMT true hlines are at most inserted until (including) the table's lat col. if the #cols == 0 then nothing is inserted if fmt.width() == 0, then fmt.nCols() specifies the #columns to use (if nCols() + d_idx >= d_format.size() then all remaining columns are used). if (fmt.width() != 0, then that width is used for the combined fmt.nCols columns starting at d_idx ------------------------------------------------------------------------------ CSVTabIns &operator<<(CSVTabIns &tab, FMTFunCH align) align = FBB::center: copy the next fmt to extraFMT and set align to CENTER. FBB::hline: use the next fmt specs to insert a hline, and ++d_idx ------------------------------------------------------------------------------ CSVTabIns &operator<<(CSVTabIns &tab, std::ios_base &(*func)(std::ios_base &)) std::left, std::right: used only for the next column insertion (via d_extraFMT) other manipulators (like hex etc): are inserted and remain active until this row ends ------------------------------------------------------------------------------ bobcat-5.09.01/csvtabins/width1.cc0000644000175000017500000000070414050437223015610 0ustar frankfrank//#define XERR #include "csvtabins.ih" unsigned CSVTabIns::width(unsigned begin, unsigned end) const { if (end > d_format.size()) end = d_format.size(); // total width of in- unsigned ret = (end - begin - 1) * d_sep.length(); // between separators for (; begin != end; ++begin) ret += d_format[begin].width(); // add field widths return ret; } bobcat-5.09.01/csvtabins/opinsert2.f0000644000175000017500000000026714050437223016201 0ustar frankfrankinline CSVTabIns &operator<<(CSVTabIns &tab, FMT const &fmt) { return tab.insert(fmt); } inline CSVTabIns &operator<<(CSVTabIns &&tab, FMT const &fmt) { return tab << fmt; } bobcat-5.09.01/csvtabins/insert2.cc0000644000175000017500000000263014050437223015776 0ustar frankfrank//#define XERR #include "csvtabins.ih" // fmt insertion: // hline: inserts hline unless beyond the last column // // left/right/center formatting: // beyond the last column: // at LEFT: align left, otherwise right // set precision unless d_size (acting as precision) == ~0U // d_nCols is ignored // within the table: // set extraFMT with d_precision: fmt.d_width // d_wdith: width(fmt) CSVTabIns &CSVTabIns::insert(FMT const &fmt) { if (fmt.align() == FMT::HLINE) // fmt contains total width hline(fmt); // and nCols used by the hline else if (d_idx == d_format.size()) // ignore beyond the last column { if (fmt.d_width != ~0U) d_out->precision(fmt.d_width); *d_out << (fmt.align() == FMT::LEFT ? std::left : std::right); } else { d_useExtraFMT = true; d_extraFMT = fmt; // when inserting d_width is d_extraFMT.d_precision = fmt.d_width; // the precision // and use d_format's d_extraFMT.d_width = d_format[d_idx].d_width; // width d_extraFMT.d_width = width(d_extraFMT); // compute the width } return *this; } bobcat-5.09.01/csvtabins/opinsert6.f0000644000175000017500000000044414050437223016202 0ustar frankfrankinline CSVTabIns &operator<<(CSVTabIns &tab, std::ios_base &(*func)(std::ios_base &)) { return tab.insert(func); } inline CSVTabIns &operator<<(CSVTabIns &&tab, std::ios_base &(*func)(std::ios_base &)) { return tab << func; } bobcat-5.09.01/csvtabins/centered.f0000644000175000017500000000201414050437223016035 0ustar frankfranktemplate std::string CSVTabIns::centered(FMT const &fmt, unsigned fieldWidth, Type const &value) { using namespace std; ostringstream stream; // format value in 'stream' stream.copyfmt(*d_out); // xfer d_out's format to stream.fill(d_out->fill()); // stream if (fmt.d_precision < fieldWidth) // maybe set the precision stream.precision(fmt.d_precision); stream << setw(fieldWidth) << value; // convert value to string string ret = String::trim(stream.str()); // remove surrounding spaces // extra spaces needed if (unsigned length = ret.length(); length < fieldWidth) { // prefix this #spaces ret.insert(ret.begin(), (fieldWidth - length) / 2, ' '); ret.resize(fieldWidth, ' '); } return ret; } bobcat-5.09.01/csvtabins/insert3.cc0000644000175000017500000000056114050437223016000 0ustar frankfrank//#define XERR #include "csvtabins.ih" CSVTabIns &CSVTabIns::insert(FMT::Align align) { FMT::FMTFun funPtr = FMT::lrcFun(align); return insert ( (*funPtr)( d_format[d_idx].d_width, // width becomes precision ~0U // 2nd argument not used ) ); } bobcat-5.09.01/csvtabins/csvtabins1.cc0000644000175000017500000000066714050437223016475 0ustar frankfrank//#define XERR #include "csvtabins.ih" CSVTabIns::CSVTabIns(unsigned *tabIdx, ostream &out, vector const &format, unsigned startIdx, string const &sep, bool more) : d_tabIdx(tabIdx), d_idx(*tabIdx), d_out(&out), d_format(format), d_sep(sep), d_useExtraFMT(false), d_more(more) { for (unsigned fill = startIdx - d_idx; fill-- != 0; ) insert(' '); } bobcat-5.09.01/csvtabins/insert1.f0000644000175000017500000000101414050437223015630 0ustar frankfranktemplate CSVTabIns &CSVTabIns::insert(Type const &value) { // beyond the table: insert as-is if (d_idx == d_format.size()) // but width a separator *d_out << d_sep << value; else // value is needed for centering insertFormatted(d_useExtraFMT ? d_extraFMT : d_format[d_idx], value); // also: updates d_idx d_useExtraFMT = false; return *this; } bobcat-5.09.01/csvtabins/csvtabins.ih0000644000175000017500000000013314050437223016413 0ustar frankfrank#include "csvtabins" #include "../xerr/xerr.ih" using namespace std; using namespace FBB; bobcat-5.09.01/csvtabins/destructor.cc0000644000175000017500000000060314050437223016604 0ustar frankfrank//#define XERR #include "csvtabins.ih" CSVTabIns::~CSVTabIns() { if (d_more) { *d_tabIdx = d_idx; return; } for (; d_idx != d_format.size(); ) // fill remaining columns with insert(' '); // spaces *d_out << '\n'; // then end the row *d_tabIdx = 0; // and back to column 0 } bobcat-5.09.01/csvtabins/opinsert1.f0000644000175000017500000000050314050437223016171 0ustar frankfranktemplate inline CSVTabIns &operator<<(CSVTabIns &tab, Type const &value) { return tab.insert(value); } // this one is called from CSVTable::operator CSVTabIns(): // template inline CSVTabIns &operator<<(CSVTabIns &&tab, Type const &value) { return tab << value; } bobcat-5.09.01/csvtabins/width2.cc0000644000175000017500000000025314050437223015610 0ustar frankfrank//#define XERR #include "csvtabins.ih" unsigned CSVTabIns::width(FMT const &fmt) const { return fmt.d_nCols == 1 ? fmt.d_width : width(d_idx, d_idx + fmt.d_nCols); } bobcat-5.09.01/csvtabins/opinsert4.f0000644000175000017500000000035714050437223016203 0ustar frankfrankinline CSVTabIns &operator<<(CSVTabIns &tab, FMT::FMTHline hline) { return tab << (*hline)(1); // insert hline in the next column } inline CSVTabIns &operator<<(CSVTabIns &&tab, FMT::FMTHline hline) { return tab << hline; } bobcat-5.09.01/csvtabins/driver/0000755000175000017500000000000014050437223015373 5ustar frankfrankbobcat-5.09.01/csvtabins/driver/main.cc0000644000175000017500000000104314050437223016624 0ustar frankfrank//#define XERR #include #include #include #include #include "../../xerr/xerr.ih" using namespace std; using namespace FBB; int main(int argc, char **argv) try { CSVTable tab; tab.fmt("iteration, women years, total costs"); tab << hline(); tab.row("iteration, women years, total costs"); tab << hline(); } catch(int x) { return x; } catch (exception const &exc) { cerr << exc.what() << '\n'; } catch (...) { cerr << "unexpected exception\n"; return 1; } bobcat-5.09.01/csvtable/0000755000175000017500000000000014050437223013707 5ustar frankfrankbobcat-5.09.01/csvtable/stream4.f0000644000175000017500000000007714050437223015441 0ustar frankfrankinline std::ostream &CSVTable::stream() { return *d_out; } bobcat-5.09.01/csvtable/row1.cc0000644000175000017500000000027214050437223015107 0ustar frankfrank#define XERR #include "csvtable.ih" CSVTabIns CSVTable::row(unsigned idx) { return CSVTabIns{ &d_idx, *d_out, d_format, checkInsertIdx(idx), d_sep, false}; } bobcat-5.09.01/csvtable/csvtable.ih0000644000175000017500000000021514050437223016032 0ustar frankfrank#include "csvtable" #include "../xerr/xerr.ih" #include "csvtable" #include using namespace std; using namespace FBB; bobcat-5.09.01/csvtable/csvtable3.cc0000644000175000017500000000041714050437223016106 0ustar frankfrank//#define XERR #include "csvtable.ih" CSVTable::CSVTable(string const &fname, string const &sep, ios::openmode mode) : d_strPtr(new ofstream(Exception::factory(fname, mode))), d_out(d_strPtr.get()), d_sep(sep), d_idx(0) { streamFlags(); } bobcat-5.09.01/csvtable/check.cc0000644000175000017500000000044214050437223015273 0ustar frankfrank//#define XERR #include "csvtable.ih" void CSVTable::check(unsigned idx) const { if (idx > d_format.size()) throw Exception{} << "starting index (" << idx << ") exceeds available formats (" << d_format.size() << ')'; } bobcat-5.09.01/csvtable/fmt2.cc0000644000175000017500000000026414050437223015070 0ustar frankfrank//#define XERR #include "csvtable.ih" void CSVTable::fmt(string const &fields, unsigned idx) { check(idx); CSVTabDef tabDef{ d_format, idx }; tabDef.split(fields); } bobcat-5.09.01/csvtable/csvtable0000644000175000017500000001335514050437223015444 0ustar frankfrank#ifndef INCLUDED_BOBCAT_CSVTABLE_ #define INCLUDED_BOBCAT_CSVTABLE_ #include #include #include #include #include #include #include #include // save the stream's original formatting values. column values are formatted // by width and position, all other formatting flags (like hex, setfill) are // kept until altered. when switching streams the next stream continues with // the formatting flags of the current stream, and the current stream's flags // are reset to their original values. When CSVTable ceases to exists the // current stream's flags are reset to their original values. namespace FBB { class CSVTable { std::vector d_format; // column format specifications // stream used by the 2nd/3rd std::unique_ptr d_strPtr; // constructors std::ostream *d_out; // stream to write to std::string d_sep; // separator between columns std::ios::fmtflags d_flags; // the original stream flags unsigned d_precision; char d_fillChar; unsigned d_idx; // start/continue at d_idx public: CSVTable(std::ostream &out = std::cout, // 1.cc std::string const &sep = ", "); CSVTable(std::ofstream &&tmp, // 2.cc std::string const &sep = ", "); CSVTable(std::string const &fname, // 3.cc std::string const &sep = ", ", std::ios::openmode mode = std::ios::out); CSVTable(CSVTable const &other) = delete; CSVTable(CSVTable &&tmp); // 4.cc CSVTable &operator=(CSVTable &&tmp) = default; ~CSVTable(); std::vector const &columns() const; // .f // fmt(...) requires // idx <= d_format.size() CSVTabDef fmt(unsigned idx = 0); // define fields 1.cc // using insertions void fmt(std::string const &fields, // define fields 2.cc unsigned idx = 0); // using ,-separated // trimmed fields unsigned idx() const; // .f CSVTabIns more(unsigned idx = ~0U); // 1.cc void more(std::string const &text, unsigned idx = ~0U); // 2.cc // insert trimmed comma- // separated text elements // (no comma // after the last d_format // field) in subsequent // columns fields using void operator()(std::string const &text); // the default formats. // insert one line, // starting at idx (or CSVTabIns row(unsigned idx = ~0U); // at d_idx if ~0U) 1.cc // same, continuing at idx // if idx < d_idx then // missing columns remain // empty void row(std::string const &text, unsigned idx = ~0U); // 2.cc operator CSVTabIns(); // row(); .f void stream(std::ostream &out); // switch stream 1.cc void stream(std::ofstream &&tmp); // switch stream 2.cc void stream(std::string const &fname, // switch stream by name std::ios::openmode mode = std::ios::out); // 3.cc unsigned size() const; // #table columns .f FMT const &operator[](unsigned idx) const; // opindex.f void sep(std::string const &separator); // 1.f std::string const &sep() const; // 2.f std::ostream &stream(); // returns d_out 3.f private: // retrieve the stream's void streamFlags(); // current flags // reset the stream's void streamReset(); // original settings // reset at the begin of void rowStreamReset(); // rows void check(unsigned idx) const; // check valid initial idx // limit idx to unsigned limit(unsigned idx) const; // d_format.size() .f // check/update column idx unsigned checkInsertIdx(unsigned idx); // (calls rowStreamReset) int preStreamSwitch(); // called by stream(...) void postStreamSwitch(int fillChar); }; #include "columns.f" #include "idx.f" #include "opcsvtabins.f" #include "opindex.f" #include "opfun.f" #include "size.f" #include "stream4.f" #include "sep1.f" #include "sep2.f" } // FBB #endif bobcat-5.09.01/csvtable/prestreamswitch.cc0000644000175000017500000000062714050437223017447 0ustar frankfrank//#define XERR #include "csvtable.ih" int CSVTable::preStreamSwitch() { if (d_idx != 0) // not at the beginning of a row row(); // then end the current row int ret = d_out->fill(); // keep the current fillChar streamReset(); // reset *d_out to its original // settings return ret; } bobcat-5.09.01/csvtable/opindex.f0000644000175000017500000000013214050437223015520 0ustar frankfrankinline FMT const &CSVTable::operator[](unsigned idx) const { return d_format[idx]; } bobcat-5.09.01/csvtable/row2.cc0000644000175000017500000000036414050437223015112 0ustar frankfrank//#define XERR #include "csvtable.ih" void CSVTable::row(string const &text, unsigned idx) { streamReset(); CSVTabIns tabIns{ &d_idx, *d_out, d_format, checkInsertIdx(idx), d_sep, false }; tabIns(text); } bobcat-5.09.01/csvtable/streamreset.cc0000644000175000017500000000035214050437223016554 0ustar frankfrank//#define XERR #include "csvtable.ih" void CSVTable::streamReset() { d_out->setf(d_flags); // reset *d_out to its original d_out->precision(d_precision); // fmt specs d_out->fill(d_fillChar); } bobcat-5.09.01/csvtable/stream2.cc0000644000175000017500000000037214050437223015575 0ustar frankfrank//#define XERR #include "csvtable.ih" void CSVTable::stream(ofstream &&tmp) { int fillChar = preStreamSwitch(); d_strPtr = unique_ptr{ new ofstream(move(tmp)) }; d_out = d_strPtr.get(); postStreamSwitch(fillChar); } bobcat-5.09.01/csvtable/stream1.cc0000644000175000017500000000033114050437223015567 0ustar frankfrank//#define XERR #include "csvtable.ih" void CSVTable::stream(std::ostream &out) { int fillChar = preStreamSwitch(); d_out = &out; // switch stream postStreamSwitch(fillChar); } bobcat-5.09.01/csvtable/limit.f0000644000175000017500000000023114050437223015170 0ustar frankfrank//#define XERR #include "csvtable.ih" inline unsigned CSVTable::limit(unsigned idx) const { return idx > d_format.size() ? d_format:size() : idx; } bobcat-5.09.01/csvtable/sep1.f0000644000175000017500000000010614050437223014723 0ustar frankfrankinline std::string const &CSVTable::sep() const { return d_sep; } bobcat-5.09.01/csvtable/csvtable4.cc0000644000175000017500000000076714050437223016117 0ustar frankfrank//#define XERR #include "csvtable.ih" CSVTable::CSVTable(CSVTable &&tmp) : d_format (move(tmp.d_format)), d_strPtr (move(tmp.d_strPtr)), d_out (tmp.d_out), d_sep (move(tmp.d_sep)), d_flags (tmp.d_flags), // original stream flags d_precision(tmp.d_precision), d_fillChar(tmp.d_fillChar), d_idx (tmp.d_idx) { tmp.d_idx = 0; tmp.d_out = &cout; // moving associates tmp with cout tmp.streamFlags(); } bobcat-5.09.01/csvtable/csvtable2.cc0000644000175000017500000000032614050437223016104 0ustar frankfrank//#define XERR #include "csvtable.ih" CSVTable::CSVTable(ofstream &&tmp, string const &sep) : d_strPtr(new ofstream(move(tmp))), d_out(d_strPtr.get()), d_sep(sep), d_idx(0) { streamFlags(); } bobcat-5.09.01/csvtable/more1.cc0000644000175000017500000000027514050437223015245 0ustar frankfrank//#define XERR #include "csvtable.ih" CSVTabIns CSVTable::more(unsigned idx) { return CSVTabIns{ &d_idx, *d_out, d_format, checkInsertIdx(idx), d_sep, true }; } bobcat-5.09.01/csvtable/csvtable1.cc0000644000175000017500000000024314050437223016101 0ustar frankfrank//#define XERR #include "csvtable.ih" CSVTable::CSVTable(ostream &out, string const &sep) : d_out(&out), d_sep(sep), d_idx(0) { streamFlags(); } bobcat-5.09.01/csvtable/opfun.f0000644000175000017500000000017114050437223015204 0ustar frankfrank // insert fields values into d_out inline void CSVTable::operator()(std::string const &text) { row(text, ~0U); } bobcat-5.09.01/csvtable/fmt1.cc0000644000175000017500000000021014050437223015056 0ustar frankfrank//#define XERR #include "csvtable.ih" CSVTabDef CSVTable::fmt(unsigned idx) { check(idx); return CSVTabDef{ d_format, idx }; } bobcat-5.09.01/csvtable/size.f0000644000175000017500000000010714050437223015026 0ustar frankfrankinline unsigned CSVTable::size() const { return d_format.size(); } bobcat-5.09.01/csvtable/sep2.f0000644000175000017500000000012314050437223014723 0ustar frankfrankinline void CSVTable::sep(std::string const &separator) { d_sep = separator; } bobcat-5.09.01/csvtable/streamflags.cc0000644000175000017500000000040714050437223016527 0ustar frankfrank//#define XERR #include "csvtable.ih" void CSVTable::streamFlags() { d_flags = d_out->flags(); // original stream flags d_precision = d_out->precision(); d_fillChar = d_out->fill(); d_out->setf(ios::fixed, ios::floatfield); } bobcat-5.09.01/csvtable/destructor.cc0000644000175000017500000000012414050437223016411 0ustar frankfrank//#define XERR #include "csvtable.ih" CSVTable::~CSVTable() { streamReset(); } bobcat-5.09.01/csvtable/idx.f0000644000175000017500000000007414050437223014643 0ustar frankfrankinline unsigned CSVTable::idx() const { return d_idx; } bobcat-5.09.01/csvtable/checkinsertidx.cc0000644000175000017500000000062514050437223017230 0ustar frankfrank//#define XERR #include "csvtable.ih" unsigned CSVTable::checkInsertIdx(unsigned idx) { rowStreamReset(); if (idx == ~0U) return d_idx; if (idx > d_format.size()) return d_format.size(); if (idx >= d_idx) return idx; throw Exception{} << "cannot insert values at column index " << idx << ": first available index is " << d_idx; } bobcat-5.09.01/csvtable/more2.cc0000644000175000017500000000034314050437223015242 0ustar frankfrank//#define XERR #include "csvtable.ih" void CSVTable::more(std::string const &text, unsigned idx) { CSVTabIns tabIns{ &d_idx, *d_out, d_format, checkInsertIdx(idx), d_sep, true }; tabIns(text); } bobcat-5.09.01/csvtable/opcsvtabins.f0000644000175000017500000000007414050437223016412 0ustar frankfrankinline CSVTable::operator CSVTabIns() { return row(); } bobcat-5.09.01/csvtable/poststreamswitch.cc0000644000175000017500000000021014050437223017632 0ustar frankfrank//#define XERR #include "csvtable.ih" void CSVTable::postStreamSwitch(int fillChar) { streamFlags(); d_out->fill(fillChar); } bobcat-5.09.01/csvtable/stream3.cc0000644000175000017500000000053014050437223015572 0ustar frankfrank//#define XERR #include "csvtable.ih" void CSVTable::stream(string const &fname, ios::openmode mode) { int fillChar = preStreamSwitch(); d_strPtr = unique_ptr{ new ofstream(Exception::factory(fname, mode)) }; d_out = d_strPtr.get(); postStreamSwitch(fillChar); } bobcat-5.09.01/csvtable/columns.f0000644000175000017500000000012314050437223015532 0ustar frankfrankinline std::vector const &CSVTable::columns() const { return d_format; }; bobcat-5.09.01/csvtable/rowstreamreset.cc0000644000175000017500000000016614050437223017307 0ustar frankfrank//#define XERR #include "csvtable.ih" void CSVTable::rowStreamReset() { if (d_idx == 0) streamReset(); } bobcat-5.09.01/csvtable/driver/0000755000175000017500000000000014050437223015202 5ustar frankfrankbobcat-5.09.01/csvtable/driver/main.cc0000644000175000017500000000205314050437223016435 0ustar frankfrank#include "main.ih" int main() try { // CSVTable tab; CSVTable tab("table"); // tab.fmt() << "case" << right("length", 2) << right("weight", 1) << // right("length", 2) << right("weight", 1); tab.fmt() << "case"; tab.fmt(1) << right("length", 2) << right("weight", 1) << right("length", 2) << right("weight", 1); tab.sep(" "); tab << hline(); // tab << "" << join(4, FMT::CENTER) << "Gender"; tab.row(1) << join(4, FMT::CENTER) << "Gender"; tab.row(1) << hline(); tab.more(1) << join(2, FMT::CENTER) << "Female"; tab.row() << join(2, FMT::CENTER) << "Male"; tab.row(1) << hline(2) << hline(2); tab << "Case" << "Length" << "Weight" << "Length" << "Weight"; tab << hline(); tab.sep(", "); tab << 1 << 1.744 << 55.345 << 1.7244 << 64.801; tab << 2 << 1.58 << 57.545 << 1.8174 << 81.451; tab << 3 << 1.674 << 62.125 << 1.8244 << 80.201; tab << hline(); } catch (exception const &exc) { cerr << exc.what() << '\n'; } bobcat-5.09.01/csvtable/driver/main.ih0000644000175000017500000000015714050437223016453 0ustar frankfrank#include #include #include using namespace std; using namespace FBB; bobcat-5.09.01/datetime/0000755000175000017500000000000014067262427013712 5ustar frankfrankbobcat-5.09.01/datetime/setweekday.cc0000644000175000017500000000100514050437223016350 0ustar frankfrank#include "datetime.ih" void DateTime::setWeekday(Weekday weekday, Relative where) { int difference = static_cast(weekday) - d_tm.tm_wday; switch (where) { case NEXT: difference += 7; break; case LAST: difference -= 7; break; case THIS_WEEK: break; default: throw Exception{ 1 } << "DateTime::setWeekday(): invalid Relative spec."; } setDay(d_tm.tm_mday + difference); } bobcat-5.09.01/datetime/replace0000644000175000017500000000165414066075555015261 0ustar frankfrank#, std::allocator ## #, std::allocator ## #, std::allocator ## #, std::allocator ## #, std::allocator ## #, std::allocator ## // replace objdump's idea of what a string is by ours: #std::__cxx11::basic_string, std::allocator >#std::string# #, std::hash, std::equal_to, std::allocator > ## // #__gnu_cxx::__normal_iterator >#Next::ConstIter # // #std::set const*> >#std::set# #[abi:cxx11]## #__gnu_cxx::__normal_iterator > >#StingVector::const_iterator# #std::vector >#StringVector# #std::chrono::duration >#std::chrono::seconds# bobcat-5.09.01/datetime/opleq.f0000644000175000017500000000016414050437223015170 0ustar frankfrankinline bool operator<=(DateTime const &left, DateTime const &right) { return left.d_utcSec <= right.d_utcSec; } bobcat-5.09.01/datetime/opaddis1.cc0000644000175000017500000000023014050437223015706 0ustar frankfrank#include "datetime.ih" DateTime &DateTime::operator+=(chrono::seconds seconds) { d_utcSec += seconds.count(); assignTM(); return *this; } bobcat-5.09.01/datetime/zonezoneseconds1.cc0000644000175000017500000000024214050437223017514 0ustar frankfrank#include "datetime.ih" // static int DateTime::Zone::zoneSeconds() { time_t seconds = 0; TM tm; gmtime_r(&seconds, &tm); return - mktime(&tm); } bobcat-5.09.01/datetime/settz.cc0000644000175000017500000000024314050437223015357 0ustar frankfrank#include "datetime.ih" // static void DateTime::setTZ(string const &spec) { setenv("TZ", spec.c_str(), 1); // use tzSpec as TZ (empty is UTC) tzset(); } bobcat-5.09.01/datetime/setmonthnr.f0000644000175000017500000000013714050437223016251 0ustar frankfrankinline void DateTime::setMonthNr(int monthNr) { setMonth(static_cast(monthNr - 1)); } bobcat-5.09.01/datetime/setseconds.cc0000644000175000017500000000015214050437223016357 0ustar frankfrank#include "datetime.ih" void DateTime::setSeconds(int seconds) { setFields(TM{ seconds }, SECONDS); } bobcat-5.09.01/datetime/data.cc0000644000175000017500000000125314067261744015134 0ustar frankfrank#include "datetime.ih" char const *DateTime::s_month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", }; char const *DateTime::s_day[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; // Zone static data: // ================= mutex DateTime::Zone::s_mutex; unordered_map> *DateTime::Zone::s_zone = 0; time_t DateTime::Zone::s_thisZoneShift; string DateTime::Zone::s_defaultTZ; char const DateTime::Zone::s_utc[] = "<000>"; char const DateTime::Zone::s_this[] = "<001>"; char const DateTime::Zone::s_anon[] = "<999>"; bobcat-5.09.01/datetime/utcseconds.f0000644000175000017500000000010414050437223016214 0ustar frankfrankinline time_t DateTime::utcSeconds() const { return d_utcSec; } bobcat-5.09.01/datetime/zoneinitialize.cc0000644000175000017500000000055414067261744017263 0ustar frankfrank#include "datetime.ih" // static time_t DateTime::Zone::initialize() { storeIUO(s_utc, ":"); // store the UTC zone storeIUO("CET", "+1:00", "+1:00"); time_t ret = thisZone(); // defines zone 'this' char *tz = getenv("TZ"); // save the current TZ info if (tz) s_defaultTZ = tz; return ret; } bobcat-5.09.01/datetime/setday.cc0000644000175000017500000000015014050437223015474 0ustar frankfrank#include "datetime.ih" void DateTime::setDay(int day) { setFields(TM{ 0, 0, 0, day }, MONTHDAY); } bobcat-5.09.01/datetime/datetime10.cc0000644000175000017500000000102114050437223016136 0ustar frankfrank#include "datetime.ih" // tm specifies a LOCALTIME time point in the time zone `zone' // The tm_year field specifies the calendar year, so 2019 or comparable. // // tm's wday, yday and isdst are ignored DateTime::DateTime(TM const &tm, Zone const &zone) : DateTime(zone) // initialize a LOCALTIME zone { d_tm = tm; d_tm.tm_year -= 1900; // -1900: required mktime correction d_utcSec = utcFromTM(d_tm); // update UTC seconds assignTM(); // update d_tm } bobcat-5.09.01/datetime/parsesetzoneshift.cc0000644000175000017500000000032114050437223017763 0ustar frankfrank#include "datetime.ih" void DateTime::Parse::setZoneShift(bool negative, int hours, int minutes) { d_zoneSeconds = hours * 3600 + minutes * 60; if (negative) d_zoneSeconds = -d_zoneSeconds; } bobcat-5.09.01/datetime/sethours.cc0000644000175000017500000000015014050437223016057 0ustar frankfrank#include "datetime.ih" void DateTime::setHours(int hours) { setFields(TM{ 0, 0, hours }, HOURS); } bobcat-5.09.01/datetime/opgreater.f0000644000175000017500000000016214050437223016036 0ustar frankfrankinline bool operator>(DateTime const &left, DateTime const &right) { return left.d_utcSec > right.d_utcSec; } bobcat-5.09.01/datetime/opaddis2.cc0000644000175000017500000000054114050437223015714 0ustar frankfrank#include "datetime.ih" DateTime &DateTime::operator+=(TM const &src) { d_tm.tm_sec += src.tm_sec; d_tm.tm_min += src.tm_min; d_tm.tm_hour += src.tm_hour; d_tm.tm_mday += src.tm_mday; d_tm.tm_mon += src.tm_mon; d_tm.tm_year += src.tm_year; d_utcSec = utcForZone(zone().spec(), d_tm); assignTM(); return *this; } bobcat-5.09.01/datetime/setmonth3.cc0000644000175000017500000000153314050437223016135 0ustar frankfrank#include "datetime.ih" void DateTime::setMonth(Month month, Relative where) { // s m h md year TM ts{ 0, 0, 0, 0, month, d_tm.tm_year + 1900 }; switch (where) { case NEXT: // E.g., month == MAY, currently SEP: next year // month == SEP, currently SEP: next year if (static_cast(month) <= d_tm.tm_mon) ++ts.tm_year; break; case LAST: // E.g., month == OCT, currently SEP: previous year // month == SEP, currently SEP: previous year if (static_cast(month) >= d_tm.tm_mon) --ts.tm_year; break; case THIS_YEAR: break; default: timeException(); } setFields(ts, MONTH | YEAR); } bobcat-5.09.01/datetime/seconds2str.cc0000644000175000017500000000063314050437223016462 0ustar frankfrank#include "datetime.ih" // static std::string DateTime::seconds2str(time_t seconds) { char sign = '+'; if (seconds < 0) { sign = '-'; seconds = -seconds; } seconds /= 60; // ignore the seconds, use the minutes // zoneshift as -hh:mm return sign + to_string(seconds / 60) + ':' + to_string(seconds % 60); } bobcat-5.09.01/datetime/parsefrommonth.cc0000644000175000017500000000222714050437223017256 0ustar frankfrank#include "datetime.ih" // Day name already read: // // Mon Dec 3 13:29:11 2018 spec. #1: d_type UTC: UTC time, // LOCALTIME: local time // or: // Mon Dec 3 13:29:11 CET 2018 spec. #2, void DateTime::Parse::fromMonth() { string month; string zoneOrYear; char sep; if ( // get all fields through tz-name not ( // or year d_in >> month >> d_tm.tm_mday >> d_tm.tm_hour >> sep >> d_tm.tm_min >> sep >> d_tm.tm_sec >> zoneOrYear ) ) throw 1; // format error -> iniParse() setMonth(month); // throws on month error if (isdigit(zoneOrYear[0])) // got a year: spec. #1 { d_tm.tm_year = stoul(zoneOrYear); d_format = 1; return; } // spec #2: if (not (d_in >> d_tm.tm_year)) // "Mon Dec 3 13:29:11 CET 2018" throw 1; d_zoneName = zoneOrYear; d_format = 2; } bobcat-5.09.01/datetime/hours.f0000644000175000017500000000010514050437223015203 0ustar frankfrankinline unsigned DateTime::hours() const { return d_tm.tm_hour; } bobcat-5.09.01/datetime/monthdaynr.f0000644000175000017500000000011214050437223016224 0ustar frankfrankinline unsigned DateTime::monthDayNr() const { return d_tm.tm_mday; } bobcat-5.09.01/datetime/utc.f0000644000175000017500000000012014050437223014633 0ustar frankfrankinline DateTime DateTime::utc() const { return DateTime{ d_utcSec, UTC }; } bobcat-5.09.01/datetime/datetime6.cc0000644000175000017500000000057114067140632016077 0ustar frankfrank#include "datetime.ih" // time: time in seconds since the epoch // UTC: merely time, zone = 0, supportsDST = false // LOCALTIME: sets d_thisZone (zone()), supportsDST, d_dst: standard DateTime::DateTime(time_t time, TimeType type) : d_type(type), d_utcSec(time), d_zone(Zone::get(d_type == UTC ? "<000>" : "<001>") ) { assignTM(); } bobcat-5.09.01/datetime/parsezoneshift.f0000644000175000017500000000011614050437223017111 0ustar frankfrankinline int DateTime::Parse::zoneSeconds() const { return d_zoneSeconds; } bobcat-5.09.01/datetime/zoneget.cc0000644000175000017500000000072714067261703015676 0ustar frankfrank#include "datetime.ih" // static DateTime::Zone const &DateTime::Zone::get(std::string const &name) { lock_guard lg{ s_mutex }; if (s_zone == 0) { s_zone = new ZoneMap; // 1st time: allocate s_zone s_thisZoneShift = initialize(); // and initialize } auto iter = s_zone->find(name); if (iter == s_zone->end()) throw Exception{ 1 } << "Unknown Zone `" << name << '\''; return *(iter->second); } bobcat-5.09.01/datetime/datetime1.cc0000644000175000017500000000020714050437223016063 0ustar frankfrank#include "datetime.ih" // UTC time = ::time(0) DateTime::DateTime(TimeType type) : DateTime(::time(0), type) // 6.cc {} bobcat-5.09.01/datetime/weeknr.cc0000644000175000017500000000017714050437223015507 0ustar frankfrank#include "datetime.ih" unsigned DateTime::weekNr() const { unsigned nr = yearDayNr() / 7; return nr == 0 ? 52 : nr; } bobcat-5.09.01/datetime/datetime8.cc0000644000175000017500000000026314066106034016074 0ustar frankfrank#include "datetime.ih" // time provides UTC time in seconds, zone sets zone + DST. DateTime::DateTime(time_t time, Zone const &zone) : d_utcSec(time) { setZone(zone); } bobcat-5.09.01/datetime/zonedstfromvector.cc0000644000175000017500000000105114050437223020001 0ustar frankfrank#include "datetime.ih" // static pair DateTime::Zone::dstFromVector(StringVector const &vs) { if (vs.size() <= 3) // no, std or time-shift DST: return {}; // return empty DST strings auto iter = find(vs.begin(), vs.end(), "until"); if (iter == vs.end()) // info beyond dst, but 'until' not throw 1; // specified return { dstConcatenate(vs.begin() + 3, iter), dstConcatenate(iter + 1, vs.end()) }; } bobcat-5.09.01/datetime/datetime9.cc0000644000175000017500000000106014050437223016071 0ustar frankfrank#include "datetime.ih" // tm specifies UTC when type == UTC, and the computer's localtime if // type == LOCALTIME. The tm_year field specifies the calendar year, so // 2019 or comparable. // // tm's wday, yday and isdst are ignored DateTime::DateTime(TM const &tm, TimeType type) : DateTime(type) // initialize UTC or LOCALTIME zone { d_tm = tm; d_tm.tm_year -= 1900; // -1900: required mktime correction d_utcSec = utcFromTM(d_tm); // update UTC seconds assignTM(); // update d_tm } bobcat-5.09.01/datetime/yeardaynr.f0000644000175000017500000000011514050437223016042 0ustar frankfrankinline unsigned DateTime::yearDayNr() const { return d_tm.tm_yday + 1; } bobcat-5.09.01/datetime/setfields.cc0000644000175000017500000000101714050437223016170 0ustar frankfrank#include "datetime.ih" void DateTime::setFields(TM const &src, TimeFields fields) { if (fields & SECONDS) d_tm.tm_sec = src.tm_sec; if (fields & MINUTES) d_tm.tm_min = src.tm_min; if (fields & HOURS) d_tm.tm_hour = src.tm_hour; if (fields & MONTHDAY) d_tm.tm_mday = src.tm_mday; if (fields & MONTH) d_tm.tm_mon = src.tm_mon; if (fields & YEAR) d_tm.tm_year = src.tm_year - 1900; d_utcSec = utcForZone(zone().spec(), d_tm); assignTM(); } bobcat-5.09.01/datetime/zonenegate.cc0000644000175000017500000000054314050437223016350 0ustar frankfrank#include "datetime.ih" // static void DateTime::Zone::negate(string &shift) { if (shift.empty()) return; switch (shift[0]) { case '+': shift[0] = '-'; break; case '-': shift[0] = '+'; break; default: shift.insert(shift.begin(), '-'); break; } } bobcat-5.09.01/datetime/zone3.cc0000644000175000017500000000033714050437223015250 0ustar frankfrank#include "datetime.ih" DateTime::Zone::Zone(string const &shift, string const &dstSpec, string const &dstBegin, string const &dstEnd) : d_data( data(s_anon, shift, dstSpec, dstBegin, dstEnd) ) {} bobcat-5.09.01/datetime/setmonth1.cc0000644000175000017500000000021314050437223016125 0ustar frankfrank#include "datetime.ih" void DateTime::setMonth(int month) { // s m h md setFields(TM{ 0, 0, 0, 0, month }, MONTH); } bobcat-5.09.01/datetime/zonestore.cc0000644000175000017500000000062214067261261016244 0ustar frankfrank#include "datetime.ih" DateTime::Zone const &DateTime::Zone::store( string const &name, string const &shift, string const &dstSpec, string const &dstBegin, string const &dstEnd) { requireAlpha(name); lock_guard lg{ s_mutex }; return storeIUO(name, shift, dstSpec, dstBegin, dstEnd); } bobcat-5.09.01/datetime/opinsert.cc0000644000175000017500000000033114050437223016047 0ustar frankfrank#include "datetime.ih" // "Wed Jun 30 21:49:08 1993" namespace FBB { std::ostream &operator<<(std::ostream &out, DateTime const &dt) { // dt.assignTM(); return out << put_time(&dt.d_tm, "%c"); } } // FBB bobcat-5.09.01/datetime/setutcseconds.cc0000644000175000017500000000016714050437223017101 0ustar frankfrank#include "datetime.ih" void DateTime::setUTCseconds(time_t utcSeconds) { d_utcSec = utcSeconds; assignTM(); } bobcat-5.09.01/datetime/zoneaddzone.cc0000644000175000017500000000274614067261303016542 0ustar frankfrank#include "datetime.ih" // formats: // name shift // name shift = // name shift dstshift // name shift dstshift mon, wkspec day until mon, wkspec day // name shift dstshift mon, wkspec day until mon, wkspec day [hh:mm] // name shift dstshift mon, wkspec day [hh:mm] until mon, wkspec day // name shift dstshift mon, wkspec day [hh:mm] until mon, wkspec day [hh:mm] // dstShift may be =, meaning "1" (standard dst shift) void DateTime::Zone::addZone(string const &line, string const &fname, unsigned lineNr) try { vector vs; String::split(&vs, line, String::TOK, ", "); // get the : , and space // separated elements if (vs.size() < 2) // name and shift not specified throw 1; if (vs[0].back() == ':') vs[0].pop_back(); // check whether the zone name is redefined s_mutex.lock(); bool redefining = s_zone->find(vs[0]) != s_zone->end(); s_mutex.unlock(); auto [dstBegin, dstEnd] = dstFromVector(vs); if (vs.size() == 2) // need a vs[2], maybe empty. vs.resize(3); store(vs[0], vs[1], vs[2], dstBegin, dstEnd); if (redefining) cerr << "Warning: " << fname << " line " << lineNr << ": redefining zone `" << vs[0] << "'\n"; } catch (...) { cerr << fname << " line " << lineNr << ": format error in line `" << line << "'\n"; } bobcat-5.09.01/datetime/rfc2822.cc0000644000175000017500000000134514050437223015302 0ustar frankfrank#include "datetime.ih" string DateTime::rfc2822() const { ostringstream out; out << s_day[d_tm.tm_wday] << ", " << setfill('0') << setw(2) << d_tm.tm_mday << ' ' << s_month[d_tm.tm_mon] << ' ' << 1900 + d_tm.tm_year << ' '; // d_tm specifies the current time according to the current zone // assume this is UTC, then mktime returns the corresponding UTC time // if TZ is switched off. TM tm = d_tm; time_t difference = utcForZone("", tm) - d_utcSec; clockTime(out) << ' ' << showpos << setw(3) << internal << difference / 3600 << noshowpos << setw(2) << abs(difference) % 3600 / 60; return out.str(); } bobcat-5.09.01/datetime/clocktime.cc0000644000175000017500000000034314050437223016161 0ustar frankfrank#include "datetime.ih" ostream &DateTime::clockTime(ostream &out) const { return out << setw(2) << d_tm.tm_hour << ':' << setw(2) << d_tm.tm_min << ':' << setw(2) << d_tm.tm_sec; } bobcat-5.09.01/datetime/zonethiszone.cc0000644000175000017500000000074514067133103016752 0ustar frankfrank#include "datetime.ih" // called from zoneinitialize.cc // static time_t DateTime::Zone::thisZone() { time_t current = time(0); // current (any utc-like time // since the epoch) TM tm; gmtime_r(¤t, &tm); // convert to struct tm current -= mktime(&tm); // this computer's zone shift storeIUO(s_this, seconds2str(current), tm.tm_isdst ? "1" : ""); return current; } bobcat-5.09.01/datetime/month.f0000644000175000017500000000013714050437223015175 0ustar frankfrankinline DateTime::Month DateTime::month() const { return static_cast(d_tm.tm_mon); } bobcat-5.09.01/datetime/stdfind.cc0000644000175000017500000000037714050437223015651 0ustar frankfrank#include "datetime.ih" // static int DateTime::stdFind(char const **names, int count, string const &target) { int ret = find(names, names + count, target) - names; if (ret == count) // not found throw 1; return ret; } bobcat-5.09.01/datetime/utcforzone.cc0000644000175000017500000000036014050437223016404 0ustar frankfrank#include "datetime.ih" // static time_t DateTime::utcForZone(std::string const &zoneSpec, TM &tm) { setTZ(zoneSpec); if (zoneSpec.empty()) tm.tm_isdst = 0; time_t ret = mktime(&tm); resetTZ(); return ret; } bobcat-5.09.01/datetime/frame.parse0000644000175000017500000000005614050437223016027 0ustar frankfrank#include "datetime.ih" DateTime::Parse:: { } bobcat-5.09.01/datetime/zone4.f0000644000175000017500000000011214050437223015100 0ustar frankfrankinline DateTime::Zone::Zone(Data &&data) : d_data(std::move(data)) {} bobcat-5.09.01/datetime/thistime.f0000644000175000017500000000017414050437223015677 0ustar frankfrankinline DateTime DateTime::thisTime() const { return DateTime{ d_utcSec, LOCALTIME }; // the computer's local time } bobcat-5.09.01/datetime/zonerequirealpha.cc0000644000175000017500000000066014050437223017567 0ustar frankfrank#include "datetime.ih" void DateTime::Zone::requireAlpha(string const &name) { if ( name.length() < 3 or find_if(name.begin(), name.end(), [&](char ch) { return not isalpha(ch); } ) != name.end() ) throw Exception{ 1 } << "Zone names (`" << name << "') must consist of at least 3 letters"; } bobcat-5.09.01/datetime/zone2.cc0000644000175000017500000000121614066052701015245 0ustar frankfrank#include "datetime.ih" DateTime::Zone::Zone(string const &spec) { switch (spec[0]) { case ':': // E.g., :Asia/Calcutta. Maybe DST is // never used, but then tm_isdst remains 0 d_data = { spec, zoneSeconds(spec), 3600 }; break; case '+': // +/-hh::mm zone specification case '-': case '0'...'9': d_data = data(s_anon, spec); break; default: // must be a zone, stored by name requireAlpha(spec); d_data = get(spec).d_data; break; } } bobcat-5.09.01/datetime/zonestoreiuo.cc0000644000175000017500000000077414067261303016766 0ustar frankfrank#include "datetime.ih" DateTime::Zone const &DateTime::Zone::storeIUO( string const &name, string const &shift, string const &dstSpec, string const &dstBegin, string const &dstEnd) { Zone *ret = new Zone{ data(name, shift, dstSpec, dstBegin, dstEnd) }; (*s_zone)[name] = unique_ptr{ret}; // store the pointer // in the map. return *ret; } bobcat-5.09.01/datetime/zoneadd.cc0000644000175000017500000000112714050437223015634 0ustar frankfrank#include "datetime.ih" // static int DateTime::Zone::add(string &dstSpec, string const &shift) { if (dstSpec.empty()) return 0; int ret = seconds(dstSpec); // dstSpec is the DST shift int dstSeconds = ret + seconds(shift); // dst time needs the total // shift when dst is active char sign = dstSeconds < 0 ? '-' : '+'; if (sign == '-') dstSeconds = -dstSeconds; dstSpec = sign + to_string(dstSeconds / 3600) + ':' + to_string(dstSeconds % 60); return -ret; } bobcat-5.09.01/datetime/dst.f0000644000175000017500000000010514050437223014635 0ustar frankfrankinline bool DateTime::dst() const { return d_tm.tm_isdst == 1; } bobcat-5.09.01/datetime/datetime.xref0000644000175000017500000003340414067261744016401 0ustar frankfrankoxref by Frank B. Brokken (f.b.brokken@rug.nl) oxref V2.00.00 2012-2019 CREATED Thu, 01 Jul 2021 06:30:53 +0000 CROSS REFERENCE FOR: -r replace -fxs tmp/libdatetime.a ---------------------------------------------------------------------- CROSS REFERENCE LISTING: add(std::string&, std::string const&) Full name: FBB::DateTime::Zone::add(std::string&, std::string const&) Source: zoneadd.cc Used By: zonedata.cc: FBB::DateTime::Zone::data(std::string const&, std::string, std::string, std::string, std::string) addZone(std::string const&, std::string const&, unsigned int) Full name: FBB::DateTime::Zone::addZone(std::string const&, std::string const&, unsigned int) Source: zoneaddzone.cc Used By: zoneread.cc: FBB::DateTime::Zone::read(std::string const&) assignTM() const Full name: FBB::DateTime::assignTM() const Source: assigntm.cc Used By: datetime10.cc: FBB::DateTime::DateTime(tm const&, FBB::DateTime::Zone const&) datetime13.cc: FBB::DateTime::DateTime(std::istream&, FBB::DateTime::TimeType) datetime6.cc: FBB::DateTime::DateTime(long, FBB::DateTime::TimeType) datetime9.cc: FBB::DateTime::DateTime(tm const&, FBB::DateTime::TimeType) opaddis1.cc: FBB::DateTime::operator+=(std::chrono::seconds) opaddis2.cc: FBB::DateTime::operator+=(tm const&) opsubis1.cc: FBB::DateTime::operator-=(std::chrono::seconds) opsubis2.cc: FBB::DateTime::operator-=(tm const&) setfields.cc: FBB::DateTime::setFields(tm const&, FBB::DateTime::TimeFields) setutcseconds.cc: FBB::DateTime::setUTCseconds(long) setzone.cc: FBB::DateTime::setZone(FBB::DateTime::Zone const&) checkDST(std::string const&, std::string&, std::string&) Full name: FBB::DateTime::Zone::checkDST(std::string const&, std::string&, std::string&) Source: zonecheckdst.cc Used By: zonedata.cc: FBB::DateTime::Zone::data(std::string const&, std::string, std::string, std::string, std::string) clockTime(std::ostream&) const Full name: FBB::DateTime::clockTime(std::ostream&) const Source: clocktime.cc Used By: rfc2822.cc: FBB::DateTime::rfc2822() const rfc3339.cc: FBB::DateTime::rfc3339() const convert(std::string const&) Full name: FBB::DateTime::Zone::convert(std::string const&) Source: zoneconvert.cc Used By: zonecheckdst.cc: FBB::DateTime::Zone::checkDST(std::string const&, std::string&, std::string&) data(std::string const&, std::string, std::string, std::string, std::string) Full name: FBB::DateTime::Zone::data(std::string const&, std::string, std::string, std::string, std::string) Source: zonedata.cc Used By: zone2.cc: FBB::DateTime::Zone::Zone(std::string const&) zone3.cc: FBB::DateTime::Zone::Zone(std::string const&, std::string const&, std::string const&, std::string const&) zonestoreiuo.cc: FBB::DateTime::Zone::storeIUO(std::string const&, std::string const&, std::string const&, std::string const&, std::string const&) dateR() Full name: FBB::DateTime::Parse::dateR() Source: parsedater.cc Used By: parsefromdayname.cc: FBB::DateTime::Parse::fromDayName() DateTime(FBB::DateTime::TimeType) Full name: FBB::DateTime::DateTime(FBB::DateTime::TimeType) Source: datetime1.cc Used By: datetime9.cc: FBB::DateTime::DateTime(tm const&, FBB::DateTime::TimeType) DateTime(long, FBB::DateTime::TimeType) Full name: FBB::DateTime::DateTime(long, FBB::DateTime::TimeType) Source: datetime6.cc Used By: datetime1.cc: FBB::DateTime::DateTime(FBB::DateTime::TimeType) DateTime(long, FBB::DateTime::Zone const&) Full name: FBB::DateTime::DateTime(long, FBB::DateTime::Zone const&) Source: datetime8.cc Used By: datetime10.cc: FBB::DateTime::DateTime(tm const&, FBB::DateTime::Zone const&) DateTime(std::istream&, FBB::DateTime::TimeType) Full name: FBB::DateTime::DateTime(std::istream&, FBB::DateTime::TimeType) Source: datetime13.cc Used By: datetime12.cc: FBB::DateTime::DateTime(std::string const&, FBB::DateTime::TimeType) opextract.cc: FBB::operator>>(std::istream&, FBB::DateTime&) dstConcatenate(StingVector::const_iterator, StingVector::const_iterator) Full name: FBB::DateTime::Zone::dstConcatenate(StingVector::const_iterator, StingVector::const_iterator) Source: zonedstconcatenate.cc Used By: zonedstfromvector.cc: FBB::DateTime::Zone::dstFromVector(StringVector const&) dstFromVector(StringVector const&) Full name: FBB::DateTime::Zone::dstFromVector(StringVector const&) Source: zonedstfromvector.cc Used By: zoneaddzone.cc: FBB::DateTime::Zone::addZone(std::string const&, std::string const&, unsigned int) fromDayName() Full name: FBB::DateTime::Parse::fromDayName() Source: parsefromdayname.cc Used By: parse1.cc: FBB::DateTime::Parse::Parse(std::istream&, tm&) fromMonth() Full name: FBB::DateTime::Parse::fromMonth() Source: parsefrommonth.cc Used By: parsefromdayname.cc: FBB::DateTime::Parse::fromDayName() fromYear() Full name: FBB::DateTime::Parse::fromYear() Source: parsefromyear.cc Used By: parse1.cc: FBB::DateTime::Parse::Parse(std::istream&, tm&) get(std::string const&) Full name: FBB::DateTime::Zone::get(std::string const&) Source: zoneget.cc Used By: datetime13.cc: FBB::DateTime::DateTime(std::istream&, FBB::DateTime::TimeType) datetime6.cc: FBB::DateTime::DateTime(long, FBB::DateTime::TimeType) zone2.cc: FBB::DateTime::Zone::Zone(std::string const&) initialize() Full name: FBB::DateTime::Zone::initialize() Source: zoneinitialize.cc Used By: zoneget.cc: FBB::DateTime::Zone::get(std::string const&) negate(std::string&) Full name: FBB::DateTime::Zone::negate(std::string&) Source: zonenegate.cc Used By: zonedata.cc: FBB::DateTime::Zone::data(std::string const&, std::string, std::string, std::string, std::string) Parse(std::istream&, tm&) Full name: FBB::DateTime::Parse::Parse(std::istream&, tm&) Source: parse1.cc Used By: datetime13.cc: FBB::DateTime::DateTime(std::istream&, FBB::DateTime::TimeType) requireAlpha(std::string const&) Full name: FBB::DateTime::Zone::requireAlpha(std::string const&) Source: zonerequirealpha.cc Used By: zone2.cc: FBB::DateTime::Zone::Zone(std::string const&) zonestore.cc: FBB::DateTime::Zone::store(std::string const&, std::string const&, std::string const&, std::string const&, std::string const&) resetTZ() Full name: FBB::DateTime::resetTZ() Source: resettz.cc Used By: assigntm.cc: FBB::DateTime::assignTM() const utcforzone.cc: FBB::DateTime::utcForZone(std::string const&, tm&) zonezoneseconds2.cc: FBB::DateTime::Zone::zoneSeconds(std::string const&) s_anon Full name: FBB::DateTime::Zone::s_anon Source: data.cc Used By: zone2.cc: FBB::DateTime::Zone::Zone(std::string const&) zone3.cc: FBB::DateTime::Zone::Zone(std::string const&, std::string const&, std::string const&, std::string const&) s_day Full name: FBB::DateTime::s_day Source: data.cc Used By: rfc2822.cc: FBB::DateTime::rfc2822() const zoneconvert.cc: FBB::DateTime::Zone::convert(std::string const&) s_defaultTZ Full name: FBB::DateTime::Zone::s_defaultTZ Source: data.cc Used By: zoneinitialize.cc: FBB::DateTime::Zone::initialize() s_month Full name: FBB::DateTime::s_month Source: data.cc Used By: parsesetmonth.cc: FBB::DateTime::Parse::setMonth(std::string const&) rfc2822.cc: FBB::DateTime::rfc2822() const zoneconvert.cc: FBB::DateTime::Zone::convert(std::string const&) s_mutex Full name: FBB::DateTime::Zone::s_mutex Source: data.cc Used By: zoneget.cc: FBB::DateTime::Zone::get(std::string const&) zonestore.cc: FBB::DateTime::Zone::store(std::string const&, std::string const&, std::string const&, std::string const&, std::string const&) s_this Full name: FBB::DateTime::Zone::s_this Source: data.cc Used By: zonethiszone.cc: FBB::DateTime::Zone::thisZone() s_thisZoneShift Full name: FBB::DateTime::Zone::s_thisZoneShift Source: data.cc Used By: zoneget.cc: FBB::DateTime::Zone::get(std::string const&) s_utc Full name: FBB::DateTime::Zone::s_utc Source: data.cc Used By: zoneinitialize.cc: FBB::DateTime::Zone::initialize() s_zone Full name: FBB::DateTime::Zone::s_zone Source: data.cc Used By: zoneaddzone.cc: FBB::DateTime::Zone::addZone(std::string const&, std::string const&, unsigned int) zoneget.cc: FBB::DateTime::Zone::get(std::string const&) zonestoreiuo.cc: FBB::DateTime::Zone::storeIUO(std::string const&, std::string const&, std::string const&, std::string const&, std::string const&) seconds(std::string const&) Full name: FBB::DateTime::Zone::seconds(std::string const&) Source: zoneseconds.cc Used By: zoneadd.cc: FBB::DateTime::Zone::add(std::string&, std::string const&) seconds2str(long) Full name: FBB::DateTime::seconds2str(long) Source: seconds2str.cc Used By: datetime13.cc: FBB::DateTime::DateTime(std::istream&, FBB::DateTime::TimeType) zonethiszone.cc: FBB::DateTime::Zone::thisZone() setDay(int) Full name: FBB::DateTime::setDay(int) Source: setday.cc Used By: setweekday.cc: FBB::DateTime::setWeekday(FBB::DateTime::Weekday, FBB::DateTime::Relative) setFields(tm const&, FBB::DateTime::TimeFields) Full name: FBB::DateTime::setFields(tm const&, FBB::DateTime::TimeFields) Source: setfields.cc Used By: setday.cc: FBB::DateTime::setDay(int) sethours.cc: FBB::DateTime::setHours(int) setminutes.cc: FBB::DateTime::setMinutes(int) setmonth1.cc: FBB::DateTime::setMonth(int) setmonth3.cc: FBB::DateTime::setMonth(FBB::DateTime::Month, FBB::DateTime::Relative) setseconds.cc: FBB::DateTime::setSeconds(int) setyear.cc: FBB::DateTime::setYear(unsigned int) setMonth(std::string const&) Full name: FBB::DateTime::Parse::setMonth(std::string const&) Source: parsesetmonth.cc Used By: parsedater.cc: FBB::DateTime::Parse::dateR() parsefrommonth.cc: FBB::DateTime::Parse::fromMonth() setTZ(std::string const&) Full name: FBB::DateTime::setTZ(std::string const&) Source: settz.cc Used By: assigntm.cc: FBB::DateTime::assignTM() const utcforzone.cc: FBB::DateTime::utcForZone(std::string const&, tm&) zonezoneseconds2.cc: FBB::DateTime::Zone::zoneSeconds(std::string const&) setZone(FBB::DateTime::Zone const&) Full name: FBB::DateTime::setZone(FBB::DateTime::Zone const&) Source: setzone.cc Used By: datetime8.cc: FBB::DateTime::DateTime(long, FBB::DateTime::Zone const&) setZoneShift(bool, int, int) Full name: FBB::DateTime::Parse::setZoneShift(bool, int, int) Source: parsesetzoneshift.cc Used By: parsedater.cc: FBB::DateTime::Parse::dateR() parsefromyear.cc: FBB::DateTime::Parse::fromYear() stdFind(char const**, int, std::string const&) Full name: FBB::DateTime::stdFind(char const**, int, std::string const&) Source: stdfind.cc Used By: parsesetmonth.cc: FBB::DateTime::Parse::setMonth(std::string const&) zoneconvert.cc: FBB::DateTime::Zone::convert(std::string const&) store(std::string const&, std::string const&, std::string const&, std::string const&, std::string const&) Full name: FBB::DateTime::Zone::store(std::string const&, std::string const&, std::string const&, std::string const&, std::string const&) Source: zonestore.cc Used By: zoneaddzone.cc: FBB::DateTime::Zone::addZone(std::string const&, std::string const&, unsigned int) storeIUO(std::string const&, std::string const&, std::string const&, std::string const&, std::string const&) Full name: FBB::DateTime::Zone::storeIUO(std::string const&, std::string const&, std::string const&, std::string const&, std::string const&) Source: zonestoreiuo.cc Used By: zoneinitialize.cc: FBB::DateTime::Zone::initialize() zonestore.cc: FBB::DateTime::Zone::store(std::string const&, std::string const&, std::string const&, std::string const&, std::string const&) zonethiszone.cc: FBB::DateTime::Zone::thisZone() thisZone() Full name: FBB::DateTime::Zone::thisZone() Source: zonethiszone.cc Used By: zoneinitialize.cc: FBB::DateTime::Zone::initialize() timeException() Full name: FBB::DateTime::timeException() Source: timeexception.cc Used By: parse1.cc: FBB::DateTime::Parse::Parse(std::istream&, tm&) setmonth3.cc: FBB::DateTime::setMonth(FBB::DateTime::Month, FBB::DateTime::Relative) utcForZone(std::string const&, tm&) Full name: FBB::DateTime::utcForZone(std::string const&, tm&) Source: utcforzone.cc Used By: opaddis2.cc: FBB::DateTime::operator+=(tm const&) opsubis2.cc: FBB::DateTime::operator-=(tm const&) rfc2822.cc: FBB::DateTime::rfc2822() const rfc3339.cc: FBB::DateTime::rfc3339() const setfields.cc: FBB::DateTime::setFields(tm const&, FBB::DateTime::TimeFields) utcfromtm.cc: FBB::DateTime::utcFromTM(tm&) const utcFromTM(tm&) const Full name: FBB::DateTime::utcFromTM(tm&) const Source: utcfromtm.cc Used By: datetime10.cc: FBB::DateTime::DateTime(tm const&, FBB::DateTime::Zone const&) datetime13.cc: FBB::DateTime::DateTime(std::istream&, FBB::DateTime::TimeType) datetime9.cc: FBB::DateTime::DateTime(tm const&, FBB::DateTime::TimeType) Zone(std::string const&) Full name: FBB::DateTime::Zone::Zone(std::string const&) Source: zone2.cc Used By: datetime13.cc: FBB::DateTime::DateTime(std::istream&, FBB::DateTime::TimeType) zoneSeconds() Full name: FBB::DateTime::Zone::zoneSeconds() Source: zonezoneseconds1.cc Used By: zonezoneseconds2.cc: FBB::DateTime::Zone::zoneSeconds(std::string const&) zoneSeconds(std::string const&) Full name: FBB::DateTime::Zone::zoneSeconds(std::string const&) Source: zonezoneseconds2.cc Used By: zone2.cc: FBB::DateTime::Zone::Zone(std::string const&) zonedata.cc: FBB::DateTime::Zone::data(std::string const&, std::string, std::string, std::string, std::string) bobcat-5.09.01/datetime/opgeq.f0000644000175000017500000000016414050437223015163 0ustar frankfrankinline bool operator>=(DateTime const &left, DateTime const &right) { return left.d_utcSec >= right.d_utcSec; } bobcat-5.09.01/datetime/yearday.f0000644000175000017500000000010714050437223015503 0ustar frankfrankinline unsigned DateTime::yearDay() const { return d_tm.tm_yday; } bobcat-5.09.01/datetime/zonezoneseconds2.cc0000644000175000017500000000025414050437223017520 0ustar frankfrank#include "datetime.ih" // static int DateTime::Zone::zoneSeconds(std::string const &spec) { setTZ(spec); int ret = zoneSeconds(); resetTZ(); return ret; } bobcat-5.09.01/datetime/opsubis2.cc0000644000175000017500000000054114050437223015755 0ustar frankfrank#include "datetime.ih" DateTime &DateTime::operator-=(TM const &src) { d_tm.tm_sec -= src.tm_sec; d_tm.tm_min -= src.tm_min; d_tm.tm_hour -= src.tm_hour; d_tm.tm_mday -= src.tm_mday; d_tm.tm_mon -= src.tm_mon; d_tm.tm_year -= src.tm_year; d_utcSec = utcForZone(zone().spec(), d_tm); assignTM(); return *this; } bobcat-5.09.01/datetime/seconds.f0000644000175000017500000000010614050437223015502 0ustar frankfrankinline unsigned DateTime::seconds() const { return d_tm.tm_sec; } bobcat-5.09.01/datetime/opbitor.f0000644000175000017500000000042614050437223015527 0ustar frankfrankinline DateTime::TimeFields operator|(DateTime::TimeFields lhs, DateTime::TimeFields rhs) { return static_cast ( static_cast(lhs) | static_cast(rhs) ); } bobcat-5.09.01/datetime/zonedstconcatenate.cc0000644000175000017500000000047714050437223020112 0ustar frankfrank#include "datetime.ih" // static string DateTime::Zone::dstConcatenate( StringVector::const_iterator begin, StringVector::const_iterator end) { string ret; for (; begin != end; ++begin) ret += *begin + ' '; ret.pop_back(); return ret; } bobcat-5.09.01/datetime/opless.f0000644000175000017500000000016214050437223015353 0ustar frankfrankinline bool operator<(DateTime const &left, DateTime const &right) { return left.d_utcSec < right.d_utcSec; } bobcat-5.09.01/datetime/datetime5.f0000644000175000017500000000021714050437223015730 0ustar frankfrank// UTC time is ::time(0), zone shift is zoneMinutes inline DateTime::DateTime(Zone const &zone) : DateTime(::time(0), zone) // -> 8 {} bobcat-5.09.01/datetime/zoneseconds.f0000644000175000017500000000011614050437223016377 0ustar frankfrankinline int DateTime::Zone::seconds() const { return d_data.zoneSeconds; } bobcat-5.09.01/datetime/setminutes.cc0000644000175000017500000000015514050437223016410 0ustar frankfrank#include "datetime.ih" void DateTime::setMinutes(int minutes) { setFields(TM{ 0, minutes }, MINUTES); } bobcat-5.09.01/datetime/datetime12.cc0000644000175000017500000000023314050437223016144 0ustar frankfrank#include "datetime.ih" DateTime::DateTime(string const &timeStr, TimeType type) : DateTime(istringstream{timeStr}, type) // 14.f {} bobcat-5.09.01/datetime/parse1.cc0000644000175000017500000000144514050437223015406 0ustar frankfrank#include "datetime.ih" // supported formats: // // with LOCALTIME: these are local times of this computer // recognizing DST times of this computer // With UTC: #1 represents UTC time, the other times are local // times, converted back to UTC times. // // 1: Mon Dec 3 13:29:11 2018 // 2: Mon Dec 3 13:29:11 CET 2018 // 3: Mon, 3 Dec 2018 13:29:11 +0100 // 4: 2018-12-03 13:29:11+01:00 DateTime::Parse::Parse(istream &in, TM &tm) try : d_in(in), d_tm(tm) { if (in >> d_tm.tm_year) fromYear(); // for 4: 2018-12-03 13:29:11+01:00 else fromDayName(); // for 1..3 d_tm.tm_year -= 1900; } catch (...) { timeException(); // doesn't return, but throws. } bobcat-5.09.01/datetime/datetime4.f0000644000175000017500000000033514050437223015730 0ustar frankfrank// UTC time is ::time(0), zoneMinutes is localZone (in minutes) // no dst, zone = local inline DateTime::DateTime(std::chrono::minutes minutes) : DateTime( Zone{ seconds2str(minutes.count() * 60) } ) // -> 5.f {} bobcat-5.09.01/datetime/zoneread.cc0000644000175000017500000000063014050437223016015 0ustar frankfrank#include "datetime.ih" // static void DateTime::Zone::read(std::string const &fname) { ifstream in = Exception::factory(fname); // open the file unsigned lineNr = 0; string line; while (getline(in, line)) { ++lineNr; line = String::trim(line); if (line.empty() || line[0] == '#') continue; addZone(line, fname, lineNr); } } bobcat-5.09.01/datetime/parsesetmonth.cc0000644000175000017500000000017314050437223017104 0ustar frankfrank#include "datetime.ih" void DateTime::Parse::setMonth(string const &mon) { d_tm.tm_mon = stdFind(s_month, 12, mon); } bobcat-5.09.01/datetime/timestruct.f0000644000175000017500000000011614050437223016250 0ustar frankfrankinline DateTime::TM const *DateTime::timeStruct() const { return &d_tm; } bobcat-5.09.01/datetime/rfc3339.cc0000644000175000017500000000112514050437223015302 0ustar frankfrank#include "datetime.ih" string DateTime::rfc3339() const { ostringstream out; out << setfill('0') << 1900 + d_tm.tm_year << '-' << setw(2) << (d_tm.tm_mon + 1) << '-' << setw(2) << d_tm.tm_mday << ' '; TM tm = d_tm; time_t difference = utcForZone("", tm) - d_utcSec; clockTime(out) << ' ' << showpos << setw(3) << internal << difference / 3600 << ':' << noshowpos << setw(2) << abs(difference) % 3600 / 60; return out.str(); } bobcat-5.09.01/datetime/zoneseconds.cc0000644000175000017500000000050314050437223016537 0ustar frankfrank#include "datetime.ih" // static int DateTime::Zone::seconds(string const &spec) { char sign; char sep; int hours; int minutes = 0; istringstream in{ spec }; in >> sign >> hours >> sep >> minutes; int seconds = hours * 3600 + minutes * 60; return sign == '-' ? -seconds : seconds; } bobcat-5.09.01/datetime/zonecheckdst.cc0000644000175000017500000000152314050437223016674 0ustar frankfrank#include "datetime.ih" // static void DateTime::Zone::checkDST(string const &dstSpec, string &dstBegin, string &dstEnd) try { if ( ( // DST details for std or no DST (dstSpec == "=" or dstSpec.empty()) and (dstBegin.length() or dstEnd.length()) ) or // or incomplete DST details (dstBegin.empty() and not dstEnd.empty()) or (dstEnd.empty() and not dstBegin.empty()) ) throw 1; if (dstBegin.empty()) return; dstBegin = convert(dstBegin); dstEnd = convert(dstEnd); } catch (...) { throw Exception{ 1 } << "Zone DST error: `" << dstSpec << "', `" << dstBegin << "', `" << dstEnd << '\''; } bobcat-5.09.01/datetime/datetime7.f0000644000175000017500000000033014050437223015726 0ustar frankfrank // time provides UTC time, zone at zoneMinutes, no DST. inline DateTime::DateTime(time_t time, std::chrono::minutes zoneMinutes) : DateTime(time, Zone{ seconds2str(zoneMinutes.count() * 60) } ) // -> 8.cc {} bobcat-5.09.01/datetime/setmonth2.f0000644000175000017500000000012714050437223015772 0ustar frankfrankinline void DateTime::setMonth(Month month) { setMonth(static_cast(month)); } bobcat-5.09.01/datetime/datetime0000644000175000017500000003707314067261744015444 0ustar frankfrank#ifndef INCLUDED_BOBCAT_DATETIME_ #define INCLUDED_BOBCAT_DATETIME_ #include #include #include #include #include #include #include namespace FBB { // DateTime objects define d_utcSec as the time since the epoch // in seconds, and d_thisZone as the computer's time zone shift in // seconds. class DateTime { friend std::istream &operator>>(std::istream &str, DateTime &dt); friend std::ostream &operator<<(std::ostream &str, DateTime const &dt); friend bool operator==(DateTime const &left, DateTime const &right); friend bool operator!=(DateTime const &left, DateTime const &right); friend bool operator<(DateTime const &left, DateTime const &right); friend bool operator<=(DateTime const &left, DateTime const &right); friend bool operator>(DateTime const &left, DateTime const &right); friend bool operator>=(DateTime const &left, DateTime const &right); typedef struct tm TM; public: enum TimeType { LOCALTIME, UTC, }; enum Month { JANUARY, Jan = JANUARY, FEBRUARY, Feb = FEBRUARY, MARCH, Mar = MARCH, APRIL, Apr = APRIL, MAY, May = MAY, JUNE, Jun = JUNE, JULY, Jul = JULY, AUGUST, Aug = AUGUST, SEPTEMBER, Sep = SEPTEMBER, OCTOBER, Oct = OCTOBER, NOVEMBER, Nov = NOVEMBER, DECEMBER, Dec = DECEMBER, }; enum Relative { THIS_YEAR, LAST, NEXT, THIS_WEEK, }; enum Weekday { SUNDAY, Sun = SUNDAY, MONDAY, Mon = MONDAY, TUESDAY, Tue = TUESDAY, WEDNESDAY, Wed = WEDNESDAY, THURSDAY, Thu = THURSDAY, FRIDAY, Fri = FRIDAY, SATURDAY, Sat = SATURDAY, }; enum TimeFields { SECONDS = 1 << 0, MINUTES = 1 << 1, HOURS = 1 << 2, MONTHDAY = 1 << 3, MONTH = 1 << 4, YEAR = 1 << 5 }; class Zone { friend class DateTime; // iuo zone names: // <000> - UTC zone // <001> - the computer's current zone // <999> - anonymous zone struct Data { std::string spec; int zoneSeconds; int dstSeconds; }; Data d_data; typedef std::unordered_map> ZoneMap; static ZoneMap *s_zone; static time_t s_thisZoneShift; static std::string s_defaultTZ; static std::mutex s_mutex; static char const s_anon[]; static char const s_utc[]; static char const s_this[]; public: explicit Zone(std::string const &spec); // zone name or // 2 // :X/Y spec. or // hh:mm shift Zone(std::string const &shift, // 3 std::string const &dstSpec, // "=" means std std::string const &dstBegin = "", std::string const &dstEnd = ""); std::string const &spec() const; // .f int dstSeconds() const; // only use when mktime // .f // sets tm_isdst = 1 // (-> DateTime::dst(): true) int seconds() const; // retrieve a zone from s_zone static Zone const &get(std::string const &name); static Zone const &store( // 2 std::string const &name, std::string const &shift, // maybe :X/Y std::string const &dstSpec = "", // "=": std DST std::string const &dstBegin = "", std::string const &dstEnd = ""); static std::string const &defaultTZ(); // .f static void read(std::string const &fname); // read zone specs // from file static time_t thisZoneShift(); // .f // this computer's // zone shift in // seconds private: Zone() = default; // required for the unordered_map Zone(Data &&data); // 4.f static Zone const &storeIUO( std::string const &name, std::string const &shift, std::string const &dstSpec = "", // "=": std DST std::string const &dstBegin = "", std::string const &dstEnd = ""); static Data data( std::string const &name, std::string shift, std::string dstSpec = "", // "=" means std std::string dstBegin = "", std::string dstEnd = ""); static void checkDST(std::string const &dstSpec, std::string &dstBegin, std::string &dstEnd); static void negate(std::string &shift); static int add(std::string &dstSpec, std::string const &shift); // spec starts with '+' or '-' static int seconds(std::string const &spec); static std::string convert(std::string const &dstSpec); static void requireAlpha(std::string const &name); static time_t initialize(); static time_t thisZone(); // define the computer's current zone static void addZone(std::string const &line, std::string const &fname, unsigned lineNr); typedef std::vector StringVector; static std::pair dstFromVector(StringVector const &vs); static std::string dstConcatenate( StringVector::const_iterator begin, StringVector::const_iterator end); static int zoneSeconds(); // current zone // 1.cc // specified zone static int zoneSeconds(std::string const &spec); // 2.cc }; private: class Parse // parse textual time specifications { std::istream &d_in; TM &d_tm; std::string d_zoneName; int d_zoneSeconds = 0; // zone shift in seconds int d_format; // see parse1.cc for supported formats public: Parse(std::istream &in, TM &tm); int format() const; // .f int zoneSeconds() const; // .f std::string const &zoneName() const; // .f private: void fromYear(); void fromDayName(); void dateR(); void fromMonth(); void setZoneShift(bool negative, int minutes, int sign = 0); void setMonth(std::string const &month); // throws 1 on err }; TimeType d_type; // current type of info in d_tm member // (LOCALTIME (implied when using displayZone) // or UTC) time_t d_utcSec; // UTC time in seconds (since the epoch: // time(0) ) Zone d_zone; // the object's current zone info mutable TM d_tm; // holds the latest broken down time // given d_type, d_utcSec, d_thisZone, // and d_dst. d_type UTC only // considers d_utcSec -> updateTM() static char const *s_month[]; static char const *s_day[]; public: // time displayed as TimeType explicit DateTime(TimeType type = UTC); // 1 // LOCAL: UTC + zoneMinutes // (no DST) explicit DateTime(std::chrono::minutes zoneMinutes); // 4.f // LOCAL time, from time(0) explicit DateTime(Zone const &spec); // 5.f // specify UTC/LOCAL time in DateTime(time_t time, TimeType type); // seconds // 6 // Local time: zone, no DST DateTime(time_t time, std::chrono::minutes zoneMinutes); // 7.f // Local time: time (UTC) + // Zone specification DateTime(time_t time, Zone const &zone); // 8 // tm fields specify either // UTC or LOCALTIME explicit DateTime(TM const &tm, TimeType type = UTC); // 9 // tm fields specify a // LOCALTIME time point in // Zone `zone' explicit DateTime(TM const &tm, Zone const &zone); // 10 // UTC/LOCAL text time, DateTime(std::string const &timeStr, TimeType type); // 12 DateTime(std::istream &in, TimeType type); // 13 DateTime(std::istream &&in, TimeType type); // 14.f DateTime &operator+=(std::chrono::seconds seconds); // 1. DateTime &operator+=(TM const &tm); // 2. DateTime &operator-=(std::chrono::seconds seconds); // 1. DateTime &operator-=(TM const &tm); // 2. void swap(DateTime &other); bool dst() const; // .f unsigned hours() const; // .f unsigned minutes() const; // .f Month month() const; // .f unsigned monthDayNr() const; // .f unsigned seconds() const; // .f DateTime thisTime() const; // The computer's local time .f TM const *timeStruct() const; // .f DateTime utc() const; // .f time_t utcSeconds() const; // .f Weekday weekday() const; // .f unsigned weekNr() const; unsigned year() const; // the real year (e.g., 2019) .f unsigned yearDay() const; // 0-based // .f unsigned yearDayNr() const; // 1-based // .f Zone const &zone() const; std::string rfc2822() const; std::string rfc3339() const; void setDay(int dayNr); void setFields(TM const &ts, TimeFields fields); void setHours(int hours); void setMinutes(int minutes); void setMonth(int month); // 0-based // 1.cc void setMonth(Month month); // 2.f void setMonth(Month month, Relative where); // 3.cc void setMonthNr(int month); // 1-based // .f void setSeconds(int seconds); void setUTCseconds(time_t utcSeconds); void setWeekday(Weekday weekday, Relative where); void setYear(unsigned year); // calendar year void setZone(Zone const &zone); // d_utcSec is kept, LOCALTIME. // use utc() for a utc DateTime static void tm2cout(char const *label, TM const &ts); private: // from d_utcSec seconds + current zone to TM TM const &assignTM() const; // from zone and time spec. in TM to utcSecs time_t utcFromTM(TM &tm) const; static void setTZ(std::string const &spec); // use "" for UTC static void resetTZ(); // use "" to use a local time // TM specification as UTC spec. static time_t utcForZone(std::string const &zoneSpec, TM &tm); // show d_tm's clock time as // hh::mm::ss std::ostream &clockTime(std::ostream &out) const; static std::string seconds2str(time_t seconds); // at most +/-12 hours away, // seconds are ignored. static int stdFind(char const **names, int count, // throws 1 std::string const &target); // on failure [[noreturn]] static void timeException(); }; #include "datetime4.f" #include "datetime5.f" #include "datetime7.f" #include "datetime14.f" #include "opeq.f" // DateTime == DateTime #include "opneq.f" // DateTime != DateTime #include "opgeq.f" // DateTime >= DateTime #include "opgreater.f" // DateTime > DateTime #include "opleq.f" // DateTime <= DateTime #include "opless.f" // DateTime < DateTime #include "opbitor.f" // TimeFields | TimeFields #include "dst.f" #include "hours.f" #include "minutes.f" #include "month.f" #include "monthdaynr.f" #include "seconds.f" #include "thistime.f" // used to be localTime #include "timestruct.f" #include "utc.f" #include "utcseconds.f" #include "weekday.f" #include "year.f" #include "yearday.f" #include "yeardaynr.f" #include "zone.f" #include "setmonth2.f" #include "setmonthnr.f" #include "zone4.f" #include "zonespec.f" #include "zonedstseconds.f" #include "zonedefaulttz.f" #include "zoneseconds.f" #include "thiszoneshift.f" } // FBB #endif bobcat-5.09.01/datetime/zone.f0000644000175000017500000000011314050437223015015 0ustar frankfrankinline DateTime::Zone const &DateTime::zone() const { return d_zone; } bobcat-5.09.01/datetime/frame.pimpl0000644000175000017500000000005614050437223016036 0ustar frankfrank#include "datetime.ih" DateTime::Pimpl:: { } bobcat-5.09.01/datetime/datetime.ih0000644000175000017500000000063414050437223016021 0ustar frankfrank#include "datetime" #include #include #include // TMP ONLY: #include #define COUT std::cout << __FILE__": " #include #include #include "../exception/exception" #include "../string/string" #include "../fswap/fswap" using namespace std; using namespace FBB; #include "parseformat.f" #include "parsezoneshift.f" #include "parsezonename.f" bobcat-5.09.01/datetime/year.f0000644000175000017500000000011314050437223015002 0ustar frankfrankinline unsigned DateTime::year() const { return d_tm.tm_year + 1900; } bobcat-5.09.01/datetime/zonespec.f0000644000175000017500000000012314050437223015671 0ustar frankfrankinline std::string const &DateTime::Zone::spec() const { return d_data.spec; } bobcat-5.09.01/datetime/swap.cc0000644000175000017500000000015714050437223015164 0ustar frankfrank//#include "datetime.ih" // //void DateTime::swap(DateTime &other) //{ // Pimpl::swap(*this, other); //} // bobcat-5.09.01/datetime/parsezone.f0000644000175000017500000000012214050437223016050 0ustar frankfrankinline DateTime::Zone const &DateTime::Parse::zone() const { return d_zone; } bobcat-5.09.01/datetime/tm2cout.cc0000644000175000017500000000061214050437223015603 0ustar frankfrank#include "datetime.ih" // static void DateTime::tm2cout(char const *label, TM const &ts) { cout << label << ", mon " << ts.tm_mon << ", mday " << ts.tm_mday << ", time " << ts.tm_hour << ':' << ts.tm_min << ':' << ts.tm_sec << ", year " << ts.tm_year << ", DST " << ts.tm_isdst << '\n'; } bobcat-5.09.01/datetime/assigntm.cc0000644000175000017500000000063314050437223016036 0ustar frankfrank#include "datetime.ih" // from utc seconds + current zone to TM // use utcFromTM to obtain UTC seconds given zone and spec. in TM struct tm const &DateTime::assignTM() const { setTZ(zone().spec()); if (not localtime_r(&d_utcSec, &d_tm)) throw Exception{ 1 } << "can't compute time for " << zone().spec() << '\n'; resetTZ(); return d_tm; } bobcat-5.09.01/datetime/setyear.cc0000644000175000017500000000024414050437223015663 0ustar frankfrank#include "datetime.ih" void DateTime::setYear(unsigned year) { //s m h md m setFields(TM{ 0, 0, 0, 0, 0, static_cast(year) }, YEAR); } bobcat-5.09.01/datetime/opextract.cc0000644000175000017500000000036314050437223016222 0ustar frankfrank#include "datetime.ih" namespace FBB { std::istream &operator>>(std::istream &in, FBB::DateTime &dt) { FBB::DateTime tmp{ in, dt.d_type }; fswap(dt, tmp); // swap the DateTime objects return in; } } // FBB bobcat-5.09.01/datetime/opneq.f0000644000175000017500000000016414050437223015172 0ustar frankfrankinline bool operator!=(DateTime const &left, DateTime const &right) { return left.d_utcSec != right.d_utcSec; } bobcat-5.09.01/datetime/thiszoneshift.f0000644000175000017500000000011614067261703016754 0ustar frankfrankinline time_t DateTime::Zone::thisZoneShift() { return s_thisZoneShift; } bobcat-5.09.01/datetime/datetime14.f0000644000175000017500000000020614050437223016006 0ustar frankfrankinline DateTime::DateTime(std::istream &&in, TimeType type) : DateTime(in, type) // 13.cc {} bobcat-5.09.01/datetime/parseformat.f0000644000175000017500000000010414050437223016365 0ustar frankfrankinline int DateTime::Parse::format() const { return d_format; } bobcat-5.09.01/datetime/zonedstseconds.f0000644000175000017500000000021714050437223017114 0ustar frankfrank // at this point DST is known to be active (cf. utcFromTM) inline int DateTime::Zone::dstSeconds() const { return d_data.dstSeconds; } bobcat-5.09.01/datetime/opeq.f0000644000175000017500000000016414050437223015014 0ustar frankfrankinline bool operator==(DateTime const &left, DateTime const &right) { return left.d_utcSec == right.d_utcSec; } bobcat-5.09.01/datetime/zonedefaulttz.f0000644000175000017500000000012214067261744016753 0ustar frankfrankinline std::string const &DateTime::Zone::defaultTZ() { return s_defaultTZ; } bobcat-5.09.01/datetime/parsezonename.f0000644000175000017500000000012714050437223016716 0ustar frankfrankinline std::string const &DateTime::Parse::zoneName() const { return d_zoneName; } bobcat-5.09.01/datetime/setzone.cc0000644000175000017500000000024214050437223015674 0ustar frankfrank#include "datetime.ih" void DateTime::setZone(Zone const &zone) { d_type = LOCALTIME; d_zone = zone; // Pimpl::set(this, zone); assignTM(); } bobcat-5.09.01/datetime/parsefromyear.cc0000644000175000017500000000155314050437223017072 0ustar frankfrank#include "datetime.ih" // expects type 4: 2018-12-03 13:29:11+01:00, where d_tm.tm_year (2018) // has already been read. // spec. 4: 2018-12-03 13:29:11+01:00 void DateTime::Parse::fromYear() { char sep; char sign; int hours; int minutes; if (not ( d_in >> sep >> // - d_tm.tm_mon >> sep >> // 12 - d_tm.tm_mday >> // 03 d_tm.tm_hour >> sep >> // 13 : d_tm.tm_min >> sep >> // 29 : d_tm.tm_sec >> // 11 sign >> hours >> sep >> minutes // + 01 : 00 ) ) throw 1; // caught by the constructor --d_tm.tm_mon; // tm_mon: 0-based setZoneShift(sign == '-', hours, minutes); d_format = 4; } bobcat-5.09.01/datetime/frame.zone0000644000175000017500000000005514050437223015667 0ustar frankfrank#include "datetime.ih" DateTime::Zone:: { } bobcat-5.09.01/datetime/minutes.f0000644000175000017500000000010614050437223015530 0ustar frankfrankinline unsigned DateTime::minutes() const { return d_tm.tm_min; } bobcat-5.09.01/datetime/timeexception.cc0000644000175000017500000000020014050437223017054 0ustar frankfrank#include "datetime.ih" // static void DateTime::timeException() { throw Exception{ 1 } << "error in time specification"; } bobcat-5.09.01/datetime/zonedata.cc0000644000175000017500000000303314050437223016013 0ustar frankfrank#include "datetime.ih" // static DateTime::Zone::Data DateTime::Zone::data(string const &name, std::string shift, std::string dstSpec, std::string dstBegin, std::string dstEnd) { // an ":Asia/Calcutta" type of specification if (shift[0] == ':') // dst may never be used, but then tm_isdst return { shift, zoneSeconds(shift), 3600 }; // remains 0 if (dstSpec == "=") dstSpec = "1"; // use the default of 1 hr. checkDST(dstSpec, dstBegin, dstEnd); negate(shift); // if specified then [0] is + or - string dstName; // -> dstSpec + d bool useDST = not dstSpec.empty(); if (useDST) // dst was specified { dstName = name; // append d, if needed also > if (dstName.back() != '>') dstName += 'd'; else dstName.replace((dstName.rbegin() + 1).base(), dstName.end(), "d>"); } int dstSeconds; if (dstSpec.empty()) // set the DST seconds dstSeconds = 3600; else { negate(dstSpec); dstSeconds = add(dstSpec, shift); } // and the spec. (no DST section if shift = name + shift + // not specified) (useDST ? dstName + dstSpec : "") + dstBegin + dstEnd; return { shift, zoneSeconds(shift), dstSeconds }; } bobcat-5.09.01/datetime/opsubis1.cc0000644000175000017500000000023014050437223015747 0ustar frankfrank#include "datetime.ih" DateTime &DateTime::operator-=(chrono::seconds seconds) { d_utcSec -= seconds.count(); assignTM(); return *this; } bobcat-5.09.01/datetime/datetime13.cc0000644000175000017500000000173714050437223016157 0ustar frankfrank#include "datetime.ih" DateTime::DateTime(istream &in, TimeType type) : d_type(type) { Parse parse{ in, d_tm }; Zone zone{ Zone::get("<000>") }; // get the UTC zone string zoneName; switch (parse.format()) { case 1: // Mon Dec 3 13:29:11 2018 zoneName = d_type == LOCALTIME ? "<001>" : "<000>"; break; case 2: zoneName = parse.zoneName(); break; case 3: // Mon, 3 Dec 2018 13:29:11 +0100 case 4: // 2018-12-03 13:29:11+01:00 if (type == UTC) { d_tm.tm_sec -= parse.zoneSeconds(); // UTC spec in d_tm zoneName = "<000>"; } break; } d_zone = zoneName.empty() ? Zone{ seconds2str(parse.zoneSeconds()) } : Zone::get(zoneName); d_utcSec = utcFromTM(d_tm); assignTM(); } bobcat-5.09.01/datetime/zoneconvert.cc0000644000175000017500000000171114050437223016563 0ustar frankfrank#include "datetime.ih" // dst specification: Mon, wkspec Day [hh:mm] // wkspec: 1st, 2nd, 3rd, 4th, 5th, or last // static string DateTime::Zone::convert(string const &dstSpec) { vector vs; String::split(&vs, dstSpec, String::TOK, ", "); // get the , and space // separated elements if (vs.size() < 3 || vs.size() > 4) throw 1; string monthNr = to_string(1 + stdFind(s_month, 12, vs[0])); char wkSpec = // handle 1st, etc. "1234"s.find(vs[1][0]) != string::npos ? // Otherwise: '5' vs[1][0] // for last : '5'; char dayOffset = '0' + stdFind(s_day, 7, vs[2]); return ",M"s + monthNr + '.' + wkSpec + '.' + dayOffset + (vs.size() == 4 ? '/' + vs.back() : ""); } bobcat-5.09.01/datetime/utcfromtm.cc0000644000175000017500000000046414050437223016233 0ustar frankfrank#include "datetime.ih" // obtain UTC seconds given zone and spec. in TM // use assignTM to set TM from utc seconds + current zone time_t DateTime::utcFromTM(TM &tm) const { time_t ret = utcForZone(zone().spec(), tm); if (tm.tm_isdst) ret -= zone().dstSeconds(); return ret; } bobcat-5.09.01/datetime/parsedater.cc0000644000175000017500000000127614050437223016347 0ustar frankfrank#include "datetime.ih" // format type 3: // Mon, 03 Dec 2018 13:29:11 +0100 `Mon,' has already been read. void DateTime::Parse::dateR() { char sign; int zoneMinutes; string month; char sep; if ( not ( d_in >> d_tm.tm_mday >> month >> d_tm.tm_year >> d_tm.tm_hour >> sep >> d_tm.tm_min >> sep >> d_tm.tm_sec >> sign >> zoneMinutes ) ) throw 1; // format error setMonth(month); // throws on month-error setZoneShift(sign == '-', 0, zoneMinutes / 100 * 60 + zoneMinutes % 100); d_format = 3; } bobcat-5.09.01/datetime/weekday.f0000644000175000017500000000014614050437223015501 0ustar frankfrankinline DateTime::Weekday DateTime::weekday() const { return static_cast(d_tm.tm_wday); } bobcat-5.09.01/datetime/driver/0000755000175000017500000000000014067262373015205 5ustar frankfrankbobcat-5.09.01/datetime/driver/build0000755000175000017500000000026114067136730016226 0ustar frankfrank#!/bin/bash # -I../../tmp -fconcepts \ g++ --std=c++2a -Wall -pthread \ -fdiagnostics-color=never \ $1 \ -L../tmp -ldatetime \ -lbobcat # -L/tmp -lbob -s bobcat-5.09.01/datetime/driver/tz.cc0000644000175000017500000002113414050437223016140 0ustar frankfrank#include #include "../datetime" using namespace std; using namespace FBB; // The value of TZ can be one of two formats. The first format is a // string of characters that directly represent the timezone to be used: // // std offset[dst[offset][,start[/time],end[/time]]] // // There are no spaces in the specification. // // The std string specifies an abbreviation for the timezone and must be // three or more alphabetic characters. // // When enclosed between the less-than (<) and greater-than (>) signs, the // characters set is expanded to include the plus (+) sign, the minus (-) // sign, and digits. // // The offset string immediately follows std and specifies the time value to // be **added** to the local time to get Coordinated Universal Time (UTC). // // The offset is **positive** if the local timezone is west of the Prime // Meridian and negative if it is east. The hour must be between 0 and 24, // and the minutes and seconds 00 and 59: // // [+|-]hh[:mm[:ss]] // // -------------------------------------------------------------------------- // DST: // // std offset[dst[offset][,start[/time],end[/time]]] // // The dst string and offset specify the name and offset for the corre†// sponding daylight saving timezone. E.g., // // TZ="NZST-12:00:00NZDT-13:00:00,M10.1.0,M3.3.0" // // If the offset is omitted, it defaults to one hour ahead of standard // time. // // The start field specifies when daylight saving time goes into effect // and the end field specifies when the change is made back to standard // time. These fields may have the following formats: // // Jn This specifies the Julian day with n between 1 and 365. Leap // days are not counted. In this format, February 29 can't be rep†// resented; February 28 is day 59, and March 1 is always day 60. // // n This specifies the zero-based Julian day with n between 0 and // 365. February 29 is counted in leap years. // // Mm.w.d This specifies day d (0 <= d <= 6) of week w (1 <= w <= 5) of // month m (1 <= m <= 12). Week 1 is the first week in which day d // occurs and week 5 is the last week in which day d occurs. Day 0 // is a Sunday. // // -------------------------------------------------------------------------- // TIME: // std offset[dst[offset][,start[/time],end[/time]]] // // The time fields specify when, in the local time currently in effect, // the change to the other time occurs. If omitted, the default is // 02:00:00. // // Here is an example for New Zealand, where the standard time (NZST) is // 12 hours ahead of UTC, and daylight saving time (NZDT), 13 hours ahead // of UTC, runs from the first Sunday in October to the third Sunday in // March, and the changeovers happen at the default time of 02:00:00: // TZ="NZST-12:00:00NZDT-13:00:00,M10.1.0,M3.3.0" // // // -------------------------------------------------------------------------- // The SECOND FORMAT specifies that the timezone information should be // read from a file: // // :[filespec] // // If the file specification filespec is omitted, or its value cannot be // interpreted, then Coordinated Universal Time (UTC) is used. If file†// spec is given, it specifies another tzfile(5)-format file to read the // timezone information from. If filespec does not begin with a '/', the // file specification is relative to the system timezone directory. If // the colon is omitted each of the above TZ formats will be tried. // // Here's an example, once more for New Zealand: // // TZ=":Pacific/Auckland" // std offset[dst[offset][,start[/time],end[/time]]] // TZ=":Pacific/Auckland" // Zone specifications: // string: name of a previously defined time zone // // [string,] string: specification as ":Pacific/Auckland" // // [string,] string: [+|-]hh[:mm[:ss]] -- zone shift // no DST // [string,] string, string2 -- string2: // DST correction // ("3", "1" means: std shift +3 hours, 1 hour DST shift) // // [string,] string, string2, string3, string4, // string3: begin of DST // string4: end moment of DST // // dst spec = "m.w.d[/time]" // m: month (1..12), w:week (1..5), d: day (0: Sunday) // specify week 1 for the first week in which d occurs // specify week 5 for the last week in which d occurs // time: by default 2:0:0 current *local* time (not considering // dst at the end of the dst) when the dst starts/ends // An optional initial string defines the name of the time zone // No zone specification means: the computer's currently defined time zone is // used. // time_t utcSec(struct tm *tm, char const *tzSpec) { time_t ret; char *tz; string tzStr; tz = getenv("TZ"); // save the current TZ info if (tz) tzStr = tz; setenv("TZ", tzSpec, 1); // use tzSpec as TZ (empty is UTC) tzset(); ret = mktime(tm); // compute the UTC time fm localtime in tm if (tm->tm_isdst) ret -= 3600; // for now: assume std 1 hour positive shift if (tzStr.empty()) unsetenv("TZ"); else setenv("TZ", tzStr.c_str(), 1); tzset(); return ret; } tm *local_r(time_t *utcSec, struct tm *tm, char const *tzSpec) { char *tz; string tzStr; tz = getenv("TZ"); // save the current TZ info if (tz) tzStr = tz; setenv("TZ", tzSpec, 1); // use tzSpec as TZ (empty is UTC) tzset(); localtime_r(utcSec, tm); if (tzStr.empty()) unsetenv("TZ"); else setenv("TZ", tzStr.c_str(), 1); tzset(); return tm; } time_t zoneShift() { char *tz; string tzStr; tz = getenv("TZ"); // save the current TZ info if (tz) tzStr = tz; tm ts; // setenv("TZ", ":Europe/Amsterdam", 1); // use tzSpec as TZ (empty is UTC) setenv("TZ", ":Asia/Calcutta", 1); // use tzSpec as TZ (empty is UTC) tzset(); time_t ret = 0; gmtime_r(&ret, &ts); ret = mktime(&ts); if (tzStr.empty()) unsetenv("TZ"); else setenv("TZ", tzStr.c_str(), 1); tzset(); return ret; } int main() { cout << zoneShift() << '\n'; tm src{ 0, // sec 0, // min 19, // hour -> current zone = CET -> UTC = 18 // (not considering DST) 4, // month-day 3, // month 2019 - 1900, // year }; tm ts = src; time_t utc = mktime(&ts); cout << utc << " dst: " << ts.tm_isdst << '\n'; gmtime_r(&utc, &ts); DateTime::tm2cout("UTC time: ", ts); localtime_r(&utc, &ts); DateTime::tm2cout("Local time: ", ts); local_r(&utc, &ts, "CET-1:00DST"); DateTime::tm2cout("Local time via local_r: ", ts); ts = src; ts.tm_hour += 5 - 1; // Kolkata: +5:30 UTC ts.tm_min += 30; utc = utcSec(&ts, ":Asia/Calcutta"); cout << utc << " dst: " << ts.tm_isdst << '\n'; gmtime_r(&utc, &ts); DateTime::tm2cout("UTC time: ", ts); ts = src; ts.tm_hour += 5 - 1; // Kolkata: +5:30 UTC ts.tm_min += 30; utc = utcSec(&ts, "ZONE-05:30"); cout << utc << " dst: " << ts.tm_isdst << '\n'; gmtime_r(&utc, &ts); DateTime::tm2cout("UTC time: ", ts); ts = src; ts.tm_hour += 5 - 1; // Kolkata: +5:30 UTC ts.tm_min += 30; utc = utcSec(&ts, "<001>-05:30"); cout << "same, using zone name <001>:\n"; cout << utc << " dst: " << ts.tm_isdst << '\n'; gmtime_r(&utc, &ts); DateTime::tm2cout("UTC time: ", ts); ts = src; ts.tm_hour += 5 - 1; // Any other: +5:00 UTC utc = utcSec(&ts, "ZONE-05:00DST"); // with a std DST specification cout << utc << " dst: " << ts.tm_isdst << '\n'; gmtime_r(&utc, &ts); DateTime::tm2cout("UTC time, with DST: ", ts); } /* time_t my_timegm(struct tm *tm) { time_t ret; char *tz; string tzStr; tz = getenv("TZ"); // get the current TZ info if (tz) tzStr = tz; setenv("TZ", "", 1); // clear the TZ variable tzset(); ret = mktime(tm); // compute the UTC time fm localtime in tm if (tz) { setenv("TZ", tz, 1); free(tz); } else unsetenv("TZ"); tzset(); return ret; } */ bobcat-5.09.01/datetime/driver/zone.cc0000644000175000017500000000325514050437223016462 0ustar frankfrank#include #include "../datetime" using namespace std; using namespace FBB; int main() try { DateTime::Zone zone{"+1:00"}; cout << "1. dst: " << zone.dstSeconds() << ", spec: " << zone.spec() << "\n\n"; zone = DateTime::Zone("CET"); cout << "2. dst (3600): " << zone.dstSeconds() << ", spec: " << zone.spec() << "\n\n"; zone = DateTime::Zone(":Asia/Calcutta"); cout << "3. dst (3600): " << zone.dstSeconds() << ", spec: " << zone.spec() << "\n\n"; zone = DateTime::Zone("+1:00", "+1:00"); cout << "4. dst (3600): " << zone.dstSeconds() << ", spec: " << zone.spec() << "\n\n"; zone = DateTime::Zone("+1:00", "+1:00", "Mar, last Sun", "Oct, last Sun"); cout << "5. dst (3600): " << zone.dstSeconds() << ", spec: " << zone.spec() << "\n\n"; zone = DateTime::Zone("+1:00", "+1:00", "Mar, 1st Mon 2:00", "Oct, 3rd Fri 3:00"); cout << "6. dst (3600): " << zone.dstSeconds() << ", spec: " << zone.spec() << "\n\n"; zone = DateTime::Zone::store("ZONE", "+1:00", "+1:00", "Mar, last Sun", "Oct, last Sun"); cout << "7. dst (3600): " << zone.dstSeconds() << ", spec: " << zone.spec() << "\n\n"; zone = DateTime::Zone::store("ZONE", "+1:00", "-0:30", "Mar, last Sun", "Oct, last Sun"); cout << "8. dst (-1800): " << zone.dstSeconds() << ", spec: " << zone.spec() << "\n\n"; } catch (exception const &exc) { cout << exc.what() << "\n\n"; } bobcat-5.09.01/datetime/driver/datetime6.cc0000644000175000017500000000053414050437223017366 0ustar frankfrank#include #include "../datetime" using namespace std; using namespace FBB; int main() { time_t utcSec = time(0); DateTime utcTime{ utcSec, DateTime::UTC }; cout << "Current UTC time = " << utcTime << '\n'; DateTime dateTime{ utcSec, DateTime::LOCALTIME }; cout << "Current LOCALTIME = " << dateTime << '\n'; } bobcat-5.09.01/datetime/driver/datetime7.cc0000644000175000017500000000062514050437223017370 0ustar frankfrank#include #include "../datetime" using namespace std; using namespace FBB; int main() { DateTime utc; cout << "current UTC time: " << utc << "\n\n"; DateTime dt1{ time(0) + 3600, // no DST, local time: utc + 1 + 3 hrs chrono::hours{ 3 } }; cout << "no DST, LOCAL time = UTC + 4 hours: " << dt1 << ", dst = " << dt1.dst() << "\n\n"; } bobcat-5.09.01/datetime/driver/datetime8.cc0000644000175000017500000000166014050437223017371 0ustar frankfrank#include #include "../datetime" using namespace std; using namespace FBB; int main() { DateTime utc; cout << "current UTC: " << utc << "\n\n"; // no DST, local time: utc + 3 hrs DateTime dt1{ DateTime::Zone{ "3" } }; // via 5.f to 8 cout << "Local time, 3 hours later, using Zone{ \"3\" }: " << dt1 << "\n\n"; DateTime dt2{ chrono::hours{ 3 } }; // same, via 4.f to 8 cout << "same, using chrono::hours{ 3 }: " << dt2 << "\n\n"; DateTime dt3{ time(0) + 7 * 24 * 3600, // one week later chrono::hours{ 3 } }; cout << "current LOCAL time, next week: " << dt3 << "\n\n"; DateTime dt4{ DateTime::Zone{ "3", "1" } }; // via 5.f to 8 cout << "current LOCAL time, 3 hrs later + dst (1 hr) " << dt4 << "\n\n"; } bobcat-5.09.01/datetime/driver/datetime9.cc0000644000175000017500000000163214050437223017371 0ustar frankfrank#include #include "../datetime" using namespace std; using namespace FBB; int main() { DateTime utc; cout << "current UTC: " << utc << "\n\n"; tm ts{ 0, // sec 0, // min 19, // hour 4, // month-day 3, // month 2019, // year }; DateTime dt{ ts, DateTime::UTC }; cout << "explicitly specified UTC: 19:00:00: " << dt << "\n\n"; DateTime dt2{ ts, DateTime::LOCALTIME }; cout << "explicitly specified LOCAL TIME 19:00:00: " << dt2 << "\n" "corresponding UTC: " << dt2.utc() << "\n\n"; cout << "time (hr explicitly set to 19):\n"; ts.tm_mon = 10; DateTime dt3{ ts, DateTime::LOCALTIME }; cout << "specified localtime 19:00:00: " << dt3 << ", dst = " << dt3.dst() << "\n" "corresponding UTC: " << dt3.utc() << "\n\n"; } bobcat-5.09.01/datetime/driver/setfields.cc0000644000175000017500000000432014050437223017463 0ustar frankfrank#include #include "../datetime" using namespace std; using namespace FBB; void show(DateTime const &dt, char const *label) { cout << label << ": " << dt << "\n" " dst: " << dt.dst() << "\n" " hh:mm:ss: " << dt.hours() << ':' << dt.minutes() << ':' << dt.seconds() << "\n" " year-month-monthdaynr: " << dt.year() << '-' << dt.month() << '-' << dt.monthDayNr() << "\n" " weekday/weeknr/yearday/yeardaynr: " << dt.weekday() << '/' << dt.weekNr() << '/' << dt.yearDay() << '/' << dt.yearDayNr() << "\n" "\n"; } int main() { time_t now = time(0); DateTime utc{ now, DateTime::UTC }; cout << "1: current UTC: " << utc << "\n\n"; utc += tm{ 0, 0, 2, 1 }; cout << "2: utc the next day, 2 hrs later: " << utc << "\n\n"; DateTime dt{ now, DateTime::LOCALTIME }; cout << "3: current local time: " << dt << ", zone shift: " << dt.zone().seconds() << " seconds\n\n"; dt.setSeconds(0); cout << "4: local time, 0 seconds: " << dt << "\n\n"; dt += tm{ 0, 0, 2 }; cout << "5a: local time, 2 hrs later: " << dt << "\n\n"; dt += tm{ 0, 0, 2, 1 }; cout << "5: local time, next day, 2 hrs later: " << dt << "\n\n"; dt += chrono::hours(1); cout << "6: local time: add another hour: " << dt << "\n\n"; utc.setFields( tm{ 0, 0, 8, 1 }, DateTime::SECONDS | DateTime::HOURS | DateTime::MONTHDAY ); show(utc, "7: utc, 1st of the month, 8 hrs, 0 sec."); cout << "---------------\n"; DateTime dt1{ now, DateTime::LOCALTIME }; cout << "8: current local time: " << dt1 << "\n\n"; dt1.setFields( tm{ 0, 0, 8, 1 }, DateTime::SECONDS | DateTime::HOURS | DateTime::MONTHDAY ); show(dt1, "9: local time for 1st of the month, 8 hrs, zero seconds"); DateTime dt2{ now, DateTime::LOCALTIME }; dt2.setDay(dt2.monthDayNr() - 7); show(dt2, "10: current local time, one week ago"); } bobcat-5.09.01/datetime/driver/anyshift/0000755000175000017500000000000014050437223017020 5ustar frankfrankbobcat-5.09.01/datetime/driver/anyshift/showtm.cc0000644000175000017500000000031614050437223020650 0ustar frankfrank#include "main.ih" void showTM(tm const &ts, char const *label) { cout << label << ": hh:mm " << ts.tm_hour << ':' << setw(2) << setfill('0') << ts.tm_min << "\n\n"; } bobcat-5.09.01/datetime/driver/anyshift/showdesiredtime.cc0000644000175000017500000000075314050437223022533 0ustar frankfrank#include "main.ih" void showDesiredTime() { if (not showDesired) return; time_t current = time(0) + desiredZone + desiredDST; tm ts; gmtime_r(¤t, &ts); cout << "UTC time shift: " << showpos << setw(3) << internal << (desiredZone + desiredDST) / 3600 << noshowpos << setw(2) << abs(desiredZone + desiredDST) % 3600 / 60 << '\n'; showTM(ts, "Desired time"); } bobcat-5.09.01/datetime/driver/anyshift/data.cc0000644000175000017500000000036514050437223020244 0ustar frankfrank#include "main.ih" bool setHours = false; bool showDesired = false; int hours; time_t desiredDST; // desired DST info (all in seconds) time_t desiredZone; // desired zone shift, not considering DST time_t thisDST; time_t thisZone; bobcat-5.09.01/datetime/driver/anyshift/getlocal.cc0000644000175000017500000000104214050437223021116 0ustar frankfrank#include "main.ih" void getLocal() { time_t current = time(0); // current (any utc-like time // since the epoch) struct tm ts; gmtime_r(¤t, &ts); // convert to struct tm thisZone = current - mktime(&ts); // local zone shift thisDST = ts.tm_isdst == 1 ? 3600 : 0; // the computer thinks DST is used cout << "Local zone = " << thisZone / 3600. << " hour(s), local DST: " << thisDST / 3600 << " hour(s)\n\n"; } bobcat-5.09.01/datetime/driver/anyshift/changehours.cc0000644000175000017500000000075414050437223021643 0ustar frankfrank#include "main.ih" void changeHours() { if (not setHours) return; time_t current = time(0) + desiredZone + desiredDST; tm ts; gmtime_r(¤t, &ts); // get the desired time spec. in ts. ts.tm_sec -= thisDST; // correction for local DST ts.tm_hour = hours; // set the new hours value // returns time_t: UTC time value mktime(&ts); // update ts showTM(ts, "Changed hours"); } bobcat-5.09.01/datetime/driver/anyshift/main.cc0000644000175000017500000000274314050437223020261 0ustar frankfrank#include "main.ih" int main(int argc, char **argv) { // if (argc == 1) // cout << "\n" // " optionally specify:\n" // " zone shift (hrs[.5]); dst (minutes); req. hours (opt)\n\n"; getLocal(); // find the computer's time zone and DST // getDesired(argc, argv); // // showLocalTime(); // show the time info based on current zone // showDesiredTime(); // show the time if requested // changeHours(); // change the hours setting time_t remoteZone = 3 * 3600; time_t remoteDST = 3600; time_t remoteShift = remoteZone + remoteDST; tm t1 = tm { 11, 29, 13, 3, // local time specification (+ 3 hrs UTC) 11, 2018 }; t1.tm_sec += thisZone - remoteShift; time_t t1sec = mktime(&t1); t1sec += remoteShift; // correction for remote time gmtime_r(&t1sec, &t1); cout << "specified hour 13, reconstructed hour: " << t1.tm_hour << '\n'; t1 = tm { 11, 29, 13, 3, // local time specification (+ 3 hrs UTC) 5, 2018 }; // local computer time: WITHOUT DST!! t1.tm_sec += thisZone - remoteShift; t1sec = mktime(&t1); t1sec += remoteShift; // correction for remote time gmtime_r(&t1sec, &t1); cout << "specified hour 13, reconstructed hour: " << t1.tm_hour << '\n'; } bobcat-5.09.01/datetime/driver/anyshift/main.ih0000644000175000017500000000114714050437223020271 0ustar frankfrank#include #include #include #include void getLocal(); void getDesired(int argc, char **argv); void showTM(tm const &ts, char const *label); void showLocalTime(); void showDesiredTime(); void changeHours(); extern time_t thisZone; // local zone shift, not considering DST extern time_t thisDST; // local DST info (all in seconds) extern bool showDesired; extern bool setHours; extern int hours; extern time_t desiredZone; // desired zone shift, not considering DST extern time_t desiredDST; // desired DST info (all in seconds) using namespace std; bobcat-5.09.01/datetime/driver/anyshift/showlocaltime.cc0000644000175000017500000000025214050437223022200 0ustar frankfrank#include "main.ih" void showLocalTime() { time_t current = time(0) + thisZone + thisDST; tm ts; gmtime_r(¤t, &ts); showTM(ts, "Local time"); } bobcat-5.09.01/datetime/driver/anyshift/getdesired.cc0000644000175000017500000000124714050437223021452 0ustar frankfrank#include "main.ih" void getDesired(int argc, char **argv) { if (argc == 1) { desiredZone = thisZone; desiredDST = thisDST; } else { showDesired = true; desiredZone = stod(argv[1]) * 3600; // seconds Zone desiredDST = stoi(argv[2]) * 60; // seconds DST setHours = argc > 3; if (setHours) hours = stoi(argv[3]); cout << "desired zone: " << desiredZone / 3600. << " hours\n" "desired DST: " << desiredDST / 60 << " minutes\n"; if (setHours) cout << "change hours to " << hours << '\n'; cout << '\n'; } } bobcat-5.09.01/datetime/driver/zoneread.txt0000644000175000017500000000135614050437223017550 0ustar frankfrank# formats: # name shift # name shift = # name shift dstshift # name shift dstshift mon, wkspec day until mon, wkspec day # name shift dstshift mon, wkspec day until mon, wkspec day [hh:mm] # name shift dstshift mon, wkspec day [hh:mm] until mon, wkspec day # name shift dstshift mon, wkspec day [hh:mm] until mon, wkspec day [hh:mm] one: +1:00 # illustrates redefine-warning: one: +1:00 = two: +1:00 +1:00 three: +1:00 +1:00 Mar, last Sun until Oct, last Sun four: +1:00 +1:00 Mar, last Sun until Oct, last Sun 03:00 five: +1:00 +1:00 Mar, last Sun 02:00 until Oct, last Sun six: +1:00 +1:00 Mar, last Sun 02:00 until Oct, last Sun 03:00 seven: +1:00 = Mar, last Sun 02:00 until Oct, last Sun 03:00 bobcat-5.09.01/datetime/driver/auckland.cc0000644000175000017500000000130514050437223017263 0ustar frankfrank#include #include using namespace std; void tm2cout(tm const &ts) { cout << "mon " << ts.tm_mon << ", mday " << ts.tm_mday << ", time " << ts.tm_hour << ':' << ts.tm_min << ':' << ts.tm_sec << ", year " << ts.tm_year << ", DST " << ts.tm_isdst << '\n'; } int main() { cout << "Local reconfig to :Pacific/Auckland, not using DateTime\n\n"; time_t now = time(0); setenv("TZ", ":Pacific/Auckland", 1); tzset(); tm ts; if (not localtime_r(&now, &ts)) { cout << "Failure\n"; return 1; } tm2cout(ts); cout << '\n'; } bobcat-5.09.01/datetime/driver/datetime12.cc0000644000175000017500000000402114050437223017436 0ustar frankfrank#include #include "../datetime" using namespace std; using namespace FBB; int main() { cout << "Parsing various input text formats\n\n"; cout << "format type 1 (Mon Jul 3 13:00:00 2018):\n"; { DateTime utc{ "Mon Jul 3 13:00:00 2018", DateTime::UTC }; cout << "Read as UTC time: " << utc << '\n'; // Note: these time specifications do not honor DST DateTime local{ "Mon Jul 3 13:00:00 2018", DateTime::LOCALTIME }; cout << "Read as LOCAL TIME: " << local << ",\n" "UTC obtained from LOCAL: " << local.utc() << '\n'; } cout << "\n" "format type 2: (Mon Jul 3 13:00:00 CET 2018)\n"; { DateTime utc{ "Mon Jul 3 13:00:00 CET 2018", DateTime::UTC }; cout << "Read as UTC time: " << utc << '\n'; DateTime local{ "Mon Jul 3 13:00:00 CET 2018", DateTime::LOCALTIME }; cout << "Read as LOCAL TIME: " << local << ",\n" "UTC obtained from LOCAL: " << local.utc() << '\n'; } cout << "\n" "format type 3 (Mon, 3 Jul 2018 13:00:00 +0100):\n"; { DateTime utc{ "Mon, 3 Jul 2018 13:00:00 +0100", DateTime::UTC }; cout << "Read as UTC time: " << utc << '\n'; // Note: these time specifications do not honor DST DateTime local{ "Mon, 3 Jul 2018 13:00:00 +0100", DateTime::LOCALTIME }; cout << "Read as LOCAL TIME: " << local << ",\n" "UTC obtained from LOCAL: " << local.utc() << '\n'; } cout << "\n" "format type 4 (2018-12-03 13:00:00+01:00):\n"; { DateTime utc{ "2018-12-03 13:00:00+01:00", DateTime::UTC }; cout << "Read as UTC time: " << utc << '\n'; DateTime local{ "2018-12-03 13:00:00+01:00", DateTime::LOCALTIME }; cout << "Read as LOCAL TIME: " << local << ",\n" "UTC obtained from LOCAL: " << local.utc() << '\n'; } } bobcat-5.09.01/datetime/driver/zoneread.cc0000644000175000017500000000022414050437223017307 0ustar frankfrank#include #include "../datetime" using namespace std; using namespace FBB; int main() { DateTime::Zone::read("zoneread.txt"); } bobcat-5.09.01/datetime/driver/datetime2.cc0000644000175000017500000000174014050437223017362 0ustar frankfrank#include #include "../datetime" using namespace std; using namespace FBB; int main() { DateTime utc{ time(0), DateTime::UTC }; cout << "current UTC time: " << utc << ", dst = " << utc.dst() << "\n\n"; DateTime utcCopy{ utc }; cout << " a copy: " << utcCopy << "\n\n"; DateTime local{ DateTime::LOCALTIME }; cout << "current LOCAL time: " << local << ", dst = " << local.dst() << "\n\n"; DateTime localCopy{ local }; cout << " a copy: " << utcCopy << "\n\n"; DateTime moved{ std::move(localCopy) }; cout << "moved from existing object: " << moved << ", dst = " << moved.dst() << ", zone spec: " << moved.zone().spec() << "\n\n"; cout << "existing object after move: " << localCopy << ", dst = " << moved.dst() << ", zone spec: " << moved.zone().spec() << "\n\n"; } bobcat-5.09.01/datetime/driver/rfc.cc0000644000175000017500000000076714050437223016266 0ustar frankfrank#include #include "../datetime" using namespace std; using namespace FBB; int main() { time_t now = time(0); DateTime utc{ now, DateTime::UTC }; cout << "UTC: " << utc << '\n' << utc.rfc2822() << '\n' << utc.rfc3339() << "\n\n"; cout << utc << "\n\n"; DateTime dt{ now, DateTime::LOCALTIME }; cout << "LOCAL TIME: " << dt << '\n' << dt.rfc2822() << '\n' << dt.rfc3339() << "\n\n"; cout << dt << "\n\n"; } bobcat-5.09.01/datetime/driver/accessors.cc0000644000175000017500000000243714050437223017475 0ustar frankfrank#include #include "../datetime" using namespace std; using namespace FBB; void show(DateTime const &dt, char const *label) { cout << label << ": " << dt << "\n" "dst: " << dt.dst() << "\n" "hh:mm:ss: " << dt.hours() << ':' << dt.minutes() << ':' << dt.seconds() << "\n" "year-month-monthdaynr: " << dt.year() << '-' << dt.month() << '-' << dt.monthDayNr() << "\n" "weekday/weeknr/yearday/yeardaynr: " << dt.weekday() << '/' << dt.weekNr() << '/' << dt.yearDay() << '/' << dt.yearDayNr() << "\n" "\n"; } int main() { time_t now = time(0); DateTime utc{ now, DateTime::UTC }; show(utc, "Current UTC time"); DateTime local{ utc.thisTime() }; cout << "The COMPUTER'S LOCAL TIME: " << local << '\n'; DateTime dt{ now, DateTime::LOCALTIME }; show(dt, "Current LOCAL TIME"); DateTime utc2{ dt.utc() }; cout << "UTC obtained from LOCAL TIME: " << utc2 << '\n'; DateTime jan1{ "2019-01-01 13:00:00+01:00", DateTime::LOCALTIME }; cout << "Jan 1, 1919, 13:00h: " << jan1 << '\n'; show(jan1, "Jan 1, details:"); cout << "\nOptionally rerun specifying another time zone specification\n" "\n"; } bobcat-5.09.01/datetime/driver/midnight.cc0000644000175000017500000000057714050437223017316 0ustar frankfrank #include #include "../datetime" using namespace std; using namespace FBB; int main() { //info DateTime dt{ 0, DateTime::UTC }; // set UTC at begin of era tm era{ 0 }; // define a tm with tm_mday == 1 era.tm_mday = 1; dt -= era; // subtract from dt and display cout << dt << endl; //= } bobcat-5.09.01/datetime/parsefromdayname.cc0000644000175000017500000000063014050437223017543 0ustar frankfrank#include "datetime.ih" void DateTime::Parse::fromDayName() { d_in.clear(); // not starting with a year, restart extractions string day; if (not (d_in >> day)) // #1-#3 require day throw 1; if (day.back() == ',') dateR(); // format #3 else fromMonth(); // formats #1, #2 } bobcat-5.09.01/datetime/resettz.cc0000644000175000017500000000031114050437223015702 0ustar frankfrank#include "datetime.ih" // static void DateTime::resetTZ() { if (Zone::defaultTZ().empty()) unsetenv("TZ"); else setenv("TZ", Zone::defaultTZ().c_str(), 1); tzset(); } bobcat-5.09.01/decryptbuf/0000755000175000017500000000000014050437223014253 5ustar frankfrankbobcat-5.09.01/decryptbuf/overflow.cc0000644000175000017500000000026314050437223016426 0ustar frankfrank#include "decryptbuf.ih" int DecryptBuf::overflow(int ch) { flushBuffer(); if (ch != EOF) { *pptr() = ch; pbump(1); } return ch; } bobcat-5.09.01/decryptbuf/decryptbuf.ih0000644000175000017500000000114414050437223016744 0ustar frankfrank#include "decryptbuf" // TMP #include #include #include #include #include "../exception/exception" #if OPENSSL_VERSION_NUMBER < 0x10100000L #ifndef BOBCAT_EVP_CYPHER_CTX #define BOBCAT_EVP_CYPHER_CTX inline EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(void) { EVP_CIPHER_CTX *ret = new EVP_CIPHER_CTX; EVP_CIPHER_CTX_init(ret); return ret; } inline void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx) { EVP_CIPHER_CTX_cleanup(ctx); delete ctx; } #endif // ifndef #endif // OPENSSL_VERSION using namespace std; using namespace FBB; bobcat-5.09.01/decryptbuf/decryptbuf1.cc0000644000175000017500000000127114050437223017013 0ustar frankfrank#include "decryptbuf.ih" DecryptBuf::DecryptBuf(ostream &outStream, char const *type, string const &key, string const &iv, size_t size) : CryptBuf(type, size < EVP_MAX_BLOCK_LENGTH ? (size = EVP_MAX_BLOCK_LENGTH) : size), d_ctx(EVP_CIPHER_CTX_new()), d_decrypted(bufSize(), 0), d_iv(iv), d_key(key), d_outStream(outStream) { if ( not EVP_DecryptInit_ex(d_ctx, md(), 0, ucharPtr(d_key), ucharPtr(d_iv)) ) throw Exception{ 1 } << "DecryptBuf: initialization failed"; //// d_cipherBlockSize = EVP_CIPHER_CTX_block_size(d_ctx); setp(); } bobcat-5.09.01/decryptbuf/cipherctx.cc0000644000175000017500000000013014050437223016545 0ustar frankfrank#include "decryptbuf.ih" EVP_CIPHER_CTX *DecryptBuf::cipherCtx() { return d_ctx; } bobcat-5.09.01/decryptbuf/eoi.f0000644000175000017500000000005614050437223015177 0ustar frankfrankinline void DecryptBuf::eoi() { eoi_(); } bobcat-5.09.01/decryptbuf/flushbuffer.cc0000644000175000017500000000372514050437223017104 0ustar frankfrank#include "decryptbuf.ih" // int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, // int *outl, const unsigned char *in, int inl); // // // EVP_EncryptUpdate() encrypts inl bytes from the buffer in and writes // the encrypted version to out. This function can be called multiple // times to encrypt successive blocks of data. The amount of data written // depends on the block alignment of the encrypted data: as a result the // amount of data written may be anything from zero bytes to (inl + // cipher_block_size - 1) so out should contain sufficient room. The // actual number of bytes written is placed in outl. It also checks if in // and out are partially overlapping, and if they are 0 is returned to // indicate failure. // // Analogously (?): // EVP_DecryptUpdate() decrypts inl bytes from the buffer in and writes // the decrypted version to out. This function can be called multiple // times to decrypt successive blocks of data. // // EVP_DecryptInit_ex(), EVP_DecryptUpdate() and EVP_DecryptFinal_ex() are // the corresponding decryption operations. EVP_DecryptFinal() will return // an error code if padding is enabled and the final block is not // correctly formatted. The parameters and restrictions are identical to // the encryption operations except that if padding is enabled the // decrypted data buffer out passed to EVP_DecryptUpdate() should have // sufficient room for (inl + cipher_block_size) bytes unless the cipher // block size is 1 in which case inl bytes is sufficient. void DecryptBuf::flushBuffer() { size_t srcLen = pptr() - pbase(); int decryptedLen; if ( not EVP_DecryptUpdate(d_ctx, ucharPtr(d_decrypted), &decryptedLen, ucharPtr(), srcLen) ) { ERR_print_errors_fp(stderr); throw 1; } d_outStream.write(&d_decrypted[0], decryptedLen); setp(); } bobcat-5.09.01/decryptbuf/decryptbuf0000644000175000017500000000201014050437223016336 0ustar frankfrank#ifndef INCLUDED_DECRYPTBUF_ #define INCLUDED_DECRYPTBUF_ // https://wiki.openssl.org/index.php/EVP_Symmetric_Encryption_and_Decryption #include #include #include namespace FBB { class DecryptBuf: public CryptBuf { EVP_CIPHER_CTX *d_ctx; std::string d_decrypted; bool d_eoi = false; std::string d_iv; std::string d_key; std::ostream &d_outStream; public: DecryptBuf(std::ostream &outStream, char const *type, std::string const &key, std::string const &iv, size_t bufSize = 1024); ~DecryptBuf() override; bool setRounds(size_t nRounds); // RC5 8, 12 or 16 void eoi(); // .f protected: EVP_CIPHER_CTX *cipherCtx(); private: int overflow(int c) override; void eoi_() override; // .cc void flushBuffer(); }; #include "eoi.f" } // FBB #endif bobcat-5.09.01/decryptbuf/destructor.cc0000644000175000017500000000017314050437223016761 0ustar frankfrank#include "decryptbuf.ih" DecryptBuf::~DecryptBuf() { if (not d_eoi) eoi(); EVP_CIPHER_CTX_free(d_ctx); } bobcat-5.09.01/decryptbuf/eoi.cc0000644000175000017500000000046714050437223015345 0ustar frankfrank#include "decryptbuf.ih" void DecryptBuf::eoi_() // overrides { flushBuffer(); int restLen; if (not EVP_DecryptFinal_ex(d_ctx, ucharPtr(d_decrypted), &restLen)) throw Exception{ 1 } << "DecryptBuf: padding error"; d_outStream.write(&d_decrypted[0], restLen); d_eoi = true; } bobcat-5.09.01/decryptbuf/setrounds.cc0000644000175000017500000000022514050437223016607 0ustar frankfrank#include "decryptbuf.ih" bool DecryptBuf::setRounds(size_t nRounds) { return EVP_CIPHER_CTX_ctrl(d_ctx, EVP_CTRL_SET_RC5_ROUNDS, nRounds, 0); } bobcat-5.09.01/decryptbuf/driver/0000755000175000017500000000000014050437223015546 5ustar frankfrankbobcat-5.09.01/decryptbuf/driver/build0000755000175000017500000000234514050437223016577 0ustar frankfrank#!/bin/bash # ln -s .. bobcat # ln -s ../ohexbuf/ohexbuf bobcat # # g++ -I. --std=c++2a -O2 -Wall -o driver driver.cc -lssl -lbobcat \ # -L../../ohexbuf/tmp -L../tmp -ldecryptbuf -lohexbuf # # rm bobcat/ohexbuf bobcat # echo g++ --std=c++2a -O2 -Wall -o driver driver.cc -lbobcat # g++ --std=c++2a -O2 -Wall -o driver driver.cc -lbobcat # echo g++ -I. --std=c++2a -O2 -Wall -o driver driver.cc -L../tmp -ldecryptbuf \ # -lssl -lbobcat # # g++ -I. --std=c++2a -O2 -Wall -o driver driver.cc -L../tmp -ldecryptbuf \ # -lssl -lbobcat tput clear LIBS=" -lbobcat -lcrypto" GPP="g++ --std=c++2a" # Using the standard bobcat library #CMD="$GPP -o driver -Wall driver.cc ${LIBS} -s" # Using the library in ../tmp/ #CMD="$GPP -o driver -Wall driver.cc -L../tmp -ldecryptbuf ${LIBS} -s" # Using the library in ../tmp/ and bobcat as /tmp/libbob.a #CMD="$GPP -o driver -Wall driver.cc -L../tmp -ldecryptbuf -L /tmp -lbob -lcrypto -s" # Using libraries in ../tmp/, and /tmp (-> boblib) CMD="$GPP -o driver -Wall driver.cc \ -L../tmp -ldecryptbuf \ -L../../cryptbuf/tmp -lcryptbuf \ -L../../eoibuf/tmp -leoibuf \ -L../../eoi/tmp -leoi \ -lbobcat -lcrypto -s" echo ${CMD} ${CMD} bobcat-5.09.01/decryptbuf/driver/driver.cc0000644000175000017500000000171514050437223017354 0ustar frankfrank#include #include #include #include #include #include #include "../decryptbuf" #include "../../encryptbuf/encryptbuf" using namespace std; using namespace FBB; int main(int argc, char **argv) try { if (argc == 1) throw Exception(1) << "1st arg: method, 2nd arg: key, 3rd arg: iv, " "4th arg: file to decrypt (to stdout)"; // e.g., driver aes-128-cbc somekey iv-from-encryptbuf-driver // /tmp/enc > /tmp/driver.dec cerr << "Key: `" << argv[2] << "'\n" "IV: `" << argv[3] << "'\n"; DecryptBuf decryptbuf(cout, argv[1], argv[2], argv[3]); ostream out(&decryptbuf); ifstream in(argv[4]); if (not in) throw Exception{} << "can't read `" << argv[4] << '\n'; out << in.rdbuf() << eoi; } catch(exception const &err) { cout << err.what() << endl; return 1; } bobcat-5.09.01/decryptbuf/driver/run0000755000175000017500000000022014050437223016272 0ustar frankfrank#!/bin/bash if [ $# -eq 0 ] ; then method=aes-128-cbc else method=$1 fi ./driver $method theKeyOfRunAES 1234567890qwertyuiop /tmp/enc bobcat-5.09.01/dependencies/0000755000175000017500000000000014050437223014532 5ustar frankfrankbobcat-5.09.01/dependencies/inspectset.cc0000644000175000017500000000220314050437223017217 0ustar frankfrank#include "main.ih" bool inspectSet(ValueType &value, Map &table) { StringSet &requiredSet = value.second.first; bool modified = false; for (auto &required: requiredSet) // visit all required classes { StringSet updated{requiredSet}; // possibly extended set // the required set of a // required class: StringSet const &reqByRequired = table[required].first; // add elements to `updated' updated.insert(reqByRequired.begin(), reqByRequired.end()); if (requiredSet.size() < updated.size()) { string const &key = value.first; if ( not value.second.second and reqByRequired.find(key) != reqByRequired.end() ) { value.second.second = true; cerr << "Circular dependency in class " << key << '\n'; } modified = true; requiredSet = updated; } } return modified; } bobcat-5.09.01/dependencies/store0000755000175000017500000000227114050437223015616 0ustar frankfrank#!/bin/bash # call this script from its parent directory: dependencies/store cd dependencies icmbuild # build the dependency checker cd .. usingClasses=dependencies/using.classes IFS=' ' rm -f $usingClasses for line in `cat CLASSES` `cat READLINE` `cat SSLCLASSES` milter xpointer do field=`echo $line | cut -f1 -d' '` # first word on lines of CLASSES # skip empty and comment lines [ "$field" == "#" -o "$field" == "" ] && continue; echo $field >> $usingClasses # write the class-name # add indented names of all # classes including the class-name # in non .cc and .f files # so: header files grep "bobcat/$field>" \ `find -mindepth 2 -maxdepth 2 -type f -name '*[^cf]'` | grep -v '/icmake\|:\s*//\s*#include' | sed 's,./\([^/]\+\).*, \1,g' >> $usingClasses done dependencies/tmp/bin/binary < $usingClasses > dependencies/required.classes cd dependencies icmbuild clean bobcat-5.09.01/dependencies/required.classes0000644000175000017500000000434614050437223017740 0ustar frankfranka2x align arg argconfig arg configfile base64bufbase ifilterbuf bigint binarysearch binops typetrait binopsbase cerrextractor exec extractorbase ifdbuf pipe cgi pattern cidr cininserter exec ofdbuf pipe clientsocket inetaddress socketbase cmdfinder cmdfinderbase fswap cmdfinderbase configfile coutextractor exec extractorbase ifdbuf pipe cryptbuf csv4180 datetime decryptbuf diffiehellman bigint digestbuf encryptbuf eoi eoibuf exception exec extractorbase exec ifdbuf pipe fbb fork fswap gethostent glob gs gs hash string hmacbuf hostent hostname hostent ibase64stream ibase64buf ibase64buf ifdstream ifdbuf ifdbuf ifilterbuf indent inetaddress iostream iobuf iobuf iquotedprintablestream iquotedprintablebuf iquotedprintablebuf irandstream randbuf isharedstream sharedbuf isymcryptstream isymcryptstreambuf isymcryptstreambuf iterator iuo level log logbuf linearmap localclientsocket localsocketbase localserversocket localsocketbase localsocketbase log logbuf logbuf mailheaders string mbuf milter mstream mbuf multibuf ofdstream ofdbuf ofdbuf ofilterbuf ofoldstream ofoldbuf ofoldbuf ohexbuf omutexstream onekey osharedstream sharedbuf pattern pf_iterator pf_iteratorstream pipe primefactors bigint process fork ifdbuf iostream iobuf ofdbuf pipe processenums selector string processdata processenums ptriter qpbufbase ifilterbuf randbuf ranger readlinebuf readlinehistory readlinestream readlinebuf redirector repeat typetrait selector semaphore serversocket inetaddress socketbase sharedblock sharedmutex sharedcondition exception fswap sharedblock sharedmemory sharedmutex sharedpos sharedsegment sharedmemory exception fswap sharedblock sharedmutex sharedpos sharedsegment sharedmutex sharedpos sharedblock sharedmutex sharedsegment sharedsegment sharedblock sharedmutex sharedstream sharedbuf sharedbuf signal socketbase inetaddress stat datetime gs stdextractor exec extractorbase ifdbuf pipe string stringline symcryptstreambufbase ifilterbuf syslogbuf syslogstream syslogbuf table align tablebase tablesupport tablebase align tablesupport tablebuf tablelines align tablesupport tablesupport align tempstream tty typetrait user x2a xpointer bobcat-5.09.01/dependencies/display.cc0000644000175000017500000000053114050437223016505 0ustar frankfrank#include "main.ih" void display(Map const &table) { for (auto const &keyValue: table) // display class names and the classes { // they depend on. cout << keyValue.first << ' '; for (auto const &dep: keyValue.second.first) cout << dep << ' '; cout << '\n'; } } bobcat-5.09.01/dependencies/main.cc0000644000175000017500000000015514050437223015766 0ustar frankfrank#include "main.ih" int main() { Map table; fill(table); inspect(table); display(table); } bobcat-5.09.01/dependencies/main.ih0000644000175000017500000000066514050437223016007 0ustar frankfrank#include #include #include #include #include using namespace std; typedef set StringSet; typedef pair ValuePair; // bool: circular dependency typedef map Map; typedef Map::value_type ValueType; void display(Map const &table); void fill(Map &table); void inspect(Map &table); bool inspectSet(ValueType &value, Map &table); bobcat-5.09.01/dependencies/fill.cc0000644000175000017500000000111414050437223015764 0ustar frankfrank#include "main.ih" void fill(Map &table) { string line; string key; string value; while (getline(cin, line)) { istringstream in(line); if (not isblank(line[0])) // add ^key to the table { in >> key; table.insert(ValueType{ key, ValuePair{StringSet{}, false} }); } else // add \s+value to the table, and { // indicate that it depends on 'key' in >> value; table[value].first.insert(key); } } } bobcat-5.09.01/dependencies/using.classes0000644000175000017500000000442414050437223017242 0ustar frankfranka2x align tablebase tablesupport arg argconfig argconfig base64bufbase binarysearch binops binopsbase cerrextractor cininserter coutextractor cgi cidr clientsocket cmdfinder cmdfinderbase cmdfinder configfile argconfig csv4180 datetime stat exception sharedmemory exec extractorbase cininserter extractorbase coutextractor stdextractor cerrextractor fbb fork process fswap sharedmemory cmdfinder gethostent glob gs glob stat hash hostent hostname hostname ibase64stream ibase64buf ibase64stream ifdstream ifdbuf ifdstream extractorbase process ifilterbuf qpbufbase base64bufbase symcryptstreambufbase indent inetaddress socketbase iostream process iobuf iostream iquotedprintablestream iquotedprintablebuf iquotedprintablestream irandstream isharedstream iterator iuo level linearmap localclientsocket localserversocket localsocketbase localserversocket localclientsocket log level logbuf log mailheaders mbuf mstream mstream multibuf omutexstream ofdstream ofdbuf ofdstream process cininserter ofilterbuf ofoldstream ofoldbuf ofoldstream ohexbuf onekey osharedstream pattern cgi pipe extractorbase process cininserter process processdata processenums process ptriter qpbufbase randbuf irandstream ranger redirector repeat selector process semaphore serversocket sharedblock sharedsegment sharedcondition sharedmemory sharedcondition sharedmutex sharedblock sharedcondition sharedpos sharedmemory sharedsegment sharedpos sharedstream sharedbuf osharedstream isharedstream sharedstream signal socketbase serversocket clientsocket stat stdextractor string hash mailheaders process stringline syslogbuf syslogstream syslogstream table tablebase table tablebuf tablelines tablesupport tablelines tablebase tempstream tty typetrait repeat binops user x2a cryptbuf eoibuf eoi readlinebuf readlinestream readlinehistory readlinestream pf_iterator pf_iteratorstream bigint diffiehellman primefactors decryptbuf diffiehellman digestbuf encryptbuf hmacbuf isymcryptstream isymcryptstreambuf isymcryptstream primefactors symcryptstreambufbase milter xpointer bobcat-5.09.01/dependencies/inspect.cc0000644000175000017500000000036214050437223016507 0ustar frankfrank#include "main.ih" void inspect(Map &table) { bool modified; do { modified = false; for (auto &value: table) // visit all elements modified |= inspectSet(value, table); } while (modified); } bobcat-5.09.01/diffiehellman/0000755000175000017500000000000014050437223014673 5ustar frankfrankbobcat-5.09.01/diffiehellman/checkdhparameters.cc0000644000175000017500000000175014050437223020662 0ustar frankfrank#include "diffiehellman.ih" // check the DH parameters. If all's well return, otherwise // write messages or throw an exception // void DiffieHellman::checkDHparameters() { int result; int ret; ret = DH_check(d_dh, &result); // 0: check fails, 1: check OK BIGNUM const *g; BIGNUM const *prime; DH_get0_pqg(d_dh, &prime, 0, &g); d_prime = BigInt{*prime}; if (ret == 1) return; if (result & (DH_CHECK_P_NOT_PRIME | DH_CHECK_P_NOT_SAFE_PRIME)) throw Exception{} << s_header << "invalid prime generated"; BigInt generator(g); if (result & DH_NOT_SUITABLE_GENERATOR) wmsg << s_header << generator << " is not a generator for the " "computed prime" << endl; else if (result & DH_UNABLE_TO_CHECK_GENERATOR) wmsg << s_header << "cannot check the validity of generator " << generator << endl; else throw Exception{} << s_header << "parameter check fails"; } bobcat-5.09.01/diffiehellman/skip.cc0000644000175000017500000000043714050437223016154 0ustar frankfrank#include "diffiehellman.ih" void DiffieHellman::skip(istream &in, size_t count) { for (; count--; ) { uint32_t length; in.read(reinterpret_cast(&length), sizeof(uint32_t)); length = ntohl(length); in.seekg(length, ios::cur); } } bobcat-5.09.01/diffiehellman/diffiehellman0000644000175000017500000001023414050437223017405 0ustar frankfrank #ifndef INCLUDED_BOBCAT_DIFFIEHELLMAN_ #define INCLUDED_BOBCAT_DIFFIEHELLMAN_ #include #include #include #include // For openssl1.1.0 see, e.g. DH_get0_pqg namespace FBB { class DiffieHellman { DH *d_dh; BIGNUM *d_otherPubKey; // public key of the other party BigInt d_prime; mutable BIGNUM const *d_pubKey; // assigned by DH_get0_key: no need mutable BIGNUM const *d_privKey;// to use BN_free static char const *s_header; public: enum SecretKey { DONT_SAVE_SECRET_KEY, SAVE_SECRET_KEY }; // The initiator calls this constructor to compute the common // DH parameters DiffieHellman(size_t primeLength = 1024, size_t generator = 5, // 1 bool progress = false); // The initiator saves the public info (prime (p), generator (g) // and the initiator's public key (g^k % p) on basename.pub // and, by providing 'SAVE_SECRET_KEY, the initiator's secret key // (k) on basename.sec void save(std::string const &basename, SecretKey action = DONT_SAVE_SECRET_KEY) const; // The initiator sends basename.pub to the peer, who reads // basename.pub using this constructor: DiffieHellman(std::string const &initiatorPublicFileName); // Alternatively, use this constructor expecting an istream: DiffieHellman(std::istream &initiatorPublicStream); // The peer now saves *his/her* public and (optionally) private // info: by calling save, providing a basename and optionally a // SecretKey argument. Next, the peer sends his/her public info // to the initiator. // The peer can already now determine the symmetric encryption // key (the shared key), since he/she has // - The DH prime and generator (received from the initiator) // - The initiator's public key (received from the initiator) // - His/her own secret key. // The shared key is returned in a string by calling std::string key() const; // 1 // The initiator has two options: - After calling save and // transmitting the public data to the peer the DiffieHellman // object is kept, and the initiator waits for the peer's public // key to become available. In that case the initiator's private // key doesn't have to be saved, and ephemeral DH is // obtained. After receiving the peer's public parameters the // initiator calls either of these overloaded versions of key to // obtain the symmetric key: std::string key(std::string const &peerPublicFileName); // 2 std::string key(std::istream &peerPublicStream); // 3 // Otherwise the initiator creates another DiffieHellman object, // using the 4th or 5th constructor, and then calls either of the // last two key members to obtain the symmetric key. DiffieHellman(std::string const &initiatorPublicFileName, std::string const &initiatorPrivateFileName); // Alternatively, use this constructor expecting istreams: DiffieHellman(std::istream &initiatorPublicStream, // 5 std::istream &initiatorPrivateStream); ~DiffieHellman(); private: void checkDHparameters(); bool load(std::istream &publicData, BIGNUM **pub_key); // *pub_key is // allocated inside this function void write(std::ostream &out, BIGNUM const *bn, char *buffer, uint32_t nBytes) const; bool read(std::istream &in, BIGNUM **dest); static void skip(std::istream &in, size_t count); static int callback(int, int, BN_GENCB *); std::string publicKey() const; std::string sharedKey(BigInt const &peersPublicKey); }; } // FBB #endif bobcat-5.09.01/diffiehellman/data.cc0000644000175000017500000000012614050437223016112 0ustar frankfrank#include "diffiehellman.ih" char const *DiffieHellman::s_header = "DiffieHellman: "; bobcat-5.09.01/diffiehellman/key1.cc0000644000175000017500000000207414050437223016056 0ustar frankfrank#include "diffiehellman.ih" // given the current user's (initiator or peer) private key and the // other party's public key, compute the shared secret string DiffieHellman::key() const { size_t length = DH_size(d_dh); char buffer[length]; if ( DH_compute_key(reinterpret_cast(buffer), d_otherPubKey, d_dh) == -1 ) throw Exception{} << s_header << "could not compute the shared key"; string ret(buffer, buffer + length); BigInt theKey(ret); BigInt qValue{(d_prime - 1) >> 1}; // (prime - 1) / 2 is also prime, as // prima is a safe prime. qValue, according to // RFC 2631 should be so that p = j * q + 1 // is prime. Here j == 2 if ( theKey == 1 || theKey >= d_prime - 1 || theKey.expModc(qValue, d_prime) != 1 ) throw Exception{} << "Key not resistant to the small group attack"; return ret; } bobcat-5.09.01/diffiehellman/read.cc0000644000175000017500000000103614050437223016115 0ustar frankfrank#include "diffiehellman.ih" bool DiffieHellman::read(istream &in, BIGNUM **dest) { if (not *dest) // No BIGNUM available (allocation return false; // failed) uint32_t length; in.read(reinterpret_cast(&length), sizeof(uint32_t)); length = ntohl(length); char buffer[length]; in.read(buffer, length); BN_free(*dest); *dest = BN_bin2bn( reinterpret_cast(buffer), length, 0 ); return *dest; } bobcat-5.09.01/diffiehellman/callback.cc0000644000175000017500000000033614050437223016740 0ustar frankfrank#include "diffiehellman.ih" namespace { char info[] = {0, '.', '-', '+'}; } int DiffieHellman::callback(int indicator, int, BN_GENCB *) { if (indicator) cout.put(info[indicator]).flush(); return 1; } bobcat-5.09.01/diffiehellman/save.cc0000644000175000017500000000264014050437223016142 0ustar frankfrank#include "diffiehellman.ih" // save the prime, the generator, the public key, and the private key void DiffieHellman::save(string const &basename, SecretKey action) const { if (DH_generate_key(d_dh) == 0) throw Exception{} << "DiffieHellman::save: could not generate " "public/private keys"; BIGNUM const *g; DH_get0_pqg(d_dh, 0, 0, &g); DH_get0_key(d_dh, &d_pubKey, &d_privKey); int nBytes[] = { static_cast(d_prime.sizeInBytes()), BN_num_bytes(g), BN_num_bytes(d_pubKey), BN_num_bytes(d_privKey) }; unique_ptr dest(new char[*max_element(nBytes, nBytes + 4)]); ofstream out; Exception::open(out, basename + ".pub"); write(out, &d_prime.bignum(), dest.get(), nBytes[0]); write(out, g, dest.get(), nBytes[1]); write(out, d_pubKey, dest.get(), nBytes[2]); if (not out) throw Exception{} << "Could not write public DH info to `" << basename + ".pub'"; if (action == DONT_SAVE_SECRET_KEY) return; out.close(); Exception::open(out, basename + ".sec"); write(out, d_privKey, dest.get(), nBytes[3]); if (not out) throw Exception{} << "Could not write private DH info to `" << basename + ".sec'"; } bobcat-5.09.01/diffiehellman/key3.cc0000644000175000017500000000065714050437223016065 0ustar frankfrank#include "diffiehellman.ih" string DiffieHellman::key(istream &peerPublicStream) { skip(peerPublicStream, 2); BIGNUM *otherPubKey = BN_new(); if (not (otherPubKey && read(peerPublicStream, &otherPubKey))) throw Exception{} << s_header << "could not read the peer's public key"; BN_free(d_otherPubKey); d_otherPubKey = otherPubKey; return key(); } bobcat-5.09.01/diffiehellman/diffiehellman1.cc0000644000175000017500000000154014050437223020052 0ustar frankfrank#include "diffiehellman.ih" DiffieHellman::DiffieHellman(size_t primeLength, size_t generator, bool progress) : d_dh(DH_new()), d_otherPubKey(0) { if (progress) // if true, prime generation is shown cout << '\n'; // as a series of dots etc, which start // on a new line BN_GENCB *cb = BN_GENCB_new(); BN_GENCB_set(cb, callback, 0); // Generate prime (p), using generator if (not DH_generate_parameters_ex(d_dh, primeLength, generator, progress ? cb : 0)) throw Exception{} << s_header << "generating parameters failed"; BN_GENCB_free(cb); if (progress) cout << endl; checkDHparameters(); // verify the validity of p and generator } bobcat-5.09.01/diffiehellman/diffiehellman2.cc0000644000175000017500000000027714050437223020061 0ustar frankfrank#include "diffiehellman.ih" DiffieHellman::DiffieHellman(string const &initiatorPublicFileName) : DiffieHellman(*unique_ptr(new ifstream(initiatorPublicFileName))) {} bobcat-5.09.01/diffiehellman/destructor.cc0000644000175000017500000000016014050437223017375 0ustar frankfrank#include "diffiehellman.ih" DiffieHellman::~DiffieHellman() { DH_free(d_dh); BN_free(d_otherPubKey); } bobcat-5.09.01/diffiehellman/key2.cc0000644000175000017500000000026514050437223016057 0ustar frankfrank#include "diffiehellman.ih" string DiffieHellman::key(std::string const &peerPublicFileName) { ifstream in; Exception::open(in, peerPublicFileName); return key(in); } bobcat-5.09.01/diffiehellman/diffiehellman4.cc0000644000175000017500000000045514050437223020061 0ustar frankfrank#include "diffiehellman.ih" DiffieHellman::DiffieHellman(string const &publicFileName, string const &privateFileName) : DiffieHellman(*unique_ptr(new ifstream(publicFileName)), *unique_ptr(new ifstream(privateFileName))) {} bobcat-5.09.01/diffiehellman/diffiehellman3.cc0000644000175000017500000000051014050437223020050 0ustar frankfrank#include "diffiehellman.ih" DiffieHellman::DiffieHellman(istream &initiatorPublicStream) : d_dh(DH_new()) { if (not (initiatorPublicStream and load(initiatorPublicStream, &d_otherPubKey)) ) throw Exception{} << s_header << "could not load public values"; checkDHparameters(); } bobcat-5.09.01/diffiehellman/diffiehellman.ih0000644000175000017500000000242414050437223020006 0ustar frankfrank#include "diffiehellman" #include #include #include #include #include #include #include #include "../exception/exception" #include "../mstream/mstream" using namespace std; using namespace FBB; #if OPENSSL_VERSION_NUMBER < 0x10100000L inline BN_GENCB *BN_GENCB_new() { return new BN_GENCB;; } inline void BN_GENCB_free(BN_GENCB *cb) { delete cb; } inline void DH_set0_key(DH *dh, void *, BIGNUM *privateKey) { BN_free(dh->priv_key); dh->priv_key = privateKey; } inline void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key) { *pub_key = dh->pub_key; *priv_key = dh->priv_key; } inline void DH_get0_pqg(const DH *dh, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g) { *p = dh->p; *q = dh->q; *g = dh->g; } namespace FBB { inline void dh_reassign(BIGNUM **dest, BIGNUM *src) { if (src) { if (*dest) BN_free(*dest); *dest = src; } } } inline int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g) { FBB::dh_reassign(&dh->p, p); FBB::dh_reassign(&dh->q, q); FBB::dh_reassign(&dh->g, g); return 1; } #endif bobcat-5.09.01/diffiehellman/diffiehellman5.cc0000644000175000017500000000076114050437223020062 0ustar frankfrank#include "diffiehellman.ih" DiffieHellman::DiffieHellman(istream &publicStream, istream &privateStream) : DiffieHellman(publicStream) { BIGNUM *priv = BN_new(); if (not (priv && read(privateStream, &priv))) { BN_free(priv); throw Exception{} << s_header << "could not load private key"; } DH_set0_key(d_dh, d_otherPubKey, priv); // DH_set0_key owns // the received key d_otherPubKey = 0; } bobcat-5.09.01/diffiehellman/write.cc0000644000175000017500000000061514050437223016336 0ustar frankfrank#include "diffiehellman.ih" void DiffieHellman::write(ostream &out, BIGNUM const *bn, char *buffer, uint32_t nBytes) const { uint32_t nBytesStd = htonl(nBytes); out.write(reinterpret_cast(&nBytesStd), sizeof(uint32_t)); BN_bn2bin(bn, reinterpret_cast(buffer)); out.write(buffer, nBytes); } bobcat-5.09.01/diffiehellman/load.cc0000644000175000017500000000051014050437223016115 0ustar frankfrank#include "diffiehellman.ih" bool DiffieHellman::load(istream &publicData, BIGNUM **pub_key) { BIGNUM *p = BN_new(); BIGNUM *g = BN_new(); *pub_key = BN_new(); return read(publicData, &p) && read(publicData, &g) && read(publicData, pub_key) && DH_set0_pqg(d_dh, p, 0, g); } bobcat-5.09.01/diffiehellman/driver/0000755000175000017500000000000014050437223016166 5ustar frankfrankbobcat-5.09.01/diffiehellman/driver/build0000755000175000017500000000056714050437223017223 0ustar frankfrank#!/bin/bash # For development purposes: tput clear LIBS=" -lbobcat -lcrypto" GPP="g++ `cat ../../c++std`" # Using the standard bobcat library #CMD="$GPP -o driver -Wall *.cc ${LIBS} -s" # Using the library in ../tmp/ CMD="$GPP -o driver -Wall *.cc -isystem ../../tmp \ -L../tmp -ldiffiehellman -L../../bigint/tmp -lbigint ${LIBS} -s" echo ${CMD} ${CMD} bobcat-5.09.01/diffiehellman/driver/driver.cc0000644000175000017500000000177114050437223017776 0ustar frankfrank #include #include #include using namespace FBB; using namespace std; int main(int argc, char **argv) try { if (argc == 1) // initiator: create DH parameters { DiffieHellman dh(1024, 5, true); dh.save("init", DiffieHellman::SAVE_SECRET_KEY); } if (argc == 2) // peer: save peer's scret key { DiffieHellman dh("init.pub"); dh.save("peer", DiffieHellman::SAVE_SECRET_KEY); string key = dh.key(); cout << "Key length: " << key.length() << '\n'; ofstream outkey("peerkey"); outkey.write(key.data(), key.length()); } if (argc == 3) { DiffieHellman dh("init.pub", "init.sec"); string key = dh.key("peer.pub"); cout << "Key length: " << key.length() << '\n'; ofstream outkey("initkey"); outkey.write(key.data(), key.length()); } } catch (std::exception const &exc) { std::cout << exc.what() << '\n'; } bobcat-5.09.01/digestbuf/0000755000175000017500000000000014050437223014060 5ustar frankfrankbobcat-5.09.01/digestbuf/digestbuf1.cc0000644000175000017500000000060014050437223016420 0ustar frankfrank#include "digestbuf.ih" DigestBuf::DigestBuf(char const *type, size_t bufsize) : EoiBuf(bufsize), d_ctx(0) { OpenSSL_add_all_digests(); d_md = EVP_get_digestbyname(type); if (!d_md) { if (type == 0) type = "** unspecified digest type **"; throw Exception{ 1 } << "DigestBuf `" << type << "' not available"; } reset(); } bobcat-5.09.01/digestbuf/overflow.cc0000644000175000017500000000032414050437223016231 0ustar frankfrank#include "digestbuf.ih" int DigestBuf::overflow(int ch) { EVP_DigestUpdate(d_ctx, ucharPtr(), bufSize()); setp(); if (ch != EOF) { *pptr() = ch; pbump(1); } return ch; } bobcat-5.09.01/digestbuf/reset.cc0000644000175000017500000000031514050437223015510 0ustar frankfrank#include "digestbuf.ih" void DigestBuf::reset() { if (d_ctx) return; d_ctx = EVP_MD_CTX_new(); EVP_DigestInit_ex(d_ctx, d_md, 0); d_digest.resize(EVP_MAX_MD_SIZE); setp(); } bobcat-5.09.01/digestbuf/digestbuf0000644000175000017500000000141714050437223015762 0ustar frankfrank#ifndef INCLUDED_BOBCAT_DIGESTBUF_ #define INCLUDED_BOBCAT_DIGESTBUF_ #include #include namespace FBB { class DigestBuf: public EoiBuf { friend std::ostream &operator<<(std::ostream &out, DigestBuf const &digestbuf); EVP_MD_CTX *d_ctx; EVP_MD const *d_md; std::string d_digest; public: explicit DigestBuf(char const *type, size_t bufsize = 1024); void reset(); void eoi(); std::string const &hash() const; private: int overflow(int c) override; void eoi_() override; // .cc }; #include "eoi.f" std::ostream &operator<<(std::ostream &out, DigestBuf const &digestbuf); } // FBB #endif bobcat-5.09.01/digestbuf/hash.cc0000644000175000017500000000013114050437223015305 0ustar frankfrank#include "digestbuf.ih" string const &DigestBuf::hash() const { return d_digest; } bobcat-5.09.01/digestbuf/eoi.f0000644000175000017500000000005514050437223015003 0ustar frankfrankinline void DigestBuf::eoi() { eoi_(); } bobcat-5.09.01/digestbuf/operatorinsert.cc0000644000175000017500000000041014050437223017442 0ustar frankfrank#include "digestbuf.ih" namespace FBB { std::ostream &operator<<(std::ostream &out, DigestBuf const &digestbuf) { OHexBuf ohex(out); ostream outs(&ohex); outs.write(digestbuf.d_digest.data(), digestbuf.d_digest.length()); return out; } } // FBB bobcat-5.09.01/digestbuf/eoi.cc0000644000175000017500000000063614050437223015150 0ustar frankfrank#include "digestbuf.ih" #include void DigestBuf::eoi_() { //cerr << __FILE__"\n"; if (d_ctx == 0) return; if (pptr() > pbase()) EVP_DigestUpdate(d_ctx, ucharPtr(), pptr() - pbase()); unsigned int digestbufLen; EVP_DigestFinal_ex(d_ctx, ucharPtr(d_digest), &digestbufLen); d_digest.resize(digestbufLen); EVP_MD_CTX_free(d_ctx); d_ctx = 0; } bobcat-5.09.01/digestbuf/driver/0000755000175000017500000000000014050437223015353 5ustar frankfrankbobcat-5.09.01/digestbuf/driver/build0000755000175000017500000000145314050437223016403 0ustar frankfrank#!/bin/sh ln -s .. bobcat # # g++ -I. --std=c++2a -O2 -Wall -o driver driver.cc -lssl -lbobcat \ # -L../../ohexbuf/tmp -L../tmp -lhmacbuf -lohexbuf # tput clear LIBS=" -lbobcat -lcrypto" GPP="g++ --std=c++2a" # Using the standard bobcat library # CMD="$GPP -o driver -Wall *.cc ${LIBS} -s" # Using the library in ../tmp/ and bobcat as /tmp/libbob.a CMD="$GPP -o driver -Wall *.cc -L../tmp -lhmacbuf -L /tmp -lbob -lcrypto -s" # Using the library in ../tmp/ CMD="$GPP -o driver -Wall *.cc -L../tmp -ldigestbuf ${LIBS} -s" # # Using tmp libraries and bobcat # CMD="$GPP -o driver -Wall -I../tmp driver.cc \ # -L../tmp -ldigestbuf \ # -L../../ohexbuf/tmp -lohexbuf \ # -L../../eoibuf/tmp -leoibuf \ # -L../../eoi/tmp -leoi \ # ${LIBS} -s" echo ${CMD} ${CMD} rm bobcat bobcat-5.09.01/digestbuf/driver/driver.cc0000644000175000017500000000102514050437223017153 0ustar frankfrank#include #include #include #include "../digestbuf" using namespace std; using namespace FBB; int main(int argc, char **argv) try { DigestBuf digestbuf(argv[1]); ostream out(&digestbuf); string hw("hello world\n"); out << hw << eoi; cout << ">" << digestbuf << "<" << endl; digestbuf.reset(); out.write(hw.c_str(), hw.length()) << eoi; cout << ">" << digestbuf << "<" << endl; } catch(exception const &err) { cout << err.what() << endl; return 1; } bobcat-5.09.01/digestbuf/digestbuf.ih0000644000175000017500000000076614050437223016367 0ustar frankfrank#include "digestbuf" #include #include #include #include "../exception/exception" #include "../ohexbuf/ohexbuf" #if OPENSSL_VERSION_NUMBER < 0x10100000L inline EVP_MD_CTX *EVP_MD_CTX_new() { EVP_MD_CTX *ret = new EVP_MD_CTX; EVP_MD_CTX_init(ret); return ret; } inline void EVP_MD_CTX_free(EVP_MD_CTX *ctx) { EVP_MD_CTX_cleanup(ctx); delete ctx; } #endif using namespace std; using namespace FBB; bobcat-5.09.01/documentation/0000755000175000017500000000000014050437223014755 5ustar frankfrankbobcat-5.09.01/documentation/examples/0000755000175000017500000000000014050437223016573 5ustar frankfrankbobcat-5.09.01/documentation/examples/sockets/0000755000175000017500000000000014050437223020246 5ustar frankfrankbobcat-5.09.01/documentation/examples/sockets/forkserver/0000755000175000017500000000000014050437223022436 5ustar frankfrankbobcat-5.09.01/documentation/examples/sockets/forkserver/main.cc0000644000175000017500000000317314050437223023675 0ustar frankfrank#include "main.ih" void sigchld_handler(int signum) { static bool stop = false; int status; int pid = waitpid(WAIT_ANY, &status, WNOHANG); if (pid <= 0) // ignore erroroneus or no child available but { cerr << "waitpid() returned " << pid << ", ignoring\n"; return; // the handler is still called. } stop = (WEXITSTATUS(status) != 0); cerr << "Process " << pid << " returns exit status " << WEXITSTATUS(status) << ", stop = " << stop << endl; if (stop) // terminate when done exit(0); } int main(int argc, char **argv, char **envp) try { if (argc == 1) { cout << "port number required\n"; return 1; } signal(SIGCHLD, sigchld_handler); // handle terminating children size_t portnr = stoul(argv[1]); ServerSocket server(portnr); server.listen(); // plain blocking listen-mode while (true) { cerr << "\n" "Wait for incoming requests..." << endl; SocketBase fdb = server.accept(); // wait for incoming int fd = fdb.socket(); cerr << "Client FD = " << fd << ", " << endl << "address = " << fdb.dottedDecimalAddress() << ", " << endl << "communication through port " << fdb.port() << endl; Handler handler(fd); // create separate process for each handler.fork(); // connection } } catch(exception const &error) { cerr << error.what() << '\n'; return 1; } bobcat-5.09.01/documentation/examples/sockets/forkserver/main.ih0000644000175000017500000000035614050437223023710 0ustar frankfrank#include #include #include #include #include #include #include #include "handler/handler.h" using namespace std; using namespace FBB; bobcat-5.09.01/documentation/examples/sockets/forkserver/handler/0000755000175000017500000000000014050437223024053 5ustar frankfrankbobcat-5.09.01/documentation/examples/sockets/forkserver/handler/chidlprocess.cc0000644000175000017500000000111014050437223027035 0ustar frankfrank#include "handler.ih" void Handler::childProcess() try { IFdStream in(d_descriptor); // stream to read from client string cmd; if (getline(in, cmd)) { cerr << "Child process gets: `" << cmd << "'" << endl; if (cmd[0] != 'q') // terminate if client sends `q' throw 0; } throw 1; } catch (int ret) { close(d_descriptor); // the connection is terminated cerr << "Child process " << getpid() << " exits with status " << ret << endl; exit(ret); } bobcat-5.09.01/documentation/examples/sockets/forkserver/handler/handler.h0000644000175000017500000000065014050437223025642 0ustar frankfrank#ifndef INCLUDED_HANDLER_ #define INCLUDED_HANDLER_ #include #include class Handler: public FBB::Fork { size_t d_descriptor; public: Handler(size_t descriptor) : d_descriptor(descriptor) {} private: void childProcess() override; void parentProcess() override { close(d_descriptor); } }; #endif bobcat-5.09.01/documentation/examples/sockets/forkserver/handler/handler.ih0000644000175000017500000000020414050437223026006 0ustar frankfrank#include "handler.h" #include #include #include using namespace std; using namespace FBB; bobcat-5.09.01/documentation/examples/sockets/forkserver/CLASSES0000644000175000017500000000001014050437223023445 0ustar frankfrankhandler bobcat-5.09.01/documentation/examples/sockets/README0000644000175000017500000000621414050437223021131 0ustar frankfrankThe directories below this one contain various programs illustrating the CLientSocket and ServerSocket classes. To compile the programs, descend into the directories and run the `build' script. Icmake must be available to run `build'. The following programs are available: - server - simple server program, serving one client at the time. Start the server as server where is the port at which the server will listen for incoming connections. E.g., server 12345 The communication protocol is extremely simple: the server expects a single line from the client, echoes the line and terminates the connection. If the line holds a single `q' the server itself will terminate. - client - simple client program, matching the abovementioned server. Start the client as client where is the name of the computer running the server, and is the port at which the server will listen for incoming connections. E.g., client localhost 12345 - forkserver - simple server program, serving multiple clients, each running as its own independent process. It implements the same protocol as `server', mentioned above. Start the server as forkserver where is the port at which the server will listen for incoming connections. E.g., forkserver 12345 Use the client defined in the `client' subdirectory. - forkserver2 - server program, serving multiple clients, each running as its own independent process. It implements a more complex protocol than `forkserver' Start the server as forkserver2 where is the port at which the server will listen for incoming connections. E.g., forkserver2 12345 The protocol allows for 2-way communication between client(s) and server. The server will start an independent process for each new client, and these processes will echo lines received from clients back to the clients. If a client sends a line holding a single `q', the server process terminates. Use the `client2' program (see below) with this server. - client2 - client program, matching the abovementioned server. Start the client as client2 where is the name of the computer running the server, and is the port at which the server will listen for incoming connections. E.g., client2 localhost 12345 bobcat-5.09.01/documentation/examples/sockets/server/0000755000175000017500000000000014050437223021554 5ustar frankfrankbobcat-5.09.01/documentation/examples/sockets/server/server.cc0000644000175000017500000000244514050437223023376 0ustar frankfrank/* server.cc */ #include #include #include #include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) try { if (argc == 1) { cout << "port number required\n"; return 1; } size_t portnr = stoul(argv[1]); ServerSocket server(portnr); server.listen(); // plain blocking listen-mode while (true) { SocketBase fdb = server.accept(); // wait for incoming int fd = fdb.socket(); cerr << "Client FD = " << fd << ", " << endl << "address = " << fdb.dottedDecimalAddress() << ", " << endl << "communication through port " << fdb.port() << endl; IFdStream in(fd); // stream to read from client string cmd; if (getline(in, cmd)) { cout << "Got: " << cmd << endl; if (cmd[0] == 'q') // terminate if client sends `q' return 0; close(fd); // the connection is terminated } } } catch(exception const &error) { cerr << error.what() << endl; return 1; } bobcat-5.09.01/documentation/examples/sockets/forkserver2/0000755000175000017500000000000014050437223022520 5ustar frankfrankbobcat-5.09.01/documentation/examples/sockets/forkserver2/main.cc0000644000175000017500000000357314050437223023763 0ustar frankfrank/* forkserver2.cc */ #include #include #include #include #include #include #include #include "handler/handler.h" using namespace std; using namespace FBB; void sigchld_handler(int signum) { static bool stop = false; int status; int pid = waitpid(WAIT_ANY, &status, WNOHANG); if (pid <= 0) // ignore erroroneus or no child available but { cerr << "waitpid() returned " << pid << ", ignoring\n"; return; // the handler is still called. } stop = (WEXITSTATUS(status) != 0); cerr << "Process " << pid << " returns exit status " << WEXITSTATUS(status) << ", stop = " << stop << endl; if (stop) // terminate when done exit(0); } int main(int argc, char **argv) try { if (argc == 1) { cout << "port number required\n"; return 1; } signal(SIGCHLD, sigchld_handler); // handle terminating children size_t portnr = stoul(argv[1]); ServerSocket server(portnr); server.listen(); // plain blocking listen-mode while (true) { cerr << "\n" "Wait for incoming requests..." << endl; SocketBase fdb = server.accept(); // wait for incoming int fd = fdb.socket(); cerr << "Client FD = " << fd << ", " << endl << "address = " << fdb.dottedDecimalAddress() << ", " << endl << "communication through port " << fdb.port() << endl; Handler handler(fd); // create separate process for each handler.fork(); // connection } } catch(exception const &error) { cerr << error.what() << '\n'; return 1; } bobcat-5.09.01/documentation/examples/sockets/forkserver2/main.ih0000777000175000017500000000000014050437223027634 2../forkserver/main.ihustar frankfrankbobcat-5.09.01/documentation/examples/sockets/forkserver2/handler/0000755000175000017500000000000014050437223024135 5ustar frankfrankbobcat-5.09.01/documentation/examples/sockets/forkserver2/handler/chidlprocess.cc0000644000175000017500000000125414050437223027130 0ustar frankfrank#include "handler.ih" void Handler::childProcess() try { IFdStream in(d_descriptor); // stream to read from client OFdStream out(d_descriptor); // stream to write to client string cmd; while (getline(in, cmd)) { cout << "Got: " << cmd << endl; out << "Got: " << cmd << "\r" << endl; if (cmd[0] == 'q') throw 1; // terminate the server } throw 0; } catch (int ret) { close(d_descriptor); // the connection is terminated cerr << "Child process " << getpid() << " exits with status " << ret << endl; exit(ret); } bobcat-5.09.01/documentation/examples/sockets/forkserver2/handler/handler.h0000777000175000017500000000000014050437223033741 2../../forkserver/handler/handler.hustar frankfrankbobcat-5.09.01/documentation/examples/sockets/forkserver2/handler/handler.ih0000644000175000017500000000024014050437223026070 0ustar frankfrank#include "handler.h" #include #include #include #include using namespace std; using namespace FBB; bobcat-5.09.01/documentation/examples/sockets/forkserver2/CLASSES0000777000175000017500000000000014050437223027160 2../forkserver/CLASSESustar frankfrankbobcat-5.09.01/documentation/examples/sockets/client2/0000755000175000017500000000000014050437223021606 5ustar frankfrankbobcat-5.09.01/documentation/examples/sockets/client2/client2.cc0000644000175000017500000000276714050437223023471 0ustar frankfrank#include #include #include #include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) try { if (argc != 3) { cerr << "Provide servername and port number\n"; return 1; } size_t port = stoul(argv[2]); ClientSocket client(argv[1], port); int fd = client.connect(); string line; cout << "Connecting to socket " << fd << endl << "address = " << client.dottedDecimalAddress() << ", " << endl << "communication through port " << client.port() << endl; IFdStream in(fd); // stream to read from OFdStream out(fd); // stream to write to while (true) { // Ask for a textline, stop if cout << "? "; // empty / none if (!getline(cin, line) || line.length() == 0) return 0; cout << "Line read: " << line << endl; // Return the line to the server out << line.c_str() << endl; cout << "wrote line\n"; getline(in, line); // Wait for a reply from the server cout << "Answer: " << line << endl; } } catch (exception const &err) { cerr << err.what() << "\n" << "Can't connect to " << argv[1] << ", port " << argv[2] << '\n'; return 1; } bobcat-5.09.01/documentation/examples/sockets/client/0000755000175000017500000000000014050437223021524 5ustar frankfrankbobcat-5.09.01/documentation/examples/sockets/client/client.cc0000644000175000017500000000245314050437223023315 0ustar frankfrank#include #include #include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) try { if (argc != 3) { cerr << "Provide servername and port number\n"; return 1; } size_t port = stoul(argv[2]); ClientSocket client(argv[1], port); int fd = client.connect(); string line; cout << "Connecting to socket " << fd << endl << "address = " << client.dottedDecimalAddress() << ", " << endl << "communication through port " << client.port() << endl; OFdStream out(fd); // stream to write to while (true) { // Ask for a textline, stop if cout << "? "; // empty / none if (!getline(cin, line) || line.length() == 0) return 0; cout << "Line read: " << line << endl; // Send the line to the server out << line.c_str() << endl; cout << "wrote line\n"; } } catch (exception const &err) { cerr << err.what() << "\n" << "Can't connect to " << argv[1] << ", port " << argv[2] << '\n'; return 1; } bobcat-5.09.01/documentation/man/0000755000175000017500000000000014050437223015530 5ustar frankfrankbobcat-5.09.01/documentation/man/log.yo0000644000175000017500000002747314050437223016677 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Log)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Log messages) manpagename(FBB::Log)(tt(std::ostream) handling log messages) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat)nl() manpagedescription() The class bf(FBB::Log) defines an tt(std::ostream) using an tt(FBB::LogBuf std::streambuf). It is used to send log-messages to the (r)syslog stream or to a (configurable) file. Refer to the bf(logbuf)(3bobcat) man-page for details about tt(LogBuf). Which (parts of) messages are actually logged can be configured using bf(FBB::level) in combination with the tt(Log) member tt(setLevel). By default all information that is inserted into a tt(Log) object is logged, but tt(level) objects (bf(level)(3bobcat)) can be inserted specifying insertion `forces' of the information that is subsequently inserted into tt(Log) objects. These `forces' are compared to insertion `resistances' that can be specified by tt(Log) objects through their tt(setLevel) members. If the tt(level's) `force' is equal to or exceeds the tt(Log) object's `resistance' then the insertion is performed, otherwise the insertion is ignored. A single insertion statement may contain multiple tt(level) calls. If so, then each tt(level) call updates the `force' of insertions following the tt(level) call. Information inserted into tt(Log) objects without inserting tt(level) objects (or before the first tt(level) object) is always logged (see also the bf(Examples) section). By default logged messages are prepended by time stamps. Following the time stamps a delimiter (by default a single space character) is inserted. Delimiters are immediately appended to time stamps and inserted messages are immediately appended to delimiters. When specifying text as delimiters consider starting and ending the delimiter's text with space characters to visually separate the delimiter from the time stamp and from the subsequently inserted information. includefile(include/namespace) manpagesection(INHERITS FROM) tt(std::ostream) manpagesection(ENUMERATIONS) The enumeration tt(TimeStamps) is defined in the namespace tt(FBB), primarily for initializing tt(FBB::LogBuf) objects. It is used with tt(Log) members as well. It has the following values: itemization( itb(NOTIMESTAMPS) Log-messages will not have timestamps prepended to them. itb(TIMESTAMPS) Log-messages will have timestamps prepended to them. itb(UTCTIMESTAMPS) Log-messages will have timestamps showing the UTC time prepended to them. ) The enumeration tt(LogManipulator) is used to handle special or exceptional situations through manipulators. It is defined in the namespace tt(FBB) and has the following two values: itemization( itb(FATAL) When inserting tt(FATAL) into a tt(Log) object an tt(FBB::Exception) exception is thrown (see tt(operator<<) below); itb(nl) When inserting tt(nl) into a tt(Log) object a tt(\n) character is inserted into the current line. If time stamps are requested the the next line will not begin with a time stamp. It is used to allow a single log message to occupy multiple textual lines. The next logged line is not indented over the width of the omitted time stamp. If that's preferred: the time stamp occupies 15 character positions (not counting the width of the delimiter, see the bf(CONSTRUCTORS) section below). If a tt(level) specification is active, it remains active at insertions following tt(nl). itb(fnl) When inserting tt(fnl) (forced new line) into a tt(Log) object the current line ends even if the currently active insertion `force' (set by tt(level)) is lower than the tt(Log) object's `resistance' level. If a tt(level) specification is active, it remains active at insertions following tt(fnl). it() bf(endl) or bf(\n):nl() When inserting tt(endl) or tt(\n) the current line is ended and the next logged line starts with a timestamp (unless timestamps are suppressed). The tt(endl) manipulator is the standard tt(ostream) manipulator: when inserted into a tt(Log) object its buffer is flushed. The scope of a tt(level) specification ends at tt(\n) or tt(endl). E.g., verb( log.setLevel(2); log << level(1) << "first line\n" "second line\n"; ) results in tt(second line) (preceded by a timestamp) being logged. ) manpagesection(CONSTRUCTORS) itemization( itb(Log()) The default constructor creates a tt(Log) object which isn't yet associated with a stream to log messages on. The member tt(open) (see below) may be used to define such a stream. By default, all messages are preceded by a time stamp (see the description of the member tt(setTimestamp) below), and a single space character is inserted as delimiter immediately beyond the time stamp. The member tt(open) can be used to modify the default delimiter. itb(Log(std::ostream &out, char const *delim = " ")) This constructor creates a tt(Log) object logging its messages to the provided tt(std::ostream) object. By default, all messages are preceded by a time stamp (see the description of the member tt(setTimestamp) below). The parameter tt(delim) is inserted immediately beyond the time stamp. If a delimiter should not be used an empty string or a 0-pointer may be specified. itb(FBB::Log(std::string const &filename, std::ios::openmode mode = std::ios::out | std::ios::app, char const *delim = " ")) This constructor creates a tt(Log) object logging its messages to the named file. If tt(filename == "&1") logmessages are written to the standard output stream. If tt(filename == "&2") logmessages are written to the standard error stream. By default the file is created if not existing, and all messages are appended to the stream. Also by default all messages are preceded by time stamps (see the description of the member tt(setTimestamp) below). The parameter tt(delim) is inserted immediately beyond the time stamp. If a delimiter should not be used an empty string or a 0-pointer may be specified. ) Copy and move constructors (and assignment operators) are not available. manpagesection(MEMBER FUNCTIONS) All members of tt(std::ostream) are available, as tt(Log) inherits from this class. itemization( itb(size_t level()) This member returns the currently set log level (i.e., the value set at the latest tt(setLevel()) call). By default, the level is set to zero, meaning that all information is inserted into the log stream; itb(std::ostream &level(size_t useLevel)) This member defines the log-level of messages that are going to be inserted. Messages are inserted when tt(useLevel) is at least equal to the level specified by tt(setLevel). The maximum level is tt(std::numeric_limits::max()). If not even such messages should be inserted into the tt(ostream), then the stream should be deactivated, using tt(off()) (see below). The level that is specified by this member remains active until another tt(level) call changes it. Alternatively, the level of inserted messages may be specified by inserting a tt(FBB::level) manipulator into a tt(Log) object (see bf(level)(3bobcat)); itb(void off()) Prevents log messages from being generated. It is cancelled by calling tt(on) (see below); itb(void on(size_t logLevel = 0)) Reactivates logging (e.g., after tt(off) was previously called) setting the level that inserted information must at least have (to tt(logLevel)). Following tt(on) and unless specified otherwise (e.g., by using tt(level)) all inserted information is accpted by the tt(Log) object; itb(void open(std::string const &filename, std::ios::openmode mode = std::ios::out | std::ios::app, char const *delim = " ")) This member (re)associates a tt(Log) object with the named file. If tt(filename == "&1") the logmessages will be written to the standard output stream. If tt(filename == "&2") the logmessages will be written to the standard error stream. By default the file is created if not existing, and all messages are appended to the stream. Also by default all messages are preceded by time stamps (see the description of the member tt(setTimestamp) below). The parameter tt(delim) is inserted immediately beyond the time stamp. If a delimiter should not be used an empty string or a 0-pointer may be specified; itb(void setLevel(size_t resistance)) Defines the `resistance' when inserting information into a tt(Log) object. Information is inserted if the level set by the tt(level) member is at least equal to tt(resistance). Following tt(setLevel) and unless specified otherwise (e.g., by using tt(level)) all inserted information is accpted by the tt(Log) object. tt(setLevel) does not reactivate logging after calling tt(off). To reactivate logging after calling tt(off on) must be called; itb(void setTimestamp(FBB::TimeStamps stamp, char const *delim = " ")) The member function (de)activates time stamp prepending. Use the value tt(FBB::TIMESTAMPS) to prepend time stamps, tt(FBB::NOTIMESTAMPS) suppresses time stamps. A timestamp consists of 15 characters showing the abbreviated month's name, two-digits specifying the day number of the month, and the (local or UTC) time of the current message, as usually appearing in messages in tt(/var/log) files. E.g., tt(Aug 05 13:52:23). The parameter tt(delim) is inserted immediately beyond the time stamp. If a delimiter is inappropriate, an empty string or a 0-pointer may be specified. When specifying tt(stamps) as tt(FBB::NOTIMESTAMPS delim) also is ignored. ) manpagesection(STATIC MEMBERS) itemization( itb(FBB::Log &initialize(std::string const &filename, std::ios::openmode mode = std::ios::out | std::ios::app, char const *delim = " ")) Returns a reference to a static tt(Log) object. It may only be called once, or an tt(FBB::Exception) exception is thrown. It associates a static tt(Log) object with the named file. If tt(filename == "&1") logmessages are written to the standard output stream. If tt(filename == "&2") logmessages are written to the standard error stream. By default the file is created if not existing, and all messages are appended to the stream. Also by default all messages are preceded by time stamps (see the description of the member tt(setTimestamp) below). The parameter tt(delim) is inserted immediately beyond the time stamp. If a delimiter should not be used an empty string or a 0-pointer may be specified. itb(FBB::Log &instance()) Returns a reference to a static tt(Log) object, available after calling tt(Log::initialize). If called before tt(Log::initialize()) an tt(FBB::Exception) exception is thrown. ) manpagesection(OVERLOADED OPERATOR) The following overloaded operator is defined outside of the tt(FBB) namespace. It is used to insert an tt(FBB::LogManipulator) into a tt(Log) object. If the overloaded operator is used in combination with another kind of stream it performs no actions. itemization( itb(std::ostream &::operator<<(std::ostream &str, FBB::LogManipulator)) When inserting tt(FBB::FATAL) an tt(FBB::Exception) exception is thrown; when inserting tt(FBB::nl) the line is terminated, but next insertions will not start with a time stamp (if applicable). ) manpagesection(EXAMPLE) verbinclude(../../log/driver/driver.cc) manpagefiles() em(bobcat/log) - defines the class interface manpageseealso() bf(bobcat)(7), bf(exception)(3bobcat), bf(level)(3bobcat), bf(logbuf)(3bobcat) manpagebugs() The tt(nl) and tt(fnl) manipulators are received by the tt(Log) objects' tt(LogBufs) as, respectively, characters 0 and 1. Since log files in practice only received printable characters this should not cause any problems. includefile(include/trailer) bobcat-5.09.01/documentation/man/ofdstream.yo0000644000175000017500000000367014050437223020073 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::OFdStream)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (File Descriptor Output Stream) manpagename(FBB::Ofdstream)(Output Stream initialized by a File Descriptor) manpagesynopsis() bf(#include )nl() manpagedescription() bf(FBB::OFdStream) objects may be used to insert information into a device whose file descriptor is available. File descriptors are not defined within the context of bf(C++), but they can be used on operating systems that support the concept. Realize that using file descriptors introduces operating system dependencies. Note that em(sockets) can be used as file descriptors. includefile(include/namespace) manpagesection(INHERITS FROM) bf(std::ostream) manpagesection(CONSTRUCTORS) itemization( itb(OFdStream(int fd, size_t n = 1)) The constructor initializes the object to write to descriptor tt(fd), using a buffer of size tt(n), by default having size 1. ) Copy and move constructors (and assignment operators) are not available. manpagesection(MEMBER FUNCTIONS) All members of bf(std::ostream) are available, as bf(FBB::OFdStream) inherits from this class. There are no additional members. manpagesection(EXAMPLE) See the bf(clientsocket)(3bobcat) man-page for an example showing how to use tt(OFdStream). manpagefiles() em(bobcat/ofdstream) - defines the class interface manpageseealso() bf(bobcat)(7), bf(ifdstream)(3bobcat), bf(ofdbuf)(3bobcat) manpagebugs() The tt(OFdStream) object uses a tt(OFdStreamBuf) for its tt(std::streambuf). This buffer is associated with the file descriptor passed to tt(OFdStream)'s constructor. When the tt(OFdStream) object goes out of scope the device (file, socket, etc.) to which the file descriptor that was passed to tt(OFdStream)'s constructor is em(not) closed. includefile(include/trailer) bobcat-5.09.01/documentation/man/sharedbuf.yo0000644000175000017500000001670714050437223020057 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::SharedBuf)(3bobcat)(_CurYrs_) (libbobcat-dev__CurVers_) (Error handler) manpagename(FBB::SharedBuf)(streambuf interfacing to shared memory) manpagesynopsis() bf(#include )nl() Linking option: tt(-lpthread -lbobcat) manpagedescription() This class implements a specialization of the bf(std::streambuf) class, allowing stream classes (tt(std::istream, std::ostream, FBB::ISharedStream, FBB::OSharedStream) and tt(FBB::SharedStream)) to perform I/O operations on shared memory. bf(FBB::SharedBuf) objects interface to a tt(FBB::SharedMemory) objects. includefile(include/namespace) manpagesection(INHERITS FROM) bf(std::streambuf, FBB::SharedEnum__) (cf. bf(sharedmemory(3bobcat)) for a description of the latter class). manpagesection(SIZEUNIT ENUMERATION) The bf(enum SizeUnit) defines the following symbolic constants: itemization( it() bf(kB), representing 1024 (2**10) bytes of memory; it() bf(MB), representing 1048576 (2**20) bytes of memory; it() bf(GB), representing 1073741824 (2**30) bytes of memory ) manpagesection(CONSTRUCTORS) itemization( itb(SharedBuf()) The default constructor defines a stub bf(SharedBuf) object that cannot immediately be used to access shared memory. Before it can be used by, shared stream classes like tt(FBB::SharedStream), its member tt(setMemory) must first have been called. itb(SharedBuf(size_t maxSize, SizeUnit sizeUnit, std::ios::openmode openMode = std::ios::in | std::ios::out, size_t access = 0600)) This constructor creates a shared memory segment having a capacity of at least tt(maxSize * sizeUnit) bytes. By default, the shared memory segment is opened for reading and writing. Different from the open modes used for file streams, creating a shared memory stream with open modes tt(ios::in | ios::out) is OK. In this case the shared memory segment is created and once information has been written to the shared memory it can also be read again. The shared memory's access rights are defined by the tt(access) parameter, interpreted as an octal value, using the well-known (bf(chmod)(1)) way to define the access rights for owner, group and others. If construction fails, an tt(FBB::Exception) is thrown. itb(SharedBuf(int id, std::ios::openmode openMode = std::ios::in | std::ios::out)) This constructor connects to a shared memory segment having ID tt(id). Specifying the tt(ios::trunc) flag immediately clears the content of the shared memory. An tt(FBB::Exception) is thrown if construction fails (e.g., no shared memory segment having ID tt(id) exists), ) Copy and move constructors (and assignment operators) are not available. manpagesection(MEMBER FUNCTIONS) All members of bf(std::streambuf) and the tt(enum) values tt(kB, MB), and tt(GB), defined by tt(FBB::SharedEnum__) are available. itemization( itb(void clear()) The shared memory is first locked. Next, all shared data segment are returned to the operating system, after which the shared memory segment is unlocked again. Returning from tt(clear) the shared memory The bf(FBB::SharedMemory) object is effectively re-initialized, with tt(offset) and tt(nReadable) returning 0. itb(int id() const) The ID of the shared memory segment is returned. itb(void kill()) Without locking the shared memory the bf(FBB::SharedBuf)'s shared memory is deleted. The bf(FBB::SharedBuf) object is unusable after returning from tt(kill). itb(void memInfo(std::ostream &out)) Information about the tt(SharedMemory) object is inserted into the provide tt(ostream) object. The IDs of the shared segments, their sizes, the maximum number of shared memory segments, the number of bytes that can be read from the shared memory, and its actual storage capacity, etc., are displayed. The inserted information is not terminated by a final newline character. itb(void remove()) The shared memory is locked, and the bf(FBB::SharedBuf)'s shared memory is deleted. The bf(FBB::SharedBuf) object is unusable after returning from tt(remove). itb(void setMemory(SharedMemory &&tmp)) The anonymous temporary tt(SharedMemory) object that is passed to tt(setMemory) defines the new shared memory segment to which the bf(FBB::SharedBuf) object interfaces. It can also be called to reuse a bf(FBB::SharedBuf) object again after calling tt(kill) or tt(remove). itb(FBB::SharedMemory &sharedMemory()) A reference to the tt(FBB::SharedMemory) object to which the bf(FBB::SharedBuf) object interfaces is returned. ) manpagesection(PROTECTED MEMBER FUNCTIONS) itemization( itemization( itb(FBB::SharedCondition attachSharedCondition(std::ios::off_type offset, std::ios::seekdir origin)) Returns an bf(FBB::SharedCondition)(3) object, interfacing to a shared condition variable located at offset tt(offset) (relative to tt(origin)) in the tt(SharedMemory) object to which the bf(SharedStreamBuf) object interfaces. An tt(FBB::Exception) is thrown if the tt(FBB::SharedCondition) object could not be constructed. itb(FBB::SharedCondition createSharedCondition()) Returns an bf(FBB::SharedCondition)(3) object, interfacing to a newly created shared condition variable which is created at the current offset of the tt(SharedMemory) object to which the bf(SharedStream) object interfaces (or at the first offset of the next physical shared memory data block, cf. bf(sharedcondition)(3bobcat))). An tt(FBB::Exception) is thrown if the tt(FBB::SharedCondition) object could not be constructed. itb(void setOpenMode(std::ios::openmode flag)) The streambuf's tt(openmode) is changed to the settings defined by tt(flag). This member is used by, e.g., tt(SharedStream::open), to adapt the bf(FBB::SharedBuf)'s tt(openmode) to the flags that are passed to tt(open). itb(FBB::SharedMemory &sharedMemory()) Returns a reference to the tt(FBB::SharedMemory) object to which the bf(SharedBuf) object interfaces. ) manpagesection(EXAMPLE) See the bf(sharedstream)(3bobcat) man page. manpagefiles() em(bobcat/sharedbuf) - defines the class interface manpageseealso() bf(bobcat)(7), bf(chmod)(1), bf(isharedstream)(3bobcat), bf(osharedstream)(3bobcat), bf(sharedblock)(3bobcat), bf(sharedcondition)(3bobcat), bf(sharedmemory)(3bobcat) bf(sharedmutex)(3bobcat), bf(sharedpos)(3bobcat), bf(sharedreadme)(7bobcat), bf(sharedsegment)(3bobcat), bf(sharedstream)(3bobcat) manpagebugs() Note that by default exceptions thrown from within a bf(std::stream) object are caught by the stream object, setting its tt(ios::failbit) flag. To allow exceptions to leave a stream object, its tt(exceptions) member can be called, e.g., using: verb( myStream.exceptions(ios::failbit | ios::badbit | ios::eofbit); ) includefile(include/trailer) bobcat-5.09.01/documentation/man/a2x.yo0000644000175000017500000001143314050437223016575 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::A2x)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Error handler) manpagename(FBB::A2x)(Objects performing ascii-to-x (anything) conversions) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() bf(FBB::A2x) objects offer the bf(C++) equivalent of the standard bf(C++) string conversion functions like tt(stol, stoul, stod) etc. These standard bf(C++) string functions are extremely useful and should probably be preferred over using the members of tt(A2x) objects, but tt(A2x) offers additional benefits in that it generalizes these functions to em(any) type that can be extracted from a bf(istream) objects. manpagesection(NAMESPACE) bf(FBB)nl() All constructors, members, and operators, mentioned in this man-page, are defined in the namespace bf(FBB). manpagesection(INHERITS FROM) bf(std::istringstream) manpagesection(CONSTRUCTORS) itemization( itb(A2x()) This constructor constructs an empty tt(A2x) object. No information can be converted from a thus constructed tt(A2x) object. itb(A2x(char const *text)) This constructor stores tt(text). If tt(text) represents a textual value of some type, the tt(A2x) object may be used to initialize or assign this value to a variable of that particular type. Extraction, however is also still possible. itb(A2x(std::string const &str)) This constructor stores the text contained in tt(str). If this text represents a textual value of some type, the tt(A2x) object may be used to initialize or assign this value to a variable of that particular type. Extraction is also still possible. ) The copy and move constructors are available. manpagesection(STATIC MEMBER FUNCTION) itemization( itb(bool lastFail()) This member returns tt(true) if the last conversion failed (i.e., the object's tt(fail()) member returned tt(true) and returns tt(false) otherwise). This member allows checks on the success of the extraction/conversion using anonymous tt(A2x) objects. The member also returns tt(true) when no conversions have as yet been performed.nl() Note that this member returns the value of a em(thread_local) static member: different threads cannot inspect other threads' tt(lastFail) status. ) manpagesection(MEMBER FUNCTION) All members of the bf(istringstream) class are available. itemization( itb(Type to()) This member returns any type tt(Type) supporting extractions from tt(i[string]streams). If the extraction fails, the tt(A2x) object's tt(good()) member returns tt(false), and the tt(Type)'s default value is returned. This operator was implemented as a template member function. There is also a type conversion operator available (see below), but the member function variant may be preferred over the conversion operator in situations where explicit disambiguation is required (e.g., in cases where a conversion has no obvious type solution such as direct insertions) An example is provided in the bf(EXAMPLE) section below. ) manpagesection(OVERLOADED OPERATORS) itemization( itb(operator Type()) Conversion to any type tt(Type) supporting extractions from tt(istreams). If the extraction fails, the tt(A2x) object's tt(good()) member will return tt(false), and the tt(Type)'s default value is returned. This operator was implemented as a member template. itb(istream &operator>>(istream &, Type &)) Extraction to any type tt(Type) supporting extractions from tt(istreams). If the extraction fails, the tt(A2x) object's tt(good()) member returns tt(false), and the tt(Type)'s default value is returned (this facility is implied by the fact that this class inherits from bf(istringstream), but it's probably useful to stress that the extraction operation is still available). itb(A2x &operator=(char const *)) Stores new text in the tt(A2x) object, resets the status flags to tt(ios::good). If a 0-pointer is passed, an empty string is stored. itb(A2x &operator=(std::string const &)) Stores the text stored in the tt(std::string) argument in the tt(A2x) object, resets the status flags to tt(ios::good). ) The overloaded assignment operator is available manpagesection(EXAMPLE) verb( int x = A2x("12"); A2x a2x("12.50"); double d; d = a2x; a2x = "err"; d = a2x; // d now 0 a2x = " a"; char c = a2x; // c now 'a' // explicit conversion to `double' cout << A2x("12.4").to() << endl; ) manpagefiles() em(bobcat/a2x) - defines the class interface manpageseealso() bf(bobcat)(7), bf(x2a)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/sharedblock.yo0000644000175000017500000000342214050437223020363 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::SharedBlock)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Shared Memory Block) manpagename(FBB::SharedBlock)(Shared memory data block info) manpagesynopsis() bf(#include )nl() Linking option: tt(-lpthread, -lbobcat ) manpagedescription() bf(FBB::SharedBlock) objects are used by tt(FBB::SharedSegment) to access the IDs and shared memory locks of shared memory data segments. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(CONSTRUCTORS) Only the default constructor is available. Copy and move assignment operators are not available. manpagesection(MEMBER FUNCTIONS) itemization( itb(size_t id() const) The object's stored ID value is returned. itb(void lock() const) When returning from this member, the current process has obtained the bf(FBB::SharedBlock)'s shared memory mutex lock. itb(void setID(size_t id)) The object's stored ID value is set to tt(id). itb(void unlock() const) The shared memory segment's mutex lock is released. ) manpagesection(EXAMPLE) See the bf(sharedstream)(3bobcat) man page. manpagefiles() em(bobcat/sharedblock) - defines the class interface manpageseealso() bf(bobcat)(7) bf(isharedstream)(3bobcat), bf(osharedstream)(3bobcat), bf(sharedcondition)(3bobcat), bf(sharedmemory)(3bobcat), bf(sharedmutex)(3bobcat), bf(sharedpos)(3bobcat), bf(sharedreadme)(7bobcat), bf(sharedsegment)(3bobcat), bf(sharedstream)(3bobcat), bf(sharedbuf)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/process.yo0000644000175000017500000010171114050437223017560 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Process)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Running Child Processes) manpagename(FBB::Process)(Runs external programs) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() The bf(FBB::Process) class offers an extensive interface to calling external programs and/or scripts from a bf(C++) program (so-called em(child-processes)). The class offers an easy to use, stream-based interface to the standard input, standard output and standard error streams of child processes. Objects of the tt(class Process) use standard process-executing functions, like members of the bf(execl)(1) family or bf(sh)(1) to execute child processes. Thus, child processes can be executable programs or em(shell-scripts). The standard input, output and error streams of child processes may be accessed through their tt(Process) parent objects. Input expected by child processes may be inserted by tt(Process) objects, and output generated by child processes may be extracted from tt(Process) objects. When using (output) redirection with the tt(USE_SHELL) path specification (see below for the path and IOMode specifications), the tt(IGNORE_COUT IOMode) (and possibly tt(IGNORE_CERR)) should normally be specified. tt(Process) objects may repeatedly be used to execute the same or different child processes. Before the next child process is started, the tt(Process) object first terminates its currently active child process. Alternatively, a currently active child process is automatically ended if the tt(Process) object goes out of scope, if its tt(stop) or tt(eoi) (end-of-information) member is called, or if the tt(eoi) manipulator is inserted into the tt(Process) object. Programs called as child processes may be specified when constructing a tt(Process) object or by using tt(Process's setCommand) member. tt(Process) constructors (or tt(Process set)-members) never start child processes. Child processes are started through tt(start) members or the assignment operator. Child processes may receive information at their standard input streams through information inserted into tt(Process) objects. In these cases the tt(Process) objects must inform their child processes that they have received all input. For this the tt(close) or tt(eoi) member or the tt(eoi) manipulator can be used. After calling the tt(close) member, the tt(waitForChild) member should be called as well. This is not necessary if either the tt(eoi) member or the tt(eoi) manipulator is used. If tt(waitForChild) is not called (but information sent to the child which could not be fully processed by the child process in case the child process terminated as a result of the tt(Process) object going out of scope), then the operating system issues a tt(Broken pipe) message, indicating that information in a pipe was lost. Arguments passed to child processes may be surrounded by double or single quotes. Arguments surrounded by double quotes have their double quotes removed, while interpreting any escape-sequences that may have been used within. Arguments surrounded by single quotes have their single quotes removed, while accepting their content as-is. In addition unquoted escape-sequences may be specified: those escape sequences are evaluated and replaced by their intended characters (e.g., tt(\100) is converted to tt(@)). A full command specification may be surrounded by backtics (tt(`)-characters). These backtick characters are removed by the tt(Process) object when the command is started. Child processes may be allowed a limited amount of time (in seconds) to complete. By default no time limit is imposed upon child processes. By default the standard input, output and error streams of child processes are accessed through their tt(Process) parent processes: information inserted into the tt(Process) object is forwarded to the child process's standard input stream, information sent by the child process to its standard output stream can be extracted from its parent tt(Process) object, and information sent by the child process to its standard error stream may be obtained through tt(Process's childErrStream) member. If the parent and child processes have agreed on some communication process, then information may alternatingly be sent to and received from the child process through the tt(Process's ostream) and tt(istream) facilities. Alternatively, unspecified amounts of information written by child processes may be processed by separate threads (cf. this manual page's bf(EXAMPLES) section). tt(Process) objects use tt(Pipe) objects (cf. bf(pipe)(3bobcat)) for communication with its child processes. To ensure that these pipes are properly closed the members tt(waitForChild, stop) or the tt(eoi) manipulator should be used. Once a tt(Process) object ceases to exist pipes to its child process are also closed. includefile(include/namespace) manpagesection(INHERITS FROM) bf(FBB::Fork)(3bobcat) (private), nl() bf(FBB:IOStream)(3bobcat), and by implication: bf(FBB::Eoi), nl() bf(FBB:ProcessEnums) The tt(struct ProcessEnums) defines enumerations and support functions which are used by several classes. Its enumerations are documented below; there is no separate bf(ProcessEnums) man-page. manpagesection(ENUMERATIONS) bf(enum ProcessType):nl() The bf(enum ProcessType) defines how a child process is started or located. Its values are specified at constructor-time or through the tt(setProcessType) member. This enumeration defines the following symbolic constants: itemization( itb(NO_PATH) The program specified as child process is started as specified, without searching the elements of the tt(PATH) environment variable. itb(USE_PATH) The elements of the tt(PATH) environment variable are used when locating the program specified as child process. itb(USE_SHELL) The program specified as child process is called using tt(/bin/sh -c). When (output) redirection is used with the specified command the tt(IGNORE_COUT IOMode) (and possibly also the tt(IGNORE_CERR IOMode)) should be specified. ) bf(enum IOMode):nl() Values of the tt(enum IOMode) are used to define which of the child process's standard streams can be accessed through the tt(Process) object. Its symbolic constants may be combined using the tt(bit_or) operator. By default tt(CIN | COUT | CERR) is used (see below). The following symbolic constants are available: itemization( itb(ALL) Shortcut for bf(CIN | COUT | CERR). itb(CIN) Information inserted into the tt(Process) object is forwarded to its child process. If this is not required then tt(CIN) should not be specified. itb(CERR) Information written by the child process to its standard error stream is accessible through tt(Process's childErrStream) member. If this is not required then tt(CERR) should not be specified. itb(COUT) Information written by the child process to its standard output stream may be directly be extracted from the tt(Process) object, or from its tt(childOutStream) member. If this is not required then tt(COUT) should not be specified. itb(DIRECT) When starting a child process (see below at the member tt(start)) the current process (i.e., the program defining the tt(Process) object) is replaced by the child process, inheriting the current process's standard input and output streams. If this mode is specified in combination with any other tt(IOMode) (except for tt(NONE), see below) an tt(std::invalid_argument) exception is thrown. itb(IGNORE_CERR) Information written by the child process to its standard error stream is sent to tt(/dev/null). An tt(std::invalid_argument) exception is thrown if this mode is specified in combination with bf(DIRECT, CERR) and/or bf(MERGE_COUT_CERR). itb(IGNORE_COUT) Information written by the child process to its standard output stream is sent to tt(/dev/null). An tt(std::invalid_argument) exception is thrown if this mode is specified in combination with bf(COUT, DIRECT) and/or bf(MERGE_COUT_CERR). itb(IGNORE_COUT_CERR) Shortcut for tt(IGNORE_CERR | IGNORE_COUT). itb(MERGE_COUT_CERR) Information extracted from the tt(Process) object is written by the child process to its standard output and standard error streams. An tt(std::invalid_argument) exception is thrown if this mode is specified in combination with bf(COUT, CERR, DIRECT, IGNORE_COUT) or tt(IGNORE_CERR). itb(NONE) The tt(Process) object does not extract information from or insert information into the standard streams of its child process. The child process reads the same standard input stream and writes the same standard output streams as its parent tt(Process) object. When this mode is specified in combination with other tt(IOMode) values it is silently ignored. ) bf(enum ChildOutput):nl() The tt(ChildOutput) enumeration defines values returned by the tt(available) member (see below) indicating to which standard stream the child process has written information. This enumeration defines the following values: itemization( itb(NOTHING_AVAILABLE) The child process did not (yet) write any information to its standard streams; itb(CHILD_COUT) The child process wrote information to its standard output stream which is waiting for extraction. itb(CHILD_CERR) The child process wrote information to its standard error stream which is waiting for extraction. ) The latter two values may be combined using the tt(bit_or) operator. The tt(bit_and) operator,returning a tt(bool) value can be used to test whether information on a specific output stream is available. manpagesection(PROCESS PARAMETERS) Four process parameters may be specified: the sizes of the stream buffers which are used when communicating with child processes; to specify which of the standard streams of child processes can be accessed from the tt(Process) object combinations of tt(IOMode) values are used; to specify how child programs are found a tt(ProcessType) value is used; to specify the maximum time (in seconds) the child program is allowed to run a tt(size_t) values is used. By default, the stream buffers hold 200 bytes; all the child's standard streams (standard input, output and error) are accessible from the tt(Parent) process; the tt(PATH) environment variable is em(not) used to locate the child program; and the child processes will be allowed an unlimited amount of time to run. After constructing a tt(Process) object all default parameters may be modified. These parameters may either be altered for a single process or a tt(Process) object's general defaults may be modified. The tt(set*) members (see below) may be used to change the default process parameters. When parameters are specified otherwise, they will only be active for the next process. manpagesection(CONSTRUCTORS) The command provided to the following constructors may be the (initial part of the) specification of an external program to run. When the program is eventually started it may start and end with a em(back-tick) (tt(`)). The back-ticks will be removed just before the specified program is executed. Child processes are em(not) started automatically following tt(Process) object constructions. A tt(start) member or the assignment operator (see below) is used to start the specified child process. Constructors expecting an tt(IOMode) argument may be provided with multiple tt(IOMode) values by combining them using the bit-or operator. After constructing a tt(Process) object its parameters can be changed using tt(set)-member functions, function call operators or tt(start) members. itemization( itb(Process(std::string const &cmd = "")) This constructor is used to specify the (initial part of a) command to execute from a tt(Process) object. Default values are used for the process parameters (see section bf(PROCESS PARAMETERS)). itb(Process(IOMode mode, std::string const &cmd = "")) This constructor requires the specification of the object's bf(IOMode), and it can be used to specify the (initial part of a) command to execute from a tt(Process) object. Default values are used for the remaining process parameters (see section bf(PROCESS PARAMETERS)). itb(Process(IOMode mode, ProcessType type, std::string const &cmd = "")) This constructor requires the specification of the object's bf(IOMode) and tt(ProcessType), and it can be used to specify the (initial part of a) command to execute from a tt(Process) object. Default values are used for the remaining process parameters (see section bf(PROCESS PARAMETERS)). itb(Process(IOMode mode, ProcessType type, size_t timeLimit, std::string const &cmd = "")) This constructor requires the specification of the object's bf(IOMode), tt(ProcessType), and child process time limit. The (initial part of a) command to execute from a tt(Process) object may optionally be specified. The default process parameter is used for the sizes of the internally used stream buffers (see section bf(PROCESS PARAMETERS)). itb(Process(IOMode mode, ProcessType type, size_t timeLimit, size_t bufferSize, std::string const &cmd = "")) This constructor requires the specification of the object's bf(IOMode), tt(ProcessType), child process time limit, and size of the internally used stream buffers. The (initial part of a) command to execute from a tt(Process) object may optionally be specified. Note that this constructor's tt(mode) parameter does not accept a tt(size_t) argument. ) Copy and move constructors (and assignment operators) are not available. manpagesection(OVERLOADED OPERATORS) itemization( itb(Process &operator<<(Type value)) This operator inserts tt(value) into the child's standard input stream. I.e., the child process reads tt(value) from its standard input. A value of any type that can be inserted into an tt(ostream) can be inserted into a tt(Process) object. Nothing happens if the member is used when the child process has terminated. Manipulators like tt(std::endl) are also supported. The behavior of this operator is undefined unless tt(IOMode CIN) was specified. itb(Process &operator>>(Type value)) This operator extracts tt(value) from the child's standard output stream and optionally (if tt(IOMode MERGE_COUT_CERR) was specified) from the child's error stream. I.e., tt(value) may be extracted from tt(Process) objects. A value of any type that can be extracted from an tt(istream) can be extracted from a tt(Process) object. Nothing happens if the member is used when the child process has terminated. The behavior of this operator is undefined unless tt(IOMode COUT) or tt(MERGE_COUT_CERR) was specified. itb(Process &operator+=(std::string const &)) This operator adds the provided tt(std::string) object to the currenly defined command specification of a tt(Process) object. The member tt(operator+=) does not add a separating blank space between the currently stored command specification and the text to append. It merely adds its right-hand side string to the command stored so far. It does not affect a currently running child process. itb(int operator=(std::string const &cmd)) The tt(operator=) member defines tt(cmd) as the stored command in a tt(Process) object. Before starting the child process a possibly active child process is first stopped by calling tt(stop). It returns tt(stop)'s return value. Immediately after calling tt(stop) the new command (tt(cmd)) is started. If stopping and restarting another command should be separate actions then use tt(stop), followed by tt(setCommand), followed by calling an appropriate overloaded version of the member tt(start) (tt(start()) uses the object's current tt(IOMode, ProcessType,) and time limit). itb(Process &operator()(IOMode mode)) This operator changes the the tt(Process) object's tt(IOMode) parameter. A reference to the tt(Process) object is returned, allowing constructions like verb( process(Process::COUT) = "/bin/cat"; ) to start a new child process with the specified tt(IOMode). itb(Process &operator()(IOMode mode, ProcessType type)) This operator changes the tt(Process) object's tt(IOMode) and tt(ProcessType) process parameters. itb(Process &operator()(IOMode mode, ProcessType type, size_t timeLimit)) This operator changes the tt(Process) object's mentioned process parameters. The currently specified default size of the stream buffers is kept as-is. itb(Process &operator()(IOMode mode, ProcessType type, size_t timeLimit, size_t bufferSize)) This operator changes all of the tt(Process) object's process parameters. itb(Process &operator|(Process &lhs, Process &rhs)) This operator implements process em(piping): information sent b tt(lhs) to its standard output becomes the tt(rhs)'s standard input. The operator returns tt(rhs). This operator mimics the piping-operator supported by most command-shell programs and should not be confused with the binary-or operator. The operator starts the tt(lhs)'s child process, but the tt(rhs)'s child process (and thus pipe processing) must explicitly be started. Since tt(operator|) is left-associative and tt(rhs) is returned piping can be em(chained), allowing constructions like tt(p1 | p2 | p3), where tt(p1, p2) and tt(p3) are tt(Process) objects. The following idiom can be used to start the execution of a chain of processes: tt((p1 | p2 | p3).start()). Alternatively, the following two-step procedure can be used: verb( p1 | p2 | p3; p3.start(); ) If tt(p1) specifies tt(Process::CIN) then this tt(IOMode) is forwared to the final process of the chain of processes. It is not necessary to specify tt(Process::CIN) for tt(p3). In fact, most tt(IOMode) flags of processes passed to tt(operator|) are ignored or modified. Acceptable tt(IOModes) are tt(Process::IGNORE_CERR) and tt(Process::CERR) (accepted for all processes), tt(Process::CIN) (accepted for the first process of the chain), and tt(Process::COUT) (for the last process of the chain). bf(Note:) when connecting a series of processes using tt(operator|) all input and output (except for the standard error streams) is handled through the last process: if tt(Process::CIN) is specified for the first process then this mode is transferred to the last process, so information inserted into the last process enters the pipe through the first process's standard input. The next example illustrates how input can be inserted into the first process from a main process and sent to the standard output stream by the final process: verb( using namespace std; using namespace FBB; Process p1(Process::CIN, "/bin/cat"); Process p2("/bin/cat"); Process p3(Process::NONE, "/bin/cat"); p1 | p2 | p3; p3.start(); p3 << cin.rdbuf() << eoi; ) When joining multiple commands using the piping operator (tt('|')), the process type tt(USE_SHELL) is not required, even though process-piping is commonly used as a shell-feature. tt(Process's operator|) handles I/O piping itself, and thus can avoid the additional shell process. ) manpagesection(MEMBERS) itemization( itb(bool active()) This member returns tt(true) if the child process is currently running and tt(false) if not. itb(size_t available()) This member returns immediately. Its return value indicates whether any information can be obtained from the child process as value(s) from the tt(enum ChildOutput). tt(NOTHING_AVAILABLE) is returned if no information is ready for extraction. tt(CHILD_COUT) is returned if information from the child process's standard output stream is available; tt(CHILD_CERR) is returned if information from the child process's standard error stream is available; tt(CHILD_COUT | CHILD_CERR) is returned if information from both the standard output and standard error streams is available. The tt(bit_and) operator, returning a tt(bool) value, can be used to determine which stream has any pending information. E.g., verb( if (process.available() & Process::CHILD_COUT) cout << "Process has child standard output available"; ) itb(size_t bufSize() const) This member returns the default size of the stream buffers that are used for communication with child processes. If called while a child process is actually running, then the value returned by this member may differ from the value that was actually used when starting the child process, as the default value may be altered by a function call operator just before starting the child process. itb(std::istream &childErrStream()) If tt(Process::CERR) was specified then this member interfaces to the child's standard error stream. By extracting the information from tt(childErrStream) the parent process retrieves the information sent by its child process to its standard error stream. itb(std::istream &childOutStream()) If tt(Process::COUT) or tt(Process::MERGE_COUT_CERR) was specified then this member interfaces to the child's standard output stream. By extracting the information from tt(childOutStream) the parent process retrieves the information sent by its child process to its standard output stream. Alternatively, this information may directly be extracted from the tt(Process) object itself, but this member does not require the use of a tt(static_cast) to disambiguate the intended stream buffer in statements like verb( cout << process.childOutStream().rdbbuf() ) itb(void close()) This member closes the child's input stream. In situations where the child continuously reads information from its standard input stream this member can be used to inform the child process that input has terminated. This member should only be used when tt(IOMode CIN) was specified for the currently running child process; otherwise its behavior is undefined. Alternatively, the tt(eoi) member or manipulator may be used. itb(int eoi()) This member closes the child's input stream, and then calls tt(waitForChild) to wait for the child process to end. In situations where the child continuously reads information from its standard input stream this member can be used to inform the child process that input has terminated. This member should only be used when tt(IOMode CIN) was specified for the currently running child process; otherwise its behavior is undefined. Alternatively, the tt(close) member or tt(eoi) manipulator may be used. The exit-status of the called child process is returned. itb(int exitStatus() const) After calling tt(eoi) or inserting the tt(eoi) manipulator into the tt(Process) object this member returns the child process's exit status. In other cases the value returned by tt(exitStatus) is not defined, and tt(waitForChild) should be used. itb(IOMode ioMode() const) This member returns the default tt(IOMode). If called while a child process is actually running, then the value returned by this member may differ from the value that was actually used when starting the child process, as the default value may be altered by a function call operator just before starting the child process. itb(ProcessType processType() const) This member returns the default tt(ProcessType) of child proceses. If called while a child process is actually running, then the value returned by this member may differ from the value that was actually used when starting the child process, as the default value may be altered by a function call operator just before starting the child process. itb(size_t timeLimit() const) This member returns the default time limit (in seconds) of child processes. A return value of zero indicates that no time limit is enforced. If called while a child process is actually running, then the value returned by this member may differ from the value that was actually used when starting the child process, as the default value may be altered by a function call operator just before starting the child process. itb(void setBufSize(size_t bufSize)) This member changes the default stream buffer size that is used for communication with child processes. A zero byte buffer size is silently changed into one. The new default value will be used when starting the next child process. itb(void setCommand(std::string const &cmd)) The tt(setCommand) member (re)defines the (initial part of a) child process command specification. This member does not actually start the child process, and tt(operator+=) may be used to append additional text to the command specification. Also, this member may be used when a child process is currently active: its use does not affect a currently running child process. itb(void setIOMode(iomode mode)) This member changes the default tt(IOMode). The new default value will be used when starting the next child process. itb(void setProcessType(ProcessType type)) This member changes the default tt(ProcessType). The new default value will be used when starting the next child process. itb(void setTimeLimit(size_t timeLimit)) This member changes the default execution time limit (in seconds). No time limit will be imposed upon child processes if tt(timeLimit 0) is specified. The new default value will be used when starting the next child process. itb(void start()) The currently specified command is started using the tt(Process) object's process parameters. Having specified a command to start, the first white-space delimited element of the specified command is used as the name of the program to start. If the program should be called through bf(sh)(1), the tt(USE_SHELL ProcessType) or a tt(system) member should be used. If a child process does not terminate by itself, then it is terminated when it has run for its alloted time; when the tt(Process) object's tt(start) or tt(stop) members are called; when the object's assignment operator is used; or when the object goes out of scope. Alternatively, the member tt(waitForChild) (see below) may have to be called to end a running process. itb(void start(IOMode mode)) The currently specified command is started using the specified tt(IOMode), but otherwise using the currently configured tt(Process) object's process parameters. The specified tt(IOMode) is only used for the child process that is started by this member. itb(void start(IOMode mode, ProcessType type)) The currently specified command is started using the specified tt(IOMode) and tt(ProcessType), but otherwise using the currently configured tt(Process) object's process parameters. The specified process parameter values are only used for the child process that is started by this member. itb(void start(size_t mode, Program program, size_t timeLimit)) The currently specified command is started using the specified tt(IOMode), tt(ProcessType), and time limit (silently converting the tt(size_t mode) to an tt(IOMode) value), and using the currently configured tt(Process) object's stream buffer size parameter. The specified process parameter values are only used for the child process that is started by this member. itb(void start(IOMode mode, Program program, size_t timeLimit, size_t bufferSize)) The currently specified command is started using the specified process parameters. The specified parameter values are only used for the child process that is started by this member. itb(void showMode(char const *lab) const) This member displays the label tt(lab), followed by the current process ID, followed by the child process's process ID, followed by a textual representation of the currently active tt(IOMode). itb(std::string const &str() const) This member returns the content of the current child process command specification. It shows the command as it will be (or has been) executed by tt(start), tt(system) or the assignment operator. itb(void system()) This member executes the currently stored command as a command to bf(sh)(1). When using tt(system) redirections can be included in the command itself (this renders the redirected streams implied by the current bf(IOMode)) useless. The currently set process parameters are used when bf(sh)(1) is executed. itb(void system(IOMode mode)) This member executes the currently stored command as a command to bf(sh)(1) (cf. tt(system) above) using the specified tt(IOMode) rather than the current default tt(IOMode) setting. itb(void system(IOMode mode, size_t timeLimit)) This member executes the currently stored command as a command to bf(sh)(1) (cf. tt(system) above) using the specified tt(IOMode) and time limit. itb(void system(IOMode mode, size_t timeLimit, size_t bufSize)) This member executes the currently stored command as a command to bf(sh)(1) (cf. tt(system) above) using the specified tt(IOMode), time limit, and stream buffer size values. itb(int stop()) This member terminates a currently active child process. The child process is twice sent a tt(SIG_TERM) signal, followed by a tt(SIG_KILL) signal. This member returns the exit-value of the child process that was stopped. Its operation and return value are undefined if called without a running child process. Following tt(stop) a new command may be called using tt(start, system) or the assignment operator (see earlier). Those members first calls tt(stop). When the intention is to start another child process, then there's no need to call tt(stop) explicitly. Also, tt(stop) is called when the tt(Process) object goes out of scope. itb(int waitForChild()) This member calls the identically named member from the class tt(FBB::Fork), waiting for a child process to end. It is called to prevent premature termination of a child process before calling tt(stop). It is not always necessary to call tt(waitForChild). E.g., when a process writes to its standard output stream and all output has been read then the child process can be stopped without calling tt(waitForChild). ) manpagesection(MANIPULATOR) itemization( itb(FBB::eoi) This manipulator may be inserted into a tt(Process) object for which tt(IOMode CIN) was specified. It closes the child's input stream, and then calls tt(waitForChild) to wait for the child process to end. In situations where the child continuously reads information from its standard input stream this member can be used to inform the child process that input has terminated. Alternatively, tt(Process) object's tt(close) or tt(eoi) members may be used. ) manpagesection(EXAMPLES) The first example shows how a program only producing output can be called. Its child process simply is tt(/bin/ls): verbinsert(//CODE ../../process/driver/ls.cc) The next example shows how a child program can be given a limited amount of execution time: lines entered at the keyboard are echoed to the standard output stream for at most 5 seconds: verbinsert(//CODE ../../process/driver/limit.cc) The final example shows how multi threading can be used to access the child program's standard output and standard error streams through the tt(Process) object: verbinsert(//CODE ../../process/driver/all.cc) Additional examples are found in the distribution's tt(bobcat/process/driver) directory. manpagefiles() em(bobcat/process) - defines the class interface manpageseealso() bf(bobcat)(7), bf(execle)(3), bf(exec)(3bobcat), bf(coutextractor)(3bobcat), bf(cerrextractor)(3bobcat), bf(fork)(3bobcat), bf(cininserter)(3bobcat), bf(iostream)(3fork), bf(sh)(1), bf(stdextractor)(3bobcat). manpagebugs() With the release of Bobcat 1.21.1 the class tt(Process) was completely rewritten. The new implementation, however, should not affect existing programs other than that tt(Process) will no longer impose a limited time-to-live upon child processes. The interface was enlarged, but this should not affect existing programs. The internal organization of the tt(Process) class em(has) changed though, requiring recompilation of sources defining tt(Process) class type objects and linking dynamically to the tt(Bobcat) library. With the release of Bobcat 2.11.0 another major modification of tt(Process) was realized. Although tt(Process)'s internal organization was again modified this does not affect exeisting programs using tt(Process) objects. No recompilation of existing sources using tt(Process) is required. includefile(include/trailer) bobcat-5.09.01/documentation/man/cgi.yo0000644000175000017500000003513114050437223016646 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::CGI)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (CGI interface) manpagename(FBB::CGI)(handles GET and POST submitted form data) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() The class tt(CGI) offers an interface to data submitted by web-forms. The data is sent to a script handling the data using a tt(
) stanza. Very often this is indeed a script, like a Perl script, but there is no need to use a scripting language. The class tt(CGI) allows bf(C++) programmers to process the form by an executable usually resulting in faster processing and in construction time benefits from the type safety offered by bf(C++). The class tt(CGI) automatically handles data submitted using the tt(GET) method as well as data submitted using the tt(POST) method. By default the class's constructor writes the customary tt(Content-type) header lines to the standard output stream. Additional (html) output of a reply page must be provided by other code. Therefore, a program processing an uploaded form will have an organization comparable to the following basic setup: verb( // assume includes and namespace std/FBB were defined int main() { CGI cgi; cout << "\n"; if (parametersOK(cgi)) { process(cgi); generateReplyPage(); } else generateErrorPage(); cout << "\n; } ) When errors in the received form-data are detected an error message is written to the standard output stream and an tt(FBB::Exception) exception is thrown. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(TYPEDEF) itemization( itb(CGI::MapStringVector) A shorthand for tt(std::unordered_map >), which is the data type in which form-variables are stored. ) manpagesection(ENUMERATIONS) The tt(CGI::Method) enumeration specifies values indicating the way the form's data were submitted: itemization( itb(CGI::UNDETERMINED) Used internally indicating that the form's method was neither tt(GET) nor tt(POST). itb(CGI::GET) Indicates that the tt(GET) method was used when submitting the form's data; itb(CGI::POST) Indicates that the tt(POST) method was used when submitting the form's data. ) The tt(CGI::Create) enumeration is used to request or suppress creation of the directory to contain any file uploaded by a form: itemization( itb(CGI::DONT_CREATE_PATH) When uploading files, the destination directory must exist; itb(CGI::CREATE_PATH) When uploading files, the destination directory will be created. ) manpagesection(CONSTRUCTORS) itemization( itb(CGI(bool defaultEscape = true, char const *header = "Content-type: text/html", std::ostream &out = std::cout)) The default constructor writes the standard content type header to the standard output stream and will use tt(std::cout) for output. Specifying tt(0) as header suppresses outputting the tt(Content-type) line. Otherwise the content type line is also followed by two tt(\r\n) character combinations. By default all characters in retrieved form-variables are escaped. The overloaded insertion operators (see below) can be used to modify the default set of characters to escape. The backslash is used as the escape character. The escape-prefix is not used if the tt(defaultEscape) value is specified as tt(false) and if no insertions into the bf(CGI) object were performed. ) Copy and move constructors (and assignment operators) are available. manpagesection(OERLOADED OPERATORS) bf(Note:) the following three insertion operators, defining sets of characters that should be escaped, can only be used before calling any of the tt(param, begin) or tt(end) members. As soon as one of these latter three members has been called the set of characters to be escaped is fixed and attempts to modify that set is silently ignored. itemization( itb(char const *operator[](std::string const &key) const) The index operator returns the value of the environment variable specified as the index. 0 is returned if the variable specified at tt(key) is not defined. itb(CGI &operator<<(std::string const &accept)) This member's actions are suppressed once tt(param, begin) or tt(end) (see below) has been called. The insertion operator can be used to fine-tune the set of characters that are escaped in strings returned by tt(param) (see below). Depending on the value of the constructor's tt(defaultEscape) parameter characters inserted into the tt(CGI) object will or will not be escaped by a backslash. If the constructor's tt(defaultEscape) parameter was specified as tt(true) then the insertion operator can be used to define a set of characters that are em(not) escaped. If tt(defaultEscape) was specified as tt(false) then the insertion operator will define a set of characters that em(will) be escaped. The backlash itself is always escaped and a request to use it unescaped is silently ignored. The tt(accept) string can be specified as a regular expression character set, without the usual surrounding square brackets. E.g., an insertion like tt(cgi << "-a-z0-9") defines the set consisting of the dash, the lower case letters and the digits. Individual characters, character ranges (using the dash to specify a range) and all standard character classes (tt([:alnum:], [:alpha:], [:cntrl:], [:digit:], [:graph:], [:lower:], [:print:], [:punct:], [:space:], [:upper:]), and tt([:xdigit:])) can be used to specify a set of characters. In addition to these standard character classes the class tt([:cgi:]) can be used to define the set consisting of the characters tt(" ' ` ;) and tt(\). Note that standard and tt([:cgi:]) character classes em(do) require square brackets. When a series of insertions are performed then the union of the sets defined by these insertions are used. bf(Note): using unescaped single quotes, the double quotes, backtick characters and semicolons in CGI-programs might be risky and is not advised. itb(CGI &operator<<(int c)) This member's actions are suppressed once tt(param, begin) or tt(end) (see below) has been called. This insertion operator is used to change the default escape handling of a single character tt(c). The tt(int) parameter is cast internally to a tt(char). itb(CGI &operator<<(std::pair range)) This member's actions are suppressed once tt(param, begin) or tt(end) (see below) has been called. This insertion operator can be used to change the default escape handling of a range of characters. The pair's second character must be equal to or exceed the position of the pair's first character in the ASCII collating sequence or the member will have no effect. itb(std::ostream &std::operator<<(std::ostream &out, CGI const &cgi)) tt(CGI) objects can be inserted into tt(ostreams) to display the characters that will appear escaped in strings returned by the tt(param()) member function. Each character for which tt(isprint()) returns tt(true) will be displayed as character, surrounded by single quotes. For all other characters their ASCII values are displayed. Each character is displayed on a line by itself. ) manpagesection(MEMBER FUNCTIONS) itemization( itb(CGI::MapStringVector::const_iterator begin()) Returns the begin iterator of the form's parameter map. Iterator values unequal to tt(end) (see below) point to a pair of values, the first of which is the name of a field defined by the form, the second is a vector of strings containing the field's value(s). See also the description of the tt(param) member below. itb(CGI::MapStringVector::const_iterator end()) Returns the end iterator of the form's parameter map. itb(unsigned long long maxUploadSize() const) Returns the current maximum file upload size in bytes. itb(CGI::Method method() const) Returns the method that was used when the form was submitted (either tt(CGI::GET) or tt(CGI::POST)). itb(std::vector const ¶m(std::string const &variable)) Returns the value of the form-variable specified by the function's argument. An empty vector is returned if the variable was not provided by the form's data. If the same variable was specified multiple times or if its value extends over multiple lines (only with tt(multipart/form-data)) then the vector contains multiple strings. With tt(GET) and tt(POST) methods not using tt(multipart/form-data) input fields extending over multiple lines are stored in one string, using tt(\r\n) combinations between those lines. When files are uploaded the vectors contain sets of four strings. The first string provides the path nme of the uploaded file; the second string provides the file name specified in the form itself (so it is the name of the file at the remote location); the third string shows the content type specified by the remote browser (e.g., tt(application/octet-stream)), the fourth string contains tt(OK) if the file was successfully uploaded and tt(truncated) if the file was truncated. Existing files will not be overwritten. When uploading a file a usable filename must be found within 100 trials. itb(std::string param1(std::string const &variable) const) Returns the first element of the tt(vector) returned by the tt(param) member or an empty string if tt(variable) was not defined by the received form. itb(std::string const &query() const) Returns the query-string submitted with tt(CGI::GET) or tt(CGI::POST) forms (if the tt(POST)ed form specified tt(ENCTYPE="multipart/form-data") the query string is empty). itb(report+CHAR(40)CHAR(41)) The tt(report) member silently returns if no errors were encountered while processing form-data. Otherwise, the tt(html) file generated by the tt(CGI) program displays a line starting with tt(FBB::CGI), followed by the status report. The following status report messages are presently defined: tt(Content-Disposition not recognized in:), which is followed by the line where the tt(Content-Disposition) was expected. This may occur when processing tt(multipart/form) data. tt(Invalid multipart/form-data). This message can be generated when readling lines while processing tt(multipart/form) data. tt(GET/POST REQUEST_METHOD not found). This message is shown if the program couldn't find the form's tt(REQUEST_METHOD) type (i.e., tt(GET) or tt(POST)). tt(Invalid CONTENT_LENGHT in POSTed form). This message is shown if the content-length header has an incorrect value. tt(Content-Type not found for file-field), followed by the file's field name. This message is shown if no tt(Content-Type) specification was found in an uploaded form. tt(Can't open a file to write an uploaded file). This message indicates that the CGI program was unable to open a file to write an uploaded file to. This can be caused by an overfull disk or partition or by incorrect write-permissions. tt(multipart/form-data: no end-boundary found). This message is shown if the end-boundary was missing in a tt(multipart/form-data) form. itb(void setFileDestination(std::string const &path, std::string const &prefix = "", Create create = CREATE_PATH)) This member is used to specify the path and prefix of uploaded files. Uploaded files will be stored at tt(path/prefixNr) where tt(Nr) is an internally used number starting at one. When tt(CREATE_PATH) is specified tt(path) must be available or the bf(CGI) object must be able to create the path. If tt(DONT_CREATE_PATH) is specified the specified path must be available. If not, an tt(FBB::Exception) exception will be thrown. itb(void setMaxUploadSize(size_t maxSize, int unit = 'M')) This member can be used to change the maximum size of uploaded files. Its default value is 100Mb. The tt(unit) can be one of tt(b) (bytes, the default), tt(K) (Kbytes), tt(M) (Mbytes) or tt(G) (Gbytes). Unit-specifiers are interpreted case insensitively. File uploads will continue until the maximum upload size is exceeded, followed by discarding any remainder. itb(void swap(CGI &other)) The current and tt(other) object are swapped. ) The first time one of the tt(param(), begin()) or tt(end()) members is called these members may detect errors in the the received form data. If so, an error message is written to the standard output stream and an tt(FBB::Exception) exception will be thrown. manpagesection(STATIC MEMBERS) itemization( itb(std::string dos2unix(std::string const &text)) This member converts all tt(\r\n) character combinations in tt(text) into plain tt(\n) characters, returning the converted text. itb(std::string unPercent(std::string const &text)) This member converts all tt(%xx) encoded characters into their corresponding ASCII values. Also, tt(+) characters are converted to single blank spaces. The converted string is returned. ) manpagesection(EXAMPLE) verbinclude(../../cgi/driver/driver.cc) To test the program's tt(get) form processing, call it as tt(driver get '[:cgi:]'), with the file tt(get) containing: verbinclude(../../cgi/driver/get) To test the program's tt(post) form processing, call it as tt(driver post1 '[:cgi:]'), using tt(post1) and tt(post1.cin) found in Bobcat's source archive under tt(../cgi/driver). manpagefiles() em(bobcat/cgi) - defines the class interface manpageseealso() bf(bobcat)(7) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/ofilterbuf.yo0000644000175000017500000001234014050437223020242 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::OFilterBuf)(3bobcat)(_CurYrs_) (libbobcat-dev__CurVers_)(ostream filtering) manpagename(FBB::OFilterBuf)(Base class for std::ostream filtering) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() The bf(FBB::OFilterBuf) class is a specialization of the tt(std::streambuf) class and can be used as a base class for classes implementing em(ostream)-filtering. Ostream filtering is defined here as the process by which inserted characters are subject to processing before they are passed on to another (filtered) tt(ostream) object (or they may be rejected). The filtering may also result in inserting additional information into the filtered tt(ostream). em(Chaining) of filters is also possible: the filtered tt(ostream) may itself use an tt(OFilterBuf) to filter its received information before passing it on to yet another tt(ostream). As tt(OFilterBuf) inherits from tt(std::streambuf) an tt(OFilterBuf) object can be used to provide an tt(ostream) object with a tt(std::streambuf). Information inserted into such a stream travels the following route: itemization( it() The information is converted to characters using the standard conversion facilities implemented by tt(std::ostream) objects. E.g., when inserting the value tt(123) this value is converted to the characters tt('1', '2') and tt('3'), respectively. it() Each of the characters is then offered (in turn) to the tt(std::streambuf) that is associated with the tt(ostream) object. In particular, the tt(std::streambuf)'s tt(overflow()) member is called. it() tt(OFstreamBuf)'s default tt(overflow()) function ignores characters, but specializations can override tt(overflow()) to process the received characters em(ad lib). it() A overriding tt(overflow()) function has access to the member tt(OFstreambuf::out()) which is a reference to the tt(std::ostream) receiving the filtered information. ) To implement a simple copy-filter (i.e., all characters are accepted as-is) a class must be derived from tt(OFilterBuf) providing an overriding implementation of tt(overflow()), e.g., as follows: verb( int DerivedClass::overflow(int ch) { out().put(ch); } ) Next this tt(std::streambuf) specialization can be associated with an tt(ostream) into which information to be `copy filtered' can be inserted (cf. the EXAMPLE section below). includefile(include/namespace) manpagesection(INHERITS FROM) std::streambuf manpagesection(CONSTRUCTORS) As tt(OFilterBuf) should be used as a base class all its constructors are protected. itemization( itb(OFilterBuf()) This constructor creates a tt(OFilterBuf) object without associating it with a destination (filtered) tt(ostream). itb(OFilterBuf(std::string const &fname, openmode mode = std::ios::out)) This constructor creates a tt(OFilterBuf) object and opens a private tt(std::ofstream) object whose filename is provided and that should receive the filtered information. itb(OFilterBuf(std::ostream &out)) This constructor creates a tt(OFilterBuf) object and will insert any filtered information into the provided tt(ostream) object. ) Copy and move constructors (and assignment operators) are not available. manpagesection(PROTECTED MEMBER FUNCTIONS) Except for the public members inherited from bf(std::ostreambuf) all of tt(OFilterBuf's) members are protected. Derived classes should provide their own implementation of tt(int underflow(int ch)) to implement filtering. itemization( itb(void reset(std::string const &fname, openmode mode = std::ios::out)) This member flushes the current destination (filtered) tt(std::ostream) and associates the tt(OFilterBuf) object with an tt(std::ofstream) object whose filename is provided and that should receive subsequently filtered information. itb(void reset(std::ostream &out)) This member flushes the current destination (filtered) tt(std::ostream) object and associates the tt(OFilterBuf) object with the provided tt(ostream) object. itb(std::ostream &out() const) This member is available to derived classes to insert information into the destination (filtered) stream. ) manpagesection(EXAMPLE) verb( #include #include #include struct NoDigits: public FBB::OFilterBuf { NoDigits(std::ostream &out) : OFilterBuf(out) {} private: int overflow(int ch) override { if (not isdigit(ch)) out().put(ch); return ch; } }; using namespace FBB; using namespace std; int main() { NoDigits nod(cout); // no digits to cout ostream out(&nod); out << cin.rdbuf(); // rm digits from cin } ) manpagefiles() em(bobcat/ofilterbuf) - defines the class interface manpageseealso() bf(bobcat)(7), bf(ifilterbuf)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/stdextractor.yo0000644000175000017500000001047114050437223020632 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::StdExtractor)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Executing Child Processes) manpagename(FBB::StdExtractor)(Runs external programs writing standard error) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() The bf(FBB::StdExtractor) class offers a basic interface for calling external programs (so-called em(child processes)) writing their standard output and error streams. The standard input stream of the child processes are by default not handled by ttStdExtractor) objects. The child's standard output and standard error streams are read through the tt(StdExtractor) object: information written by the child process to these streams is extracted or read from tt(StdExtractor) object. The tt(PATH) environment variable is not used when calling child processes: child process programs must be specified using paths. tt(StdExtractor) objects may repeatedly be used to execute the same or different child processes. Arguments passed to child processes may be surrounded by double or single quotes. Arguments surrounded by double quotes have their double quotes removed, while interpreting any escape-sequences that may have been used within. Arguments surrounded by single quotes have their single quotes removed, while accepting their content as-is. In addition unquoted escape-sequences may be specified: those escape sequences are evaluated and replaced by their intended characters (e.g., tt(\100) is converted to tt(@)). includefile(include/namespace) manpagesection(INHERITS FROM) bf(FBB::Exec) (private), bf(FBB::IFdBuf) (private), bf(std::istream) manpagesection(CONSTRUCTOR) itemization( itb(StdExtractor(size_t bufSize = 100)) A tt(bufSize) argument may be specified: it defines the internal buffer size used by the tt(StdExtractor's) streambuf. By default the stdandard input stream is not handled. itb(CoutExtractor(Mode mode, size_t bufSize = 100)) The tt(mode) argument must be tt(StdExtractor::CLOSE_STD). It indicates that the standard input stream is redirected to tt(/dev/null): the child processes cannot read their standard input streams. A tt(bufSize) argument may be specified: it defines the internal buffer size used by the tt(CinInserter's) streambuf. ) Copy and move constructors (and assignment operators) are not available. manpagesection(MEMBERS) itemization( itb(void execute(std::string const &cmd)) The argument specifies the command to execute: the command itself must be specified as a path (the tt(PATH) environment variable isn't used). This member immediately returns, after which information written by the child process to its standard output and standard error streams may be extracted from the tt(StdExtractor) object. Once tt(execute) has returned it can be called again, either using the same or another command. Arguments passed to the program to be executed as child process may optionally be specified using single or double quotes, as described in this man-page's DESCRIPTION section. itb(int ret() const) Once tt(execute) has returned this member provides the actual exit code of the child process. Its value equals -1 before the first tt(exectue) call. ) manpagesection(PROTECTED MEMBER) itemization( itb(Pipe &childOutPipe()) If derived classes need to override the redirections-members then they probabaly need access to the pipe written by the child process. This member provides a reference to that pipe. By default the parent process reads information from the pipe, while the child process inserts its standard error output into the pipe. ) manpagesection(EXAMPLE) verbinclude(../../cerrextractor/driver/driver.cc) manpagefiles() em(bobcat/cerrextractor) - provides the class interface manpageseealso() bf(bobcat)(7), bf(cerrextractor)(3bobcat), bf(cininserter)(3bobcat), bf(coutextractor)(3bobcat), bf(execl)(3), bf(exec)(3bobcat), bf(fork)(3bobcat), bf(process)(3bobcat). manpagebugs() None reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/tempstream.yo0000644000175000017500000000422114050437223020261 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::TempStream)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Temporary fstream) manpagename(FBB::TempStream)(Temporary fstream) manpagesynopsis() bf(#include )nl() manpagedescription() bf(FBB::TempStream) objects are temporary tt(std::fstreams) opened with mode 0600 (user only read+write). The file created by a tt(TempStream) object is removed from the file system once the tt(TempStream) object goes out of scope. A tt(TempStream) object creates an empty file, and information can immediately be inserted into the tt(TempStream) object. To switch between insertion and extraction simply call tt(seekg) (for extraction) or tt(seekp) (for insertion). includefile(include/namespace) manpagesection(INHERITS FROM) bf(std::fstream) manpagesection(CONSTRUCTORS) itemization( itb(TempStream(std::string const &base = "/tmp/FBB::TempStream")) The constructor initializes the object and creates a file with the given base-name to which six random characters are appended. If the tt(TempStream) could not be constructed an tt(FBB::Exception) is thrown. ) Copy and move constructors (and assignment operators) are not available. manpagesection(MEMBER FUNCTIONS) All bf(std::fstream) members are available, as bf(FBB::TempStream) inherits from this class. In addition, tt(TempStream) itself offers itemization( itb(std::string const &fileName() const) The name of the created temporary file. ) manpagesection(EXAMPLE) verb( #include #include using namespace std; using namespace FBB; int main() { TempStream ts("/tmp/demo"); ts << "Hello world\n"; ts.seekg(0); string line; getline(ts, line); cout << line << ", removed: " << ts.fileName() << '\n'; } ) manpagefiles() em(bobcat/tempstream) - defines the class interface manpageseealso() bf(bobcat)(7), bf(mkostemp)(3) manpagebugs() None reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/socketbase.yo0000644000175000017500000000642214050437223020230 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::SocketBase)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Base class for sockets) manpagename(FBB::SocketBase)(Base class for socket-constructing classes) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() This class is a base class for the bf(FBB::ServerSocket) and bf(FBB::ClientSocket) classes. Since it is designed as a base class, all its constructors are protected. includefile(include/namespace) manpagesection(INHERITS FROM) bf(FBB::InetAddress) manpagesection(PROTECTED CONSTRUCTORS) itemization( itb(SocketBase(size_t port)) This constructor creates a bf(SocketBase) to be used with bf(ServerSocket)-objects, listening on tt(port). itb(SocketBase(std::string const &host, uint16_t port)) This constructor creates a bf(FBB::SocketBase) to be used with a bf(ClientSocket)-object, connecting to tt(hostname), at port `tt(port)'. ) These constructors throw a tt(std::exception) if they could not properly complete. The copy constructor and copy assignment operator are available. Both offer protected access rights. manpagesection(PROTECTED MEMBER) itemization( itb(SocketBase makeBase(int socket, sockaddr_in const &address)) This member returns a bf(FBB::SocketBase) object initializing its socket and bf(FBB::InetAddress) from the provided arguments. ) manpagesection(MEMBER FUNCTIONS) All members of bf(FBB::InetAddress) are available, as bf(FBB::SocketBase) inherits from this class. itemization( itb(bool debug() const) This accessor returns bf(true) if the socket's em(debug) (bf(SO_DEBUG)) socket option is active. It throws an bf(FBB::Exception) exception if the status of the debug option could not be determined; itb(bool reuse() const) This accessor returns bf(true) if the socket's em(reuse) (bf(SO_REUSEADDR)) socket option is active. It throws an bf(FBB::Exception) exception if the status of the reuse option could not be determined; itb(void setDebug(bool trueIsOn) const) This member may be used to modify the socket's em(debug) (bf(SO_DEBUG)) socket option. It throws an bf(FBB::Exception) exception if the socket's debug option could not be modified; itb(void setReuse(bool trueIsOn) const) This member may be used to modify the socket's em(reuse) (bf(SO_REUSEADDR)) socket option. It throws an bf(FBB::Exception) exception if the socket's reuse option could not be modified; itb(int socket() const) This accessor returns the bf(FBB::SocketBase)'s socket value. ) manpagesection(EXAMPLE) The classes tt(FBB::ClientSocket) and tt(FBB::ServerSocket) were derived from tt(SocketBase). E.g., verbinclude(../../clientsocket/clientsocket) See the bf(clientsocket)(3bobcat) man-page for an example showing how to use tt(FBB::ClientSocket). manpagefiles() em(bobcat/socketbase) - defines the class interface manpageseealso() bf(bobcat)(7), bf(clientsocket)(3bobcat), bf(inetaddress)(3bobcat), bf(localsocketbase)(3bobcat), bf(serversocket)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/exec.yo0000644000175000017500000000563114050437223017032 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Exec)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Executing Child Processes) manpagename(FBB::Exec)(Runs external programs) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() The bf(FBB::Exec) class offers a basic interface for calling external programs (so-called em(child processes)). The standard streams of the child processes are not handled by ttExec) objects: the parent's standard streams are used by the child process. The tt(PATH) environment variable is not used when calling child processes: child process programs must be specified using paths. tt(Exec) objects may repeatedly be used to execute the same or different child processes. Before starting the next child process, the current child process must have finished. Arguments passed to child processes may be surrounded by double or single quotes. Arguments surrounded by double quotes have their double quotes removed, while interpreting any escape-sequences that may have been used within. Arguments surrounded by single quotes have their single quotes removed, while accepting their content as-is. In addition unquoted escape-sequences may be specified: those escape sequences are evaluated and replaced by their intended characters (e.g., tt(\100) is converted to tt(@)). includefile(include/namespace) manpagesection(INHERITS FROM) bf(FBB::Fork) manpagesection(CONSTRUCTOR) Only the default constructor is supported. manpagesection(MEMBERS) itemization( itb(bool execute(std::string const &cmd)) The argument specifies the command to execute: the command itself must be specified as a path (the tt(PATH) environment variable isn't used). The member returns tt(true) if the child process's exit value equals 0. Otherwise tt(false) is returned. Once tt(execute) has returned it can be called again, either using the same or another command. The class tt(Exec) does not offer facilities to forcefully terminate child processes: parent processes are suspended until the child processes have completed. Arguments passed to the program to be executed as child process may optionall be specified using single or double quotes, as described in this man-page's DESCRIPTION section. itb(int ret() const) Once tt(execute) has returned this member provides the actual exit code of the child process. Its value equals -1 before the first tt(exectue) call. ) manpagesection(EXAMPLE) verbinclude(../../exec/driver/driver.cc) manpagefiles() em(bobcat/exec) - provides the class interface manpageseealso() bf(bobcat)(7), bf(cerrextractor)(3bobcat), bf(cininserter)(3bobcat), bf(coutextractor)(3bobcat), bf(execl)(3), bf(fork)(3bobcat), bf(process)(3bobcat), bf(stdextractor)(3bobcat). manpagebugs() None reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/ofdbuf.yo0000644000175000017500000001227114050437223017351 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::OFdBuf)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (File Descriptor Output Stream Buffer) manpagename(FBB::OFdBuf) (Output stream buffer initialized by a file descriptor) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() bf(FBB::OFdBuf) objects may be used as a tt(std::streambuf) of tt(std::ostream) objects to allow insertions into a file descriptor. File descriptors are not defined within the context of bf(C++), but they can be used on operating systems that support the concept. Realize that using file descriptors introduces operating system dependencies. includefile(include/namespace) manpagesection(INHERITS FROM) bf(std::streambuf) manpagesection(ENUMERATION) The public enumeration tt(Mode) defined in the class tt(FBB::OFdStreamBuf) has the following values: itemization( it() bf(CLOSE_FD), indicating that the file descriptor used by the object must be closed; it() bf(KEEP_FD) (the default) indicating that the file descriptor used by the object must not be closed. ) manpagesection(CONSTRUCTORS) itemization( itb(OFdBuf()) This constructor initializes the streambuf, without associating it to a file descriptor, and without using buffering. The member tt(reset) can be used to associate the object later on with a file descriptor and optionally a buffer size. When the object is destroyed or if the mode-less overloaded version of the tt(reset) member is called, the file descriptor is closed. itb(OFdBuf(Mode mode)) This constructor initializes the streambuf, without associating it to a file descriptor, and without using buffering. The member tt(reset) can be used to associate the object later on with a file descriptor and optionally a buffer size. When the object is destroyed or if the mode-less overloaded version of the member tt(reset) is called, the tt(Mode) argument determines whether the file descriptor will be closed or will remain open. itb(OFdBuf(int fd, size_t n = 1)) This constructor initializes the streambuf, associating it to file descriptor tt(fd), and an optional unget buffer size (by default having size 1). When tt(reset) is called subsequently, or if the object is destroyed the provided file descriptor will be closed. itb(OFdBuf(int fd, size_t n = 1)) This constructor initializes the streambuf, associating it to file descriptor tt(fd), and an optional unget buffer size (by default having size 1). When the object is destroyed or if the mode-less overloaded version of the member tt(reset) is called, the file descriptor will be closed. itb(OFdBuf(int fd, Mode mode, size_t n = 1)) This constructor initializes the streambuf, associating it to file descriptor tt(fd), and an optional unget buffer size (by default having size 1). When the object is destroyed or if the mode-less overloaded version of the member tt(reset) is called, the tt(Mode) argument determines whether the file descriptor will be closed or will remain open. ) Copy and move constructors (and assignment operators) are not available. manpagesection(MEMBER FUNCTIONS) All members of tt(std::streambuf) are available, as tt(FBB::OFdBuf) inherits from this class. itemization( itb(void eoi()) The file descriptor used by the tt(OFdBuf) is closed, irrespective of the tt(Mode) that was specified when the tt(OFdBuf) object was constructed. Following tt(eoi) the tt(OFdBuf) object can no longer be used until one of its tt(reset) members has been called. Instead of using this member the tt(eoi) manipulator can also be used. itb(int fd() const) The file descriptor used by the tt(OFdBuf) object is returned. If the tt(OFdBuf) is not associated with a file descriptor -1 is returned. itb(void reset(int xfd, size_t n = 1)) The streambuf is (re)initialized, using file descriptor tt(fd), and an optional unget buffer size (by default having size 1). When called repeatedly, the tt(Mode) specification used whem the object was constructed determines whether the file descriptor will be closed or will remain open. itb(void reset(int xfd, Mode mode, size_t n = 1)) The streambuf is (re)initialized, using file descriptor tt(fd), a file descriptor closing parameter and an optional unget buffer size (by default having size 1). Depending on the tt(Mode) argument the object's currently used file descriptor will be closed or will remain open when the tt(IFdBuf) object is destroyed. ) manpagesection(MANIPULATOR) itemization( itb(FBB::eoi) The tt(eoi) manipulator can be inserted into the tt(ostream) instead of calling the tt(OFdBuf::end) member. It performs the same actions as the tt(eoi) member. If inserted into a plain tt(std::ostream) nothing happens. ) manpagesection(EXAMPLE) verbinclude(../../ofdbuf/driver/driver.cc) manpagefiles() em(bobcat/ofdbuf) - defines the class interface manpageseealso() bf(bobcat)(7), bf(ifdbuf)(3bobcat), bf(ofdstream)(3bobcat), bf(std::streambuf) manpagebugs() None reported includefile(include/trailer) bobcat-5.09.01/documentation/man/exception.yo0000644000175000017500000002551414050437223020106 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Exception)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Error handler) manpagename(FBB::Exception)(std::exception objects acception stream insertions) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() bf(FBB::Exception) objects derived from tt(std::exception), but accept stream insertions. Their intended use consists of throwing an anonymous object, into which the text of the tt(std::exception::what) message has been inserted. tt(Exception) exceptions are thrown by several Bobcat classes. These classes are tt( Arg, ArgConfig, BigInt, Cgi, Cidr, ClientSocket, CmdFinderBase, ConfigFile, DateTime, DecryptBuf, DigestBuf, EncryptBuf, Fork, GetHostent, Glob, HMacBuf, Hostname, LocalClientSocket, LocalServerSocket, LocalSocketBase, Log, MailHeaders, Mbuf, Milter, Mstream, OFoldBuf, OneKey, Pattern, Pipe, Process, Redirector, Selector, ServerSocket, Signal, SocketBase, Stat, TempStream, User, Xpointer) manpagesection(NAMESPACE) bf(FBB)nl() All constructors, members, operators and manipulators, mentioned in this man-page, are defined in the namespace bf(FBB). manpagesection(INHERITS FROM) bf(std::exception) manpagesection(ENUMERATION) The enumeration tt(Protection) is used by the member tt(protection) described below. The enumeration has two values: itemization( itt(ANY): an existing file may have any set of protection bits; itt(EQUAL): an existing file mut have exactly the set of protection bits as specified when calling tt(Exception::protection). ) manpagesection(CONSTRUCTORS) itemization( itb(Exception()) The default constructor (assigns 0 to tt(FBB::g_errno), see the next constructor). itb(Exception(int errnoValue)) This constructor stores the provided tt(errnoValue) value in a thread-local variable tt(int FBB::g_errno). Before Bobcat 4.04.00 tt(errnoValue) was only stored in the global tt(::errno) variable (it still is), but as this variable is also used by many other functions, tt(errno's) value may have changed by the time the exception is caught. The tt(thread_local int FBB::g_errno) variable does not have that drawback. When tt(g_errno) must be declared without including tt(bobcat/exception) then do verb( namespace FBB { extern thread_local int g_errno; } ) ) Copy and move constructors (and assignment operators) are available. manpagesection(MEMBER FUNCTIONS) All members of bf(std::exception) are available, as bf(FBB::Exception) inherits from this class. itemization( itb(char const *what() const noexcept(true) override) Returns the text that was inserted into the bf(FBB::Exception) object. ) manpagesection(OVERLOADED OPERATORS) itemization( itb(Exception &&operator<<(Exception &&in, Type const &t)) A function template implementing the overloaded insertion operator. It can be used to insert values of any type that can also be inserted into an tt(ostringstream) object. ) manpagesection(STATIC MEMBERS) The following convenience functions can be used for controlled opening of stream-type objects, like tt(std::ofstream) and tt(std::ifstream) objects. These stream-type objects must support tt(open) and tt(close) members, like those provided by tt(std::ifstream) and tt(std::ofstream). If the stream was already open it is first closed. If opening fails an tt(FBB::Exception) exception is thrown containing a short message stating that the named stream could not be opened. itemization( itb(static StreamType factory(std::string const &name)) Returns an open tt(StreamType>) stream object which can be used to move-construct a tt(StreamType) object. E.g., verb( auto out{ Exception::factory("/tmp/out") }; ) itb(static StreamType factory(int errnoValue, std::string const &name)) Returns an open tt(StreamType>) stream object which can be used to move-construct a tt(StreamType) object. If constructing the stream object fails, then the thrown bf(FBB::Exception) assigns tt(errnoValue) to tt(FBB::g_errno). itb(static StreamType factory(std::string const &name, std::ios::openmode mode)) Returns an open tt(StreamType>) stream object, created using the tt(openmode mode) flags, which can be used to move-construct a tt(StreamType) object. itb(static StreamType factory(int errnoValue, std::string const &name, std::ios::openmode mode)) Returns an open tt(StreamType>) stream object, created using the tt(openmode mode) flags, which can be used to move-construct a tt(StreamType) object. If constructing the stream object fails, then the thrown bf(FBB::Exception) assigns tt(errnoValue) to tt(FBB::g_errno). itb(static StreamType factory(std::string const &name, std::ios::openmode mode1, std::ios::openmode mode2)) Returns an open tt(StreamType>) stream object. the stream is initially opened using tt(mode1). If that fails, tt(mode2) is used. If both ways to open the stream fail, then an tt(Exception) is thrown. The returned stream can be used to move-construct a tt(StreamType) object. This member can be used to open an tt(std::fstream) which may or may not yet exist for both reading and writing. E.g., verb( auto out{ Exception::factory("/tmp/out", ios::in | ios::out, ios::in | ios::out | ios::trunc) }; ) If tt(/tmp/out) already exists, then tt(ios::in | ios::out) should succeed. If it doesn't, then it's created empty for reading and writing, using tt(ios::in | ios::out | ios::trunc). itb(static StreamType factory(int errnoValue, std::string const &name, std::ios::openmode mode1, std::ios::openmode mode2)) Returns an open tt(StreamType>) stream object. the stream is initially opened using tt(mode1). If that fails, tt(mode2) is used. If both ways to open the stream fail, then an tt(Exception) is thrown, assigning tt(errnoValue) to tt(FBB::g_errno). itb(static void open(int errnoValue, StreamType &stream, std::string const &name, std::ios::openmode mode)) Opens the stream object, using its tt(open) member, passing tt(mode) to tt(open). If opening the stream fails, then the thrown bf(FBB::Exception) assigns tt(errnoValue) to tt(FBB::g_errno). itb(static void open(StreamType &stream, std::string const &name)) Opens the stream object, using its default tt(open) member. itb(static void open(int errnoValue, StreamType &stream, std::string const &name)) Opens the stream object, using its default tt(open) member. If opening the stream fails, then the thrown bf(FBB::Exception) assigns tt(errnoValue) to tt(FBB::g_errno). itb(static void open(StreamType &stream, std::string const &name, std::ios::openmode mode)) Opens the stream object, using its tt(open) member, passing tt(mode) to tt(open). itb(static void open(int errnoValue, StreamType &stream, std::string const &name, std::ios::openmode mode)) Opens the stream object, using its tt(open) member, passing tt(mode) to tt(open). If opening the stream fails, then the thrown bf(FBB::Exception) assigns tt(errnoValue) to tt(FBB::g_errno). itb(static void open(StreamType &stream, std::string const &name, std::ios::openmode mode1, std::ios::openmode mode2)) Opens the stream object, using its tt(open) member, , initially passing tt(mode1) to tt(open). If that fails, tt(mode2) is used. If both ways to open the stream fail, then an tt(Exception) is thrown. itb(static void open(int errnoValue, StreamType &stream, std::string const &name, std::ios::openmode mode1, std::ios::openmode mode2)) Opens the stream object, using its tt(open) member, initially passing tt(mode1) to tt(open). If that fails, tt(mode2) is used. If both ways to open the stream fail, then an tt(Exception) is thrown, assigning tt(errnoValue) to tt(FBB::g_errno). itb(static size_t protection(std::string const &path, size_t protect, Protection type = EQUAL)) Returns the protection bits (cf. bf(open)(2)) of tt(path). The tt(protect) parameter is used to specify the requested protection bits. This value is usually specified as an octal value. If the specified value exceeds 0777 an exception is thrown. The third parameter is only used in combination with already existing files. If specified as tt(ANY) the file's actual permission bits are not compared with tt(protect); if specified as tt(EQUAL) the file's permission bits must be identical to tt(protect), or an exception is thrown. If tt(path) does not yet exist a file tt(path) with permission tt(protect) is created. This member returns tt(path)'s permission bits. If tt(path) is created by tt(protection), then opening a stream for tt(path) does not change tt(path)'s protection. ) manpagesection(MANIPULATOR) The following manipulator (which is em(not) part of the bf(FBB::Exception), class, but em(is) defined in the bf(FBB) namespace) can be inserted into the bf(FBB::Exception) object: itemization( itb(FBB::errnodescr) The descriptive text associated with the current tt(errno) value is inserted into the bf(FBB::Exception) object (it can also be used to insert the descriptive text in a tt(std::ostream) object). No text is inserted if tt(errno) equals zero. This manipulator is thread-safe (but tt(errno) may be modified when tt(errno) holds an invalid value). ) manpagesection(EXAMPLE) verb( if (exceptionalCondition) throw FBB::Exception{ 1 } << "Exceptional condition occurred"; ) manpagefiles() em(bobcat/exception) - defines the class interface manpageseealso() bf(bobcat)(7) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/include/0000755000175000017500000000000014050437223017153 5ustar frankfrankbobcat-5.09.01/documentation/man/include/trailer.yo0000644000175000017500000000142514050437223021170 0ustar frankfrank manpagesection(BOBCAT PROJECT FILES) itemization( itt(https://fbb-git.gitlab.io/bobcat/): gitlab project page; itt(bobcat__CurVers_-x.dsc): detached signature; itt(bobcat__CurVers_-x.tar.gz): source archive; itt(bobcat__CurVers_-x_i386.changes): change log; itt(libbobcat1__CurVers_-x_*.deb): debian package containing the libraries; itt(libbobcat1-dev__CurVers_-x_*.deb): debian package containing the libraries, headers and manual pages; ) manpagesection(BOBCAT) Bobcat is an acronym of `Brokken's Own Base Classes And Templates'. manpagesection(COPYRIGHT) This is free software, distributed under the terms of the GNU General Public License (GPL). manpageauthor() Frank B. Brokken (bf(f.b.brokken@rug.nl)). bobcat-5.09.01/documentation/man/include/namespace.yo0000644000175000017500000000025014050437223021455 0ustar frankfrankmanpagesection(NAMESPACE) bf(FBB)nl() All constructors, members, operators and manipulators, mentioned in this man-page, are defined in the namespace bf(FBB). bobcat-5.09.01/documentation/man/include/header.yo0000644000175000017500000000132614050437223020756 0ustar frankfrankDEFINEMACRO(Manpage)(1)(\ whenman((Manpage: tt(man -e bobcat ARG1)))\ whenhtml((Manpage: url(ARG1(3bobcat))(ARG1.3.html)))\ ) DEFINEMACRO(itb)(1)(it() bf(ARG1):nl()) DEFINEMACRO(itt)(1)(it() tt(ARG1)) DEFINEMACRO(itrange)(2)(tt(CHAR(91)ARG1, ARG2+CHAR(41))) includefile(../../../release.yo) htmlbodyopt(text)(#27408B) htmlbodyopt(bgcolor)(#FFFAF0) whenhtml(mailto(Frank B. Brokken: f.b.brokken@rug.nl)) DEFINEMACRO(lsoption)(3)(\ bf(--ARG1)=tt(ARG3) (bf(-ARG2))\ ) DEFINEMACRO(loption)(1)(\ bf(--ARG1)\ ) DEFINEMACRO(soption)(1)(\ bf(-ARG1)\ ) DEFINEMACRO(ix)(0)(bf(imgx)) DEFINEMACRO(Ix)(0)(bf(Imgx)) DELETEMACRO(tt) DEFINEMACRO(tt)(1)(em(ARG1)) DEFINEMACRO(rangett)(1)(tt(CHAR(91)ARG1+CHAR(41))) bobcat-5.09.01/documentation/man/multibuf.yo0000644000175000017500000001557614050437223017746 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::MultiBuf)(3bobcat)(_CurYrs_) (libbobcat-dev__CurVers_) (Writing multiple streams) manpagename(FBB::MultiBuf)(Selectively writes multiple streams) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() The bf(FBB::MultiBuf) class is a specialization of tt(std::streambuf). It can be used to write selectively to multiple tt(std::ostreams). Each tt(std::ostream) that is associated with a bf(MultiBuf) is given a mode-tag indicating whether the stream should always be used when information is inserted into the bf(MultiBuf), just once, or not at all. Each of the stream's mode-tags may be set to any of the defined tag-values. When the address of a bf(MultiBuf) is used to initialize a tt(std::ostream) the constructed tt(std::ostream) becomes an output-multiplexer: by inserting information into the tt(std::ostream) object, all tt(std::ostream) objects added to its bf(MultiBuf) buffer which have an active mode receive that information. An bf(MultiBuf) object should be outlived by all active streams that are associated with it. bf(MultiBuf) objects refer to tt(std::ostreams) which are passed to it, and not to their tt(std::streambufs). So it is possible to change these tt(std::ostream's std::streambufs) without reinstalling the tt(std::ostreams) themselves. No assumptions should be made about the order in which the tt(std::ostream) objects that are associated with the bf(MultiBuf) objects are visited when information is inserted. includefile(include/namespace) manpagesection(INHERITS FROM) tt(std::streambuf) manpagesection(ENUMERATION) In the bf(Mode) enumeration the following values are defined: itemization( itb(OFF) A tt(std::ostream) having this mode will not be used when information is inserted into a bf(MultiBuf) itb(ON) A tt(std::ostream) having this mode will be used when information is inserted into a bf(MultiBuf) itb(ONCE) A tt(std::ostream) having this mode will be used once, until the next flushing operation, when information is inserted into an bf(MultiBuf) itb(RESET) A tt(std::ostream) having this mode will not be used when information is inserted into a bf(MultiBuf). At a flush operation all bf(ONCE) modes will be set to bf(RESET) itb(ALL) This mode is used in combination with the member tt(remove) to remove all tt(std::ostream) elements matching a specified tt(std::ostream) argument. ) manpagesection(TYPES) The following subtypes are defined in the class bf(FBB:MultiBuf): itemization( itb(iterator) This is a synonym of tt(std::vector::iterator) itb(const_iterator) This is a synonym of tt(std::vector::const_iterator) ) manpagesection(NESTED CLASS) The class bf(MultiBuf::stream) is defined as a nested class of bf(MultiBuf). It offers the following constructor and public members: itemization( itb(stream(std::ostream &os, Mode mode = ON)) The constructor stores a tt(std::ostream) object, and associates a bf(Mode) value with it. itb(void setMode(Mode mode)) This member is used to redefine the bf(stream)'s bf(Mode) value. itb(void mode() const) This member returns the bf(stream)'s bf(Mode) value. itb(operator std::ostream &()) This member returns the bf(stream)'s tt(std::ostream). ) manpagesection(CONSTRUCTORS) itemization( itb(MultiBuf()) The default constructor creates a bf(MultiBuf) object which contains no associated tt(std::ostream) objects. itb(MultiBuf(std::ostream &os, Mode mode = ON)) This constructor creates a bf(MultiBuf) object which is immediately associated with the tt(std::ostream) specified as its first argument. itb(MultiBuf(std::vector const &osvector)) This constructor creates a bf(MultiBuf) object which is immediately associated with all tt(std::ostream) objects that are stored in the bf(MultiBuf::stream) elements of the specified vector. ) Copy and move constructors (and assignment operators) are not available. manpagesection(MEMBER FUNCTIONS) All members of tt(std::ostringstream) and tt(std::exception) are available, as bf(MultiBuf) inherits from these classes. itemization( itb(iterator begin()) This member returns an iterator to the first bf(stream) element that is stored in a bf(MultiBuf) object. itb(const_iterator begin()) This member returns an iterator to the first (unmodifiable) bf(stream) element that is stored in a bf(MultiBuf) object. itb(iterator end()) This member returns an iterator pointing beyond the last bf(stream) element that is stored in a bf(MultiBuf) object. itb(const_iterator end()) This member returns an iterator pointing beyond the last (unmodifiable) bf(stream) element that is stored in a bf(MultiBuf) object. itb(void insert(std::ostream &os, Mode mode = ON)) This member adds the specified tt(std::ostream) using the specified bf(Mode) to the current set of bf(stream) objects. Note that if called multiple times for identical tt(std::ostreams) these objects are inserted multiple times as well. itb(void insert(std::vector const &os)) This member adds all bf(stream) objects stored in the bf(os) vector to the current set of bf(stream) objects. itb(bool remove(std::ostream &os, Mode mode = ONCE)) If tt(os) is stored in the bf(MultiBuf) it is removed, and tt(true) is returned. If mode tt(ALL) is specified all tt(os) objects that were stored in the bf(MultiBuf) object are removed (and tt(true) is returned). If the tt(os) object was not stored tt(false) is returned. To determine whether tt(os) has been stored in the bf(MultiBuf) object its address is compared to the addresses of the tt(std::ostream) objects that are stored inside the bf(MultiBuf) object: the object(s) having addresses tt(&os) is (are) removed. itb(void void setOnce()) This member will reset all the tt(RESET) bf(Mode) values of the stored bf(stream) objects to tt(ONCE). itb(size_t size() const) The number of streams currently serviced by the bf(MultiBuf) object is returned. ) manpagesection(EXAMPLE) verb( #include #include #include using namespace std; using namespace FBB; int main() { MultiBuf msb(cout); ostream os(&msb); ofstream out("out"); msb.insert(out, MultiBuf::ONCE); os << "This is on cout and out\n" "This is on cout only\n"; msb.setOnce(); os << "This is on cout and out\n" "This is on cout only\n"; } ) manpagefiles() em(bobcat/multibuf) - defines the class interface manpageseealso() bf(bobcat)(7) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/cidr.yo0000644000175000017500000001321314050437223017022 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Cidr)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (CIDR matching) manpagename(FBB::Cidr)(Compares IP4 addresses to CIDR specifications) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() Objects of the class tt(Cidr) can be used for testing whether IP4 Internet addresses belong to address ranges defined by Classless Inter-Domain Routing (CIDR) address block specifications. CIDR blocks are specified as tt(a.b.c.d/m) where tt(a.b.c.d) are the four octets of a dotted decimal IP4 address specification (e.g., 129.125.14.80) and tt(m) is a mask-size (ranging from 0 to 32) defining the number of most significant bits to remain as-is. The CIDR specification 129.125.14.80/16 defines a class B network, with addresses ranging from 129.125.0.0 to 129.125.255.255. The mask size does not have to be a multiple of 8. E.g., when specifying 129.125.14.80/5 only the most significant 5 bits of the first octed are fixed, resulting in an address range ranging from 128.0.0.0 to 135.255.255.255. CIDR specifications passed to a tt(Cidr) object must be of the form tt(a.b.c.d) or tt(a.b.c.d/m). If the mask is not specified a mask-size of 32 is used, effectively defining an address range of only one address. Mask values of 0 are ignored. Mask values of 0 are ignored by tt(Cidr) objects. When specifying CIDRs on a stream, empty lines and comment lines (having a hash-character (#) as their first non-blank character) are ignored. Non-empty lines must start with a CIDR specification, and the tt(Cidr) object will ignore all information on a line trailing a CIDR specification. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(CONSTRUCTORS) itemization( itb(Cidr(std::string const &cidrPattern)) The tt(Cidr) object is initialized with a single CIDR specification. itb(Cidr(std::istream &cidrStream)) The tt(Cidr) object is initialized with CIDR specifications read from the tt(std::istream cidrStream). ) Default, copy and move constructors and the copy and move assignment operators are available. manpagesection(MEMBER FUNCTIONS) The return valuess of the accessors (i.e., the tt(const) members) are only defined following a successful match (see below, the tt(match) members). itemization( itb(std::string const &address() const) returns the address matching a CIDR. itb(std::string cidr() const) returns the CIDR containing a specified address. itb(std::string first() const) returns the first address of the range of addresses defined by the CIDR specification. itb(std::string last() const) returns the last address of the range of addresses defined by the CIDR specification. Note that tt(first, last) do not define an iterator range. The address returned by tt(last) still belongs to the CIDR-range. itb(bool match(std::istream &in)) The value tt(true) is returned when an IP4 address found in the lines of tt(in) belongs to a CIDR range inspected by the tt(Cidr) object. The tt(match) function returns tt(true) at the first matching address. E.g., if a line contains the text verb( This is address 1.2.3.4 and this is 5.6.7.8 ) and the CIDR specifications verb( 5.1.1.1/8 1.2.1.1/16 ) were provided to the tt(Cidr) object, then the object will report a match for tt(5.6.7.8). As soon as a match is found tt(match) returns tt(true). If none of the addresses found in the lines of tt(in) matches any of the object's CIDR specifications, tt(false) is returned. itb(std::string mask() const) returns the mask used by the tt(CIDR) specification. itb(bool match(std::string const &line)) The value tt(true) is returned when an IP4 address found in tt(line) belongs to a CIDR range inspected by the tt(Cidr) object. The tt(match) function returns tt(true) at the first matching address. If none of the addresses found in tt(line) matches any of the object's CIDR specifications, tt(false) is returned. itb(void setCidr(std::istream &cidrStream)) A new set of CIDR specification is loaded into the tt(Cidr) object, reading the specifications from tt(cidrStream). itb(void setCidr(std::string const &cidrPattern)) A new CIDR specification is loaded into the tt(Cidr) object, using the specification found in tt(cidrPattern). The tt(Cidr) object is initialized with a single CIDR specification which must be of the form tt(a.b.c.d) or tt(a.b.c.d/m). If the mask is not specified a mask-size of 32 is used, effectively defining an address range of only one address. Mask values of 0 are ignored. itb(void swap(Cidr &other)) The current and tt(other) object are swapped. ) manpagesection(STATIC MEMBERS) itemization( itb(size_t dotted2binary(std::string const &dotted)) Converts "a.b.c.d" to a 32-bits value itb(std::string binary2dotted(size_t binary)) Converts a 32-bits value to a dotted decimal IP4 address ) manpagesection(EXAMPLE) verbinclude(../../cidr/driver/driver.cc) manpagefiles() em(bobcat/cidr) - defines the class interface manpageseealso() bf(bobcat)(7) manpagebugs() Members of tt(Cidr) use static data. The current implementation of tt(Cidr) is therefore not thread-safe. includefile(include/trailer) bobcat-5.09.01/documentation/man/readlinebuf.yo0000644000175000017500000002752414050437223020373 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::ReadLineBuf)(3bobcat)(_CurYrs_) (libbobcat-dev__CurVers_) (Editing input lines) manpagename(FBB::ReadLineBuf) (std::streambuf offering line-editing and history) manpagesynopsis() bf(#include )nl() Linking option: -lreadline -lbobcat manpagedescription() The bf(FBB::ReadLineBuf) object may be used as a tt(std::streambuf) of tt(std::istream) objects, allowing line-editing and history manipulation. The bf(ReadLineBuf) class uses Gnu's readline library to allow editing of input lines. The tt(ReadLineBuf) object can be used to construct a tt(std::istream) allowing in-line editing of lines read from the terminal. All lines may be preceded by a configurable prompt. Since Gnu's readline library operates on global data there can only be one bf(ReadLineBuf) object. Therefore bf(ReadLineBuf) is a singleton class: in any program there can only be one bf(ReadLineBuf) object (Gnu's readline library does, however, offer functions allowing programs to use multiple histories. So it would in principle be possible to design a non-singleton tt(ReadLineBuf) class. Since programs normally only interact with a single terminal, there is probably little use for non-singleton bf(ReadLineBuf) class). bf(ReadLineBuf) offers editing capabilities while the user is entering lines. Like Gnu's bf(readline)(3) function, the line editing commands are by default similar to those of bf(emacs)(1), but can easily be reconfigured, e.g. to offer bf(vi)(1)-like characteristics. History manipulation is provided as an option. The collected history may be accessed for reading using an bf(FBB::ReadLineHistory) object. Specific information about the facilities offered by the Gnu software used by bf(ReadLineBuf) is provided in the GNU Readline Library documentation (tt(http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html)). Gnu's tt(readline) function reads its information from the standard input file. Programs using tt(ReadLineBuf) should normally not extract information from tt(std::cin). However, as the standard input file has a file descriptor (0), redirection should be possible (e.g., using tt(FBB::Redirector)). When the command line is kept, history expansion is offered as an option. History expansion introduces words from the history list into the input stream, making it easy to repeat commands, to insert elements of a previous input line into the current input line, or to fix errors in previous command lines. History expansion is usually performed immediately after a complete line is read. The line selected from the history is called the tt(event), and the portions of that line that are processed are called tt(words). Various modifiers are available to manipulate selected words. This is comparable to the way a program like bf(bash)(1) breaks up its input line into `words'. History expansion is introduced by the use of the history expansion character, by default equal to the tt(!)-character. Only backslash (tt(\)) and single quotes can change the history expansion character into a normal character. The remainder of this section is copied almost verbatim from the bf(history)(3) man-page. The reader is referred to that man-page or to the Gnu History Library documentation for further details. The following bf(event designators) are supported: itemization( itt(!): starts a history substitution, except when followed by a blank, newline, tt(=) or tt(CHAR(40)). itt(!n): refers to command line n. itt(!-n): refers to the current command line minus n. itt(!!) refers to the previous command. This is a synonym for `!-1'. itt(!string) refers to the most recent command starting with string. itt(!?string[?]) refers to the most recent command containing string. The trailing tt(?) may be omitted if string is followed immediately by a newline. itt(^string1^string2^) (quick substitution) repeats the last command, replacing tt(string1) with tt(string2). Equivalent to tt(!!:s/string1/string2/). itt(!#) the entire command line typed so far. ) bf(Word Designators) Word designators are used to select desired words from the event. A tt(:) separates the event specification from the word designator. It may be omitted if the word designator begins with a tt(^, $, *, -), or tt(%). Words are numbered from the beginning of the line, with the first word being denoted by 0 (zero). Words are inserted into the current line separated by single spaces. itemization( itt(0) (zero) The zeroth word. For the shell, this is the command word. itt(n) The nth word. itt(^) The first argument. That is, word 1. itt($) The last argument. itt(%) The word matched by the most recent tt(?string?) search. itt(x-y) A range of words; `-y' abbreviates `0-y'. itt(*) All of the words but the zeroth. This is a synonym for tt(1-$). It is not an error to use * if there is just one word in the event; the empty string is returned in that case. itt(x*) Abbreviates tt(x-$). itt(x-) Abbreviates tt(x-$) like tt(x*), but omits the last word. ) If a word designator is supplied without an event specification, the previous command is used as the event. bf(Modifiers) After the optional word designator, there may appear a sequence of one or more of the following modifiers, each preceded by a tt(:). itemization( itt(h) removes a trailing file name component, leaving only the head. itt(t) removes all leading file name components, leaving the tail. itt(r) removes a trailing suffix of the form tt(.xxx), leaving the basename. itt(e) removes all but the trailing suffix. itt(p) prints the new command but does not execute it. itt(q) quotes the substituted words, escaping further substitutions. itt(x) quotes the substituted words as with q, but break into words at blanks and newlines. itt(s/old/new/) substitutes new for the first occurrence of old in the event line. Any delimiter can be used in place of tt(/). The final delimiter is optional if it is the last character of the event line. The delimiter may be quoted in old and new with a single backslash. If tt(&) appears in new, it is replaced by old. A single backslash will quote the tt(&). If tt(old) is null, it is set to the last old substituted, or, if no previous history substitutions took place, the last string in a tt(!?string[?]) search. itt(&) repeats the previous substitution. itt(g) Causes changes to be applied over the entire event line. This is used in conjunction with tt(:s) (e.g., tt(:gs/old/new/)) or tt(:&). If used with tt(:s), any delimiter can be used in place of tt(/), and the final delimiter is optional if it is the last character of the event line. An a may be used as a synonym for tt(g). itt(G) Apply the following tt(s) modifier once to each word in the event line. ) includefile(include/namespace) manpagesection(INHERITS FROM) tt(std::streambuf) manpagesection(ENUMERATIONS) The tt(enum Type) defines the following value: itemization( itt(DONT_EXPAND_HISTORY): history expansion is not requested; itt(EXPAND_HISTORY): history expansion is requested. ) The tt(enum Expansion) provides meaningful return values for the history expansion process. Its values are: itemization( itt(DONT_EXEC): history expansion succeeded, but the expanded line should not be executed. E.g., after entering the line verb( ls * ) the line verb( !!:p ) should cause the using program to em(display), rather than exectute tt(ls *). Note that interpretation of this expansion return value is not the task of the bf(ReadLineBuf) object, but of the program using the bf(ReadLineBuf) object. itt(ERROR): the history expansion failed. See also the member tt(expansionError) below; itt(EXPANDED): the history expansion succeeded; itt(NO_EXPANSION): no history expansion took place. ) manpagesection(STATIC MEMBERS) itemization( itb(ReadLineBuf &initialize(std::string const &prompt = "", Type type = NO_EXPANSION)) This static member returns the tt(ReadLineBuf) using an initial prompt, using a history of at most tt(std::numeric_limits::max()) lines, and by default not using history expansion. If the object has already been initialized a tt(logic_error) exception is thrown. itb(ReadLineBuf &initialize(std::string const &prompt, size_t historySize, Type type = NO_EXPANSION)) This static member initializes the tt(ReadLineBuf) using an initial prompt, an initial history of a predefined maximum size, and by default not using history expansion. Specifying a history size 0 results in no history being kept, any value equal to or exceeding the predefined constant tt(std::numeric_limits::max()) results in a history of at most tt(std::numeric_limits::max()) lines. If no history is requested but tt(type) is specified as tt(EXPAND_HISTORY) a tt(logic_error) exception is thrown. A tt(logic_error) is also thrown if the object has already been initialized. itb(ReadLineBuf &instance()) This static member returns the already initialized tt(ReadLineBuf) object. If the object has not yet been initialized a tt(logic_error) exception is thrown. ) manpagesection(CONSTRUCTORS) As the class bf(ReadLineBuf) is a singleton class it offers no public constructors, nor are overloaded assignment operators available. manpagesection(MEMBER FUNCTIONS) All members of bf(std::streambuf) are available, as bf(FBB::ReadLineBuf) inherits from this class. itemization( itb(ReadLineBuf::Expansion expansion() const) The status of the history expansion after retrieving a line from the terminal is returned. Its value is determined after each line retrieved from the terminal. If no history expansion is requested it returns tt(Expansion::ERROR). itb(std::string const &expansionError() const) A short textual description of the nature of the error when tt(expansion) returns tt(Expansion::ERROR) is returned. If no history expansion is requested an empty string is returned. itb(bool setExpansion(Type type)) History expansion can be activated or stopped using this member. When history expansion is requested but the bf(ReadLineBuf) object maintains no history the function returns tt(false). Otherwise it returns tt(true). itb(void setPrompt(std::string const &prompt = "")) The prompt that is displayed in front of the next line read from the terminal can be modified by this member. When called without arguments no prompt will be displayed. tt(setPrompt) can be called while input lines are being received. The new prompt will be active after the current line has been read from the terminal. itb(bool useTimestamps(std::string (*timestamp)() = 0)) When initialized with the address of a function returning a tt(std::string) the entered commands will be given a timestamp equal to the text returned by the function pointed to by tt(timestamp). The timestamps can be retrieved using the bf(ReadLineHistory)(3) object. By default or after passing an explicit 0-pointer to tt(useTimestamps) no timestamps are stored. The value tt(false) is returned when no history is kept, otherwise tt(true) is returned. ) manpagesection(EXAMPLE) verbinclude(../../readlinebuf/driver/driver.cc) manpagefiles() em(bobcat/readlinebuf) - defines the class interface manpageseealso() bf(bobcat)(7), bf(readline)(3), bf(readlinehistory)(3), bf(readlinestream)(3) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/pipe.yo0000644000175000017500000002073414050437223017044 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Pipe)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (System Level Communication Pipe) manpagename(FBB::Pipe)(Defines a system level communication pipe) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() bf(FBB::Pipe) objects may be used to construct a em(pipe). tt(Pipe) objects offer a simple interface to the reading and writing ends of pipes. tt(Pipe) objects are object-wrappers around the bf(pipe)(2) system call. A tt(Pipe) which is created just before a program forks can be used to set up a line of communication between the parent and child process. Information which is written by the child process to its standard output stream can be redirected to the writing end of the pipe (using the tt(writtenBy) member). The information appearing at the reading end of the pipe can then be extracted using, e.g., an tt(IFdStream) object, initialized with the tt(Pipe)'s reading file descriptor, or the reading end of the pipe can be redirected to an existing stream whose file descriptor is known, like tt(cin) (which uses the tt(STDIN_FILENO) file descriptor). When a tt(Pipe) object goes out of scope, no bf(close)(2) operation is performed on the pipe's file descriptors. After setting up the pipe using the tt(Pipe's) member functions and passing the tt(Pipe's) file descriptors to code that uses the tt(Pipe's) descriptors, the tt(Pipe) object might even be destroyed. The using code is responsible for closing the pipe. If the pipe should be closed at destruction time, then a class could be derived from bf(Pipe)(3bobcat), whose destructor may then close the pipe. Alternatively, tt(Pope's close) member can be called. The value -1 indicates that a file descriptor does not refer to a bf(pipe)(2) file descriptor. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(CONSTRUCTORS) itemization( itb(Pipe()) The default tt(Pipe) constructor constructs a pipe, calling bf(pipe)(2). This constructor throws an tt(Exception) exception if the default tt(Pipe) constructor did not properly complete. The thrown bf(Exception) object's tt(which()) member shows the system's tt(errno) value set by the failing bf(pipe)(2) function. itb(Pipe(Pipe &&tmp)) The move constructor moves the temporary object's file descriptors to the tt(Pipe) object being constructed. itb(Pipe(int const *fd)) This constructor expects two file descriptors, referring to the read and write file descriptors as returned by bf(pipe)(2). itb(Pipe(bool initialize)) This constructor can be used when the tt(Pipe) object should not be associated with an existing pipe. Instead it initializes its read and write file descriptors to -1. This constructor may be used in classes that define tt(Pipe) data members that only after the object is constructed can open their pipes. Having constructing a tt(Pipe obj(false)) object it can be associated with an open pipe using tt(obj = Pipe{}). When passing the argument tt(true) it calls tt(Pipe()) to construct a pipe. ) The move constructor and move assignment operator are available. Copy construction and copy assignment are not defined. Note that tt(Pipe's) destructor does not close the pipe's file descriptors. To close the pipes tt(close) must be called. manpagesection(MEMBER FUNCTIONS) itemization( itb(void close()) Both file descriptors of the tt(Pipe) object are closed; itb(void closeReadFd()) The file descriptor of the tt(Pipe) object that is associated with the reading end of the pipe is closed; itb(void closeWriteFd()) The file descriptor of the tt(Pipe) object that is associated with the writing end of the pipe is closed; itb(int readFd() const) Returns the pipe's file descriptor that is used for reading itb(void readFrom(int filedescriptor)) Sets up redirection from the internal em(read) filedescriptor to the given filedescriptor: information written to the write-end of the pipe may be retrieved by extracting the information from the stream that is associated with the indicated file descriptor. E.g., after the call tt(readFrom(STDIN_FILENO)) information inserted into the write-end of the pipe can be retrieved from tt(cin). itb(void readFrom(int const *filedescriptors, size_t n)) Sets up redirection from the internal em(read) filedescriptor to the given filedescriptors: information is read from the tt(Pipe) object when reading from any of the bf(n) provided filedescriptors (experimental). itb(int readOnly()) Closes the writing end of the pipe, returns the reading end's file descriptor. This member can be used, e.g., to construct an tt(IFdStream) object to extract the information that is inserted into the write-end of the pipe. itb(void swap(Pipe &other)) The current and other tt(Pipe) objects are swapped. Following this call the current tt(Pipe) objects refer to the other object's pipe file descriptors and vice versa. itb(int writeFd() const) Returns the pipe's file descriptor that is used for writing. itb(void writtenBy(int filedescriptor)) Sets up redirection from the internal em(write) filedescriptor to the given filedescriptor: information is written to the tt(Pipe) object when writing to the provided filedescriptor. E.g., after the call tt(writtenBy(STDOUT_FILENO)) information sent to the standard output stream (by either tt(cout) or by a child process (cf. bf(exec)(3))) is inserted into the write-end of the pipe. itb(void writtenBy(int const *filedescriptors, size_t n)) Sets up redirection from the internal em(write) filedescriptor to the given filedescriptors: information is inserted into the write-end of the tt(Pipe) object when writing to each of the bf(n) provided filedescriptors. E.g., when passing an array of two tt(int) values, respectively equal to tt(STDOUT_FILENO) and tt(STDERR_FILENO) to this member, all information which is thereafter sent to the standard output or error streams is inserted into the write-end of the pipe. itb(int writeOnly()) Closes the reading end of the pipe, returns the writing end's file descriptor. ) manpagesection(PROTECTED ENUMERATION) The bf(RW) protected enumeration has the following elements: itemization( itb(READ) The index in bf(d_fd[]) (see below) of the element holding the pipe's reading file descriptor; itb(WRITE) The index in bf(d_fd[]) (see below) of the element holding the pipe's writing file descriptor ) manpagesection(PROTECTED MEMBER FUNCTION) itemization( itb(void close(RW rw)) When passing argument RW::READ to this member the reading end of the tt(Pipe) object's pipe is closed. When passing argument RW::WRITE the writing end of the tt(Pipe) object's pipe is closed. ) manpagesection(EXAMPLE) verb( #include #include #include #include #include #include using namespace std; using namespace FBB; int main() { Pipe p; // construct a pipe cout << "Read file descriptor: " << p.readFd() << "\n" "Write file descriptor: " << p.writeFd() << endl; int pid = fork(); if (pid == -1) return 1; if (!pid) //child { p.readFrom(STDIN_FILENO); // read what goes into the pipe string s; getline(cin, s); cout << "CHILD: Got `" << s << "'\n"; getline(cin, s); cout << "CHILD: Got `" << s << "'\n"; return 0; } p.writtenBy(STDOUT_FILENO); // write to the pipe via cout cout << "first line" << "\n" "second line" << '\n'; waitpid(pid, 0, 0); } ) See also the 2nd example at bf(fork)(3bobcat) manpagefiles() em(bobcat/pipe) - defines the class interface manpageseealso() bf(bobcat)(7), bf(fork)(3bobcat), bf(pipe)(2), bf(mkfifo)(3) manpagebugs() Note that when the pipe goes out of scope, no bf(close)(2) operation is performed on the pipe's ends. If the pipe should be closed by the desctructor, derive a class from bf(Pipe)(3bobcat), whose destructor performs the required closing-operation. includefile(include/trailer) bobcat-5.09.01/documentation/man/signal.yo0000644000175000017500000001303114050437223017354 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Signal)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (signal handler) manpagename(FBB::Signal)(Signal Handler) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() Signals have the well known drawback that signals arrive free of context. E.g., assume a program runs a flow control loop like this: verb( void Class::run() { while (d_continue) handleTasks(); cleanup(); } ) then if the program needs to recognize a termination signal then the typical signal handler looks like this: verb( void signalHandler(int signal) { // perform required actions } ) Since the tt(signalHandler) is called asynchronically, there is no context available, and the usual way of communicating between objects and signal handlers is via static variables, like this: verb( // declared as static bool s_continue; bool Class::s_continue = true; void Class::run() { while (s_continue) handleTasks(); cleanup(); } // declared as static void signalHander(int signal); void Class::signalHandler(int signal) { s_continue = false; } ) The class tt(Signal) allows the signal handler to operate in the context of a class. The advantage of this is that static data members are no longer required and that the signal may be used to control data members of individual objects. The signal is now handled by an object, whose class must define a member verb( void signalHandler(size_t signum) override; ) and this function is responsible for handling the received signal. Since it is a member function it may affect its object's local variables and it may call its object's member functions. Static data members are not required anymore (see below for an example). Note that, as the signal may arrive at unpredicable times data members that can be modified by tt(signalHandler) should be declared using the tt(volatile) modifier. Moreover, data that can be modified by the tt(signalHandler) member and by other class members should be protected by em(mutexes) (cf. the bf(C++-11) class tt(std::mutex) or bf(pthread_mutex_lock)(3posix)). includefile(include/namespace) manpagesection(INHERITS FROM) tt(Signal) is not derived from other classes, but the classes for which signals must be handled by tt(Signal) must themselves publicly be derived from the class tt(FBB::SignalHandler) and must implement a member verb( void signalHandler(size_t signum) override; ) handling the received signal. manpagesection(CONSTRUCTORS AND OVERLOADED OPERATORS) tt(Signal) is defined as a em(singleton), and does not offer public or protected constructors, nor does it offer overloaded operators. manpagesection(STATIC MEMBER FUNCTION) itemization( itb(static Signal &instance())nl() This static member can be used to access a reference to the program's single tt(Signal) object. ) manpagesection(MEMBER FUNCTIONS) All of tt(Signal)'s member functions can only be called through a reference to the program's tt(Signal) object, returning a reference to the program's single tt(Signal) object: itemization( itb(void add(size_t signum, SignalHandler &object))nl() tt(SignalHandler object) is activated on arrival of signal tt(signum). If multiple tt(SignalHandler) objects must be called then multiple tt(Signal::add) calls can be provided, and the various tt(SignalHandler::signalHandler) members are called in the same sequence as their respective tt(Signal::add) calls. If one of the earlier tt(signalHandler) members terminates the program then later tt(signalHandler) members are not activated anymore. If tt(Signal::add) is called by, e.g., an object's constructor, then its destructor should call tt(Signal::remove) to prevent the object's signal handler from being called after its destruction. itb(void remove(size_t signum, SignalHandler &object))nl() tt(SignalHandler object) for signal tt(signum) is removed from the tt(Signal) object. It is the responsibility of tt(object) to deregister itself from tt(Signal) just before tt(object) goes out of scope. Objects can only deregister themselves if they've previously registered themselves using tt(add). itb(void ignore(size_t signum))nl() Any previously installed tt(SignalHandler) object is no longer activated on arrival of signal tt(signum). In addition, if possible, signal tt(signum) is completely ignored (some signals cannot be caught, blocked, of ignored, like tt(SIGKILL) and tt(SIGSTOP) (cf. bf(signal)(7))). itb(void reset(size_t signum))nl() Any previously installed tt(SignalHandler) object is no longer activated on arrival of signal tt(signum). In addition, the default action the program takes on arrival of signal tt(signum) is reinstalled (cf. bf(signal)(7)). ) If the tt(signum) value that is passed to tt(Signal)'s members is not a defined signal value, then an bf(FBB::Exception) exception is thrown. manpagesection(EXAMPLE) verbinclude(../../signal/driver/driver.cc) manpagefiles() em(bobcat/signal) - defines the class interface manpageseealso() bf(bobcat)(7), bf(pthread_mutex_lock)(3posix), bf(signal)(7),nl() and the bf(C++-11) class tt(std::mutex). manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/hmacbuf.yo0000644000175000017500000001172714050437223017516 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::HMacBuf)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Compute HMAC Message Digests) manpagename(FBB::HMacBuf) (Computes HMAC Message Digests from information inserted into a std::ostream) manpagesynopsis() bf(#include )nl() Linking option: tt( -lbobcat -lcrypto) manpagedescription() bf(FBB::HMacBuf) objects are bf(std::streambuf) objects that can be used to initialize tt(std::ostream) objects with. All information inserted into such a tt(std::ostream) is used to compute a message HMAC from. All the message digest algorithms defined by the OpenSSL library that can be selected by name may be used in combination with tt(HMacBuf) objects. The following message hmac algorithms are currently supported: mull, md2, md5, sha, sha1, sha224, sha256, sha384, sha512, dss, dss1, ecdsa, mdc2, ripemd160. These very names are the ones to use to select the particular digest algorithm for the class's constructor, below. It is quite possible that future releases of the openssl library will support additional message digest algorithms. The header file tt(openssl/evp.h) lists all available hmac algorithms (in that file look for tt(EVP_MD *EVP_): a message digest algorithm immediately follows the 2nd underscore. E.g., tt(const EVP_MD *EVP_md4(void)) which refers to the md4 message digest algorithm). includefile(include/namespace) manpagesection(INHERITS FROM) bf(std::streambuf) manpagesection(CONSTRUCTORS) itemization( itb(HMacBuf(std::string const &key, char const *type, size_t bufsize = 1024)) This constructor initializes the streambuf, setting it up for the message digest algorithm specified with tt(type). The message hmac algorithms specified in the bf(DESCRIPTION) section may be used here. E.g., to use the sha256 algorithm specify tt("sha256"). The constructor's first argument defines the key to be used when computing the HMAC message digest. The tt(bufsize) argument specifies the internal buffer used by tt(HMacBuf) to store incoming characters temporarily. The provided default argument should be OK in all normal cases. ) Copy and move constructors (and assignment operators) are not available. manpagesection(OVERLOADED OPERATOR) itemization( itb(std::ostream &operator<<(std::ostream &out, HMacBuf const &hmacbuf)) The insertion operator is a free function defined in the namespace tt(FBB). It inserts a hash value as a series of hexadecimally displayed values into the provided tt(ostream). See the example below for an illustration. ) manpagesection(MEMBER FUNCTIONS) All members of bf(std::streambuf) are available, as bf(FBB::HMacBuf) inherits from this class. itemization( itb(void eoi()) This member completes the message digest computation. It is needed as the tt(HMacBuf) object has no external means for deciding whether all information to compute the digest for has yet been received or not. Alternatively, the tt(eoi) manipulator can be inserted into the stream computing the message digest (see below) The general approach for computing a message hmac is therefore: verb( create a HMacBuf object use it to create a std::ostream object insert information into the ostream object call the HMacBuf object's eoi() member or insert eoi into the ostream object obtain/process the hash value from the HMacBuf object. ) itb(std::string const &hash() const) This member returns the hash value computed by the tt(HMacBuf) object. Its value is only defined after having called tt(close()). The hash value is returned in a tt(std::string) object. This string's tt(length()) member contains the number of characters used by the hash value, and its tt(data()) member refers to the hash value's characters. Note that a hash value's character value may be 0 (not to be confused with tt('0')). itb(void reset()) This member reinitializes the message hmac computation. One a message hmac has been computed for, say a stream tt(streamA) this member can be called after which the hmac for a stream tt(streamB) can be computed using the same tt(HMacBuf) object. itb(void eoi()) This member can be called to complete the message digest computation. Instead of calling this member the tt(eoi) manipulator (see below) can be used. ) manpagesection(MANIPULATOR) itemization( itb(FBB::eoi) The tt(eoi) manipulator can be inserted into the tt(ostream) to complete the digest computation. If it is inserted into a plain tt(std::ostream) nothing happens. ) manpagesection(EXAMPLE) verbinclude(../../hmacbuf/driver/driver.cc) manpagefiles() em(bobcat/hmacbuf) - defines the class interface manpageseealso() bf(bobcat)(7), bf(digestbuf)(3bobcat), bf(std::streambuf) manpagebugs() None reported includefile(include/trailer) bobcat-5.09.01/documentation/man/logbuf.yo0000644000175000017500000001414214050437223017361 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::LogBuf)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (log messages stream buffer) manpagename(FBB::LogBuf)( bf(std::streambuf) handling log messages) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() bf(FBB::LogBuf) is a class derived from bf(std::streambuf) handling log messages. The stream to log to, timestamps and log-levels can be configured both at construction time and beyond. The bf(FBB::LogBuf) may be used to initialize a bf(std::ostream). includefile(include/namespace) manpagesection(INHERITS FROM) bf(std::streambuf) manpagesection(ENUMERATIONS) The enumeration bf(TimeStamps) is defined in the namespace bf(FBB) to be used when initializing bf(FBB::LogBuf) objects. It has the following values: itemization( itb(NOTIMESTAMPS) Log-messages will not have timestamps prepended to them. itb(TIMESTAMPS) Log-messages will have timestamps prepended to them. itb(UTCTIMESTAMPS) Log-messages will have timestamps showing the UTC time prepended to them. ) The enumeration tt(Active) is used to distinguish between suspending message insertion when a message's level does not exceed a minimum level and suspending all message insertions (e.g., when suspending inserting messages into bf(FBB::Log) objects after calling their tt(off) member: itemization( itb(OFF) All insertions into the tt(LogBuf) object are suspended; itb(NOT_ACTIVE) Insertions of messages into the tt(LogBuf) object are suspended if their levels are less than the a specified minimum (as set by, e.g., tt(Log::setLevel)). itb(ACTIVE) Messages are inserted ) manpagesection(CONSTRUCTORS) itemization( itb(LogBuf(TimeStamps timestamps = TIMESTAMPS, bool active = true, char const *delim = " ")) This constructor constructs an bf(FBB::LogBuf) object writing its log-messages to bf(std::cerr). If the bf(active) parameter is initialized to bf(false) no messages will be logged until the buffer's activity is switched on (see bf(setActive()) below). The parameter bf(delim) is inserted immediately beyond the time stamp. If a delimiter is inappropriate, an empty string or a 0-pointer may be specified. When bf(stamps == FBB::NOTIMESTAMPS delim) is ignored. A time stamp consists of the month, the day number of the month and the (local) time of the current message, as usually appearing in messages in tt(/var/log) files. E.g., tt(Aug 5 13:52:23); itb(LogBuf(std::ostream &stream, TimeStamps timestamps = TIMESTAMPS, bool active = true, char const *delim = " ")) This constructor constructs an bf(FBB::LogBuf) object writing its log-messages to the stream used to initialize its bf(stream) parameter. If the bf(active) parameter is initialized to bf(false) no messages will be logged until the buffer's activity is switched on (see bf(setActive()) below). The parameter bf(delim) is inserted immediately beyond the time stamp. If a delimiter is inappropriate, an empty string or a 0-pointer may be specified. When bf(stamps == FBB::NOTIMESTAMPS delim) is ignored. A time stamp consists of the month, the day number of the month and the (local) time of the current message, as usually appearing in messages in tt(/var/log) files. E.g., tt(Aug 5 13:52:23). ) Copy and move constructors (and assignment operators) are not available. manpagesection(PUBLIC MEMBER FUNCTIONS) All members of bf(std::streambuf) are available, as bf(FBB::LogBuf) inherits from this class. itemization( itb(bool active() const) Returns tt(true) if log-messages are currently processed; itb(bool empty() const) Returns tt(true) if the object's buffer is currently empty (initially or after a newline character has been inserted); itb(void setStream(std::ostream &stream)) This member may be used to switch the stream to log to. It is the responsibility of the programmer to ensure that the external stream remains available for as long as log-messages are inserted into it; itb(void settimestamp(FBB::TimeStamps timestamps, char const *delim = " ")) The member function (de)activates time stamp prepending. Use the value bf(FBB::TIMESTAMPS) to prepend time stamps, bf(FBB::NOTIMESTAMPS) suppresses time stamps. A time stamp consists of the month, the day number of the month and the (local) time of the current message, as usually appearing in messages in tt(/var/log) files. E.g., tt(Aug 5 13:52:23). The parameter bf(delim) is inserted immediately beyond the time stamp. If a delimiter is inappropriate, an empty string or a 0-pointer may be specified. When bf(stamps == FBB::NOTIMESTAMPS delim) is ignored; itb(void setActive(bool active)) Unless the current object's tt(Active) state is tt(OFF) this member can be used to (de)activate logging. The argument bf(true) activates logging, the argument bf(false) deactivates it. If the current tt(Active) status is tt(OFF) then this member does not change the object's activity status. This member is normally called by bf(FBB::Log::level) members; itb(void setActive(Active active)) The member function (de)activates logging. The argument bf(ACTIVE) activates logging, the argument bf(OFF) completely suppresses logging, the argument tt(NOT_ACTIVE) also suppresses logging, but here tt(setActive(true)) can also be used reactivate logging; itb(void setEmpty(bool empty)) This member may be called to ensure that a timestamp is inserted before the next insertion. It is called as bf(setEmpty(true)) when a newline character (tt(\n)) is inserted, ensuring that another timestamp is prepended before the next insertion. ) manpagesection(EXAMPLE) verbinclude(../../logbuf/driver/driver.cc) manpagefiles() em(bobcat/logbuf) - defines the class interface manpageseealso() bf(bobcat)(7), bf(log)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/ibase64stream.yo0000644000175000017500000000476714050437223020570 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::IBase64Stream)(3bobcat)(_CurYrs_) (libbobcat-dev__CurVers_) (Base64 encoding/decoding std::istream) manpagename(FBB::IBase64Stream) (Std::istream performing base64 encoding and decoding) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() bf(FBB::IBase64Stream) objects may be used to base64 encode or decrypt information that is available on a separate tt(std::istream). The tt(class IBase64Stream) is a class template, using a tt(FBB::CryptType) template non-type parameter. Objects of the class tt(FBB::IBase64Stream) base64 encode the information they receive, objects of the class tt(FBB::IBase64Stream) base64 decode the information they receive. includefile(include/namespace) manpagesection(INHERITS FROM) bf(FBB::IBase64Buf) (private), nl() bf(std::istream) manpagesection(CONSTRUCTORS) itemization( itb(IBase64Stream(std::istream &in, size_t bufSize = 1000)) This constructor initializes a tt(std::istream) providing it with an tt(FBB::IBase64Buf) stream buffer. The tt(IBase64Buf)'s constructor receives all arguments that are passed to this constructor. - tt(IBase64Stream) objects perform base64 encoding;nl() - tt(IBase64Stream) objects perform base64 decoding;nl() - tt(IBase64Stream) objects obtain the bytes to encode or decode from tt(std::istream &in);nl() - The internally used tt(IFilterBuf) is initialized with a buffer of size tt(bufSize), using a lower bound of 100. The constructor uses a configurable buffer size for reading. Characters that were read into the buffer but are not part of the actual base64 encoded data are unavailable after completing the base64 decrypting. If information beyond the base64 input block should remain available, then specify a buffer size of 1. ) Copy and move constructors (and assignment operators) are not available. manpagesection(INHERITED MEMBERS) Since the class uses public derivation from bf(std::istream), all members of this class can be used. manpagesection(EXAMPLE) verbinclude(../../ibase64stream/driver/driver.cc) manpagefiles() em(bobcat/ibase64stream) - defines the class interface manpageseealso() bf(bobcat)(7), bf(ibase64buf)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/readlinestream.yo0000644000175000017500000002666314050437223021115 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::ReadLineStream)(3bobcat)(_CurYrs_) (libbobcat-dev__CurVers_) (Editing input lines) manpagename(FBB::ReadLineStream) (std::istream offering line-editing and history) manpagesynopsis() bf(#include )nl() Linking option: -lreadline -lbobcat manpagedescription() A bf(FBB::ReadLineStream) object is a tt(std::istream) objects, allowing line-editing and history manipulation. The bf(ReadLineStream) class uses Gnu's readline library to allow editing of input lines. The tt(ReadLineStream) object can be used to construct a tt(std::istream) allowing in-line editing of lines read from the terminal. All lines may be preceded by a configurable prompt. Since Gnu's readline library operates on global data there can only be one bf(ReadLineStream) (and underlying bf(ReadLineBuf)) object. bf(ReadLineStream) is a singleton class: in any program there can only be one bf(ReadLineStream) object. bf(ReadLineStream) offers editing capabilities while the user is entering lines. Like Gnu's bf(readline)(3) function, the line editing commands are by default similar to those of bf(emacs)(1), but can easily be reconfigured, e.g. to offer bf(vi)(1)-like characteristics. History manipulation is provided as an option. The collected history may be accessed for reading using an bf(FBB::ReadLineHistory) object. Specific information about the facilities offered by the Gnu software used by bf(ReadLineStream) is provided in the GNU Readline Library documentation (tt(http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html)). Gnu's tt(readline) function reads its information from the standard input file. Programs using tt(ReadLineStream) should normally not extract information from tt(std::cin). However, as the standard input file has a file descriptor (0), redirection should be possible (e.g., using tt(FBB::Redirector)). When the command line is kept, history expansion is offered as an option. History expansion introduces words from the history list into the input stream, making it easy to repeat commands, to insert elements of a previous input line into the current input line, or to fix errors in previous command lines. History expansion is usually performed immediately after a complete line is read. The line selected from the history is called the tt(event), and the portions of that line that are processed are called tt(words). Various modifiers are available to manipulate selected words. This is comparable to the way a program like bf(bash)(1) breaks up its input line into `words'. History expansion is introduced by the use of the history expansion character, by default equal to the tt(!)-character. Only backslash (tt(\)) and single quotes can change the history expansion character into a normal character. The remainder of this section is copied almost verbatim from the bf(history)(3) man-page. The reader is referred to that man-page or to the Gnu History Library documentation for further details. The following bf(event designators) are supported: itemization( itt(!): starts a history substitution, except when followed by a blank, newline, tt(=) or tt(CHAR(40)). itt(!n): refers to command line n. itt(!-n): refers to the current command line minus n. itt(!!) refers to the previous command. This is a synonym for `!-1'. itt(!string) refers to the most recent command starting with string. itt(!?string[?]) refers to the most recent command containing string. The trailing tt(?) may be omitted if string is followed immediately by a newline. itt(^string1^string2^) (quick substitution) repeats the last command, replacing tt(string1) with tt(string2). Equivalent to tt(!!:s/string1/string2/). itt(!#) the entire command line typed so far. ) bf(Word Designators) Word designators are used to select desired words from the event. A tt(:) separates the event specification from the word designator. It may be omitted if the word designator begins with a tt(^, $, *, -), or tt(%). Words are numbered from the beginning of the line, with the first word being denoted by 0 (zero). Words are inserted into the current line separated by single spaces. itemization( itt(0) (zero) The zeroth word. For the shell, this is the command word. itt(n) The nth word. itt(^) The first argument. That is, word 1. itt($) The last argument. itt(%) The word matched by the most recent tt(?string?) search. itt(x-y) A range of words; `-y' abbreviates `0-y'. itt(*) All of the words but the zeroth. This is a synonym for tt(1-$). It is not an error to use * if there is just one word in the event; the empty string is returned in that case. itt(x*) Abbreviates tt(x-$). itt(x-) Abbreviates tt(x-$) like tt(x*), but omits the last word. ) If a word designator is supplied without an event specification, the previous command is used as the event. bf(Modifiers) After the optional word designator, there may appear a sequence of one or more of the following modifiers, each preceded by a tt(:). itemization( itt(h) removes a trailing file name component, leaving only the head. itt(t) removes all leading file name components, leaving the tail. itt(r) removes a trailing suffix of the form tt(.xxx), leaving the basename. itt(e) removes all but the trailing suffix. itt(p) prints the new command but does not execute it. itt(q) quotes the substituted words, escaping further substitutions. itt(x) quotes the substituted words as with q, but break into words at blanks and newlines. itt(s/old/new/) substitutes new for the first occurrence of old in the event line. Any delimiter can be used in place of tt(/). The final delimiter is optional if it is the last character of the event line. The delimiter may be quoted in old and new with a single backslash. If tt(&) appears in new, it is replaced by old. A single backslash will quote the tt(&). If tt(old) is null, it is set to the last old substituted, or, if no previous history substitutions took place, the last string in a tt(!?string[?]) search. itt(&) repeats the previous substitution. itt(g) Causes changes to be applied over the entire event line. This is used in conjunction with tt(:s) (e.g., tt(:gs/old/new/)) or tt(:&). If used with tt(:s), any delimiter can be used in place of tt(/), and the final delimiter is optional if it is the last character of the event line. An a may be used as a synonym for tt(g). itt(G) Apply the following tt(s) modifier once to each word in the event line. ) includefile(include/namespace) manpagesection(INHERITS FROM) tt(FBB::ReadLineBuf) (privately), tt(std::istream) (publicly) manpagesection(ENUMERATIONS) The tt(enum Type) defines the following value: itemization( itt(DONT_EXPAND_HISTORY): history expansion is not requested; itt(EXPAND_HISTORY): history expansion is requested. ) The tt(enum Expansion) provides meaningful return values for the history expansion process. Its values are: itemization( itt(DONT_EXEC): history expansion succeeded, but the expanded line should not be executed. E.g., after entering the line verb( ls * ) the line verb( !!:p ) should cause the using program to em(display), rather than exectute tt(ls *). Note that interpretation of this expansion return value is not the task of the bf(ReadLineBuf) object, but of the program using the bf(ReadLineBuf) object. itt(ERROR): the history expansion failed. See also the member tt(expansionError) below; itt(EXPANDED): the history expansion succeeded; itt(NO_EXPANSION): no history expansion took place. ) manpagesection(CONSTRUCTORS) Preamble: since there can only be one bf(ReadLineBuf) object, any attempt to define a second bf(ReadLineStream) object will fail as there can only be a single bf(ReadLineBuf) object in any program. An attempt to define a second bf(ReadLineBuf) object results in a tt(logic_error) exception being thrown. itemization( itb(ReadLineStream(std::string const &prompt = "", Type type = NO_EXPANSION)) This constructor initializes the tt(ReadLineStream) object with an initial prompt, using a history of at most tt(std::numeric_limits::max()) lines, by default not using history expansion. itb(ReadLineStream(std::string const &prompt, size_t historySize, Type type = NO_EXPANSION)) This constructor initializes the tt(ReadLineStream) with an initial prompt, an initial history of a predefined maximum size, by default not using history expansion. Specifying a history size 0 results in no history being kept, any value equal to or exceeding the predefined constant tt(std::numeric_limits::max()) results in a history of at most tt(std::numeric_limits::max()) lines. If no history is requested but tt(type) is specified as tt(EXPAND_HISTORY) a tt(logic_error) exception is thrown. ) Copy and move constructors (and assignment operators) are not available. manpagesection(MEMBER FUNCTIONS) All members of bf(std::streambuf) are available, as bf(FBB::ReadLineStream) inherits from this class. itemization( itb(ReadLineStream::Expansion expansion() const) The status of the history expansion after retrieving a line from the terminal is returned. Its value is determined after each line retrieved from the terminal. If no history expansion is requested it returns tt(Expansion::ERROR). itb(std::string const &expansionError() const) A short textual description of the nature of the error when tt(expansion) returns tt(Expansion::ERROR) is returned. If no history expansion is requested an empty string is returned. itb(bool setExpansion(Type type)) History expansion can be activated or stopped using this member. When history expansion is requested but the bf(ReadLineStream) object maintains no history the function returns tt(false). Otherwise it returns tt(true). itb(void setPrompt(std::string const &prompt = "")) The prompt that is displayed in front of the next line read from the terminal can be modified by this member. When called without arguments no prompt will be displayed. tt(setPrompt) can be called while input lines are being received. The new prompt will be active after the current line has been read from the terminal. itb(bool useTimestamps(std::string (*timestamp)() = 0)) When initialized with the address of a function returning a tt(std::string) the entered commands will be given a timestamp equal to the text returned by the function pointed to by tt(timestamp). The timestamps can be retrieved using the bf(ReadLineHistory)(3) object. By default or after passing an explicit 0-pointer to tt(useTimestamps) no timestamps are stored. The value tt(false) is returned when no history is kept, otherwise tt(true) is returned. ) manpagesection(EXAMPLE) verbinclude(../../readlinestream/driver/driver.cc) manpagefiles() em(bobcat/readlinebuf) - defines the class interface manpageseealso() bf(bobcat)(7), bf(readline)(3), bf(readlinebuf)(3), bf(readlinehistory)(3) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/binarysearch.yo0000644000175000017500000001013614050437223020554 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::binary_search)(3bobcat)(_CurYrs_) (libbobcat-dev__CurVers_) (Binary search function) manpagename(FBB::binary_search)(Extensions to the STL binary_search function template) manpagesynopsis() bf(#include )nl() manpagedescription() The bf(FBB::binary_search) function templates extend the STL tt(binary_search) function templates by returning an iterator to the found element, instead of a bf(bool) value informing the caller whether or not the searched for element is present in a provided iterator range. The bf(bool) value returned by the STL tt(binary_search) function template is often not the kind of information the caller of the function is interested in. Rather, the caller will often want to use tt(binary_search) in the way tt(find_if) is used: returning an iterator to an element or returning the end-iterator if the element was not found. Whereas tt(find_if) does not require the elements in the iterator range to be sorted, and therefore uses a linear search, tt(binary_search) benefits from the sorted nature of the elements using a binary search algorithm requiring tt(2 log N) iterations to locate the searched for element rather than (on average) tt(N/2) iterations. The tt(FBB::binary_search) algorithm uses this binary searching process while at the same time allowing it to be used like tt(find_if). Since the tt(FBB::binary_search) function templates use the same number and types of parameters as the tt(stl::binary_search) function templates and because they are implemented using the tt(stl::lower_bound) algorithms the tt(FBB) namespace must explicitly be specified when calling tt(binary_search). includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(OVERLOADED FUNCTIONS) In the following description several template type parameters are used. They are: itemization( it() bf(Iterator) represents an iterator type; it() bf(Type) represents a value of the type to which tt(Iterator) points. it() bf(Comparator) represents a comparator function or class type object which was used to sort the elements to which the tt(Iterator) range refer; ) itemization( itb(Iterator binary_search(Iterator begin, Iterator end, Type const &value)) Using a binary search algorithm tt(value) is searched for in the range of elements referred to by the provided iterator range. If the value is found an iterator pointing to this value is returned, otherwise tt(end) is returned. The elements in the range must have been sorted by the tt(Type's operator<) function. itb(Iterator binary_search(Iterator begin, Iterator end, Type const &value, Comparator comparator)) Using a binary search algorithm tt(value) is searched for in the range of elements referred to by the provided iterator range. If the value is found an iterator pointing to this value is returned, otherwise tt(end) is returned. The elements and the provided value are compared using tt(comparator(*iterator, value)) calls, where tt(*iterator) refers to an object in the provided iterator range. The elements in the range must have been sorted by the tt(Comparator) function or function object. The tt(comparator) function is called with two arguments. The first argument refers to an element in the tt(begin..end) range, the second argument refers to tt(value). Usually the types of these arguments are identical, but they may differ. Assuming that tt(Iterator) refers to elements of a type tt(Data), then comparison operators tt(bool operator<(Data const &lhs, Type const &rhs)) and tt(bool operator<(Type const &rhs, Data const &lhs)) must both be available. ) manpagesection(EXAMPLES) verbinclude(../../binarysearch/driver/driver.cc) and an example showing the use of different types: verbinclude(../../binarysearch/driver/driver2.cc) manpagefiles() em(bobcat/binarysearch) - defines the template functions manpageseealso() bf(bobcat)(7) manpagebugs() None reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/csvtable.yo0000644000175000017500000007025014050437223017710 0ustar frankfrankincludefile(include/header) COMMENT(replace 'classname' by the name of the new class) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::CSVTable)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Table Construction) manpagename(FBB::CSVTable)(sequentially fills tables row-wise) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() bf(FBB::CSVTable) is used to fill tables row-wise. By default the table's elements are comma-separated. The elements may contain any type of data that can also be inserted into tt(std::ostreams), as may also contain horizontal lines (optionally spanning multiple columns). Before inserting elements into the table the widths, alignment types and precisions of the table's columns are defined. By default values are right-aligned. While inserting table elements the alignment types and precisions may be altered for specific elements, optionally spanning multiple columns. When inserting values whose representations require more characters than the current widths of the columns receiving those values then those larger widths take precedence over the defined column widths. Different from tables defined by bf(FBB::Table)(3bobcat) all data inserted into bf(CSVTables) do not have to be completely available before the table is inserted into a destination tt(std::ostream). As the table's column formats are known before entering the data the bf(CSVTable) knows which format to use for which column. These column format specifications may be defined in multiple ways, e.g., by using text labels and values. bf(CSVTable) objects always use the widest column specifications and alignment types that were specified last. When inserting elements into bf(CSVTables) the standard bf(C++) IO manipulators can also be used. Table rows do not automatically end after the table's last column has been filled. But when inserting elements beyond the last column they are inserted as-is (but then the standard I/O format specifications can optionally be used). Table column definitions and table rows end at the end of insertion statements (see below at the descriptions of the various tt(operator<<) functions). bf(CSVTable) uses two support classes handling, respectively, the definitions of the characteristics of the table's columns and inserting values into the table's elements. bf(CSVTabDef) handles the table's column definitions, bf(CSVTabIns) handles insertions into the table elements. Their main characteristics are various insertion operators which are described below. Constructing tables normally consists of two steps: first the characteristics of the columns are defined, then values are inserted into the table's elements. This sequence is not enforced by bf(CSVTable): after inserting values into the table column definitions may be updated, whereafter additional values may be inserted into the table which then use the updated column definitions. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(FMT) bf(FMT) objects are returned by several free functions (like bf(left), described below in section bf(FREE FUNCTIONS)), and bf(FMT) defines the enumeration tt(Align) (see the next section) specifying alignment types. bf(FMT) objects are internally used by bf(CSVTable) objects. A bf(FMT) object specifies the width, the precision when floating point numbers are inserted, the column's alignment type (left, right or centered), and the number of table columns to use. bf(FMT) objects can be inserted into tt(std::ostream) objects showing its characteristics. In addition it offers the following (const) accessors: itemization( itb(FMT::Align align()) the alignment value; itb(unsigned nCols()) the number of occupied columns; itb(unsigned precision()) the precision used when inserting a floating point value (tt(~0U) (= -1 as tt(int)) is returned if tt(precision) is not used). The insertion operator shows tt(precision: -1) when precision is tt(~0U); itb(unsigned width()) the width in number of characters; ) The static member bf(char const *FMT::align(FMT::Align value)) returns the textual label corresponding to tt(value). manpagesection(ALIGN ENUM) The tt(enum FMT::Align) defines the following values indicating the alignment types of the columns of the table: itemization( itb(FMT::Align::CENTER) The information inserted in the column is centered; itb(FMT::Align::LEFT) The information inserted in the column is left-aligned; itb(FMT::Align::RIGHT) The information inserted in the column is right-aligned (this is the alignment used by default); ) In addition, when inserting horizontal lines, the value bf(FMT::Align::HLINE) is used. manpagesection(CONSTRUCTORS) itemization( itb(CSVTable(std::ostream &out = std::cout, std::string const &sep = ", ")) This constructor by default writes its table to tt(std::cout) and uses a comma followed by a space character as column separator. During the table's construction the stream to write the table to can be altered using the tt(stream) members, and the separator can be changed using the tt(sep) member, but the separator can also be changed while filling the table's elements (see below). When the bf(CSVTable) object goes out of scope the stream's original configuration is restored; itb(CSVTable(std::ofstream &&tmp, std::string const &sep = ", ")) This constructor by default uses the same separator to separate the column's elements as the first constructor, but writes the table to the tt(ofstream tmp), which is grabbed by tt(CSVTable); itb(CSVTable(std::string const &fname, std::string const &sep = ", "), std::ios::openmode mode = ios::out) This constructor by default uses the same separator to separate the column's elements as the first constructor, but writes the table to the file having (path)name tt(fname), by default (re)writing the file. If the file already exists and tt(CSVTable) should start writing at the file's end use, e.g., tt(ios::ate | ios::in). An exception is thrown if the specified file cannot be opened. ) The move constructor and assignment operator are available; the copy constructor and assignment operator are not available. manpagesection(OVERLOADED OPERATORS) In the provided examples tt(tab) refers to an existing bf(CSVTable) object. Each insertion statement (note: not insertion em(expression)) either defines or updates the table columns' definitions or fills the next row of the table with data. bf(Defining column characteristics) The return types and left-hand side operands of the following insertion operators are specified as bf(CSVTabDef). The member bf(fmt()) (cf. section bf(MEMBER FUNCTIONS)) returns a bf(CSVTabDef) object which is then used in combination with the following insertion operators to define the characteristics of the table's columns. itemization( itb(CSVTabDef &operator<<(CSVTabDef &tab, FMT const &fmt)) This insertion operator defines the characteristics of the next table column. bf(FMT) objects inserted into bf(CSVTabDef) objects must have been returned by bf(center, left) or bf(right) (see section bf(FREE FUNCTIONS), below), or an exception will be thrown. When redefining column specifications (e.g., when inserting bf(FMT) objects for previously defined columns) then the width of the wider column is used. Example: verb( // left align using 10 char. positions: tab.fmt() << FBB::left(10); // 1st col now right aligned, but its // width remains 10 tab.fmr() << FBB::right(4); ) COMMENT( itb(CSVTabDef &operator<<(CSVTabDef &tab, Insertable const &value)) This operator is defined for the template type tt(Insertable) parameter tt(value), where tt(value's) type must be insertable in tt(std::ostreams). The (trimmed) width of tt(value) when inserted into an tt(ostream) defines the width of the next column, which is right-aligned. As width the previous insertion operator: if a previous definition specified a larger width, then that width is kept. Example: verb( // 2 columns, having widths 2 and 5: tab.fmt() << 12 << "hello"; ) END) itb(CSVTabDef &operator<<(CSVTabDef &tab, Type const &value)) This operator is defined for the template type tt(Type) parameter tt(value), where tt(Type) values must be insertable in tt(std::ostreams). The (trimmed) width of tt(value) when inserted into an tt(ostream) defines the width of the next column, which is right-aligned. As width the previous insertion operator: if a previous definition specified a larger width, then that width is kept. Example: verb( // 2 columns, having widths 2 and 5: tab.fmt() << 12 << "hello"; ) ) bf(Inserting the table's elements) In addition to the insertion operator actually inserting a value into the next table's column(s) several format modifying insertion operators are available. When a series of specifications are inserted before the actual value is inserted then the specification inserted just before inserting the table's value is used, overruling that column's default specification. Format specifications other than those provided by the standard I/O manipulators are ignored when used beyond the table's last column. The return types and left-hand side operands of the following insertion operators use bf(CSVTabIns) objects. bf(CSVTable's) conversion operator tt(operator CSVTabIns()) described below returns a bf(CSVTabIns) object which is used by the following insertion operators to insert values into the table. itemization( itb(CSVTabIns &operator<<(CSVTabIns &tab, FMT::hline)) This operator inserts a horizontal line in the table's next column element. It is ignored when used beyond the table's last column; itb(CSVTabIns &operator<<(CSVTabIns &tab, (*FMT::hline)(unsigned nColumns))) This operator inserts a horizontal line spanning the next tt(nColumns) columns of the table. If the argument tt(nColumns) is omitted then a horizontal line is inserted spanning all of the table's remaining columns. When covering multiple columns no separators are used between the columns containing horizontal lines but one continuous horizontal line is used instead. The horizontal line is never written beyond the table's last column. COMMENT( itb(CSVTabIns &operator<<(CSVTabIns &tab, Insertable const &value)) This operator is defined for the template type tt(Insertable) parameter tt(value), where tt(value's) type must be insertable in tt(std::ostreams). The value is inserted into the next table column, using the format specification that's active for that column. However, the specifications may be altered just before inserting the value. Values inserted beyond the table's last column are inserted as-is (although standard tt(I/O) manipulators can still be used); END) itb(CSVTabIns &operator<<(CSVTabIns &tab, Type const &value)) This operator is defined for the template type tt(Type) parameter tt(value), where tt(Type) values must be insertable in tt(std::ostreams). The value is inserted into the next table column, using the format specification that's active for that column. However, the specifications may be altered just before inserting the value. Values inserted beyond the table's last column are inserted as-is (although standard tt(I/O) manipulators can still be used); itb(CSVTabIns &operator<<(CSVTabIns &tab, FMT const &fmt)) bf(FMT) objects are returned by several free functions defined in the tt(FBB) namespace (i.e., bf(center, left,) or bf(right), described below in section bf(FREE FUNCTIONS)). Example: verb( // left align using precision 2. E.g., // e.g., '12.13 ' tab << left(2) << 12.1278; ) itb(CSVTabIns &operator<<(CSVTabIns &tab, FMT::Align align)) The alignment argument can be tt(FMT::CENTER, FMT::LEFT) or tt(FMT::RIGHT). Example: verb( // centers '12' in its column, // e.g., ' 12 ' tab << FMT::CENTER << 12; ) itb(void operator<<(CSVTabIns &tab, std::ios_base &(*func)(std::ios_base &))) This insertion operator accepts manipulators like tt(std::left) and tt(std::right). When inserting these manipulators the next value to insert into the table is manipulated accordingly, overruling the next column's default specification. Example: verb( // 'hi' is left-aligned, using the // using the default width and precision tab << std::left << "hi"; ) itb(CSVTabIns &operator<<(CSVTabIns &tab, Sep const &sep)) The separator used when starting to insert values into the table's next row is changed to the separator specified by tt(sep). It remains active for the table's current row, also when inserting values beyond the table's last column. Example: verb( // writes, e.g., 'one, hi there' tab << "one" << FMT::Sep{" "} << "hi" << "there"; ) itb(operator CSVTabIns()) The conversion operator returns a bf(CSVTabIns) object which is used in combination with the above insertion operators to insert values into the next row of the table. Normally insertions start at column 1, but when called after calling tt(tab.more) (see below) then insertions continue after the last element that was inserted into bf(tab.more). Each time this conversion operator is used another row is added to the table. Insertions beyond the table's last column are processed, but bf(CSVTabIns's) insertion operators are ignored, inserting values as-is. However, in that case the standard tt(std::ostream) manipulators can also be used. itb(void operator()(std::string const &text)) Calls bf(row(text, 0)) to insert the trimmed comma-separated elements of tt(text) into the table's next row; itb(FMT const &operator[](unsigned idx) const) Returns the default bf(FMT) specification of column tt(idx) (see also the description of the member bf(size()) below). ) manpagesection(MEMBER FUNCTIONS) In the provided examples tt(tab) refers to an existing bf(CSVTable) object. itemization( itb(std::vector const &columns() const) Returns a reference to the vector containing the format specifications of the table managed by bf(CSVTable); itb(CSVTabDef &fmt(unsigned idx = 0)) The elements inserted into the bf(CSVTabDef) object returned by bf(fmt()) define the specifications of the table's columns. Specifications start at column offset tt(idx), using 0 if not specified (its argument may not exceed the number of already defined columns or an exception is thrown). When called repeatedly for already specified columns then the widths of existing columns are kept if they exceed the widths of the corresponding inserted bf(FMT) elements. Repeated bf(fmt) calls may specify more columns than previous calls, in which case new columns are added to the table. itb(void fmt(std::string const &colSpecs, unsigned idx = 0)) The comma-separated space-trimmed words of tt(colSpecs) define the widths of right-aligned table columns, starting at column index tt(idx), using 0 if not specified (its argument may not exceed the number of already defined columns or an exception is thrown). When called repeatedly for already specified columns then the widths of existing columns are kept if they exceed the lengths of the corresponding trimmed words. Repeated calls may specify more columns than previous calls, in which case additional columns are added to the table. Example: verb( // Define three right-aligned columns, // having widths of 3, 3 and 5. tab.fmt("one, two, three"); // add columns 4 thru 6 tab.fmt("one, two, three", 3); ) itb(unsigned idx() const) The index of the column that will be used at the next insertion is returned. When inserting more values than the number of defined table columns then the return value of the member tt(size) is returned; itb(CSVTabIns more(unsigned idx = ~0U)) When the default tt(idx) argument is used then values that are inserted into the returned bf(CSVTabIns) object are inserted beyond the last-used column of the table's current row (which may be the row's first element). When using another argument then insertions start in column tt(idx). If tt(dx) exceeds the last-used column index then intermediate columns remain empty. If tt(idx) is less than the column index that is used at the next insertion an exception is thrown. Insertions beyond the table's last column are processed, but then bf(CSVTabIns's) insertion operators are ignored, inserting values as-is. However, in that case the standard tt(std::ostream) manipulators can also be used; Following tt(more) the current row doesn't end, but values inserted next are inserted into the same row. Example: verb( // a row containing one element: tab << 1; // the next row contains 2 elements: tab.more() << 1 << 2; // now containing 4 elements // (element at idx 2 remains empty): tab.more(3) << 4; // completes the row, now having // 5 elements: tab << 5; ) Following tt(more) calls the current row ends at the next tt(tab.row) call. If following tt(more) calls the current row should merely end then simply use tt(tab.row+nop()()); itb(void more(std::string const &text, unsigned idx = ~0U)) This member's tt(idx) parameter is handled as described at the previous member. The trimmed comma-separated elements of tt(text) are inserted into the current row, without ending the current row; itb(CSVTabIns row+nop()(unsigned idx = ~0U)) This member's tt(idx) parameter and insertions into the returned bf(CSVTabIns) object are handled as described at the first tt(more) member, but the current row ends at the end of the statement. Example: verb( // a row containing one element: tab << 1; // the next row contains 2 elements: tab.more() << 1 << 2; // the now contains 4 elements // (element at idx 2 remains empty): tab.row(3) << 4; ) itb(void row+nop()(std::string const &text, unsigned idx = ~0U)) This member's tt(idx) parameter is handled as described at the first tt(more) member. The trimmed comma-separated elements of tt(text) are inserted into the current row, whereafter the row ends; itb(void stream(std::ostream &out)) After calling tt(tab.stream(out)) the table's construction continues at the next row using the stream tt(out); itb(void stream(std::ofstream &&tmp)) After calling this member the table's construction continues at the next row using the tt(ofstream tmp), whih is grabbed by tt(CSVTable); itb(void stream(std::string const &fname, std::ios::openmode mode = std::ios::out)) After calling this member the table's construction continues at the next row using the (path)name tt(fname), by default (re)writing the file. If the file already exists and tt(CSVTable) should start writing at the file's end use, e.g., tt(ios::ate | ios::in). An exception is thrown if the specified file cannot be opened; itb(std::ostream &stream()) A reference to the currently used stream is returned; itb(std::string const &sep() const) Returns the currently used default column separator; itb(void sep(std::string const &separator)) Changes the currently used default column separator to tt(separator). itb(unsigned size() const) The number of defined columns is returned; ) manpagesection(FREE FUNCTIONS) In the following examples tt(tab.fmt()) refers to a bf(CSVTabDef) object. next examples tt(tab) refers to a bf(CSVTable) object (using its conversion to a bf(CSVTabIns) object) and bf(Defining Column Characteristics) The following functions are used to specify the alignment, width and optional precision of columns. The first argument of these functions specifies the column's width, the second argument is optional and specifies the column's precision (used when inserting floating point values). The precision is only used if its value is less than the column's width. itemization( itb(FMT center+nop()(unsigned width, unsigned precision = ~0U)) When inserting this function's return value into tt(tab.fmt()) the values inserted into its column are centered in fields of tt(width) characters wide. Example: verb( // values are centered in fields of 10 // characters wide, floating point values // use 3 digit behind the decimal point: tab.fmt() << center(10, 3); ) itb(FMT center+nop()(std::string const &str, unsigned precision = ~0U)) A convenience function calling tt(center(str.length(), precision)); itb(FMT left(unsigned width, unsigned precision = ~0U)) When inserting this function's return value into tt(tab.fmt()) the values inserted into its column are left-aligned in fields of tt(width) characters wide. Example: verb( // values are left-aligned in fields // of 5 characters wide. tab.fmt() << left(5); ) itb(FMT left(std::string const &str, unsigned precision = ~0U)) A convenience function calling tt(left(str.length(), precision)); itb(FMT right(unsigned width, unsigned precision = ~0U)) When inserting this function's return value into tt(tab.fmt()) the values inserted into its column are right-aligned in fields of tt(width) characters wide. Example: verb( // values are right-aligned in fields // of 5 characters wide. tab.fmt() << right(5); ) Right-alignment is also used when using bf(CSVTab's fmt(std::string)) member or when directly inserting values into bf(CSVTabDef) objects. itb(FMT right(std::string const &str, unsigned precision = ~0U)) A convenience function calling tt(right(str.length(), precision)); ) bf(Inserting Table Elements) In the following examples tt(tab) refers to a bf(CSVTable) object returning a bf(CSVTabIns) object using its conversion operator. Except for the function tt(hline) the following functions are used to alter the column's default alignment and precision. The precision is only used if its value is less than the column's width. By specifying tt(~0U) the precision is ignored. If only the default alignment should be overruled then inserting the corresponding tt(FMT::Align) value suffices. Altering the default alignment of individual columns: itemization( itb(FMT center(precision)) After inserting this function's return value into tt(tab) the value inserted next is centered, using tt(precision) when inserting floating point values. verb( // centers 9.87 in column 1 tab << center(2) << 9.876"; ) itb(FMT left(precision)) After inserting this function's return value into tt(tab) the value inserted next is left-aligned, using tt(precision) when inserting floating point values. verb( // left-aligns 9.87 in column 1 tab << left(2) << 9.876"; ) itb(FMT right(precision)) When inserting this function's return value into tt(tab) the value inserted next is right-aligned, using tt(precision) when inserting floating point values. verb( // right-aligns 9.87 in column 1 tab << right(2) << 9.876"; ) By default bf(CSVTable) uses right-alignment. ) Joining columns: Alignments specifications may span multiple columns. This is realized through the tt(join) functions. When inserting a value after inserting the return value of a tt(join) member then that value is inserted occupying all the columns and using the alignment type specified when calling tt(join). If necessary the number of columns is reduced to avoid exceeding the table's last column. itemization( itb(FMT join(unsigned nCols, FMT::Align align, unsigned precision = ~0U)) A value that's inserted into the table after inserting tt(join's) return value occupies tt(nCols) columns, using alignment type tt(align), and optionally using tt(precision) when inserting floating point values. The alignment specification must be tt(FMT::CENTER, FMT::LEFT) or tt(FMT::RIGHT). Example: verb( // writes (assuming columns 2 and 3 occupy // 10 characters): // left, mid , right tab << "left" << join(2, FMT::CENTER) << "mid" << "right""; ) itb(FMT join(FMT::Align align, unsigned precision = ~0U)) Same effect as the previous tt(join) function, but this function occupies all remaining columns of the table's current row (this can also be accomplished by calling the first tt(join) function specifying tt(~0U) as its first argument). ) Inserting horizontal lines: If a single table element should contain a horizontal line then simply inserting tt(Align::HLINE) works fine. The tt(hline) functions are used to insert horizontal lines spanning one or more table columns. itemization( itb(FMT hline(unsigned nCols = ~0U)) When inserting this function's return value into a bf(CSVTabIns) object a horizontal line spanning tt(nCols) columns is inserted into the table. If necessary tt(nCols) is reduced so that the horizontal line does not exceed the table's last column. When spanning multiple columns no column separated are used between the spanned columns: a single uninterrupted horizontal line is inserted. Example: verb( // columns 1 and 2: a horizontal line, column 3: // contains 'hi' (preceded by the column separator) tab << hline(2) << "hi"; ) ) manpagesection(EXAMPLE) verb( #include using namespace FBB; int main() { CSVTable tab; tab.fmt() << "case" << right("length", 2) << right("weight", 1) << right("length", 2) << right("weight", 1); tab.sep(" "); tab << hline(); tab << "" << join(4, FMT::CENTER) << "Gender"; tab << "" << hline(); tab << "" << join(2, FMT::CENTER) << "Female" << join(2, FMT::CENTER) << "Male"; tab << "" << hline(2) << hline(2); tab << "Case" << "Length" << "Weight" << "Length" << "Weight"; tab << hline(); tab << 1 << 1.744 << 55.345 << 1.7244 << 64.801; tab << 2 << 1.58 << 57.545 << 1.8174 << 81.451; tab << 3 << 1.674 << 62.125 << 1.8244 << 80.201; tab << hline(); } ) This program writes the following table to tt(std::cout): verb( ------------------------------------ Gender ------------------------------ Female Male -------------- -------------- Case Length Weight Length Weight ------------------------------------ 1 1.74 55.3 1.72 64.8 2 1.58 57.5 1.82 81.5 3 1.67 62.1 1.82 80.2 ------------------------------------ ) manpagefiles() em(bobcat/csvtable) - defines the class interface manpageseealso() bf(bobcat)(7), bf(table)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/milter.yo0000644000175000017500000006471014050437223017405 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Milter)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Milter interface) manpagename(FBB::Milter)(Interface to the sendmail mail filter facilities) manpagesynopsis() bf(#include )nl() Linking option: tt(-lmilter -lbobcat) manpagedescription() bf(Milter) defines an abtract base class interfacing to the sendmail mail filter (milter) facilities. It defines a bf(C++) interface, based on the assumption that a single mail filter program does not implement multiple mail filters. The traditional sendmail bf(C)-based Milter API uses a (tt(SMFICTX)) pointer representing a mail connection, and a pointer to connection-specific `private' data, requiring the Milter constructor to perform quite a few administrative tasks. While acceptable in a bf(C) environment these administratve tasks distract from the main task: the Milter's mail filtering functionality. The bf(FBB::Milter) class hides these administrative tasks from the programmer, who is then able to concentrate on filtering mail. The main benefits of bf(Milter) are therefore itemization( it() Basic administration is performed by the bf(Milter) class it() The class' interface is more bf(C++) like than the raw bf(C) interface offered by the milter API. it() Administration, allocation and communicating of connection specific data is no longer required it() It is not normally necessary to use connection-specific data, like a pointer identifying the connection, anymore when implementing the Milter. it() bf(Milter) uses current-day design patterns enforcing principles of reuable software, thus simplifying the construction of the actual Milter. ) To activate a milter from the tt(sendmail.mc) configuration file, use, e.g., tt(INPUT_MAIL_FILTER(`name', `S=socket')), where tt(name) is the milter's name, and tt(socket) is the name of the socket. See also the tt(setConnection) member below. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(ENUMERATIONS) The class defines four enumerations. One enumeration is used to indicate the callback-functions that need to be called, the second one renames the flags that can be passed to sendmail to indicate which actions the milter is allowed to perform. The third one defines status values that may be used to inform sendmail how to further process a message. The fourth one defines return values. The enumerations are: bf(enum CallBack)nl() This enumeration holds the following values: itemization( itb(CONNECT) Indicates that the milter defines (overrides) the connection-functionality. This is the first callback function that can be called by sendmail. itb(HELO) Indicates that the milter defines (overrides) the helo-functionality. This indicates that the tt(helo) function should be called by sendmail, providing the milter with information about the connecting client. itb(SENDER) Indicates that the milter defines (overrides) the sender-functionality. This indicates that the tt(sender) function should be called by sendmail, providing the milter with the sender's envelope information. itb(RECIPIENT) Indicates that the milter defines (overrides) the recipient-functionality. This indicates that the tt(recipient) function should be called by sendmail, providing the milter with the recipient's envelope information. itb(HEADER) Indicates that the milter defines (overrides) the header-functionality. This indicates that the tt(header) function should be called by sendmail for each mail header that is used in the current mail message. itb(EOH) Indicates that the milter defines (overrides) the end-of-header-functionality. This indicates that the tt(eoh) function should be called by sendmail once all header lines have been processed. itb(BODY) Indicates that the milter defines (overrides) the body-functionality. This indicates that the tt(body) function should be called by sendmail, offering the mail-body to the milter. itb(EOM) Indicates that the milter defines (overrides) the end-of-message-functionality. This indicates that the tt(eom) function should be called by sendmail, once all elements of the e-mail message have been processed. itb(ABORT) Indicates that the milter defines (overrides) the abort-functionality. The tt(abort) function may be called by sendmail before tt(eom) is called. It should reclaim all resources used by the message, but not delete any memory allocated by the milter, as this is tt(close)'s job. itb(CLOSE) Indicates that the milter defines (overrides) the close-functionality. The tt(close) function should delete all (connection specific) memory allocated by the milter. It may be called `out-of-order', i.e. even before tt(connect) is called and developers should anticipate this possibility when crafting their tt(close) code. In particular, it is incorrect to assume the private context pointer will be something other than 0 in this callback. itb(UNKNOWN) Currently not used. Reserved for versions exceeding version 2 of the sendmail milter API itb(DATA) Currently not used. Reserved for versions exceeding version 3 of the sendmail milter API itb(ALL_CALLBACKS) Shortcut to indicate all callback facilities. The tt(CallBack) values are bit-flags. The tt(bit_or) operator may be used to combine them, and the tt(bit_not) operator may be used to remove a flag from tt(ALL_CALLBACKS) (e.g., tt(ALL_CALLBACKS && ~ABORT)). ) bf(enum Flags)nl() This enumeration holds the following values: itemization( itb(NO_FLAGS) No flags are defined. itb(ADD_HEADERS) This flag indicates that the milter is allowed to add headers to the current e-mail message. itb(ADD_RECIPIENTS) This flag indicates that the milter is allowed to add recipients to the current e-mail message. itb(CHANGE_BODY) This flag indicates that the milter is allowed to modify the message's body content. itb(CHANGE_HEADERS) This flag indicates that the milter is allowed to change headers of the current e-mail message. itb(DELETE_RECIPIENTS) This flag indicates that the milter is allowed to remove recipients from the current e-mail message. itb(QUARANTINE) This flag indicates that the milter is allowed to request sendmail to quarantine the current e-mail message. itb(ALL_FLAGS) Shortcut to indicate all callback facilities. The tt(Flags) values are bit-flags. The tt(bit_or) operator may be used to combine them, and the tt(bit_not) operator may be used to remove a flag from tt(ALL_FLAGS) (e.g., tt(ALL_FLAGS && ~QUARANTINE)). ) bf(Status)nl() This enumeration simplifies the extended tt(SMFIS_) values used by the bf(C) API. These values may be used to return tt(sfsistat) values: itemization( itb(ACCEPT) This value is equal to tt(SMFIS_ACCEPT), indicating that Sendmail should accept the message. For a connection-oriented callback (see below at bf(PROTECTED VIRTUAL MEMBER FUNCTIONS)), accept this connection without further filter processing, call tt(close) (see below). For other callbacks: accept this message without further filtering. itb(CONTINUE) This value is equal to tt(SMFIS_CONTINUE), indicating that Sendmail should continue processing. This is the default for all callback functions which are not overridden by the class derived from bf(Milter). itb(DISCARD) This value is equal to tt(SMFIS_DISCARD), indicating that Sendmail should discard the mail message. It should not be returned by a connection-oriented callback. For other callbacks: the message is accepted, but silently discarded. itb(REJECT) This value is equal to tt(SMFIS_REJECT), indicating that Sendmail should reject the mail message. For a connection-oriented callback, reject this connection; call tt(close). For a message-oriented callback (except for tt(eom) or tt(abort, see below)), reject this message. For a recipient-oriented callback, reject the current recipient (but continue processing the current message). itb(TEMPFAIL) This value is equal to tt(SMFIS_TEMPFAIL), indicating that Sendmail should return a `temporary unavailable' message to the sender of the mail message. For a message-oriented callback (except tt(sender), see below), fail for this message. For a connection-oriented callback, fail for this connection and call tt(close). For a recipient-oriented callback, only fail for the current recipient and continue message processing. ) bf(Return)nl() This enumeration simplifies the extended tt(MI_) values used by the bf(C) API. Most return values used by the bf(Milter) class, however, are tt(bool) values. The tt(Return) values are: itemization( itb(FAILURE) This value is equal to tt(MI_FAILURE), indicating that a bf(C)-api function failed to perform its task. itb(SUCCESS) This value is equal to tt(MI_SUCCESS), indicating that a bf(C)-api function succeeded in performing its task. ) manpagesection(CONSTRUCTOR/DESTRUCTOR) itemization( itb(Milter()) The default constructor is available for derived classes. It performs no actions. itb(virtual ~Milter()) The (public) virtual destructor performs no actions: derived classes can override the destructor to suit their own needs. ) Overloaded assignment operators are not available. manpagesection(PUBLIC STATIC MEMBER FUNCTIONS) These functions form the heart of the bf(Milter) base-class. They can be called to initialize, start and stop the Milter. itemization( itb(void initialize(std::string const &name, Milter &milter, callback_set callbacks = CONNECT, flag_set flags = NO_FLAGS)) This function initializes the Milter's administration. It expects the name of the mailfilter as its first argument. Its second argument is a reference to a tt(Milter) object. Since bf(Milter) is an abstract base class the actual object is always an object of a class derived from bf(Milter). Its third argument specifies the callbacks to call for this milter. By default the tt(connect) callback will be called. Note that the tt(close) callback is not called by default. This is ok, since the bf(Milter) object doesn't have to cleanup `private' data, as is normal with the bf(C) API. The last argument defines flags, specifying the Milter's capabilities. itb(std::string const &name()) This function returns the milter's name. itb(bool start()) This member function calls tt(smfi_main), controlling the milter's event loop. It returns tt(true) if the event-loop is successfully terminated. itb(void stop()) This member function terminates the milter's event loop, after finishing all threads. Following this call tt(start) may be called again to continue the milter. ) manpagesection(PROTECTED VIRTUAL MEMBER FUNCTIONS) The remaining functionality of the class tt(Milter) is useful only for Milter-implementations in classes derived from bf(Milter). The following members can be overridden by derived classes. Note that tt(clone) em(must) be overridden. Except for tt(clone), all the members in this sections are em(callback) functions. I.e., the MTA will call them to process parts of the mail message. Recipient-, message-, and connection-oriented callbacks are distinguished. The recipient-oriented callback (tt(recipient), see below) may affect the processing of a single message to a single recipient. Connection-oriented callbacks (tt(connect, helo) and tt(close)) affect the processing of the entire connection (during which multiple messages may be delivered to multiple sets of recipients). The remaining callbacks are message-oriented, affecting the processing of a single message to all its recipients. itemization( itb(virtual sfsistat abort()) This message-oriented member may be called at any time during message processing (i.e. between some message-oriented routine and tt(eom)). tt(abort) reclaim any resources allocated on a per-message basis (which are em(not) the connection specific data, which should be handled by the derived class' destructor), and must be tolerant of being called between any two message-oriented callbacks. tt(abort) is only called if the message is aborted outside the filter's control and the filter has not completed its message-oriented processing. For example, if a filter has already returned tt(ACCEPT, REJECT), or tt(DISCARD) from a message-oriented routine, tt(abort) will not be called even if the message is later aborted outside its control. itb(virtual sfsistat body(unsigned char *text, size_t length)) This message-oriented member is called zero or more times between tt(eoh) and tt(eom). tt(text) points to a sequence of bytes. It is not necessarily a 0-terminated. Moreover, the sequence may contain 0-characters. Since message bodies can be very large, defining tt(body) can significantly impact filter performance. End-of-lines are represented as received from SMTP (normally CR/LF). Later filters will see body changes made by earlier ones, and message bodies may be sent in multiple chunks, with one call to tt(body) per chunk. itb(virtual Milter *clone() const = 0) This pure virtual function must be implemented by derived classes to return a newly allocated copy of the derived object passed to the tt(initialize) static member. It is used by the standard `virtual constructor' design pattern. The destruction of the allocated object is the responsibility of tt(clone)'s caller. itb(virtual sfsistat close()) This connection-oriented member is always called once at the end of each connection. It may be called "out-of-order", i.e. before even the tt(connect) is called. After a connection is established by the MTA to the filter, if the MTA decides this connection's traffic will be discarded (e.g. via an access_db result), no data will be passed to the filter from the MTA until the client closes down. At that time, tt(close) is called. It can therefore be the only callback ever used for a given connection, and developers should anticipate this possibility when crafting their tt(close) code. The member tt(close) is called on close even if the previous mail transaction was aborted. itb(virtual sfsistat connect(char *hostname, _SOCK_ADDR *hostaddr)) This connection-oriented member may be called once, at the start of each SMTP connection. The parameter tt(hostname) is he host name of the message sender, as determined by a reverse lookup on the host address. If the reverse lookup fails, hostname will contain the message sender's IP address enclosed in square brackets (e.g. tt([a.b.c.d])). The parameter tt(hostaddr) is the host address, as determined by a bf(getpeername)(2) call on the SMTP socket. It is 0 if the type is not supported in the current version or if the SMTP connection is made via stdin. itb(virtual sfsistat data()) Not yet supported. Will be available with libmilter versions beyond 3. itb(virtual sfsistat eoh()) This message-oriented member is called once after all headers have been processed. itb(virtual sfsistat eom()) This message-oriented member is called once after all calls to tt(body) for a given message have been completed. Note that only in this function modifications to the message headers, body, and envelope can be made (see the tt(add-, change-) and tt(delete-) members listed below). itb(virtual sfsistat header(char *headerf, char *headerv)) This message-oriented member is called zero or more times between tt(recipient) and tt(eoh), once per message header. The tt(headerf) parameter contains the text of the header, the tt(headerv) parameter contains its value. E.g., if an e-mail message contains the following headers: verb( From: sender Subject:no ) then tt(header) will be called twice with the following values for, respectively tt(headerf) and tt(headerv): verb( First header: "From", " sender " Second header: "Subject", "no" ) Further details about header information is given in RFC 882. itb(virtual sfsistat helo(char *helohost)) This connection-oriented member is called whenever the client sends a HELO/EHLO command. It may therefore be called between zero and three times. The tt(helohost) parameter should be the domain name of the sending host (but is, in practice, anything the sending host wants to send). itb(virtual sfsistat recipient(char **argv)) This recipient-oriented member is called once per recipient, hence one or more times per message, immediately after tt(sender). The parameter tt(argv) is a 0-terminated array of pointers to SMTP command arguments; argv[0] is guaranteed to be the recipient address. Later arguments are the ESMTP arguments. TEMPFAIL may be returned indicate that sendmail should return a temporary failure for this particular recipient; further recipients may still be sent, tt(abort) is not called. REJECT will reject this particular recipient; further recipients may still be sent, tt(abort) is not called. DISCARD will accept (but discard) the message, tt(abort) will be called. ACCEPT will accept recipient, tt(abort) will not be called. More details on ESTMP responses, are described in RFC 1869. itb(virtual sfsistat sender(char **argv)) This message-oriented member is called once at the beginning of each message, before tt(recipient). argv[0] is guaranteed to be the sender's envelope address. Later arguments are the ESMTP arguments. TEMPFAIL may be returned, indicating that sendmail should return a temporary failure for this particular message, tt(abort) is not called. REJECT will reject this message, tt(abort) is not called. DISCARD will accept (but discard) the message, tt(abort) will be called. ACCEPT will accept recipient, tt(abort) will not be called. More details on ESTMP responses, are described in RFC 1869. itb(virtual sfsistat unknown(char *ptr)) Not yet supported. Will be available with libmilter versions beyond 2. ) manpagesection(PROTECTED MEMBER FUNCTIONS) The following members are non-virtual. They can be called by members of classes derived from bf(Milter): itemization( itb(bool addHeader(std::string const &hdrName, std::string const &hdrValue)) This member may only be called from tt(eom), and the flag tt(ADD_HEADERS) must have been specified or it will fail. The tt(hdrName) and tt(hdrValue) must be non-empty strings. Each line of the header must be under 2048 characters and should be under 998 characters. If longer headers are needed, make them multi-line. To make a multi-line header, insert a line feed (tt(\n)) followed by at least one whitespace character such as a space or tab (tt(\t)). The line feed should em(not) be preceded by a carriage return. It is the filter writer's responsibility to ensure that no standards are violated. itb(bool addRecipient(std::string const &rcptName)) This member may only be called from tt(eom), and the flag tt(ADD_RECIPIENTS) must have been specified or it will fail. itb(bool changeHeader(std::string const &hdrName, size_t headerNr, std::string const &hdrValue)) This member may only be called from tt(eom), and the flag tt(CHANGE_HEADERS) must have been specified or it will fail. See tt(addHeader) for the header-requirements. The tt(headerNr) parameter is a 1-based header index value. A tt(headerNr) value of 1 will modify the first occurrence of a header named tt(hdrValue). If tt(headerNr) is greater than the number of times tt(hdrName) appears, a new tt(hdrName)-header will be added. If tt(hdrValue) is empty, the header is deleted. itb(bool deleteRecipient(std::string const &rcptName)) This member may only be called from tt(eom), and the flag tt(DELETE_RECIPIENTS) must have been specified or it will fail. This member removes the named recipient from the current message's envelope. itb(SMFICTX *id() const) This member may be called by the Milter object to obtain a pointer identifying its sendmail-connection. Normally it should not be necessary to call this member. itb(bool insertHeader(size_t hdrIdx, std::string const &hdrName, std::string const &hdrValue)) This member may only be called from tt(eom), and the flag tt(ADD_HEADERS) must have been specified or it will fail. See tt(addHeader) for the header-requirements. The tt(headerNr) parameter is a header index value. A tt(headerNr) value of 0 will insert this header as the first of the tt(hdrName) headers. If tt(headerNr) is greater than the number of times tt(hdrName) appears, a new tt(hdrName)-header will be added. itb(bool openSocket(bool removeIfTrue = true)) This member should be called before tt(start) is called. This member attempts to create the socket specified by tt(setConnection) (see below). This allows the calling application to ensure that the socket can be created, possibly changing its protection (access rights) before the milter starts its work. If this member is not called, it will be called implicitly when tt(run) is started. It returns tt(true) if the socket could be created. itb(bool quarantine(std::string const &reason)) This member may only be called from tt(eom) and causes the MTA to quarantines the message using the given reason. itb(bool replaceBody(std::string const &body)) This member may only be called from tt(eom), and the flag tt(CHANGE_BODY) must have been specified or it will fail. It may be called multiple times in which case the various body content are concatenated in the final message. Newlines should be coded as CRLF. itb(bool setBacklog(size_t backlog = 5)) This member should be called before tt(start) is called. Sets the incoming socket backlog used by bf(listen)(2). If tt(setBacklog) is not called, the operating system default is used. The function returns tt(false) if the backlog could not be set as requested. It is the responsibility of the programmer not to call this function with a 0 argument. itb(bool setConnection(std::string const &name)) This member should be called before tt(start) is called. Sets the socket through which the filter communicates with sendmail. The socket may be specified using one of the following variants:nl() tt({unix|local}:/path/to/file) - A named pipe;nl() tt(net:port@{hostname|ip-address}) - An IPV4 socket;nl() tt(inet6:port@{hostname|ip-address}) - An IPV6 socket.nl() If possible, filters should not run as root when communicating over unix/local domain sockets. Unix/local sockets should have their permissions set to 0600 (read/write permission only for the socket's owner) or 0660 (read/write permission for the socket's owner and group) which is useful if the sendmail RunAsUser option is used. The permissions for a unix/local domain socket are determined as usual by umask, which should be set to 007 or 077. Possible failure of this function cannot be determined from its return value. Rather, tt(run) will fail. itb(setReply(std::string const &rcode, std::string const &xcode = "", std::string const &msg = "")) This member sets the default SMTP error reply code. It may be called from any callback member, except tt(connect). The parameter tt(rcode) should be a he three-digit (RFC 821/2821) SMTP reply code and it must be a valid 4XX or 5XX reply code. The parameter tt(xcode), when specified, must be a extended (RFC 1893/2034) reply code. The parameter tt(msg) may be an additional textual message. The bf(Milter) class has no member comparable to the libmilter API function tt(smfi_setmlreply). the bf(Milter) class. itb(void setTimeout(size_t seconds = 7210)) This member should be called before tt(start) is called. Sets the number of seconds libmilter will wait for an MTA connection before timing out a socket. If tt(setTimeout) is not called, a default timeout of 7210 seconds is used. It is the responsibility of the programmer not to call this function with an argument equal to 0. itb(char const *symval(std::string const &name) const) This member returns the value of a specific sendmail macro. The tt(name) parameter should be set to he name of a sendmail macro . Single letter macros can optionally be enclosed in braces (tt({) and tt(})), longer macro names must be enclosed in braces, just as in a sendmail.cf file.0 is returned if the macro is not defined. By default, the following macros are valid in the given contexts:nl() for tt(connect): tt(daemon_name, if_name, if_addr, j, _);nl() for tt(helo): tt(tls_version, cipher, cipher_bits, cert_subject, cert_issuer);nl() for tt(sender): tt(i, auth_type, auth_authen, auth_ssf, auth_author, mail_mailer, mail_host, mail_addr);nl() for tt(recipient): tt(rcpt_mailer, rcpt_host, rcpt_addr).nl() All macros stay in effect from the point they are received until the end of the connection for the first two sets, the end of the message for the third (tt(sender)), and just for each recipient for the final set (tt(recipient)).nl() The following macros may be specified in the sendmail.mc configuration file:nl() tt(define(`confMILTER_MACROS_CONNECT', `m1', ...)), tt(define(`confMILTER_MACROS_HELO', ...)), tt(define(`confMILTER_MACROS_ENVFROM', ...)), tt(define(`confMILTER_MACROS_ENVRCPT', ...)), where tt(`m1', ...) represents a comma separated list of returnable macros. Single letter macros can optionally be enclosed in braces (tt({) and tt(})), longer macro names must be enclosed in braces. itb(bool wait()) This member may only be called from tt(eom) and tells the MTA that the filter is still working on a message, causing the MTA to re-start its timeouts. ) manpagesection(EXAMPLE) To do manpagefiles() em(bobcat/milter) - defines the class interface manpageseealso() bf(bobcat)(7), bf(getpeername)(2), bf(listen)(2), nl() tt(http://www.milter.org) (e.g., tt(http://www.milter.org/developers/api))nl() tt(http://sendmail.org/m4/readme.html)nl() tt(http://rfc.net/rfc821.html)nl() tt(http://rfc.net/rfc822.html)nl() tt(http://rfc.net/rfc1869.html)nl() tt(http://rfc.net/rfc1893.html)nl() tt(http://rfc.net/rfc2034.html)nl() tt(http://rfc.net/rfc2821.html)nl() tt(/usr/include/libmilter/mfapi.h) manpagebugs() tt(-lmilter) must be specified before tt(-lbobcat). includefile(include/trailer) bobcat-5.09.01/documentation/man/config.yo0000644000175000017500000003217214050437223017353 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Config)(3bobcat)(_CurYrs_) (libbobcat-dev__CurVers_)(Configuration File Processing) manpagename(FBB::Config) (A class processing standard unix-like configuration files) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() bf(Config) objects process standard tt(unix)-style configuration files. Initial white-space (blanks and tabs) are removed from processed lines. If a line ends in a backslash (\), then the backslash is removed and the next line (initial white-space removed) is appended to the current line. If the tt(rmComment) flag is set to tt(true) blanks lines and information on lines from the first tt(#) are removed. If a backslash precedes the comment character (i.e., tt(\#)) then this is not considered comment, but it is replaced by a single tt(#) character. Similarly, if the tt(rmComment) flag was set two consecutive backslash characters are replaced by a single backslash character. All lines of the configuration file (possibly without comment) are stored in the bf(Config) object. Their line numbers can also be retrieved. At construction time comment handling (keep comment / remove comment) and type of searching (case sensitive / insensitive) can be specified. In addition to one of the constructors, the tt(load) member can be used to processes a configuration file, replacing the object's current content by the content of another configuration file. The tt(load) member cannot be used to alter the configuration file's processing parameters, but overloaded assignment is supported and comment- and letter-case handling can be modified by set-members. Often lines in configuration show the following structure: verb( id: value trailing content ) If tt(id) is a bf(C++) identifier it is called an tt(ID) in this man-page. When looking for tt(IDs) all non white-space characters immediately following the tt(ID) are ignored (in the example the ID is tt(id)). A tt(Key) is defined as the first white-space delimited entry on lines. In the example the key is tt(id:). The first space-delimited entry following the key is called the line's em(value), whereas all of the line's content starting at tt(value) is called the line's tt(tail). tt(Config) objects offer various members to process configuration file lines that are structured this way. However, lines do not have to be structured this way. All the lines of a configuration file are made available by tt(Config) objects and can be processed in several other ways as well. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(ENUMERATIONS) The following enumerations are defined by the class bf(Config): itemization( itb(Comment) This enumeration has two values: nl() bf(Config::KeepComment) specifies that comment on lines must be kept; nl() bf(Config::NoComment) specifies that comment on lines must be removed; itb(Casing) This enumeration also has two values:nl() bf(Config::UseCase) specifies that specified targets must match case-sensitively;nl() bf(Config::NoCase) specifies that specified targets are matched case-insensitively;nl() ) manpagesection(TYPES) The following types are defined by the class tt(Config): itemization( itb(const_iterator) a random access iterator referring to a line read from a configuration file. tt(FBB::Config::const_iterator) objects point to tt(FBB::CF_Line) objects (see the next section for a description of the class tt(CF_Line)); itb(CIVect::const_iterator) an iterator type referring to lines matching regular expressions or IDs. It supports the standard random access iterator facilities. The dereference operators of tt(FBB::Config::CIVect::const_iterator) objects return tt(FBB::Config::const_iterator) objects; ) When two tt(CIVect::const_iterator) objects are subtracted the number of lines matching their regular expressions (or IDs) is returned. E.g., verb( Config cf(...) auto pair = cf.beginEndID("scenario"); cout << "There are " << (pair.second - pair.first) << " lines starting with the ID `scenario'\n"; ) bf(Pattern)(3bobcat) objects are used when looking for lines matching regular expressions. manpagesection(CF_Line) tt(const_iterators) point to objects of the class tt(FBB::CF_Line). Objects of this class contain a line from the configuration file and its line number. The class offers the following facilities: itemization( itb(CF_Line()) the default constructor initialized its object with line number 0, and an empty line; itb(CF_Line(uint16_t lineNr, std::string const &line)) this constructor initialized its object with line number tt(lineNr), and a copy of the contents of tt(line); itb(std::string const &line() const) returns the object's line; itb(std::string key() const) returns the line's em(key) field; itb(uint16_t lineNr() const) returns the line's line number; itb(std::string tail() const) returns the line's em(tail) field (i.e., the info beyond the tt(key)); itb(std::string value() const) returns the line's em(value) field (i.e., the first white-space delimited entry following the line's ID); ) tt(CF_Line) objects may be inserted into tt(std::ostream) objects, inserting their lines into the streams. Copy- and move-constructors and -assignment operators are available. manpagesection(CONSTRUCTORS) itemization( itb(Config(Casing sType = UseCase, Comment cType = NoComment)) creates an empty object. It is not associated with a configuration file; the tt(load) member can be used for that. The parameters specify specific handling of comment, and letter-casing; itb(Config(std::string const &fname, Casing sType = UseCase, Comment cType = NoComment)) creates a bf(Config) object, containing the information from the configuration file tt(fname). The other parameters are used as described with the abovementioned constructor. If the file cannot be opened an tt(FBB::Exception) exception is thrown; itb(Config(std::istream &stream, Casing sType = UseCase, Comment cType = NoComment)) same functionality as the previous constructor, but reading the configuration information from the tt(std::istream stream); itb(Config(std::istream &stream, uint16_t lineNr, Casing sType = UseCase, Comment cType = NoComment)) same functionality as the previous constructor, but the line number of the first line read from tt(stream) is set to tt(lineNr); itb(Config(std::istream &&tmp, Casing sType = UseCase, Comment cType = NoComment)) same functionality as the constructor expecting an tt(istream) reference, but this time the configuration information is read from the tt(std::istream) rvalue reference tt(tmp); itb(Config(std::istream &&tmp, uint16_t lineNr, Casing sType = UseCase, Comment cType = NoComment)) same functionality as the previous constructor, but the line number of the first line read from tt(stream) is set to tt(lineNr). ) Copy- and move-constructors and -assignment operators are available. manpagesection(OVERLOADED OPERATORS) itemization( itb(CF_Line const &operator[](size_t idx) const) returns the (0-based) tt(idx)-th line of the configuration file. ) manpagesection(MEMBER FUNCTIONS) itemization( itb(const_iterator begin() const) returns a tt(const_iterator) referring to the first line of the configuration file; itb(std::pair beginEndID(std::string const &rid) const) returns a pair of tt(CIVect::const_iterators). Its tt(first) field is an tt(CIVect::const_iterator) referring to the first line containing ID tt(id); its tt(second) field is a tt(CIVect::const_iterator) marking the end of the series of lines containing ID tt(id). The difference between the two iterators equals the number of lines containing ID tt(id); itb(std::pair beginEndRE(std::string const ®ex) const) same functionality as the previous member, but returning a pair of iterators to lines matching tt(regex); itb(const_iterator end() const) returns a tt(const_iterator) pointing beyond the last line of the configuration file; itb(void clear()) clears the current content of the tt(Config) object. This member is automatically called by the tt(load) members; itb(const_iterator find(std::string const &target) const) returns an iterator to the first line containing tt(target), starting the search at tt(begin()). Note that tt(target) may appear anywhere within a line. It returns tt(end()) if no such line was found; itb(const_iterator find(std::string const &target, const_iterator from) const) same functionality as the previous member, but searching starts at tt(from); itb(const_iterator findID(std::string const &id) const) returns an iterator of the the first line containing ID tt(id). It returns tt(end()) if no such line was found; itb(const_iterator findID(std::string const &id, const_iterator from) const) same functionality as the previous member, but searching starts at tt(from); itb(const_iterator findKey(std::string const &key) const) returns an iterator of the the first line containing key `tt(key)'. It returns tt(end()) if no such line was found; itb(const_iterator findKey(std::string const &key, const_iterator from) const) same functionality as the previous member, but searching starts at tt(from); itb(const_iterator findRE(std::string const ®ex) const) returns an iterator is returned to the first line matching the regular expression tt(regex). It returns tt(end()) if no such line was found; itb(void load(std::string const &fname)) the content of the file named tt(fname) is stored in the tt(Config) object, replacing any previously stored content. The file is read according to the latest setting of the tt(Comment) and tt(Casing) flags. If the file cannot be opened an tt(FBB::Exception) exception is thrown; itb(void load(std::istream &stream, uint16_t lineNr = 1)) same functionality as the previous member, but reading the configuration information from the tt(std::istream) reference tt(stream). The tt(lineNr) value specifies the line number of the first read line; itb(void load(std::istream &&tmp, uint16_t lineNr = 1)) same functionality as the previous member, but reading the configuration information from the tt(std::istream) rvalue reference tt(tmp); itb(void setComment(Comment type)) the object's comment-handling type is set to tt('type') (ether tt(KeepComment) or tt(NoComment)). It doesn't affect the current content of the bf(Config) object, but when calling tt(load) the configuration file is processed according to tt(type's) value; itb(void setCasing(Casing type)) the object's letter case handling type is set to tt('type') (either tt(UseCase) or tt(NoCase)); itb(size_t size() const) returns the number of lines stored in the tt(Config) object; ) manpagesection(EXAMPLE) Assume the configuration file is named tt(config.rc), containing the following lines: COMMENT(Keep the blank following the backslashes below:) verb( # this is ignored noline: this one too line: this is found this is not a line containing line: at the beginning \ of the line line: this one is line: what about this one? \ it extends over multiple lines and there may, of course, be more lines in this file ) The next program may be compiled and run as tt(a.out config.rc): verb( #include #include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) { Config cf(argv[1]); cout << *cf.find("this one") << '\n'; // find text within a line // find all lines specifying ID 'line' auto [begin, end] = cv.beginEndID("line"); copy(begin, end, ostream_iterator(cout, "\n")); } ) Producing the output: verb( line: this is found line: this one is line: what about this one? it extends over multiple lines ) manpagefiles() em(bobcat/config) - defines the class interface manpageseealso() bf(argconfig)(3bobcat), bf(bobcat)(7), bf(exception)(3bobcat), bf(pattern)(3bobcat) manpagebugs() None reported includefile(include/trailer) bobcat-5.09.01/documentation/man/mailheaders.yo0000644000175000017500000001601214050437223020357 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::MailHeaders)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (SMTP Mail Headers) manpagename(FBB::MailHeaders)(Handles SMTP Mail Headers) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() bf(FBB::MailHeaders) objects extract header lines from e-mail. Reading stops at (and including) the first blank line, which becomes the last element of the bf(FBB::MailHeaders) object, interpreted as a bf(vector). The actual e-mail content is therefore left unread on the file containing the e-mail. Each line stored in a bf(MailHeaders) object represents a complete header line. Headers continuing over multiple input lines are concatenated to a single line retrievable from bf(MailHeaders) objects, separated from each other by tt('\n') (newline) characters. The last line to join a multi-line header is not terminated by a newline character. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(ENUMERATIONS) The following enumerations and enumeration values can be used with the class bf(FBB::MailHeaders): bf(enum Mode)nl() This enumeration defines two values: itemization( itb(READ) When this value is specified at construction time, e-mail is immediately read by the constructor. itb(DONT_READ) When this value is specified at construction time, e-mail is read using the tt(read) member (see below). ) bf(enum Match)nl() This enumeration defines the following values: itemization( itb(FULL) Used by tt(setHeaderIterator) (see below) to indicate that the headers must exactly match a specified header name. itb(INITIAL) Used by tt(setHeaderIterator) (see below) to indicate that the initial part of the headers must match the specified header text. itb(PARTIAL) Used by tt(setHeaderIterator) (see below) to indicate that the headers must contain the specified header text. itb(CASE_FULL) Used by tt(setHeaderIterator) (see below) to indicate that the headers must exactly match a specified header name. The matching is performed case insensititvely. itb(CASE_INITIAL) Used by tt(setHeaderIterator) (see below) to indicate that the initial part of the headers must match the specified header text. The matching is performed case insensititvely. itb(CASE_PARTIAL) Used by tt(setHeaderIterator) (see below) to indicate that the headers must contain the specified header text. The matching is performed case insensititvely. ) manpagesection(NESTED TYPES) The class tt(MailHeaders) defines the following types: itemization( itb(const_iterator) An input iterator returned by tt(begin) and tt(end) (see below) itb(const_reverse_iterator) An reverse input iterator returned by the members tt(rbegin) and tt(rend) (see below) itb(const_hdr_iterator) An input iterator returned by the members tt(beginh) and tt(endh) (see below) itb(const_reverse_hdr_iterator) An reverse input iterator returned by the members tt(rbeginh) and tt(rendh) (see below) ) Objects of these two iterator types point to header lines. Their dereferenced type is tt(std::string). manpagesection(CONSTRUCTORS) itemization( itb(MailHeaders(std::istream &in, Mode mode = READ)) This constructor defines the file containing the e-mail to be processed. The second parameter is by default bf(MailHeaders::READ), causing the object to start reading the e-mail immediately. If set to bf(MailHeaders::DONT_READ), the e-mail is not read. In that case the member tt(read) can be called to process the e-mail later. ) The move constructor and move assignment operator is available. manpagesection(OVERLOADED OPERATORS) itemization( itb(std::string const &operator[](size_t idx) const) Returns the tt(idx)-th header line ) manpagesection(MEMBER FUNCTIONS) itemization( itb(const_iterator begin() const) Returns an iterator to the first line of the mail headers. itb(const_hdr_iterator beginh() const) Returns the begin-iterator corresponding to the first header selected by the tt(setHeaderIterator) member. itb(const_iterator end() const) Returns an iterator beyond the last line of the mail headers. itb(const_hdr_iterator endh() const) Returns the end-iterator matching tt(beginh). Note that the member function's name ends in tt(h), to distinguish it from the tt(vector::end) member. itb(const_reverse_iterator rbegin() const) Returns an iterator to the last line of the mail headers. itb(const_reverse_hdr_iterator rbeginh() const) Returns the reversed begin-iterator corresponding to the last header selected by the tt(setHeaderIterator) member. itb(void read()) Reads the mail-headers from the file passed to the bf(FBB::MailHeaders) object's constructor. An bf(FBB::Exception) object is thrown if the mailheaders were already read or if the file is incomplete (i.e., the (obligatory) blank line wasn't found). itb(const_iterator rend() const) Returns an iterator before the first line of the mail headers. itb(const_reverse_hdr_iterator rendh() const) Returns the reversed end-iterator matching tt(rbeginh). itb(void setHeaderIterator(char const *header, Match match = FULL)) Sets the header-iterators to the specified tt(header). The parameter tt(match) defines the match-type to use when selecting headers. The default bf(FBB::MailHeaders::FULL), indicates that the text provided in tt(header) must match exactly an e-mail header. nl() When matching headers the colon terminating the header is em(not) considered and should therefore em(not) be specified by tt(setHeaderIterator). nl() Alternative matching strategies are used when other values of the enumeration bf(FBB::Match) are specified.nl() The member tt(setHeaderIterator) em(must) have been called at least once or the members tt(beginh) and tt(rendh) will throw an bf(FBB::Exception) exception. An bf(FBB::Exception) exception is also thrown if tt(setHeaderIterator) is called when no mail headers are available. itb(size_t size() const) Returns the number of header lines ) manpagesection(EXAMPLE) The following example shows the normal use of these members: verb( // create a MailHeader object MailHeaders mh(cin, MailHeaders::DONT_READ); try { // read the headers mh.read(); } catch (Exception &err) { cout << err.what() << endl; } cout << "There are " << mh.size() << " header lines\n"; // look for the Received: headers mh.setHeaderIterator("Received"); // show the Received headers copy(mh.beginh(), mh.endh(), ostream_iterator(cout, "\n")); ) manpagefiles() em(bobcat/mailheaders) - defines the class interface manpageseealso() bf(bobcat)(7) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/table.yo0000644000175000017500000002372514050437223017201 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Table)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Table-formatter) manpagename(FBB::Table)(Generates row- or column-wise filled tables) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() bf(FBB::Table) objects can be used to create tables. The tables are filled either column-wise or row-wise. Many of the table's characteristics may be fine-tuned using a separate bf(FBB::TableSupport) object, described in a separate man-page (bf(TableSupport)(3bobcat)). When no bf(FBB::TableSupport) object is used, a plain row-wise or column-wise table is constructed which can be inserted into a bf(std::ostream). Tables defined by tt(Table) consist of a (number of element dependent) number of rows and a fixed number of columns, the latter value is specified at construction time. Columns and rows are normally addressed using index values (starting at 0). Before the leftmost column, between the columns and beyond the last column em(separators) are defined. By default the separators are empty, but each separator may be given a (fixed) width or content. The separator before column tt(col) is addressed as separator tt(col), the rightmost separator is addressed as separator tt(nColummns). Likewise, rows can be separated from each other using separators. These separating rows are also empty by default. The row-separator before row tt(row) is addressed as row-separator tt(row). The row-separator following the final row is addressed as row-separator tt(nRows), where tt(nRows) is the value returned by the tt(nRows) member function. Non-default (i.e., non-empty) separators are defined using tt(FBB::TableSupport) objects (cf. bf(tablesupport)(3bobcat)). tt(Table) objects look a lot like tt(ostream) objects, but they also adopt a fairly rigid way to define new elements: each new insertion defines another table element, and it is difficult to end a row before it has received its tt(nColumn) number of elements. tt(Table)'s sister-class, tt(TableBuf), is a tt(std::streambuf) type of class, offering additional control through the use of a wrapping tt(ostream) class object. includefile(include/namespace) manpagesection(INHERITS FROM) bf(std::ostringstream) - tt(Table) inherits from bf(std::ostringstream), allowing insertions into a bf(Table) object. Each separate insertion adds another element to the bf(Table) object. bf(FBB::TableBase) - This class implements common elements of the table implementation (the tt(FBB::TableBuf) class is also derived from tt(TableBase). The tt(TableBase) class is not intended to be used otherwise, and no separate man-page is provided. All facilities provided by tt(Table) inherited from tt(TableBase) are described in this man-page. manpagesection(ENUMERATIONS) The following enumerations are defined by the class bf(FBB::Table): bf(enum FillDirection)nl() This enumeration defines two values: itemization( itb(ROWWISE) When this value is specified at construction time, elements are added row-wise to the table. I.e., the second element inserted into the bf(Table) will be found in the second column of the first row. itb(COLUMNWISE) When this value is specified at construction time, elements are added column-wise to the table. I.e., the second element will be found in the second row of the first column. ) bf(enum WidthType)nl() This enumeration defines two values: itemization( itb(COLUMNWIDTH) This value may be specified when the columns should be allowed variable widths. In this case each column will be as wide as its widest element. This is the default bf(WidthType) used by bf(Table) objects. itb(EQUALWIDTH) This value may be specified when all the table's columns should have equal width (i.e., equal to the width of the widest table element), ) manpagesection(CONSTRUCTORS) itemization( itb(Table(size_t nColumns, Table::FillDirection direction, Table::WidthType widthType = Table::COLUMNWIDTH)) The table's number of columns, the fill directions and the column width-type must be provided. The number of rows is implied by the combination of this parameter and the number of elements that is actually inserted into the bf(Table) object. The bf(direction) parameter specifies the way new elements are added to the bf(Table) object: row-wise or column-wise. Finally, the tt(widthType) parameter is used to specify the way the width of the table's columns is determined. Each column either defines its own width or all columns have equal widths. itb(Table(TableSupport &tableSupport, size_t nColumns, Table::FillDirection direction, Table::WidthType widthType = Table::COLUMNWIDTH)) This constructor operates identically to the previous constructor, but expects an additional reference to a bf(TableSupport) object. A bf(TableSupport) object offers additional formatting features used by the table defining elements like horizontal lines between rows, additional separators, etc, etc. The bf(TableSupport) object is passed as a non-const reference as the bf(Table) object must be able to manipulate its data. See bf(tablesuppport)(3bobcat) for more information about tt(TableSupport). ) Copy and move constructors (and assignment operators) are not available. manpagesection(OVERLOADED OPERATORS) itemization( itb(std::ostream &operator<<(std::ostream &str, Table &table)) This operator inserts a bf(Table) into a tt(std::ostream) object. This operator requires a non-const table as it may have to complete the table by adding empty elements (i.e., empty strings) to obtain a completely filled rectangular table. itb(Table &operator<<(Table &obj, Align const &align)) This operator is used to change the default alignment of either a column or an element. It is a wrapper around the member tt(setAlign()) (see below for its description). By default, all elements are right-aligned. See bf(align)(3bobcat) for more information about the tt(Align) class. itb(Table &operator<<(Table &obj, Type const &x)) This overloaded operator is defined as a function template: bf(Type) is a template type parameter instantiated to a type for which bf(std::ostringstream) insertions are possible. It inserts the value/object tt(x) into the bf(Table)'s bf(std::ostringstream) base class object as the next element of the table. ) manpagesection(MEMBER FUNCTIONS) itemization( itb(Table &append(std::string const &text char const *sep = " \t", bool addEmpty = false)) Fields in tt(text) separated by one of the characters in tt(sep) are added as additional elements to the bf(Table) object. Empty fields are ignored unless the parameter tt(addEmpty) is initialized to tt(true). itb(void clear()) The content of the table are erased. All existing elements are removed, and the table will be empty. itb(void clearStr()) The content of its tt(std::ostringstream) base class buffer are erased. itb(void fill(InputIterator begin, InputIterator end)) This member is defined as a member template; tt(InputIterator) is a template type parameter representing any input iterator. It can also be, e.g., a pointer to an insertable type. The iterators must point to data elements which can be inserted into an tt(std::ostream). The range of values implied by the member's iterator pair are inserted into the table as new elements. itb(void push_back(std::string const &element)) New elements can be added to the table using tt(push_back). It is, e.g., called from a tt(back_inserter) adaptor). itb(size_t nRows()) The currently available number of rows in the table is returned. Its value is only defined after calling bf(CHAR(d)ef()). itb(Table &setAlign(Align const &align)) The alignment type of either a column or an element of the bf(Table) object is defined using tt(setAlign). The standard alignments tt(std::left, std::right) and tt(std::internal) may be specified, but in addition the alignment tt(FBB::center) may be used if elements should be centered into their column. A construction like verb(tab << Align(2, FBB::center)) requests centering of all elements in the table's column having index value 2 (i.e., the table's 3rd column), whereas a construction like verb(tab << Align(2, 3, FBB::center)) requests centering of element [2][3]. It is the responsibility of the programmer to ensure that such elements exist. By default, all elements are right-aligned. itb(Table &CHAR(d)ef()) After inserting elements into a tt(Table) object its number of elements may or may not be an integral multiple of the number of columns specified at construction time. To `complete' a bf(Table) object to a rectangular object, for which all column widths and alignments have been determined tt(def) may be called. It is automatically called by tt(operator<<(ostream, Table)). In other situations it may be called explicitly to force the insertion of another row in a table using tt(ROWWISE) insertions. With tt(COLUMNWISE) insertions its working is complex, since new elements added to a tt(COLUMNWISE) filled table will reshuffle its elements over the table's columns. ) manpagesection(MANPULATORS) itemization( itb(Table &CHAR(d)ef(Table &table)) This manipulator can be inserted into a table to call the table's bf(CHAR(d)ef()) member. ) manpagesection(EXAMPLE) verbinclude(../../table/driver/driver.cc) manpagefiles() em(bobcat/table) - defines the class interface;nl() manpageseealso() bf(bobcat)(7), bf(align)(3bobcat), bf(csvtable)(3bobcat), bf(manipulator)(3bobcat), bf(tablebuf)(3bobcat), bf(tablelines)(3bobcat), bf(tablesupport)(3bobcat) manpagebugs() Note that tt(CHAR(d)ef()) will reshuffle elements over the table's columns when new elements are added to the table subsequent to calling tt(CHAR(d)ef()) includefile(include/trailer) bobcat-5.09.01/documentation/man/cmdfinder.yo0000644000175000017500000002124714050437223020042 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::CmdFinder)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Command-function associations) manpagename(FBB::CmdFinder) (Determine (member) function associated with a command) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() Objects of the class bf(CmdFinder) determine which (member) function to call given a command. Although associations between commands and (member) functions are often defined in a switch, a switch is not the preferred way to define these associations because of the fect that the maintainability and clarity of switches suffer for even moderately large command sets. Moreover, the switch is hardly ever self-supporting, since usually some command-processing is required to determine command/bf(case)-value associations. The alternative (and preferred) approach, which is also taken by bf(CmdFinder) is to define an array of pointers to (member) functions, and to define the associations between commands and member functions as a mapping of commands to array indices. Plain associations between (textual) commands and functions to be called can also easily be defined using a bf(std::map) or other hash-type data structure. However, the syntactical requirements for such a bf(std::map) structure are non-trivial, and besides: user-entered commands often require some preprocessing before a command can be used as an index in a bf(std::map). The class bf(CmdFinder) is an attempt to offer a versatile implementation of associations between commands and (member) functions. In particular, the class offers the following features: itemization( it() Associations between textual commands and (member) functions are defined in a simple array of pairs: the first element defining a command, the second element containing the address of the function associated with the command. The function addresses may either be addresses of free or static member functions or they may be defined as member function addresses. it() Commands may be used `as-is', or the first word in a bf(std::string) may be used as the command; it() Commands may be specified case sensitively or case insensitively; it() Commands may have to be specified in full, or unique abbreviations of the commands may be accepted; it() Several types are defined by the class bf(CmdFinder), further simplifying the deriviation of classes from bf(CmdFinder). ) The class bf(CmdFinder) itself is defined as a template class. This template class should be used as a base class of a user-defined derived class defining the array of command-function associations. The class bf(CmdFinder) itself is a derived class of the class bf(CmdFinderBase), defining some template-independent functionality that is used by bf(CmdFinder). The enumeration and member functions sections below also contain the members that are available to classes derived from bf(CmdFinder), but which are actually defined in the class bf(CmdFinderBase). includefile(include/namespace) manpagesection(INHERITS FROM) bf(FBB::CmdFinderBase) manpagesection(ENUMERATION) The enumeration bf(Mode) is defined in the class bf(CmdFinderBase). It contains the following values, which may be combined by the bf(bit_or) operator to specify the bf(CmdFinder) object's required mode of operation: itemization( itb(USE_FIRST) This value can be specified when the first word (any white-space separated series of characters) of a provided textual command should be used as the command to find. Both the command that is used and any trailing information that may be present can be obtained from the bf(CmdFinder) object. By default, the complete content of the a provided command is used. itb(UNIQUE) This value can be specified when any unique abbreviation of a command may be accepted. Assuming that the commands tt(help) and tt(version) are defined, then the following (non-exhaustive) series are all accepted as specifications of the tt(help) command if bf(UNIQUE) is specified: tt(h, he, el, p). By default the command must match a command-key as found in the array of command-function associations exactly. itb(INSENSITIVE) When this value is specified, commands may be specified disregarding letter-casing. E.g., when bf(INSENSITIVE) is specified, both tt(Help) and tt(HELP) are recognized as tt(help). By default, letter casing is obeyed. ) So, by default a full, literal match between provided command and predefined command-keys is required. manpagesection(TEMPLATE TYPE PARAMETER) The template class bf(CmdFinder) has one template type parameter, which is the prototype of the functions defined in the array of command-function associations. This type becomes available as the typename bf(FunctionPtr) (defined by the class bf(CmdFinder) in the class that is derived from bf(CmdFinder)). manpagesection(PROTECTED DEFINED TYPES) The following (bf(protected)) types are defined by the template class bf(CmdFinder): itemization( itb(FunctionPtr) This type represents a pointer to the functions whose addresses are stored in the array of command-function associations. itb(Entry) This type represents the type bf(std::pair). Its em(first) field is the name of a command, its em(second) field is the function address associated with the command name. ) manpagesection(CONSTRUCTORS) itemization( itb(CmdFinder(Entry const *begin, Entry const *end, size_t mode = 0)) This constructor is defined in the bf(protected) section of the bf(CmdFinder) class. Its parameters tt(begin) and tt(end) define the half-open range of bf(Entry) objects, defining the associations between commands and functions. The parameter tt(begin) should be initialized to the first element of an array of bf(Entry) objects, the parameter tt(end) must point just beyond the last element of the array. The parameter tt(mode) may be speified using any combination of values of the bf(Mode) enumeration, using the bf(bit_or) operator to combine multiple values. When a non-supported value is specified for tt(mode), an bf(FBB::Exception) exception is thrown. itb(Note) There is no default constructor. ) Copy and move constructors (and assignment operators) are available. manpagesection(PUBLIC MEMBER FUNCTION) itemization( itb(setMode(size_t mode)) This member function (defined in the class bf(CmdFinderBase)) may be called to redefine the mode of the bf(CmdFinder) object. The tt(mode) parameter should be initialized subject to the same restrictions as mentioned with the bf(CmdFinder)'s constructor. ) manpagesection(PROTECTED MEMBER FUNCTIONS) itemization( itb(std::string const &beyond() const) This member function returns the text that may have been entered beyond the command (if bf(Mode) value bf(USE_FIRST) was specified). It is empty if no text beyond the command was encountered. It is initially empty, and will be redefined at each call of bf(findCmd()) (see below). itb(std::string const &cmd() const) This member returns the original (untransformed) command as encountered by the bf(CmdFinder) object. It is initially empty, and will be redefined at each call of bf(findCmd()) (see below). object. itb(size_t count() const) This member function returns the number of commands matching the command that is passed to the function bf(findCmd()) (see below). Its return value is 0 when bf(findCmd()) hasn't been called yet and is updated at each new call of bf(findCmd()). itb(FunctionPtr findCmd(std::string const &cmd)) Regarding the bf(CmdFinder) object's bf(mode) setting, this function returns the address of the function to call given the provided command. By default, if no match was found, the address of the function stored in the last element of the array of command-function associations is returned (i.e, element tt(end[-1])). itb(void swap(CmdFinderBase &other)) The current and tt(other) object are swapped. ) manpagesection(PROTECTED DATA MEMBERS) The class bf(CmdFinder) has access to some protected data members of the class bf(CmdFinderBase), which should not be used or modified by classes derived from bf(CmdFinder). manpagesection(EXAMPLE) verbinclude(../../cmdfinder/driver/driver.cc) manpagefiles() em(bobcat/cmdfinder) - defines the class interface+nl() em(bobcat/cmdfinderbase) - defines the base class of bf(CmdFinder). manpageseealso() bf(bobcat)(7), bf(cmdfinderbase)(3bobcat), bf(exception)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/stringline.yo0000644000175000017500000000461014050437223020260 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::StringLine)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Line extractor) manpagename(FBB::StringLine)(extracting lines using operator>>) manpagesynopsis() bf(#include )nl() manpagedescription() The standard tt(operator>>(std::istream &, std::string &)) string extracion operator extracts the first `word' from a stream. In cases where the intent it to extract lines from the stream this operator cannot be used, but tt(getline(std::istream &, std::string &)) is usually called. However, tt(getline) is not called by many tools of generic algorithms, like the tt(istream_iterator). The class (actually: struct) tt(StringLine) was simply derived from tt(std::string), and defines its own tt(operator>>), reading the next line from the specified tt(std::istream). includefile(include/namespace) manpagesection(INHERITS FROM) tt(std::string) manpagesection(CONSTRUCTORS) tt(StringLine) is an empty shell around tt(std::string). It does not explicitly define constructors. Copy and move constructors (and assignment operators) are available. manpagesection(OVERLOADED OPERATOR) itemization( itb(std::istream &operator>>(std::istream &in, StringLine &str)) The extraction operator returns the next line on tt(in) in tt(str), calling tt(getline(std::istream &, std::string &)). ) manpagesection(MEMBER FUNCTIONS) All members of bf(std::string) are available, as bf(FBB::StringLine) inherits from these classes. manpagesection(EXAMPLE) The following example extracts all lines from tt(std::cin) and adds them to the tt(std::vector lines): verb( #include #include #include #include #include using namespace std; using namespace FBB; int main() { vector lines; copy( istream_iterator(cin), istream_iterator(), back_inserter(lines) ); } ) manpagefiles() em(bobcat/stringline) - defines the class interface and tt(operator>>). There are tt(StringLine) object files in the Bobcat library, so linking to Bobcat when using tt(StringLine) is not necessary. manpageseealso() bf(bobcat)(7) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/align.yo0000644000175000017500000000607314050437223017201 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Align)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Table Element Alignment) manpagename(FBB::Align)(Class used to align elements in Table objects) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() This class defines objects used by the class bf(FBB::Table) to define the alignment of its columns and/or elements. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(ADDITIONAL TYPEDEF) The type bf(FBB::Manipulator) can be used as a shorthand for verb( std::ios_base &(*)(std::ios_base &) ) which is the prototype of standard io-manipulators like tt(std::left). manpagesection(CONSTRUCTORS) itemization( itb(Align(size_t column = 0, Manipulator manip = std::right)) This constructor defines how the content of column `tt(column)' of a bf(Table) object are aligned. When used, it is the responsibility of the programmer to ensure that the table's column exists. This constructor can also be used as a default constructor, by default using right-alignment. itb(Align(int row, size_t column, Manipulator manip)) This constructor defines the alignment of element tt([row][column]) of a bf(Table) object. When it is used, it is the responsibility of the programmer to ensure that the table's element exists. itb(Align(Manipulator manip)) This constructor is used to initialize the object with the address of an existing io-manipulator function. ) Copy and move constructors (and assignment operators) are available. manpagesection(OVERLOADED OPERATORS) itemization( itb(operator size_t() const) Returns the value representing a requested width of an element in a bf(Table) object. ) manpagesection(MEMBER FUNCTIONS) itemization( itb(size_t col() const) Returns the object's column index. itb(bool hasRow() const) Returns tt(true) if the object's bf(row()) member returns a sensible value. itb(size_t row+nop()() const) Returns the object's row index. itb(Manipulator manip() const) Returns the bf(Manipulator) stored in the object. itb(void setWidth(size_t width)) Defines the field-width of element(s) of a tt(Table) object to which the bf(Align) object is applied. itb(void setManip(Manipulator manip)) Changes the object's currently stored bf(Manipulator). ) manpagesection(MANIPULATORS) The following manipulator (em(not) part of the bf(FBB::Align), class but defined in the bf(FBB) namespace) can be stored in bf(Align) objects through, e.g., tt(setManip): itemization( itb(FBB::center) ) manpagesection(EXAMPLE) See the bf(table)(3bobcat) man-page. manpagefiles() em(bobcat/align) - defines the class interface manpageseealso() bf(bobcat)(7), bf(manipulator)(3bobcat), bf(table)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/sharedcondition.yo0000644000175000017500000003542714050437223021271 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::SharedCondition)(3bobcat)(_CurYrs_) (libbobcat-dev__CurVers_)(Shared Memory Cond. Var.) manpagename(FBB::SharedCondition)(Shared Memory Condition Variable) manpagesynopsis() bf(#include )nl() Linking option: tt(-lpthread, -lbobcat ) manpagedescription() Condition variables are used to synchronize threads based on the values of data. Condition variables allow threads to wait until a certain condition has occurred, after which the threads continue their actions. Thus waiting threads don't continuously have to poll the state of a variable (requiring the threads to gain access to the variable before they can inspect its value). Using condition variables waiting threads simply wait until they are notified. bf(SharedCondition) objects can be used in combination with shared memory. bf(SharedCondition) objects interface to objects (called em(Condition) objects in this man-page) which are defined in shared memory and contain a tt(SharedMutex) and a shared condition object. These tt(Condition) objects may be accessed by threads running in different processes. These different processes might run a single tt(main) thread, or they themselves can be multi-threaded. Condition variables are used in situations like these: itemization( it() There exists a thread which should be suspended until a certain condition has been met. it() This thread locks a mutex (or waits until the lock has been obtained) it() While the condition hasn't been met, the thread is suspended (i.e., waits), automatically releasing the mutex's lock. it() Somehow (see below) the thread is resumed, at which point the thread has automatically reacquired the lock. it() Once the condition has been met, the while loop ends, and the mutex's lock is released. it() There exists a second thread, which influences the variables that are elements of the condition, and which may notify the waiting thread, once the required condition has been met. it() This second thread locks the same mutex as used by the first thread. it() The second thread modifies the variables that are involved, and if the required condition has been met, it notifies the first thread. it() The second thread releases the mutex's lock, allowing the first thread to obtain the mutex's lock. ) While the first thread is waiting, it is suspended. It may be resumed when it receives a notification from another thread, but also for spurious reasons. Therefore the first thread must verify that the condition has been met after resuming its actions. As condition variables are always used in combination with a mutex, bf(SharedMutex) encapsulates the mutex-handling. The software using bf(SharedCondition) objects doesn't have to handle the mutex itself. bf(SharedCondition) objects are used to synchronize actions by different processes, using shared memory as their vehicle of synchronization/communication. The actual condition variable that is used by a bf(SharedCondition) object is defined in shared memory. bf(SharedCondition) objects themselves are small objects, containing the necessary information to access the actual shared memory condition variable. includefile(include/namespace) manpagesection(INHERITS FROM) bf(SharedMutex)(3bobcat) manpagesection(CONSTRUCTORS, DESTRUCTOR) itemization( itb(SharedCondition()) The default constructor creates an empty stub which cannot yet be used (or an tt(FBB::Exception) is thrown). As the bf(SharedCondition) class supports assignment operators, empty stubs can easily be (re)configured at any time after their construction. itb(~SharedCondition()) The class's destructor releases (if applicable) its lock on the shared condition variables mutex lock. The destructor takes no action if its object is an empty stub. ) Default, copy, and move constructors as well as the copy and move assignment operators are available. manpagesection(MEMBER FUNCTIONS) Returning from bf(SharedCondition) member functions the offset of the tt(SharedMemory) object in which the condition variable has been defined has not changed. Internally, the current offset is saved; the requested function is performed; and the original offset is restored. Consequently, bf(SharedCondition) member functions can be used disregarding the tt(SharedMemory)'s current offset. itemization( itb(void lock() const) When returning from this member, the current process has locked the bf(SharedCondition) object. Be careful not to call tt(lock) twice during the same thread of execution (cf. bf(sharedmutex)(3bobcat) for details). itb(void notify() noexept) One of the threads waiting on the bf(SharedCondition) object wakes up. The thread calling tt(notify) should release its mutex lock shortly after calling tt(notify), allowing the notified thread to obtain the lock. A prototypical piece of pseudo code illustrating the use of tt(notify) looks like this: verb( sharedCondition.lock(); // lock the mutex ... // operate on the condition's variables if (conditionWasMet) // ready to notify sharedCondition.notify(); sharedCondition.unlock(); // release the lock ) As the tt(sharedCondition.lock ... sharedCondition.unlock) sequence itself may be executed at different flow of control sections, the tt(unlock) member cannot be called from within tt(notify). itb(void notifyAll() noexept) Different from the plain tt(notify) member, this member wakes up all of the threads waiting on the bf(SharedCondition) object. However, after the current thread has released its mutex lock only one of these signaled threads will actually obtain the lock. The pseudo code for using tt(notifyAll) is identical to the pseudo code for using tt(notify) (i.e., calling tt(notifyAll), of course). itb(std::streamsize offset() const) The location of the shared condition variable (within the tt(SharedMemory) object) is returned. The shared condition object ends at tt(offset() + SharedCondition::width()), see below. itb(void unlock() const) The object's lock is released (nothing happens if called when the current object does not have the object's lock). itb(void wait()) Before calling tt(wait) the current thread should have obtained a lock on the bf(SharedCondition) object. When calling tt(wait) the running thread suspends its activities and waits until being notified. Once notified, it reacquires the lock and continues. Shortly after this the process should again release its lock on the bf(SharedCondition) object. lock. A prototypical piece of pseudo code illustrating how to use tt(wait) looks like this: verb( sharedCondition.lock(); // lock the mutex while (conditionWasNotYetMet) // waiting required sharedCondition.wait(); ... // do something: we have the lock sharedCondition.unlock(); // release the lock ) itb(void wait(Predicate pred)) This member was implemented as a member template. tt(Predicate) either is a predicate function or a predicate function object. The predicate function or the predicate function object's function call operators may not require arguments. As long as tt(pred) is returning false, tt(wait()) (no arguments) is called. The function returns once tt(pred) has returned tt(true). The running thread should have obtained a lock on the bf(SharedCondition) condition variable prior to calling this member, and should release the lock after this member has returned. The pseudo code for using tt(wait(pred)) is identical to the pseudo code for using tt(wait) (albeit that tt(pred) has to be passed to tt(wait), of course). itb(std::cv_status wait_for(std::chrono::duration const &relTime)) This member was implemented as a member template. tt(Type) defines the type of the variable holding the amount of time (usually tt(int64_t)), specified in time unit tt(Unit). Predefined tt(duration) types are available from the tt(std::chrono) namespace, like tt(std::chrono::seconds(4)), representing 4 seconds, or tt(std::chrono::milliseconds(30)), representing 30 milliseconds. The running thread should have obtained a lock on bf(SharedCondition) prior to calling this member, and should release the lock after this member has returned. This member acts like tt(wait), returning tt(std::cv_status::no_timeout) if a notification was received before tt(relTime) has passed. Otherwise tt(std::cv_status::timeout) is returned. A prototypical piece of pseudo code illustrating how to use tt(wait_for) looks like this: verb( sharedCondition.lock(); // lock the mutex while (conditionWasNotYetMet) // waiting required { while (sharedCondition.wait_for(someTime) == std::cv_status::timeout) handle_timeout do_something } sharedCondition.unlock(); // release the lock ) When returning from tt(wait_for) the current thread has obtained the shared condition's lock, but maybe due to a timeout: this can be verified by inspecting tt(wait_for's) return value, and an appropriate action can be selected. itb(bool wait_for(std::chrono::duration const &relTime, Predicate pred)) This member was implemented as a member template. tt(Type) defines the type of the variable holding the amount of time (usually tt(int64_t)), specified in time unit tt(Unit). tt(Predicate) either is a predicate function or a predicate function object. The predicate function or the predicate function object's function call operators may not require arguments. The running thread should have obtained a lock on bf(SharedCondition) prior to calling this member, and should release the lock after this member has returned. As long as tt(pred) returns false, tt(wait_for(relTime)) is called. If the latter function returns tt(std::cv_status::timeout), then tt(pred) is called, and its return value is returned. Otherwise tt(true) is returned. The pseudo code for using this member is identical to the pseudo code for using the abovementioned tt(wait_for) member (albeit that tt(pred) must also be passed to tt(wait_for), of course). itb(std::cv_status wait_until(std::chrono::time_point const &absTime)) This member has been implemented as a member template. tt(Clock) defines the clock-type to use (usually tt(std::chrono::system_clock)), tt(Duration) is the type name of a duration type (as used with tt(wait_for)). E.g., to specify 5 seconds after the current time this member could be called like this: verb( std::chrono::system_clock::now() + std::chrono::seconds(5) ) The running thread should have obtained a lock on bf(SharedCondition) prior to calling this member, and should release the lock after this member has returned. This member acts like tt(wait_for(relative-time)), returning tt(std::cv_status::no_timeout) if a notification was received before tt(absTime) has passed. Otherwise tt(std::cv_status::timeout) is returned. The pseudo code for using this member is identical to the pseudo code for using the abovementioned tt(wait_for(relative-time)) member (albeit that absolute time must be specified). itb(bool wait_until(std::chrono::time_point const &absTime, Predicate pred)) This member was implemented as a member template. tt(Clock) and tt(Duration) define identical types as mentioned at the previous member. tt(Predicate) either is a predicate function or a predicate function object (not expecting arguments). The running thread should have obtained a lock on bf(SharedCondition) prior to calling this member, and should release the lock after this member has returned. As long as tt(pred) returns false, tt(wait_until(absTime)) is called. If the latter function returns tt(std::cv_status::timeout), then tt(pred) is called, and its return value is returned. Otherwise tt(true) is returned. The pseudo code for using this member is identical to the pseudo code for using the abovementioned tt(wait_until) member (albeit that tt(pred) must also be passed to tt(wait_until), of course). ) manpagesection(STATIC MEMBER FUNCTIONS) itemization( itb(SharedCondition &attach(SharedMemory &shmem, std::ios::off_type offset = 0, std::ios::seekdir origin = std::ios::beg)) The tt(SharedCondition) object interfacing to the shared condition variable located at tt(offset) (relative to tt(origin)) in tt(shmem) is returned. An tt(FBB::Exception) is thrown if the requested offset is invalid (i.e., smaller than 0 or exceeding tt(shmem.maxOffset())). itb(FBB::SharedCondition create(SharedMemory &shmem)) A shared condition variable is initialized at the current offset of the tt(SharedMemory) object referred to by tt(shmem), or at the first offset of the next physical shared data segment. A bf(SharedCondition) object interfacing to the initialized shared condition variable is returned. An tt(FBB::Exception) is thrown if there isn't enough memory available in the tt(SharedMemory) object to define a shared condition variable. itb(size_t size() const) Returns the size in bytes of the shared condition variables stored in tt(SharedMemory) objects. ) manpagesection(EXAMPLE) verbinclude(../../sharedcondition/driver/driver.cc) manpagefiles() em(bobcat/sharedcondition) - defines the class interface manpageseealso() bf(bobcat)(7) bf(isharedstream)(3bobcat), bf(osharedstream)(3bobcat), bf(sharedblock)(3bobcat), bf(sharedmemory)(3bobcat), bf(sharedpos)(3bobcat), bf(sharedreadme)(7bobcat), bf(sharedsegment)(3bobcat), bf(sharedstream)(3bobcat), bf(sharedbuf)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/osharedstream.yo0000644000175000017500000002004614050437223020744 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::OSharedStream)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (std::ostream on shared memory) manpagename(FBB::OSharedStream)(std::ostream operations on shared memory) manpagesynopsis() bf(#include )nl() Linking option: tt(-lpthread -lbobcat) manpagedescription() This class offers the features of the bf(std::ostream) class, operating on shared memory. includefile(include/namespace) manpagesection(INHERITS FROM) bf(FBB::OSharedBuf) (private inheritance),nl() bf(std::ostream),nl() bf(FBB::SharedEnum__) (cf. bf(sharedmemory(3bobcat)) for a description of this last base class). manpagesection(SIZEUNIT ENUMERATION) The bf(enum SizeUnit) defines the following symbolic constants: itemization( it() bf(kB), representing 1024 (2**10) bytes of memory; it() bf(MB), representing 1048576 (2**20 bytes of memory; it() bf(GB), representing 1073741824 (2**30) bytes of memory ) manpagesection(CONSTRUCTORS) itemization( itb(OSharedStream()) The default constructor defines a stub a bf(OSharedStream) object that cannot immediately be used to access shared memory. To use it, its member tt(open) must first be called. itb(OSharedStream(size_t maxSize, SizeUnit sizeUnit, std::ios::openmode openMode = std::ios::out, size_t access = 0600)) This constructor creates an tt(std::ostream) that interfaces to a shared memory segment having a capacity of at least tt(maxSize * sizeUnit) bytes. By default, the shared memory segment is opened for writing. The shared memory's access rights are defined by the tt(access) parameter, using the well-known (bf(chmod)(1)) way to define the access rights for the owner, the group and others, using octal digits. If construction succeeds the shared memory is ready for use. If construction fails, an tt(FBB::Exception) is thrown. itb(OSharedBuf(int id, std::ios::openmode openMode = std::ios::out | std::ios::in)) This constructor creates an tt(std::istream) that connects to a shared memory segment having ID tt(id). If construction succeeds the shared memory is ready for use. If construction fails (e.g., no shared memory segment having ID tt(id) exists), an tt(FBB::Exception) is thrown. ) Copy and move constructors (and assignment operators) are not available. manpagesection(MEMBER FUNCTIONS) All members of tt(std::istream) and tt(std::ostream) and the tt(enum) values tt(kB, MB), and tt(GB), defined by tt(FBB::OSharedEnum__) are available. itemization( itb(FBB::SharedCondition attachSharedCondition(std::ios::off_type offset, std::ios::seekdir origin)) Returns an bf(FBB::SharedCondition)(3) object, interfacing to a shared condition variable located at offset tt(offset) (relative to tt(origin)) in the tt(SharedMemory) object to which the bf(OSharedStream) object interfaces. This member does not alter the value returned by the stream's tt(tellp) member. An tt(FBB::Exception) is thrown if the tt(FBB::SharedCondition) object could not be constructed. itb(FBB::SharedCondition createSharedCondition()) Returns an bf(FBB::SharedCondition)(3) object, interfacing to a newly created shared condition variable which is created at the current offset of the tt(SharedMemory) object to which the bf(OSharedStream) object interfaces (or at the first offset of the next physical shared memory data block, cf. bf(sharedcondition)(3bobcat))). Creating a tt(SharedCondition) object does not alter the value returned by the stream's tt(tellp) member. An tt(FBB::Exception) is thrown if the tt(FBB::SharedCondition) object could not be constructed. itb(int id() const) The ID of the shared memory segment is returned. itb(void kill()) Without locking the shared memory first, all shared memory is returned to the operating system. The bf(FBB::OSharedStream) object is unusable after returning from tt(kill). Other processes that were using the shared memory can continue to do so. itb(void memInfo(std::ostream &out, char const *end = "\n")) Information about the tt(OSharedMemory) object is inserted into the provide tt(ostream) object. The IDs of the shared segments, their sizes, the maximum number of shared memory segments, the number of bytes that can be read from the shared memory, and its actual storage capacity, etc., are displayed. Following the information about the shaed memory, tt(end) is inserted into tt(out). itb(void open(size_t maxSize, SizeUnit sizeUnit, std::ios::openmode openMode = std::ios::out, size_t access = 0600)) This member creates a shared memory segment having a capacity of at least tt(maxSize * sizeUnit) bytes, and connects the shared memory segment to the bf(FBB::OSharedStream). A matching tt(close) member does not exist and is not required. By default, the shared memory segment is opened for reading. Different from the open modes used for file streams, creating a shared memory stream with open modes tt(ios::in) is OK. In this case the shared memory segment is created and once information has been written to the shared memory by another process it can be read. The shared memory's access rights are defined by the tt(access) parameter, using the well-known (bf(chmod)(1)) way to define the access rights for the owner, the group and others, using octal digits. If opening succeeds the shared memory is ready for use. If opening fails, an tt(FBB::Exception) is thrown. itb(void open(int id, std::ios::openmode openMode = std::ios::in | std::ios::out)) This member connects the bf(FBB::OSharedStream) object to a shared memory segment having ID tt(id). A matching tt(close) member does not exist and is not required. If opening succeeds the shared memory is ready for use. If opening fails (e.g., no shared memory segment having ID tt(id) exists), an tt(FBB::Exception) is thrown. itb(void remove()) The shared memory is first locked. Next, all shared memory is returned to the operating system. The bf(FBB::OSharedStream) object is unusable after returning from tt(remove). Other processes that were using the shared memory can continue to do so. itb(bool truncate(std::streamsize offset)) If tt(offset) is not exceeding the value returned by tt(seekp(0, std::ios::end)) this latter value is changed to tt(offset) and tt(true) is returned. Otherwise tt(false) is returned, and the value returned by tt(seekp) is not altered. If the value returned by tt(tellp) exceeded tt(offset), tt(tellp)'s return value is reduced to tt(offset) as well. ) manpagesection(EXAMPLE) See the bf(sharedstream)(3bobcat) man page. manpagefiles() em(bobcat/osharedstream) - defines the class interface manpageseealso() bf(bobcat)(7), bf(chmod)(1), bf(isharedstream)(3bobcat), bf(sharedblock)(3bobcat), bf(sharedcondition)(3bobcat), bf(sharedmemory)(3bobcat) bf(sharedmutex)(3bobcat), bf(sharedpos)(3bobcat), bf(sharedreadme)(7bobcat), bf(sharedsegment)(3bobcat), bf(sharedstream)(3bobcat), bf(sharedbuf)(3bobcat) manpagebugs() Note that by default exceptions thrown from within a bf(std::stream) object are caught by the stream object, setting its tt(ios::failbit) flag. To allow exceptions to leave a stream object, its tt(exceptions) member can be called, e.g., using: verb( myStream.exceptions(ios::failbit | ios::badbit | ios::eofbit); ) includefile(include/trailer) bobcat-5.09.01/documentation/man/iobuf.yo0000644000175000017500000001074014050437223017207 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::IOBuf)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Streambuf doing I/O) manpagename(FBB::IOBuf)(streambuf allowing input and output operations) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() This class implements a specialization of the bf(std::streambuf) class, allowing input operations from and output operations to different files. It is intended to be used in combination with bf(FBB::IOStream), thus allowing all stream-based input and output operations using the same object without the need to use em(seek)-operations. Using an bf(FBB::IOStream) object it is, e.g., possible to construct two-way communications using pipes, much like the facilities offered by sockets. If the streams that will be associated with the bf(IOBuf) object support seeking, then the bf(IOBuf) will do so to. Seeking might also be available for a single stream (either the bf(std::istream) or the bf(std::ostream)). When the bf(IOBuf) object goes out of scope, its associated bf(std::ostream) object is flushed. includefile(include/namespace) manpagesection(INHERITS FROM) bf(std::streambuf) manpagesection(CONSTRUCTORS) itemization( itb(IOBuf()) The default constructor results in a bf(IOBuf) object that cannot be immediately used. Its member bf(open()) must be called first. itb(IOBuf(std::istream &in, std::ostream &out)) This constructor associates the bf(IOBuf) object with a bf(std::istream) and a bf(std::ostream). All output operations will be passed on to the bf(std::ostream), all input operations to the bf(std::istream). The streams passed to bf(IOBuf()) should outlive the bf(IOBuf) object. ) Copy and move constructors (and assignment operators) are not available. manpagesection(MEMBER FUNCTIONS) All members of bf(std::streambuf) are available, as bf(FBB::IOBuf) inherits from these classes. itemization( itb(void open(std::istream &in, std::ostream &out)) This member (re)associates the bf(IOBuf) object with a bf(std::istream) and a bf(std::ostream). All output operations will be passed on to the bf(std::ostream), all input operations to the bf(std::istream). The streams passed to bf(IOBuf()) should outlive the bf(IOBuf) object. If this member is called for an bf(IOBuf) object already associated with an bf(std::ostream) object, the already associated bf(std::ostream) object is flushed before setting up the new association. ) manpagesection(VIRTUAL PROTECTED MEMBER FUNCTIONS) The following bf(std::streambuf) member functions should only be called when the bf(FBB::Streambuf) object is associated with bf(std::istream) and bf(std::ostream) objects (i.e., they should not be called between the construction of a default bf(FBB:IOBuf) object and a subsequent call of bf(IOBuf::open())): The members listed in this section implement the tasks of comparably named virtual function in the class's private interface. This separates the redefinable interface from the user-interface. The class bf(IOStreamBuf) can, in accordance with Liskov's Substitution Principle, be used as a tt(std:streambuf); but it also offers facilities for classes deriving from bf(IOStreamBuf). These facilities are listed here. itemization( itb(pos_type pSeekoff(off_type offset, std::ios::seekdir way, std::ios::openmode mode = std::ios::in | std::ios::out)) With seekable streams, repositions the associated bf(std::istream) or bf(std::ostream) is repositioned to offset tt(offset), relative to tt(way). itb(pos_type pSeekpos(off_type offset, std::ios::openmode mode = std::ios::in | std::ios::out)) With seekable streams, repositions the associated bf(std::istream) or bf(std::ostream) is repositioned to offset tt(offset), relative to itb(std::streamsize pXsputn(char const *buffer, std::streamsize n)) This member inserts tt(n) characters from tt(buffer) into the associated bf(std::ostream) stream. ) manpagesection(EXAMPLE) See the example provided with bf(process)(3bobcat). manpagefiles() em(bobcat/iobuf) - defines the class interface manpageseealso() bf(bobcat)(7), bf(iostream)(3bobcat), bf(process)(3bobcat) manpagebugs() None reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/indent.yo0000644000175000017500000000625414050437223017371 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Indent)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Text Indentation) manpagename(FBB::Indent)(Configurable text indentation) manpagesynopsis() bf(#include )nl() manpagedescription() bf(FBB::Indent) and its various manipulators offer text-indentation. Text inserted into streams is indented over a fully configurable amount using a set of manipulators and (static) member functions. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(STATIC MEMBER FUNCTIONS) itemization( itb(void clear()) Resets the indentation level to zero. The bf(indent) manipulator will have no visible effect after calling this member. itb(void dec()) Reduces the indentation level by the current increment (4 by default). The indentation level is never reduces to a negative value. itb(void inc()) Increments the indentation level by the current increment (4 by default). itb(void setInc(size_t inc)) Defines the increment value used with the bf(dec) and bf(inc) members. itb(void setWidth(size_t width)) Defines the indentation to a specific value bf(width). ) manpagesection(MANIPULATORS) The following manipulators (which are em(not) part of the bf(FBB::Indent), class, but em(are) defined in the bf(FBB) namespace) can be inserted into the bf(FBB::Indent) object: itemization( itb(FBB::decindent) This manipulator will first call bf(Indent::dec). Then bf(FBB::indent) is called. The effect will be that the indentation level is reduced just before the indentation is inserted. itb(FBB::incindent) This manipulator will first call bf(Indent::inc). Then bf(FBB::indent) is called. The effect will be that the indentation level is incremented just before the indentation is inserted. itb(FBB::indent) This manipulator will insert the currently defined number of indentation blanks into the tt(ostream) for which it it called. itb(FBB::indentdec) This manipulator will first call bf(FBB::indent), Then bf(Indent::dec) is called. The effect will be that the indentation is inserted first, immediately followed by a reduction of the indentation level. itb(FBB::indentinc) This manipulator will first call bf(FBB::indent), Then bf(Indent::inc) is called. The effect will be that the indentation is inserted first, immediately followed by a increment of the indentation level. itb(FBB::nlindent) This manipulator will insert a newline character (tt(\n)). Then bf(FBB::indent) is called, indenting the next line over the currently defined number of blanks. ) manpagesection(EXAMPLE) verb( using namespace std; using namespace FBB; int main() { cout << indentinc << "Not indented" << nlindent << "Indenting with 4 blanks\n"; Indent::clear(); cout << "No indentation\n"; } ) manpagefiles() em(bobcat/indent) - defines the class interface manpageseealso() bf(bobcat)(7) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/datetime.yo0000644000175000017500000007571114050437223017710 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::DateTime)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Date and Time) manpagename(FBB::DateTime)(Performs Date and Time Computations) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() bf(FBB::DateTime) objects contain and represent date and time values. Individual date and time fields can be requested or modified, returning `sanitized' times (e.g., a date like March 33 or a time like 56 hours are never returned; instead the next month or day is returned). Times may be specified in local time (according to the computer's idea of what the local time is), in em(Universal Time Coordinated) (tt(UTC)) time values, as a time in a named timezone, or as a time in a user-defined timezone. Refer to the section bf(TIMEZONES) below for a detailed description of how timezones can be specified. Dates/times represented by tt(DateTime) objects may be modified by adding, subtracting, or setting (tt(std::chrono)) seconds, minutes, or hours, or by specifying (a selection of) fields of tt(tm structs). Date/time modificationsthese are always performed relative to the tt(DateTime) object's current timezone (which may be tt(UTC), local or another timezone). Conversions between timezones (including the tt(UTC) `timezone') are also supported. tt(DateTime) objects can be constructed in many ways. Dates and times may be specified as UTC time, as local time, as (tt(std::chrono::minutes)) shifts with respect to UTC time, or as a date and time in other (user defined) time zones. Negative time offsets refer to timezones West of Greenwich, and positive offsets refer to timezones East of Greenwich: these offsets represent the zones' local time differences with UTC time. Timezone offsets are always computed modulo 12 hours, as timezones may at most differ 12 hours from UTC. tt(DateTime) objects always contain date and time points in seconds since the beginning of the `epoch' (midnight Jan 1, 1970 UTC). The bf(C) function bf(time)(2) returns this value for the current date and time (assuming that the computer's clock has properly been synchronized). Daylight Saving Time (DST), when defined for tt(DateTime) objects' zones is automatically applied when DST is active. E.g., when a tt(DateTime) object's time represents 12:00 hr., and it zone's DST (using a standard +1 hour shift) becomes active tomorrow, then the object's time shows 13:00 hr. when 1 day is added to its current date/time. Handling time is complex. The bf(C) function bf(time)(2) returns the time in seconds since the beginning of the epoch. Beyond that, simplicity ends, and the reader is referred to Eric S. Raymond's (2007) coverage of the complexities of handling time: see lurl(http://www.catb.org/esr/time-programming) (this document is also included in bobcat's repository). manpagesection(TIMEZONES) tt(DateTime's) nested class tt(Zone) is used to specify time zones. Time zones have various configurable components: itemization( it() The time shift itself. E.g., Central European Time (CET) uses a shift of one hour: when UTC time is noon, then it's 13:00 h. CET. The time shift doesn't have to be multiples of full hours. E.g., India uses a time shift of +5:30 h relative to UTC. it() Maybe a Daylight Saving Time. Most timezones use a +1 hour DST shift: when in the previous example DST is active then CET's local time is 14:00 h. Some countries do not use DST shifts. E.g., Afghanistan doesn't use a DST shift. it() A date-interval in which the DST is used may be standard. E.g., it starts at 02:00 h. (local time, becoming 03:00 DST), the last Sunday in March, and ends at 02:00 h. (local time, resetting DST 03:00 to 02:00) the last Sunday in October. it() Other calendar intervals may apply. E.g., in 2019 New Zealand's DST starts September 29, and ends April 7th. it() In practice, DST shifts are equal to 1 hour, although there's no formal requirement for that. ) tt(DataTime::Zone's) class offers a variety of means for specifying time zones with or without support for DST. Time shifts can be positive or negative and are specified in hours and optionally minutes. E.g., -8 or -8:00 for a timezone 8 hours earlier than UTC (noon at UTC becomes 04:00 in this timezone) or +5:30 for a time zone later than UTC (noon at UTC becomes 17:30 in that timezone). Timezones can be given names (which may or may not be the names of the `standard' time zones like CET or PST) but can also be constructed by providing itemization( it() a mere shift relative to UTC, no DST. it() a shift relative to UTC, using a standard DST (1 hour) time shift. In this case the computer's idea of the calendar interval in which DST is active is used; it() a shift relative to UTC, using a specified DST time shift as well as a specified calendar interval, optionally specifying the time when the DST calendar interval starts and/or ends. ) includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(ENUMS) The class tt(DateTime) defines the following enums: bf(DateTime::Month)nl() This enumeration has the following values which are ordered using the default bf(C++) tt(enum) values: itemization( it() bf(JANUARY), it() bf(FEBRUARY), it() bf(MARCH), it() bf(APRIL), it() bf(MAY), it() bf(JUNE), it() bf(JULY), it() bf(AUGUST), it() bf(SEPTEMBER), it() bf(OCTOBER), it() bf(NOVEMBER), it() bf(DECEMBER). ) Standard 3-letter abbreviations can also be used (e.g., tt(DateTime::Jul)): itemization( it() bf(Jan), it() bf(Feb), it() bf(Mar), it() bf(Apr), it() bf(May ), it() bf(Jun), it() bf(Jul), it() bf(Aug), it() bf(Sep), it() bf(Oct), it() bf(Nov), it() bf(Dec). ) bf(DateTime::Relative)nl() This enumeration is used with the tt(setMonth()) member (see below). It has the following values: itemization( it() bf(THIS_WEEK), it() bf(THIS_YEAR), it() bf(LAST), it() bf(NEXT) ) bf(DateTime::TimeFields)nl() This enumeration has the following values which can be tt(bit_or)-ed when calling the member tt(setFields()): itemization( it() bf(SECONDS) it() bf(MINUTES) it() bf(HOURS) it() bf(MONTHDAY) it() bf(MONTH) it() bf(YEAR) ) bf(DateTime::TimeType)nl() This enumeration has the following values: itemization( it() bf(LOCALTIME): the tt(DateTime) object's date and time use a shift relative to UTC according to the object's configured time zone. it() bf(UTC): the object's date and time represent the Universal Time Coordinated. ) bf(DateTime::Weekday)nl() This enumeration has the following values which are ordered using the default bf(C++) tt(enum) values: itemization( it() bf(SUNDAY), it() bf(MONDAY), it() bf(TUESDAY), it() bf(WEDNESDAY), it() bf(THURSDAY), it() bf(FRIDAY), it() bf(SATURDAY). ) Standard 3-letter abbreviations can also be used (e.g., tt(DateTime::Wed)): itemization( it() bf(Sun), it() bf(Mon), it() bf(Tue), it() bf(Wed), it() bf(Thu), it() bf(Fri), it() bf(Sat). ) manpagesection(TEXTUAL TIME REPRESENTATIONS) tt(DateTime) objects may also be defined using textual time-representations. In addition, the date/time represented by tt(DateTime) objects may be altered using textual time representations extracted from tt(istreams). The following time formats (shown by example) are recognized: itemization( itt(Mon Dec 3 13:29:11 2018), as displayed by tt(put_time(..., "%c")); itt(Mon Dec 3 13:29:11 CET 2018), as displayed by the bf(date)(1) program. When this format is used the specified zone name must have been defined. tt(CET) is defined by default, other time zones can easily be defined using, e.g., the member tt(DateTime::Zone::read) (see section bf(ZONE MEMBERS)). itt(Mon, 03 Dec 2018 13:29:11 +0100), as displayed by the tt(date -R) command (and the tt(rfc2822()) member, see below); itt(2018-12-03 13:29:11+01:00), as displayed by the tt(date --rfc-3339=seconds) command. ) manpagesection(ZONE CONSTRUCTORS) The class tt(DateTime::Zone) defines how time zones can be defined and used. Time zone objects are expected by several tt(DateTime) constructors and by the tt(DateTime::setZone) member. The class tt(DateTime::Zone) supports the following constructors: itemization( itb(Zone(std::string const &name)) The argument tt(name) refers to a predefined zone name. By default the zone tt(CET) is available. Other zone names can be defined using the members tt(DateTime::Zone::read) and tt(DateTime::Zone::store); itb(Zone(std::string const &specification)) The argument tt(specification) refers to a zone specification that's available under the directory referred to by tt(/etc/localtime) (e.g., tt(/usr/share/zoneinfo)). The specification must start with a colon, followed by the name of an entry that is found below tt(/usr/share/zoneinfo). E.g, to specify the tt(Europe/Amsterdam) zone use tt(DateTime::Zone{ ":Europe/Amsterdam" }). If the specified zone uses DST then a +1 hour DST shift is used; itb(Zone(std::string const &shift)) The argument tt(shift) defines the zone's shift in hours and minutes relative to UTC. Shift's format is tt([+-]hh[:mm]), where negative time shifts refer to time zones West of Greenwich and positive time shifts to time zones East of Greenwich. No DST is used; itb(Zone(std::string const &shift, string const &dstSpec)) The argument tt(shift) defines the zone's shift in hours and minutes relative to UTC. Shift's format is tt([+-]hh[:mm]), where negative time shifts refer to time zones West of Greenwich and positive time shifts to time zones East of Greenwich. The tt(dstSpec) argument defines the time shift to use when DST is active. It uses the same format as tt(shift), or tt(=) may be specified, in which case the (standard) DST shift of +1:00 hour is used; itb(Zone(std::string const &shift, std::string const &dstSpec, std::string const &beginDST, std::string const &endDST)) Like the previous constructor, but in addition tt(beginDST) and tt(endDST) are used to define the date/time interval in which the DST is active. These arguments use the following format: verb( Mon, weekSpec Day [hh[:mm]] ) For tt(Mon) a standard 3-letter month specification is used, like tt("Jan") for January, for tt(Day) a standard 3-letter day specification is used, like tt("Sun") for Sunday (cf. the standard 3-letter abbreviations listed in the section tt(ENUMS)). The tt(weekSpec) defines the number of the week of the month containing tt(Day). Use tt(1st, 2nd, 3rd, 4th, 5th) or tt(last). Here, tt(1st) refers to the first week having day tt(Day), while tt(last) and tt(5th) refer to the last week (so not necessarily the 5th week) having day tt(Day). The time specification defines the time when the DST starts or ends. Some examples: verb( Mar, last Sunday 02:00 Oct, 1st Monday 03:00 ) ) Copy and move constructors as well as assignment operators are available. manpagesection(ZONE MEMBERS) itemization( itb(std::string const &spec() const) The constructors' zone specifications are converted to a form recognized by the function bf(tzset)(3). This member returns the converted string; itb(int dstSeconds() const) If DST is active for a local date/time point then the DST shift in seconds is returned by this member. Use the member tt(DateTime::dst()) to determine whether or not DST is active. itb(int zoneSeconds() const) The zone's time shift relative to UTC in seconds. Negative values represent zone shifts West of Greenwich, positive values represent zone shifts East of Greenwich. ) manpagesection(ZONE STATIC MEMBERS) itemization( itb(DateTime::Zone const &DateTime::Zone::get(std::string const &name)) The time zone object named tt(name) is returned. E.g., to retrieve the time zone object for tt(CET) use tt(DateTime::Zone::get("CET")). If the named zone has not been defined an tt(std::exception) is thrown; itb(DateTime::Zone const &DateTime::Zone::store(std::string const &name, ...)) A time zone object is defined and stored as zone tt(name). Zone names must consists of (at least three) letters. The ellipsis should be replaced by the arguments of the tt(Zone) constructors (except for the arguments of the first, copy, and move constructors). A reference to the newly defined tt(Zone) object is returned; itb(std::string const &DateTime::Zone::defaultTZ()) The TZ specification that is active when the program using tt(DateTime) objects starts. It returns the return value of tt(getenv("TZ")) or an empty string if the tt(TZ) environment variable was not defined; itb(void DateTime::Zone::read(std::string const &fname)) Time zone specifications as expected by the above tt(store) member are read from the file named tt(fname) (one specification per line, using blanks between the elements, and inserting tt(until) between the tt(dstBegin) and tt(dstEnd) specifications (if provided)). For cosmetic reasons a colon may be appended to zone names. Examples: verb( ccu: +5:50 nyc: -5:00 +1:00 cal: -8:00 = eet: +2:00 +1:00 Mar, last Sun 02:00 until Oct, last Sun 02:00 same: +2:00 = Mar, last Sun 02:00 until Oct, last Sun 02:00 ) If the first character on a line is a hash-tag (tt(#)) or if a line only contains blanks it is ignored; itb(time_t DateTime::Zone::thisZoneShift()) Returns this computer's zone shift in seconds. ) manpagesection(DATETIME CONSTRUCTORS) itemization( itb(DateTime(TimeType type = UTC)) The object's date/time is initialized to the current date and time. By default UTC time (no zone-shift or dst correction) is used. When specifying tt(LOCALTIME), the computer's timezone and DST correction are used; itb(DateTime(std::chrono::minutes zoneMinutes)) The object's local time is initialized to the current UTC time to which a zone shift of zoneMinutes minutes is added. DST is not used. Note that by specifying a zone shift in, e.g., tt(std::chrono::hours) a conversion to minutes is automatically applied; itb(DateTime(Datetime::Zone const &zone)) The object's local time is initialized to the the current UTC time to which a zone shift defined by the tt(Zone) argument is added; itb(DateTime(time_t time, TimeType type = UTC)) The object uses tt(time) to set its UTC time in seconds since the epoch. When tt(LOCALTIME) is specified its local time is obtained by applying the computer's timezone and DST correction; itb(DateTime(time_t time, std::chrono::minutes zoneMinutes)) The object's uses tt(time) to set its UTC time in seconds since the epoch. Its local time is then obtained by adding a zone shift of zoneMinutes minutes. DST is not used.; itb(DateTime(time_t time, Datetime::Zone const &zone)) The object's uses tt(time) to set its UTC time in seconds since the epoch. Its local time is then obtained by adding a zone shift as defined by the tt(Zone) argument. itb(DateTime(tm const &ts, TimeType type = UTC)) The tt(tm) argument is a struct defined as: verb( struct tm { int tm_sec; // seconds 0..59, or 60: leap second int tm_min; // minutes 0..59 int tm_hour; // hours 0..23 int tm_mday; // day of the month 1..31 int tm_mon; // month 0..11 int tm_year; // year see below!! int tm_wday; // day of the week 0..6 int tm_yday; // day in the year 0..365 int tm_isdst; // daylight saving time // > 0: yes, 0: no, < 0: unknown }; ) Values outside of these ranges may be specified to compute points in time in the future or in the past. E.g., tt(tm_hour == 30) is normalized to tt(tm_hour == 6) of the next day. Note that functions like bf(mktime)(3) expect tt(tm_year) to be specified relative to 1900. The tt(DateTime) constructor does em(not) expect this: the tt(tm_year) field should be the specified as the (calendar) year, e.g., 2019. Using tt(tm's) fields the object's date/time is initialized to either UTC or LOCALTIME. The DST, day of the year, and day of the week fields of the tt(tm) argument are ignored; itb(DateTime(tm const &ts, Datetime::Zone const &zone)) The fields of tt(ts) (see the previous constructor) define a tt(LOCALTIME) time point in the specified tt(Zone). itb(DateTime(std::string const &timeStr, TimeType type = UTC)) The object's date/time is initialized to either UTC or LOCALTIME using tt(DateTime's) supported textual time representations. The time representation without explicit timezone shift (e.g., tt(Mon Dec 3 13:29:11 2018) is interpreted as UTC time when tt(type == UTC) is specified, otherwise as local time (tt(type == LOCALTIME)), using the computer's time zone and DST correction). The other textual time representations provide zone specifications which are used to obtain the requested time representation (e.g., when UTC is requested, and the textual time specification contains tt(13:29:11 +0100) then the object's (UTC) time is set to tt(12:29:11)). DST specifications are ignored, except when named time zones are used, as in tt(on Dec 3 13:29:11 CET 2018); itb(DateTime(std::istream &in, TimeType type = UTC)) The object's date/time is initialized to either UTC or LOCALTIME extracting a supported textual time representation from tt(in) as destribed at the tt(DateTime(std::string const &timeStr, ...)) constructor. The tt(std::istream &in) stream may also be a rvalue reference. ) Copy and move constructors are available. manpagesection(OVERLOADED OPERATORS) All class-less overloaded operators are defined in the tt(FBB) namespace. All overloaded operators modifying tt(DateTime) objects support `commit or roll-back': if the operation cannot be performed an exception is thrown, without modifying the destination object. itemization( itb(std::ostream &std::operator<<(std::ostream &str, DateTime const &dt)) Inserts tt(dt's) date/time into tt(str) using the zone-less supported textual time representation (e.g., tt(Mon Dec 3 13:29:11 2018)); itb(std::istream &std::operator>>(std::istream &str, DateTime &dt)) Extracts a supported textual time representation from tt(str) and assigns the implied date/time point to tt(dt); itb(bool operator==(DateTime const &left, DateTime const &right)) Returns tt(true) if tt(left) represents the same UTC time as tt(right); itb(bool operator!=(DateTime const &left, DateTime const &right)) Returns tt(true) if tt(left) represents a different UTC time as tt(right); itb(bool operator<(DateTime const &left, DateTime const &right)) Returns tt(true) if tt(left) represents an earlier UTC time as tt(right); itb(bool operator<=(DateTime const &left, DateTime const &right)) Returns tt(true) if tt(left) represents an earlier or equal UTC time as tt(right); itb(bool operator>(DateTime const &left, DateTime const &right)) Returns tt(true) if tt(left) represents a later UTC time as tt(right); itb(bool operator>=(DateTime const &left, DateTime const &right)) Returns tt(true) if tt(left) represents a later or equal UTC time as tt(right). itb(DateTime operator+(DateTime const &obj, std::chrono::seconds seconds)) Returns a copy of tt(obj) to which tt(seconds) were added; itb(DateTime operator+(DateTime const &obj, tm const &ts)) Returns a copy of tt(obj) to which the tt(tm_sec, tm_min, tm_hour, tm_mday, tm_mon) and tt(tm_year) fields of tt(ts) were added; Caveat: note that this is an em(addition) operation: if you want to add 1 year specify tt(ts.tm_year = 1), and not the finally expected calendar year! itb(DateTime &operator+=(std::chrono::seconds seconds)) Adds tt(seconds) to the time represented by the current object; itb(DateTime &operator+=(tm const &ts)) Adds the tt(tm_sec, tm_min, tm_hour, tm_mday, tm_mon) and tt(tm_year) fields of tt(ts) to the time represented by the current object. Caveat: note that this is an em(addition) operation: if you want to add 1 year specify tt(ts.tm_year = 1), and not the finally expected calendar year! itb(DateTime operator-(DateTime const &obj, std::chrono::seconds seconds)) Returns a copy of tt(obj) to which tt(seconds) were subtracted; itb(DateTime operator-(DateTime const &obj, tm const &ts)) Returns a copy of tt(obj) to which the tt(tm_sec, tm_min, tm_hour, tm_mday, tm_mon) and tt(tm_year) fields of tt(ts) were subtracted. Caveat: note that this is an em(addition) operation: if you want to subtract 1 year specify tt(ts.tm_year = 1), and not the finally expected calendar year! itb(DateTime &operator-=(std::chrono::seconds seconds)) Subtracts tt(seconds) from the time represented by the current object; itb(DateTime &operator-=(tm const &ts)) Subtracts the tt(tm_sec, tm_min, tm_hour, tm_mday, tm_mon) and tt(tm_year) fields of tt(ts) from the time represented by the current object. Caveat: note that this is an em(addition) operation: if you want to subtract 1 year specify tt(ts.tm_year = 1), and not the finally expected calendar year! E.g., the following program fragment displays midnight, December 31, 1969: verbinsert(//info ../../datetime/driver/midnight.cc) ) Copy and move assignment operators are available. manpagesection(MEMBER FUNCTIONS) All members returning a time-element do so according to the latest time-representation (i.e., tt(UTC), tt(LOCALTIME), or using an explicitly set display zone shift value). All members returning numeric values use 0 as their smallest return value, except for the bf(...Nr()) members, which start at 1. itemization( itb(bool dst() const) Returns tt(true) if the current object's time includes a DST shift, otherwise tt(false) is returned. itb(unsigned hours() const) Returns the number of hours represented by the current object's time (0-23); itb(unsigned minutes() const) Returns the number of minutes represented by the current object (0-59); itb(DateTime::Month month() const) Returns the tt(Month) represented by the current object; itb(unsigned monthDayNr() const) Returns the day number of the month represented by the current object's date (1-31); itb(string rfc2822() const) Returns the current object's date/time displayed according to the RFC 2822 format. This format is used, e.g., by the tt(date -R) command (cf. bf(date)(1)). For example: verb( Mon, 3 Dec 2018 13:49:10 +0100 ) itb(string rfc3339() const) Returns the current object's date/time displayed according to the the RFC 3339 format. This format is used, e.g., by the tt(date --rfc-3339=seconds) command (cf. bf(date)(1)). For example: verb( 2018-12-03 13:29:11+01:00 ) itb(unsigned seconds() const) Returns the number of seconds represented by the current object's time (0-59, but 60 and 61 may occur at leap seconds). Note that this member does not return the current UTC time in seconds (since the epoch): if that's required use the member tt(utcSeconds); itb(void setDay(int dayNr)) Assigns tt(dayNr) to the day number of the object's current month. Caveat: since day numbers start at 1, passing 0 or negative values to tt(setDay) results in resetting the objects date to an earlier month; itb(void setFields(tm const &ts, DateTime::TimeFields fields)) Assigns the fields of tt(ts) indicated by a tt(bit_or) combination of tt(TimeFields fields') value to the corresponding current object's date/time tt(tm) fields; itb(void setHours(int hours)) Assigns tt(hours) to the number of hours of the current object's time; itb(void setMinutes(int minutes)) Assigns tt(minutes) to the number of minutes of the current object's time; itb(void setMonth(int month)) Assigns tt(month) to the current object's month. January is represented by 0, December by 11. Smaller or larger values refer to previous or future years; itb(void setMonth(DateTime::Month month)) Assigns tt(month) to the current object's month; itb(void setMonth(DateTime::Month month, DateTime::Relative where = THIS_YEAR)) Assigns tt(month) to the current object's month. By default the month of the current year is updated (tt(where == THIS_YEAR)). Use tt(LAST) to ensure that the month is set before the current object's month (e.g., if the current month is tt(JUNE), then requesting tt(AUGUST, LAST) will decrement the object's year, but requesting tt(MAY, LAST) won't). Analogously, when specifying tt(DateTime::NEXT) the resulting month is set after the current object's month. Caveat: If the day number of the current month exceeds the number of days in the requested month, the object's month and day number are updated to the next month. E.g., if the current day number equals 31, and tt(NOVEMBER) is requested, then the object's date is updated to December 1; itb(void setSeconds(int seconds)) Assigns tt(seconds) to the number of seconds of the current object's time; itb(void setUTCseconds(time_t utcSeconds)) Assigns tt(utcSeconds) as the number of seconds since the epoch to the current object's UTC time; itb(void setWeekday(Weekday day, Relative where = NEXT)) Assigns tt(day) to the current object's day of the week. By default (tt(where == NEXT)) the day will be the next occurrence of tt(day) (maybe the current week, maybe in the next week: if the current day equals Monday and Friday is specified, the current week is used. If the current day equals Friday and Monday is requested the next week is used). By specifying tt(where = LAST) the day will be most recent occurrence of tt(day): if the current day equals Friday and Monday is requested, the current week is used). By specifying tt(where = THIS_WEEK) then tt(day) is selected in the current week; itb(void setYear(unsigned year)) Assigns tt(year) to the current object's date. Note that tt(year) is the actual calendar year, and not, e.g., the year relative to the beginning of the epoch or 1900; itb(void setZone(Datetime::Zone const &zone)) The current object's time zone is set to tt(zone). This does not alter the object's UTC time, but merely its time zone. If the object represented UTC time before calling tt(setZone) it will represent a local time after calling tt(setZone); itb(void swap(DateTime &other)) Swaps the current and other tt(DateTime) object; itb(DateTime thisTime() const) Returns a tt(DateTime) object using the current object's UTC time, applying the computer's default time zone; itb(tm const *timeStruct() const) Returns a pointer to the object's current tt(tm) representing its object's broken down time elements. If the object holds a local time the tt(tm) struct represents the local time (if applicable: including a DST shift), otherwise it represents UTC; itb(DateTime utc() const) Returns a copy of the current object representing its UTC time; itb(time_t utcSeconds() const) Returns the current object's (UTC) time in seconds since the epoch; itb(DateTime::Weekday weekday() const) Returns the current object's tt(Weekday) value; itb(unsigned weekNr() const) Returns the week number of the current object's date. Week numbers are numbers of complete weeks. If Jan 1st is a Sunday then the week numbers of Jan 1st through Jan 6th are returned as 1, otherwise the week numbers of Jan 1st through the date of the first Saturday of the year (which could very well be Jan 1st) are returned as 52; itb(unsigned year() const) Returns the year of the current object's date (note: this is the actual calendar year, not the year since the epoch or relative to 1900); itb(unsigned yearDay() const) Returns the day in the year of the current object's date. January 1st is returned as 0; itb(unsigned yearDayNr() const) Returns the day in the year of the current object's date. January 1 is returned as 1; itb(DateTime::Zone const &zone() const) Returns the current object's tt(Zone) object. ) manpagesection(STATIC MEMBER) itemization( itb(void tm2cout(char const *label, TM const &ts)) This static member is primarily used for debugging purposes. It displays the values of tt(ts's) fields, preceded by tt(label) and tt(": "). ) manpagesection(EXAMPLES) Many examples illustrating the use of tt(DateTime) objects are provided in the source archive's tt(bobcat/datetime/driver) directory. Here is an example: verbinclude(../../datetime/driver/accessors.cc) manpagefiles() em(bobcat/datetime) defines the class interface. manpageseealso() bf(bobcat)(7), bf(Exception)(3bobcat), bf(gmtime_r)(3), bf(localtime_r)(3), bf(mktime)(3), bf(time)(2), bf(tzset)(3),nl() bf(http://www.catb.org/esr/time-programming),nl() bf(https://www.timeanddate.com/time/dst/events.html) manpagebugs() See bobcat's changelog file for an overview of members that were discontinued at release 5.00.00.nl() The class tt(DateTime) assumes that bf(time)(2) returns the time in UTC.nl() English is used/expected when specifying named date components. includefile(include/trailer) bobcat-5.09.01/documentation/man/irandstream.yo0000644000175000017500000000446014050437223020416 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::IRandStream)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Random numbers istream) manpagename(FBB::IRandStream)(Istream producing random numbers) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() bf(FBB::IRandStream) objects may be used to extract random numbers in a given range from a stream. includefile(include/namespace) manpagesection(INHERITS FROM) bf(std::istream), nl() bf(FBB::RandBuffer) (private) manpagesection(CONSTRUCTORS) itemization( itb(IRandStream(int max)) This bf(FBB::IRandStream()) constructor initializes the random generator. The default seed (i.e., 1) for the bf(srand)(3) function is used, meaning that every new run of the program will generate the same sequence of random values. Another constructor (see below) is provided when this is not considered appropriate. Random values between 1 and tt(max) (inclusive) are returned. itb(IRandStream(int min, int max)) This bf(FBB::IRandStream()) constructor initializes the random generator. The default seed (i.e., 1) for the bf(srand)(3) function is used, meaning that every new run of the program will generate the same sequence of random values. Another constructor (see below) is provided when this is not considered appropriate. Random values between tt(min) and tt(max) (inclusive) are returned. itb(IRandStream(int min, int max, size_t seed)) This bf(FBB::IRandStream()) constructor initializes the random generator. The seed is used to initialize the random number generator. To start the random generator at some unpredictable point, tt(time(0)) could be used. Random values between tt(min) and tt(max) (inclusive) are returned. ) Copy and move constructors (and assignment operators) are not available. manpagesection(INHERITED MEMBERS) Since the class uses public derivation from bf(std::istream), all members of this class can be used. manpagesection(EXAMPLE) verbinclude(../../irandstream/driver/driver.cc) manpagefiles() em(bobcat/irandstream) - defines the class interface manpageseealso() bf(bobcat)(7), bf(randbuf)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/arg.yo0000644000175000017500000004450214050437223016657 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Arg)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Command Line Arguments) manpagename(FBB::Arg)(A singleton class interfacing command line arguments) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() Singleton class (see Gamma em(et al.), 1995) built around bf(getopt_long())(3). The class handles short- and long command-line options, includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(ENUMERATION) The bf(FBB::Arg::Type) enumeration is defined by the bf(FBB::Arg) class. It is used to specify whether or not long options require arguments. It defines the following values: bf(None, Required, Optional). itemization( it() bf(None): the long option does not use an argument; it() bf(Required): the long option requires an argument value; it() bf(Optional): the long option may optionally be provided with an argument value; ) These values are used when defining long options (like tt(--version)), which are defined as objects of the (nested) class bf(FBB::Arg::LongOption). manpagesection(THE NESTED CLASS FBB::Arg::LongOption) Long options are defined using objects of the nested class bf(FBB::Arg::LongOption). This class provides the following constructors: itemization( itb(FBB::Arg::LongOption(char const *name, FBB::Arg::Type type = FBB::Arg::None)) This constructor is used to define a long option for which no corresponding short option is defined. The parameter tt(name) is the name of the long option (without specifying the -- characters which are only required when specifying a long option when calling a program). itb(FBB::Arg::LongOption(char const *name, int optionChar)) This constructor is used to define a long option for which a corresponding short option is defined. The parameter tt(name) is the name of the long option (without specifying the -- characters which are only required when specifying a long option when calling a program). ) To define long options use the following procedure: itemization( it() First, construct an array verb( FBB::Arg::LongOption longOptions[] = { c1, c2, ..., cn }; ) Where tt(c1, c2, ..., cn) are tt(n) constructor invocations of bf(FBB::Arg::LongOption()) constructors it() Next, pass tt(longOptions, LongOptions + n) as arguments to an tt(Arg::initialize) member that supports long options. ) Objects of the class tt(LongOptions) are normally used internally by the tt(Arg) object, but they can also be used outside of the tt(Arg) object. For that situation the following members are available: itemization( itb(std::string const &longName() const) returns the tt(LongOption's) long option name; itb(int optionChar() const) returns the tt(LongOption's) option character (or one of the tt(Arg::Type) enumeration values if there is no option character associated with the tt(LongOption)). ) manpagesection(CONSTRUCTORS) Since the class tt(Arg) is a em(singleton) there are no public constructors. Instead, static members are available to initialize and to access the single bf(FBB::Arg) object. manpagesection(STATIC MEMBERS) All tt(initialize) members initialize the bf(FBB::Arg) singleton, and can only be called once. An exception is thrown when called multiple times. All tt(initialize) members return a reference to the initialized tt(Arg) singleton object. All tt(initialize) members define the parameters tt(argc) and tt(argv) which are interpreted as tt(main's) tt(argc) and tt(argv) parameters. When an tt(argv) element points to two consecutive dashes (tt(--)) then that element is ignored, and all of tt(argv's) subsequent elements are considered arguments instead of options. itemization( itb(FBB::Arg &Arg::initialize(char const *optstring, int argc, char **argv)) The parameter tt(optstring) is a null-terminated byte string (NTBS) optionally starting with a + character, but otherwise containing option characters. One or two colons may be postfixed to option characters: quote( itemization( it() a single colon (:) indicates that the option requires an option value. it() a double colon (::) indicates that the option has an optional argument. With short options the option value is considered absent unless it is attached to the short option (e.g., tt(-tvalue)). Long options optionally accepting arguments should always immediately be followed by an assignment character (=), immediately followed by the option's value (which must start with a non-blank character). E.g., tt(--value=) indicates an absent option value, tt(--value=text) indicates the option's value equals tt(text). If an option value itself contains blanks, it must be surrounded by single or double quotes (e.g., tt(-t'this value'), or tt(--text='this value')). The surrounding quotes are not part of the option's value. )) When tt(optstring's) first character is + then all non-specified options are considered arguments, appearing in the final arguments list at their current argument positions. E.g., when tt(optstring) is tt(+ab) and no long options are defined, then calling verb( prog -a -z -b -yvalue --long arg1 arg2 ) results in the member tt(argv) returning a vector containing the elements tt(-z, -yvalue, --long, arg1,) and tt(arg2). If tt(optstring's) first character isn't + and an undefined option is encountered then an exception is thrown. itb(FBB::Arg &Arg::initialize(int accept, char const *optstring, int argc, char **argv)) Acts like the previous member, but in addition defines the parameter tt(accept) specifying an option character from where all subsequent arguments and options are considered arguments. To ignore tt(accept) the value 0 (not the character '0') can be specified or an tt(initialize) members can be used that does not define an tt(accept) parameter. When arguments contain both an tt(accept) option and two consecutive dashes then the first one is interpreted, resulting in all remaining tt(argv) elements being interpreted as mere arguments. For example, when specifying tt(initialize('t', ...)) and calling verb( prog one -ttwo -c -- three ) then the member tt(argv) returns a vector containing the elements tt(one, -tttwo, -c, --), and tt(three) (see also the member tt(beyondDashes) below). itb(FBB::Arg &Arg::initialize(char const *optstring, Arg::LongOption const *const begin, Arg::LongOption const *const end, int argc, char **argv)) Acts like the first tt(Arg::initialize) member, but in addition defines two parameters specifying the range of elements of an array of tt(Arg::LongOption) objects specifying long options. The parameter tt(begin) points to the first element of the range, the parameter tt(end) points just beyond the last element of the range. E.g., after defining verb( FBB::Arg::LongOption longOptions[] = { c1, c2, ..., cn }; ) the arguments passed to tt(begin) and tt(end) could be specified as verb( initialize(..., longOptions, longOptions + size(longOptions), ...); ) itb(FBB::Arg &Arg::initialize(char accept, char const *optstring, LongOption const *const begin, LongOption const *const end, int argc, char **argv)) Acts like the previous tt(Arg::initialize) member, but in addition defines an tt(accept) parameter as defined by the second tt(Arg::initialize) member. itb(FBB::Arg &Arg::instance()) Once an tt(Arg::initialize) member has been called this member can be called from anywhere in the program (and it can be called multiple times), returning a reference to the initialized bf(Arg) object. If it is called before an tt(Arg::initialize) member has been called an exception is thrown. ) manpagesection(OVERLOADED OPERATOR) itemization( itb(char const *operator[](size_t idx) const) Returns tt(argument[idx]), after all options have been removed. It returns 0 if no tt(arg[x]) is available. The program's name (tt(argv[0])) is NOT counted here: index 0 refers to the first ARGUMENT, e.g., the program's tt(argv[1]). ) manpagesection(NON-STATIC MEMBER FUNCTIONS) itemization( itb(string const &argv0() const) Returns the program's name as specified by tt(argv[0]) (see also the member tt(basename)); itb(char const **argPointers() const) Returns tt(argv)-like set of pointers to all remaining arguments. Element tt(nArgs() + 1) is a 0-pointer. The first tt(nArgs()) elements point to the respective values of the NTBS arguments that were passed to the program, after having removed the options. The caller is responsible for returning the array of pointers returned by this member to the common pool, but the caller should not delete the NTBSs to which the pointers point as illustrated by the following two statements: verb( char const **ptr = Arg::instance().argPointers(); delete[] ptr; // don't delete ptr[idx] elements! ) itb(std::vector const &args() const) Returns a vector of strings containing all arguments after having removed all options. The program's name (tt(argv[0])) is NOT included here: its first element refers to the first ARGUMENT, e.g., the program's tt(argv[1]); itb(std::string const &basename() const) Returns the program's basename (i.e., tt(argv0()'s) value beyond the last directory separator); itb(std::vector::const_iterator begin() const) Returns the iterator to the program's first argument (i.e., tt(args().begin())). This member, in combination with the member tt(end), allows processing of all arguments by generic algorithms; itb(size_t beyondDashes() const) Returns the index of the first argument beyond the tt(--) argument or returns the index of the tt(accept) argument (whichever comes first) or returns tt(nArgs()) if no tt(--) or tt(accept) argument was encountered. See also the member tt(nArgs) below; itb(std::vector::const_iterator end() const) Returns the iterator pointing beyond the program's last argument (i.e., tt(args().end())). This member, in combination with the member tt(begin), allows processing of all arguments by generic algorithms; itb(void help() const) If the member tt(versionHelp) (see below) was called then this member calls the tt(usage) function that was passed to tt(versionHelp). If tt(versionHelp) has not been called (i.e., if no tt(usage) function has been specified) an exception is thrown; itb(size_t nArgs() const) Returns the number of arguments after having removed the options (i.e., it returns tt(args().size())). Note that the program's name is not counted here; itb(size_t nLongOptions() const) Returns the number of long options not having short option synonyms. Multiply specified long options are each counted; itb(size_t nOptions() const) Returns the number of specified single character options. If short options have long option synonyms, then these long option synonyms are counted as if they were specified as single character options. If single character options (or their long option synonyms) are multiply specified, then each specification is separately counted; itb(size_t option(int option) const) Returns the number of times `option' was specified (or its long option synonym, if defined); itb(size_t option(std::string const &options) const) Returns the number of times each of the options specified in the `option' argument were specified (or their long option synonyms). Note that each character in tt(options) must specify a single-character option; itb(size_t option(string *value, int option) const) Returns the number of times the provided option (or its long option synonym) was present. If the return value is non-zero then the value of the first occurrence of this option is stored in tt(*value), which is left untouched if `option' was not present. The parameter tt(value) may be initialized to 0 if the option does not have a value or if the option's value should not be stored; itb(size_t option(size_t idx, string *value, int option) const) Returns the number of times the provided option (or its long option synonym) was present. If the return value is non-zero then the value of the tt(idx)th occurrence (0-based offset) of this option is stored in tt(*value), which is left untouched if `option' was not present or if tt(idx) is or exceeds the number of specifications of the provided option. 0 may be specified for bf(value) if the option does not have a value or if the value should not be stored; itb(size_t option(size_t *idx, string *value, int option) const) Returns the number of times the provided option (or its long option synonym) was present. If the return value is non-zero then the offset (within the series of tt(option) specifications) of the first option having a non-empty option value is returned in tt(*idx), while its option value is stored in tt(*value). Both tt(*value) and tt(*idx) are left untouched if `option' was not present. 0 may be specified for bf(value) if the option does not have a value or if the value should not be stored; itb(size_t option(string *value, char const *longOption) const) Returns the number of times the specified long option (not having a single-character synonym) was present. Its value is then stored in tt(*value), which is left untouched if the long option was not present. 0 may be specified for bf(value) if the option does not have a value or if the value should not be stored; itb(size_t option(size_t idx, string *value, char const * longOption) const) Returns the number of times the provided long option (not having a single-character synonym) was present. If the return value is non-zero then the value of the tt(idx)th occurrence (0-based offset) of this long option is stored in tt(*value), which is left untouched if the long option was not present or if tt(idx) is or exceeds the number of specifications of the provided long option. 0 may be specified for bf(value) if the long option does not have a value or if the value should not be stored; itb(size_t option(size_t *idx, string *value, int longOption) const) Returns the number of times the provided long option (not having a single-character synonym) was present. If the return value is non-zero then the offset (within the series of this long option specifications) of the first long option having a non-empty option value is returned in tt(*idx), while its option value is stored in tt(*value). Both tt(*value) and tt(*idx) are left untouched if long option was not present. 0 may be specified for bf(value) if the long option does not have a value or if the value should not be stored; itb(void versionHelp(void (*usage)(std::string const &progname), char const *version, size_t minArgs, int helpFlag = 'h', int versionFlag = 'v') const) If the tt(helpFlag) was specified tt(usage()) is called with argument bf(basename()) whereafter the program throws tt(int 0). If tt(versionFlag) was specified the program's name (using basename()) and version is displayed to tt(std::cout) whereafter the program throws tt(int 0). If there are fewer arguments than tt(minArgs) tt(usage()) is called with argument bf(basename()) and the program ends with exit value 1. Note that tt(versionhelp) compares tt(minArgs) against tt(nArgs). If tt(minArgs) should be compaired against the number of arguments up to a possible `--' argument (i.e., tt(beyondDashes)' return value), then add tt(nArgs() - beyondDashes()) to the tt(minArg) argument. E.g., verb( arg.versionHelp(usage, version, 2 + arg.nArgs() - arg.beyondDashes()); ) The address of the tt(usage()) function, the current version and the minimum number of arguments must be specified. Default argument values are provided for the option flags. ) manpagesection(EXAMPLE) The following example illustrates defining long options and shows an initialization. It is not a full-fledched example in the sense of a small runnable program. verb( #include using namespace FBB; using namespace std; namespace // the anonymous namespace can be used here { Arg::LongOption longOptions[] = { Arg::LongOption{"debug"}, Arg::LongOption{"filenames", 'f'}, Arg::LongOption{"help", 'h'}, Arg::LongOption{"version", 'v'}, }; auto longEnd = longOptions + size(longOptions); } int main(int argc, char **argv) try { Arg &arg = Arg::initialize("df:hv", longOptions, longEnd, argc, argv); // code using arg, etc. } catch (exception const &err) // handle exceptions { cerr << err.what() << '\n'; return 1; } ) manpagefiles() em(bobcat/arg) - defines the class interface manpageseealso() bf(bobcat)(7) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/syslogstream.yo0000644000175000017500000002634014050437223020642 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::SyslogStream)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Output Stream for Syslog) manpagename(FBB::SyslogStream)(An output stream inserting syslog messages) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() bf(FBB::SyslogStream) objects may be used as a tt(std::ostream) to write syslog messages using stream facilities. Multiple separate insertions can be used to create a single syslog message: the message is only sent to the syslog daemon after receiving a tt(flush) command (e.g., after inserting tt(std::flush) or tt(std::endl)). Non-printable characters (like tt('\n')) show up in the syslog message as octal values, preceded by tt(#) (e.g., tt(#012) for tt('\n')). The newline normally inserted by tt(std::endl) is ignored: bf(SyslogStream) objects interpret tt(std::endl) like tt(std::flush). One series of insertions may contain multiple tt(std::endl) or tt(std::flush) manipulators. At each of these manipulators a new message is sent to the syslog daemon, containing all info that has so far been buffered. After sending a message to the syslog daemon, the bf(SyslogStream)'s internal buffer is cleared. includefile(include/namespace) manpagesection(INHERITS FROM) bf(std::ostream) manpagesection(ENUMERATIONS) The following enumerations are defined in the namespace bf(FBB): bf(Priority): The values of this enumeration match the corresponding priority tt(LOG_xxx) values used with bf(syslog)(3): itemization( itb(EMERG) system is unusable; itb(ALERT) action must be taken immediately; itb(CRIT) critical conditions; itb(ERR) error conditions; itb(WARNING) warning conditions; itb(NOTICE) normal, but significant, condition; itb(INFO) informational message; itb(DEBUG) debug-level message; ) The tt(setMask) member (see below) can be used to select which type of messages will actually be processed by the syslog daemon. bf(PriorityType): This enumeration has two values fine-tuning the type of messages that are actually processed by the syslog daemon: itemization( itb(SINGLE) Only messages of the priority specified at the tt(setMask) call are processed by the syslog daemon; itb(UPTO) Messages of priority tt(EMERG) up to the the priority specified at the tt(setMask) call are processed by the syslog daemon; ) By default, the syslog daemon processes all messages it receives. bf(Facility): The values of this enumeration match the corresponding facility tt(LOG_xxx) values used with bf(syslog)(3): itemization( itb(AUTHPRIV) security/authorization messages (private) itb(CRON) clock daemon (tt(cron) and tt(at)) itb(DAEMON) other system daemons itb(KERN) kernel messages itb(LOCAL0) reserved for local use. bf(LOCAL1) through bf(LOCAL7) are available as well. itb(LPR) line printer subsystem itb(MAIL) mail subsystem itb(NEWS) tt(USENET) news subsystem itb(SYSLOGBUF) messages generated internally by tt(syslogbufd) itb(USER) generic user-level messages itb(UUCP) UUCP subsystem ) manpagesection(CONSTRUCTORS) itemization( itb(SyslogStream(string const &ident = "", FBB::Priority priority = FBB::NOTICE, FBB::Facility facility = FBB::USER, int option = 0)) This constructor initializes a bf(SyslogStream) object. The tt(ident) parameter is usually the name of the program. Its content are prepended to syslog messages. The tt(priority) parameter determines the default importance of the message sent to the syslog daemon. By default messages are sent to the syslog daemon with priority bf(FBB::NOTICE). Syslog messages may be given different priority by inserting a bf(SyslogStream) manipulator (see below). The priority set at construction time may also be modified using the tt(setPriority) and tt(setDefaultPriority) members. Which messages actually appear in log facilities is not determined by the messages' priorities, but by syslog's em(log mask). The log mask can be set by the static member tt(setMask) (see below). The tt(facility) parameter determines the type of program doing the logging. By default bf(FBB::USER) is used. The tt(option) parameter may be used to specify various options (use the binary `tt(bitor)' (`tt(|)') operator to combine options): bf(LOG_CONS): write directly to system console if there is an error while sending to system logger nl() bf(LOG_NDELAY): open the connection immediately (normally, the con- nection is opened when the first message is logged) nl() bf(LOG_PERROR): print to stderr as well nl() bf(LOG__PID): include PID with each message nl() By default no options are used. ) Copy and move constructors (and assignment operators) are not available. manpagesection(MEMBER FUNCTIONS) All members of bf(std::ostream) are available, as bf(FBB::SyslogStream) inherits from this class. itemization( itb(void close()) If the bf(SyslogStream)'s internal buffer is not empty it is flushed to the syslog daemon. Thereafer bf(closelog)(3) is called. itb(Priority defaultPriority() const) Returns the current default priority. I.e., the priority that will be used for the messages after inserting tt(endl) or tt(flush). itb(void open(string const &ident, FBB::Priority priority = FBB::NOTICE, FBB::Facility facility = FBB::USER, int option = 0)) Redefines the current identifier, priority, facility and options that are used when sending messages to the syslog daemon. If the bf(SyslogStream)'s internal buffer is not empty it is first flushed to the syslog daemon using the identifier, priority and options that were active just before calling tt(open). itb(Priority priority() const) Returns the next priority. I.e., the priority that will be used for the next message that is sent to the syslog daemon. itb(Priority setDefaultPriority(Priority priority)) Changes the default priority of the next message that is sent to the syslog daemon after inserting tt(std::eoln) or tt(std::flush). The previously active default priority is returned. itb(Priority setPriority(Priority priority)) Changes the priority for the next message that is sent to the syslog daemon after inserting tt(std::eoln) or tt(std::flush). Subsequent messages will again use the default priority. The previously active priority setting is returned. ) manpagesection(STATIC MEMBER FUNCTIONS) itemization( itb(Priority setMask(Priority priority, PriorityMask upTo)) Syslog messages of (if tt(upTo) equals tt(SINGLE)) or up to (if tt(upTo) equals tt(UPTO)) the indicated priority are processed by the syslog daemon. itb(Priority setMask(Priority priority, Priority ...priorities)) Syslog messages of the priorities passed to tt(setMask) are processed by the syslog daemon. At least one priority must be specified. itb(Facility stoF(std::string const &name, Facility facility = USER)) Returns the facility matching the name of the facility provided by tt(name). Facility matching is performed case insensitively. E.g., if tt(name) contains tt(daemon), facility tt(FBB::DAEMON) is returned. If tt(name) does not match any facility name then the value of this function's second argument is returned. The function's name (tt(stoF)) was used in analogy of the various tt(sto...) conversion functions that were made available by the bf(C++11) standard. itb(Priority stoP(std::string const &name, Priority priority = NOTICE)) Returns the priority matching the name of the priority provided by tt(name). Priority matching is performed case insensitively. E.g., if tt(name) contains tt(emerg), priority tt(FBB::EMERG) is returned. If tt(name) does not match any priority name then the value of this function's second argument is returned. The function's name (tt(stoP)) was used in analogy of the various tt(sto...) conversion functions that were made available by the bf(C++11) standard. ) manpagesection(MANIPULATORS) The following set of manipulators are all defined as (static) members. They may be inserted into an bf(FBB::SyslogStream) object. Except for the last manipulator (tt(strerrno)), they have the following characteristics in common: itemization( it() They change the priority of the messages that are subsequently inserted by the bf(FBB::SyslogStream) object, thus acting like a separate tt(setPriority) call. it() When inserting multiple manipulators before the inserted message is flushed (e.g., using the tt(std::flush) or the tt(std::endl) manipulators) the last inserted bf(FBB::SyslogStream) manipulator will be used. it() If the manipulators are not inserted into an bf(FBB::SyslogStream) object (but in another tt(std::ostream) type of object) then they perform no action. ) Here are the available manipulators: itemization( itb(SyslogStream::alert) Messages are inserted with priority bf(FBB::ALERT). itb(SyslogStream::crit) Message are inserted with priority bf(FBB::CRIT). itb(SyslogStream::debug) Messages are inserted with priority bf(FBB::DEBUG). itb(SyslogStream::emerg) Messages are inserted with priority bf(FBB::EMERG). itb(SyslogStream::err) Messages are inserted with priority bf(FBB::ERR). itb(SyslogStream::info) Messages are inserted with priority bf(FBB::INFO). itb(SyslogStream::notice) Messages are inserted with priority bf(FBB::NOTICE). itb(SyslogStream::strerrno) This manipulator inserts the textual interpretation of tt(std::errno)'s current value into a tt(std::ostream). Note that, different from the other manipulators, the object into which this manipulator is inserted does not have to be a bf(FBB::SyslogStream) object. itb(SyslogStream::warning) Messages are inserted with priority bf(FBB::WARNING). ) manpagesection(EXAMPLE) verb( #include using namespace std; using namespace FBB; int main(int argc, char **argv) { SyslogStream sls(argv[0]); sls << SyslogStream::debug << "Hello world" << flush << SyslogStream::strerrno << endl; } ) manpagefiles() em(bobcat/syslogstream) - defines the class interface manpageseealso() bf(bobcat)(7), bf(closelog)(3), bf(openlog)(3), bf(rsyslogd)(8), bf(syslog)(3), bf(syslogbuf)(3bobcat) manpagebugs() The constructor's tt(option) parameter is an tt(int). Because of this, tt(int) values rather than enumeration values are passed to the constructor. It is the responsibility of the programmer to pass defined option values only. includefile(include/trailer) bobcat-5.09.01/documentation/man/sharedmemory.yo0000644000175000017500000004170614050437223020610 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::SharedMemory)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Shared Memory Memory) manpagename(FBB::SharedMemory)(Shared Memory memory structure) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat ) manpagedescription() The class bf(FBB::SharedMemory) implements a usable interface to a shared memory segment made available by tt(FBB::SharedSegment) and monitored by tt(FBB::SharedPos). It is the main building block for tt(FBB::SharedBuf), defining the `device' to which tt(FBB::SharedBuf) interfaces. All shared memory related I/O should be performed by bf(FBB::SharedMemory) objects, which are true objects, not themselves residing in shared memory. An bf(FBB::SharedMemory) object defines, connects to and manages access to shared memory, encapsulating all raw shared memory operations. In addition to the class bf(FBB::SharedMemory) the header file tt(bobcat/sharedmemory) also defines a bf(struct SharedEnum__) defining bf(enum SizeUnit) within the namespace tt(FBB). The requested amount of shared memory is always a lower bound to the maximum amount of shared memory that eventually may become available. When defining a bf(SharedMemory) object not all of its potentially available shared memory is immediately allocated. Shared memory will be allocated by the bf(SharedMemory) object once needed (up to a calculated maximum). As a fictitious example: assume 100 kB of memory is requested. The bf(SharedMemory) object then maintains a table of, e.g., 10 entries, each entry controlling access to a shared memory block of 10 kB. These 10 kB blocks aren't immediately allocated, but become available once the program reads from or writes to addresses located in these data blocks. Newly allocated data blocks are initialized to 0-bytes. Caveat: when constructing a shared memory segment make sure the segment's ID is stored at a retrievable location. This allows other processes to access the shared segment. The shared segment ID is also required to delete a shared memory segment. If the shared segment ID is lost, the memory occupied by the shared memory segment remains inaccessible (although they can be retrieved and removed by additional means, like bf(ipcs)(1) and bf(ipcrm)(1)). The member tt(id) returns the ID of the shared memory currently monitored by an bf(FBB::SharedMemory) object. includefile(include/namespace) manpagesection(INHERITS FROM) bf(FBB::SharedEnum__) The bf(struct SharedEnum__) is a wrapper struct around bf(enum SizeUnit), which is available through inheritance in several bf(FBB::Shared*) classes, and offers symbolic constants defining standard memory sizes. The bf(enum SizeUnit) defines the following symbolic constants: itemization( it() bf(kB), representing 1024 (2**10) bytes of memory; it() bf(MB), representing 1048576 (2**20) bytes of memory; it() bf(GB), representing 1073741824 (2**30) bytes of memory ) manpagesection(CONSTRUCTORS, DESTRUCTOR) itemization( itb(SharedMemory()) The default constructor defines an empty stub, which cannot immediately be used. As the bf(SharedMemory) class supports move assignment, empty stubs can easily be (re)configured at any time after their construction. itb(SharedMemory(size_t maxSize, SizeUnit sizeUnit, size_t access = 0600)) This constructor creates a shared memory segment having a capacity of at least tt(maxSize * sizeUnit) bytes. The shared memory's access rights are defined by the tt(access) parameter, using the well-known (bf(chmod)(1)) octal values to define access rights for the owner, the group and others. If construction succeeds the shared memory is ready for use. If construction fails, an tt(FBB::Exception) is thrown. itb(SharedMemory(int id)) This constructor connects to a shared memory segment having ID tt(id). If construction succeeds the shared memory is ready for use. If construction fails (e.g., no shared memory segment having ID tt(id) exists), an tt(FBB::Exception) is thrown. itb(~SharedMemory()) The destructor detaches any attached shared memory segments from the bf(FBB::SharedMemory) object. If the shared memory segment is currently locked by the bf(FBB::SharedMemory) object, the lock is removed. ) Copy and move constructors (and assignment operators) are not available. manpagesection(OVERLOADED OPERATORS) itemization( itb(std::ostream &operator<<(std::ostream &out, SharedMemory const &sharedMemory)) The overloaded insertion operator inserts information about the tt(SharedMemory) object into the provide tt(ostream) object. The IDs of the shared segments, their sizes, the maximum number of shared memory segments, the number of bytes that can be read from the shared memory, and its actual storage capacity, etc., are displayed. itb(SharedMemory &operator=(SharedMemory &&rhs)) The overloaded move assignment operator is available. It is used to (re)define the shared memory segment an bf(FBB::SharedMemory) object is interfacing with. ) manpagesection(MEMBER FUNCTIONS) itemization( itb(size_t blockOffset() const) The offset within the shared segment data block matching tt(offset)'s return value is returned. 0 is returned if the bf(SharedMemory) object has not yet been connected to a shared memory block (or if the offset happens to be at the block's offset 0). itb(void clear()) First, the shared memory is locked. Next, all shared data segment are deleted, and the shared memory's own data are reset to indicate it is completely empty. Following this the shared memory segment is unlocked again. Returning from tt(clear) the shared memory The bf(FBB::SharedMemory) object is effectively re-initialized, with tt(offset) and tt(nReadable) returning 0. An tt(FBB::Exception) is thrown if the bf(SharedMemory) object has not yet been connected to a shared memory block. itb(size_t dataSegmentSize() const) Returns the size (in bytes) of shared memory data block. 0 is returned if the bf(SharedMemory) object has not yet been connected to a shared memory block. itb(int get()) First the bf(FBB::SharedMemory) object calls tt(lock) to lock the shared memory segment. Next the character at tt(offset) is retrieved and tt(offset) is incremented. Then tt(unlock) is called, and the retrieved character is returned. If tt(offset) is at least equal to tt(nReadable, EOF) is immediately returned. An tt(FBB::Exception) is thrown if the bf(SharedMemory) object has not yet been connected to a shared memory block. itb(int id() const) The ID of the shared memory segment is returned. Following tt(kill) tt(id) returns -1, indicating that the shared segment cannot be used anymore (note that tt(operator=) can be used to re-initialize the bf(FBB::SharedMemory) object). itb(SharedType *install(std::streamsize *offset, Params &&...params)) This member was implemented as a member template, using tt(typename SharedType) and tt(typename ...Params), allowing perfect forwarding of arguments to tt(SharedType)'s constructor. This member installs a tt(SharedType) object at bf(SharedMemory's) at bf(SharedMemory)'s first available offset: either at the current offset, or (if tt(SharedType's) size is too big to fit in the current data block at offset) at the first byte of the next tt(SharedSegment) shared data block. The actual offset where the tt(SharedType) object is installed is returned in tt(*offset), unless a tt(nullptr) is passed as tt(install's) first argument. A pointer to the installed tt(SharedType) is returned, with tt(shmem.offset) pointing just beyond tt(SharedType's) last byte. The tt(SharedType) object is installed using placement new. E.g., the following example illustrates how a bf(SharedMutex)(3bobcat) object can be installed at the first possible location of tt(SharedMemory shmem): verb( std::streamsize offset; FBB::SharedMutex *mutexPtr = shmem.install(&offset); ) If the installed object must be destroyed, its destructor must explicitly be called. E.g., to destroy the tt(Mutex) pointed at by tt(mutexPtr) use tt(mutexPtr->~SharedMutex()). An tt(FBB::Exception) is thrown if tt(shmem) could not install the object in its shared memory data blocks. itb(void kill()) Without locking the shared memory all shared memory controlled by the bf(SharedMemory) object is deleted. The bf(SharedMemory) object is unusable after returning from tt(kill), with its tt(id) member returns -1. Nothing happens if this member is called when the bf(SharedMemory) object has not yet been connected to a shared memory block. itb(std::streamsize maxOffset() const) The maximum possible offset that can be used with the shared memory segment is returned. The members tt(offset) and tt(nReadable) never exceed the value returned by tt(maxOffset). 0 is returned if the bf(SharedMemory) object has not yet been connected to a shared memory block. itb(std::streamsize nReadable() const) The number of characters (bytes) that can be read from the beginning of the shared memory is returned. 0 is returned if the bf(SharedMemory) object has not yet been connected to a shared memory block. itb(std::streamsize offset() const) The offset within the shared memory segment (i.e., relative to the segment's tt(ios::beg) position) is returned. 0 is returned if the bf(SharedMemory) object has not yet been connected to a shared memory block (or if the offset happens to be at the shared memory's offset 0). itb(char *ptr()) Returns 0 if tt(offset() == maxOffset()). Otherwise it returns a pointer to the character at index tt(offset) within the shared memory segment. An tt(FBB::Exception) is thrown if the bf(SharedMemory) object has not yet been connected to a shared memory block. itb(int put(int ch)) After locking the appropriate shared data segment, tt(ch) is written at position tt(offset), incrementing tt(offset) thereafter. If tt(ch == EOF, EOF) is immediately returned. An tt(FBB::Exception) is thrown if the bf(SharedMemory) object has not yet been connected to a shared memory block. itb(int read(Type *value)) This member was implemented as a member template. It calls the next member, casting tt(Type *) to tt(char *), and using tt(sizeof(Type)) as its second argument. The number of bytes actually read is returned. This member returns -1 if initially tt(offset) was at least equal to tt(nReadable). An tt(FBB::Exception) is thrown if the bf(SharedMemory) object has not yet been connected to a shared memory block. itb(int read(char *data, std::streamsize len)) While locking the appropriate shared data segment(s) at most tt(len) bytes are read from the shared memory, starting at tt(offset). The bytes read from shared memory are stored at tt(data). The number of bytes actually read is returned. This member returns -1 if initially tt(offset) was at least equal to tt(nReadable). An tt(FBB::Exception) is thrown if the bf(SharedMemory) object has not yet been connected to a shared memory block. itb(int read(std::ios::off_type offset, Type *value, std::ios::seekdir origin = std::ios::beg)) This member was implemented as a member template. After changing the bf(SharedMemory)'s offset to tt(offset) (relative to tt(origin)), it calls the first tt(read) member, passing it tt(value). The number of bytes actually read is returned. This member returns -1 if initially tt(offset) was at least equal to tt(nReadable). An tt(FBB::Exception) is thrown if the bf(SharedMemory) object has not yet been connected to a shared memory block. itb(void remove()) The shared memory is locked, after which all shared memory controlled by the bf(FBB::SharedMemory) object is deleted. The bf(FBB::SharedMemory) object is unusable after returning from tt(remove). An tt(FBB::Exception) is thrown if the bf(SharedMemory) object has not yet been connected to a shared memory block. itb(std::ios::pos_type seek(std::ios::off_type offset, std::ios::seekdir origin = std::ios::beg)) Moves the tt(offset) position relative to tt(way). The value -1 is returned when seeking before offset 0 or beyond tt(maxOffset), otherwise the offset relative to the begin location of the shared memory (i.e, tt(offset) for tt(origin == ios::beg)) is returned. 0 is returned if the bf(SharedMemory) object has not yet been connected to a shared memory block (or if the offset happens to be at the shared memory's offset 0). itb(std::streamsize showmanyc() const) The number of characters that can be read from the current shared segment data block is returned. This member interrogates the number of readable characters in the shared memory segment. This number may change while this member is being executed. In order to receive a stable return value, calling functions should have obtained a lock on the shared memory segment before calling this member. 0 is returned if the bf(SharedMemory) object has not yet been connected to a shared memory block (or if the no characters can currently be read). itb(void swap(SharedMemory &other)) The current and other bf(FBB::SharedMemory) objects are swapped. itb(bool truncate(std::streamsize offset)) If tt(offset) is not exceeding the value returned by tt(nReadable) tt(nReadable) is changed to tt(offset) and tt(true) is returned. Otherwise tt(false) is returned, and the value returned by tt(nReadable) is not changed. An tt(FBB::Exception) is thrown if the bf(SharedMemory) object has not yet been connected to a shared memory block. itb(int write(Type const *value)) This member was implemented as a member template. It calls the next member, casting tt(Type const *) to tt(char const *), and using tt(sizeof(Type)) as its second argument. The number of bytes actually written is returned. This member returns -1 if initially tt(offset) was at least equal to tt(maxOffset). An tt(FBB::Exception) is thrown if the bf(SharedMemory) object has not yet been connected to a shared memory block. itb(int write(char const *data, std::streamsize len)) The bf(FBB::SharedMemory) object calls tt(lock) to lock the shared memory, and writes at most tt(len) bytes into the shared memory, starting at tt(offset). Next, tt(unlock) is called. The number of bytes actually written is returned. The member function returns -1 if initially tt(offset) is equal to tt(maxOffset). An tt(FBB::Exception) is thrown if the bf(SharedMemory) object has not yet been connected to a shared memory block. itb(int write(std::ios::off_type offset, Type const *value, std::ios::seekdir origin = std::ios::beg)) This member was implemented as a member template. After changing the bf(SharedMemory)'s offset to tt(offset) (relative to tt(origin)), it calls the first tt(write) member, passing it tt(value). The number of bytes actually written is returned. This member returns -1 if initially tt(offset) was at least equal to tt(maxOffset). An tt(FBB::Exception) is thrown if the bf(SharedMemory) object has not yet been connected to a shared memory block. ) manpagesection(EXAMPLE) See the bf(sharedstream)(3bobcat) man page. manpagefiles() em(bobcat/sharedmemory) - defines the class interface manpageseealso() bf(bobcat)(7), bf(chmod)(1), bf(ipcs)(1), bf(ipcrm)(1), bf(isharedstream)(3bobcat), bf(osharedstream)(3bobcat), bf(sharedblock)(3bobcat), bf(sharedcondition)(3bobcat), bf(sharedmutex)(3bobcat), bf(sharedpos)(3bobcat), bf(sharedreadme)(7bobcat), bf(sharedsegment)(3bobcat), bf(sharedstream)(3bobcat), bf(sharedbuf)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/localclientsocket.yo0000644000175000017500000001167114050437223021611 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::LocalClientSocket)(3bobcat) (_CurYrs_)(libbobcat-dev__CurVers_) (Unix Domain client Socket) manpagename(FBB::LocalClientSocket) (Client Socket connecting to a Server in the Unix Domain) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() An bf(FBB::LocalClientSocket) may be constructed to connect to a server process in the Unix Domain. The socket made available by the bf(FBB:LocalClientSocket) may be used to initialize a bf(std::istream) and/or bf(std::ostream). The bf(std::istream) is used to read information from the server process to which the bf(FBB::LocalClientSocket) connects, The bf(std::ostream) is used to send information to the server process to which the bf(FBB::LocalClientSocket) connects. Since a socket may be considered a em(file descriptor) the available bf(FBB::IFdStream), bf(FBB::IFdStreamBuf), bf(FBB::OFdStream), and bf(FBB::OFdStreamBuf) classes may be used profitably here. Note that having available a socket does not mean that this defines the communication protocol. It is (still) the responsibility of the programmer to comply with an existing protocol or to implement a tailor-made protocol. The latter situation implies that the sequence of input- and output operations is defined by the programmer. includefile(include/namespace) manpagesection(INHERITS FROM) bf(FBB::LocalSocketBase) manpagesection(CONSTRUCTOR) itemization( itb(LocalClientSocket()) This constructor merely creates a bf(FBB::LocalClientSocket) object. Before it can be used, its tt(open()) member must be called. itb(LocalClientSocket(std::string const &name)) This constructor initializes an bf(FBB::LocalClientSocket) object, using the named Unix Domain socket to connect to the server using the named Unix Domain socket. An bf(FBB::Exception) is thrown if the socket could not be constructed. The construction of the socket does not mean that a connection has actually been established. In order to connect to the server, the member bf(connect()) (see below) should be used. ) Copy and move constructors (and assignment operators) are not available. manpagesection(MEMBER FUNCTION) itemization( itb(int connect()) This member returns a socket that can be used to communicate with the server process. An bf(FBB::Exception) exception is thrown if the connection could not be established. itb(open(std::string const &name)) This member function prepares the bf(FBB::LocalClientSocket) object, constructed earlier using the default constructor, for use. The named Unix Domain socket is used to connect to the server using the named Unix Domain socket. An bf(FBB::Exception) is thrown if the socket could not be constructed. The construction of the socket does not mean that a connection has actually been established. In order to connect to the server, the member bf(connect()) should be used. ) manpagesection(EXAMPLE) See also the bf(localserversocket)(3bobcat) example. verb( #include #include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) try { if (argc == 1) { cerr << "Provide filename representing the unix domain socket\n"; return 1; } LocalClientSocket client(argv[1]); int fd = client.connect(); string line; cout << "Connecting to socket " << fd << endl; IFdStream in(fd); // stream to read from OFdStream out(fd); // stream to write to while (true) { // Ask for a textline, stop if empty / none cout << "? "; if (!getline(cin, line) || line.length() == 0) return 0; cout << "Line read: " << line << endl; // Return the line to the server out << line.c_str() << endl; cout << "wrote line\n"; // Wait for a reply from the server getline(in, line); cout << "Answer: " << line << endl; } } catch (Exception const &err) { cerr << err.what() << "\n" << "Can't connect to " << argv[1] << ", port " << argv[2] << endl; return 1; } ) manpagefiles() em(bobcat/localclientsocket) - defines the class interface manpageseealso() bf(bobcat)(7), bf(ifdstream)(3bobcat), bf(ifdbuf)(3bobcat), bf(clientsocket)(3bobcat), bf(localserversocket)(3bobcat), bf(localsocketbase)(3bobcat), bf(ofdstream)(3bobcat), bf(ofdstream)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/csv.yo.deprecated0000644000175000017500000002561314050437223021002 0ustar frankfrankNOUSERMACRO(CSV) includefile(include/header) COMMENT(replace 'classname' by the name of the new class) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::CSV)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_-x.tar.gz) (CSV convertor) manpagename(FBB::CSV)(Converter for comma separated values) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() Objects of the class bf(CSV) can be used to convert series of comma separated values to the individual separated values. These values may be converted (individually or as a group) to standard integral types tt(int, size_t, long long,) etc., to floating point types (tt(float, double, long double)), or they can be accessed as tt(std::string) values. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(TYPEDEFS AND ENUMS) The bf(enum Mode) specifies how a bf(CSV) is extracted from tt(std::istream) objects: itemization( itt(TRAILINGCOMMA) a series of comma-separated values ends at a final comma, which is removed from the tt(istream) by the bf(CSV) extraction operator. itt(LINE) after extracting a bf(CSV) object any remaining characters on the current tt(std::istream) line are ignored (i.e., the extraction operator reads full lines of input). ) These enumeration values may be combined using the tt(bit-or) operator. The bf(enum InsertType) specifies how a bf(CSV) is inserted into tt(std::ostream) objects: itemization( itt(LENGTH) indicates that all specifications (i.e., the em(length) of the type-specifications, see the member tt(length) below), are inserted into the tt(std::ostream) as a series of comma-separated values. itt(SIZE) indicates that all (not ignored) comma-separated fields (i.e., the em(size) of the fields vector, see the member tt(size) below), are inserted into the tt(std::ostream) as a series of comma-separated values. itt(COUNT) indicates that all valid (i.e., the em(count) of the valid fields, see the member tt(count) below), are inserted into the tt(std::ostream) as a series of comma-separated values. ) The class tt(CSV) defines the nested classes tt(const_iterator) and tt(const_reverse_iterator) which are tt(InputIterators), which can be used to iterate over the sequence of comma-separated values. manpagesection(CONSTRUCTORS) itemization( itb(CSV(std::string const &specification, Mode mode = LINE, InsertType = LENGTH)) The specification in tt(specification) defines the subsequent fields of the comma-separated value. Specifications are quote( itemization( itt(S): the field is left as-is, and can be retrieved as a tt(std::string). itt(I): the field represents an tt(int) value; itt(D): the field represents a tt(double) value; itt(X) or tt(-): the field is ignored and is not stored inside the bf(CSV) object. E.g., with the specification tt(SXS) two fields will actually be stored inside the bf(CSV) object: field 0 contains the first field extracted from the input stream, field 1 contains the third field extracted from the input stream. ) ) Specifications may be separated by space or tab characters, which are ignored. The number of specification characters determines the number of fields that are stored in a bf(CSV) object. The final field may or may not be followed by a comma. Each specification may also be followed by a positive integral value, indicating that the input at that point contains that number of comma-separated fields of the specified type. By default the bf(CSV) extraction operator extracts complete lines from the stream from which a bf(CSV) object is extracted. When inserting a bf(CSV) object into a tt(std::ostream) object all fields that are specified by `tt(specification)' will be inserted. Ignored fields will be inserted as single blanks. ) The default, copy, and move constructors are available. manpagesection(OVERLOADED OPERATORS) itemization( itb(std::string const &operator[](size_t index) const) The content of the indicated field is returned as a tt(std::string). itb(std::istream &operator>>(std::istream &out, CSV const &csv)) The data fields stored within tt(csv) are inserted into tt(out) as a series of comma-separated values. The fields are inserted according to the latest tt(InsertType) specification: quote( itemization( it() For tt(LENGTH) all fields are inserted according to their original type specification, where tt('X') and tt('-') fields are inserted as fields of single blank spaces; it() For tt(SIZE) all fields that are stored inside tt(csv) are inserted `as-is'; it() For tt(COUNT) all valid fields are inserted. )) If tt(csv)'s tt(Mode) specification contains tt(TRAILINGCOMMA) then a comma is expected and extracted beyond the last field; if it contains tt(LINE) then any information that is found on the line beyond the last field (including its terminating comma, if applicable) is ignored (including the tt('\n') line terminator). itb(std::ostream &operator<<(std::ostream &out, CSV const &csv)) The data fields stored within tt(csv) are inserted into tt(out) as a series of comma-separated values. The fields are inserted according to the latest tt(InsertType) specification: quote( itemization( it() For tt(LENGTH) all fields are inserted according to their original type specification, where tt('X') and tt('-') fields are inserted as fields of single blank spaces; it() For tt(SIZE) all fields that are stored inside tt(csv) are inserted `as-is'; it() For tt(COUNT) all valid fields are inserted. )) If tt(csv)'s tt(Mode) specification contains tt(TRAILINGCOMMA) then a comma is inserted beyond the last field. ) The copy and move assignment operators are available. manpagesection(MEMBER FUNCTIONS) itemization( itb(CSV &append(char spec, std::string const &value = "")) A field tt(spec), with textual representation tt(value) is added to the object's current set of fiels. A specification tt('X') or tt('-') is added to the object's set of specifications, but does not add tt(value) to the currently stored set of values. itb(std::vector const &available() const) A vector of tt(bool) values indicating which of the matching data fields are valid (i.e., could be converted to its specification as defined at construction time or by tt(setSpec)) is returned. itb(CSV::const_iterator begin() const) This is a template member returning a tt(CSV::const_iterator) to the object's first field. When dereferencing a tt(const_iterator) the value it refers to is converted to the indicated tt(Type). If the conversion fails, the tt(Type)'s default value is returned. itb(size_t count() const) The number of fields that could actually be converted to their indicated types is returned. E.g., an empty field or a supposedly numeric field whose content cannot be converted to the indicated numeric value won't be counted here. itb(std::vector const &data() const) The vector of fields stored inside the bf(CSV) object is returned. itb(CSV::const_iterator end() const) This is a template member returning a tt(CSV::const_iterator) pointing just beyond the bf(CSV) object's last field. itb(Type field(size_t idx) const) This is a template member returning the content of field tt(idx) as a value of type tt(Type). When tt(Type) equals tt(std::string) a tt(std::string const &) is returned. For tt(Type) all integral and floating types as well as tt(std::sting) are accepted. If field tt(idx) cannot be converted to tt(Type) a bf(std::exception) is thrown. itb(Type get(size_t idx)) This is a template member returning the content of field tt(idx) as a value of type tt(Type). When tt(Type) equals tt(std::string) a tt(std::string const &) is returned. For tt(Type) all integral and floating types as well as tt(std::sting) are accepted. If field tt(idx) cannot be converted to tt(Type), the tt(Type)'s default value is returned. itb(InsertType insertType() const) The object's current tt(InsertType) is returned. itb(size_t length() const) The number of specifications (defined at construction time or by the tt(setSpec) member) is returned. This count includes the number of tt(X) and tt(-) specifications. itb(CSV::Mode mode() const) The object's current tt(Mode) value is returned. itb(std::string const &spec() const) The object's current field-type specifications are returned. itb(CSV::const_reverse_iterator rbegin() const) This is a template member returning a tt(CSV::const_reverse_iterator) to the object's last field. When dereferencing a tt(const_reverse_iterator) the value it refers to is converted to the indicated tt(Type). If the conversion fails, the tt(Type)'s default value is returned. itb(CSV::const_iterator rend() const) This is a template member returning a tt(CSV::const_reverse_iterator) pointing just before the bf(CSV) object's first field. itb(void setInsertType(InsertType insertType)) The objects tt(InsertType) is changed to tt(insertType). This has no immediate effect, but is only interpreted with the insertion operator. itb(void setMode(Mode mode)) The object's current tt(Mode) value is changed to tt(mode). This has no immediate effect, but is only interpreted with the insertion and extraction operators. itb(void setSpec(std::string const &spec)) The information stored inside the bf(CSV) object is erased, and a new field-specification is defined from tt(spec). itb(size_t size() const) The number of fields is returned (the returned value equals the value returned by tt(length) not counting the tt(X) and tt(-) fields). ) manpagesection(EXAMPLE) verbinclude(../../csv/driver/driver.cc) manpagefiles() em(bobcat/csv) - defines the class interface manpageseealso() bf(bobcat)(7) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/mstream.yo0000644000175000017500000003343014050437223017554 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Mstream)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Message handler) manpagename(FBB::Mstream)(Generic message handling stream) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() Objects of this class are used for handling messages in a standardized way. Messages may be prefixed with order (line) numbers an/or, labels. Messages generated by tt(Mstream) objects may optionally end by throwing an tt(FBB::Exception) (which is an tt(std::exception)), allowing simple implementation of, e.g., fatal error messages. Four message streams are provided by the tt(BOBCAT) library and may be used after including the tt(mstream) header file. They are all defined in the tt(FBB) namespace: itemization( itt(FBB::emsg) for generating standard (labeled and numbered) error messages, e.g. verb( [Error 1] this is an error message ) itt(FBB::fmsg) for generating (labeled) fatal error messages, ending in an exception, e.g., verb( [Fatal] this fatal message is followed by an exception ) The exception's tt(what) member contains tt(FBB::fmsg's id) value (see member tt(id) below). itt(FBB::imsg) for generating plain informational messages, e.g., verb( this is a plain message ) itt(FBB::wmsg) for generating (labeled) warning messages; verb( [Warning] this is a warning ) ) By default all messages are inserted into the standard output stream, but other destinations (standard error, a named file, etc.) can easily be configured. tt(Mstream) objects themselves are tt(std::ostream) objects, so they can be used as objects passed to functions expecting tt(ostream) arguments. Messages inserted into tt(Mstream) objects are buffered until the buffer is flushed by their tt(std::ostream) parts or when either the tt(FBB::endl) or tt(FBB::flush) is inserted into the message stream. Since these manipulators act like tt(std::endl) and tt(std::flush) when inserted into another kind of tt(std::ostream) object, tt(using FBB::endl) and tt(using FBB::flush) might be worth considering. Also, when tt(using namespace std) em(and) tt(using namespace FBB) is specified the tt(FBB::endl) and tt(FBB::flush) manipulator will automatically be used with tt(Mstream) objects. Messages inserted into tt(Mstream) objects are considered completed at the insertion of the tt(FBB::endl) or tt(FBB::flush) manipulators. Message labels, line number labels and line numbers will only be shown for the next line after these manipulators have been inserted and exceptions are, if needed, thrown from these manipulators. manpagesection(NAMESPACE) bf(FBB)nl() All elements mentioned in this man-page, are defined in the namespace bf(FBB). manpagesection(INHERITS FROM) bf(std::ostream) manpagesection(CONSTRUCTORS) itemization( itb(Mstream()) The default constructor generates messages using the tt(std::streambuf) used by tt(std::cout). There is no limit to the number of messages that may be inserted. No message or line numbers are shown, no exceptions are thrown when inserting messages. itb(explicit Mstream(std::ostream &ostr, size_t maxCount = std::numeric_limits::max(), std::string const &tag = "", bool throwing = false)) This constructor uses the tt(std::streambuf) that is also used by the tt(ostream ostr). By default (using the default argument values) there is no limit to the number of messages that may be inserted. No message or line numbers are shown, no exceptions are thrown when inserting messages. Specifying any other value than tt(std::numeric_limits::max()) will set the maximum number of messages that can be inserted to that value. The tt(tag) defines the text of the message label (e.g., tt(Error)). When tt(throwing) is tt(true) an exception is thrown after completing a message. The generated exception's tt(what) member may show the bf(FBB::Mstream) object's id (see below at the member tt(id)) of the tt(Mstream) object throwing the exception. itb(explicit Mstream(std::streambuf *buf, size_t maxCount = std::numeric_limits::max(), std::string const &tag = "", bool throwing = false)) This constructor uses tt(buf) to insert messages into. The remaining parameters are identical to those of the previous constructor. itb(explicit Mstream(std::string const &name, size_t maxCount = std::numeric_limits::max(), std::string const &tag = "", bool throwing = false)) This constructor creates a tt(std::ofstream) from the provided tt(name) parameter. It throws an exception if the stream cannot be opened for writing. If a file by that name already exists it is rewritten. The remaining parameters are identical to those of the previous two constructors. ) Copy and move constructors (and assignment operators) are not available. manpagesection(MEMBER FUNCTIONS) itemization( itb(size_t count() const) returns the number of inserted messages (if tt(setCount) has been called: the value set by the last tt(setCount) call plus the number of inserted messages since that call). itb(bool isActive() const) returns tt(true) if messages can actually be inserted into the bf(FBB::MStream) object, and tt(false) if inserted messages are ignored. When ignoring messages the message count is not updated. itb(int id() const) returns the unique em(id) of the tt(Mstream) object. itb(bool lineExcess() const) returns bf(true) after attempting to insert an additional message after tt(maxCount) number of messages have been inserted. itb(std::string const &lineTag() const) returns the currently used line-tag (by default `tt(Line)'). itb(size_t maxCount() const) returns the maximum number of messages that can be inserted. If the returned value equals tt(std::numeric_limits::max()) then there is no limit to the number of messages that can be inserted. itb(void noLineNr()) calling this member will suppress the display of a line number if it is called after calling tt(setLineNr) (see below) but before a message is being (or has been) inserted. itb(void off()) after calling tt(off) messages inserted into the tt(Mstream) object are silently ignored. After calling tt(off) the internal message counter is not incremented when messages are inserted. itb(void on()) by default and after calling tt(on) messages inserted into the tt(Mstream) object are sent to their destination stream. itb(void reset(std::ostream &ostr)) messages inserted into the tt(Mstream) object are handled by the tt(std::streambuf) also used by tt(ostr). Other parameters (e.g., tt(maxCount), the message label) are kept as-is. itb(void reset(std::streambuf *buf)) messages inserted into the tt(Mstream) object are handled by tt(std::streambuf buf). Other parameters (e.g., tt(maxCount), the message label) are kept as-is. itb(void reset(FBB::Mstream const &mstream)) the current object is reset using the parameters of the tt(mstream) parameter. itb(void reset(std::string const &name, size_t maxCount, std::string const &tag, bool throwing)) messages inserted into tt(Mstream) objects are handled by a tt(std::ofstream) created using the provided tt(name) parameter. An exception is thrown if the stream cannot be opened for writing. If a file by that name already exists it is rewritten. Other parameters (e.g., tt(maxCount), the message label) are kept as-is. itb(void reset(std::ostream &ostr, size_t maxCount, std::string const &tag, bool throwing)) messages inserted into tt(Mstream) objects are handled by the tt(std::streambuf) also used by tt(ostr). By specifying tt(std::numeric_limits::max()) for tt(maxCount) there is no limit to the number of messages that may be handled by this tt(std::streambuf). The tt(tag) defines the text of the message label (e.g., tt(Error) or the empty string for no message label). When tt(throwing) is specified as tt(true) an exception is thrown after completing a message. itb(void reset(std::streambuf *buf, size_t maxCount, std::string const &tag, bool throwing)) messages inserted into tt(Mstream) objects are handled by tt(std::streambuf buf). The remaining parameters are identical to those of the previous tt(reset) member. itb(void reset(std::string const &name, size_t maxCount, std::string const &tag, bool throwing)) messages inserted into tt(Mstream) objects are handled by a tt(std::ofstream) created using the provided tt(name) parameter. It throws an exception if the stream cannot be opened for writing. If a file by that name already exists it is rewritten. The remaining parameters are identical to those of the previous two tt(reset) members. itb(void reset(FBB::Mstream const &mstream)) the current object is reset using the parameters of the tt(mstream) parameter. Following the reset all of the current object's parameters can independently be modified from those used by tt(mstream). itb(bool setActive(bool ifTrue)) If tt(ifTrue) equals tt(true) the tt(Mstream) is activated otherwise its actions are suppressed. Returns tt(ifTrue). itb(void setCount(size_t count)) assigns the value tt(count) to the object's message counter. itb(void setLineNr(size_t lineNr)) specifies the value tt(lineNr) as the message's line number when the next line is displayed (see also tt(noLineNr)). This value is em(not) changed by the tt(Mstream) object. To display another line number the member will have to be called again (i.e., the line number is not displayed automatically again at every new line). itb(void setLineTag(std::string const &tag)) specifies the tag prefixing line numbers. By default the line tag equals `tt(Line)'. itb(void setMaxCount(size_t maxCount)) defines tt(maxCount) as the maximum number of messages that can be inserted into the tt(Mstream) object. itb(void setTag(std::string const &tag)) specifies the tag prefixing messages. By default the tag is empty. If not empty the tag is enclosed by square brackets. E.g., specifying the tag `tt(Error)' will prefix messages with tt([Error]). itb(std::string const &tag() const) returns the currently used message tag (by default an empty string). itb(bool throws()) returns tt(true) when the tt(Mstream) object will throw an exception at the next completed message. The generated exception's tt(what) member contains the id (see earlier for the member tt(id)) of the tt(Mstream) object throwing the exception. itb(void throwing(bool ifTrue)) modifies the behaviro of tt(Mstream) objects at completed messages. After passing tt(true) tt(Mstream) objects will throw an exception at the next completed message, otherwise this exception is not thrown. The generated exception's tt(what) member contains the id (see earlier for the member tt(id)) of the tt(Mstream) object throwing the exception. ) manpagesection(MANIPULATORS) Note that the following two manipulators are not members of the class bf(Mstream), but are free functions defined in the namespace bf(FBB). itemization( itb(std::ostream &endl(std::ostream &out)) This manipulator inserts a newline character in the tt(Mstream)'s stream and then calls tt(FBB::flush). This manipulator acts like tt(std::endl) and tt(std::flush) when inserted into another kind of tt(std::ostream) object. itb(std::ostream &flush(std::ostream &out)) This manipulator completes the message that is currently being inserted into an tt(Mstream) object. It flushes the object's destination stream and prepares the object for the next message. When the object's tt(throws) member returns tt(true) it throws an exception whose tt(what) member contains the id (see earlier for the member tt(id)) of the tt(Mstream) object throwing the exception. When used in combination with another kind of tt(std::ostream) object it acts like tt(std::flush). itb(std::ostream &noid(std::ostream &out)) This manipulator completes the message that is currently being inserted into an tt(Mstream) object. It flushes the object's destination stream and prepares the object for the next message. When the object's tt(throws) member returns tt(true) it throws an exception whose tt(what) member does not contain the bf(Mstream) object's ID. When used in combination with another kind of tt(std::ostream) object it acts like tt(std::flush). itb(std::ostream &noidl(std::ostream &out)) This manipulator inserts a newline character in the tt(Mstream)'s stream and then calls tt(FBB::noid). This manipulator acts like tt(std::endl) and tt(std::flush) when inserted into another kind of tt(std::ostream) object. ) As the manipulators tt(FBB::endl) and tt(FBB::flush) act like, respectively, tt(std::endl) and tt(std::flush) when inserted into another kind of tt(std::ostream) object, using the declarations `tt(using FBB::endl)' and `tt(using FBB::flush)' might be worth considering. Also, when tt(using namespace std) em(and) tt(using namespace FBB) is specified the tt(FBB::endl) and tt(FBB::flush) manipulator will automatically be called when inserting tt(endl) or tt(flush) into tt(Mstream) objects. manpagesection(EXAMPLE) verbinclude(../../mstream/driver/driver.cc) manpagefiles() em(bobcat/mstream) - defines the class interface manpageseealso() bf(bobcat)(7), bf(exception)(3bobcat), bf(mbuf)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/ifdbuf.yo0000644000175000017500000001154614050437223017347 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::IFdBuf)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (File Descriptor Input Stream Buffer) manpagename(FBB::IFdBuf) (Input stream buffer initialized by a file descriptor) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() bf(FBB::IFdBuf) objects may be used as a tt(std::streambuf) of tt(std::istream) objects to allow extractions from a file descriptor. File descriptors are not defined within the context of bf(C++), but they can be used on operating systems that support the concept. Realize that using file descriptors introduces operating system dependencies. includefile(include/namespace) manpagesection(INHERITS FROM) bf(std::streambuf) manpagesection(ENUMERATION) The public enumeration tt(Mode) defined in the class tt(FBB::IFdStreamBuf) has the following values: itemization( it() bf(CLOSE_FD), indicating that the file descriptor used by the object must be closed; it() bf(KEEP_FD) (the default) indicating that the file descriptor used by the object must not be closed. ) manpagesection(CONSTRUCTORS) itemization( itb(IFdBuf()) This constructor initializes the streambuf, without associating it to a file descriptor, and without using buffering. The member tt(reset) can be used subsequently to associate the object with a file descriptor and optionally a buffer size. When the object is destroyed or if the mode-less overloaded version of the tt(reset) member is called, the file descriptor is not closed. itb(IFdBuf(Mode mode)) This constructor initializes the streambuf, without associating it to a file descriptor, and without using buffering. The member tt(reset) can be used subsequently to associate the object with a file descriptor and optionally a buffer size. When the object is destroyed or if the mode-less overloaded version of the member tt(reset) is called, the tt(Mode) argument determines whether the file descriptor will be closed or will remain open. itb(IFdBuf(int fd, size_t n = 1)) This constructor initializes the streambuf, associating it to file descriptor tt(fd), and an optional unget buffer size (by default having size 1). When the object is destroyed or if the mode-less overloaded version of the member tt(reset) is called, the file descriptor is not closed. itb(IFdBuf(int fd, Mode mode, size_t n = 1)) This constructor initializes the streambuf, associating it to file descriptor tt(fd), and an optional unget buffer size (by default having size 1). When the object is destroyed or if the mode-less overloaded version of the tt(reset) member is called, the tt(Mode) argument determines whether the file descriptor will be closed or will remain open. ) Copy and move constructors (and assignment operators) are not available. manpagesection(MEMBER FUNCTIONS) All members of tt(std::streambuf) are available, as tt(FBB::IFdBuf) inherits from this class. itemization( itb(void close()) The file descriptor used by the tt(IFdBuf) is closed, irrespective of the tt(Mode) that was specified when the tt(IFdBuf) object was constructed. Following tt(close) the tt(IFdBuf) object can no longer be used until one of its tt(reset) members has been called. itb(int fd() const) The file descriptor used by the tt(IFdBuf) object is returned. If the tt(OFdBuf) is not associated with a file descriptor -1 is returned. itb(void reset(int fd, size_t n = 1)) The streambuf is (re)initialized, using file descriptor tt(fd), and an optional unget buffer size (by default having size 1). When called repeatedly, the tt(Mode) specification used whem the object was constructed determines whether the file descriptor will be closed or will remain open. itb(void reset(int fd, Mode mode, size_t n = 1)) The streambuf is (re)initialized, using file descriptor tt(fd), a file descriptor closing parameter and an optional unget buffer size (by default having size 1). Depending on the tt(Mode) argument the object's currently used file descriptor will be closed or will remain open when the tt(IFdBuf) object is destroyed. ) manpagesection(EXAMPLE) verbinclude(../../ifdbuf/driver/driver.cc) manpagefiles() em(bobcat/ifdbuf) - defines the class interface manpageseealso() bf(bobcat)(7), bf(ifdstream)(3bobcat), bf(ofdbuf)(3bobcat), bf(std::streambuf) manpagebugs() The member tt(xsgetn(char *dest, std::streamsize n)) sets tt(istream::good()) to tt(false) when fewer bytes than tt(n) were read using tt(istream::read()). Also see tt(xsgetn)'s description. Note that by default the provided file descriptors remain open. The complementary class bf(ofdbuf)(3bobcat) by default em(closes) the file descriptor. includefile(include/trailer) bobcat-5.09.01/documentation/man/lm.yo0000644000175000017500000000455014050437223016515 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::lm)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (OFoldStream manipulator) manpagename(FBB::lm)(Manipulator setting left margins of OFoldStream objects) manpagesynopsis() bf(#include ) or nl() bf(#include ) nl() Linking option: tt(-lbobcat) manpagedescription() The tt(lm) class implements a manipulator that can be inserted into tt(OFoldStream) objects to set the stream's left margin to a requested value. Depending on the tab-setting of the tt(OFoldStream) the inserted value represents the number of blank space characters or the number of tab-characters that will be used for the left margin. The request will be processed at the next newline character or tt(std::flush) or tt(std::endl) manipulator that is inserted into the stream. If a line is still once an tt(lm) object and a tt(flush) manipulator are inserted into the stream then the new left margin will be effective at the next word inserted into that line (cf., the example section below). A em(bad_cast) exception is thrown when the manipulator is inserted into an tt(ostream) that is not using a tt(OFoldBuf) buffer. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(CONSTRUCTOR) itemization( itb(lm(size_t newValue)) ) Copy and move constructors (and assignment operators) are available. manpagesection(MEMBER FUNCTIONS) itemization( itb(std::ostream &modify(std::ostream &out) const) This member is normally not directly called from user-programs. Instead, it is called by the insertion operator when inserting the tt(lm) manipulator. ) manpagesection(EXAMPLE) verb( #include #include using namespace std; using namespace FBB; int main() { OFoldStream out(cout, 0, 80); out << "hello world (left margin is 0)" << lm(4) << "\n" "this uses a 4 character wide left margin\n" << lm(0) << flush << "at column 0 again\n"; } ) manpagefiles() em(bobcat/lm) - defines the class interface manpageseealso() bf(bobcat)(7), bf(manipulators)(3bobcat), bf(mlm)(3bobcat), bf(ofoldstream)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/sharedpos.yo0000644000175000017500000001332114050437223020071 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Sharedpos)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Shared Memory Offsets) manpagename(FBB::Sharedpos)(Shared Memory offset controller) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() The class bf(SharedPos) is a support class for Bobcat's shared memory handling classes. It controls the shared memory read/write ofset and ensures that shared memory operations never exceed the shared memory's maximum offset. The class bf(SharedPos) has several public members, but they are primarily useful for other tt(Shared*) classes offered by Bobcat. There is probably little use for a stand-alone bf(SharedPos) object. In the descriptions of the class's member functions tt(offset) refers to the read/write offset within a bf(FBB::SharedSegment)(3bobcat) object for which bf(SharedPos) performs the offset-administration. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(TYPEDEFS AND ENUMS) manpagesection(CONSTRUCTORS) Default, copy and move constructors as well as the copy and move assignment operators are available. The default constructor does not yet monitor the offset of an tt(FBB::SharedSegment) object. The member tt(reset) is used to start monitoring offsets. manpagesection(OVERLOADED OPERATORS) itemization( itb(void operator++()) The offset is incremented. If this member is called when the offset is equal to the shared memory's maximum offset an tt(FBB::Exception) is thrown. itb(void operator+=(size_t len)) The offset is incremented by tt(len). If tt(offset + len) exceeds the shared memory's maximum offset then the offset is set to the maximum offset and an tt(FBB::Exception) is thrown. itb(std::ostream &operator<<(std::ostream &out, SharedPos const &pos)) Inserts information about the bf(SharedPos) object into tt(out). ) manpagesection(MEMBER FUNCTIONS) Note: the behavior of member functions returning values which refer to information of an tt(FBB::SharedSegment) is undefined until the member tt(reset) has been called. itemization( itb(bool atMaxOffset() const) Returns tt(true) if offset equals the maximum offset that can be used for the configured tt(FBB::SharedSegment) object. itb(size_t blockIdx() const) The index of the configured tt(FBB::SharedSegment) object's shared segment data block to which offset refers is returned. itb(size_t blockOffset() const) The offset within the shared segment data block matching the member tt(offset)'s return value is returned. itb(bool eof() const) Returns tt(true) if offset exceeds the maximum offset of any character ever written to the shared memory to which the bf(SharedPos) object interfaces. If tt(eof) returns tt(true) information may still be em(written) to the shared memory: writing is possible until the maximum shared memory segment offset has been reached. itb(std::streamsize eos() const) The offset just beyond the maximum offset for the current shared segment data block is returned. E.g., if tt(blockIdx) returns 5, and the size of the shared segment data blocks equals 2000, then tt(eos) returns 12000 (the first offset of segment 6). itb(std::streamsize maxOffset() const) The maximum possible offset that can be used for the currently monitored tt(FBB::SharedSegment) is returned. itb(std::streamsize offset() const) The offset within the currently monitored shared memory segment is returned. itb(void reset(SharedSegment *sharedData)) The tt(SharedPos) object is reset to monitor the offset of the tt(FBB::SharedSegment) object whose address is passed as argument to tt(reset). The address must point to a bf(sharedsegment)(3bobcat) object that must exist until the end of the bf(SharedPos) object's lifetime or until its next tt(reset) call. Immediately after calling tt(reset) offset is reset to 0. itb(std::streamsize showmanyc() const) The number of characters that can be read from the current shared segment data block is returned. This member interrogates the number of readable characters in the shared memory segment. This number may change while this member is being executed. In order to receive a stable return value, calling functions should have obtained a lock on the tt(FBB::SharedSegment) data before calling this member. See also the bf(sharedsegment)(3bobcat) man-page. itb(std::ios::pos_type seek(std::ios::off_type offset, std::ios::seekdir origin = std::ios::beg)) The monitored offset is changed to this member's tt(offset) argument, relative to tt(origin). Seeking beyond tt(eof) is OK. However, -1 is returned when seeking beyond tt(maxOffset) or seeking before the shared segment's offset 0. ) manpagesection(EXAMPLE) See the bf(sharedstream)(3bobcat) man page. manpagefiles() em(bobcat/sharedpos) - defines the class interface manpageseealso() bf(bobcat)(7), bf(isharedstream)(3bobcat), bf(osharedstream)(3bobcat), bf(sharedblock)(3bobcat), bf(sharedcondition)(3bobcat), bf(sharedmemory)(3bobcat), bf(sharedmutex)(3bobcat), bf(sharedreadme)(7bobcat), bf(sharedsegment)(3bobcat), bf(sharedstream)(3bobcat), bf(sharedbuf)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/digestbuf.yo0000644000175000017500000001121514050437223020055 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::DigestBuf)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Compute Message Digests) manpagename(FBB::DigestBuf) (Computes Message Digests from information inserted into a std::ostream) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() bf(FBB::DigestBuf) objects are bf(std::streambuf) objects that can be used to initialize tt(std::ostream) objects with. All information inserted into such a tt(std::ostream) is used to compute a message digest from. All the message digests defined by the OpenSSL library that can be selected by name may be used in combination with tt(DigestBuf) objects. The following message digest algorithms are currently supported: mull, md2, md5, sha, sha1, sha224, sha256, sha384, sha512, dss, dss1, ecdsa, mdc2, ripemd160. These very names are the ones to use to select the particular digest algorithms for the class's constructor, below. It is quite possible that future releases of the openssl library will support additional message digest algorithms. The header file tt(openssl/evp.h) lists all available digest algorithms (in that file look for tt(EVP_MD *EVP_): a message digest algorithm immediately follows the 2nd underscore. E.g., tt(const EVP_MD *EVP_md4(void)) which refers to the md4 message digest algorithm). includefile(include/namespace) manpagesection(INHERITS FROM) bf(std::streambuf) manpagesection(CONSTRUCTORS) itemization( itb(DigestBuf(char const *type, size_t bufsize = 1024)) This constructor initializes the streambuf, setting it up for the message digest algorithm specified with tt(type). The message digest algorithms specified in the bf(DESCRIPTION) section may be used here. E.g., to use the sha256 algorithm specify tt("sha256"). The tt(bufsize) argument specifies the internal buffer used by tt(DigestBuf) to store incoming characters temporarily. The provided default argument should be OK in all normal cases. ) The copy and move constructors and assignment operators are not available. manpagesection(OVERLOADED OPERATOR) itemization( itb(std::ostream &operator<<(std::ostream &out, DigestBuf const &digestbuf)) The insertion operator is a free function defined in the namespace tt(FBB). It inserts a hash value as a series of hexadecimally displayed values into the provided tt(ostream). See the example below for an illustration. ) manpagesection(MEMBER FUNCTIONS) All members of bf(std::streambuf) are available, as bf(FBB::DigestBuf) inherits from this class. itemization( itb(void eoi()) This member finishes the computation of the message digest computation. It is needed as the tt(DigestBuf) object has no external means for deciding whether all information to compute the digest for has yet been received or not. The general approach to follow when computing a message digest is therefore: verb( create a DigestBuf object use it to create a std::ostream object insert information into the ostream object call the DigestBuf object's eoi() member or insert the eoi manipulator into the ostream (see below) obtain/process the hash value from the DigestBuf object. ) itb(std::string const &hash() const) This member returns the hash value computed by the tt(DigestBuf) object. Its value is only defined after having called tt(close()). The hash value is returned in a tt(std::string) object. This string's tt(length()) member contains the number of characters used by the hash value, and its tt(data()) member refers to the hash value's characters. Note that a hash value's character value may be 0 (not to be confused with tt('0')). itb(void reset()) This member reinitializes the message digest computation. One a message digest has been computed for, say a stream tt(streamA) this member can be called after which the digest for a stream tt(streamB) can be computed using the same tt(DigestBuf) object. ) manpagesection(MANIPULATOR) itemization( itb(FBB::eoi) The tt(eoi) manipulator can be inserted into the tt(ostream) to complete the digest. It performs the same actions as the tt(eoi) member. If inserted into a plain tt(std::ostream) nothing happens. ) manpagesection(EXAMPLE) verbinclude(../../digestbuf/driver/driver.cc) manpagefiles() em(bobcat/digestbuf) - defines the class interface manpageseealso() bf(bobcat)(7), bf(hmacbuf)(3bobcat), bf(std::streambuf) manpagebugs() None reported includefile(include/trailer) bobcat-5.09.01/documentation/man/serversocket.yo0000644000175000017500000001534614050437223020631 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::ServerSocket)(3bobcat) (_CurYrs_)(libbobcat-dev__CurVers_) (Server Socket) manpagename(FBB::ServerSocket) (Server socket accepting Internet connection requests) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() An bf(FBB::ServerSocket) may be constructed to listen for connection requests from the Internet or from the local host. Connection requests may be accepted in either em(blocking) or em(non-blocking) modes. When a connection is accepted a socket is returned which may be used to read information from or write information to the client that requested the connection. The socket that is made available is a em(file descriptor) which may be used to initialize a bf(std::istream) and/or bf(std::ostream). The bf(std::istream) is used to read information from the client process; the bf(std::ostream) is used to send information to the client process. Since a socket may be considered a em(file descriptor) the available bf(FBB::IFdStream), bf(FBB::IFdStreamBuf), bf(FBB::OFdStream), and bf(FBB::OFdStreamBuf) classes may be used profitably here. Note that having available a socket does not mean that this defines the communication protocol. It is (still) the responsibility of the programmer to comply with an existing protocol or to implement a tailor-made protocol. The latter situation implies that the sequence of input- and output operations is defined by the programmer. A Unix Domain server socket can be defined using tt(FBB::LocalServerSocket). includefile(include/namespace) manpagesection(INHERITS FROM) bf(FBB::SocketBase) manpagesection(CONSTRUCTOR) itemization( itb(ServerSocket(size_t port)) This constructor initializes an bf(FBB::ServerSocket) object, which will listen for connections at the specified port. The construction of the socket does not mean that the bf(FBB::ServerSocket) object is actually listening for connections. To start listening, the member bf(listen()) should be used. ) Copy and move constructors (and assignment operators) are not available. manpagesection(MEMBER FUNCTIONS) All members of bf(FBB::SocketBase) (and thus of bf(FBB::InetAddress)) are available, as bf(FBB::ServerSocket) inherits from bf(FBB::SocketBase). itemization( itb(void listen(size_t backlog = 5, bool blocking = true)) The bf(listen()) member defines the way the bf(FBB::ServerSocket) will listen for clients requesting a connection. It can be used only once with a bf(FBB::ServerSocket). An bf(FBB::Exception) object is thrown if listening fails, if the constructor could not create a socket, or if the bf(SocketBase) base class could not properly be constructed. The bf(listen()) member's tt(backlog) parameter defines the size of the bf(FBB::ServerSocket)'s internal queue in which connection requests may be stored waiting for their turn to be serviced. When tt(backlog) requests are waiting and another request arrives, then that request is lost. The member's second parameter, tt(blocking), is used to control the blocking mode. By default, blocking is used, and tt(listen()) will wait until a connection is established. This is ok in situations where clients connect infrquently and for relatively short time intervals. Otherwise, in more complex programs, an bf(FBB::Selector) object can be used to sense input on the server socket and/or on various client sockets. itb(SocketBase accept()) The bf(accept()) member returns an bf(FBB::SocketBase) object containing information about the client whose connection request was accepted. The bf(FBB::SocketBase) object's socket value may be used to initialize streams that can be used to communicate with the client. In more complex programs the bf(FBB::SocketBase) could be passed to a class derived from bf(FBB::Fork), handling the communication with the child as a separate (child) process. ) manpagesection(EXAMPLE) See also the bf(clientsocket)(3bobcat) example. verb( #include #include #include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) try { if (argc == 1) { cerr << "Provide server port number\n"; return 1; } size_t portnr = stoul(argv[1]); ServerSocket server(portnr); cerr << "server listens on port " << argv[1] << endl; cerr << "serversocket returns:\n" << "address = " << server.dottedDecimalAddress() << "\n" "port = " << server.port() << endl; int fd = server.socket(); // open the socket's descriptor cout << "File descriptor of the socket is " << fd << "\n" "The server terminates when it receives a " "single `q' on a line\n" "A connection is terminated when no input " "is received anymore.\n" "Then another connection is possible" << endl; server.listen(); // listen in blocking mode while (true) { SocketBase fdb = server.accept(); int fd = fdb.socket(); cerr << "Client FD = " << fd << ", " << endl << "address = " << fdb.dottedDecimalAddress() << ", " << endl << "communication through port " << fdb.port() << endl; IFdStream in(fd); // stream to read from client OFdStream out(fd); // stream to write to client string cmd; while (getline(in, cmd)) { cout << "Got: " << cmd << endl; out << "Got: " << cmd << "\r" << endl; if (cmd[0] == 'q') return 0; } cout << "Ready for another connection\n"; } } catch (Exception const &err) { cerr << err.what() << endl << "Server socket on port " << argv[1] << " can't be opened" << endl; return -1; } ) manpagefiles() em(bobcat/serversocket) - defines the class interface manpageseealso() bf(bobcat)(7), bf(clientsocket)(3bobcat), bf(fork)(3bobcat), bf(ifdstream)(3bobcat), bf(ifdbuf)(3bobcat), bf(inetaddress)(3bobcat), bf(localserversocket)(3bobcat), bf(ofdstream)(3bobcat), bf(ofdstream)(3bobcat), bf(select)(2), bf(selector)(3bobcat), bf(socketbase)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/bobcat.jpg0000644000175000017500000037125614050437223017502 0ustar frankfrankÿØÿàJFIFHHÿÛC  !"$"$ÿÛCÿÀ³ø"ÿÄ ÿÄH !1A"Qa2q#‘¡B±ÁRbÑð$3r‚’áñC¢Â45Sƒ²Ò%csÿÄÿÄ9!1AQ"aq2¡±Áð#3‘ÑBñ$4RrábCÿÚ ?ìÙÕXÊ¢Y'*‹8 Øi¶ücŽæ~Î|Lôyë%;ëš Õ‹^Ë}ŽÇ#ñþª1ø_P±2$Á5!õ6Úç‘þ—Â_øMÌb 4žIu,H&÷±Ç”„g ezÑ…+ ÉÙg\Š¿.È¿…U7^(‡•ö½ÁÙ±M DuSb»› ë‹Þ{,sÃ,PyžÛ…ï¶9GˆNg—tfÌôÇ“K…°Ô„=ûZø®zU5mÓ_Äöù,ðR¬5RÄ êS¸m€¾û`újå†@YÙnl·;c|Ò‘ãð¤9„%&ª¦MZ£õcæÿ¦*çf:Q é3Ø~;÷Æ4’M?Cm>Ért*lñI#{°úжö”6³ ñÏE\ QJâPyùO¦5Éüb°TJªR“)²ßaúá1OkøXa7„¿ñk—G˜þK7Ä©‰XÄ5 jÚÛcã$‚“ÄwD–:<è(ZÉJ€…ÿž×ÜÛßAÿŦs>SñøBÛ€>[‹cå³;fŽkÎtù¬(ç~Fö°Á7ßÏäž—¿S¯…IãLŽº¡¨0W™ ¨ÈQ£ÒP0õÞØä,[OM• ‚kúþøŸ4¨š¢©ªkª¤’vÒu¹ X”;ÚÀý0;§MŒÅH 6o`ß¶6²Öo?E †ƒQ°ï²Üqú_õÄNæHYJ&’Úà)÷Û}ñ‡¨º†Ÿ<~bI»þøÑUÀ:ZÊÄê[ŽqoÕ"MDyÁº‘Ææöý­÷ÆJì!uÆCrâäìq¦ÆÀ‡#kißõǬ%‰Ù€US°çëƒÏ@7ìÖ±RÄ_ûciæ ^ò\ °¦"xÜMX “§öÆXX$—ÖO呯ãÛïƒ×=ÎŒ,m£o2rHõÇB€>¶%´ùnm×ÛÄt¶¢Íp"ÛöÁµ@ÃÿQ`™E—Ê ;ò-ÿÆ€åúZ­˜y[RÞÀòqŒ‘3 ªÃv’E€ýAÆ=ä¹’BŒ»ì6Ù] ‰lI]½®?{àV¡b*¥\ù†«Ý¿Li/PD:¬{D¶ mÖF$òN§œzÐʦÊ-a¾ n]ìPýÆí¥bЀ­Øj$p1ê»Õ0wcÎ47ÝØ÷8€%Hÿ-¤eNÚÄØú_÷¿Û©ŒyH³1¸aÂãÕsÔÖÀ0Q°?Lm"° ±åmˆCPÂ3°ù¼¤Ÿë‡>¨øÌɉ¤øÊ i•AÜ”!·ä\a8Œhر¸Ø{ûãhø+i m¹½‡^ý±IO+ÓUGShúd:Úû•76ý?|} ઺³h«ãN•,’G6². “ͱll à¶>x+  åv<§×oìöXa)º‚%,»@=†ŸûC~„úâœðsƒ¡¢éŸjåy²Å'Tˆ¢«Xå!v Ê…[X€Úw·<€ ªžŽ¸Ó:f‘ÒÇ ÅÓªš)Ú:³É¤,àaÀ½·µù¾QWG˜d•U4õ KRVÒ± ð°p}¶-q·6[c§øV 4f’J’÷–(îWH#·òî-bGÍcÜNÖÚM›—(/-ðè¢ñ)©y*«(&‰aè««GÌDí¨‚F’ê9 O8ʜζ Þ¥k2êŠL°:âdœ¾‘¨ô@5¬n6 ûaʵQ½44²SÒSXÆV"À£3j ¼Þ¾›aUu8­‰:Q¬b•ž8È™T.£È'M­«p1l¢—’ûa–Ã41É]GM–KKKyÆŠ‰/䑘Á®iç~p,Ô|n¡(+§Y%¼¦kÉMrC)f ˜ÉX“{í|E–çRC->m)Ëå™ÉF’_,ªw ³-¯bEÁ¾ ¥yºµÙe9iëâE!âŸÊ…&ÍpÄ…"À‹wÜßR\kO³É*+c-OK—Ös±P¹Üs±'ÔVÎÒÐÏ;” ñ4±h6º›‚mµíkÛ «ZŠIà˳(⫊Œyæ1ÒIPÛ öïÍïˆü;•å¹u²(ãʨ]EK¥9®¢*€H±°ßVÖ›ßF^ÂË®K!¨!›á vbŽÚL-J’I¸ÄàFCU4F…%te–'q­K ò ˜‘`GÜ`§hY5É)‰ÔGŠ)0cqÈÙ"ësõÛjhØ'+DËêòêO„Ü&¨±+ss«{(õá¯Å¯…4/ÓKÇM)`c>U±'¾ÆßqÈÛ„óST=@r*Yz…¾Eßï°kúŒ UæÇIâ(Ÿ5ÑÕ­sºƒK9©c×¹/·ÌxÜ’ Û‚NZZJ3 ôKNH£fV³Èí¨• v¯~O8®Qª¸Òኢ’•¥žhãQv¾¢.v½¹ßüQ_AS–ÓMñÃåHÒ åä…Ë1N¢T{xß%˜Û·!TW Í-9I‘çiu¼€ZÃ~8·Û}ð.Y”Uæ9„0Ñåí$­ªPîI["ÞÄðå}Êíäj“ ¨cX´RÙÝí© ±»òÜõÁ¾ ª¦Ê3åÌj£©thÊ•%têbUÎÚl íÎÚº+@­•ü4añ +Æ ÖŒ¡F¶ìªu(±ù{qHË3‡wêYéâV*RÝ5}¬m½¾Ø>&zÚyë‘:ŒÉ tì©½Ïøˆ:xØþ¸CTÃ_œ)ÖAuy²™È$†;ñÍ€ÚØ0¾Øh•§øÂ°8‘Ĥj²‹‹›óèIöÄ •VD€ÄGŸUÉÜÜO°l/*”ÕG¨”ÂnM¶Ñæ=¼§žÄ`utx ÄÆ4G^í¿À¯>»a“Vl¾I4¥\ByÝ¢ÞÑ;7Öê» ü×àLô°ÒÆ`ª}FÌ\5®ò„A¸°ºïmýñ¤S¤1—1G9ô…I,>]m$i’á™?q¿û1ðì0•ª©¨1ºÓÆB6ØìÌonä}‡¶ÍO4®ÏðÌÑ‹0PI¾×¸á‡é†yŠd´ùZô ˜M›^ÝJ¨Ý¥`ñ%ùIÛ½ŽÆÖµ÷ãÍ'Ê h)j^—T ¿–à÷–SO%p¶S¢âöþbyÁÕ5$ÖÉ%2BË{¹¾Ýý†ʆ”ÝT4î.~ßL0 Ø+º$ Ý¬ƒƒÍ¶úŒf%FŒÄ ˆæÖt…{©B,m·ÛˆìÏÇùj¼IXþÉ¥ŒÒ£r±Øt€-ÎÄþ˜ð*¨ðnezÊç˜JÅ™tºm¸{áSã¡éÚYk'.n·S¨“ÚÞ l1¯ñ¦Y•e¦µ2ì?"6:˜l{û±äõù5jKKñîTá’icŠ>ð¬PV×I˜ªÙtÙ.xûbµøý”,Þ ¨ž%BQìßö'»ðñ+1ͼQ55I`…ˆéžvØŸ×Cñ²¸IàÊÈ£$-k íc·×c:m<žU ½¢œ‰`˳Ԩ~ø’ª¯ÀÔñõƨ‘•ËÈê0%:æ Y†½‡¹¿úPr*–ð߇Vžª©ºò­Ú0»î6{‹ÆI,•Ù|­Øàöüã™®Æð¹WV̺•4έá&I¨QB’Œº·Áõþ¢©Ú-Ø6Ç/ͼoW༰VGFj)à!gUxÀõÿ±†¹Oâµ_Ѝ„9>Y-;¸±yPƒk‘q~ÞøÉ¦Ó½›åÂ:v£º\ÿâ^ ¦Àµ4³K˜Ãq¨ÜÜq·ÓÎ9µ¶à¨)î}±÷}gá]'‰Õ¿õ=eUh/vŒÔ2¨öØâ½â?øgð5eZêrê€IC8>„êßíŽæ‹ÅtúXyr“þƼZœP†Ö|]D(&p7󅶸Ò[Xy•ô‹yw?{ãÅ4Ò‚·±÷çÿ“ˆBr¬SN›±6µñª»Æ©̶}½ñàvÂÄÜ žËó¾7žUi®,Ñ¡6¬"ÿSß CU0²+™¬ {.Âø–¢5é2‚»ÙÃAa°¶4+iCHÂåB¥‡;{{Û;¹A:¶åSÕFãûþØ„•;Üwã, ¼£æ=±ë¬GÔÛ„ÈÁXéV;’6b2«\+¯6ã>¢XÛF’ÇRÿ‡åem$‡±µ¿®#I%ÖŠ50Þöö¶$˜³ ¤ºüšÀ}1äq”“ó[¦ÃWr Y%›ôËIÕµ®/ýñ³À¬Ž¦ÊàØ½¶>Ñõó‚,/Î20Ä+¸é¾ÖýÇïˆCRSE®,EÏ7Ã3l£5¥­hR¡`7h‰Y‹0?U6ÛëÈÀ'ç0”+yHî=6}CA}ß­Q¬¿sdš®–š©þ`]hOL«_Z·›k$wb7¶;­gKE=2» ¦ZYjæê9EŠ%b‘É«IÍ©HÔopO+ÿsúZªŠ¦¤Z9¥˜õ ]•£º¯ø¶•‡ÿXúg¹¥LÒ“ôb GêH!dשÇþJ# ¢ú›·|r³cÛ#^)pt*ÓåD*²igäd¨¬Š-VÓg˜4®£¥tìoëÆ'|æ¦ :™3ÚxhÞ8Ù£¬¦“¨ÉKpI$éÙ·Qµ†+u¹e6mVe®ñ ’µñÑÄ"*ërªdm¬ µ¶±@»ÛUUåuk4b¦dááJÐCÎP%•¬# {Xò0«'ȵÅvZ²ÈiÞ(©é/ å´¶‹Xg!t«×{€EØŽ[Œœx~‚|±,õšÁ“âàÒÍ!`ÇYmÇr50¶þ˜]QšÍqœÕ×/Š%=\’5¦,XôܮŎ‘º½ˆm¯lC›>bòPüu] #2–„COb­¤F]K »Ãƒ°ÁiG–-; ‚’’œŒÓ0ÌäÕ THGRr‰6W,7ò¯o®šn¬Tù„´i˜ÍmQ8Ò &’y¸7qÛéŠvW›6[Hí•æ•µÔð]êêò"9kiÕo?ÌI ¾ÂÂÇå~,¡ñSÑe9Fq˜™ãtjµDÁŽ—}l¬®HqÎ&>z¾c:Ìú†‹/—1Ìä4‘4«0Cù.þ}%EšÇb7½‰âÖÝÁ¤Êê$Ö•RÒU,iä´—¿ÈÄßVãœ{X)29Ú¶³3–ž¿.:e fboem:‰<NÛnùSâ"ùaLfVç+në܃¶4¨ÿäUËè>ªòŒZÙ ˆ «Ú…îŽ]¦Ì…[4yd4eK>£(Òk$ùT³-¿—‘ŒÎ3¸*U"ËóJ-:z“Ô®bâÊH#Ìx;{b¿˜dù‚ÐÍ] sœÎ®ƒT²¸h U-¹d±{Û{ -ïŠå±:ô%:ä=ÃÓ4µ”U4Ô°€ÚÒff2(²*Æ …°Ð·-arHÞøVÏ–¶m@þ"Aj´ÉIÎ¥°2JT†±$©,n¶ › ¬2›7›øvUâé³…‘i¡’>œzÁ ¬áœ‹}½ÆùåluiIE=Lo"´TÑ5l+üÂ;ニ"à“~%²F©çµÃ(‰…E{dCid4óȨµÿ,³©¸ØïblqV¢Ï+jâ­Í!­žY«)c†ˆM’IŽ@»ªéÔ±k>cɉL«Qá·–·4 ¬¥«éƒ$èŒÒFe‘Ø‹ØÄjfú0Ûç¹VYYð³Ã/Áõ¨–™ÃB¨ËmE‰,IU>c¾þã m‚=òsÿEüKÄ­Njk$iKUÅy%Œ‡Q­˜“ªÀo°±'lTó¨'zxdžò‘´ê‰r@$ìånmvŽØ»BÕ4Ô’¶ZÌôuq2L†§Ë¡™Ž‚H¶ö¿¯®(9Å,Ç8T™êcŠÌdPàCkÛP‘~ޖŸ¤Ð™nìOâoæpBŸ ѤHÄpFÌB[e ¤ìI`I6¶ø­WM3Lªu‡óF<±Ù¯Èo{ ÅÎ ¨WêžT…i‚,e"Ô4*ðtÛ鵆xóSç/ŠJ…R C*rÄvQÏ~>˜»ÒtVÛ’²¯.b•£I÷,HòÛ’£Øm¾5Š(ªuÉ4©P\ÜŽ}Ô[þpfa”×ÆÌ„:!YÂ"-¹"Ü‚9í‚i²Y"lºc4É"‡+þbd·×ƒÅí÷ÅÍßLNBü?¦ &AYª¦¹I~m`nöú5È㊫12“¥SN’¼f)C*!ÒHÜ–bmb6FõÞ*”Êiªš™È©™<ÁiåhYر¶ƒ¤ÿ+[NûßÓ ³,¾¿Âe´p…žYÒ«âU:Â! ®“ó’×¶àƒmX¢JåÈv¤'Ì)i¥®¦¬Í#©39‰ã‹R:ŠÞÛ§Ì/`nwº喣ÄsSå6y…WZ$E¹P6 ì ·{È¿ãÈ'­¬…í4®ÑÂÌÖP£cÍ€#ÔÛ×ÐÒÐIG+UWÓC+Î-TÉ}VPáSº÷È7űЉ-#J´Z†/ÓŽ?Ë^º¯]Í€QpZæû‹LižºÔGà LY8êZ@‘ap× êf6¿˜^ˆbàm.nö½·Ü\_“¶,9‚×´ñê¢ø ×1ÃD‘õcP.TXƒ¡ÔnÇÊú$’´6T¦.ª¬°£·™Ø€'bMín6õÄ‹»LgIBj("YÒŠ(PtÖG!ƒæÔÀy76ûZøc—ÔÍ—S¼2åï- Òt%!£WX[÷½Þ×{ ¦¥Y(¦†’v2ÓHee!ƒ[ccÇ¥½°Ë4¬ªšžx¾.IäÔ#Czzeyó°1—¡¼IK–EAI&\ì,Q0Ff)wF,unIÞü=pn`­+ü5éòÔüˆL©È1³.­ÎåÍ͈¿#Œ_ev©žq9 P˜ bÍæþ`ö±Ö*zQ»Gi"Mª<Ú·Ëî7çÿ|2è…¶8*«¼9 ¹l“Ê> õ5ìUÎ’&ÜïßSdô´ô­W=KÇm ¥3ÝÕΫjí¨»²ûâÌÓÿ¥£†9$„ \3z”m,ÆßV6ߎØMDœÕœ¾äÿ˜} ¢=a.ÃHõ¹qþ-» &<¶†}OI6ªZt~•$Ë»0·<-Áß óyȨ3­*ÆÅE¼Ä¨ÛI \íoLYsÐôùdT¶cÓ{#© ‹.¦%IâÛÍ”vÝ,4Ô¦©]–v»H7m†Ä°’}IÃÚ+´-¬Íçš`ÐÅ*Ä"nF¥f;l9¹?~øß.š¢IE‰„É!`gQ¤¡¸½»›Üq¦Ç +¢Žž”³E ÎÓéWPz¬ªA;j¨ãßôÆM:Õ$1#4•náRa¸ŸñXpWÄ2h6ª•g‚Ö ¤ª’Õ@t¦Ÿ1ï¸7û$¨š†;iˆLD¶Ô“¢ÛEî ¾¸e–×è™W4Žd ÁÆ7CþíbyÚÁg4N*~ǡ՞$uaÅîÅI<ëéÎá‘ö{K@=u³ÇO4ŠZ5cÓˆn1ž'Íi䮞“/š:¸TéY´X½Àó.Û0±µ¯é€W-ÓHU(ÚjÆ´p›Ú6Úç~ âÜàJïˆ@#E”û(½Í›ÒÜâ$“'`’É[%[Í;´·7~²{ñŸÓSM ’’zr Ž ³ù¬7* ¬@ÞÞ¸.::ZjC]$rM …VœØWeöÒ./êAô¿¹nV•õÓÈ좆™–?0˜3¢éÛƒæ]¿Êpï¡fv±S©tª¼0ÐÀ4–q+DŒÊ½ì <öCÖ’¡¤i%œIP CÜý.>ø+ÄU*õÂó4Á3?“q¶ÞÜ_½±6X‘ÓuM<±~A, ¿”;wÛSmkñ€…h‚!SlÒT±aùƒÏ¶’Gï÷Ѫjþ¦¥BkòµÅ·¶ûÞøgtõÂ’9* ]D‚:Œw¿Û‹E¯¿8 ¥’’zˆuš2£¨§™N¥?âòß”S+ON•†›‡(-{›Ûm=ñP«˜€Ÿ—Vú@Üo¶%‘*Œ±9h‰µ£Ü-÷ßß}þø––œd«@ FÒ(%[MÔ_©Äj¹‘åæŒ4ÕPh™-"ÃSXXƯ¹_[KdSU¤±‡¸²É öÕØÛÔvÆTf¼J4’$i#I}1‘p6þm—œmUð3jªXÈÞo—PÚÃôÅT÷[¾’L­uEɺØ(¹Øv7ÆÑÆÁAg@RË°ÚØ/E?X·XEÔI7qô6ãÖTj*^(gHâSw6ò»A·æíú[î\`M%•œ »1 zÿVÆ`¿ˆMRTE jÄÉ)¨(=yoÓ‰L‡z¥ü8Éhszh¾*Yuò#LBŽÜ[f¸c¦fÞðþiBa’š lT²€@°¸·{w÷Ç=üV5ð¾gK]Q$¦švÚM?-·½ðû)üQ¡¬¤Jxâ¾`ê”î7íí·ß?2ÕfQ̘³ó8q(^ vðâL™d¬®‹ éɨþjÁ=ŽÇïÄyŒþ,zD¢RôÈ8¸6{Ž]šx_7Í*¾) §©‘7""Ç{o~Üö.:wàÆQ[áêuƒ1òÊæPÄü×ÚÃéµÑ‹R‹¹Upƒ—˜Ý´ŽøŸáÿJŸà™Œ”Ì¥¾ƒZÄ^öÚ×8ñ"§.Š’ xäéʇRÄÛ³°ãýqöö]EL"eè¡<À÷ÇÍ_?‚9¦y㑘x^©)¦ˆõî»jõbÜZ¼yžÍB¥@Ç›hîšÍK‹4g?Kßß-ðoIø}W’flj ´Å¤ëË·ÖÃ_À¯æ1u²:šñKç·$µÈÿLdͤŽ};xŸ õò.ÏæÂ¶ô}XÑ(b -Ç:{ U2S¨iTw¾*> ‡8¢žxóôªU}Q»¡î?ùÅÐÔ+¥ŸÌ§ÒØàePN¢yÙãQ3åøªñU›R „Å,Ѿ¡}Èìmö7ûcæÉçX-¯Ì¡@Ûõç ?ˆÿ†¾ ñ},‹˜e‰hY£LŠħ×þ+~æñ£¨a&_PÅ)ªEÔ06µýïêocàšÜ/ÁÎÖ–xå h£¨mE¬¬×‹ãÍl¯Ô+ÓˆàソLL:O§•¼ìX€5pÿ\hË”ñ0*£êÛÜíÇé@ø4sêD¦²+t˜Ø6<úãБdò,lJÖ.¤m«mû÷ôÄŠ›JDÖKZäÞàñôÆ*º¬ÒY”êUIÛaÇßÀG©Yµh½ì@mƒíÈÄ^EB´›ªN« é•‘U­å-¾ýùã{ãÆGy´¦F;Þ×?~17ÊijëçO¯oÛ§QoÔ7¾ }e4l†ç`qᢤ:ÈÙvÜ⊀»8;€Fã¿ÓÔ3i‹…ö?|M5ËÉEpnÞ›öý1Ÿ)PQÈ㆗ ‰‰Õ¤èý9Æèå£!j'UÀØüýñ‹y -`ª6õÄq;º+ÚÖ#Mí…!ì„;‚¬.ÎÛï|E¡X™O¡ï‰åS…‰®ãr6¶!e.Û°_6âØb>A‰!Šî/|xQŠZByÙoΈ"€ì °n8zúóoÓ­:JHÒW@¤ÙÂï¶!YŽÊ²ÝæöÛ¶•MLA'u`~QLm¥I¿˜Üݱ±VŽÊÁ‹0µ­pÞø„#2,%Gp/‰Àu ɰߪª²0Ðv*¢Ço\c8XTMíÅȾ! àU.àÞÆøÉ<Ášè Œ—¹'ÓÏ«Pc¦Çb/‰#å˲°¸}û6ØR+òƒówôíýÿlo"¡v-q©A!O&øßRK©UØ µ¶úã@ÌÀùv°ÃÏtuØn[Òücɤà*‹AbÜïûctf Z3ua¸&ÀØlw÷·éb ³9Œ)]Ë €Ø›kÛ…Ïðηá#¯Q8ƒLªKs`mFvçÓÀY‚OLré^UœŠ~¡! K°Sµî4\[{ ·||Ýá*šj/SI^#4’þK¾‹‹0$7ƒ¤ûŽÓà³#Tä T”É$7 Tò³YxØÜ_{¶ý±‹R™d&Ó;…$;…5JŠd—Xep Ù!½Å†/ÜÄùƒG]I@ié>1—2H™aø¬½¢ë̺u–R†Ìlañ]—ÔçpäyFJ«QP¢£2h¤b½Š•¾ÁÁÔÄ5ûÜúX(—5§É¦­£ñ yž_ù’¼Ô5R !cÙÙö`/æ_aéUüA‡'¢¥ˆMK Pæ,«ODÌÊjKCHÁˆ?˜ñ³£c~F+“i‰&Úçõy6SQG•ÐfYñ6"9^ª¾DÌgFÐt«·U“km=Ÿ׿Ôù¼0Å•%<M,Áàbʲ™µ \îjÙ·¹Y˜d?ÃkéàËü7Ô­ŽO†¦§ˆÃwvrß:i c-÷ÙNx—9ðóVA–çí;VªË-U6@Ò^" ¶ùϘ3q·;Š2Ksà¯u)³¯/N&Ê!ª¦£¦" ºXM@iH!ä‘Ë_I¹"ÌvQÀªs\Òºl®‹.¦h™š–AÒ«0´ÆÀ”AU>cßp+Ù½gŒóAԢ˨2âšLº£š™A) >³³$‚»l5Ï)§Ë|EM%-|5±¬=^”EÂØê²iÜ‘³no[Esá2E«6­ðÆwᬂ£7§ A,Â9²á ImIuù¼­rIÛóÅ9c©hÿõ EªÇVh#•]Ù¤óê£ÈŒý,.N÷Åø¾}â*Ũ ù¦ ÙzF Ù’22È×EãmôÛGGürº:ŠêZ<äeò|]@(ù\÷Ûƒ¾ È(ß4«–‹2Ë²ã—ÆIY#}:<ĪÌ ^öä pN'޲zxg«§Ë †­íðæIò²0îšÀb{Ü{û@ñ lÇ+–7‡¤)Ј+N«#C „#ObÚlw<–µÆ+pf#ô"êt©jhÔ0P} ò0%¿O@pó/‘UC[ÀCÂUþ%*‘Ô L‡HE¬þ§¾üáŒA_šÕæÉ”™²‘½uUB®à^9t†Ò¤µù,¹8hʹeRðŠ}3CS˜ÇV*Jˆ •ÔÄ ÆÚ½Ó|ü©©"Y3JŸ‹©PRXPÌ’j;·”‹)Ók6þa¶ã _Ã3‰(©àI¤\¿*`ú˜’Ö°e$…XøÙ«hà¡ZLí3 ™×HIiÿë]ã$«ÀX#PóÇͰűžîP®Œ®‰òYSÄt•ú+i+:t¦6/ª9Y-¶€t-ŽÛ°ìq`¬§š³ÃðµrÖf•’»MP²)ävW”î@&?æ²Úü0²š¢—0Ë(c¦Ž:ªJZ–ÕÀ~ ¤ªªd-¨^U;Ø &äÜŒY(hëü)S^ùuhë=;DáÙTd*4Ô5µXZÝ´S$ÕSìN¨¦xŸâ²‰¢5rÇ,ŠTiι@_"ïÅô‚-Å€q„•õ4±fo‡ž&Œ$†YQ_Pµ÷yÉa¦ã{𠯞0Ëh§7Å 29.H}Cù‰@@¯}À¸˜¥WÒšÙ_;Ž›7QåI#ŒD7[ƒkrµñf)RäKk€Zir©çjjX*¬Å5Növ‰VÊ¥ˆ‹5ÍñfSÕ;Skš9_ç Xçc¨ïÏÛ3(ª'•èr¡ t´ñhN»,rUh»–ˆ%ˆ+s`‰ÅZ¢/Îi讄Ë{-íroÙ¿^×¹wÙ#ØÎdJÈ™)bge[NÌöSm#@êÖy¹¶jKÕN" ¹<ñF4“¤rA$îˆúâT¢VÈMGJ¢Ä’N½"íº‘É,Û€7û¸§«Ÿ3ñ%ÆåÔ‘ôd5 _Jº-Ø÷±m{[~O8–Y‹—„²äðÝMNcÇ1‘#XnC‚@ÔÜ\(M7½÷ê[±²’ÓåõœTBëP 5u&@#%Æ››.­:¬°ÖÛ‚E˜ÿêøé'Š’¦:6¹\(}¹Q½‰‹ƒ¤\ßLû5Ÿ2­–QWPG]ºˆ¾][ 6ç± Osh³j×™¥¥‹¦!§…C¹DÒefØ›o}‰'Ó §®D‚0¢MÁ6ïe;öß|XóÜښƂÜI-¢‘‘õÎÌl7 o*ŽvÒq„4‘=M|tÓKsK1™THÚt«j6–<÷ÄÆŸÚd}›eP¢C(¨?M¢ŒD$Öá—‹|¦Áüã}“liN’â¨Eùˆ?˜K)ºƒÁnonI¾ÛbQ5-<†‡âÑ:Ä¢0m@“Åì@æÛ’xŦ©éhŒqJÅRš)Ö$¨Rfu$à²ØmÁç’îMrÃSa¢ËºÅc¦ÌjªÂF…cRÚáTµÆß±Àpe­T9ToäF°îþŸM¶ÃÌê?‡¤†´×´E˜¬Š,d,È·]r–ß·aµ·I˜gqumG ¡PBÈ&$’8;Ž?|Ûè„5TuQDfDV³ÆÎ¤¶ÇŽ1äï,’êÚÃR™5yîn6äv"ÜÛÔgõÕ´pÓÖº³DtÅ'ó"ßu—çƒÎ½C¨XÎè$º¡;ßnO>ŸÛ¾ §-èA8M`k(,#ý.>÷À¢ôªAí"‹‚7°Å‡+Ïèé¼?>X|9’ÏSRìã0ªYLé«ËäüÀ‹m¿óõÂm$Ç‘$±Ýlmµ½ýï†NÈkJæs OÔr ÒM>„ßcÁ_ÖǶäæu‹S%ÙV-Q‚B€nûqˆ¥u£uë¤Ò.cý0D©ÇDR]YHÖ-}¬>‡‚ ea~I%š×$݆4ë×­DЬTj>_Mÿ[਄>¹ƒ³‹êZÆö]½0bº´B²zxã]%è^5cÁ'¿$­CÌέ¡1 .-èIÆašSE׺7.W§¤7¡õçëlf!µÿâ/%øïÏÒ$ž"lŽÛZÖÿbøã?†y™|ÐUÖPT?P]¬¡oÅì6*Ao}[c¶øÚºt¦‰i;n8a‰¿hcÌØZ5h”\wÔ{íß{ãÃOPôšG‰_"O+ÇŽˆr¬®¢®H§‹RSÞÎMïúø¿nø¹Öes5=5]#]à7`x6ÁSÐ,6Uü¦Q°ß ²hL´OCpGûõÇ#K)Ûg=g¥õåuÐOB•1J¥ó ð{á-e5ddÄUŠ›qlÊßÂÞ%«©ŽQ%5XÖTl ú_ xÆžŽGš´$j6{þøìnQ’}Ù)â{WLéŸ ‘ºH€‡w¿âÃgÀ¿ˆ‡?Ê¥GW)iQ?üd²·=¸ýñôöAø‹çÙÁeó#°Õ7qÈÅñÓÂTÞ.Ž¢3ª^'Sò›ïì~øëiå 2ø“IölÁ“Ë[_Bþ"Ó'…a̤+;Ñ z‘XoRÿ®.o‹²LÚ™*²Êã$L·[°íÛ¯ðs•~ñIÊsÈÒzY_DS”ºº6ÚXp·ôaÜwœ¯À™6FÏYSBZë A·äëô¸ ÷bå5Å'q+“gtÂÆJÈÀÒKZÇ7þ%3ܳ4ðóQ‰aœ‡ ƒ´» ëæý±õKø{'ª„ÓÕPÂèyÔ£úãŒþ2Ã^_PÔfþ­–‹1 ŠYñLmÀ'ä;Qê1_†áƳ©ÛAÒaIÙñiÌAO ›±íŸ)Í¿Ó kòªª Þ§.¯SKSOhåWKY¯ýýxúce¥UŒkSÒùüž`»üÄwíèqîÓO”u*€ã§:™Y1ˆE ½­¿ÓÛôïM;Â/-ï¨Ym`oÜ6‰#øKH4}Á!¸<{ßŽÇØ`yéµêo0ˆ.èÄÆýû®vÁ¬·”ÆUI±¿$ÞÇ÷ÄoM¬ŒFÚ‡§§í‚š¶:—Nësí·÷ý±˜Ý¨³Þþ‚äûbU #Hìm<“{ܯéQ$vV¾•bËÁà K"2£J Y¼À–ìß2†Ršé’Àéäþ0À5™LŒË *Wrn7ó[úíˆÅ€Ð¶ÒM˜‘Æ6XÑZÜ:Eöõ#÷¶1Ð0k’Äì›ï€WŒƒ¤þR ’C_éÆ<$dT·”Yÿ ÷¾ßßJ­ÒöòÞüã¬N‡*ö*àÝpHFÊv,äèÙl¼ã$¼„$£AÚÛ›ñ‰•m¡íT+¯çÄÜ}ÇaýOéˆCQ%Y,}lx~qí²ÓTu)ö;FÅ팜4B·R€Wûß°õÇŠ#fÐΪ@½•xöæçPœÁ£’±ç‚™cŽCsþO_ß|@”äÙ™UU÷ @Ü~¸ò%´";—!x;[˜Ã£•v°óík{_b>™f]h4”q‰)1’µìlÛôõÇ"êt«Ü|Åœmkÿ¡ÆM¨,ê4’6Ü÷Ä!-=#HIUÞçVæÝ·çÖø‘)çkt:8.Ão`§îבM 7RZ‰>! b8Æã§bY¯Çr-Îø9U,ò1Ôm¿”› ûàQ -F­üÆÌo]cT2#u|ÂÖòúo‰X2Kue*P Èo¿ÜÛîq‘S1{ ¤¹¹û}¦¬Ð´ve&5MБeäïL ÆK8!ÁØzúor~Ø"8µRÁÔ #h°n ùù8ΤK¨éclÛÜ’Ùýp£º—+®‚XØØl»úx~Øî_…¹…&}CPµr²¹hZs¬†VIÖ·ÕÚÌx¿ëŽ%*’ņº¯Å°ûÀ9›äÞ ‚MX§H,-r=í„ˈS;Ô_-s5$õrÖÈÙœ1 ©ˆÞ÷ã׿¶.¾ñ[ÓÓÏáÑOIQIQh=i`¦ÌØoZûÞÝͱHËÖŠ¶ )©ªJ¥Ç˜1 µêQ°,€}ž7Á³KEM.yq™c*ÌçHY~VVdâûvòØï{cš¾¡v‹žsŸKCY]F¹œ”4vè˜ÒQÔfÎöÜX,Ø3$©‚£#Ž óúˆeª£êäòÌ‘Í ìÈË $Ïó^æû÷Å -γ\¡((èRŽ(ª˜-Ô¢3ÀñÊjvÿ˜•Ãß%Ì󚪎´«—½<¤RÉ¢¢%Õª­bÁn66õÜâUðYmô8’,žw9‡Æx-¡PA‚ŽIeF 11˜Ã0#Q$0·$lÒRPë¨_dÍŽÔiRU5c³1;0E6N¦×+}ïr§À™æi˜ÖÖTQCÎe:c¥„Ç$ÑȲÉÓ pÚu’4ˆ8)ól¦jÊš·ªÍ¢9D´«—U<¯JxȬ,̬mæ,YˆØ.*EÓ'/ä5 lç%Î ¯ðçˆséÝg9giÔjdV¢¶H6õO„³ÌØÓµ>ayRÒ˜©jè&$j- ˆ;†ío{`zO?ÀÅE6cC%RL±FÕ´à9î<Û½Áô8 øT¾ 9¥ mKe™t…–©2‰ ³Ê·Éo=˜B€·'ro‹ít,žÞþ!›ÃY<£1‡)4p>ªI¥ ¾WQRÛ­º îiy­e=vmQO‘ÖTICXß‚ZY˜´QǼJ‹&Ú·¶Ö+‹Nf´™¤””sÏWKCdG hŽ’´šÕVK€«ÇQ–ÜX•IšdóÖÿW«¤Ž7o‰Êªç‰gtQ¤m· Y~R5U•Њßx¸RŒºƒ3É|=VÕOO˜×ºs¬j/#¦ñ¸fµ‚7Í{ì/&][ÿ¥ü7ª9ó_Ï¥ F¢#-UlÎ Y b #loåàžN3ÄVf9•=kPSÍ *LqSÀ]n ›Ùˆeó¸‚m„=jê<®¢¯;Ì!Éå•d®1Ë,“F‚˘›ªì¢ÊG“Mö°Å;ý(N»/¹ŽxjZ?ý'YM—Bâ]€©Q;!'Rmum‡ë€+3¸« RC˜¤óÎÌiÒ2ô°Ì»#4Ï¥ (. oÓÚøç¹Õ6BµB¨ªrÉÖ U3 VÁX +³¶Õ`C\_q‹Cžå¹vaIšÖÔõ©%-QQÐX™4”»–:F£¦öµ·—<2‹èÚl¿ÄUñ@‰1£Ëê<”ì5ÙÝ]ƒ$L×f[‚Úù%½Â*O ÔÑPÕTgy–_UÓ!ŒÕÔ°2  PªXl[Rع>Qfa'‹rªt†ŽZ¶Ž*x*:TµtÍÝ¢¹d, ‘AbAÔ/`0«6Îe«¤¥–®³¨ZœQGN¦HÖ@™ÚÀoͬì÷¾ÖB—E¶ŠÞuG–É%‘ikj¯†5RF]*@ä‚É}È…Ým~X|IG>OC$ô•³(4€-K­Ê3›Z›µÍ÷8eʵ“šµÏ©CD«T]eI7¿WËlD{$3”I§6ak˜ŠœÖ|Â\Êdé¨J’¦4Ž4Œ9ak—:.…õj6Ü¡*¦…‘Y=5;¥+–’Ÿ¨ñ´'yNÄ‘³ÇæÛaˆŒóÒfz±iQ¬’tË>’P¹³X 0<3©²Ù‡‡¾+¬ŒÞEHVm/S¥Èsk[HPí`oçQºák–Ï@‚‰)«B¤Põ. îB¡厢iµˆùu+Å@Gk±¾qOÔI*᦭˜BJ5E€vÛBÙlÈ ±kÜóÍ…Ôº,Ó0øšºªÊXµ#ÇK¦ äKò±A7amñA”Õ&csuši ˜U~oFTÚþbHÔv÷ûž1m¬Î_•KMšfuz´Ó:Dd‘dSp¯å•Û{ìÆÖã sª:–¤ÍòD§êòC™eeÖ E–à› ­¸¸’#¤‚(#ª­X險®† Gä騻µÊ¥È¾±rmmÉÞÉ5'bÇ„E—Åñ"=Ó '©UWR›V¬EÀ6äÚÖà âc–6MQ›RÓÕQÄ“ƒ•RI­Ò©—H•Ø3å…¸¹ûó¤K-BPÇIºVŠWTŒ=KyÉà’É'±ÂZ褪ž²½Ò8&«y„ÃxàRÁˆÊm½ímÈÃBM•SÁšé'ÊÊE4U’FÎå@hßUÜÆÖ µ î,ÄÛlI‹!×IULe«ºMJ¢K€,~8aëél1Ê2å™R$¤¥ªš»ÉÔšR °³¸C¶ÞSqØ8°ât«ÍòèáŠbbÌAFÊßÊ*X‹½³Ì] EV:…Jèk˜M$릛•šúYF÷}¸&ÖǕѪ¦¦•ÿæ‰Pº†Ù. ¬ÂÛq¶ø¶] Ú–÷;{b«5+tMfÆÈE¯¹Û°ÛG,ùmBOM;Äɰ™RŽx¶Û~÷ÀP¤öv:’|×Ê“(–ôRÓFâ13Ʊ({ w·bAïa)é"¨…dª†VªH4D†P±­†Wåw$ðpºlú«3¤H³£i S¤()®äqÆ­m{ž×Ç‘Í,´M0¬j¦E‘¤“r¢×ž÷?¾ R®D`ï“Ô¨§c$Ê4FÖÓpÆ÷=ûoïé3jªJ³4eK4a@ºé¹ç×ý/‚§›â‘i: IºV4!€$úÞÃÌFø§œE"é,×Y“e÷¶"~ŒÊ…–´´Q$“V±c+w.àzŒVZ2ídˆ¡p7 ÷ú`÷+IÒ•ô5þB@'ûÿLÈ®Ý-J¥lF­Í¾¸eÚ$I)ÙÄf)GQmu¿ly$ºÁº m•UA»{ßëlz¤(Y‹»ýoŒ{´m%ÙE†‹Á¿ =Œ2©£¦ëCð/V-¨‚º#“ÜX×O+<ÊúNeôÛµï‰aªEVµ›‚ŽTÇ'‚/÷¾4ždž™u²§uPàì¶íß„P,šÝš1(?æ#ký%˜ÃT5³Ãƒb4íµ‡ô¾"ë4b VÅäI°[m½½}qá7A;—.@µ”`ð”n›2G€nP›Ÿ¶29¤XX¬ÌT¸:\€ úû×*Hºu(mK¹$_ÀÐdfAmŠ‹›ƒ~16c™Öˆc¨¨zŽœk–_µö¹Æ`§vªë‡Q¸RlG|f!µ¿óª|¾™ÀŒHõر6þ–ÅÃþ3¬·6ðá…^6ªˆ›µÅͬü[ñ“0–Z¯‡Y‘C1 Ý­°ý±à·Š…¼R¨­¢'–Á€]$î.väãªðäô)ú f†ìI¥ÉõLjíQPlû_²BÑ#¶Ê“ŽsâÿPC”ŠÎª1”kM/~FÛñŽm™ÿÄ Ôeðj#9‚Û‘ÜñŽNŸÃòå§ÁÏŦ“šrE‹Çþ9¦_¶W)3R± ¶•6æÿlsÅÖdó¦YÓgÅ$Vó†Ûïmþ˜åUùåunmüOZ´é&Ö“Ê×"÷sŽ¢ù,¿ˆþ¦_JlÞ—óikuAµÐ“Ç?¶;484Ù#’}~§Jx¢šoÐAø Ï•~ ky„±ÌKÖáGoü|}s™Ó®jÐÔÁ#7囨|Ç?þ~æ‘VC˜g5²üB¸†= ‡¾;·†2ªì¶tZº†’šÖ!¬qƒ]“lßÊ‘—Pã4ÔY>T¯8BHr,Iûsý°ñM™µ¯ÈàéÛë·®–²´…ÉbHb¢ÖÀÜmÎÖöÄ= gS¤Æ™ÉÛcÿë~žãNƒÍ*§`úMÛŠ@E¨ª8>o2Ÿ1Øú‡ë†?ÃÈT¸Y 0¸R·¹>˜ĈÆŒ£weØýÿQ†©Pñ¶™âb%ˆQv&Ö°7ÚØQCÒº¯"Ãæ¿7ý°v)‡ Çp7âefT[‚WŸ”^û½Î$‘º–‘ŠĪÛ •¢3j@-æ;~»‘úaì„)¦‘y‚ìß1í&V €àßaþýq wGF€;¡`@.û|K$r#8yl<¤ÃÔû¹Û²•‰Bºì‡a}‡ïô@¡#U˜Éo8cl;OPÏ1GV>Pª,-ÎÂÜb‚Iåbï®ûŒDqþn²÷g÷K_cöǺõ)`¾UÈ€ ÿë „ÈQ#CÔ#vbo}½nvß×Ç£«¨ y:oa·¿½ùÄ!ˆŽñE—Wÿ‘@¸ý¿¯ÛßÂU÷.U›I¶%@<ßm†ØâŒ•ƒ¡kæß·¦62F²<ÀYȸónnEÒÛsˆC4¤£XT¾ÙØ CÛ¤FET›å-»saka‰a¨VÒ¤Ž=-‚# ¿˜fI#bq,SH©®€JX‹G•­¹¿ÚãR®J(ŽBJ³ã}¿¾5ŽƒYõ–±Qakí{÷ÄŽ½z¹òáŒï°m®Å¿¾ H•F†Dt¥ívµÎûúc$E(£-÷d½·Ûcfb¨Í&À û ¿QúãO#>‰.„(Ûò× )è"T‚lo¬Ãa®ØóA$·ÊÄßK~»ck©á ?”în#í‰'•ÄìKBº˜Ø•#Hæöç°?o| ÷ pÈ|g$hiêúE®W¬ñi2 ’A m{û_O%­¦¯ðìSU<³RL—øË$sôï¡“‚›sɰµìmóº ÊF¨ƒ]Û›ùô´ø7Äu9l‚‰¦~C V D×°>coñZçkŸlfËŠùŠ,S¾¥˜3×|6e–=B¶•1HUdK¤> 9±?Lá¼æJ*Ì¡–:U«uw–bŸ5”juieU¾ÖÛœ'Ë+œ  lÎ ª)â*£›†mÂm¸[m±Q¾7š²ŒLÙ(¡j™-ÕŠe‘%•ˆÐ²-ŽÛísŒnýGÜ×Eó3ñfš º\šƒø€Ò)s4鱺£VöFä›^üb˘g26[ü0§¨éaÓŸ ˜YAá\HÒܱ;›ã‘Q¼Ôµ2QÓ;ÔÅ3¹UIÕÌ6Öu¯¥ŽÚM°M^}˜ÉUE$U³V7…kV&ìåwÀ}®FÅI–,‰öuLŸ6’*8§§–´Ö'’ÙA&=MrƒI »ü×$é±µÉÂßx²¨ÔGSO-l™ŒàÓµ%¢/($±K€ “óÜ“kzâMâ¬öjTš<ª¢ž{=;LXª¶ÛË"ª®Æúoå¶×ßmTÏÄfZêúÏ‹ª#Š3T.§7µ®Ç`4E÷ÚÍUOâÚ®¢ ÎZJõ€Á …úŒ¾Àäv˜’y`vS"ð´rÕÇ>yQË•B-S´éÔˆ×pOÎÇrÿ(µ±¯"ùa“k’:,³+Ã=JŠÆ¦J˜’D¢Ö¢IB6 $ÛWÏóüq9¬Ôª´o£áÖë²´€y´ÆO˜žFÜ}6MWZ•äRÑe¯OI …ÙÉPMÊ*-{ØØvì0ëÃIM”æ“|TÙU|ñ[N°dkŸ. Æéå­åäïë{ŒnÁºèj”ë%5 ELÔâyT|-LND î·qó-ŠÜÜ1ôRü¼¶Ÿ2̳Šyj*@jU5 sek0Þ÷"Äyv# ³œï7Í^®–tQP]iú”³±Œ Ôò,ª@»µ´¹Ÿ Érè$Ë^7i(éjËU,ò¢O]7åþJiÙµjÓвÞÄU~%…Fº9"Ët´Q£y–G ¨+pt(·[€ íe3|¦’¡s<¾ª‘)äC™#H$ЈÎ-$—²–.8ä ñ¾š·:­ÎëÛ,ŽiJŠhe/$tà@KyZûjîØ 2Íê £ ÌêZ¦²¨VæfšgH$!¬ «ÕbÚ€à× â¤¹ÐÄfTuõ¯K•ÎÐSJˆäC,lH.ãX(Ý}ÊÛ€/o¬lʵª3ßÉðÔÔ€%\†Ñbd ü¬K½…Ã/{Z‹Oi]I.q6cI¥ø33ÇÕ»1O)ÊI¹·bO—.¢•* Q$•ÓC:CRË,®à ”·•W^‘¿ÓkíR"n‰6mO™Råõ5u™Õf™ô%SÆ,È.4¨@S©‡Æ×á=_ˆ¨+d©S”­TñEV¡ SÄä±!™ŸVýÅ…ñ¦k#×ç9‚š,Ê¢¦¾µQªZ`G)‘AÑ` `Il ±/†rì¤H”t°f•4̆Ig©t=”r£Q°mÆç½øÃÂ;cÉ[T×ÔTÑÏMU5<ƽ;B@:SS‚¾­ÍØrZûp«Ij)XSOWK §RjµG);hãkbN×Û|EIO,óÌe‚ 4ÄÜ ±< ½¸`/ňäñ|dô“tž¸ˆÖ…î†ÞÊ6ÓeÞþ¸h*V+å‚ÿ#J½Žª%I‘%%Šjß@ LרX^æöÅÊGê"g5peÂgÔg”Ç¢4¾äësÅ‹í`1­$m&iBJ xêÕb0ˬk!5l4 ›Úâö±¬ÓRg5l«Q]E¢9jkŒÊ‚62#6Ö8$X‹ ÞÄ ²ÎéCí+Ã(É+V%HA,®[ÈUP’B¥ôé·˜kH7 :‰(aj5ò@Æ%.ŒÏ»"/`§OqumÍŽKW ¹… ŠŒU†ËÞ©¡Õ î…€¾½ /·”ö6µ^¼šjqXª­'OT‰g‰â”– ª‹e;)Ü ƒk.Û©³\ŠRšqÔsLºµë£!?á;1Ûm‡cЦaÁO#Æì\ôÕAƒ€nG`pûᦒ©©«J‹D"E†7 N¬ÛM½—ïˆ³Š ØhRXbã¶¿4ª„›åÞûñ¡7È¥f™«*¤“2–iŒQ21•…”€£së¨ÚÜÚÇße´äë$’ªÈÖe•ÅHõ ßßoC‚g…³ ºzzU¥2Ós K¥RnÅI¹o5ˆ>UÄ´5Q×å±RL‘¢º³4Î¥¤•Šɸv'Û}P}]?[\ S v‘ÞBãQa°R6Ø}ùï€ãg貪Ç:F ÁT¸¸`>Æã›Û £Ë(¦¤–ª*åH¡†7cÍ+ 1;“±öõ¦ˆSÍ/QzŒ±9uYAKB݈ÿð wÃoÓwÓ#Ø´’݈·nû|Þ¶ÃH(š¥•ƒÅ¢ SÁÔ´áÉäy†Ø‚:+S‰ªÁy#U7QÁ`6#ëoÓEJÒE0¼k;³F)´…ò¹-òÿ‹›¶í‚vÊF­¦+2Ç?@Ù…ÈeÙ´ÞöææÖlHJ:3P’WÕÓi¥‹ªI"÷6Ûæ¶!¸•´¸*¡59nl7ú£ëlF8ר¬&fu’44Î[@HΡ}ÕEûü¸ûþ|¹‡S0’ÒI5™ñ¤î,;vÇȘ3:j©F„Iãç}î ñÉ·ëÑà ªZßÐI!EŒ-ÓƒŽÉ¸Æ ¦gÔ§' g_NçŸ|ÅéÝ›ËÓMeUye{bIXšÓåÔ°ìOÓûã#*:lœ{ß×cœ’ýBÛ­¯¿§ìp ¬+ 22Ç羑v¸\në ë+j» sooÓ:&F`é¦ÄãÏ;2Gi¡¬E6'îL…šiË$ #­Ùƒ-¬qí°Çša“TöÙm©KEÿA~9Æ‚&,ª¡Y]@ÛÌAù¶û_olHCtä…SùõÛI>ÖãÀF5£G$l¥‘®„r.7ûZÖÇ¥F‚ÇMÎæCó_Qú\sÈÆà-Q %Ø–6°°½ÿ®2Hã:€(l_Ðjú[Ÿ¾È`@á§•X„ÒM…ÍÎÖÆ±²Äš¯åPÚÌMÿ—õûãwˆúHWWÊ âÞܶ0þe×ÊɧI%v@G;wÀ!¤‰d¬²¨€¤­­ÏØþ˜òXÐÉ¢I\òÚ¹ý/‰’V¸$%ØÒÄîN!$¥Œ‘–mÞ×#Ù ·á>©š:Õô’-©‹æ"çÊxVýŽ.U}&vjd¯¡‘b‚HÐ+hé2 †{j7ò7àîqÉr:Êì£7¦®„J­€•¾a­xϨ#×Lн%_âTó4©øˆÃ*ÚPŽý¿AŒ¹±zt\Ëàê>††ž ‰*TjpPyV#ºß·¯±-;1˜¬--0 G@Hb¬­ªÞP6¿~EöĬ¹œUU+—eÓ§æÁ ² z¶mDm·§¦£NžmU4õðËIT5ÀC n²oÉ¿”Kw6ÆYD=Ž^Jf£ŒÖF`.Hv7ÓrúqºÜ}‡lEI=-,õ+$ZgUòÅò™.EÚãgeqº•߱䯓𢫠UD²:Êb¢’âß–À•!ƒXêø†¾¥)¯JY$qWEpÅ‹æ6ØÝ»]Τš°Õr‡™ýfYðˆËU˜`r)$y<ñ)ŠüÀŽÄ¨ã¥ÍRG ;¼ »¼~vg-©X¡>K…>ÛÇRÉ!¢ rʪˆ•À/$`€¥€Û{ƒ½‡ØaÍŘG).µcX^‚ÓÞÄlžbàZÄ@·8*\ô+å rßãÔ2M–š±VÅd¨ÎkÛ‹ ­k)àã9 [UMBez9#‰¹]ë»4wÜwcp4ê&à*²|Ó% 9s Í?[K±n˜¥Õveû~vÀùöeùë=}M­WhFtc§k*ð@ÏóX“l:{‰Ëoˆ)&JXòúêʇDoR!±F¿ Ç6æöb1YS]O«.š¦GšK¸v÷G21Ô åàØßŒU)ëè…2TTäSÒåñÎ&’4© ÌH$›¨±ÿ@Þ£$ñ]=mttš)é„zD 4Ž|ÁIb4DŸ°ô±Ib’û%«CJœãÃÑU°uU55$/ MW!‘«*n»r¢ÅM¶½Ž)2Ûç52TÔeÑ 8táiq*t¸UMˆ¾‘Þ÷ßåÌ~ »1ˆtŒr…Nª´æírQ­±+mïpžFä“eƒŠÇ•ëF²1ÔÁ-«}EN¿'öÃB; 'eÄ5ôSœ°¬JÒGG ÐÄ[f}6 ’|§rJ‘űXøè²ú4´*‰òG'̱½¸¸õ]½ñxñeFEDÍIEלÊÂ)dr¨ö±$÷‘¬ÞÀ€ Ú×5úÊ:ɪ㩞L‘C$‹$ѵÞ+{rI]…»€1ªÄ’®†Sææ9m44ÖU=Gü¼1ÖRݵìK4mÈ‘ü£“cŽ“xZlß9¡Ëà˨ž µ"éSÑÍ*GOK&£,Á¤`I:u %@ê îXÞË$¢ ¢ž¦¤SxŽ„5uT’Y"3($fÿ6›‹@º–°'f•ôiMvES[FÝfZú7Ò„bºb‰‡•5=…ì ±=í\šºhtMG:æÇ(’º³¼&®ªw“U€s!ÜÊÀ1¾Ú‰; &§šÐå­]¥óUž† zЦ§˜¼…) ÒQÙ®lÖÙ/Í‹ç„ë3iëhKIÕb›TKUXTSͰ“B¡QvbÎÛlür2ÚßGD”T ˜ÇÕGQN¥guIˆëo9NÚ›¹¹ÅOà—=™O§È%\²Á$u Q(¦èT»+ºj fb©ü¼ZçmÖà(ͲØAPµbžˆÁy¡iG—K ²ç!Aã†; ˆ3Ox¶¹èM<5±¬rD&€!.Ò@ÔÚ¯¸±Á™SÌþ+8–:,È­CT<ÕHC.›nVÖkê6ÄpæÐEw)Ÿ,¤¡ž›2Ì*©fHÞ¦B´ˆ¡B•s¤0÷ke:¼ÃË›C=,¨sˆ]ëfÉÔ§A#Ä[¨ÈÜ_ù² ½±‰jâ¢ÏEKQTºf˙гtUô†ò‘r ^ÄØo°ÂÊ<‡2Îë]åÌ㤦4rÅ$ˆeUˆ@E÷7ÞæÄß¶˜Âãl®ÆÙ[e”tU1Tä4e 1§j¦GµîŠÌß—bm°õãœMÕU§†y⨎*‡üéAnŒìLl.@Û¸#SåYÇRiêgCEÔDª¨é³,ºËXJ@±RIÕµìNeešOX2¼ÂªT|,zå,‘„k++î]´’/p[‹‚¹èÖi[¦QæXÑb“©S,Àæ² ¿bHõ¹Á³PSSW×å´Ó, ôúS4fÒé+­Šü¥I]>c¶øŽ®‚I2ÖZ4©š 7Òï3àë^×Vy œÚåy b½]EC.šºAM4ê³–w/.¯›X¹ .ªltÛO_…ðI6>¤Í©²Ü²±*"ÅA’AsÙ£[Ò{nnª¾:ªª™QZOËRßQPOŸQ?P» XGSdÔ5™‚šḋ.ÜÉ2½=(6 "‰{.Ëk\€.NëØ+,Ôd‰†–`QÊL¢ÄÛS[¿6|«âaÜeEc¡uå*e7Üoí¨+é⬊ªh£©xÛ΀·7±=ö6ýqPª˜ ã1ïÒMÌd{úv;ú)]ÐH^4Ö@ÈI<}=ðS¯¼eã4ðÞd<'Qâéž„ŠŠ÷†JaRÂhuÈÚJ€w HRv«6gWOšÃU`Z2…‹ “nms¿÷½ð]ˆ3šL¢|®ž¦igõ"6ó4½¯{]tþ˜@d’Yž6@ŒÝäbmí‰ÊØ_¥Âù¾Rs¸«$®©¤cqC±,’ 2€ Û}DKß“½Ó;‚L—À9gŠk+²ªü¿4}4ñSj„s¨¢–ʯº’ÀPu¡*ñ^f1é#H!AòßÖþþŸAƒi¤IæïNb3nX5Šê® Zýñžx#'ºÇÞ¨j3LòŒ¢Irõ’œD|ÝRÏ«UÜ\› €úaFcVDï$Lë;«*€@Ð/qk}w÷ )rì¨UNõ5/JzBTPäþb€JnH>ÄóŠõj151G#ÊuiSämÉ úY |™ƒtÜË'UIT#‹mô-ú—³TJ–TÕ‰ÔÌ. ƒ·`vÀ€Ó®·%…ŠÜ¸;ó·ëFaªxÝ(â2«,¦ÏÛÓmC¢cD›Tºõ)žæÿ\“<àD+I 7e]¯{ý°ó¼Ó ¨,×vrpÏ.häs®$ƒY60 ¬ÂÀž÷ý±˜Kš ÖGÞÏbE­¿AEÕ’ÍrÀ°¾¯”íbOn¸lÃ××LÝx™<ýd¼ŽIöíˆM-õJU p“ù¡­åÿ¶ö¸U:â‚ °¦ò¢'ó%\IúcYORXàŠb!YU˜o· ýíïƒj‚TÔÉ%4!âg¿J!W¹@n×ÿ-ûài5§BØ-Žû0ÛrGžÛá…=®uš~iDe…Ñïe Øß’Lfx~(êªÌ“,s,q e†`<‹u‰Ü®ý¬IØŒÂ9íàd>«™¤hcêH5ꈫ©M†à¶›_{Üð²™ÒÅ,zŠ®‡#ù@ ›wØ+;൧…”¼ ÊÛ.¡”s}Í¿>Ø6d¨¥&1!{nYÈ+_V·ÛØáâ¨Û.„b#Ô:nàËçM‡$X’;vÆä2ÅÔ ³Hä ×b-sÏÓúc,CXس@'Aî8¾&§!ˆ‘ãè êf½Ø‹ßoûþÜ+M4U\†ÀˆªæY„ml@:£>caü¿1ý±ô_ü8~( ±ÿ€gREò–$yMϦÝûcçÊX‚I m2ë»vWàlwÿéôÇ”uFh$t›V‚áÿ˜ ˆK~£×5zhê ¡.×Cäħ õ?@äñ]Q]ÕqL_R0kßé‹ !B}” ññ7àω+ ñJ¥uDŒl{¯{í¶>ñ/âML/2Ç:Â$±<©¶ÿ¸ÇÕh2G*ŠæÎZÂð䪳†ÿÅåm.aœÇ!XÑ–àï¿õàãær,«Ð$‡7ã“`C{rqÔÿ³6Ï3ºÊô2iÒÌ7)rÃkØqÌ"‚I&X#w’B$ü£PõúÜ}F=V pé㾎ŽEQHò’­REÉw± ÿ¶×ÅŽXÀ §F>oÜXlBE½ñ =$qSô¢†0æ0®Ë¨ïë·ÓØãk™åfak‹0×ä^äë{Øñl[9î$#êÃ#–žúb]`yŸÊY~kù»}¿¡ÄUmÈ’ 7òžMís蟩çtšE/3WÍ`.B‹?^?\l‘Ì‘ÊÌŒºN’$#WXwþ^=pD~äZžPQUnª|ÀY½Šö;ÛŒÌK!™õó2­¬xÞû0d”£.•€Û·ù¿n1¬€°³ù¥±%XÜ1ò„Ûéo§|D“€K:ÄJ,bá#Ñss½¯Ü›±DŠó–5²y‰N›‘o©¹šhB¶µ[³àðFû.çnÖ<‹œ c©žŠ&qe×eÖñ·þ˜}¨ã¢)ã#ÆÄ|¤›Áßôýð:« c:A¿Ë§†—÷ÁnŒúÞSæ6ò›lv~ã±Î¡©ÀþS¨pnm¸ØvÃ@XtE‡‘·ðÞØò$‰B¨²}߸ûà„¦§«hÝ&¬¶2G¾ ¾ß@ÁT*ÕË\"(ˆgU6%wïÿÁk‹`§î$ö%´†ÌG®!cù ©ÉF=ÏÌ6ÚÞÄßWÇDÒ£BÕ Æ6 /q…Ê:¬±3¸Ò@mmÁ?ýz`D +ut)[‡:Á'½íûã"wyZgÒJ‚à(ÞÜmö±Ä5=eX¶¢ñõL_I,E‰úbt ±¸Ñe/n,.oÏn0X¨ÆŽ.´…Q4æem€'‹ž~øÔF õ%f’RAU&à ~–Æñ(dXô¸Y7*Ãw$‘µý=±¶ÒÚ†1Ÿ7{3vàþØ$ŠhÐ+ ›]lÛnTÚßkc"Œëp—N×aaöôÀè’£kVµem¯ë·ÛI>eÙÉ\zßúbR :<²+šŠ¾¢° óïèqèhÂ+„uFþ[‚~ý¿|jB4` زßLbÄ%©#"û S*ìI{·#…fò˜ãé>×A© Ù¹õDZÀçJ°ebVþK“éínq$Q,‘¿1ŽêÌ µ†<øq,"We$!76ílB&m $Äoȹ] ‹·¥ý>ØG‘ }N Ô?_n>؆®BìvgÍqÀõö#‹ûb=(þA bAuapI{ù¸õÀ#àÞt‹JËndØ\-ì;öúXí«F‘¢@b"Í­–Ä|Ûw8BˆÕn€Ü: ^ÿ×ûœK*ÆêqFp ÷¶ãÛ×\@0Œ­ÕV csnM‰çílaY:jªêK°PïqkƒíÎübIcŒDJ0Òx'v;¶›Ûæãò€1d!,[Id%Š›°6ßùc¢}:„NѲíªäjÞÞo\nª ´%ÕX ’Æ÷¸¸µ¸ØŒFoê¼EÇOJƒÿp7¿ë(¸øs:êÅNŠ)ç«VA*°&à³pvÙÜw+èlʶªª¶ˆG-5CÌ*xŽ€_{}Šk›{ûcŸA*Fà–F‚±”]”éÛ~ãQ?ûqbËë`Îk$†PѳÆÊcÔèMÔ9Ô_ÛdÇÍX2¬Ì¤ ˜ÍY-;ÁÊÀHg'ÌÛ6QëÎUM2ô+#JyéE§²"éÜIÜ6µ¿{%™e‚:¨#Ò`fY,[f±±°ì ¯}»cPt•âXcóê†äÛdäboÜ9ÅrÇÈÎTè}M5E\²Ñfs£D‘‚èAÖMÊv²Géèq´ôÓÐR  ©-*è’X#:´•¹Üð7öôÂ:LÒ²á×à⺒A6.Mö$Øý†øomY ‘ÉIPóGjm,E–×âäò[“ÍñK„×]š¶cQÒH3•”o7–Öàñ¿8ÝÂ×I Ò|%LŠéü¾¸ô‚|Ú…ù±ß 3(êsZž¢ÒËNÒŽ¡W»+íç‘kü¤mq{zŒL…2ÒK˜Ö#ÄÄúUÕ ªýù6nÞ¸j¡qZI%}Kw%ìÛ{½¯íjª«ŒPAš³3ÃÕPícæ!A¬v'î8Ä5ÑÕAÔVͬHÚï¨-®Oòðp%LŽôጋiS¥®ÆÜ\‹’mÀäÜ Æ.‚Ûȯ²j*ù)+úˆÐDJk°R ÙEÍ­¹·µ½7,LÕ_ ø¶Ž˜¯æªt»zø–ç éé"™`h¥¥3je¶€Ê-k¾ç|I[³DV~«mÉù™-͹R/Ûå¶TØ»™”YÙZwZ8 r´š™Ñ´¸òy½õa° y¯`Íj¾)jNs ED‹tÔh$'¢ÝEÜ…Q¸;[qê.ã„“¦ØjÒ·cÐo¶’ko~O Ã ¾»,yiÅM*| GªÑʙŎÖQÃ5Žý…»’¯@¹rޝm™õè¦Ì ¦¢“á#¨'Run ºFó]w¶æÇ›ÛÕÏUÊ'Î&Z¹z‡UMÀ”Š×"«Tmæ&À¨Å/zœ%¬âŠZŽž†ÕI¤ÌIÚæÄÜs|II™åRRËSaÔ¼²H°Ô¡‘%RÁXZÎHkê¸ôßlS&ܹ-Ü\ÆmYáì±d¤ÌÍ Å,JÍ…¢0£‹)p|¥¼Ææìmsëƒè³š1—ÇÒÍK Dè&ž¢n³* Ó¬¶•CXéym¹Ç%Î3j¬Êª ªÙæž5E‡Dš­‘‚ÇJkwÛ[;§‚ó8Y6w&QX)ŒRM-2MÖ`t´v a 7’78Ž!”¬6ôQS Ö‹.L³Èšuøšjp@M@½•I \Žþ˜¨TMj€ALÐ<‚¢%Ö¬äT‹± Ö!T€r;b÷âhrœ¦ Ê*:)³kOS©Öf³iM[é-`¤M¶¸§Õµ ¥š¾®•jdÔ•b½€ãÌ;‘p c¶>Ñ[ìY2TxxUüP¬¦·‘~1RImqÓèÌîN¦XZüÚÁK6eáÃKž¥OÀõ˜¬FZQ$sF÷.@$°`[VÔA¸íŠrtÊs Hër¥Ê£¨¨a¥nµ<¨ZEn@7-ÿ˜Þ×ÂZœÆh•VÆÍ¡u)SK!gPÑ‘b¥¶]ùØ‹¥:á *ÌÒlÖÏêhë)²÷Jy+DÒʺa¹$"…ÞÖ,ã…-†Ð|OáaS>wj‘I¸…4ýFú Rumˆ±;ÖÔHµÕáÊ¢‚’ŸT(°]a„‘`ªÀصÈ·™°øÆ†E;Rå‹%4Áä©”R¦·S¤~m\켌PÓ°£×ñO–PÐQdÙvyQU Å=d•€Šdv%D!,·ØÏr ÈjµÕ©SW—ÔeÔ†))áê4eµ‹¸¿6<’þ¼à¦Êêft5Ò2jfg”F .5ØóuòÞ×½ì/…þ!ÉFWQ§4– *h”W,$˜Ü­Á}$X1MûbÜp¯B2z Á¨žŸ1­§¤J8¥ÅÌ-¬jz…o¤¶£kiî$Ê3È¿Œ:ÈjÙØS…–3¹Ô j.ÖSroasÎ*$°ë2ÈÊQ Ðý`ep§æ•?ÎäžM×J÷Å¿$ñ|Q´MH“¥q‘N“ʯ$È müÎ}Oç¾ Ó“´Ñ\Íą³Ž4ðÔ<:ä0‘b¶¢Ö7²Ÿ*‹“bM‡¦ÀÍñ´¢8¢ŸY®LBIB©Öä€/k“ó(ˆ¦¨ž]LóÊ–ºùɸÝ>öö;žqä𕘙ͩßCDªMéäÚý½0eNM A̵GBÈ–pÈG{› ù¶ m÷=ðLsUC«s ¬„B‚ÝXƧ:ºcùUX“}Á;Fb|•S÷+•JU–$ˆ²‚ )6%Ï qÇØŸQ€å…Ì¡&GêêoËwÜ0;–#qa‹ 2¼RO-DÐÔÎe:ÑžÊdSmέäÛn76'ËM=E µ¹„²Gþsh`Å¿#žÿgˆö0¶… …DoHd} f E¶¸¸ØÞþÞ¶·‚(ãŽ]113,zšá¶`/k‹{á…fY]ñtÔõPU­;Ç¢’Ñò“m@R}O8i–(¥ÖõyzÔ DŒ ƒxïæ[í}­¾ŽÐF8âiŒs:Ô¬š¶6{ŸnØǪ "…œ˜ío›ï†¦&–Ĉ,ÂéÚG›Q>»î=oBFùrËQ"I¨ƒùlêT›+wÙIúí† v'•¥•ƒÊˤznŒF®ÃûŒOO˜M;ÅPXÆë`o°67ôÿ{sƒsL©£Ðêé"¬È €"æÅ¸à¹Äô†:dŸK:Ú8õék}Å­‰º=eOâJ闥鷀ÍsÜy¹ß× kªËM)‰ÒÙ˜…mΗltÜl·ßŸ6 zx–A%Lš;#+‚,-ÍøâØöJ$H‘¡©ó>÷U”›ˆ•r@óXîY‡•íöpU%+2 ‚•pÖ¬l{oë|ÑB¹AéiYOæ5È÷ÛýßÏKPè#€âéëeqó-`}û}Æ%²Ši*$e¤R1,Â×pÎ܉Cš!%Y÷*ϤÆÖ"À‘oß¾$¨yÍ¢¦Žë"-W}‰qÀØÛNBÇ38I†£uc¸·| ¾-žÏYWÏ"Ä©U·çG0*Š múßëŒt¥f5PÌ‹Z(¥>`¶¾«Ÿób:jg¨r(éX·M¤™T]Å&ÖãÓ½ ÑÒK0¥D’tÎ&˜ ìUTïÏlð‡³Ú…1U•¨–™™–2’BHP 7;wÆ´jÎ h’GkFpº7ÜwljðÔ V*ˆú6§‰I }&ÀÇ›Ôö÷™æJùž¦§ô„²j,¤w¹¹¤âÍŠ=É G(/wç{ ÷ßúßégY¤ ïÀòDä±ÿÇW¸`ѢƬˆöPf°¿6öØ_ÿŒy•éüípNç{ý»âv%X±—B!Ræb-ç[ê^ÿca¾4`‘kpÀ¨êqèOµ€®MbÌË/È5Üm¶#ª¥xcg°6.‚àö`ŽwØ’} | I1L‚fÔÚU¤ÊEøúcËIÑ»¹r.F¥¾Û‘úÛöÁ«FòH±” aÒ_.ÚT“½÷½»àaÆD—~e A>¶±?åþž§Õ‰D3ÓT ’&œ²èò€ÃÊî,04QÓLzup­µy€ qôþø%ä°häR¤ + Øwÿ·õÄ%Ri:AÔ¡‚ØX±¹¿é‰d=†š’E•$&‰:-ÅûƒôØý°Ã&ðÖmšÔ%%faP¶ü¸ãÕ¥FÞcÀ_©ÂǪ¡DNX±ß(à ‰ÓÓ(¼I5 ¬¯Î+¾+4y+fŠ"© k ÷$÷;í&icvxáŒKm©öÿ0v’èZ4i%T¯—æ¾ßqýñ*¢êDf}LYl{‹ßèlL‘™Jît)%P§žþ¸ÖYŠþ`*¢Û‹÷oµ°´ hÒ=À¹é¨ccr·|MNt£ÛT—óo*é®Üóûch)g•¡âRÄ=͉údé6,®›ìw6"ÿÓ÷Ä!´G­JX31°"ÍÀÿgöÆäþoYjÔàqk û_õÄw s"Ã"¢;µ¸Øqôïcm7´¥ˆÒ-a¸íˆ«”y:êy ]™ÀcmJ÷ÆñˆE—,Ž-ÚüŒb„$F؈X¶÷þøÛH‘f”·•v; Ïö?¶ HòõRþbH F£¶®>ƒtÄjCÆnlRAo.åOðyÇ’²•h wZàp£Ü†þž£˜ÊUc*Äjµ&à[½»âuÀlÝ@©A¨ ‘«bEÎÿ¶4ذghPjòpHäߨâ[ 6Œ\äršNÛX‘ë§÷Ææ™ Áô—`©©ƒl~æë‰uÑ ˆh/dˆ1°¸coo¡Æt¥iGÌË}ÇóZÿoÓD«b %Û“¿úmöõÆ$0é¨V ‘d_[ –'ÔŽ0nȨ)•R¡•‰¾»‘¹··Ó6¦Uê'Q"ÆÊ>ã ‰™B‚.¼»§ïˆª:k`Ä¢þ@7Ðq郼€E$„²ž‘aa°ú{b@j)´´R$X›’t÷ýìv½±4H¥È*4‡¹ .Ü|f¡!¨'fÔ··a°½¹ý±ÜNºPfQˆáMPÊT#9 ¥ì íé{{a­;ŒÎ¦¢Z¦Y¡Eü¿*‚Å»ÚภPïikXöF$¤ªziC¶–Rì/åb?{b¬˜Ó\ ™mš¢JÚ™a¸5,Ý=í¤ ­Þû›“}÷$ß#Ö*tiÔFÏ.¸ÈstE#Ì;§¡6½ŽÂÃ%l/©J:wóÑ·oƒ_0ŠH.Ò&†É¤„àX›^þanÇnØ¥EÇ´D3¤Íª'¬ž8JXæ¨×¡,±Æ’k›‘p¡ü¤ÚØÖ¶©rµ!úæ¬çÖ»µ´kîo¿7ï…Ðf&¢®7¬†9¦Y €±ƒÀ w÷8‘‰j¢y–E>eÒT2†½Í›Žv6=ÁÙ\=IÑ­tm"<òH"ižMEQÈØ°<ÔßߘU!)0VpzƒB€U‰ìßá~§kZ2Êcé§M:šâK—u#ÊǸÙo°ï€§™± xj „ :QØF'°ãZ \[ ÌêòߌJz\iD}522 X’IÚûIàn/¶4Šf£š*ŠºX奘ÙZK5€emîv^FžÛ‹ØœÂ8fHÒT)"9`MD¦ÛèoÛ±>¸ 8”‡BHåQæVò²ìÌw¸77‹bØJ"0É¡¡\¶y–]h…DŠò177<`y'õÄõ3´´I=MUEDâtŒ@ð=(Ð]ƒ-ɰXõm{a,.Ñ–gY i¨pßQê6úàÄ5Ì ‘ÅÓù´…{Ø ˜‹í`lD´Zü#•Ög•ÿ.l”7…¥F‘Â!!@+©Å”NÄ|išeÓgµù|Ù‹Ô”… ¢]Ù†ÀµY—ƒk”튷Ä: UL‰…~!D¢òßQ=î×6Ûk {s=!Ó0ž0X,Î|׉·#æû÷YÁp±Àµ/:ÊŸF¥* ž0Aeý0±ÔL‚hÚ£Xpê]Õl¤VýìKqÎ'’¾:¦Mh¢´Ž¬¬¨·cÙ¯nûZÜïˆ+'¦ëI)‰ÌNÌÌ¥k$ßUö÷w¿¾n.ƒOÜÚ“2Ì!2;L‚D"Bó\¹ yO5ìm‰³¼ÂzÆŽf†Xú’š‰H ,ÀܨïmW»ZÀal€kK¡'KbÅ“H°¸^ËÁ>ç³€Ä1[ÌŠÄÉ"Ö¦%€i7k°bxío¨ÂÙcZÂýXÚî›ãsé½ñWl6X3zïâQÐÖ$f@Ѩ›YA{TiQåï¹íîf“*‘Œ5j GóGSPU£[ÞëΕ$íÞá{_},ѹ‘JP ݷ؃ߑƒâ–µ!ëÈ^¦0š'k[ w'`~ø.ýY@µÀ*¹ é|u'5«ž¾PŽJ»ˆÆ“Ò¶¢çd²òyµðêDë”&Ì«ÇMA$A …cH{€O<µïg’)Fª’›¨xäUE úó·®%«•¸ÍD…‰UY«¨¾›_‹Xþ»zám9¥ø–騀šàO÷ÇßQUh‹ªÔ@Ò¼1%CÊ=lŒl•ï~Ûˆ£§¤—-’a"ÀÉå•J?Ê@µýG7ÃùM(µSPÌÈUÄl­c±7î?¡À&u–¤H³fœéa%ßZì,A׸ú`mkÔcjy ÑÅq­T“‚¦›Fê-`çܶ·øqMÓŽ–ŠHWX{K3’æÄêµõÛG1Y©ž4©h£,b%obH¹µö&ø–ž µ/ÓžLÀèkÌË`yÚäò§ß{àsîuOC©,ÆIe–InV6án@RÖ°“<Ë$®ÆÀÔº>nƒßq‚©©Ýó‘Fj!ZŸ‡º)»_mþºc‹fy‘WäâIåEh*n²JÑ[M”“€FæÛÚ×¶¦“V%<°S¼ÒÏ%<އIØ ÜùNÄ.Ö<ß~0Ãóó¨=9êäc2–ëêàý÷?\ P¹ÞšV¥’@j‚`ê[( ‘Àýp ™RV’Ìm Ry¯ëmì@?lY$œB†¹ñ’§1þ0¯ùÇTö¨ w!¬@6· ŸüpmUPpCæY Æ£a}…Ǿ4–xß6¦žxHÕ‘Ìen6$“m¶'Û¹Á+:,ÁYI®2Xò졾½±DcŸ‚‚,ºŽ¿ªUêˆüµq¡t» X_žwÆcÜ»3SÔG]Z ˜¤BC7úîïÛèq˜TÆL¸J´uL3täN#gé0mJZà\_UÅÉÞ÷ÛŒ+‰ãYõNóOF¾`ÚŒK¶¦Û€6ç|ʲª,¥C,Ÿ™#Ÿ1 ëÜþ˜,­QÈ4Ç%‚¶›X6ö÷Úüý=‰“£%LK˜GÑ•‘ ºFÛµÚúmï{úúál&Â?Ëd¦V!¸;pÄžý­ÎyÖÅPz#•T¸X°¹ÜYnwîG¦TÇÒê[¬º¹òìoo½íô¶¯²¹Q´ë‰|Ò"“sµÍÿC‰ i#WH`¤y.Ã~ãoKãØeX¢" FI}7–˰ÛÖûãx‘¿åéXº•H°#¹>þ‡Óð®ÅÛ󀫥Du,H´ àzj¹¿¡î7ˆ¢D Lm §c$"Kmfòß×ùèIÆQ4^TF=PͬÊH¶à}·½½F6ÎN§†7›©#(v¾æÇHý-söÅv›àµCjì šrfrQfI¹f¶­½qÆØ,ŒŒ²!ê1ûA¿ÖàmíèN',º•å™,HK66ÿ¸ IK)d31 ÍÓr¶,ËÎý­î7Ų’K¢¸§d4¹M;–’í} ìvR­ëÁ;œniã…ÕVÔê!ˆkÞú¯oo(8:!ñhŠF‚™F XÌNÚn{Û}û`Š5¦Úzy—¦m,á®ÍªÊ¾Ö ø¯w¸|»x"øwX –[*Ø‘co[z{à)eK*Ì—V:Xƒsµ‡ë†9‹"G‘~m…ˆã›sak{b#N”ðËPáTò¨èwr÷×{{[àTÕáµ¢‡øœ’ v·}ðe&]%d¯À¬ÌÊššeU$Æ’nwôzßkb#ÖL.ŠÉ 5.ÊEÕJÞÞ‚ø*’áFh¥ó¨ \2/¹¶û‚>˜Y6 «ØY_Ô’RINDm“}@€©õ=ï~øn˜fŒ£:˜|£×éƒf޶I@Ä…©n¶$Ûocúâ#Kù±LšäÔ,’5‰”s}Æß|üP‹†E öŠU†3p©Í˜{žÇGß”ñ°K±Ö‘úîmoÞØ&4!S*«’T@3KÿÝaÆš6ŽzvR¹×±¶æÛíï†Rô 3ÚHà–eXÑpêu©ÜƒÅý š j€È½HäÒã;ÚÄúl~¸Ñ„2u"»1;‚Üq±Ø €Óÿ—×ô¡øY •ÝJ¨þm>£îwôúaei‚‘Zš¬ÂµT2‰ì —cÇ­°²?„x„Hï®Ä‹›\Ø6úé7÷ÅÛ %’]L£MÈ‘ÅÔˆ÷ÿËŠýfXùN&`Ež5 ØZÿ²‘÷²2*”E ÖX@ù-nTzïú4É"šyd™ìœ+cņÇkœH(úGR:Öüô,9äzoŒž Õ*“LîËbAãkÛßE}´ÑN&s[%1TÕ¤B[S1;{oëê=EâéL‘1ëõØÆ9&ßn;àÊ<Å)Ù™¨RP‚÷*HtßcarI·}´‘µö•ªiUª^HšN/¸äÜlpŽiz MŠè4ei»yH¹ü×¾=ZW!“MÀUµù¸ýÓ¹GuŒ—,T?婸Sß‘cÎ I¢mF²Ó¹B ¨RIVà{Ÿ·÷ƪ‡eQ5i`ì³¥'ÜéßiYt¢™XÜÁ‘wâë{ßspOºúú1„™@`ŒÛ;m·J® Ñ1ÿ¤dˆ Uô÷cßžßr1“DU)×̤—Ѱ½ïý¸Æ°™XÕë #b7Úÿâ[Ë1*®Ïaå$¬O¥þmö>÷Ä%‘è?t@Skp‡®øƒK, (Œi° [Ì­±,=ˆûà•Ò',±ü­Ó}ȧ×LŒ‘+\n5>À{ bŠXÆ)* ]ì}M±¬Û®±Ã$º”ê1.Àß]¯o¾§ # ¡ä¾¢ ÞßM¸÷çtâQDxbÊ6 võ_éÛ„$…b^Š…Rˆ°±$ïê/úâ6uhúŠ ê°T;›ì;qsýp^Ð$èÐ¥nšI#n¥­«ôÀÝ9`M1ÁP[ê!–çÛ¢z öËë:±Ó+¦TfRÿ‡ó_~pŸ0+5;´‡Ët‚¨nIÂýýpžT¨Hîuéca¨ß{ö~øö9ä§dpöÒ÷¸’/ßÔkádˆX 2’µÓ¯T)wŒ’H#›͆öàm‰(êm"Å,¥$ ª9i²ûíÜߌm–æ¹eLlõ§#‘bȧ¤TÎ÷d`w»ïÆ54oQEu‰5,V¦ä8Qcsm¬v-~äûÛwÃÙ-VÑT[Tf;)¶£cówàÿ»cÚy3ITUf`e´ªN»åÙE‡ßi–™P²ÉÈä`Èàì.òù9‚N$Ëå¤w•’˜,ƒ¦cq`U îAÛã‹A¹>ÆY­`¤éij»J® ´€ ì$¿˜ê°‚ö#§¦5=HŠ8ÉVÔ…î[ õ'aaÅñ 5’tJ¥c" nÁ…ÁÛ{¿®媳‰£­ ¥˜‰ œÆ¤ê¬–ï{sűL ¡É<ë6•ZcYÞ4ŒG ……ŠŸ±Žx£‹Èó2º†F$…bN =Eý0áéèÞ)…JFMiåÞ%`uó·Ì÷?Lj´æZi(¹™Ú2ÍI¨1-kÞàŸs‹c$Ñ*…Q/@G$ècÜùKØënû¯o\oP†zR<…Ewî‚8çìNŸ*¥‚‚Vš®Ýì ¶Òذã0¾û„á}o–v˜Åi˜Ï=ºˆ”0¥D{Ɔ»)R ØŽ  ¨ÖäóUÃYAÒ§A,14 :!ºQÉÓ¨·n9Âd¦nˆ”–Òê 1uIã`vÛoSlOI—FÊR©:  ¶-bØüÛ͇^„ v¨êÃ\±Š2T¹a(¸B¥Øîô;ŽÃudQ3L¬Í¥›w¶ãŸÿZ×ß|O2ÑÍ'VX‡Æ\kjiÃ&ûHòÛcaö¾­•+•¥š z±©Ôë"Øî¦QbwÔmnø 7Ã%„É4k†¦ å¨M-N&«/{ ì>Ç lu5Â!B¤²„†í}ÉÛù|IPñ1f0¼(Ì£C0$l}ì1 S²+ˆ#X[›±í½®mÀ}Ho32-gÃÂɨ—”*´…Ùxs¹£èVI*ãw¶‚±&­BöÁ¶S‰rùbIÄõ1E9M¼‡@gÍ¿nݰÚäÕò Reõ*¦I5¸h® •p}@'Ë·8µÐÈGK¦;À'È¥ˆ q¤n}?lGx’bõ2É !ÙZí±Ô-~ …·í‚*ž®´RшjZ6òȬËp;Ûµ¿M±í\ÂwŠ™’dR¤õwþo[anÀwÄO€uáW3. Ñ²4}X® _5¹Ý¹ã¸ÒŽÑˆ•5j%€³î/ý?|K^¿ ³A-€±€66ÔÊ5 ís÷¾¬eƒD ‰..×$z[¶„³$o˜ñÓRÌc1Iuµ¯Åîoí÷™ò¹zzyzº–%wÒ ¹¸ß‹Ü`Ln¬ð³ù‰nCì6w*:§:zzK+IíæÛ½þÇØ Úx¡y"UÒáÇSCù¸¹÷Õßûbz_„š`‰,ÓNÂà”ÞßáÀO Ž 4ÒIÿTØî[bß¶%XÐËPŒ!lIxßöÄ|ÞªvŽIây ’¦5e¦E&Öõß|z"¦f`¯RYÔ¹ºÜ±±tð,m¹¾ÀúÛÉ$°@±ƒ Zn5Æ4—]¶ö'cþÁQÏ3ռН!PÊ5(,ª{v¾ G5‹«Dt=41Fª'’Ò_Ìm7¶ïôØq…T±ÎªòÅV©J匡€g°çMö-Å­½½ñ­(­kÔÅ4¿ 0>m:˜m¤@m~†:Y£º¡_B’¥†–7%okoµÎø)×%OœÚ!%:9«zÎ’éc§óHú­y/°¶¥]ý0=DÔ‚ ujRyQ¤/u .¿k¸ÛÖÖZz–™£Ö:„‡!eèÄyoO­¯$¨’›-ššH!Ž6óçK‹÷çíÓ¤ìªðS!‚>³éÖQEØ‹ý¿\-Jîƒ+.™¦VÖK(Ø­ôéno~mí+<Ó—–;>PçQE;\Zþ¿¶Ófq;Ãu;;ÜÕôîѪŽHý·\5 Ur‡UôÕY\u9•‹PDe²°I£+ùfÀînŽp=EJUTf«GDa•]RI‰Òäù€Õ¹äñý@DzCK˜P­kÕÔVÎŽÆ:jj^šFÊÄ›•ì0 h%¡ªI\ÉJγ2ÈŽÚîH$,Ê{â.›dа(äëTˆ¥…¬¬Ÿ5……í¸$† ÚÃïä¦hç†u†’^¬e%‰$0¹+¨_›[ßü+ÈíPÔô3V©äPëc¨†7o)¹µÖÃæf93ÖHV¢¦PGYc;7–ÜI›bºL °Y+ÍD´æJ£iP©¶nXÚì²ú_Ûì–1/‡*s6¬@©êÍP¬Â@ª·U´ìnAæÃæ®:u¯cBª ¬ Á'˸n¤5ùŇøÅFO’.G%ZTAÚyuïpT €B›ßæÅ!ÓtUshã“§4V½‹‹‚Ö·˜‚vß{{qÛõZ}sÆ!“N«Aµ€úàŒÖ«âæyfE¨”ͨ”?6Öæçü'¾!FêÔè$UxÂNF›ð7‹ß@=ªÿ™ž@õ´Ku Ô·"Ý­n×¾6§¬@ÔúÌŒ‘½’vE;X›ƒµÆHH€ :¾îà×$Îà±»®¹ô#¾°lÛßן¾  Žéêªcªc$1È· e¥e½÷n-öÎ3å½%‰Á–R–!‰mm/–Ö¹ÞÌ?›lÀÛC¥f†#ZÒˆb†%—tA¤-À7µï½¯s|o, S–ÏQ81˜ÂÞÀ€Fú–8ž HŒÈ³#‚ÊB©G¹Q~<ÛÜãzªiRVI|È×g†G{Úã~;ã4¥Oƒ±MvV%bÕQÍ#L:révk­øûþž£ ³9cøÞ“¿–+7 ߸<á߉)éPuÕüåJ¶›Yˆ¯Å¿R{ ÍuK0”Ëz–Q¨ °,,¶ß76¹3˳@e2ª©C!Üêe y&ÃlLª5´“*˪ýˆ¿¹ïµÆH¡HÚ7Á´  -Üëý Á3˜ôÇ#(J@,àYG¡ßÒØFÕtóÈñ%™è¿E‘4.¥N›(mÛœkRNòTº°„]@6;_GÖÀÿî¾ šm&'r‰Ó)¥¹7û›ï)ã1 M¤$$ ØX›ð,1RøKí4L~"ž(¥˜>i`$öÜ~¸/)Wi• H*#U:¤•í±>e·66Üö ¶ïˆÌò‰d½D„.E…”@Ómü¡–À߀/lM8’¨*‡…bÓ®î.¼îý.0'º„¯¨Zs°éÃJê½÷>m³ý¬m‚Zjw£E==î}o~øÚ†–¢ª¢UŒ mj ¾÷ì ·ãc²¨ÚZµ¬šÒSÈ]R·åÇêmênwõÅ[¸ät…õ<5JL1–1ÒÉpmrû!¿¿ÔcÏ‚2æò¨: c©n6 ÷8.¦Š‚½M@WåŠ •UbFäðoca‚©]– ;Óž£Ä b;Û¶üážfרS¶AP­ §Ž=€e±R9·~N34ˆ°-JŽ£/ò¶¸íè×ûlxÄù“¬±DIWT®Yü¯kïcký°³2HYòÈ 1°[ lGk HÜ…mY>`h©¨¡•ã€U8m@vÛù­¨ò{wä„õ/T±é(Òô‚‘²ôì}?í¶7èUTQ¤xƒÚÖöS`6¡Ò¥ÅƒŽoryÚß~ø±ü#¤J% ¾¡‚4›¨?L-©Ëd1-9A³ †@[›‹7Ì¿Abùé)¦’%hc(5(©@[†¿–ý0 u ¯D’2ÔŠiu3ê“e_ê/Û²û>Í)tËHöŒvkÙl/ò–ãœC0xѧŠiZ¢m ‡™o`yòÞß©¶íÔZõeymLÙ„T‘á:ˆ‘æ:UUU™¶öPO¹ãr1.^imKMW$µ´ö #Ò^9ØÙ®w* ‰Ûp,/†QAñ}E14AãóJ)Û·›l¸ÀÓЖ<ë ü£B_kµ¯ÛôöÅždExÒä×)¥¢ËƒTÖÑGš3¨ ®CL+Zéo›kÜâJê<¹LC&‚ ³FzÂO‘I;Û¶ÂÃpÄTJAK€ €F×é°úÛÐàuVøg¦§u±$K¯žWéÍÿL#¯p:¢:|¦›«%T«~kÇ[€Hò’qãeô)U’p;én €Z÷;‘Ë£¬k!U ÙA*ÜÛUþØŒ$½(ã.¥µ+p“¸¾Ûö1»Ef†Wvy$Cy`.HÜíö½±ªSºÈ³<¤"6á·qöq,Ž`kKmO"‹vÚݯßü¾§HÕ˜–k†ÑNÄ86ãk_ßn&Ò¦fX‘\ªÔ݈'ÜöÇ‘ÉU"F¡Ì¤vmí¸ì=ã½Þi É»XXÜâI ±ª#°M¤e¹o·ëmðþ‚2)„Ecaæ Ø*‹.çö*ñ÷Æ:«x¤u íè=}q1Š@šä`‹g!ïkÿ§Û¸‡¦ò+tùC¿¦ß¦ W(‡¨(…QïæØˆÛéµ°5¢K+H¤!ì.­a±¶çü†%T’h‹ÈñHƒÊä~·ý­YÊ¡ ª$Ö“©íe½À'Ô)ÀÜFJdBýHÔHÎ!F«Þÿ]ùïˆôÇž›{”¸ó¿§m΂/‰*QP– µÉ¹âü“Å×¾5HÙB É(·å&ìuz/›·¦ס)º¤ßåF«ÜïkÿMñ¤¤1·N6gSú vû`ЏLG§:õ•­«]ìo¿n>ØWheˆ£xÑX1KêÜmˆ‚j8Vgk?ÊŽ‚æÞ˜ h–Pªoré{€»(·žq¤uEÐFe³¶ÄÞÃÜxÓ„•a#S\jÓìß-øäþØ-{‹hõàŽfœL±©Ø-ü îÞÃïŒašúŠ+ N4{vá\E>¦C®EuW:~‚ÿP9Æ© H×iKFÅ´ÚQòŽFßoÓ ³æV€  1ßIØ­þ b6PôÅì¤Ü1ß{•×ä‚4»«ÈW© ³î}ìqŽ\ TÕ}a…ï¹à`Ý^ÖêßP©;ðûZØ(°é«ì5X-ô^ä¿8ÞÈú ÝŽ¡`~»úcÇG-h¬7¹ öÛ÷õÃZö!$Ù¤1˜¢©%YV6!…ùïÀß òúÊÞH!øŠv'C.®£m߀.£Ÿ\#]z£’èT@'PîKcVŒ“Ô(–ÌTÛŸ_× Ò} tÙißáÃË|,®M[{ƒ·ò~Æ÷$QôMêR£‡ù¿[ŒRrºúŠvfK&›$„jn Çûô¸,1 zq9Wk_Éc}ãד„p®ÃßCšŠi꯮ž•V%ms<¾r¾V»à ÚÞ˜V¢j‰Zh¢s²9;j½»Ú×䟩ãÏ_¢’ø¨YnÚ’@— lO¡µ¾þ˜ÊÙ²ïƒé¥0‡O˜0%Õ;[pÊ9à66jˆš¢ž#R²#ÔÁ]õÓ»i#q§¨Äߙ՘ArËk½î¶>¤Û›amP’•RJjˆÙ‹öÙ†Á¶¯v¿ÓQISSSBª(™J }’ÎÏu瓽ïÆ«”¼´Ôe’Jk&ÓË¥)ˆ¹W'ÈIâÀ3qÚØ ,y«¦ŽIÄí1?Rú7—Êw;[n>‡|faCS ¬ÇO¼ÅR¤¨,ƒµÍù  û 0® §’sQ# á%Wòì\sÔ'°ÛôÀ·d"“á˜UÍ™GYLvàd{±}g“¿û82éY ’Ò5(p:ª.ÿÿMþø?4¡t*¥Îˆ yX[F°œ¨±'‘ë|_ÿ ÿ "ñ.O/‰Ø(ë ¨Í¡ã»;¸]¬MÅù؆ø !&¤GL¢[:­sïaßa‰ÊÐêW]vR\X¶ê9ãœ- =bé)_)Ÿ‹žÃ{b $H•µK :¬ª/åçrx=ÿ\F`"¤À!Gy>TÕ¶ûÜúï¦%ž¥Ž)§éúKÚŠÚ÷Ø`ôÈê㈠-Ôg j(-êHÆÕ“B‰ÓA1ebds)³\Ümö¶YäeE@È¡maØÿCöÆÁKëq›6žonÛ–ørA“R ¶ºŽ’m¨Évî;½±·Ä)œËTšÈJ•k77ãž?™CßKLçVíÜX}íúºÕÞ]lo¦À‡±Û‰c¡PÑÀðÁR†#¥×¨y:Æ =xoO\C%i°Š9"ÚK¤’OÖþÖÂÄ5 @"ÖØ±õ#°ÞøÜÊc‘ä@H ?šß\.ÒÜÇU™@]mf6ã›=ñ,Õ•l¯K*Å«)—@ÔóÞã·azªÖj&K_K3Ü“a¾ ‰åã¥ÿ$¨ÆìÂöíïoÓ D|¹©DrÕB`F Ë"E‡Øz¾Šª¤üTŽÅ„ #1[GÚÞÛãzÆ«§Š3-.‘fFàêAo(7úiBÐôŠI$…ÛËÓk*¯¹Ÿ\(G5SQ4uIu†WeE»ÞãÍöôöÄÕsÒÁ$¦j)*åK™%²X·–ÇÖå¶;ï…QGªe]X]Ú€ï¶à¥ýq¾O]HÓÇOP%žž6gü­1Ô)6àn/}°ª<ö({ÔÍE_åIœ´}F3ÂÍÍüÊ_ç•/VñSÓeòQŽ€„“SH@Ý…ÍÉ6¿kcJ å2ÇKIW,Ö –ÒÒ|Á¼Äl¡¿ßôe`ô¯1M ÉNC+ Øj'cÁ^G8}¨„YElqL®òc§* œc³^ü›×çfõÔµýWn¨‘I]´”Q`ÀmqÎÇ ³>­)j@÷’.ÊÃp.÷öÿëÁds,R¤“2» ¬íq~8ÛoL݄ʊ”4©NQiÍõ5¸>¼_õÀsÎ`ŽÉÐ-PX°`u§)ísý1MgŠ.¦¤ÞãkLCw,²"–’Åœ…Õaöãkaˆ0ª®+S8Š>¯QI`[V¢T©$ò67ã¶÷ÚÃËPÓG¥™‚X’ÚImkz}þøö ÒF¨ #–f,6kqcˆÅ³)o—Uƒ}ÎÞ¸›ˆ05†”F©U"<Íi4*{€,M·ñ˜¨³ë’xTB£Jok~üf'cYܪu2CÚHGAÂêoüÀŸR7÷Á5©ˆÔ,©R#@ F£P<ðyR7Û×IAÓ¢\¼»»ë`€ ÎÖ*O¥Î¯­½SÉQ—ÕÒÒÓF"p,Òò*m$ž9Úøç9¦v)Šsú_Œ– \o ¢âø¥U+¤Ë$W1µ”Ü ìO§®ÿ¦:¦sJ‚Ñ´]Hʺƒ%F«ð/{‹cšç¬”Õ’ …µ-©®TØmúß1dÝ*ËVÏÓŽV_)!”\0â÷ÁÚäš yIµ²’v݉ûq…ýEY5#1[`¦÷¹íµÿ\dˆ #ÚØîMõ ïǾ8*‰%6•‹^¿Íp&w/cµ»_s¤î6údëÌ‘¤f8d>cky"×úßaQ#4l€T3 Qü€Ò} ýqlË’2áË— ¨2éÔµ…½ï„kŽ{ Ÿ&ñÓ2G G$®4‰[Ì¥‰S_*›S|7ÑU”=n¹R€éîFþûÞØÆ5µF«'LF<¢÷½ôí{_UïÎ2fІHDò?Q´³o¨E”nEùÛ¹7Ãe´2£Ÿ¥F¯ŽY&³ ¹P¶þœ‚¿÷zâH §¦eé®gò²0"ûí€GF•B«½ +b8íc¿úãieN³º¼pCo°UÜ~/¹ý1ž|ôYÒ31øye–Fò€ªT‹) {‰½ùÀÕiO0E„ÀÚ$ÔKƒpÅu[mýwâø/.@ìÒ2LŸ–¥¬I°c·k~˜¾&†J‡”i ×ÿ ì=Îäý¾É.…öšxä ÅŽ°î_€Ö¸·©Æ³ÒM"K1_3&ÒKÛrl>˜"h* EM!Ya±½boïo×Þy#JX"ê2“v帻ÎáKcTR3N$ôŽÓäÆSå$1ÕavþS·ÐŸÔc*ý%$´­ZÃÌBíô䟶 ê¾ ãCvH@Eì ±â~ØÒ jk¬„++\aåÅñª„óÌi I]‹/°­éî7Á}TªLŽ%Nv:Å”ÿ‹ÛÔKK«NcT db<ÇîvØ“þÁÀâ2ÆÐ u  »ök¹SìVÚvš©c#ª s®/ñF¥‰ ÿãc‚i–7w˜ªõ$µ ȶé¸î}9ÄqÁ<õ*êl¡Ölußo顈Ñu‚™Ø èŠ0¢8$žçôÄ—È‘o¶ e¦Õ:ˆmæ7ó/¾‘RH´ ©ÃJ$þk þ‚ß¾1,$$êˆB÷aeV‡{’ Ÿ|CHô´Ð´óFòèÓ*F¿-…­ìpbùd`3Äf}N:@ Ø\ê$ÜA÷ĤO*KžR¢'ÖJ¬(.vê,öï醰Mø˜#[!%•¶^ÀqÛM"A Œ˜¥”’ÇO5®;žGÿCò ¾À$TJé+ç,ÑtEÑÊÆþNnl;‚;óµ×˦)ºÓG „é½´ÊŽäßnÀœ<©WÐÅÙÚ?9ѱñ· kîq KR©2SG‰Œ;“`7¸Ûb8¿®- (¡E s*ÔõšÌŽ e³ ¾÷¿ ~Ûà•¦°è#€H,Â÷7?^þ¾—é)éÚ+UäÒ¥Z@H[’6#¾Øõâ•©¦ž•8ŽÌ,ÈÄ6§’.7"ãuÃn¾Û]Ö‰>V6Ôöd;[O¾ý÷çÛªtçø‡Bì5tÿ3d¾ü}IÃ`‹;ENçTm2¶£Ù-k1o×ÄÓF ƨ†:A½Àµ¯Ê­ýÁÁ‹\€_T´ë$p˜•š]@]šÄÜé–¸í‰ú¢Öœi†›…"‘{þ¿û8‘ªT†©@it¶)uùyÚý°¦…ÌDoùj¬·µ€-«G©[ÜÿŠÜß ¤) M<…²9¼Ê4üÆö{qˆ)àR¥‹TßÌw¸ßéƒJ=B¼Ñ¶²-äò‚/anÜŽ}1¬mE¨*Âê]¬oÁ7#ÐbÕ&ø`«#ŽOl4Jî¥5·äq~ ñÉ¢Õ*¥‘nB™/½îí¿}ñ<+®&–Vm°‹/•G;Î5‘UØu騲€v°ü`ÂWÀ)¼rèD‰Òçž.ÓÇI$Q„,Ê.K‚IÞݽ±³Æ^D!cÒ6Ò¦Äýñšî"S¬l Zëk’9úâ¶Ú ñ´^[Ɖ©“ʼ]†ÿ¥ÿO¦#0¬9j>¬rDãK*I?Í«ÓÉ ¬bYaò€[Ø›ò@÷·éˆ£…›™YD‘;ƒÓ-°ÛEýÿk`§} â=òW4• 25@Ö¤­ú— ]IØnÂÿ| <0*m;"”hÉ>cíký0ÚjYä.ð‚Üý€;zàg‰žušÔ\éX¸ØZçŸ^0Ñ®-PÓ™Ay¨ãy™º…Úm ‹n½ïÎ!ZqÔdhº¥‡WV ÅIºé¸ôçí†pFåZ8*ƒ-¢TÛHï`H¿ÿxÑhãpœµËK` ªn{ß®MvÀ¢˜–¥ Ô#¨:ôj³®’~çœIQcEIœÄŠ\­î¢ûØ’mÆü`Éé^U§œFÚ:…´°k›`»o¾ê²I²Y•\i%y'}öÕkzínów±(ŠM),›2†b£IQ·¥¿¦4qxÚtê*k"2G6¿›üÆþØ)„ò!TP#A¹[y¯½ÿ|cïä,¨äiq¢á¸ÜØ]Þà}K r5,ÀØDzž×Ämf’>¤ÆûŽ¿Ðâi”ºÏ£¦0l[ŸN'h¢D_:¶¿œÿ5ý¯ôýðl ŤI"^™žKqN1¸˜´’˜®üžÞûóëƒ'P2DÅ® lœ óˆ&u çÍ%×ry$mˆB2ìÈEÀ l·\ß}ÿ|z[S¥Rû‚ ã#) Ì ØonØñLLƒþ¾ãJm‡qúßÈ*GEÒBŠƒÊ¦¦×ûýðÇ*ÊàR¡aK•ÄŽI·ûì;œ!‘uÈËsäžm¿ö¶ Ëjj²ê”©§ ®¶`ob¿¨í>cHƒœÌe’Â>‚Tô†ì©Ï×¹ÀðÎñF¥)cŒ¬ƒf#¹ôõÄO™Šº‚õÆ Ô#îÿkTÈð“G] åP¤]‰VßÔX°·¿½Â¤Òä!R|n]O54tñÌ#tgiRiyGb©Ô~€wÃDÎr8i§—-ge×Úô¾–¹ Ã}ˆ ¶Âö786:$]$ñéø™©ÂVuhÜhÒmµöïr×À>$Ë)…j©ž¡uÍ¡#¨±c‰7à–'ô'Œ-¦è6ffô”ùU5tåLÁ ˆÀk–²ª‹›ÀßÓQŸ(4¦¦SeôQSvÞêŠY‰6ܱ$ûœ|k“Ñÿñ>O–¬‹ Tf4ð I¸GyoÆNØûÞ®:*ïg1IW54ë1Pj6½ï÷þ˜0$ï£&Š~¤= Rü=U1:”­‡”ù¶-fß‘úcæÇÏÃi¼›¥vPìþÍßVXÆÄ@Ä1=Íü Ïb=>é%¡ž†mLen™üÀņ Xñ{ó¾(^+ðNWâ_ f~ÎÞU‚±„™|Ϲ¦˜da}ü»þ Är-ŒÊn64Õ£àú8$¯ÙÂ>Ì¡ü»wo\FâšHUä3È¡*‹÷ãúœâÌ’¿Ã9ÝfU›SÉO™QÊbž?Ìz©ƒèFK ‚Í5ÑØê¹ÚöÓnØÚ¹äÊ$(.lH{]@¹‹þ–À3Ô¶£«Qaù„†7'å±cÎÂøÒÚÃÕ¬5¬Ž"•B®w&ö,?L@†Ñ$zãJ©ÈŒYžÑõ4\üݵlGÛOYNáb@Ê¡æÚœ°Üp;€hELr‰)ÉY€/¢ÚƒCéƒÒ¦ƒáì)䊦2«yIãn÷Ø6 ½ƒ%Y TêÝK¡í}€Üò88ˆ´rO+Gc+±"K6~Æø"•?åËËDLfèŽÒ• Ã[ž!t$´NC›j°,GaúÛ°ƒÆ’M.‹†,l»…ïo[`ºHÆ…u$X“¨›ßµ¿®š) Èu±/²Ü¸ãé¸ý7ã ¼)g+Ï)r,™ ²ÌÊQ´‘¥ÂõXÿ†öQlJ®Â£¸†–’júºz*Zijj¥`© LK›È°µ‡|\Û𺲇©>™Ç š©ápΤî¶;/‡üIà\¾J?忝0UÕS›Têëàª\Ø <kØð¿Ät5&”Í2¤ÚÐ\,BÅï»avýN(ž[á å$pådyÁ/"N¡¢vÛºúab¶‘ƒæoûØÿL_ápÙÎôóYM…Ê·§kóŠU4ÐÆÎH…£bŽNâÿ¨ÃÂ[£É[ᑳÀ£H†&>U 0±}žø§–q,€ª^mïÏÞØaX2é˦+iµ½°¼IJÌCê Õ—’} Ã"Ë4sI$òkHÎÀØ’Ãm÷?\fº X€-tó€Aõ8ÑäÕ)–ÃIVáÆJÌ#GéÇPó8¶ÆØˆ&É< D®ê˜•1'Ÿé¾$¥©HÒ´EÏo>–ˆ'o^ªUCÀ\äøð›È Èêû®ìFÛXÚÞíƒD¾f‰˜àS#”n«k;zßÁпœï%ÿ,…ù˜­­qÁà ­}ÉŽ™¥Œ‰æXÑWbÇæ¶<§1ÓÕ(Vt ë‚@$÷°Û…“0I2ÜÎE¦«zªY!Y¡FÆ"6Õþ`IÝN-4%MRMMˆ¡:šRmpôþ˜ ‘éuÔJ‘§N×½¯~.qµZÃH·‘ºÖÜ$rís½Ïqkâj' ~£³ ‚Ÿ(÷íúcÈÖ­ iÚéƒÎÇbVæà[è0»âµºX[q½Í»ï¾9˜7T<‘Á6Á :ÏÕ$+3ì,®,H·¯$³‚ Ø1¸µýùÜ~øeHj½×ü¾˜òZ‰<¥• cåxÚÖĤÂ4Y1©„r„º£yH±¹°ôÔLfõ)LCÍ0™mm†“þÆ3‰´úÿ:©¢‚ŠI¡£›T1>°jv"þe>›{_ºˆÚ¬ÔìÉ)‰ ¢uØñÈï°íßšª|äæi$`UAL]OšÄqs¶£…ut9vdº'†ºž`dŽg±$r‡¸·õÇ'ÏR_ ÞÚãÃTÆV…z½F»Ü³ãÓµöñ¾9ß©à3ëÆêìñ€Y¸ ï{úñŽŠÕ:³ ºÎ T©>c¿]¶öõÅ#Çñ¡†y#E‰ÙCb:…íèAûcFšu:+Ê“…•I:H5G ^¢Ôó[{\lGc¤©2%ãT l¡H·¾<™‹U#O>²N÷ßsÛœC4©b¨Š.[ñn÷õßcŸ)qHò®XaEÒ̬nÄÞëklEíc±õÅï*­1è}³¨b lvßý~¸çZT†C°o¾×íÉÅÇÃS òØôÛòY},o{ž9®„Ú-Õ’SeZã’+Ë (:¾FÔ4>ýÀ¾#ãL¾*4åMÓ[mnn}NøÒYTÆÌ‹"JC+ p·:® í)ÝN^éš3-¢«Û~w8ɱ3eŒ2õz‡E $Íæ w¿ôôÁ2–¬¨ø§&çdM%¹#õ'œ.ÊêÔ#Ø)gÃìWb ú‚l—%;æ “Ù$yåÒlú¬A<Ÿ0Æ9´"ÖîzñR¬òˆ§n“lP'ó”\ý½°š¬;¹†Mzƒ‰dB¿ªÜméú{Œ6š“Me‰‘îA[ l?òíé…³ÀK«EÔP²•I»9$nø@½þƒ‰ÓË€iª©”hªJmC«¤³36¸ÚÖßõÄô4U-˜*$.B™C|Ä×ÐòŸ¦!b²SBÅQÔ:‡LvÓs«mË÷öÄÐS;ÒÉ—T¸F’™F N« °µ¯a¿®57ÁWmÑ+¦sfbªºO ÚÇÛÓÛÕÒ¡¦Ó dt’Ä ÎHóaoÛÜa¬u0e´¦Me•…­®ž§×±ÀYÝLlÑS$ #2%Ž‹ù¸ç·ëŒñRÜ;v©€F’ÐQ6¸ÒI–'HC¿&×ÜÓÒø‚[AK!!B Žçÿ“‚'–T†!Õ…üò!±ù{q}Á#Ñë0¤½da¥‡Æû/oÿ[6•.¸cŽER½£Ý͇@FÞ„ãzpÌ©³€åJ;n-ó_î £Ž3 ?Ä$9qvéùÕn~À·ÇŠñ‡5-ü„DNîn,@ï}\à[D¦dôái®±,FÄ‚ÝM´ûï‚ §²:¢…_ÏæÝ®6&ûã׉XG!s#³ †Aåc¸ïÚÿ¾1áYÞß$LÅ.o`6Û›÷í|#ú„raš«%S… ©ÒŠ×þí±æ`ä;ë$/•\ÜYï`NÂ÷#V:ÅNŒÄ€ ¹;Û{Xzý±¬sR¥”6®€«I{¡Ûbpª\ƒj¬u±Vv4Ѽeâm±@,X½‰ÞÇŸKãiaT´°½ArÒÕ ¤mÏéƒd„‘¦ÍÉzc‹¦Y~nVÃ`–àóô¾ø„išD»Êe,ÝÎÅù@®W2SÃ3Ž¢K-ÀRÑùc M˜žÛÄI`𳨹`@¹Þݾo鉡“D¿´ÃK©Pã¹¹7ŸÛ¦†n¬ˆ„;³™@¿ûZØ—èVÍ¥B¬(E€UŽG¹Õå7!oÀýð2TÕ"$*u¶ãÐw7¹'ÔàÚ‘O%AiÕä-«ª‹.Üz_:ÌõD“1Ò­hìÀM®O?oMñ#ÏsTxRœKÆ  ¨!áK-–絬1¨ŽP]m Áb|šz –°ÿnq,$U‚]ärħRÚY¬Tû[|nYúL‘ɪH“Jùl8ÿ(&öçl5T„—"ÍAÔŽ°Rö¾ä¯°[Þøš(¡ Z#2‚¬ Pš½ˆ¿n>Ø™Ä-NêeWa/Qa”n{Z÷ích: ª’êW¨Œ§½ûÈCÊ< ÑUB™)]‰"û’Û›|{Fk* 3‹Èѳ<¦ÚWJ’½v¶,kÐ$ˆ„/”ذÛkóßÓ¾!žL%áv/Ó`#W;ƒcÁþز3‰T“¡IW‘ÂõDN¦7ŽÖP›’>ø™?‰j’F ò þUôåõÁ44²ˆ®È¨’¾St"æàöí*žÕÒj¡n|Ì×=¹Ü1?é½Ë”_T¶ c¢HÙš4ÔMÙÅÃ1Øiú\[,lQµ&³‹þeÎÇŽ= l2–jj ‹™$Ò‚†ÓpW’Hà_°%P“ g‘^á;¶÷ñß-Ñ/ƒH¹ÐÓ0`,n¤AÀâàŸSˆ ¥.Vm¶½ÔTÚúO¡Ú×=؉¡#„•omŸßùq«2ÌåK+¨xíäÄÜÛŽ-ÉÄ‹c`Ú¦ñH±”o9QaÈ6 ûàj÷ eEb/§ÞØ8«µ4DÈIPB²¢ÙU”sÏ|. VÕ[<¦ÊQ!‰¶ã·Íûa£Ý‚ìÁÃ(cÜ·cqޱ”ôƽî n¾ b‹ R¦ÛM‹_ssß|F!yY„Y‰_Ð\þØ}ÉúŒ;´qÙ×EÊíê6ß¿>ø†4]ÅÓü#×Ð «H²i ¢B€uoúcÆDí`~R“µÛÞëè~¸–ˆ 'OFÃ’uzƒnþœcÈ]ÑiÔÌ¡<©Á)NÌ@„É»±øïÆÿ\F!—[´eRÒà“{okß¾M’ìJ3(fUqÿPßµ¸àséï†Pg5‚œÓ­Hu,hEú@H´ßÿ,+굕EüªÖùO¿ÞÇí"ª‘h˜&üî6¾±†Yb½T05\Ôè*K’Üp|YøÜoñIXCX™´³l,»¹,»_nm|Qd,%U•7Ø€JñúÿloO$ÔìÎ¥C¤cc¶ØWv…{%^]˜ŒÈËÔ¨¢¨I˜Ñõ=¯»oíÐj‰éeñdù…=9ªŠ²8ª!ÐÅIGPÊN×Ü~xõàu-$D)[1Wòî Ÿïÿ»rþfYnqøyà<Ï4j‹Tä«J$Ý©\ÀÆã×H?|F›F½+Ig/¬¤šœ(¦JYA:cYC7äœ%ñ®^eUn´ÐÔ  æÅC}ý¿þì<¢¯ðå2ô²µ§27äs…^!¯x”‰ÕYOÌ·¹ Þß Æ-CQ]š±E¾ÑÄ¿â_ðÒx£Åùu0odp—™cæ²™>aîÊ#ØŽ#‚z†¸‚¥Ì‹å!Im¿}ñú)I]ðu)TŽdP‰¡‘ÅX€nob-pG¡ùßñOÃ4~ñÎeA”ÐGQ_j¬¶¤DYc¹á7âÄ5½­ƒƒ;ÛL§>š§hùâ«,ÌèÓþj†@\(Ò#¶—"ö>äo÷ÀÒÆèª²ÄÑù*ɽÀàŸ¶>‘¡Ëˆ2ÁDñ„I ‚V¨]g`è@·ø}0ü/IS•ÖR|1Ôd %Ì¢ ç¨R—)ੱ{ݯÉÉT´í3…š ØÙÜSH ê'•&ܯ©û`¹„K—(ø~œ„êeh‰ {ý~øì™žZ¹Öað¹U+=5l:EB²ê¾•¸kŸ+‚¡¶äzß eË(¦Î$ÌáWl’*E‚ªiPØÈAb¿]W?ýa÷Z±|‹áš xÝX²®£f Ûê;}±¬JU:]wbŽÎ ¨!¶æÞ c²Rø@PåKW5#=lJ*«¯ÊK7î>Þ˜OQáxs¿Sxw) ‹ãêYDr6«-·f&Ü-ûöÛ’0!•7Bù pVÿ¼œþ gÿÂòvP#@õuS 1SE}™Éî|À/rlqô÷ƒ¼1‘ø3,Oøf#VÒ’s,Ô°ŒÌul6Ü\mÓ]€÷$ƒ<%•dŸ‡™xo&gel®EÞ¦F¸2ú›[ʧƒsÉÅ£!¡Z–g–€TB )#Fl—Øék^oŠ2e“t1ŵrV3꬯$¡´t“™¾i Hf¶âýÀàöõÇ9ña&eDÏUdºN•ŠHÅ•¯n¶:â6{G qÐÓÔÃN¯d` ²’<»·+ÅÁôõÇ<¡××PE]Ç.³×º(Ö«sÉ Îþ\D• Úmœ»ñÖN¶w”åÄT™x©6"Gb÷>›ŽxèeƒYR±6]Öÿ× üeœ¶sâ¬Ó0Tu•‰l¶6ôßlÕ¥,oV+}¶oqQIY¢Ó³Ç  [¹?lG1,ÒÏn¶ºýôà„–™æUêu]¼Ö$ÚÇÛ;åÑÃ*üDˆ †˜ÆÎAÿ¸Û9-ÓZagqù€¯<_œFÒ̳d%•tÜò-¶ØŽz¤c­@yQnFÞ½ÿ®¢©ãèÍQ1#k‹‘õÀŸ¡ÕWsP‘ ¢³’lwío|{*Ñ t’Àé·õ¾5–¦’ÊDIn@fÜi¾ãË(!\Xب€¬3Ì (8äÒlR÷ûìqÕÎÒiR‘±ò‹­ùâØ†‚ -ƒCØcÙKÞúÉý0Ã9’Rt¼¯Ü’}½1>–ÎX‚é-vFï`T‘¨cÅtª+8ÿþ˜„<”ÔÌFöÉ4€I››ã^ ‹c¾øÈmÔólÄ!ééèPÒï¨ÝHÚÖ¸ýñ´ª€¯æ,‘ØËp"äXï±6ûc-“bª@äŽq¬~C¨ÚÇ"øƒ=ƒl×÷Æci]cpx'cŒÄ!÷°È­xÉ&3å^ÖÛ]^ºâ ^âFm•U|¶ù½qm©¨ÕGU0Š61ÒUÛÌEúoŠÄ5 Cá8²ÚØf`òZµîlÏpwïlptñŒ“Hïæ“N„é®YŒLLWQ ›0PT“k±Üo¿6ß3œú<Œ(Œè[ÈÜÛ_ôoᚆ†¼R3¨Z€ve ¤Ž7çqqÇ|(†Äi"ɦÉm­ìqäM"L’êU1ðH$ƒ÷Ä—ÙéS!¬ªhä˧Òé+‰¥»}Á±ïƒ¨(ÙÐt9 ÂV]lUšß·ëŠ–OY=}QÄÂv$0mWµî=-ÀÅÊ þ"•LÑ‹º,~aÏ=ûc ‹³d%jÄ”ÒFiŒÁç˜;_ó,JÙÆÛóߌ:£©Š¥¢¨t†s œmrT›  ÂEéÐæbš-Z˜§Êu{z‹ÚÞØeJÍ ¡KêX”ÒÚCXOûzß玹.Œ•ÐÖª²«¨ÑD[£©äßPC§÷8’¾&V¾…ôÉ-æõmǶ=‚½Œ­7E›ªF§’Û)'ûpd OTæI]!¼Ì¢äšÂÝïµøÂ)méjnk¾.¦‘Qz*J”MÐ\¶þçnp]1ádª©~”3fÔ ·ÿ8ŠZšk¤´ë>§/"°»)~p-|6¢•3Xô˜™`{‡ŽeXÜA±6ï«ÊW`qqÊ)+Ÿ©+S®Úv±Û{÷6¿¶4¦FRÒRÑùzÆí¨°¾ŽO°ÃAIy|ÔêÝ)R1bÖ·nucb±2Æ”¬ë¤ª+•°"ö·§ò±ÅË!L¢Û±-\'Hibc¡F†K­…½{â ã¨y — ­Ô°>âÜá”’Jõ²yŒÃmÿq©¡Š“0^ˆ2ë»Ë#–ßýì0ÎN»$Õt) ¨„ Þx‘Ø î-pïk[ 䤡 *,ó'#vQkñ}6ûàºøfzˆBÏ$á•ouÞøÐÒ¸Žë°ÁV+°¸ÒM¯ìKý°Ñ•rÀie€C¢£Ô‡L†÷'qÖÄà†¨òJE2S†;Zàñ`ïìqÁü†¡DrHÖEÒN†6€/Üoƒ¢.ñ…š5-¤°%®‹æ¿ÓÒøIIv@jwd”´Éx×{ 7·ùÇ…å&šË§•˜)º9µˆ=ü–\ÔÒ*!i£‘©–1e c°ÔxØŸÓ åIþ&eY˜I02 {Aeßô8‘VF_:ºü?LDWL­¥(5V#Ü‹ýp®^5YŸDeÔ³é=OÆÉC y„r±c’9`ÖÖßro`¦§XZ¢z™¢éTR W#ÜvàiL¡öyK ´ÒÇR°ÉMhÕÑ®÷Ò ¶°ÚçßÉ2E¦h쑨ëÀsÚÞ÷Ç„SÆ“,z§(TF/Í®~§¿éôÀðG,’H–"EóTkrwÚÇ¢TÙà "É«£Sp5^Ö6ÜqÛÎΙ’ƒÓ V46 ß·½¹ÀÉ2Ï0U]ºŒcÒ[ky·· âxÕʤìUm¦ú|º—»sDZôÄ¢vm+†Ðñ%Ü2y´Ö6$v툥ŠÑÝ›¥;!PÅ—{ìoƒ©ázºyj啡׿•ÔîFžOÌ@·¯±ÀÆ5DX$Ów¼jö\“ªÆöÛHãÓí m ¦úAEÆ`Mîn}»â6d˜²—å¾Ì ]»bt½4E¥]1MvÒÃå,;lÖUI"‰µ¹VB#ÜE”÷ÿLYBöITÔ¬ìðF±Ä5–-¿'Ün?|dÏJ²$£N€.mÏ\m*Ýpˆ”¨ê $Ç›~‡¬" ¢%c  1u%‰¿C Ä”´Þ:1tIÝœ‰.8°þÃENÑÍ鵑H°àébFûo¾ $Ef ²»æ%7bÚ±>¶ÄÔ‘¿^Yå‹K[m`qïÌ¢$Búø·o÷lB²Ù|ÊA½Ž6D™N £Æ RUGËb.{cÆ% ÂíˆCÖ Ë¢1pH¶Øœf6EDPbSP,¿OþÆ3 ‚}ËPÊi¤ª%¸Yáe7€Û}GéŠGˆª©¥FˆÆ"f{Ý›Ê@]ÍûvÅ×>Ì£93T:±™lŒ±µ®MÎ÷çp9!¨“2ÏNÂ*,¬SO—X ŽÿËn1ÃŽ/ŠãÂ;ûª7 ʼØ'‡é€«»Nöê2ùIçoéŽMã ó]šºÈUŽ­ kßb>–·é‹ö{YEIOQ=02Å‘iL“]U,ío˜VôÇ.©‘¦žZ¹eMbúCK)ÞÛ{zãv—lŪ*{ßgg±óHßßé¶=m˜þeä>[ CÓo¯íœ°Û:)Uæ÷=¹`1©PAU+¦úî;ýÿÓLHÕÈqk1bl6°¿§öÇ‹¥ÒÅ4Hæ÷U±úÛí«.·˜•[NÚ¯ïp®úK-¯n;ýÀÁ3!«u¨ª ¬Æ÷TÔ‘±¹˜»PO,FX#JãÌ¡n•+ÎÛñ°õÇ>:cŽ5ó1+¤ ‹ïõÅ—ÃŽÒÑ2<ý˜e $ÝÅîmïþƒäYŽtèX“Â"ŠWY’ULQ…6&ûúžø`”a|)E™u–ye‹]‹ŸNö-ú*̦©ªËºô€$¦UYÕ”‚<àƒ÷g5rŸÃõèÌÒ鮎Ab•¾caØyÿ»öîEû¾ ðóÇõ¦uC©š0£€O¶åÆÈYQåuÈ»°ãHÛ’*ùMJKI$ !YáŸ}¶©ÃQK#ÊÄ*ľ]!¶,Xßµ›ôÆYÆE÷NÐʦ–(ª‹|S°S}m¶£¾ûýoV ´ðË+;ÉÖéV½‚²›mí|m@B¬@3,‡¬ êÇqíƒZО©eÔI&ö¸ýÇê8ÏrÆÍ41§§Š:uHWb‹?UlNîm`0s¡ Š}“SÀL€):´–6·*IãÅ—QOXé[UÈ!þRx7ßÒøÒ MfH=4@¤(Ûa¾Ö±¿×&ªÌûO%G$5(Í%”F¬N*6çkñë€ÙfDfn€¼ ¤}íaå¹ôãí†HZ¾Œt‚EF©G;qaÀ÷çÂ"ò™"E ¬AP ŽûoÏë‹Ô.ve”»T²Ž’ùžäÝ-ÆžÛs÷ÄóF²ÖÁ;Dz±{kkµ†ä €}ðâèª:­G7-Œ§¦‚'‚d›TkæÜ’Ûwã)¤Tñ±L±BõȲ´Z"2µ‰ )²ý±!ª¥øZg]N‡bl/¹í°o×NáÝÂZYU¶E¸`F×¾ë°À-I4É(VŒÉ´fINÈ*û(<úâ,‘o‘öpG^ô²ËQ=#ÆæRB#`{1û`¨%šé¥’âB…ä°­~ÒâÜoƒça¡Š©­‰,J’mÛˆR©RšHÐÇbMa¬Ä ìGnpÏ%>«ì«*Ìa’)|ËäWsr¢þ`04%V?Ëäs((¤gõ7ß… n0÷4£(©-T…¤ @º Ž=öÀ}Dø˜F¢J‡s¨’t›_·ÔãJ’hË’űÄCK$ª&¶•o!Œ› ¯Ð®% 4´Ì¡Ë&¥Ö¤…co°Äšá0F&*±((ÁMü¤ó븶!:Cø ÐÑLDr™™Ëé…+FZà…úiÛïë,а§4ò™6C¥\./ÚÖ;zà° #F‡ëµõØ^ñS ºK!h˜M«üÝ·ÚÆÜío\2©2,²€¨Ïghº‚NËqÛq¶#¤52S¤tÑ"#ÙP¢’Cìà‘qpkb'} Á&šC"…ÌV#Ì¡ísέ½~Ø‚9©jgN”ˆ^ûÀÜÜqkzàÚñÈmy‘#éÛM´ì{ý°¾SO,õ&¦o;€Ê,«ÚÖ6ýpÔŸ]ÔoYH…Q+®RÅÌHx¹°±Øl?lC$LGVe$`«‘Àã“¿¦$v0§ZR“›ù”ùƒ/¨ï¸¹ãÛ­¬F‰°UUº®çƒ}ù¶ãšº´È$‚XØ‚Ä&û[{›spÿùÆMK­ÔÊΧI¸P.E¿\RYÃä`¥Puî ‡ÐŽy¾!P Ychä}Riܰ#¿¦àqëƒ"& ñÔ°Ðè®ÈÁsaŸAÁÛ߬jò Òh,FÊ›\÷±Ã*ÈLnutݘ² 5ÉÞÆUZ%!^0) ¯—kØâئ»=‡¥„*‚æFC¤ŽFüÞÚGë‰VFF]/:u%*”ÜØ]Çí…ÞB¡Ý‰ä© ާ¾ V"MzAEÔ_k zß¾%¦Æ@qFZš¡eŠI&FÒ©•UÈ6.}O|H<ú‹\–ºŽH? &Ø"¬¬´é ÑFÎÞR¤ÞÂà1Ûƒamû±ÄI« ¤J*b=C9;ì?ÓŸ¹åY’8á†FÔ¿3Û}F÷úù€ý0)éÄ·emAØy”¿=ð`«âµhˆ%K)7¸·~ob€Ù@³ž™×}o\6ßB |˜®Oã|:{tè3:j¹|ÁJªJ®Mýw#nÇØãê¿ÄóŒò®’hÁžbÉ8mï»鸾øù_Â>©ñV}A–¨êÖÉ¥]Ö$·™ˆ=®ú´¼;G–I™¦`¹‚QÀYLztr=lßNøÇª|#v‘º&ȳi¼3àü¶šyÅDïq× ¥ØVOkŠÆaœÖ×(wŽžrUÊÝìñ’§e÷¹8w˜K_ŸTšÉ] ¡Ž="¬‚ÞB¬¢üǦ+Yµ=1}tâ–H Fü¾¨gÔ@ÐËµÅ¼ÞøÇ993b6WëZ¢¶’QÐ0"(…U\þmÈQ~ôùÿ†h«ia¦Š¿ªñæt”CB¨m¤±`ã{m{öÄ‹w@“¾ˆü3U µ3äùƒEE]L ·;ã™çcâÿ|C5Z³+SªÜØÝv…¼§è1q–še5>’±ªF•ŒXs¨Ÿ” ½I°Ç"üFÏ’J:_E+Ån A &ûm÷¾ü[C™2ñhæe”›H]MÚâÃëBÈ­aµÁ$Xo~>˜ ºK²ÈCÜ64#€à\€Æü”eˆ+‡Qªálnm¿kcYØÏ»›p0\–S ,Z÷ßßlFð”•lÈUŽ«†6>؃YÈ)™œ-Ø­€ôÆ„!]·ÞäâCbKhרã4¨#Ì®6õ$%$U qÎ1îÌ]"æçYãK)bx6ÆÀ,å‰.!|ÀõSqÁïÔÀA‰M™½®œ‹Ž>ØÚ4qw º?•NÛaˆht…WP.9Ûy‹ºµÞÇkb^˜p6ì5 ¬1¬z¤ 1çýû`Ò!ãhHì›ê];‹ýñ Òîmk„î·÷ÆË¤Fl·¿>ØÀ •B°îNÆ’2©a±Œ{[€zrYG òq°Euлi&çÔsЬ"Ò0'²ŽE÷5KF– äFý¸ÆcË ±×þ.ݱ˜>­ñ‘Ì+i KLÆIUÅ–ößv¶)%švgZ…¥PH:‚ªµïc{{àŒóÄÔuÒ2C= 1³$r=‹I¦ÚØ‹kq~Ýņ)Þ#Ϫii™7;¥µ {Ÿ_þ¸èã“två=¼°ofK-I¡£x„½…†Äíûâ·„ˆBá»\û¾¢Øß‹ÈìF£rtîwçÐcÀÅÉ]wPlú³z]mo¦Ç pبçežù[< ! ØñÏ©õú½½1¬Šî÷V] W[m~ØÚuHE/å¸.-·°â>˜ Õiù…Éû^öû`ôSÙã  (o0ó®®Tz_é2 hS}¬/ß~xÆ]o`Ú‹ +°öǤ5ÉŒé]>c~¿úÓ†FŽ×{¬6ÆôrKx–”tä_F"÷·ÖüûcÄ]®-bÊÂæûmþŸ¨õÆÚB.ÎΪ¼ÆÛûò1ÜEÙ~ŽQY—DÔ“t†¬h±cbMïï…‘¡£ŠL´ʤú“û8ãmð¯Ãµ¿ Z°Îê`s°k·×éõÅ1©2—ÚÚˆ&ä_Ž,yT¢¤O,Id9B«cnE÷ú׈fèé…™žÀ­¬v¸&û‹÷91®QÓ ÁbHí͇Ô~˜Ïš­ÆE–„K Áf‘PºØ¸ävØàŠÃTÚdy ʬeÊMýxÛú…qU´UÔ¤¢‰‚‹=†”»/ƒrv¸úaµ7æHV`dÇg úµîKmm·'œ][uô1¥5©õ,¢kË È;“¹ýðtŽDEäžDÒÊ\[ªÞÀádSÀR…"]"(kè±×÷ß ëÙÙ:–+".¢$]/m†öî1W̲"$éP IBB Ç{|»‘û_)Á’1:•—qnã¹Æ²Rõ«RµA.U[FÚm§Mù¿;á‚è…¢–­DrR¾m”ØX[íkûá·/N“³q4Ô ,‡]üÚuêU¹;ßb8À/#Ñ1ˆ£‰ù=;X¦ûs‚¥žQ4S¼¬4 eóbè?~7ÀòÉùZÄZE]$‚@ÜùÿlDžâH޶ ?ˆK"Lç^­+p6¾ÞØ’¥¢–XÊ4®]ÎÖÛ·Ó`-ï…Qˆ’» îÒSy¼Úé|6GPÒPÆ5=62G,x¿·8ic¹å\ÖhjÅørª±¦²\|ÃØ}°¿4®H&ž95¹Uô:¾`7¶ßÓIi)æÉ`¤-Õ¬xíÉÂʱ­T«˜–b²h6(>E=ö 1v6“*‘ Ñ@Žem$½®Çn7øu‘ÑÄ! Ð Ã1$Ü{]Çí…9¦¢¢’®¢6Zº™:+ „*/æ6Úä#ÚØe–™)rø×®–’U°ÕvÜ}ÿ®u\Ì& ¦eÒ³H²’ÈCÛt[q¶Á¸æÃV“Q‘JÔìÖ¹`M¼§é…½-T—" )u€Ì¤Ÿkí‡óTTb¤? ú£Ð»!mï·¸[âžKRR±%J¢Ç$²h´Eæw;Úànæäl1”sȰ¼ÒÃ3‡óôDdò·o¡ýðc°†«ã!‚KuC°] p-m»~˜‚¤ô+’gr®[R^[˜ÅÍØŽm°û]Ä|*!¢Žjddxä’rIRR@àþöÄ™ÇÆË O:h³…FæâçÝ8Œ!–AÒ’¬]›‚YMÜ_ê>½±cuh+Èî7-°¾ûúâI|B9m‰¶Q1ëHÓÒ^=/)À ¨]îHá[ëIõBõîf,À¨#Q&Æû-þlJ¿—DeêÆÌΆK;E¯Üÿãô¼µL)LRJw ‚KH¸ôFmäÕðe.¿òÌh–%=5Ô¥#ƒö¶¨wò„oR=Z•¬4¨¹oAüÇì}ñM?Ã̽[±Eôº|Ûm½î0Æ)’®™§ZTŠa5¦çÊ„j>¡u Z×ÔáÓô;«Ì h^úªÞe‘È °;ó¾脞¢jevhI]PJ ¹¾Àïo{ö76j†Ìgø©‹É**¨2ƒ¤­þÖŽšCT³|ÝXUÒ67¿#÷ÃÖÞ¤RÔHU‰ú¬ìÈ&—¸ôíÞø[T(cˆªÈ ë(VÜö¾Ü{aÇM^iâÊ’ÜÞEsÈíïï„õô’GP"›òúd4„/P¿}Ë~¸d•ò$ˆ\§ÄZFrñÙÀÜS‰Šº¹*Å!Y×Üé‰ X¨òQRó$/«P¾†° sÛÓí‚"Ÿ\, NÉm* í›X¹Ä›äˆ ¤Úc•Õ„L×%£Ü Éý‡öĵZÞh€e7 oí‰Zq*™J®¡¯që{{]†%‰išúr©D@t…¹$ö'×¶ÜydÚ(Yd³Ú冮yûblîÎb}®äZÂ猠HD’kXÑ®6ôäïaŽ66gI;°¸±ùyéؖú ,e’ÈšIÐt¶Ä¿íf¿ÛSÓ$ÒÆÝDR£0¿ÖÜóˆä(ÊÅtFulà’mŸüœ{4‚ü£Õº¨f mÛ…Xù»÷Ä|r:<­E‚¸ÙXôÉ7v‚>¤~¸‚Œ£Ôˆœ)%À`Yœev%pDé$ZëÙ—¦šâÄny°SoS¶GjyJÇQ#€Ö`Ö¸S¹aém8eʰ’K,Œ ²j rW@R^üí"§š bwbÚYPÜ€IÛîo‰#Ž6x¡3C$hÀ,‰å&ÆÜ~˜èß‚ž¦ÏüogË`jRj$žug:…ŽÝ¯¸ÛÚø]ÔÛ&89N™Ðÿá‡Áåy}O3#Ó¨¨½%<¢Å#fbx¹$]±Ôés)ic7?Z²,è±·ž#¸eÞÝÇ6897ÌV††¶5¦$™]%BT[hø !ðÄ+[—WE—å‚’têWJ†°Ü“bJƒaþ,`›–GlìB £ZZÚˆrª'eœ©Ã.»Ê€†åI±ar@ì0-8©§†žjÊ¥Uª²ô– —µ›Uô÷;\.k”ÑfÑä¹³ ŠÓæiâS·‘Ûc¹ÀßˆÇÆh2ï EC¦©=C Ö©r|‹Øù¶'°¦nÁ«^¥âÒ¥!Š1+TÏ Ù .ä [÷ÓŽQø}—eÞñ–cálˤ•Yí/S/®e!eÿñ¿£\5­ó Åðé³ßøÃÙE,Y-m})¢³2·PF5v[û~çÓÓøçðçÅTôÑx¦ZxÕ+dq C*¹½‡òê¶’À›98ÑŽ DË–Osäð2’âÞ ñ n—U­š,Ó¹µ5,0Ð×ÒÑITÔq¯æÍ:hqßK‚§ˆáËÕfQ—ÔOC@àÍzoÓ,åJ;iÚþ÷ÚøÅ5 “˜³“ð¼dKRñM:eW!HÛ\E—ý-rh·x7ø«þAOðp½U<(’Y«Jû Eý®yÅC,¯ªð'6ª—0šjºéLQÕM¦òH–FÒ>fàÚÀì1çá¼k‘g-“»åÙdîÔ‘×ÈX$q€«#!#€«Ï¾,¹W¼–eÐIœRfm•@zZ*Ã’T › ‚uúa¡®EÉ(õf߇ž̲Á!†Ÿ3’hUªZ0«2³H·¾+ùìTôÙ½Gðú9LIfÓ–gÒšálmïÆÑxÀæ)[U”N¹ŒR+Fý(44vîÅOïŠç…3•›9z Ò¿‰‚dP.Dñ’l}ì,>Ø™x¢F[—$ù¦sçqft­NÇòDì/° Üß¿ôÇ.üVÊ¢¢¯8¢5‚:Ì|]­m±{Í#Êjàš¾Ž½c1Ô“ 1 å½ÐyGšç×Ó*Lâ¨æ–dIcè¯ÄI©ƒ¸½ÎÇaÜï·;bÌrågŽågŽhÌŒK¬š—Oéˆãyú¦P²æ+°áïßøƒ.¨ Ì¦£œj•PÅ·>ƒ{0=Ké*ŸúdîÝ÷ÆÕÉ„Ðr#&ËÀÔ9ÆŽ©o lÛâR¥n«3 Á7[•ÛˆÂÝv¿;¾ tH¨£¨Ê5ªmôÆHìcÔ£È<Ì4“o[ÛðC6´m$Æ Üé¾5D˜'å¸Ê/'æû[$KìÇ{_ØcRŒd²9P¬Ü‘Ü\f é`ok78ñP+_«¤ßve¸ˆýñª¥T»Vâû‚>˜Û  ‹Ü¶úvÁ4ÀtYn–µÈ*7íúcΛ(qÓ(µ‘€Ê…’DÔ¤é¸Sé|la$ Π@Úâ×ß®'&ÑylV÷b{ì1$e dhÂ16îG?Û÷Á ­uc¤ð¶;ØÙÕ¤Œ#ŽÆÊ4ï¿9 [I¨òY;µïlKU$u ëó¤`X ÉZþŸ|@nbU+§S%Mïk_n1$w7³ ´•ÕblLʈŒ25…ûchD“ EFº9 {ooôÄ0xA‘ØK½Ï6Æa…D±uZ@àI¨ª¯šÂÖ±ûc0¤,Žk4êðS¯J=MòGc{úmûáy€™´×Q0îwí÷¿ÛØé$£gÞ÷µý†þ¿|Gd²³DB›’÷ØlEº5JM¾YꩱME7çtõ6àÜcT@d ¡5¤“qµì~Ç…t²nm¶ØÕŒMk;k½†ÞÿéˆVGrT‘åÕ{ñ½­÷¶%e*» W$qîöãÈ>´]{é¹Zöþ›ãÅ`Æš Ž,ç±Äë²H$ ®¬.oÿM{{ý¯÷8ò é’ Œ~m€íÈýAØœjÙ]4®¿-…ì¯ëcöÆÌ "•d^Ü}ñbº®ñ€ÌA*OÌ@àû}€î5BE-¡I7V Öà÷¸>øÚu)LȦÊÁB ì{ßï‰)$¯™™-¬•ýûñű{,ú@XY˜åØK\Äi?®-9eD5´hºlèÝ8ƒ5‰‚OÛ÷Åb”3Ũ4ŽQïÁ·ôÕŒz©iSº€Ð7¿¾pSTö–‡Óô§Œ¤èÇA¾¥{’moíR¨|öU‰–åx± c)d9Å02*ì ³\ö6}pDÁZñ„WbKk;rlqƸeÊ\ZSI#²“gBå6˜)±ÞÝ·;~øwx§hX¤ŽÎjˆÙ£[{öÚø©A["ÍÕ$ªª‘*`E»[é‡9md ©Jˆ'QVa©IÛ·¶¡÷ÅY"ÒùFe®Ò:¦iÑ j@f³›\ úŒX)f5• ÉxJV°ÒÍrÝù$ÚÖöÅMB|,h“²†ˆ‘ÈàÕLX2w+ hGM#¿˜ ·ûë¶1ʨ¾2¥3Ë5ÕLæÔÛo}¶ãÛWHhš±–9LChÈÕÔ‘aô½ðž‚¯PS6©X‰¨@P£ÓÂå©Ëš«ÙµY­`¶>»’1S‹í'Áâ¤ÿ’e"wQm:°€oÿ·ëh*žS¢hõ]€cgo¹ã`Ôa¼5&ž­ÖycW’çH'k[p;›\mV‹jÇO‡pt´¦×°:H ÍÎ,‹qì©òÊ£¬µSNZ¸Æ B&ݬw"ø†–¾9«cŠ‰Ò¢– CH<©ªÛóË /ë‹oI•U[5*T´’ܤCS5€6ãpp¹t*Œ^˜¢1€ùRä‘ê.KqliI´PÓ±-^gªHÄÏ1Hï$q‹±“ü?\ ­,¯Rz2Á –G*  ½ô8zi窑¦HUZý.ˆ¸ ÍÛѯ¤ØzaÍ2JÔ]y Òʪ²y®u^Ü=ñK„›|פu©T^WM}IE¬ÈËúúcÚjË1 ÕD‘˜±&ÀíÛXý0lQ(ÜÈ# ÈLa±ß| ;kŸ«LJ@YÅþ%nÜU'%Â-i0I™D†yüññ¡”Ù×Qû÷ý°²±R¦)ê•äøwb/b,u[b0§ò‹H&Õ¡œð éúÂ鋪AµÉ.ÈMÉbR}8ï‹j™ž@ÊÏçŽÌ’HAüÂ@M‹ mÇûp6Í1aXÑ–=Qßp ¶]︹<ìpÒ~¼rEª)ˆ­•€Ð¤Üßõ'é*#?Ãcb¦ÿ”¢Ëp ¹<ï‹"Û讂ÄMLÑĨ½'“P²‹í¾¨ŠU™¡¢–*iI.ľÌHÚþ¿(ýp¿*`¯$3 Ì^FŒÜþú_ Òá–$é¹ùUÜ^ü }¬12:kâè6¾¾ ê:oÕ%”7sb6ýñ­]êcˆ#Œ('NÇQ¾ê?\Å"¯¥Œ,u ˆ…ÎÀ®Í©dI])ÉŽXcF·¹g݋ְÊw ½Ñ °ª~s˜Ü Ø•¾ÛwÜ Hj±^exI˜³Ä‡Ì·7Üñ‰'žJêá”äÊÒ i¶ ÌËèl7ÿ¸`ªŽ$ê)Ÿ}G ±SÉ Ë[÷¶#{P±à*¨Ìð<+1¨²0¸ W›ß’°-rB•“G%#ÌÑvšößïôǵ’ff1ÓÄÀ‘¨…b %@÷ßÔo„RÓ´lñ¼ÎæòJ@$^÷ºƒ±$m…Mº^ÀU*ô¬ð¿LÉ!Rú€ˆîoô_¦5™âžD@ÎêVà±òÉ©wý.lYÄdŽe¤3’îN½ïûb héh‘)[Y6y>¤ƒöÅÕe:¦¤G3­8I¤@C¼»&ÅÖÂäÜÛŸÛÏJ‘j,HH%îC6ŠîO­öçŒI@ìñSÆËÒe`Ê>[¦×÷ý°$ý4¡W2H%Švd‰¡»©½¬/Ξø ¾L¯ƒ3H‚ÍðîÒÈa_$ŒÂ슢ŭÆËÛB"y:4°J጖µ¬ ý"&z¹‘¢HÜ·U¤¹ar×ÒI;oÁ7æÜb Öï ¢THAy‘köýF]Ðð|æ²"<‘<]VÚÇk±:¯þ÷ÛR ’–YZ¢öŒ¨<Ê¿¦›ýŽ5†Ehš&e!®@‹úóp9¸÷ÒÖ~”ò¶›¦¤@y,§kw"âþø±¯DÀIYF½{E(©C€Uÿé…I7Û‘~{álÑ ª 0rDŠXÛmùÛŒ%‰5¨‹R•u:î?šÃaêA¸úcÚ¶ˆÓ$r¢)xÏ äy¾àâ%nÀNÖ=5iGù4îÜ/ü¶¸>ø#ádšˆHÌå•®oåÓê}îo‰"j… SýP¨Í¡ê6äk~˜œ¤2H]a›YG$±7Ë¥ˆûñÎ —$$:"º¶Òx-ë·× ”Í_QLÐİDQe –ÔÞ§¾ä}ñ®ºifŽhÜéž;VæÇ~ØWJJ©àª”ÊBê@1iºžw[ÚþþØWraŽ 1iɨm{ÝMûloï|k›Ï0)ʲƂÅ6;Ûaïl]›˜mPÅ¢h›T1#¨+¶«zp?›Øá]B<#¥© %5”°¶÷~ |2M2¹…°É1—qó&‘kƒÜò?ý,@öMº,¦5î=I#qÎØ&éØÕUV4èέ"…K€½”ÛÔúãØ:rÔ6‡X£!]Øéa¶þ‚øn¹`³Ig¨•\¡‚‹´›‘m‡Øûïˆgz|(dÒàå7ö¾ÿßÁ£âºQS³D$UÒG˜ù‡ÿ8’lª¶³6j*ZC;‡Pl· Ÿ^ŽÿDDÛè[OK%B#G”jm¤°¿ØcèïÀ¬ƒ8_ ´ª“ÐѰ/¬?žKÜ3Xw°¦9ß…ü#$4‚˜å­že Y‡›a{L}#A™å¾ð¼M%\Á "QFÆnžÂïcÇ<ñŠsÍU#vŸߊE'2¦¥ÊD“Uõäž8Âj7¹ÖRyïúàäÎ|USáÃM—S34®Ì±»dPl5ç× ³†Ík«ÅE2TSR‚e’Z¹ »yˆ±7ãz\ï=“ÆQd¹\‹$¢#%mFW·ÎAÀ·c-Õâ÷#¡þþÓåò¶cžÖEQZì$¨,$eîÑê½´îwĹá½/Ç>iø}âh)јŸáäüE;K¹ ¿)}0fU/‹<[ EH²Ü•£]3¼¬%kÿ*í}ûßgð^MBDÐUÅE'@,Ð,ú#˜.ÚÛ¸ F4yqšº3K$¢øg4Ë|}ø—á*zÔñ‚`­ž)UY ¨NŒ@Ô Ø/;ò7¿Òþxñª“Å­ð†y+¨5M ÃæÜY#: ƒÍíßì—Ä^ñFe˜åžWÏj2Ø^žD’ ,d(cÍôžx¶öÅ?7Îtó âƒ,ŠzVh¢‡ªÑAn¡Ž Zûâ½Ò‡Úá ·O©ËeË|eÿ¾0¢Ì<;âÎò Ø– ÒÔŠ¶-C«¤îX‚{vÇMüYÊrŒê¿Ã߈þÓ>yL¥Ú1fRz¥FÚ´Ù¾Þ¸[,’Uø µ’D›*®Ž¦ˆ%ŒrC%„Ð@›m¶Û‘€¿bÌSðË#ðÖl¿ƒÔÔˆeQ»Æò3…7=¶·±\ÙVLtÉ‹Ç1äye5>SNñ¼R’¬ ]ƒ•lwÍö¶)^>É1®¤Ê ¬‰i^¢5’ç€ÇIÓcr-·Öø»Ô&k9 Ôž8”‰•#@«ªäXpoŠ®{•H*¢¦,³J– ˆÊ³²ñsÜ[~ØÏÍšfÕôAøíœçYˆ2OÀßÃrrÊ ↱áMi™Gåê¿MÏ©'œ—~~~~gŒë³O瑘Ùè©ÁciÚT€W~Xá‚L´ÿŽu^-Î(zé5dõÐ÷s.€±‹ÚöBM½¬7¶,”´5u‰WUN!\ÞY/)špæÖäÛùúÇBYI#"ÃvÙˆüQVa©ÊüàÊ(J¢’úD’(7·—Ô?ûÆeÞñ%Fo—ÔÔ ²BºÕ «*ÚÅ@îí‹5$9µU JOгÂ4¬ÿ"B͈¸ ìús°ƒ4ËüEYLù}ZFÝhá­iØŸ”6ŸË w¾+PßÈÔNMã,š x¹ªja„Ræ”Ç º+.Cq¹ØoMð›;«’*š˜¨úTæ;<¥EÉ7¸`¹íÈÅÏÅ”qÑä«E^òT,sèõnËÜkcÏ<íµ±Î+sÓ ßâ|™Ža \§óÞ$Jѱ–#›ûb´²ØD¦`’Mˆ6ÛÐᇉ’x3VxÄaîê !Iïíô²†6dw=C¾ÂÂ×çaÄLo³Æp<Ý3¦Ö>]':E¤:ë7÷¹[\n éFgåK\¾2c1‰J+)ÛùOc‚€y%3®ê‚ª– om…Ž$Š–'¢–iÕÔ^ýA}6€£ëßÞ8ä¹fê! –àÿ³|HÆ7q|‘’AÀƒc÷à~¸±ˆêhÑfÕFáJ+TÛ hè_‡å•dš7#N›…ÔTy¾ÅÛ Œªµ-Ò‚M˜Ç¿®ÊëZ’’¦.Z µDÔ/xέ½ýøÂÓ÷ìYEKëb±¶ä‘·{ïöÄU  ÷¾’{Ûœ1©ŽžJ†F7B:€Ü€Û½;⇩ ÔWW˸߱ÃõÀi åböQbmbÚöÄ´£\í’=,XmÎÀoÏöHÁž8Ý7¿Î6f¸Ûl]Jiê­@ˆlãc{zzˆÊIÌ1¼ñ•¤Ø—*ÿÛO%;¡ ªÉ,…Šßtaµ…¹íƒL2 ‡¡w§g„•P6Rµî6âüâ6A¢ñ­î9Sß`>˜€!‹IMMçQmÈìw¾ÜúmïÞ`#ódó«: ä‘~ÃN}q+‰)ë”ÓÀ2Så\~ö?lyWM-.• n©bTP>› â @ÿô짤Úô’E¬;{X~¸ÌLŽ6e.†D@÷¹ãpq˜„'ù=…¬Ì[Ër/ǯl{34÷y ‚*¥É·Û}®~ÇM©Mô]ǡƱLé"ùNÛS-Á@Ìt)µ¯o ¸ #P«`îwÚÌ,m±·ß²¸éô‡\k\‘q‰DÊ®‘³6¤]µÚXq¿}­Þ-hÎŒ¢E­¿™ŽçŽ?ß{,Ю­ª›ì¼ÿùÄ€`îÁšö 4ƒµ»ûãC¹P†Óå›ÚÄßéµý9Ä©`£¦§Q%µ¶÷7ý±:ìm¨†XTÆ£-öa¸¿þ˜‘üñH€n\Ûc¸#×ÔËÉ7žiF­®O>ƒFAÔ[tÆ{v·Û|AÍ·q‡Ôu˘ёP¥Ä mà w<[c©QÒÚEì ÎÄaµ$"uD6o"›éý072 ª˜$WǦú¬¤Ûsö'ey˜J’$DÔÛiÒ©ÚÇ÷ÄÍÒeI䕨Y¶–Ö'·ßpqíd*Ñ ˆUž'µÈ)¾˜¥¦¸uòZòÚÕ©gPa%¢ k6׿¨ßO>˜q’fpTPÍ LÑÈì¿õ ]6Û÷›‹oÆ9ÞQ^ô²Æ5*˜SP¸»p6Ûk_×::…ŠHêU`ñ’Èà Â×s`ÇoôÅ2ÄYŽG@ðÄ1ËIJTBEÔ¡Üê$íkM»œ4©‰Ò‰ªf~“-‰±˜}À±.9߇«9fHjz’‡Ef.‡]Ù†öÛ¾.tù‹Ôåñ5úë!ce°dK0 ‹ Þ÷Øc+ÆìЧÀΜƹh™•d´òº]͈íüÇf=¹ÁÔÓFa‰š ™’ì­Š+ü^ÂûaGĽ2¥H£6 hÃ_H"Âý‡7û`|Ñähžbì“ ѽ渚“qÿqý0vr…Ý]æùŒt4¨‘B°F?/A;»Û–ä/Ûèq^ðíF¼¶¦lÆG‘áž^šIó Ú÷ ïÁjŠÙã™f)%@%mgF‹ók_Pâþ—Ã*4è gXÌzšF#ʸ'k›ì~ؽ?B©I¹eô±Bˆ$DШÉ˩ܛ”†ø8OÄ]faÌÔžÛnyõÿÇÜaŸMž(Q”´3]nÌ9[\\nFã÷ôÀ9¹SKy!Õ™`Æ÷*¬^ãamŹ´ßCî ±1„¦++1Ž1Øj;œDÕr%04ðFâàÊtÆ¢úãtsJ©æ.Tyg1ß{ÚÿìqìÕ *ŠË!FÚ¥±,Ãå'Q·Ë€´×PÃSQ:Çñ¤Qêb”†µ­pv½ÁU$ÑÂÎï-™Úcù‚Æö¸õ¿Ó 3ª¦«x5,‚XÙ”B·[°I>ŸOðàyšxTCO<ŒH°PConçÍ~Ûàß¡T‘ u?0UaE {Xuö&ßKãÚCSñƨšZ6Œ÷#pÆçck·¶ —,¯c>—’I#RY&¿˜°XY†ÞØ“%ÉêéËÉ^çTlìúYt‹ù€]‡ÐbËQèNEù:ǯˉcÜï~=v¶ M ])c¬îÀ‚B•&þýýðeyãÔ¬¢’A$­se%mp/~×ØØØï‚d’ )¤”ηr\‹noìlíò aQÏÓ­Z‚úO²¹!®Eû÷ûbwQM;ÈæQ%IºÝnx<ßÓш|s#¼ÇXŠ6i$ |Û;zú8y%4ìVtšxHQ Bª¨mqo¹ßG¦è—%’¨fŠ`"–0Îóm7&ÞÖ$oôeBñVÏ,?ª®×V‘ˆf+³ð9çë…Ñ×ÌÉ43ZS3%ÏPjÚÖí½¾ØÚ‚BÕ)˜ cL‹+²3lß(RAô»bÇw|({8ËäÉ¡¨¤ZhãRÈϨ«w÷;µð$EÝ‘”€¬À¬‘¹‘kmÁÆ•TÂzø¤[B’¤a´¾Ìö¹,}=±‚…^n”RHÑ4z¤;é]'r¶öÀØIO“EeXä´ò-Éèê3è%Mÿî·é‰(#fn˜r«"Çc¨¾úÇÜß±¨G­ZjwI£[‘Õ[X½‡ØýØW!šÂX§Y‚\]\Ýì4ÜÛq²àíbM¡©„¾bˬOH<º»'p/Ç}¹ßøŠ(¥xúʱHEеÂÚè/ï°8KM,‚•^'¿M‚ê2ߟå·Û÷ÁÔ“À¦šLÓæÊ%,H ×r ‹žlªmÇšøWYž÷1UJºêid…b¨ ,)Ô~{~¸k$ø™]ÙcÆì,¤¨ ¯ß›û†•ÓA4•STPÊ€ºº$Î53n'Óµ»_Û )ÒH¤Ò@QÚbÎрѰ¾ÖúzcBè;Yìu’£êH-ȸ[ã¬Rx…¦§†s$J o;lÛÆÞø%ü/ 4&?‰©‘!ubðª›< ÛÛ ó.c¥“휾 “0”‰êDF&*Yo¤i°ïÇ ¾5“#§J‚’HìŠAXãìÖß÷ýqmÏ䤦žJH¢–Y,‰fÒü•c‘å©QÑ’¥t‰v@NÖã}ð<ä£ÉltépU©¼5Q=Rf•i ™÷#‘lZ2\Š›,øv§£•ÚR7 TÙš×Þ䓇µ”°khÉ´Q+gQ"Ê9·©ô8šš’Ždy XšÃQU _skz[§e±ÇŽü5•šŸÃM–ÝÂ"èi*µü¤ûluÛ#£¤¤©–²ºXÔ*Ä%øxÀ&Ý»³ñbÖ°°¶Øç?‡pˆ Î ´õu4É,#SÊUNì ­ØzbýàF¾IâŠ<î¥b uB&ÊJŸ˜ßcé…§˜°jk”Y2üö“ùM[IE•ä0»"ÍDš¤qþ#qçâÖÜï„Ô5­Sâ›eu9†S.€•UD5ä+/!=ý=°Ö·!Ê2Ì­h²1P”ÎäMTÌàƒ¾‘'{âçžÊü[—xG5¥—'G†6zúäéFñ2©wibT²®Ýöí…É1pY£.Ajk¥°GBD”ÅYÒ" Øj$Üllß¹Üwà $dú¡©¥XYºqù®‡}üǽˆÅ¶¿!ð¬ÞÿüFgM_4Ð ¢D•YL6$8P~R{÷¾9w„ž¢Šƒ*¦ ¦-Cï—¥<B´½K†ÓÈ`€xýq\1¨ªh¿ÌÝ/„éÖÒ®LÐCH«%Écv¸b/oM°Ž¾£.ª½-Uá“Y}a 6$¦Âý°lô³ÓfTñÔPfDXê•a20¹6fù@®øöŠ:v¤­¥2­*»+·Â²ÿëoÓ B%y Œ©.ä±`$ Ö#¾Ü[ a‰ŒñÒÆ &MDnvÒMÎç‹b_щç™ÈŠBÓům7¶j’JšŠ¨¢º´ÏÊ(b«o­°ÂÐ5 (KqÕ7{ÚÛ[úb:•2M( vî µ¿[ïa‚z‡ZUÐImªû±¿é‚B&_C4MZi Œ•"Ê£ÓêK~¸o‡¤€ä`]ÒÄ•RÓ}Ààô…_JÒA¨– ¬âëknÀpÇ"EuÂ[ WƒhÙધJyõ³/•AîNø•B0ºŠ Ž’ %R²Yt¢Ü*ܵíÚäá*Å]HZJExŒH$’2uë³-þ›úaålòS½; ‘TÔ$ƒüÈ “ý1tôu1Ç,3Æ¿™óE͸öû`8C _UJ²)@%!FÊÇlOY=,ªP˜rur}¿Ûˆš?1"=l€?–Û÷ý±•-Ë*¨P9·Öç¸{,ÙL±Ó˜Z‰d–™™ŒÊ»¸Wô¡û^ã1H–Ei,#˜¡ÖmÇþ< r¬¯20ÌUœlÚwž7þ\\ò,Ú–Z`µJ$’%2,›Üz õþئX©6[Žvù/B K¦©’(ª#Û¤¬O­ý{àbV¤"-@‚Mˆ'›ýo€©ªr©êcu^êÓÓŒ‘suï¿©àœðé4ѬU’H^ÚŠXµ¬¦Ø§ak|ƒeFš¶ZX*+*P;€eŠ4±-«V¢GÊ4ï‡Y…lIÈ´Ð" +ɺ[ŽøS iE%M;Æ©–CÛ¨Íå!¯ÀÝ8úà¹LʘÇK:ÒÉ$¨¦ìt‹0bm€³s놥Ñ"›d™l’A–ÓÉY oé,LK1ÔA½¾½½0U|"©jH£mNÌëüö o§úãL»*ªJ(!’UÍ$ecXþX°!‹¬;áâå”ôñSšõëÕTCá”îo{{ßåE‹ ›äG–eó<°ÇQI>—ÞO1@‚ç{oL0l.eÌ+DÒ±&åÆú·2í‡óÓ˜¯ü¼0ÊâGy …”I'°°Æë•Õ7J:áð•¢…H”‡`FÇQùp*ËT6‰2¼¦ª::–SM YmJãÓÊÜ‡× £Ë`zhÞŽ Wžx‚ÇÓWISs¸ïqûaS˜M]ðtÖÇE ÌYe¬6c{ âZü¿Ä0˜ †–ŠHâ-¯S+mõÀûˆ£O]ô„2eôS‰Ÿ0–u}HŸ ܵÁƒn1¥,t« °ÀèÓÈ¿’€’ µÆçŸa‡ttC•<"’E¦C í,ŒM¬‹¹µ·Á4zš2éòÉ §DŽ6Ý[½½°~áRV"ƒ/­•gµ<²Ô/NO†ôX(ØXÜß·¸!è(Ýá•è¥S#èuq½”.Á‰ãkz†/áüÃ/­LÕâøªUd™’PW`¤6Ì>ø7Ãtt5y²D™fh¦XÙÝfeté!®EÁ¶Ûâ.É$º*3ÇMÏO>^µ ý>A Žo¡#×|Ù-NbbJ!XÈXl|¬ÄX‡ö¸'ÏÑA‘çÔåiéÖW‘KÈ–sm!¶¶äó‹ …hç®ë:Q ‘̱ÆC-ˆ;qí†ÝìG¶/ÑÁW?4,ª$ 㲞v¹7ß ¡ð*UƒMü;–=ÏÂæ÷ÛmþØë¹œÐå¯PG=+ Ó47"2Ûy½Á úâ¡HÕœJc‚IÚFD ^;iÔÌmÅ+†M•Ê¢øÂÕ³´tÎëðhEõ9v,.>¸Ê ’µ Ç ŽK1¬mfãap}8¾É—K*MQ¤!ž&KV¹ßÜêØâ*<²ªWs.–¨ê« [ÊË^O¾x¾II_yV¦:Èô ´dk¿ó¥¶Ä4™%w„Fâ(ïpT†ÈõÛnqÒ©rØ©c5;šQ£á¥V6ßIÿºøJjˆ:ޝS¡VdÜêí{ÞÛó¸žR]•¼³*£2Ô¤±RÅ!+¦WCJI¾ Ë{w·8Ýòܾ–®ž‚ž¢s%ÒBàÎÞbF÷mí‹{—ud¤‹4“«?^&W ÊPYIØœl¹m]E(†R*4ÊçÛ}CÛoÓx<˜®R¯‡h†Nõ5qôdR;5<”#{Iß¾#¥‚Ž8Úx¼=¬õUÀ¸Þú‡kž=}°þ¶<¾tWiAXï®á"ã‹©¹ß±À´…d£«y(5†P­%0ÔÒXÜ,Wƒ¾üƒ‰ó²Rö5#1¥†*AgRc†í#*Ôì;‘oSƒÓ/3‰)c§¥KҔá›f?Ínþ->Êrsá÷¨Z)ÅRL&z‘%œBš²êäžnFÏè©8«©†­h#iÙ–¤ ñcóc,5˜²Íã]®Êc–“‚\¢¬Ôñ,5R)n˜v‰u.°vv›[ÇÑŽ™º¤‰4=ÔÌïf#Ø.ÌÙ*JÕ4¹mC‚ LTÜ-óoõµ±-^[M×¥ž[y, ak¯ºóqëÆ5ð‹”,¯åÑe”ÕrGOFÁªK…(p,wàîG·Û `¥òÙbg_¬U$eù½©8aU–´’T‰âiKÒ·±D ^Ý®AÚL¾¼P´°ÒQH«v!H2‡Á´r¨œ ¨Ó+„ª+kÀ¦øiaŠB³Å) ¹³|Àß…oÔaÆk ™ =L?Ãéâ˜ðD™E¬n»òHÄyecÑLÙ„ Ôµ`™VR†ÃIblë‰3šÑš¼?Ë4±y„ÁÂFÑb,wÂþ˜IHe…w•j#©«™iŸIa*>[€l7õßWACIHÓkÊ–¦TVÑ—Ò{jV§ßœK‘ÔÍZíEM)F@Í0@Jzsc€j(%þ%ðU¥^$½ÁŽÁ°·¦ßrpŸRÝ´"ª¤Wš*úÉ)êêÝ4¤lFên am·ûaæ_M^(ã5BYŽ”Wº1<ÙmÇßg=yó¨e’•é©á Ê®©¤nE¶;oï‡ô” OM2™¦}JÓ)Di¸näǦ'\ £ÈðO^•ç\ëЌ<€è[M¤z�ñ½NK¦’ZÖ¨j¨™´Ê„Û\„îAî6Æ™<4Çâg¡’!V©Ó,K±7#kï÷Ã\Ê ¸+KxìªãV·ä1köïÎ!ix¢ ª¾ Š·¨žhÏåEJ/ÔrÀª[è–Ç[ñJ湦OM5LÍÞj™Uu%öR-¾«Ù}1Ér¹ªÛ5޵BŽ%µB(VßæÍ~F:ôù†^þ¡–d’ jˆDñÐßTÒª! ½øR}oêÛh‚O–gÈødÓåù=¹]4í$×z©ã}sʬÙÞKØØZßlT?˜çÿˆ9Me1lÛ)ñ.{“2BXÊŽÓÀ‡fœí!¶Ö˜*5Ñ\ågð'‹ÿ2üΛ=–‹4ð^cY“-.`Œiúza÷Ôü_¿>øé~<ü=Ï¢3x‹À9}Ml°±4ubÑJH@6ÊÖEâÝñJƒÇy¼å^¿>ðW‹écf Û)’Ž©@m,…(/ÚþØ¿Kø«ðuŸ"ŠXצ°Õ,ˆSH6¾ÖÚàa¥‚ùdŽgQÏ? ¿³ZÌ—3?ˆT‹–æ9Up¢q(¬à)Úç}ÎÝñ>qâŸx·Çu>ð~C´ô@%}}[Ú.-¤/ mÞûcŸþ3x§Ãþ#Õ™®bÙTÒW ¨ŽŠ£¨’i;±KÖÞþø»~øú‹Ã´ MSeµKU*™çZ›M*躳_pyú±Rû³üÆN\™ã å_‡~†¿Ä¾ è$ÊRZh#>`ª¶èÄOóGÐA|Wó:jx2º_ÃßMáêzxô¶kšÊ«Q28,aúÙ¬Þ×¶.þ9ñ»×ÖDÕ´9]-JDé‹F+æUÔ-¥šÊ Á"Ûƒë<-‘Í]Ís/ŒŒ®’iÙÙ”.¥'ü£ ±(˜G7l‚º j•úË5d2Åæ­‹{‘Ú÷¹>ûmŠâ-.M‘¤Êëâ0º4E„2lÄntù¹öÇr¦Ë¥PòºYzksÉ·?lTüá”›Ãõë-2T˜£r‚6º S~ Ò1T¢Ó´Fø>\ðcf±ç_ÂÖuž!!#¹);[רâÿ.D’é–ž6APíׂHÁê­Ž O°±¸à[,˜ÑÒøÞÇ––{ÄVk¨(°<ÿ¥ŽÁUG–RR–™ški ¹Õ¦çr{¨SnüY*q|ñg,—,Ì…*´º]ÃÂdbÅЋ©o`Ä[›cŠH8‹r‹©’Ûoé‹âˆ[;&¥P2G*’Çe%v.?ÂX ú“ÛY€dÐo²6­¶k[‡|HpŠ˜5Ñ‹…·,O~ÇúãÍ(¬­©‡ ¥E¯ÆÄ}¿|Na¦Dô‡Om˜Æøös  HŒ \ÜXú‘¿6Å›‘ ²èY s& ÝÀm;ïnû_LMWã¡‰Š„nI:HÛel‘Jï*;€¾ûŽ}¬xmjê²lÁ´ºÄ"«1í¸Ûï%\²ÞšY""Ä^7$6­óþ˜‘DÑ2y(½Ø6ö¾÷µð|Í Ï ¦Vi7W¨i*õµ°;Ž”=XX4M ‹™‰&ûaT‰F©3­KŠ)C«sÍïûàê•‘#I\Ư(d$3ܸ g2ON¡JJU”°½÷ýGl1ÌcXhËHšH([¯¿í‡¤•ð I~*–V.Ö$³dcØzaú…Uq5=`IC3xßnø-¤õúSEÕ+çR¦'q`7ílmGE54‚:³$¯©1‚ Ÿ§ï…±’D0<ÌŒQ/R±2Ø¡Üíþù w°etÔmC#ÔN5‰m-׿zóû`9’)s,++ mê@"ÁÏc±?ùàbjià–7xÔCPïùª\«qp¶Úû¶‡†Ô¹'H)jrÙØ„G8R$p¬„Hö?ÊMÁ=­½¶ÆÈc£¦§¨¤§eè:HÑÌw!läûiÛÛK¨¨”ÔÁ#ôÕQ˜fÖàíʋ؃è1½dÔñÌ'£tÚ-ÿŒXXFÓ¨}vôÂnm Ò||,•&–š¦­Jƒ+yщòÛíý1˜+(z£˜%uTMP‹+ã¸k ‚MîÜöÆa÷(‚¬­• {<‰ªÈ Úÿù/ƱìÈå ]WU{¸î9ÇŠŠÁVVÀê!l9Û“èë,ÒÈY%îtŸå¾ÿµðv·ê_Lñ54Œ¡ü¬î£×Öÿïob7º'RÍsr·;m÷в(“YÕb‡Ø_úca²îÆ×ÚÚ‰ÿæØ•@2%R,J•mÅÎ’·çúã)d%<Á”h±¬IïÛ‹öÇ«u,ÿ*oµÍ¬F7°UÙ÷]JĽñ6™Õ ÜÂnÚ·ÃkãjZ)+]DI!?4…¶²žmô$ }1ìQ¬Ò7 Ü6ÆK’°ß)4SBD# —‘ƒÜ¶ö°ôù¿¯p1>ï°š⥤hb*¬ˆÌ–7R<¶'ìoçV¦fN¤Ž¢(×H°ÕaÞÿSúã%‚¯¡Ô$ôæ!Rék ÈÛü þ¸2“/þ'›n«Ô]¸çÛ¨”oIKК{õ<ÇO•ü‹zX~˜ð­-E,•ІŠ&Ǧä¼ešÿù1&Þšw¶=JzQU$¹}r¤1FÀ®¡¦äúžûáíÒªôˆéFCyÈ7#b/Æ×'$—h©ÇFòNô²õe"GÐn âß\kð–¨MH²Â:‚NåT×ûß ¶Z˜èL³Ë4šÅÖþsµÏ°8Úe¦¬§XÝ¢}lnêÛÄ_í‹P¬ë葞y:Ò½È}tŽÝÿ\"f¢Zä–™”+Ø23lûöôÁÕùe:Ï2¢‰¤›m'¸ÛïrêT›¨±Â5˜ÅäpK\Ÿÿ«öÁ|¡@ëàPë¥Pvb …mÁ¿°·ëí…sUÓ»²-™ÌGmì?®ÉKQ¤’()T–(Ë÷Ü}ð%6Z¹4…¿-È7€.ûöÅ}NÕa”«`QòÚû},o‰¨æžš¡>¢Šì5­¹ãkm ÄÉ–»NNé2¡6uÚöÇÔ`‰<“ÒF›Ü…½†ß×o¯¨À»ì ò^2¬Ê›3ºHÆ6RªpÌÖ—7ï¾,TR~e*TÕÕ6¢lHQ"Öæãê1Oð—†g®™'©‚…Pie†B9`Wu;žGlu?ÄÔµ±f4¢ j$ ÔX"Û Ýˆ,DZ÷û yd“à׋Ÿ!Ù|‹””ÿÂ!•ëF¨¡ ©Ôùl@Üöõ8®IhòY玊Ij¤¼QÄYX–ض˽Ç?\8†läf¿-\/PWOÆÇfrªn” 1€Äi[^öÃɨj`¤¦›5v(ñÈúË©¯óÆê£Êôãƒj¹¶kŒAòlÊ‚‹.Š™YÒ¹€"42tµ #S|Å­Ø q‹QÄç¯ ¤t„X:KIAÚËr_ Ï—eðÔÈ¢'©¨i,¨€@*N÷½ÔXzaîGIK,˜J•r†k¥ÁU$‹•;ïÏñ“Pûd“³RVIÊõS¿Ri º:|ùTž{m†5ÙUlæÔu LÇLõF÷yRI;_qå·¾ È28ÕµC$ò´kj˜*êÁäœY2¶K¦›ÃòÈŠ@’2â%@[Þ÷7Àpî“¡Z® N]á©©žJUÎózó !YÙ sr@[nH¹ë‡ÑduÆ‘cªÊ)âTµDoaÍùkóíÀÃЕeµså•Iʲҋè#Û“ö?| Qâ 2Ê%‡?ËjÝiØ$]EpžûöÀr¶ éƒEᯈJjØkCÁ ùn¢Û€Ä_ôÁ—…–zÀ(sªªDrZYeX° lX —ok`¬£2 •à$Jú— :LÆ„^à}ÿÙÆA–xW+Îdóæ‘`,µÌʃp¿ ‹n;‡ÜØš¸æY]lTRåkYE$‡DŽÌáIqªáEøbNÛ[C–fÔ•ó–Zg}%c©²­¯pI;ž-‹†UU_N½I"zÚP‹¢dóÕ~o½·¿×n-…Yˆ¥Ík*šjy©gVeXj¬ŠJ’./±Ü7ÐŒ L^Jî_â|º·Ä‘åY—^Iiõ ‡Á ºQ‹XÚÖ?û°Oˆ"ZŒ¾ž–Ž»IK3°"Jé`ÜÛaúaõg…rY|Uüfе2Üà§üÊÂö(•û®ãoÄï ærd/ÏÕJ—Ä J¸ÕµÈþ–Ãp€ÈOàåΣÍÍð,µ5JP €†7 o—W¡>Š{á‰òŠJ æ©¢Y Zò¯$1›-µ 9›ýñAÿ‡ßÍ«1ʳ)¤LÎ*b”ÿI%õìûi¦.> ÎZ¢’¯˜+H§¦ÑŸ2¤r\ÛÛm?ùbK„$yìŠ*HM$‘JÝ$¨­ tVRÄ«v´¿>¸§Y‹¼ôfxR6°ê0°'ëôæø3*®¢¦­©Šw OCTd†Q##°”öØsï‡ÂŽU‚±#‹â¥Œë‹ãi.e jeîG®Ø¯—Ébi•¨ršÙežjÚgA8’7–,tÚà›Û¸ãf•.Ôìh¤êL“Z¢–K¦=· ïÞØw.oâ:LèE™R£e•¡žLM‰f>€ ~˜ß6ñ em:½KL+am2ô¡¸"÷¹ßl*iv_(0<ºŠuËÄ$ò^QjvÊþÁ¬vž1í5mõS©©¯¡è“ÐK ßfRw±%lIÚøySG•­ 5= ôò4Ï®¦6PM¾a»\ƒ`9¿;[Œ ñyU5d±õ(ºq•ifŽà-¬çŽñb¦¬W ðŒT•ë ´±ÒÎò4QÓ6>Vc`äôúc|þ‚z,Ѫk+)ºë/Ri/}ô¨öãß òŠÙ¦’:È+"diÄ”ÏM¥@/þnÞkû·¶$tre’TÔI=LæMM$ »lîww톋²6šàØÓÌŸÄ%) É0’4rA×r- *þäzbãÓü]LÒ½UH©…âyZ2dÒM‚Æ-ÆÅvØXv',¦IVÞš8©Þ&H™ÜuÀÜv ±7æÿl m ΩQHñ…Uêuu*'kì1r•Ê-ðZÿ³ºþSx-©UTÓE¤;Ôbäp,O“ŽøyCa›ÓÑ>_KYW5ROÔ!’4ŽÎºQ?ÆìUÉ7A¸¹Þ÷œC-nh^¦Js 0R ‡Ô"ú@¹úž0Gò£ÍëÎ_XðUæsž’ÕÒº˜‘¹Q¹{Üv»Ete–¹gGð‡k E Ï$ïŒ&«ê‡ëN\ë-° ¨ÀXx±·GË3 „B5z›éD°Š1mØ7¶ÜÛØâ©O]Eà,¨†²ê$(ž`ŠB¬J¢ú¤‘ƒÝ…À7ù¬Ñøg §©®­Š/„ps&Ù‹Ë!@w$’EþO|hhªè¶JÐ#¤õU$u^ñ€@[å÷ýð,“Šªw«–6Žp¨ûÒpkLrì³ñ&—2ñ Ff‘TÉÜ\F·6Ó±ï{‹à¿þ"eõ²Ç[*ØfPSDÀ–2¬¤©kv^7à)7°# i>HÓh;ð÷‡«³kü4QÕNJ-B Qe7©-ö¿ 3_TÒe”ù„ê–Ró;j¸$éµ­Æ¡úã\Þ§5—ÂM^•RC-ê%PGæ)r¤;î÷{àßÄù¼/ .YâX¦¨?¦  §wßf=¸ï„’ŒŸdPtM‘þ d41IJÔñ´î®ÒÌ_@ýˆÿÛŠì¿‚™GŠ©³`M ±Z¦+ém¨ºŸK­ÿ\uø‘=m‘’ &ÔxbB“qþøÂ¬ïÆÉžQÃOJ$† ¤é».Ç>ŠnG퉲¸²·emó åH””‰ Ð#ôu³öó)õÜûX2ÓWÏÐõ• U€,¦ö'éb>Øå^#ü?5wËg"D•d¤êËß`§QÿÛˆ¼9 ±¹ø–––¶˜¥@UÔ›éaìA ú6,‚uL \ŸDR³ fFFê:cH[w >Ø‹4¦L‰¢¬ŠZq ÿò½Áîó ínÂþئåÍLP m%m‡P(#ó/Ë!ãPéþø¸å9”OD³hg[-‡M€á¯º’-Ç®"‚ £æÿÆÏ˕Ԯ{•¨™Ý:’"FͨÿŽÖùòíè=qîMžAâÃ'žiᥩ‰6yîÊJ|À•¹÷¸ô¶;‡ŒrªŒÂ‘Ÿ+U4„láE˜nA;XŸ6þØàþ!Ëêi²œÂ™)R†IKË¥lš †Vù b‰Î+á&?Š-k2‚,¯*pÆ f­fŒ£†Ð_Ò÷mð²™ÓÊ8™˜• ‚Üúéýñ5\R†ZIå’0¼ $ÖVÃaņ<¤ŠÇ§óÙ€ÒQ±¾àwk°ÌT¸=’ ’®¦’-:\Ø\ÿ´¾¨ËŸ*YêÊdÐUw6·;ý;bJhš…içi Æ4±á®=;zûášAÒ‚’CŒ¬ À±ÿºœTåÈDpÈ(ô#|¬ï¥@à÷ÛlX²¼‹6´õRCP'3GM0-`†û^ÿËûá4O³|+2õ5ªj"ýûvôû‘ÜáŒUõAš–YzÎFU䆶½@–À_× r’ zÁN!f–¥Ô+²Äk‘m@Ÿ]´Øý0Ã-˺ÌÔ±­¶Ücq].ϸ[ù½Ç¶5`ùU”›¹½­Ïïc‰©o:G+7MA²­¸#ù¾¾Ãlåñ•+$¯vkí¦ê,..{wÁÓÉ© †Ubʃ¨N•QÎÛ[±”t’5\k i¤bײ€ÌmÉ·ÓÒšjÚcT¯ª4zÿ-oü›Xî;úœ2ç ¾³ ©8 µ uÅ ÔÀiöÔ?Ø8ÚI–Š©êfHTYd(¦û›íë±Ñ‹Õ×ÅMcL@¬±EoknÖ¹ÿdBš“9ª9”JÒLЬ«·³{ØvÁjºµDÔæ›ã–E¦EJÝjeÓæc£B‹öµìpË30––9ƒA!æ`l'NŸÞø®f²;9™`Xu»µÈ$½Ç°l´Î+RžJi;‰?'™¬æ;ño¦²·Ø·0Ìkji SÕ°¤X©Œ(Õm*M·ÒŸaî1£=4³UÔÆ°„êÀHB.[Žq#åo™WSå¤uŸ°²£o&¥òñ°®oïc°ÇBéEI™Óœ’*/Ч òÔ6TÙXÚáØP6‘{- ã6ZM מgbÁ5oÿ§jüµ(|9QÒȓȯU+°°mm`þ÷úá^i–æQghÓkJ˜Ô¼Ž¯§R›ä-É;‡Ö)ëói¾*®G]I 3ɳªÀõkmc‚Я‚,Ç-žXŒÑÇ<ŒªfÖ·J€í~0’Å$´Ñ'S!1éeQü‰ûbó5>fÔïL±¬ L"ZCk^–6Ĺ„äñ U;<”ôôÔÒI jWÊ@õØÛ‹á%(Å[ `çÑ]Êr*ßÕ¬4-L¢572\݈º¨¶ûnvÇGðWáÆK rÖg¯%UYœ+,P ÜÚæýùã¤ÊPÒSÁOHŠ(ËŒ¬Bnå‚›jç××f™|ô4Ô4/0ª•ŒI„ÊÑ.X°½»úc²9ônÅ‚)«Mᬪ)JÍ–Ã4€IQ•-€_æ>¾‡|A>º!–äÑÑEqÆ–d=XÅÅÀþPwôãÑÐÉOS)Ÿâ?ˆ2*å”»7©…úbÏáú)Ó\õU OmG@‡P}¬5‘kßžN)kÜÒ¢®¢S©ò2êê™ìôÑ‹=D2Úc#°º)µ·ä[×WQÃVO R& Ó­ìštùÜ)ÚÀpCÕÒOo%+´wwŠ71‰.-©‰íÎÃ}ñ>UFÕ1ˆÒ¾Bµ;H (ÙÛµ”snp–˜û+³Xi+¾)¥E©x¾XD,H«¹bOâÀûá…,‘­ešOn0wŠó¬ÃÃþ–¶Wƒ1…7/£Ì¡çro<5âü¿Å^š¿* rBXä@¯mÀämÏ¥±k6…ÝKžŽKøÏœf™e&a•ÁSÃÓ)*ä¢06Ô7±§n;bÙø{øƒI⬞š<êZJŠ•môDêê·<‚~ÛzaŸŠ|=–xŸÂ­O]W²TŤ wYAßìEÁÇ$ð§ƒ`ðž\+ 5J7\ÁQÔr%BnÉ Œ\2ßnn;ŒY½Uå‹sN!¾/ðòä_ˆßÇrYéŸ/QñÓ A•¬ÚZ;ÜFÇìqŸŒ,>§Î²EIš)ä$­sÆÚFµÿÛŽ™—øG-­ðäsNòšéè&’4·ÎæìH[ËÞ×aŽãß øªŸðò ¢L–°Åy:î ¹„’l„•]6µÀ°ÅK,T’b,øå)+*ÙßÄ<;\ÒÁP%–˜ÓIï"¡6ت‘~Ûc£ø/Æœ ¦Š£âªž–?†Y嘽®Çp8Øú}1Ê<%AW ~] ?,nýI&S­›™•ôÔÖÚûoŽ»C›,*éSE `JIll<Ú‘†àð8õÃNTè³8äóÃÝeLfJá¢s©c©M-¥–à+@*uÆÜvÁ™VqšNñԯóR»G<š‚¡rJíéß +3¿S,“UT ÈU":c¿–ûm{…ç“|_òlƒ(Ï<;”Wf2K\Ò£É!b¨¤³ b6"ø¢Rvɩɋ“å•üå**蟥1YD€#²ï¾÷ú i‘P,Íñº¥¹Pöô±ãGÊ’ÌÑçWfQ°ÒúùæÜûàLÏ;‡*ƒ„ÕÓ-,@r½‡|dÑæ“ÆßÌÃà³ópI¿FW5‡|1Yðq²õªâ°F:˜’¢Ûû)ýN6ñÔ™vW_”­3OÃþEÀfVÔo#{ ö¶gµ VrH–ÓÈk¤üªƒö¹"þø¸xÇ/§©©JŠŠQRV#›_bIàokž×Æ 6¦sÕ9?W_ØÇ¢›Éª”½Û_دÁÇ•ÿ-‰[•ŒX°$âH¼A"e“e9–UZQ_TÂäÜ_Ët#­·®ößS@Y0ÿŠÄ•õØ\ðyÀÓ×ÓJJš‰A¦™¡)ÜŽÅX[o5÷ã á|kr¿¨t*µ™¬M’æô’fòeÓ)ÿ—[MÉi¬™o·ÿ bj깡¯Žêj –8Ú0U÷ú¿L8‡Â4kZ™Õ=\ІÑÉmCPÌžþ¢ö&ø& ™j²É¢ŠA(‚K´òÆQÁÐN~–oNÜã½t‘ÞnŠNR³G/ÃÍÒIަ–V+ªúNÃ`{î-Üàè)3YZ*)k(å^†v‹¤ÞafŒŽÀ0b ãÓê!ª†/Jš [jUš'ób5_e¿›ÓÕ>\YrÚeŠ@Fࣀ·õí„ó>7ìgY›ÊÒé~ÐÉ3LùY**%C7Uw.,O>i, ¹Ð§f¤¬øf£©Ë)ê´­bÈ:ÉmGV– +yóŽâQO.Z*.–™ÉŒé×§kX‰‰?lV³餢y<$”¨‹×{\|ßlW‹&ïÔ]^G,’õä9ÇäÔS|®C*ÓÇ¥¯…€»Ü.Ö²íÆ)Ÿˆ³Õ¥ÖTSQTJˆd¦E ‚Ì Ü±ãù¶÷Ū’¿#ø¸éŸ>¢jÛÚ(tM½É(Eíac¸ÞøKãL¾Ž*7©£y§™#صõ.ÌÃçäÛlhMZ4ÆÜ öQ—ÃiÄÌòÕ©ê’Ç(ÔØ\Nq µ‹Lg¦œ¨–¡nˆÇQ°>q¯¶dô´ëIfV©©a4ì²^8õ0(½ïb.7îG$‘GX”¹dtrÏL$U# ¥IV‘œÛåµµ}­‡\²§ÇÔTõ´9ïÁÐKÓÏÖÂ5»+„m¶ÒÅSWL"˪VV¦iA¡°½…‰°Üíéßhék!©’¶,Æ)§k)3Ñ;3ž<ÀØ×Û‹›`ì²8¨’I«iÚ:‘¹_1á­Í­¾ý°ñjèdZ"¤®šHg¬ÐzÑ¡çÐÛIµ¼·;?ŸÃ ˆÑÓŠ: ÀU€Ôb@nëÆÇß°Âß ×eRÁ$Ù¦rÕÕV¬‹®8Öü7ïkáÄ ÊÑSÒ¼tsÔ*¢Jà,9·òÞäØÛ‘€¥m úYƒHÔÐ%#K‰>…ºˆ7°î9Â|Ï/54SÑ=c»HƒP€èƒ"¾ƒcµ´·mÎ-Ù•-NgMZñK)ꔨx­Å€^ÝØM±&g“üBd³åQHÍ“RÔ–ü+-¤RÁ. µZ÷Ü®öØ€§nàÊT£>™Í‰§P² T(;½½»b\‚Ÿ3˨ڻ8øùêŠ4°Qƒ§I7mÙ$O$Ûl]<²Œ[lŠmœ¿)ʳX¼$Õy¤mCUšT´tTßY„qY^R>@5ÖÛÝn ŽÕðÙ3ÓeU©_—E×ÕcWOMü€¶–'­ÉóœÎz¼=]Y5%CRB^0”㦳êÕvRnmÉ*qSͪ£Eu¨šºZJ… ¦_ÍÔ,,§˜¢‚6'Üâœs”–æÄ„mX‡Ãy¼ –T=e|U’<‰p¡H[ƒ #{8£Z̪ˆåRåµñ‡‚©ÐDõ*¬¾BA<ùdu /akãŸç^ƒ(¡©¬£ª\º\È<€±a:éÒ [–Ô×X•ôÃ=Ì«f>t’AYM¤,“±G@ÀbâÒ+!¹µôß{cBjJÉ>8ƒÁµþI%’«ã༲OÇTŒ®ÊQAþoçÜv¶å™©?IJ|³­§¥”ìXÿ5¹¹Ûµ½qÑ)h —ÃP|sõégŒS´ÐHHö*EÇ®÷¶)þ3àßÕx{6wª£rjhjjêÀNÄÜ|ë¸#Þø ½Å{ äÉóIêV¾ŠYij!OÍ…¾W· {ÛПåúánsI4…ª…:´M"‡Ó}Q°;ŽÃŽ1רéV°´ùq3®¸Õ’Ä)é·sÏöÚØE˜ÐÐjyÕ 8w),V6€&þ¸Ø“÷)”iœú*z¸ké$ˆÃ/æ"‚T+Λì½½xǹÕut1Ùc˜¸rt8¸Üÿˆn ¶°Ã?N´O UP¬qÎLqOº,¨n5v B‹{yŒÜ¢µ.‰Ô&E#X[GnOëC)ì‹—°6ñ`³ÕVfm–ÒVÈVY%U–>§Ê¦MÔXî¯sØý°ƒñEDuÌPG ‰'™eÿˆ7Úüóßß Ò¤¾5¦i@µ<’ÔÊá#¸?kÛõÇ6ñµ%nrõù5–y…L2ZHÕó¯qs`{öÇG)eÏ)7ÁÎÑÎO,ß§' Î)æYja¨Ó õ¯"žUoa¿Üc#–ž¡+Ó$>­DnŽ×ô6®Ü’ σŒîy£©Žµ¦]ØT€EÁÞú¤)"ìÊK(×ÒØì®³^à·*BôË´²²¸ìï¶þøeYPeb:æ]1-p4óû.ЃO!–W˜\ùd–Sc¿6¶ÇŒ:‚:zXÌ•²I$êL}ûÿ5ïsæ}ý0³»AO†-®§¦TZy ‘JXÕV±‚n8°µÅö'èJ`ó1´G,¡Ò”ù7;CÍðZ-)Œª]µ¢‹Ï)bÊ¡¥ÆÄ`!4rÔÚË ¢ËºêæçÛw¢"d‰ J 󨱒N”4Øþ/-¸õ3,¬JÚ*µž®ÄÊЬsgxÍ‹väŸÛ­¢ËgÊZ(ê#Ò@“²°&ã{£ôÄôT±£"å°–@Ê®G ¨ÞKÞÝí}°-Œ¨n–YUMO,J%Ø·”‘rm‹ýp>|‘CE23 V-ëý`;~ƒJ¦¢–U„B9ÌË¢R ]¯sÍ·¢ßLn¹ä”ËOL´qUR+3Ç ¶²»¶’ã‹}íÎO²ÕïXÄ-!Œ)[½‰¿#m±½L”Ö‰¨ê5ͽˆ$pO{qq‚3*pf–9ŧ[¼HÏÂ1$®ÛÜo±Âú¥q/V8íÓEE!n, B1mª ÀMO%2ÆÑ¬îÀ¤Ä’6Ô'êq-/À|$³T¬ƨÐÿÓ'‹}y·¾3+ –¢0+Z'Q¥‰±î9#o\™iªXÄ= DÐom;s¿s¸ÄRˆÍpA/^ñªÄ,>€ðA=û[× çŠªj+-®’&»Þß[aÜ“,QE ;Ë##^ò]Gókí¸±ß{ñ„Ó‰V®jŠxuÁ))¤žàÅÎû oÛУܽé˜)’T]µ2«i™¶eíúƒŒÂASQ|r¡Hº nú$A{mëŒÄrcïhKÊÕ±ò‹_þq«(ÖÄ0@%É÷IJtQÜèI 6 tŽënoê=ˆÆ¦12©ÒYnÞÛïƒwÁqàafѨZÂöcÍ *=µÖ}ûñ³³ M¥Ž£¨jS{öÖ5g•›Y Iõn-éÀÁª¨S"«+ß[ÙG$wÃJ>´ŠóÏ¥c󼓵…° mñ-PÅÀ-†ýÑ¡êHºH¢Ãͨ}~÷ÀJÁl,É$RÍR’Kʲ-Á`ÑÉQEKfUW6¶£¿;°ÿcTRËR]`óME¾‘{oúáŽd•0eÔÝ"±Èñˆa`t°vp/è-ï놪 ìÌ’yé´MFTTÈT¡[‡Rn}{ó‡•zÕ¦šF©…%–)7Eˆ»”X(ûàÂf£¥9VSG”Fcj¶±ab—P{ > á5%%DyµP‰§ÒBiä¾Ä5ŠßÝBŒ2÷@h—øƒÖËIENÑË$ÃQ²(bÍßs¾&ÍR¾jØ©#ÍRZ UUù,¨ÎH(>P¿8“Å®²šz,½Œ"e´E´ô÷"8ÉãUÎßka~Cæ¾®ŽŽtªJ©ÅÓ¸‘s¥»bXbü0 xs*¼ò¶£«5ă;J<ÄܯÔâÙU-ã™h`2©Ìih†š} ½Ï=¸À O—äEÖ£‹.hcÖt·æ8ÿ5‰£òšº[444îRÿ0Ët¶ÖÒ ¹ý±Nl»xFŒXw?ˆ£(zxô,p>L—¸$“½÷ÞÆüm‹o€òáBŸ™PÇf;Ç+` ò¨ª ÛÖÜŒ) ¢¦þ#MO²ôà_4Ͻ{^Äú[Ÿq‹”UÔµR$Ô´LÂ=ˆ@jAÇéýqΔœŸfÅŽ1iEËlÍ 4bZx‡QL“1Te<|¥t‹l·Æµ©i¢…‹3«¶¦I ¨Þ÷éß¾å°Ï[A::0©‡e´µìCX¶øÖµ©á),Q¢=‡QÃ#}{¦3Ï.ÞPÃl‚ (‘$¤jã-銃ÿXØ]¯M†ÃMJ¹LpÏ=4lùj\¨Q¶-ϧÛsjœÑ£X §ãT@Å/ÁÕ{ÛQÓg•N ¨J5qF¦z…’ѪÇî«v$ߋ۹õÂù|3á: ÏN+yP”– âè, ê½‚“ÞöûŠ,߆ÓÒx¡«ò&‡R j!©s$E[o;óªÀ“íkbý•øVžL‚§0Ì3ÚÊö dŽJRöÜÆ‘¶Öçw&Rœ£ô!¢ð,9&WUUÕu€cYtɪˆgóp;_ø2ž¼Ôÿ£…ic #†Á!Šû»·$ÛHQß¿ çôPF2ú‰+¦ÿ¦“ ="Ëó*ßµøÚ×ÂïÕåž"¢•£Ÿ/eŒÓ€Wf±[.÷ç¢2“l°e>É!™³x zz—R½WÙT^ûú~ØÄL_—d¬„z@q$v¸);zbµ–RÏ[“VÉün­ƒ†H ê£ÞÀùQwô'ÛžöÆÞÊf‹ ­Ëjhó!%„‹RL®äÞâ;Xƒ~\ì8í‹qÂ2ù§º òX¾>?äRÒMá|ÖŠvWŒ|e?L)•Á ‚wr)^ðŠü!“ÕÉÑæ}xÊ Ñ«Ä׃¹k²Øí‹oáa–ѪÕÍ[M ¢ ‰Y‰(±bwbÖ· a|^ªc•áéÃ"£‹2êÛýq¥â}™V_Jõ>`˧ÏÏâ%DòÐÓ&[JU¥3( ¢6çe 5É펒iÒ†¶g¨ †Wª£ë„ËçR,A[’œ\a}Î<ʼ+[Mø—šIK5¹téÕÒIè›Z¬7'F;Ž ±í„?‰ù¾oÿ®Z/ÅPFINõf ¤¤RMhͲä&÷Ó½…Û 6i·¾æì­øÊZ¬Û?’º†¢nŒ,i‰™#:C‹p5$ñϦ)yõ>qñ2DkeZ"|öƒ€CZÇÆÈó?ÔFPU)¹öÅŠ“,Ëë#†Y¤§—-™RÝH‹þ¤n{cN,Oiöu´¸Ô1(®NwáÊŠ\¢hÇÀËVCydFªçn9&äàSTfÙt’A•fôÊ fAsÈQ×< tæÊ²\²’¦Þ¢j†:…KȾS½ˆúq„>,’ª–š5®­ ŽÈË¡fN;›ƒq¹·‹*Ÿ ô YqæmGÓ†qzì²®<žz”š”j+2‹Jö![‹‘s¹Ç™] "¢—8£¦YIˆÏ!fkrGr4Ø >übÇå1×M[ZðU¿U´jÉ` ÊÜúmÆSå²Õ~øƒÅ9ÅCM6[V™f_$zIžY´†BÉ©7?̧½Æ4â“|12TyAYOZJTŽªžAANÝ3ÑRÞfòà°·qßêËÖªz̾šžk‹™¥caºØw€q|P)ç«§CCD­$bpÆ5 N‚,Y¯üàƒ¿¶.S³À(â§Jjt˜tŒ‘ ¬’,=ÉS©¾¸¹¤º;dLdZ‘DiVyF—„¢ß@ùXŽMÉö8g”2먪Ý&ajWgxñõNÖBy`n6ôÂhòég¯/§—®#XB3ùK07¬/bGÚø´ Ñe”Ô035Fa$ê%9)Ô®„¿#{’{ñm†2êµ0Ã_Äý zÝJÉۡ¯†ë©èRŽŽS^wW]tÁš÷ósˆsÌŸø‡ž«,ñ ϺúúÍb¢”)‰­ky…탪aÊçñ@ƒ3øU¦§X¢EÔD¥Ÿ–ÜX˜÷ão\0ñ†]$^øXR91jE•Kúعÿ.&žK:k²6E8Ë·OñÉVrI©åþ3;Ä dF¬îXÎI\Þݰ枦¦j±UU$5R‡†#NÈ%€v°S]΋_“*’oXÌL*Ä­r;°o°¶&¨›2¢ðõCAP‚¥5µ;É>¾¤§å%šÖ{ÇlLÚÇõttµË…÷n…§Žiª)ê3òŠ:$œ/JšºÒjÙ¬NǵÇ$_Úèü]YA’×KS=.o™Já]é¡!• ³¶¥¹Ò ¸ÛÍcþ²ð$~9e¨—6®¡£ŽsÕó’¡eÛm@j(A‘ÍŸÄ®_âž±Ž,Âò´E «ˆõ€ }D7±'IÔÖ>˜º1Ù}RT…ô™7„óêJz4ÊÒl®°‰å=p¦1$vWa{«\F j9žøÓÂþ—+Ë—%Ïê¡Î%‰D´ì𢙣ŽÌL— Ùxµ€½±,°ç™Å¹6{AiY,pÓUê꤄° ä$ƒ{\l4œ>‚ƒÄ¾Ëê&ªø¬ú¢•U£–8´HBì«e¹Úäâô•M"oÔÅK–V@¹ƒÏ%‰16˜˜÷ÐÛbI¶Ö]ø‰AW˜xR*ì–š®ŠA&)iìƒÜ|>SüQs(#Ž’ºU0TÇ'óØyoý/í†9ŠJ”j©¡ ±ê]wtÿ¾Öű“i ’<‘PM•WS2µ*Éýh°,¦Ö'±ކà "£È[(z˜²Há$Fë3²‘{0'Ö÷¶ÓÓQ”5ÔQ²ÉZ3æòµ6û¨ûaöt>)¨T`ž™ŠÖþƒwÅuÓŒœbø8Í^E9Fƒ›x[­$Ùýy*$ZhèÕ˜|Ï3Ý€ÿÅ7·ø±UüQ–: ‚®8ó“SẌÉr5îTnì=xÅ×ÃqMáø'œˆÚj¹+‘ÃXêò×ÚÄùãñÇÄU‡ˆ$zVN­¢­!›íØ‹¯¥·Æ¿ ƒþ3õfv`úœæ¾)u¤ãJsÓu`Ûm¦ÖäX6ãÒ…ê|AÒà£G}dMîEÅn0"WAQ5J zÄkÒìXØìǸ›áœÎ5©»HHòÍíÏ; ±ÛrF– A k54µ¬X‚Ô“p¼“þýp] 1ž¢9ãi²Û·ßs´Ÿ—Òd“g:»óßœK ®ŒÄk¾‚• ûþ¸®Ÿ b×±ä4TÐʉ-ГÓG¹* Ÿ×ŒG.Q8¬0¦™ä…D'å¶ãcq¿ÞØ¥5D®‡Ri u-ØsÛÔì1>_$⥵±R²ûؽ·Â{¢Èíí‘fðCÒ…V^ŒÅÉ–× ›a·?Bq ³ÐÑÓCMUP³’ÂhÜ †ä<‹à꺞²&¢ä°,Q£· O©7ÿBp4æ9Äj ‹¥nt ´·¥¸ç â‡b|ØV[’ÀVÐL+‘d¾ êmGn (íTuÂÑÔIh¸#I÷°Û·×¤“F“T1L‘’@|ºˆïmCÓŒQ=4s¯Ä ÔÃÄnuA°ÜlA¸#Ø`òнtÄ™âx@iMõ, ˜ÈÕ§Iú¤÷Ò$”Ízþ€v@Ò6»)'b>ÂÂØabT¬¤ ,le#æÞ×÷o°µÅŽøÊZ•jš†7«ÏMQ9ŽIM­xïÏs¿a÷ÁmÁ ù‰.Ai…ZÓ‰c‡S‘qÒ>CaÅŽü[@+™’ŽjfÝ•‘cÉ6ˆs‹QáI S×ç1Ųè†:ÈžOÌÕ •Ûeí~.m|OCÅEZ>"*š,Ò¢55=dº–­8ò7 v<‚/mÆJ“²·™{•JªÝê ŠL¢ª™¥%â`\ ‰‚ux¶ñM¡ã¥øÈJ%?j…O1!MìlH^üâÃâŒË<¦¥" Ý J@=6sJæTÜÛcqÛsÀ¶9ä4tÒÖ´sf1$÷Ò†xKz ‹Ûùyõ¸³µc'¹¦ƒ²Ü½*ª™+(£.”-(@ÈQ{‘¹þaŒÀõ™lAŠHžÊÍ€Ž˜¹ÖºÜ ØvÆbí¥©7ÐT©!R2ÊÉp@ÜoÛê?_\xÊbUus¥ÍÉö7µøØa“,€ª«žm­{íÍÿli-2éU0±Sù€.êØOµÉu L‹¾²ª €ê·;vDzO¨î6a¤Ûp,?¾Ÿ/ŸCH©*¢ ,8$ú}­#£hB¼‹¤sa¨·©˜–ýB£DÑSé sk°ã¶'¥/6˜éßSÀQ}Ç8ÚY¡U*°UIU$HzÓFN”—:¹&݈ãù-4”B¬Uæ7¦y<Š{X¸Û¾Ö¹Ëë I+3nCX›žÀ{ÛôÁ†Ér\³%Â*¾ †Ë~¦®XÕ¤e”Lör×ìn.,Mí‹tU"åÚ¡hé‹XHÑŧXæ+sé±ÂÀñJÒÒÉ,I*µ›arøÁtó/ÀQÒ¾s¥šôãs¤ÎÞ¸ççO¤kÂ÷ Ùîv‚·%ª¢¥¦–C’U;‰T)±"56×¶¦l%*?‹ÔÇ>aK[3´,âQ&“¦ä Û\tßÃé ‹Â‘ÕÆ§¦:Òµ†æÎ×þ˜åð¾c[AÂ*EiêŠàî{sŒk"É®C¢Í,¹eô¸Òf¹|×§’ž‹®¦ñ‘+$‚Ç€G8 ¾†¦£0dC}OÔü‰Ë›{úlI$•] ×1Ëh€@«LePíq³†æø'3¦ÍòšþZ‘FÃI”FK\‹\ ÷ ñ86&Ÿ ·ÃTÕ&Š®©êRäõFöæÀßËϦ+™·ƒ©(&’«/ÍÚyKu'èÕ–k| 3(÷ ¹<¦74ùí%E:fÔ1¼÷iØÀÒ'þL ›oÆxŽ—Ä0ED‹W TBx§ZJ ©1Ù€g?1çkÛaŰñÝt$©–ð¹„YDÏ=Jш£yZÌHmV:@Ûe$í{ê÷Ç39n{t³-;Î$ÉPkI`¤ ßMÂùG Xâç”ø®¯ ¢Ít×fµà=X‰Y £Œ7äÃ{nXÆàw>cÛ{fe—¦c;DÊ#Hñ¨y4 ä³^à mÛŽØv²G¢¸ÍK†(UŸÅ9ÈCÊëW­,³µšÝØ‹‹lÄmË—ä MÂÑÁNÇâ*.BÉ}§sɹïc‚s¨ü5—A–UæJÓÕ–)OLžjƒk%nT îEË †,> ¯ ‘J´©¡tÚv¹ n…À;úŒ<o’¬’Qç?…Y?ˆW5®¨šÖYžÿ=A)Ò;ˆ€^âÖ¹þ˜êÞȲú8êz–êy¤«m˜éáA±ï±ÅcÇ5teoMVhªUZW^0H\.›±±°oŽsø/™æ¹¯ˆþ38ñ>cÐ>[LÂ3PâÆä ô‹Ø¹·-`@× »f<ùZ§@üZñ_‡(Ö/ e”‚¹¤éÓÝDQ—m€ÕÈ-ÅÔ}ûb_Á<ò ê§3zXb¨èôãªÌ–™£ @ª é¸$ðFÂø´WäÑæÕ”“æY \!ºq£)A{rÁ-}½nûvå^ñfEà¿Ux_4¡ª Ž M)¨š¢z‡‘”»´J ]‡aaípĮ̙r6•tmø²3l—ñ2‚JL¶ˆP´o&_ðå¦J©4•üÖ´± ìov;v<ަ¦²‹¦ëO=6¨bÚäpt’·åM‰Õs{ƒÞøªxâ ÚÿøU)ro©f©”’ëvk0$°@</qv—Dšòä’Heé‰ãV]¹ ÅÉkß×:¤#~¢ÁCK“e“EµI,f}4êKtÖ䩵Ë3gmÍÈ¢øÖ®,·$ª†¡ÄuÖ¯xäoÊc§Bf¸@·^ú¨¿CÏa£zZ§3vˆÇ=D‰óiC«ö›cæ¯A˜x2¦ñu(‚µë¦z”ÍfÙx (m…ŽÛb¹ÔSêm!¥3æ#<ʨóJ=]+ΕIEƒ(%E¹;©Çb”L”4rTÆñH^˜²¹Ü¢|P3íG=§Ì&c+ ”üÀÖÒ¥Öö첬7Ûa‹ýty*DhÎðFXâà†ý1ãøÇ©Ï™1ÒáYÉÔê|÷û7ùU‘šäÝ4©ŽXç©Uˆ£h³4Ž›÷€¢áÕ,¼I”ÑÅ~y˜0&úcé®ÿÿ2ÿQ턞d®£¤šHV¦X›«XÉ=@η›­Úþ—Ãß Ig•±Ê·ž(#‘äÔ „ŒÅSbxê¿}ciuyaíl£6I.“t-üGÉëóßeBƒ0J)ãª&–.¢j- oRºŽäpqåeFUšUÐÒÎÐÁ =0%ÜØw>ApÃ{nG¦DíS4ˆI·T¶÷¿ï{}1ȳÿMlÙ›TT Š—Ö ÅÆÊר,-Æ:øusj»gCµRÍ~Ñ/5.+) 2Kyf¼2B,ÚH%KX؆½øôÅb§Ãé(Z©³Jƒ#&(‘c¾Ào!$’=6kálΧ=ð÷ñ  ’–^¼þ`ä(³z[ÍÛm­Šï|3>mI#Òæ2Ç.¢u5››Xîq‹ ¬¹WÌÑáÓ^nuÿèš§%z,Š»-§ÔÔG\°S­Œ‹fr\n™I°¶ê;a/ã5/†ÿü-áJz9*ÊùkªuXÈŸÎÛa,ªo~#öÅ“ðCÃTãÀsGUÏ$«›Õ¼« R8õXrŒ‘b÷çþ7TeÙ¶w.AY›,¥Té¨+8ÔKz ¿¨Æèjbò8Á’MgÍ'ÕœŽFj¡ ÒTÕÖ=(‘#”j°ÓÔ,lAXýñÐü!]5fT*ä ,Ñi"rçÊt!vÓ½Ï×ï|µ´?‡Þ8¦i™LJtééµd•Hf¯%·°'ŒT<.j)³•Êæ†Xcu"Dp5ì¬ûòǃÁí¾ØØ²)ð»CãÊ¥-´u ÙäÊÍGU%Yã2¨Ý܉ !Ü}ýŽ:…F£Ä£H\}Øÿ[žqÎ2iÄ544ŠÚ¦žµFUºÜÖ¹öîyÇE ¯j:|ß1tWz(Œp­¾vk[û’£ï9â‘ݮŸ³8þ5 ùñÁ•lÆxŠgì‹%Hi%hØÚ– áW݆•;Øm‹í\õþÊ&y#–¦²Ž95°²»´$†#ÜØã—Í”f5™7Áè³ Aê }lÀ-÷÷'O1’Ž ˆòúp‘ŠxD”è¼*'–À{鎾I8½KüQ¬0‚hä^ ?ˆ¹—ˆ*¤žWøùÑZÖE G7çS'Ë'¥ËÔSg,¦IšJÂw6Òµ¸Çúâ ꦕDu’ÕCOE*TG#3žíæ"÷ÚßCˆ¼_áŸýKYaª4©bZ&C}‚éÿ ±ÜásåRɇ»·÷/òlœÞGŠ?yZñãxš²…ÆMQĵ'¨ðÓÊ ¥¶Ð5ZÁy7äÞØcà™óŠt3*殨j’ É ÃÊ"ÆàÛ¿®*TõYC[7ò£0BïWFá×b@}ôìw÷Å¿ÃIOáj(å™'všI ‹&µ`d$}-oéŽ_üG›,4—ÓlÍâ²ò´êQ|(³z3e¤ž¢š’UA ¯Ó•`Hµ¿Ä1îWIšÉšRf2×ÑUÔE4åþEÐÄŸ{mþÁÁYW‡rÌÆ¾’|Ζ jAYJ–µ‘1¨ú\_ÓÂáx)²Ø]¦”<¦ëæ"û­‡c¦Ê~·Ç¡ðùOÈ„§ÛHÑ…îÄ›î‘d¨‚)¢SBZÕv7{±ç¾*~*X¢ž Ög.†4WÓäšÇcîTØ=0Ë'̨ãÊb.…$D‘–AÌäÏfþ`ãíé…™šÔIZ“3Æ” æ’Íÿ$}õ¾Ç~øê¼vVîìQⲺù5q#!´±Ž“s¸÷:¾‡Ûøb—2©Ë3|²¿]t(¢HHüÅ êßÜþ˜Ÿ9‰)sï!ºìÄ‹^ݵ Ôð1Z¢’FŠ*é)V¥¤Iõ­N‹uî-¼Š¶æý±ƒ>o*2’&|ž^'"ËQG•Э->½M4Œ :®à7?RIû UŽ*³,«ø5EK_]ŸˆŠp€5¼¤ƒÆÀ 4¬ñ-ø9£ËúµÕš¢XÍã…•Ø÷ùÉ¿}öÇ4¥i!ÏKÆì¦8ui½þã3Pç’kæyš”¥mwÉѳùá‡Á‰—PKtt”j•M ‹xÝÿÎl7f#ËcäoÄ9>dÔµðKçu×ÙÕÁ!H½­õ¹žû}⠤˿Z…à†¢©|Ê7 $Ф“*5€Õ§k†#b/Ÿ|-xz,ó*ªLΗ8ËÓ0Ëê /²0S$M¯ÌÅurÄ8Üg ŽÌ1‹àìâ·Š%M;,ÀÄáÑ€1Ëk¯¡ÁÑÕ»RXªÜꡱØð¾å)ÄM½ÀÍqm­÷e™åÎW—å5Ùž[=%s Ÿ.š`Íb¬@ç›r7±6ñe´û 5’ËÃDG¤|Ì×m7<L@Ù‹ÄEK¤ ÍpNÄX÷Æù…³ÂôT¹¿¼k[0’:Ü®šŠª’[µGNEp;0e7‚»sŠä••«•‹l\€.vÛß/ÃRdðçâ6V¥eð¿Ä %ÏäÕÀIûÇ 2̲‚¦‘…UM}3¡Ô =:9Óm$Íþ튷ԥ~ëò$c¹½]RÔEUš5[úü¤­ý,H¿¾5ˆg¹Ô£çre=ý/†ð?„(©'‡«›WÊ„œÅJ•Y‚ê{É;m{vÁT”™Zæq*ªëi«%e‘d§"ŒNÂÛ\ûbÄíô2ƒ=ȼ=šçrÑSÓô\ÊgŒ Ùúk.’\µìPÞÖ·8iâÏïøfxFk”OUN[O ©f*c½Å‡løKâÈ3:ª·*2-Ay$ŠFH޽!Aì¦Çî3C‘GD2¼Ò®ª·¤¡ã¦ªh ‰RífC»±µ¯`-a¾*k›Lx8.¹e>cšfˆ¹5ucAP©6¥Ñ+qrì6P|Çï‰i¥È ×9ž )$0.*œ\0V䇷Óg~2Ï|UKSE˜VS¤Ë¥¡G}¯·+µ­aýñZñ{¦UMMŽš˜‚àÄW\€±âö!HÞÛï{a'‡|{)ËÎ4މøKRåµÂ*ü‡¡Lу YŠæE,@bOøŽøCøÅ˜ÔÖxž<×3¤ª¥ |5r02"!ÜÞ×ó-Š^aš¾c4Ó|]U:T‚¯Ý(ØØÜ±ǃë°Áðç ¾ëĦ޼ û«H¢×Ü’¶c{m‹ž•ðÛáÿ·Zè²Ðf-˜kks(i#x¡“7Ž2òQµ¬xź‘1ÞàjüÖÒøæƒ5ðæG•ÿêSY%cê’£2KOKWŽ:+ ‹et²m™K6×bŸ›xªžªaYKM¾Q6SZt·6’™ÏÈêA ¾Ÿåc¨jXR\Å¥Ê\ºÅÌV¯/ª¢Š†zZµhÚPšúRu$—à!·ýÆbùŸ~eÑFž/ðtY ÕÕH*dó6$7÷ÇDÊr<œ/Çå¢y ‰4ê"5…×`A?|_ü-á7¢š:¬¶%£€ûI†B:ÛlU¯¨¯X|Z"Êò*è©£ñLú‹‚ÓhÌl7¹÷Úç¶+©I®Å¹=L¾"Ée× p§Q]'*ãa°@?­°ûðöy'­¨Ëó IêàŽNËr{o{qíƒ(|6S?\Ç.«žÈ˜)†Ö¿ÔbýECM_Å:B’2ð—¾þÝð#‰§ažN(†¢Ž¥c,4ðîV07°ì~ãï|qÿÏ f‰,÷‰ŒšUÍÎ) ývÇY̳‚iËC ,S~Z°ÞïoíÎ8¿_1‡9h£T”Ý^-€Û’ìNÖ¸?A{ª<‰Š-C˜ËœSÒ»QÏQ q<ÅQˆáÆ“û 2¨jÊøb¦©Ž%=O*Ñô½Î×Þø]–åt¹|rÓ§FE9‘fbnF“ô¨±dÙ}R;×ç”4³ZánŽÖé‘cõ'ûcªžçÁÑÓü ä[üMá\±ANéW}8Øy Émïk\ú⫝̸xoÆ9µ!)5===„…\mÞÀß$zH<ªˆ^™VE]F÷È'÷Åƾ\ã0M,°Ç ¤ËS,}Py]Z€ÛµíŒZxðÓ*ÑËù’kŽJŒÞ¨É¡‚óÄ5RüÎêˆZ2òßp?¸çô£†—%J¬ž«3«‡Kã#ºuá¹_Ó¶ LƒÄ.‘Ò"£å°Ž*Ž£=LV¶öÜIÉò°ûŒVóL‡Ç4™…?Âæ9Ä”’•J¨ÙmeÖpÀŒØp¿¨ÅÒƒ4F|ªeC9ÿÓã¾{S,ÕB@ž•™‚³¦àƒmírA'~غxV_0©*®¬Ì³9s4´ä‹ Ĩl¹KܤKCPfl¢_5k(•or\*4Øw t­,*ê, <²nxÔ7ÿ~ØATÔÙ·‰|;âl²qŠŸ55ÔÓe’ ®š˜ËJ§¦®½‰<ö8ã^8EËi)éd™^¡*kyÙ‹êE‘w>š‰~Û[ÉjaŽ âv—·ÌëcÏáq6u ›<É*Ò–xäxÀ:n6ßÓoÓ| QdsUEEÑ(I¥m7°$îvüvÀÞ¨þ'à<º¥è–¦o„$ ›=¶b/Íþ[ÿ˜âXdžH!–bÂB=%T)­ÿLs|AÁÎk›Oð9Ÿ‡â’äW %}¹JæÕ‘UÕš"³TFìáš3»n7 é…>Ys<Ã2Í~.* fi$b—®{€ÊíµÀÃÏÎÑä Z õ#üµ oùƒGìJŸ¶(ùfK]œÖE”SÔOðtÂ(UT¡ì×ó\‡­øÞøöê.*Óé~¥8s5‘l]–º³X¿Ãr@Õi @4Ñ·ý5$¼‹îpMaЦ¢««Q4Ò´4Õ2´¡WIcå‚串›_VûcIs*lºc”xvž&e’$Ì'e!ó)RîûŸ*íØ ±cðÒµ0”–yúÖ p€ v²Œ[J(s üú»2£øœ¾†‚ÿéõ[@iÆæ×çÔ‘Øà¿ÕÑÅàÉêÕ!§§Š‘fÐma)Ò#AêI%xܑߵUBå™õ^¤– Ó@&ÿ•!Rö±#Ø‚;bˆ–_2Ô3¤q•˜Z=L¡ZêBžHØp(Ôkc†PÇ·ÓŸ©ç’¤ãè•G+äðÃS[P¢4Y 3­§PeSby:H;ß~G;e¾}QNÔËšU½E2:éaL¨±Âíå[èqB”¥=m"µP¤šVŠxå¶µ?2w¸õúœYó c‹%éáPË(4…BànÖÍ¡WŽYõe:zP“¿qX¨Z,¿1ÌIÒ°G$¬Om wû[;ðìÙ•RŸ5Ó 3cƒ·¹pt¨Ø¶:oŠ£®ŸÀYÄYdTòÕÔS¼1¬ï¢?Ì: b{Äý°»#Èò<¾•)+iòá Q2£åÏ+cÜLw¼/ ž=æÿ{1ËæVÿ Îaáþu~küF¢:ʳA–ì«ÑFU¸½ì×ßÛŸø»2­ËalÜ &‰LÓê%ʼn:M¬wù·úc­lž(ç‡)h¡†YÈ©UmK4CkƒÆ0§ÃÞ¦È㫯‡)˪’'Zg’­5žžgH&À¯Üý±L2,RÍ)/T]‡:Û4¾h{ág‹ÃùlO¤É*É qùŽÏÏŸ;y8ñNwY }Y3i§§™Ø±é-‘ž,W¿¾;îk1¦£™‘BtéÎ…^…Ø8¶(¿‡hk|-.gZ¦Y §Y”%nÄ[¶çõÇàד&\Ÿ2x~O3$¦»8ö_â̧9ð‡ˆ(*('§9žmIB“ÒYã•¡LXÜð@ Šüo€2œ¾*G“æòÊÕÒÂéA.»,9€ÓÒì¬P8‰âáâ_Ñø{+ðÍ{»ÔÓ%E}U=dIW=@Hɰù™!…6çŒ\¼)øi—ø§Åô9íaÎ2l’°Çñ±ç˜¥¡þMÉ ßä=Î=gîÅ(ÂLuø}á8i|/EâZÇ©§Ì*ê$hÞ6F%cf6Ô [5ƒ ^ݰßÄ”ðxià©‘ÕÔˆ‹ årxußž=-Y÷ÁÇC%*EO¦PI*ð>› RsŠ5Ϊ~ºr”´È¥ÌÌÂå½­ý1ç²7›Æ.éLSyµ·'j(ßÃõ5uÙ}uL.ôО&zrUv"ÊÛ½½Í¯3ª)‡â4Y§^òP¢Ä!ht‚î×6ÝY…¹¹³Ò™>ã ækƲŽ¡8çÕžÏ_=Ìä¨Î(3hfÓm#Íwþ[R/{s¶:ø“ÔJ_Øé`ʵ¹ç9/†©zªÊüó.¨¦¤ŠJs2ÃQ3\²Ã=€âÄmsµÈÆx‚Z*ZZéjž•ZP JÇQP\€-Á¹8³øt=6Y$26·²ùím^P/o{_èF(SÐeYæw[šæÐ|%&J:}d˜¢JPùŒ{0®qÂ8òãË'Ô]”á’MoÿJ€«7ð§†<7K”fôYŒÙ]ME‡¦Y“¬¢æQpMÚê âÖž¤äÔ4•TKAQÖš'§Ö•ÅÀ ü×oƒk3Yë“.Ц *v)£i‰o/—k"éb;ê8Å’²–ikÇ¥Æ+y‡‡‡‰éråR馭ž’¾† nš(,ÞÚaûâË3éËW<βö¦p΋"T±:dIo¿¶.^Ž<Æ£)ÍëLÂeY¥§ª™$ ¥‘˜`VÓ°ï|tµ> ¥§ŽLO„ßäͺ‰c”!gñ†<{øñø[žOA]ä³Á M]Q¦©zY.N¤…‘€$—+ó8Âx~|ú˜nË*HË‚Yr»OƒÅX M[­ÔÔD¬Œ à(6 ?Ká¶WQ#P:Í–-^L’ K=‡@ògžÖÓïŽÍÿÿ†ù„üA•x‡' \§ÃóSŒ¶zZ(‚ªÎ¦éì5Ç{·ªMÎ8nv’UF‘ÓÖRËK¨Å"5AŽ{ƒÛ†c>µ;áz{þ©rLûÆÙ¦QKMG'Æd5ÐÌäå*Ú!Úå®~€ádñ#<Õ™ Š1$Ÿž˜ÂÒhüÙ6é’M…ù7µí?áBh×ñß!ŒNÌ~¨„t MÀ·m»úbÓAAK–þ þ2å’Ò _/ÏZ”3KO ±¼Q—úE‰÷aÔgŽõ.~t7›rEƒð'ȳïÃïæ9ÞS—6O[¯.d¥`¡‚3#º±ØyJ±Ø2cæœÒš§"ª¥Ë"®s,)Ô‘é\•bA·rµìÝù?Of4uü$G–åðÃEnW ÐM•~*@òI¾Èî9'lpÏ ~çYæe£ëO2­\”ÌòGL€¬Kfr§ùHÅ^¨z‰æ›u.>ˆ§§•¹z"»SSâ/ftrÍÉAL°D"‰#ie <¶ÔÇÐ Ÿ{âoå9žK_ZÕ0ÏUl*#tšuävâàùÎÖ ï¶;‡j(|´Ÿ†¾ ð¯ÇUåÉ^eœÑS*UJ˜,£xÙ”<Ã…Q¾(~ ð?‹3”Ë¢ƒ#ëCQ.¬Ò«_å‘rºõ1óäûúõ¡‘NÚTI)«Š9öH*'i~"ž¡tC­Ø)³ $m¸’~Ø—Ã2PTf´yuv{‹Ó4f HÚvMDÝ9ä\Ü[:§ðwÅÙeOUr솹„Eš¢ éX©$1tE:Ëc`¤úî,t4yui0Í3¼¦_ÖQ%4pÒC¦:x%´* ç`IcÈ ;a^X¾=FPÚrŒ×(ɼ;ñ¹]FW&]™ÐªÅWt¢©$³¸6[ZÖåK÷ã͘eu¹5]\•uei)X£D…”ê`,éÞ×Û}ï‹æAàÜú<Ís1˜d…éGQä’…'Yƒ.¥bYõ[p|À€qÔüEŸÐx>¤DÍ’ ’·ø}"¯ÄÙÊݬºØÛƒ½Åu˜ñÊ8¥þ¯Ð®rPkw©óçƒ<&+óŠx³ ŠzLŽ*¥züÊ6`Æ"nLjEÌæò€m킼Eøg5ñÑ$nÔ«S'Âü5WMé¢d™X³6ÿ(µöíŽÃø¯7¼;‘ÒþŠÊ ¢²H”ËZ´BCBšƒ,L/©Z[€YO”sÜãœæ†ywƒ£Š³4ñ],ed‡_á²þj4dyl«Þà-Ú÷ä iy·»C¦§öxD4~"©Ék¢“-˪[6Ÿ-Ijê¬Dä2èT`H¤Ü Ü‘µóÿôn[šxbLý¼QQMENZ¸ÇÑ€"Ĩ©©×ÎXÚT“sÀãŒ9¡’ÜÙ_—ŽŽ[œRMGQ,u3ÒÓÔ! GRÁ¯°½¯«ž}°VL³J9ž§1쥬D„ú/?p~Ø»UeuЬPF”/I ](Öª!#ª“s§Z’õ¸òI”0©Êiéª493£@Û|Ãa¡÷ܾçrv“3ü4¡–géÅPTFÆŽ$²0m% @‘~Âz红øs/Ç»APÊ$¶ÄCËÀâþزå>$¦©–’iÄY]UJ’‘»¹Ž72†#O Èç1䌸3|XßG9¤ð`&–9èNgGäXäºïuòôp ÓÂEœE*¹¨QÒÔ–d`. ?®Ä_ÅÆ“'ž³Q0eÊÓùVn¤nÀ_wB¡oclM[áò ÑW–ÕDµFgâäRÈ4¸òü¦ß1Üó‡òâßJj\¡vw—GžeÉ—ç°Fÿ!X$…TξÌÜÛŒUrï d±—Éëê&umh’‚D¶NÌ>ÜbþML¹¢A_•%E`R#jxÉrodíokÛæ)UF”Óæ9D®D¤Å­2ÜY¶ÚÄ{ae>†Y8ðÎGX™zäÏ5,“”§Sì¦ú•A°mÉ-nÇl>ðîG_@µñËJ®ÔõKE „g]Ù»VÞ„àßÓÐG˜­D0T#“uAPΨF÷`ÀiîvæûâÁâ*ÛSP…Œuf©,X-ÈŸ¢Üã™›&Üëí•ÿ÷m@4”Ô”¯xÓÅóæþ9fŠ•Z³A*> ½lïÅ#2ñ¶m`J¶H‘„t¨Ð³:-­óêžü{o…4Š[0ƒâiÍLMV&!Y”ë noȽ¨ÆmNEµí5iøM—joÅ“Í@ÙåUVSS ôÝêA‰]5zµƒ-˜ C½ý1c’ž ê¤#Ï4šKÈzq-€»’¡®îv87Å“ÿë òŠ]y•+ã]‚é°–2»Üi&ÃÔÜá-~u•åÕõ0fÍ[Ð=<*·TQ(`¬¥ù‰/ Ó¹Ç|yª/Ójc–à×(êTõTõ_‡5U(ãáúsy‹iUÈ¿šÖÜ Wòô™*)£ƒ: ml%W_4á * YX‹ß{ìF%ðÖ`¾)üÌæËËLj>6(ƒÝ®DŒ YyãŠUu]\t°Ð'Rµi,Óuád5µú~SªÇ°#å;ààO{bišnttºíš­-U¦"Uª–y»5ÕT(:¶ù¹ÛœKYK–K-såÕeŠ3J—VÞÚ@V7Üéä‹ón1Ãrú÷;˲UŸ­UE:*ÄòôéápÒcbÃR­üŒ8k’E±Ô¼Eð¹{垇'—0Érj_ˆ¬h¦XÈuFÐy¹½Àîã[ÚÄË‘oQHsS‘F”É\óäU²;êž‚‘´Œ¶’H"äˆãxlf¹ÕTkø„$ZIŒU LêÖà±PG#¶ÄskãÏ x¶y-E_`j…4”ϡٺŒûª/›››{í‹ ¸•¦b-k¶þ—ûáGáõEMfO]âZº?‡©Íóji¡bn±"t¢'ÓTq‡·bþ¸hdŠB²DÀ¯Ëqqb ŸB0e2½Un¾JjZslE¯#|ÚG  ñ¹·|cð­DòeÍË¢˜NRõä;(êrÊyä`Ìè `,¾Vf5”ÙŒ9 Dùp³Kž9 ¼vV›XmÁ½Áãå•rVd‘e1u¢F§Hž \1wµÂÛqe$êà¦<ðfKQ”ø)hÌLÚY/rNþäéV=îN:ø²I`„Ò¶Ò.Ç{#fÞʪ[]\òÇWKYıÝÙˆRÛðý6‹† <©(2;³X)$óo¦ÁLRÇH—Б…½÷Úß×|'™Å‡Ïµ½ñÇñܹcÊêÊóq\™•Ê¿1–G¹Þä“cíé‡ÎD)"‚­u³pþ+EO9BT¹¸™üEZ‹üj’J*Qa{Y©ì¶1nÖ»€= ãx¦RrÑ|ìM4«á2µ—xr«$ñ¶aGJÏK˜Æ&‰VäG &ö€­Ç¦üE?Šc~º2EFÁ€\±[qË=ûáÅ%|Y…4YŒ c`B[ì ½wç̼`!øúh–F6˜u'´l,>^~øÅªÓ`†v×|×ÜŸêW’÷S÷6É$ ™¢¾Ñƒ{ßA°ß×}ñÎrì®SC¡ghÝ(ÝÒè½Fg þ ~áGs‹ÖkV”UUPħáP°ÿâ0PìGÔ“†™Í6]\´ÌHÒÖÂ…iÈo!W*ÇPïm"Þ‡ïn~•¨ãšÝöûýŒZv–èß\‚R<9fG,0™RÀ)©!}Û§é]Çv6'×c‚éèÖкùäX”HokµÎ£ô»Û óC$9šÓ”eÕHõÒº­ûŒ2˜T Æ‚•Y”k–&V¶’έü£Ûœ>“ËŽO"åq÷Ù#)e””×Ëñ=¯¡šl–ª! Ó% ]†êG­ˆç¾'ʤ¢èÑ0ži–†¦¤€W­+?Q™‡›W•Eìl­acl_é$Y3ìèîɾ‘vL*ϲš Óç_ió:†¢YŠ´õAÐs}ï¼b÷HMŽØ³G(焤¸iq.Ã¥„-×§è“PeÙETp54iª6¼²YÊÚÊIúnE¶<âÅKG.¶t‚Pd1rÊA@úúóŠËI)®Å¥Ì%Žàµ»«“öÃì¶­ãRW}È#{gþ?¥YÔyÓøºøž£$’£±–LÀW; 0ío®ØW—RPøf¬å´ê“OΣQcoO׌›ÍS™*ÆÐƦ'G§rm{þ£lKáúx›,ZS˜´™¥| ]3DˆTÆ,8PHü^aŽ·†8åË“Ëé¥ÉfEå’‚áúƒçy…câZ¬¶–jŠcKDËÉ Æ@‚ü€»“ÇžÃ|-ñMoð ý¨äd­§†A—ue…\}w#fðæÆUsÍAð”QGR̬¿óܱØß˦Ö6ÁSÈ%…!êÌfö±¸ïúc‰â×-FKôegs’—eCðî›1¡ðtµëÕª¯q$èd_úÎiýOõÅ–‚ƒ=9fSKR]bÔ£WÈ„C¡‹/ذØ{)ü2J¿‡®Ì/*e‚¨SPDà€©*Î`Ïý¸»-c|<ÍT3ͧYä½¾ÇôÆ­µë_q4ø¡·âö*~,˳¿ÉK–Æe¼Éñ ÖPaF,äj"ü=qϲ¸ê寫¯¦¦¯ŒÉåø9j.‹á´¡Úþ„“¿ëpòM®ËCf:¬¶±ý†9®MM]GRôê!‰WáìÒ9!A. ¬n~/AàyÖ\iRLèè' pÚ—E+Á?Åãþ=GšÓšX™à’L:Wq }¬/ü¿¯±ÅÒ‚™_ÁÒe3<}P±U_üZKïf\“O>Jé¡WˆÙÖê •Á ˜ž00«Lî8òj„) ¥,±€¡YA-sÜ«liãkª‹!TêÉ-1žK5µ°`6?VzŒ/ð ;ÁUmKÊL7H‰ÝF I>¦Ü_ß ɦœV6î_‹ùpÏ&)Òõ/>¬ðæ}¯>Êé(>5JIæjeŽmq,·"ößkÃ|àÏÁà?Ñä”2,õžš[ÿÌUJ÷gk\س_½”[°Å[ð£Ãá_4Î*éRZy«z™RÔ i!`­“)#Ê$E¹òÜöÅæ)?ˆxÆp A”Àf“}Œòl¿pºþXöx¢£:CtçñlOýÅY £¦JE‘ædÔÆGÙ¤sËpI¹ûâåU§ÄÓÏ ùiE†[HŒ£t#ê¹ÿ Í¥ÿ˜ªž þ 4št°°M;2¸&øÚ—]ŠW©“åô,t­¿Aýqåpdòµ™²Çšáì9,Ò~à9½u <éLÎ’JUi£W²ïn›Å÷ðÜŒâ<ʶ¢(¥ie¥«VêÝ6W»!µÁ6}mÚØ¬~*WœˆäôÔt‰U˜æ“ `’©( LÌ×°P íµÏ|4ËczjJŸ2šV©ÌKÍ:‘Óekïv[ØvÓlz <œtÊQ~÷õ78å4ËiCœÕTeÙ>CJ*éd¤ŠV¦Šq.—böf¼nÚ›rMùÅðÄ5¹×†*e3A&]T ˆ„…â1££\zkeÿà «©¨2ï UÉe™l¹M3½bÔCÔ { ÁÛµ·¾+_†å±øƒ>¨É¥h«i)eqÅÓn­5ÓOþ <¸kÿ£IÝÓïêlÅ9K\ðE—å9}‰|QÑe4Ùl¨dyêéé˜Fß. mÕ±&ã›¶à9ð>W“#G/K+¥ŒEO®.—VÆÍ;óÿ”üØc %ŒÑSRÓH+%¯u…lIÓbO•Fý…°Î¡i©æ-UP‘à(Ô ƒÜº(]WæÀo¶&+Ô´ý»2yžt’¾…µVmŸf±F‡,£h£¥œ‹|CL„ŽF“eôçÓ jÏüî\‰.†gs§üJÇì.1ˆQâlT"ÞÆÿ׿8Äõ_‘ÔéS2Sµ<¹–fUP;v;®0GãÕKw ÐŽíÈCø’ÉV´UÐu5Àâ´4.G=­{ öÕ~8†£Ä³fù#ÒS¥ tpÁ¦¡™[Ö°Õ©Vý¿¦/Ù}SÓSѳ5CGÄîö³ØX’>ƒ¬ó#ðöAOœf•9U•ÓM,ïVéy|ò“¬–¸±qmˆ[Ûp1º á=ý:FÍ;Ç‚3]³šçôSÃKE\¢„xÇZޝO8° ¤ƒ¸ú›ã¡x2jjºÚºšZT§†Hc1Æ>X'R½ÿLWÒg¿‡¹–SI”É¥®Žx#Ô»2¾”6{_ar×¶,Ÿ†ES$a$Šhʉ¢poæÛûßÏÑÏK5·ì?C³I,96Áü,ñ?1«Ëé©i©j$ˆLN®™ ¶‘¨Eˆ÷çë‡> Érú ªsj:cù¼’Ô7VXÛÍn%‰$s}÷Â_ÄŠU¬¨$¨’e‰¡wXšCµõ ›ïÛÐaÿ†¦Š?åk—æG1S¬i*‚·`,<¬clUƒrÇ–-¾(ÓæŒwóêsÕðösãÚx+Æ™QÌò*¡ùñ$e´Ä·ìQ£BWc¦FõÇÉùð TrZ<±Ö|º˜S×”Œ—3)´…€â¾>ÿðßñY¨óJ…–4b*:V½´lØÜ’M½=±Tñ§áï…¦Y”ó ï¹ÃK$±b”¾Cj'(brH+ñŸÃôä´ÙV[GM8…Џ‹J+/mµYK~˜#ÅÕ’ÑUåÒE$ùsÔ¥DQæ-E׆œêBVE KXƒÖÄ(ÿˆ|³?¯¡ðŒÞ¬JY"ΣJ’μL `=~A·¾þ;äÕY“e•ú)é¡‚nµLèæN¸Êõ´‚Inos°ÇY\óa”ûø‘Çó<ÉÂSè/ðœyÊf³å9'…+hT£Uæ#à [‹kyBÆ7PH*˹ÜX¼É«2sèü#–eÔ^$§ª†¥d–,ùm<ÊA¢wÑ"\YŠ.¡q¤Þãâ³Ä9tT±åùõ\Þ$Ëè¦%&Y-L4sLåe²uU³\ö8¹å~?Ì3jùa¡oá2VµB¬ÔqÃ%Lr…´,ÿ©}^çRª‚#…c”-®Ž¢Ü£q\þ$~Ñx“*˳h2ñHÐ&a’­ix¡»€^,¢ö'KØé76 ˜‹(Ÿ0ͼs_žå™´¯CBƒâåxº-(w+¥£ÐXê× ‹öß1ÍÍŸdªN˜™8:“¦R╪]Lï´ìê“Í݉ú†óµ <3iêJ°"ˆuAóAØ{ñŠÇ‡h¼Fõó¼”4à*¼Ž“KTw, Ð]®l}ß :sP=fœË)ŽJšq§_ÊAá´µ¶°óKã¶¾.Ìh`•ÏñVÒ‘¡_+¤‹ÜØZÇ›ý1cU52šÂó¾±"CÔg^ ‹ÀŽäï{[d^¬Î³‡§ÿÔu‡4¯»RÒP<’õ’×ü‘ ¶«Ÿ¦-_ˆ‡õ~ŠJ”ÌÐe•+Óž¹êä–}_1YzbÃ{X›ì1T²Â2QO’™d©S*¾"Ìc”CES,241’ÖXä"×RØßžøq—~(ø¦y#øOeP+Ìð]¡ŽžPFåwß‘Ï èj2xs)c2Ó׫¸é˜cÊãÿÃu1 . × å ÉØs ‘%il„ AƒvŒ)°çQ%½q¯|’àGXDþ$ñæm”|-Wˆhêä’@ÑÀfŽÀ‰#+f{“bIãü1ZÇW.[&hõNbÓ¢hʹõ•`ü-éMK›Pç”fŸòÜEÒ1¢87E‘JòFÀòG©øz QäŸ Ká|ÚDžbTW‰dòÛÎÊG _×nØU<†Á¶%Ûðã8ϳÄ\šš¿5©hcëui¤«K˜Y†¸ÉÕn9ãø\ÞH<-Wታút5SÕFYU>U¹!˜ ŽþKá Ÿä’QäU”¹ª$Â*š–F(½)5  Ü“ØáßãÆw—åµÙM%qa!Ëå!Ö©`,YH;éãR1Íøž½G×i’Q_Ä´½Š‹¼’ø[;§¡ðÝ-C¶iI-sMR“ÆÁ`RŸËdR×Mµ‰ÛvÊóÈåH3ïæùVµ-ù=BÅNƒimÒ ¡ˆÓbËÇì!ªÈ*?¼!YYF¹„R@·lvúŸ æy6CS_—xt$µr¬M>C<•‘D§Mµ5Ô‚ºµ5Á±°·¬fµ¹ vo$Y¦Xiꢓ ýva4h„v ¸±¸c>S.‹I÷ÁOüË*<_ã ͙ÕÔCBÕ’Ïü*šq!•BÀØþeÈ;ÜbÕø±àjŸe¹/ˆdñæá«%FºH©Æ¶»#*FÁÁÞä•=Ž~I’ŸÅŠhòì¸A3RTS‡j¢Ik$!îÛú^²3OÃeü&ÍrÉsH¥—/JÊ—ž$é¬aÞI@î5Zþ£ó,Ìj¼E$mñ•ŸÃ¦ƒ¥Ó³‹’NÂãYÀ‘¿Í¾:wŒ#–«Áž(…QXË•Í`O6CûcždËUN’P²²š¢9’:eyD±”܄٠`E¹Ókó…ÐåzœRÉjÐfR„¦øÿq¯á‡†h<9U›ø¶¾’mª‹G%[†c.’ƒ1ÕüößL.q_Ù…Lóæ)I&ePO,æJU+ «!ó•¾ÃP&Är<¦åã )2ÏÐä9ÉièéQ~:¦m?vk°½Í…8­øf¶”æç9hÕT£/•f¤¨DJt‹§’ö v“kéÆÈ·._¡f*œÞDA•ø§<ž¾Ž¾Z¦tœÄÒÀ¯ 1;ù#B  }#P ß(±åÞ"úŸ$&àž¢V¦’8™Æµe°”…ÕKß{‹8¸çuù .`”ôÙí,ÙβiÊÂÝ$X¥µ|§¶“ë†9…üC˜µU.S-55V\DVg¥ByHu=@t›ÞÖØv¾¢5‰¹:P㱫;æ^^7š4DÂáM†Äß{bYieC-sÍ0Ã¥EÄLd±P6?}·Äyqœ˜f«HàšXѤ‡¨£..66&×ÇϹ‡â5G…üY›åY‡Š³É¿‡ÔH’!Ê40Уau#a½·Ç?Âç<{ ¹JÎ~’.1¯c´§ƒ«²ÊÌ´åõíWG Ô¶«kÔ2È ¬´‡±Óa†¾¤©FdáLŸÑR¼{°·Ô¥±R˼L¾JW™SçÒ´T¯LTkv•d;*¡ÚÝÂ÷8sâ_Px*<°f´“­ \­NÒš„ ¶’ËÉ M¶r1|µ1É©ŒÚ«‹‹x“Ëß Îv*YNÝîpÊ ÒhbnÂþã æ–›âç¡Vÿš TõFº‚>êÙÁ4·4iê.1ç!«Ë‹4å-"Œ-Æ[~G™„ ™ ¾¤*¤‹ÜÜ#ƒN6õÃ!2üDt„)^Û ïícúá6Kñ‘çUS<±ü Ó"B‚C«¯ªBįÒW|E˜LÿiØ•R–, ãëõ·ëŽÔ|[—O†MÝ.@²¼xácLÆzš˜f¦ -GR’¬-#¥ì 6=÷±ÛûáfY_m•ÒæTÿô§QJ•e%XXî,AÛÍW\a¥¼ ÓÅ5匛u¢¡q{ áŽý‡®åQSR@hã*%–If°]:–úu[±$}ÉõÇSÇ0¬ºK^…ù–ìjc M/S2Ù¡'b0}$¬r¸S¦²u‰ƒ[N’|Üóµþø[–0ØXÙ?kÿa‚(g•㎂d‘"39öó+¾ÛÙøô÷âx,¿›ýT¿¿Ë*ÓI7ýÿ@/PPPåÒ.YpÁQ,•K`ª FãJÿ.Àl6¹8¯xz¦9|WðÐBõ-F³üKÇwTù‚žOœÚ݉'|]•?:mEUoÀÅ^ž‚¢›Å²W‰PÅÍ¿êT»ÚÇ:ó2,•îW(s¸ó7…¥Ÿ¥RóDP+’‹6bn=p/†)ò:h¡w¯ZV©*Ÿ9¿•Iä(=ì0Û5¡ª‘àªHÔÃ3u€jïÇêðå/𼺒(c¦†áF½ŽÂ× û=ز8J/–Œ‹S\0zƒÖÎó*û xœ­+1Ù¤ ¸±ï¦0~ø‡ÂTò¢µ\³K_LÌýid@–}6spÖý"þQšø…Vž™´e£«gØK-´³ú‘®?îõsã ’¸Å‘®_õ–ºœÔÙTSPÝI¹Ýîmþè1é!§ó1ä”W«fÌxe'&ø7©ÑüXÕ µŒ€ñrý?|W&c–M–I"©©F ª=zXî¦Þ«±À•M#eV(D²¸m¶ÞØ‹â#«¡^Ey&#ÕSÿŒyì9T'%Ûoó2ù»27Ç=etUyE%=erVÍ (¯R‘”êéÛV›ì.Eð~TªÔ)õäbH6R[V‘ô "¨òxfƒ<¨MÃ*ÌÙ£v:6ìnéïë¶'¥¢¬ ª¨JÊÊWy$Õ=:±®ä¹¿ó;]¥ì8Å™4o)Êkºkï p8|}'úžÃ2.h‘«"hcqµ‹[žoõÓÂ^­Ê)eoá´šýDÂü™¶ýQ½EQfL7iNÑí`Xý ˆ'ë|=D"ÊrñWR()as®ä‹o½<ûz`Üü•Ì€5Jù‹ •‚¤úŽ!øV¥|¦‚Šs£ât37ó.‡r6÷¥ñÎÉ‹ÌÔJ1ånÿ4ÁG$¾_åø’š–›:Ës:ö’œÄ¸XЫ³nou}J/¶+ÑEKUR¾„Íð“¤Ò»^ÒYF•wùÇþ# ?jh ÊòúŠÊežz:£-20Ñ.†PÚTv’ ð³!ðýfW™ä™¤Õ!ä«Ã$&1xÀ†F‘®=_|mͨóV(àôù~ÿ1u_HÆ>²ïNc¤UT$±ÞÀØ`?N)|7›çÕWI%Ï}¦ß¦ãøŽ¥b¢†‚6j½R0uEþ×°ÃI ‚—ðþª*ˆíÑÉÕ@w:ÁÔ?{c¥¦–ìîMð¢ß÷ÿáV¿3ŸE¿¸­åhr¿®úêž™d“©ËHËrOÜœD+³h¨²ÒÒåÉža–hÜí2©^²F?Ç iÛ½í†A£@aÓ+¡¿$l}1½‡òڿ㙥TÙ§N ihدK©}FR©·°·ÛsÁô³ÏšRO„Ã¥•µÒfÔYUxƒ4¯[SÓÿÌBæ3«t 6¿‹v˜S$ùmFcCK‚ÄÏQðáƒÈ×FReÿÌ×7Û` ½Á¯ÌóJ ‡ÍŒTÁY*^5°11ºíØ%os}7¹çÏÂ\š²ø“3Ìë饞Y +IÔV ì©)~ÅÂ|£Í±è!›#<yÔSU'ý‹–pžX+•t™“ϵ¹;úâ™øù“PÐf‹á)$iL]ÎÓm ê'‹jîHߌtªºežyiUGQ)î€Ü+1ÿ7#{vÅS7Ëåž‚®Ž£É(ˆÄÌ7±¶Ì=mÏé?©Ã›OŸv>¸ÿ'Q âɾ>¿¶ ”fsfY[žtzsÙˆÓo3#$[` ¸í{c\Ã8¼]—,žd3E+,ïvgûñ†tÙaÉüá¼µ‚š¨©M£‚åHßBç÷Âlæ ¸Ð>[ /ÇȦz™£iœî’‹ÿ…¼ÀXÜó¶(É ˜úûަ]R†=±xžUŠŽ¢y3$Ë¢‰ËPÆÀÈÛrO`78ªAœO˜åu9„æ«‚u•ó* 5°d:qî06ÔN¡¿Ø´øâ’®¯/¨¢Ê Š¢¶¡?åWÒNT“c° _ ¼'QáôËÿ7$UŒÊ¦%aÓ¬YTª‚Æà’~ƒ'†-¸§}î*ðüpøå/F\hƒµsÆàí4£½È0¾äØ ù<K¨Ä~©y"ж¸täxúò®×ù­·× al¾*¹dHäêÕ$—`G `ÒÊ)Jr’æAÃ4ÓiöÉaFø§¬’F°¤‰À$I÷áGØâø©Dùׂ3|»§<“U¢B©³3;H¶PHïÛLñª*sïÏ è¥†¢qQˆhK¡ÿËÓL02­¯¨ƒqß× Ÿ,Tá Ö“+Í5qiñe ð5ð¿‡óÜÓÂYUe[H&0Âjу™e@Ì $ çùqŽ™0©¨-5S†™‡óAý>}ÈÿåyUtSËYY›IœN´‰"…Ó2ÈKJßEÉbx%qßc­5Ô´•Tò¡30F1‹CÔ]â¹å=¹W1ö5ê²G2Þº)¿ˆðT­P©¦/$Ý;ÝÆúw¶›V7¿_øc™ÖçÌVºªZ§ƒ5juY]µiX£:.|Ã{ûàLËÅñÕfùí5e³¥tòt«ºÑˆ¦²Hœ¬l&×Ü­ï¿ÉV^ž8Þ\êPÝ;”f駘m¶ÞÖØcˆà–¼vžÓ“›MäÊUÓçû—¯f9~XÙtæ_‘®ŠÅ£FwóÆàk!€áÍÅøÄ™Ëå®Zâɤ²šTÜêQÛk\úáánZÙnW›=MLRVÚ9æbڂܬÂåAؑ鵰~eNž Ës|®:Å¥yuS-@º2iXúÙˆ¿Ó ©ÖMk`¤iÏ“$W¨»/†Vð¾s›g2ÑTÏ_:ÐQM—He(ÚDE ‹»1eƒ}†x–¬¿ˆ2Úw:¡Ñ+Ù›`À®ŸÛPÿc&E5†² ”OM,”C%kÅN9]˜ªöìmŠç‹«óüRÊr¸©²Ö£)$íLJ,û²¯S€Jö¿¦Ä2KQº7ÒfmJœ®+¥E«&i©òšhz"Æ¥Pì9ö¶=Ì“.cOYTª¹„ŒÐÓ9-c±b·àϦ'¦…éÑ ’>›Z—Ð’IÆ54æ)ÒVéÏ©Ò 1uk®ç·7ö'瑬ßᮾfxMôýBbað•qÊÁÄÁ˦ “È?0öÅ;2ü8‡"˲\ÇÃ9&{= 4Táë^ÒÇ ®ÁPR,@mõiy¬-r#TåµÔÀÒBéqȺ‘úàÌ·á(3 §Å-,’3(¹P›Øs`=qØð_“íôt4·…*We''ñUy‘ÿ£Ëš—3ZXÖ(—C* +`T€ ùŽÃp; ±wË3Ü·2¦«Êèê)^j2:ⲩaªÄp¦ç‹ßÃx)Z‚U§…%Yrâ¶jXâ1Ì.(R䮯þ¶O0 ¦§¢…!§•^I’8º~bùÜ#ýF;Ín/*xeö/Ôêk5IÅÁöW¿#¯_ǯ˚d©¡Ì¨æ¼BçA#nÇm.OÛÏdùgˆ¼3]áúÈ•rúøZR?˜þaèÀîb/€ó,¦—Ä>ÌrZÛjàxØ‘}&×ìl~Øß)ªšJ8Cê/,zÔ;÷úœr0gÙ² w¸âÇ*Ž%^§ÈÕ>¦ð µ´~$ª0ŠTwZ:w˺°‘‚›2…ÞÚ½@Åg;ñLÕzT·…骅Â-.¹ÁŽ×ªÆK”ñ~GâŸeg5ª«_áõ4­¦…gYn¦àW ëeÅkðsÂtKŸ¼­’׿²Q@³e•³JñRüA]`6¶ÒÚ6:½îv¹¿©Ódóð©{},üØ®xGGÍii²/ÃÏ ªÒ¬¾i™ÌJÆQåDòH\êÓ§A¹Ü›ÜÞøÌMYQ•fƒ+ðNkš>oâŠwžjJÄ£1RÓ¨•º’é ÄGau rïŒÇœñloø–ýÌÚüqžfí#œÕFÐçÙ^A‘Ñ ºL·øu=E\hhäeuR©¤;omHE€^×8ï™ÇàÏ&ËÄIO5ņº¤pòIÉ7 ‹’NÊ1Íj)28¼]ái<-6c’ÒgÑSWSÕQõ$£˜È¢7RÚl.·YÍ”)Ç~Î%W‘!¾à_|wµZÕ¦ƒkäuuYü¿‹9VG“P~xë"£‘r“Gšõ¨éªÞ­„å¬/H‹Ä(¸6P »Å¤Î©óG’L¬ˆä©¦ÐXÆujÙK¶°# ó|«)Ï¿2t©­¨Ž·$„ÖGNµP]H&;À7Ûµ¨¨¨žª•Wc [¨ nE¶k~‡V®%‘4åìažW’Q”»gÎÕTy®YâʧðÆ]Q—d¬è´µ´T±K2 ÔÌ5­˜°ÇËbÖÂ/ø2j8i3ÜÞªªž:Ø%‘‘óˆ¤UDo:€A$ÛrFú®qzȼ$Ã%Íç“ÄùÜt³­$ôKUCXò3¨ÚhØ‚=6ùÇ`þ0Ôu‘É,äR„Ìm`B¦æÛï°Ûlv2ë–±ÇvjË«†ž¢ùmŸ'Oà?æ°œØåž/ªÕZ:øà5Y|,– çÔ±òØ^Ö°½°Ç&†–‹ÄTfõkðrJc©§¬…‹T¢¨6FFü­ÔùÏa½øÅ½ü{—çtVþ.æZÕÔ¸J92$•³“¡‘̺’ÌAvàpx–§Ây§ŠrDÉè¼7â9b“ábŽŠ¢jfI ¨C $œ›éÕØÝmŽ¢Éq§Ã5Eï´»~Eáø‰Gü1üCK˜EE,‹E˜%<‘¨u´IÔã•Ã{a¿ãBÒUøÅ)åñ/„複,Ž3I›T”{³=ÝQ€F:O:¯· ð‡Ãu¾ üH–SAñJžâ­ËC¥®C‚¦úHö¶ç|MøŠhs_ÄlÒ‚Ž‚£6ͨb§—á"¦z…D(î… `çbnoéŽdmk[¿DdQqÌÛýðKãf9§á‡r<åSÍOQ ÈjôÓR@¥o®ú” loŠmGáwâ9}Dõ¹5 ÖRÒ¬Âe–Fu C~–Ž¥µ0]dü»vÇKüJðýyàì%žYb¦JˆÈdŽ“J¤,.÷K ߀»p1^ÈüoàÿÂÜêoæTuæi¢Ž¦6„uÖ(U™‚÷ Ú×ì1_ƒJ~[õø˜Øè.=YMÊ2œî«4‡àFc“××t•z£F\±:ÔF¶]ü—-¾âÀcyò¼Ò«Å£ Ϩëslâ:¨é©b«®2[YÁB„ÝlCw°¹6uoæ^ñ—cÎr߈¯—$…æŠišGHšrB…/b§Hk¥¼¤ó` ³ø·Ã³ø˜PÏC[G—f4hêZ2ƒbVI‹î õ Åßó pÕ •6ƒ¾´“>Érjj¼«=¬Ëijóº'§sdó6ÜÜ1Øúà¯ÓœÛÁYµ:ÅÓ5†5pl]F¥½·ù€ïr/ýA‡ãIAñ±Ë ’ZmÑÑË!ò€ ØØ °ã/Œ§ŠDWFo”îNÇúã£4£©§éþç9e—œãû÷9ßü8Ï¢“= HR5V! Is,v-¿Èñ~pçÇÖ'âG‚ô]©ä£Ìã›Ï`˜vîn§÷Å#ð·5È2ŸÇŒÇÂô2ÓeÃáæ¢‚‚í®I"`Ň"ÅW>¸»þ)«Eâ/Õ šjtÄ‘1™´—SÈ4êmý1£Ä`å 5ê¿Á£$I~ýƶ_GœeÕy6b²5aLô³ˆä1¶–6a¸8V²æcÅÑÒÐ×¹>G@ÇG$}Iæ™ÉH˜¹Ü-“É6Å‚aÒ‰& Zdc¡ù›¿np¢£!̦ðáÊ"Ïh"žW‘ážJkF˜ `IÒXÕ3ö8óÞ“,gåEðÿS&?³÷•Úª<Æ,Ö|ªxjò–¼µÎZm)d£ù<á¤:ŽíüÛÛYáø“Âmálç+É¢¨Í#j¼àÄâ8VÔ‘U @Ò£VÜmnÖÿx_2¢Ìa¨Ì|J•”±!£¤¥øhQl0;l¢ÿ·¦‹;Í^Yê¥h>%̺²í¨ÜÜ]Fæ÷¸¶ÛzˆT¥Eð»:Øš‚KØâÓ~ø#0­|Â:¯R©n¢ Ì”}ºE—Xò“»瓎£øw”Å•å³Áaœf/$ã[fu]y†•¸»Pyôôúâ|ûÃÑSAP™=IÎkhç^\±˜!7¹“@òÚÇsk÷87ÀQ²dš:p¡šVe1T4Éè|ÍënWÿ‹zgí¢­vÙãTE4ŸÄäck'—þû P¼uàŒˆøÞ¯Ä¯“QÖVVtæ`Ä#é±Ò ‰AÜq~øéRQå´."‚ªS-IòFæà6Ûo_LŸÓTÕÍIOK³Èñ¹*–R¡Jݵ»kÜörü;ÌÑäk»öäçé7`>Aü e™E- Kjy°INŠ ••-º±V*lMÆüP?á±+S±?2,º@ç–µ¬æÝ±d†ž¯£^0³, H·o…+¦ª—ÃsA$• ©^`ŒªV5¹g»r¶¸Í»_¯6mJ„•FÙ|%)eŠ}XN_ÅÔÒçNÇ®ÙjÆêÀê*÷ßqb·¾R4R»•b•·~׬‚º¦¿Ã”™M ËÞh.iõêû‹¾6¡•Ö®U6±õÇ7U?#6É.YšY,‰P>O_4¹«ÐTSIDr¼½MI)¸îî®4ÏŒùkUfµ ×¥2D HÔÝO¶Àïêp}O6l¥ÀŽ’`Hå˜úþߦ&Ÿ.̨¦øb’jôÛUÃ&å‡c«Wí‹qi¡,?Í}Ý}Rà\pYVßíýŠÌÍmèò j¹äVi+ªÚrdÓi{*­‡.ö@±ìë/£ÍÞœfU¹}2I81RÂYw"ýF-f‘Fäk‚ùÀYT0³Ã›$¶dÈ”«#›MbBŸrïõÅÆi Ã"¨óqßðÜñÍ¢©6ízûû°dÝŽšUI $ŽRB-½Y‚ë‚ès TY©P·ÄF©#ƒ¥õ³ZÇäm¸Úö¸¸µQCR‘$×*qìAR?|BYšB·ò¤cHõ,Ð~ç:™é²]z4¾ó>ý²n=çÙðË¥¤¤×?¯$µR’#€!P¥»0_¾ÑÒ´0K&dci\üúî·¯¦äb§âú:…’³4ðîcOˆ" ZEø¿44ÈÌβ±óÐI +°½ðKgíMAü5m,ÈìÒM1,ÿ3wg îMÏ|uåž1m›ø©–y¸á[Ÿ!‘6šøB…GòmÀµ¿¦,IN¥XbYùœ ¹Åj#y¢%Îpúš=Q’·-½±ÌðL¹d—7ïúé¦ÜåDGóº"´ÒkrìÖäý¶%ë£JñFàº8ÊH¸¡ïâE¡¡55V†(c2ÊÄü¶?¥±]ðFqMœœÒ®–ŠzF’¬<‹4æF$ƶ6áv`N:Ù²äÅ‚*|?Åû›±Í­©öÏ|\ e-E€ïÀ0力~ç 鄹®GKWOu–Z)‹rd¬/ÇÎñ,©K˜åñJB¼²9U7%Ž¥ØîÿvÄhrƒÈÅâ[…Ó¶<Ô%³[¹ð•wòHãdÝçܺÿbÓ—Ÿ‚Éé(ƒ‰LÇb9* _ö¾*é_H’6f ÊjçÌ¥™F’B6¸Ã`Ò¶CTúÛ¨b”‚„^öa·¾ØSø] ¤ð¬3I•jc(ÔLJ¢íno©˜œudÿ”e'J¸_3l·fQôõ'”ƒ]Óeb%^-K~›~¸u—˜Ä)Ú6IF†Gÿò_k[Ó}ðPLª Ê–‚7–š œNáVà~ƒ s䞳°WÁG5EU7Nª!„d¸$°ÔE‚ÆÝíoLdÑcž“>îßE8ñ¸»õeÔ–GIDj^ SÆ"ê8³2¯Û½¬>Ø/†)2œã&¤­A™¥L“º;\+3k…˜s …ÞÍß ŒgàQªf‡®#Pån|Ã÷=ñ´ŸÂòô|ÌSF+36†›Ë`ó0¸E¹ôÒøêé±)ê& ûFœpjÑ¥ H'N˜Óh¤†:Oö8Š¢¤¬2ÔHþf)?SaýpêŽ05<#n;a}vXóR˜ãxÁ¬›žÁÃ[öÁŽ,¸ñU{ÿð\Úil[XŸ<é>SP“̰ÆÑ¶¹ì‚×-öÆxR–h ¦ŠTh ,5(÷bnEù7Ä~$Žœe²Á[2ÃO:ôå'’¤ù€ØÜ‘q|%šæÒVf^u5Tñ±–9i©,„’ oµ¶Ç"Œ£%9ST讌²|O¡ÖmN¿µ(xˆ4U%¶ž9ãät­,´rÔ¹IQ,ÀqÈ‘ýöÆù­Q¦dÈ‘¨vÔì8MÀ÷ÛÖ6gÿ¦je:Ö¼.È y®G—ïÆØ».M™ˆŠæí¯™w¦å_º²ÓÑfG*¨ªÊþ.%ŸâVn³Fi¶bÊ—K5ï¶ÃÛøxÔf(¯«Ž*˜r˜`Šƒ,YâhÌ…Yši¬Ö'Si»é¾-y –SEU*"ÂA"ÎÖ·úíí…µÓÔ=8“¯4ÓN~žH¡‘¤o#àçÙN:ØñµRæOðJx×±.]˜Câ<Á«¨ú “=-U rJó°íÎ:šmÄä¾Òtÿ#~,UwöŠÞ_šÓÖ¢TT‹UÖ¤qDðôå‰ÔëÂÿÊV׸Þ÷Á™Ð’ æ8$ cS,dn­rG¨¤øz|Úz/ KŸŠdª¯ª¬««@¡UGNFBý—@½íúŒ\i詨²ú» G ;¼†Ì]´ }ïÆ×ß),–9÷|?™Cãj~¿îWsãX¾&Èê&Ì)é2šH2ÈG^iHŽ4=»‹{âxÊM0NPHT›ÿ21Sûƒ‰–Z_SdùŽYÅ©òÙfMÔØXÿ+-øô*yÑ5,TP-=8c:Ó°f%îNøàøšžG4»NŽvxü¾SÿúYúñ?å”1HS̾Àýö#_Äjéòºœ¦z? IŸf5}ZZ8~2 u2X>’Ò›î·PM•½F,™L•ÄED#ƒ0íÿÕ°Nt´4K±êxÈd³”`Ö¶ Ë¸ ^ß쎴rãœ<Ì®•°íœ7>¾eS9̳<—ÔyÆkMK=m!ë" ÔкØjXï¹XØ›€ml"ñCC—gU S;A–#©’ÃY…M4á'Ž6•HQü ’7Úä.x¾+„^GLÏ7*6Ìrÿô3Îê`ËÐ!S0Ò²ONþƒx&§/ªË)'§ª†ŠjéÚ‰ ¼–µžãm$Gµ°Lù§ˆ¼I™äu¹n]ZcŽˆª_ˆ†$ÿò‚Q‡kî#kááøŸà(*¢¦¹æiª…\ñ¬oRK$šËe]J»¤¾:Ù¤²èT2§ýËñ%,I?r½Ÿø'& Í³˜ëæ4T¹œŸL0³TG¨ÚxÕ­¤ͨà·x.–šŠ(h2É¡¥Ìݺ³NLQ1–fï!Ô/¾ÀXqއâùg‹/3QEHÕWj•ò4e‡P‰à_ê)¾øÊ™ÎcVúÍdáâ{yž ˆ‘³ *u‘÷·Í‡ñ*þË‹½­#gˆ4ðÒô¢UÏ6G[•ÊNU™ÍAw,Y#}ö³ØznØQ‘ÊÙgŒóÜŽ²zq5eGñ Xó´LºNÝìÑßn5 á÷⪋)•*©+M™Ô?6Û|¤thä3°Bÿš¶-î=~›c™æÙ½?âæe ôy×ðz© ¦”KA/ÂÔƒFút™®×RIÜvÇVø.ŒÐÈÑ©”#F¯ªæÄ‚GÒà S›UX’9˜FN¥hÛvÜoék}±V-N-2”³'ʯ¼Ì« þe‘¬pÇÖf2±f,FÄ‘Øûb r©U kùózà×I*™Ž¢€oÚÛ⨔©ˆ]P±a¾Ç·íŒ3Mj}zœSwèCŽWÇϽ°»ÆYFeŸøÄ9>T!9†a–ÔSSõŸB $B€“cë†fF“Z®ÚÂÖÚØ‹7Š€ärRgTóMEV¢)R;‚ÈnNà†[˾øëé7'虫Š’^ˆ¦~xGÄ^§«_gÙ5Lrª(Žš-1Ó²ÏeÝÅñgÉtÒ…‚£/ˆA)˜‚a[eï±î}EñVðîG‘ £ÄTtY= 6Y5qV–~¢Mdž,×:®^ýîVå¹t &sŸg4ù|å²Ò±ÝdŽ77•îÇIQ¹M¶Åøç,ÚüR·øQfl«&ßÐ}LŒÑ΀²†V®-„sÕSÁ‘š8LírG2kÓh‰é»ïÍÕnvÃè*â›óiåE(©¸e;ƒ¦Öj„D5V*–îOÿ'õÇ2Y^Ñqå¦ÿ å¶ GŸAžouFU˜Ñ嵿WQM$pÔh ÓvR±ƒÎ9~kàüÅ?©ëÖ¢Žšº‘OEVQ²êT É©QÀµikŸñm¾øêô¡ ¦"’"€Ä‘fù…¾‡¿Äys§¦Šƒ8¥ËQZ™$’Ìà `¦ûn|Ö6?AA¥Ë›ãsV ³„”—ÀÒæÔ0Sd5çõ±ÍNÒütuâZ¢t\„ˆ"…B˰6õç‡^”U×Áiâ¨/NOñš1¨‹ßÊ»«o{ðC’1˜Çÿe”5[W²+ñDüåô+¿„qWÃâÈ3$ðõT9Ek˜^¦³-–)†¦Ö‡Hw@,Nೇ~¶Bù”››arJÜÎ ¶„fÓG5PŒ ƒYXÛ°Ôloîp4’2 ª„aº`±¹{›ñ‰®×ÃR ¡Ú|-fmõ!2e£ñ=SÉ[#.g#åÒ*ÄŽ–™Ê…$^U'¿Þá—ÊæUâ‘¡G"J@ó¨ë¶xïÿ妤øˆ• Õ,r BüâÃI÷Ûúâ ºuªš¦XŒþRT5¿Fï…ÕgXµKbå%ߣèµF¤¿¨ÄTt5ÙÆTSE Ç™µtëè:Â襭ɻ)ßÓf‰fº %AË \–ãõê\êêÖ®ZEÝ~b×$ý/÷š©)©3ZÈs$«¢vD‘æìxãû›a5^d3ji&ø3KÌÝMzðTò?Âl®•dÌéòZ “Q±5HiX†'ˆҢÍ{ÛÌ—%¥Èª!¯Îi²ê"gJz xbAs{@¹oÿ·Íñuy–_SKM–™uD)ÖÉ  ¡ÖâÄÙ…øØqp0ë?ðSÕˆ¡¢‘t´êeÇ£{®=^}LeŠN/”Ž´õ ]•¥š¦OÄYcž61´N»Æ($+rG¯Û¯STÒx‚£2ZZ¼¶¢yÌ+SòÃ×@]Em«·7µ±Ð¢¤¨‹:­Í*þá¤t*ªu©#ó‰ÚæÊ»/¾ ¥Ì$‘Èq·éŒPÏ‹E)¿‰ÅË,a:}µESÄô´õrSÃ;Hå\~^ª1[Zç_oP;\á ÿ†~ÎrÙó ÿ©ë3™t2¨¹.#&ÄbæÜ¾-(Ìh©³ì¶ìÁ²Õ¨IÚ9V3¥yYØÙ‰½¬7ÀòWÓÉ]–åyò-\“|LÆXLS4dì[qp-Á¸ß¾,ÐäZ}5üØ0ÏÊ…|Ù§|á_e•xW*9]>a8©’rÚ UPæÀÅûàïÍ]No_Ló7Z°nì ùcU@˸$ïsßç“J)ª©‘Ò2OB=n½®sÉ·¶"ðˆ2¯å36MC_MGK1€ÉYOÐw•~kÆÖpx7 ^øäè°½N\š‡ïÁ^ÝÎý€ér¡-gˆ²Ó=HJÉ •<ˆ”6±'ß×|[åX`B¢Ü ý°$5QTWÕDZjVX‹ T>×çf·· ãÊö}iä(žç™–%&ÒoŽEœcçŸxƒÂ°/â®SâE¬HtL8E!˜´ŒrIé‚ \Ü ï|^¼I–SfSeÒTÀÓ%4æA` S¤ÛñŶß|W–%Ml™ÍÓ¢šN»u5Û¿­ù`ú dâ’Iú²ÒÆ´òIþ7 .|çË15Ù&Y&aD‘Ë>[¥ B<•#PÓæÙ®XòJžÆÎéH„º,fR0€ßNÖ·¾Øhôo>w[JV$E-?; v¿°ÔoLQMOw©,Çùˆ¾Û .·MlÔ©G÷eY å_"¿œæ”93ÁSšKO-Dß ’̱é˜(ˆ®¿|4´”µùTÕ-+Õ–•"% ¶"ï#F  {ò,8ÁpKô͉I¹‚O¶àí„ÕUÔÐçHÕóIÔT$TQ$=BU#yO „Õ¥îÞ_•w½±4ùqáÙ(»bÃjiû‡f• ñ $rW«)¸ ŽÞ؆ŠW¢J¥µt[èlFÇלev‰%- ºVv°µ¶Á4‘ı™õ` … í|qpäž]dúßâejRÉÇVY™Ašey˜Ž)’JPôõ௜ƮB–µÅlFÞ˜ŽBÕoþ$Ò~·PpÆHéÛà ”ÔÓQÂÔÅ)T‡PHÕ}ï`¼ï…Ôh©WRå;ÚçÓIn1W‰nÉ™ÎOØ£Uæ@yEG±¢üÛ³z›ã̶ŠhóªúƒaO40¢­­çS&£÷ ƒí‰ü?NÏH]¯¤ÈÅI;‘ÿÝñVɳ ·ãVyEKâLÚ§;l²1&Y oƒ§Š&´~[k-&û“¹íŽî-òáŽYªHߦƪ2=¡Ÿã<7P”ådà•cw:9ý<È>˜¶eU"«-§¨Y ~´ v…àkob9¾ø«ÏЦ©«ÒS©*OÄ*I¼fBX‡^×רzß*9£x`TU…ºd"i nÖûã?ƒæxá,3UT×ÐÍŽnq~€“¡.§æ ~ÇËo뤨‚ő勇ÒçÓI-#Õ×¢ê.•L\›HÓk»ßüÕõ:põ,š ê±ßÓ¶Üã—U Ñ?æ¢îmï‹="$qj"Æ÷ÅfG1ͪ?™ â×ÈòÓ+ÎÖÛQ8ÍàŒrJ)søi)I ?UÇü:\µf§•°È±E5ô²ÛÍAm®v¹­þCSKáŠQ_C s3=TQ±`¯v,~kQqpm±"Çg¹ ùŸˆéê«f)F TòfU`V2{‚t±ÿ´ŒI"ÆXWå꾊 ‡÷ÆïÎäâ¥ÝÑdåYf)¹õ%TšorÈ€ï¹ û\þ¸Mâ:È|?áêÜÍÖá$ò‹ìÅœêØ›SÑÂZD-$ñ†“ò«6¢>ä²á>]‹ü9šåuȓԙ©Ä¬ÑÕÈWQè >˜áj0ïÔ(>ßû3$ã»7–ûì'ÀsË7€rj™™z•‰1'k—:‡?÷ažS9H Ëá#E$+>Ö?{ˆ²š2¬«/ÉÔjŠ‚š(T7ÿëPý†øƒ04–h/ÂPÏPoÛJí¸²ìËÇѯÀ9¦à–ß’x鞟Ã…d“ÂPUÈd&Á‚ÀžÛ I˜ÏI𤗧«£‘“afÄ0ö'õĉJdü?Ì¡ëi©š%opöF¸ô³,ª‚X²\š$muPÓ@†Ë+ˆÒßåÛQïåßâpŽ,ŽIòéšfÚüe‚÷o®¤ÄeAæxµH¡ÀØ¡$~÷·Òødò­€Üííƒjhä¨Éê(d˜A<ôÒD$˜ÙÖ×þÿaŽg…)FS’¾xþåXÔ¼×^ÀË_Y¬èé—J<‘;^Ûù…ø½‰öÃvc ½†ûÛ ª ÙME4’$PèêI»µ—’{“ƒiËje ÞÆãí‹!’jJ2•Õþ¥rRÚÿ}”ïÔ$™…^çTeKÈ  › ûZí‹…)écÊR¾H›âëÕeõXÜ‘Ïa¨â©›ÓÇQãd1„"¨ŽöÖ¶c¹çL^z+ÑŠ*T"4@¨£°Ãûc›¤É/6sŠç…Lͤ‹óg9}(‚²¦‚|ú‡.F&xÓâYXˆ÷‡¯›lo–etÙloCGñ©Q,ÒKQ!‘‹¨›Ûpì±íNIEünƒÄCZÖCA%¶ÚãvŽKpcÛÓSzá†V‹_ôÂ\êï}ïnØõ°Ó¥7¾­ÓÙé¹l÷ÿà“ÅÓ˜( VêÇ%0k•}1Ôm`6#M÷\V]fc ŽzÇk0&•V-ö`MùëĹ´|NäÁgUÌçËû/ï€ihêž )Ôjdc¾ëæíÀ7Ç™ñLù笔qÉíêr5¹eæì‹ë§‚©z¾!­Í¥‰Äp¢Ã8ù˱_k¿¾øŠM˜`¨IÁ‰% Yp#‚©’8 “À¯0:žY•>Ü㳬Œ4Þ±'Ù¾XüŒ;S*ÙUZ·Šªr÷–‚ðeú’0¡ªS&£¨|«ºùM‰ ZÇÿÉ”Px©+rŸ øeóVªãj(ZyĬRF¢Ì.Úb¹Ø\‹ã f2Ôxªº#O i9šDu‚Ï ò…gc½´¨z*d4ß‹â£,ƒ4Ìê¨:RV%=b!¥…¢S¤ÈKFÄ–$5‰$¨O Ã,rŽ,}mWïß¡V›œÔaÕ~èºøv‹Ä•ßQœf•4U•-€Ë†D[°%%Rû‹mï~m‹¢h¯£›,Íåx™*!F%^6ºß}ìG鸾ØQSIM+Óæfª\ºiM[Æî"ÉR:’«rÃIÕbEï…y>c˜ËŸÖ½Nq•VVšt‰Ýu™YJŸò›cµ¤þ\g>íÿ.;™´ËçZ9%¬£’‡.§0«$Å¿/ù®x€/¿ ¼C›ærxª::FËゞš¢ªY¤b "§‘Ç Z÷'Øp7ÃJúª<»ÄC“¨9Žu´’0Õ FƒKH ‡E¼Ä’/|•TŖ屸Ц²¡je£š¥ø›Îí#S#¤I ô&øÇ-&+Ûu\’Xñ¼Mß?šÏxfާ3¦ŠÆ/ùm}#sî.¥ã(J‘q¨ŽØ 1I¢O1EÕ©‡ø…ˆ°ÿ}±7€|gá¼Ö´äÙfd²Î°õXI¤³¶Åä7Þãkßì0ŸÅçù‰úù= Õ´ÎJ¥ZE±õ6ÞƒÏÒ,˜¡(;çš9š¨Fxã(rXrzZÇYs ä:ƽ;]y¿ïo¶Í樧§ªª‚ŠjÙ!¤Zh­®[J­Í®ml–f’E’ÐE6Y,m;˜ÊS¥Ö+“f ØÇm¯ƒÅO"T•$©±ÓßmïŒú9COŽ/õ-Œ!µ$þ¢Ì(Фô¼’Ï©¢""AžCcmÎæÆÞöà ·=¬ªÊ¨â«Eޝ«•¥Œ¨–3ÌP>RHàñ¿k éKŠá€,TÀ°ÝE¸Qņ£sL³?y¥¯ŠNšR8žÀ1MË-¯¶ÞQÛ¾&›Q<d1}”ÚäXNQMcêÝ ÌΞ*œÌÅwª †Þ]ÔÙG¸ÿLG”æ âß)¦ª®¨˜Fµ%¤ƒL*¥ŠGÒ5n¾§Q,²æìa 5€Û+X’OÜŒ[)¨é×-Šâ"Dl7q‹¼/ñO3ˆÚe“wbqþŽF÷°ß4˜£›2Å7Izˆã¹Ç‘'€2¼Û 9a–­==EÑÑH¯¢«å)ëƒüNùFiIáèh^D§¤kÔX$k¥”(Ò6¹»€Ü †-ÕRfñ½ZE!Š Ùi¥/åè˜Ö%—p7Rx àšqCF%hÚòLLŒ ¹; ½»c¯/ Ç;—™QìÐð(Ímt—'µ” WA9F ¨5×Ë¥®-ï¶A“Ë—ÓQGY]\ѱE0ÓT‹íeØÞøW[ŸË[â˜(fšHòèæÉ_#J~@ÏÍÅÔûlyÅÊ(RH0»FÖQo”ãN_#Q, ý~ôZœu Åz”Ÿe¹}8¡«¯øùÍm]I›ÏòI;º¯›*•_¶Ûa¦_áÉòÚ<Ýà¥J¹ëëª+)\c!°M!~÷Á>âÎëaœ–”6÷ù™ô±ûáìë^[,R!1¼eC$¸¸Ü`htpË,œ6Û¯ ˜1'çÛU9›Sº¸‰VÀñå#oN1TÊü2|)•R䋙͘SR‚”ÒOn¢D’6?ͤYAôy“AU—äÐQÇ$3TBÌ‹#"¹Ð¬NþUÚýíïjŒÏP±Õt–e°~™Ù›¹^qÊñHÂ8¤”{’¯ðfÔ¸äpÊÖ _N’>ÅN<­s3V$I,±ÂÁDŒUEí¹öÏ–0Éå_¢3ä©ãŠ~ƒŒ¡©Ý3ºjR{{a'äY2™Ú®º:Zuu ,— —`­¸ÞØŠ÷' u©‘Ä13³ôÈPªT¾çæ® ÎbŠ»-žœ7äÕEmz°"÷í¸³Fzm*^ÃK"Ú¢úù rܲ›&ÈirêEÓbRÖßS3ßÞäþøM™øw$˼O&e[OO4ù¬PÓÕüLß”ñ™4ôîokÞÖï°²WUÃ6uMÉô‚¬Án{ z÷ÛÓ ³ ™ÌsÕÕÕS¥=\kÀ¢çÌ[IÕu±Õn8ã{c‡¨yÏ#¾X¸¼¹j*¸ô,RQRå•£/¥ˆCKOG \Ø Pón0³1G†u‘f1X3à882j™k4ST<ÓÃ9Œ³Æ#m'u½¶ ¯a{_gó¼rÇ.•ºj(I·òý…íƒ«Åø©F|+ãè&xÅÍÅð·d•ó&§GS ž"Yoå}gpl-§o\4Ìé–§)–ʨ³Vˆ‡JjÙtÂöØ–¸+°$îGIP’g“VH)éèT&»8X€nàžûs‹ ÏIWN&†JzÚ*„(ÅçŒÇ Ãî mÁÎXŒ³z{°Ç´Š `X|ç¶3Žûç_•?uùeÚ%‡j™ÀØjÐcŸ~+TÏC—UÕRHbš:j‰QÇ!Ò7*~ÄöÆc1ÖÕ$ÒÿÛõ0æê?R½ÿ "μEøAšçY„••“ÔH$•€¿1Æà8QŽ‡á ¦—*ž9eyÚˆcÖu‹#.w6c1˜Åü鯜‰oÞÆ5îÁa[ílAM±6õÆc1‘;|þø'õÏNQ–f쯙ÐÁVÔìL-"Ü¡Ûqé…^aUšæ²TE ’Ñ:ÃO+D½HÑ£GemV,ÄØœf3›ÂGé/Ì׋¤kã,³(ð/‰óŒºn…u%ÒA.ÚPlAQ†ž†6ðÅc.ªŠºh¦žBnd¨»sëŒÆcg‚$ô*þ©lò¾ñÃ&P±µd&×öÆc1®Bm{¢‰º‹£!ÿ­õ8IT‚ibŽáZWfÞ÷'¹?sŒÆcâ®´òûÿ4QŸì/ߪ=„ ÏùpÛ/U¡ ƒ{q˜Ìr¼ 5~ýQ~0™•YH`Àµ ª«¤±Æc1èuðÉ×5ú–¿²'[·ˆ* &éK]øšø2¡˜Ò¾çƒŒÆcÎaoÊŸÞe›vþñm  ¹Ý­ö¶&Ψéžlªv…L±HìÜ ¯ô$c1˜£EÎß±^›œlŽ`µ¶°Ã¾”ÃŒšZÆH6ãlf3üygký?©fÌ€k)¡Š9¡D²1f ’nXê'rp¹ãA]VÁ@=8«ã1˜«W¾¿r¬énþÿ©g¢i"4ŒP| åt)«Ìé)Ý*«+sG¨s;°sñ@|¤Ã`Æc1ëÒÿ§‚ù#tz-Ù¾_IPÉ,±@ª.Ê3X†€Ãë{vÆðe´u9†‚ŽhË+$ú“ëŒÆcáÓuÍ"N+º+{æõ$ò'$}zC r`57°Æc1âp6µËÿfq´¯ùïïæ_þô£ÿþRÿú˜ƒ3v†‚c鱯c1è|Yµ—'Ö?‘ÖÉö×ü ë6IæØw–K!Ño.Ž-ŒÆcá²qÌé˜tî³?¸¯øƒ,+»5S1Ôå·Ò=N!ð̲Kâ,Õdb©ÄwþPCûã1˜Ñªþ¤>¬wýXýÿC%kwb—?øœIà×hëe¦Kº+&›˜»Üã1˜Ëƒþ÷ßù™0¿ú˜ý?PœÓËW-¶Øàj Jjêÿ…«…&Ñu£ †±&ÇÔl6ãŒÅºdž¾)û‡*¼é?pÿ36OP„ùX”#ü¥.F–1Qx|ÆlED ~vé°þ˜Ìf:ž+ÿs#TÿªÆr‹•¿­±*ÿûË6• ·ä&3Žf‘ÿÓÏÿeù1¢¾'÷~£jUWG,!…®?Ê0¶OÿjmûߌÇKU°Aü‹sÿ§ê&§‚¼1g,jõ…`S1ù¬Öý¿\ZèAÈ1˜ÌSáQ^n'^‹õtþKõ$«ÞhT€A'cœ— í°÷Æc1èòÿý_ï¤_´s|ÖÏŠ(œ‚Z¢¦g”–'S#*§èÃú%V­2vÔÆÿsŒÆcůêKêŽ%-ëêkã™*,©cm!ꔵ»•‡è@8Æ’É%Dѵ¤C©M¯b3¾1ý&¿õüZž¤¾Ÿ‘Gü7&ÎX#:cžä”½NxÃ/¢ogþ24ÑŒÿÃTO”×(Ó$¥ÖÛiYÕ¡Ã-÷¶3ŽÖŸ\+ÿUVE_øŒ29ž¶Ÿ §­ÓUvDeªYÔH&biïª÷½úqÆÿLY–Ð'ŒòzØé"Ž¡`D é²×"ÿíÌf,ÓÿÚ¿ß©n•|R_!Ô”´Ë+Öˆ#ø†êÄdÓ¾’¬Ä~¢ÿ¯©Ç-¨¤ƒ0ñ†O–U¡jFŠedV(YZW¸%H$l6'¶3†È•/ß±VOè 2¬â¿#ÿˆ|¯ÁY;ÃAáýGOO lY‚êc¿$œtßÄfh²™*âwIà™Ll¬E®TñÁàsŒÆc6·Œ Œyat<ȉh£v7/N¬ÞäØßT¨ÖÛkc1˜£:þF?«þ’É+‰ª%Õç Eý‹[úbÅ4):Öªž»RôË$i °±Û¹íŒÆcŸá½dûÿ1|9ý¡6C=\…–äJqq”鉭µ†3Ž¿€$´²h»ÃÕce$%š¼±'þnN~§TM"çYE( ÁS3$ÈTà! ûŒÆcÎxõ¾ÿÔ˧ûýú‡øb†–ƒÂttô‘tâ:‹1õ8ÆòŠÆ2 *}9Æc1ÝñERÓô6æí~ýÎ|[Q[â¿áUf)¨î* 4Ks!ÔKµÎàr{bùãjªšZœŒÓÏ$]Jäôµƒ)µÁÌfgN¡Vf„FŠ zh˜ØRIûã1˜§Âÿ¡36ŸìHÀša£\h‚TVÜ+†>aèq˜Ìf+‹à–ÿÙbobcat-5.09.01/documentation/man/readlinehistory.yo0000644000175000017500000001660014050437223021311 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::ReadLineHistory)(3bobcat)(_CurYrs_) (libbobcat-dev__CurVers_) (Editing input lines) manpagename(FBB::ReadLineHistory) (std::streambuf offering line-editing and history) manpagesynopsis() bf(#include )nl() Linking option: -lreadline -lbobcat manpagedescription() The bf(FBB::ReadLineHistory) object offers access to the history maintained by bf(FBB::ReadLineBuf) and bf(ReadLineStream) objects. The latter two classes use Gnu's readline library to allow editing of input lines. The accumulated history of these objects can be accessed from the bf(ReadLineHistory) object. Since Gnu's readline library maintains global data there can only be one history. The bf(ReadLineHistory) class is therefore, like bf(ReadLineBuf) a singleton. (Gnu's readline library does, however, offer functions allowing programs to use multiple histories. So it would in principle be possible to design a non-singleton tt(ReadLineHistory) class. Since programs normally only interact with a single terminal, there is probably little use for non-singleton bf(ReadLineHistory) class). The bf(ReadLineHistory) class encapsulates history access. It offers limited facilities: either forward or backward iterations over the history are offered as well as reading and writing the history from/to streams. The content of the history lines and --if defined-- the timestamps of the lines in the history can be obtained using iterators defined by bf(ReadLineHistory). includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(NESTED TYPES) The class bf(ReadLineHistory) defines the following nested types: bf(HistoryElement) The iterators made available by the bf(ReadLineHistory) object provide access to a bf(HistoryElement) object. These objects can be copied and assigned to each other, but user programs cannot otherwise construct bf(HistoryElement) objects. The class bf(HistoryElement) has but two members: itemization( itt(char const *line() const) returns the content of the history line to which a bf(ReadLineHistory) iterator refers; itt(char const *timestamp() const) returns the timestamp (if defined) of the history line to which a bf(ReadLineHistory) iterator refers; ) bf(const_iterator) and bf(const_reverse_iterator) The iterators returned by members of the class bf(ReadLineHistory) are input iterators, pointing to bf(HistoryElement) objects. As they are input iterators modification of the history elements to which they refer is not allowed. The class bf(const_iterator) allows iterations from the first to the last history element, the class bf(const_reverse_iterator) allows iterations from the last back to the first history element. The iterators can be incremented, compared for (in)equality and offer tt(operator*) and tt(operator->) members, offering access to, respectively, bf(HistoryElement) objects and their addresses. manpagesection(CONSTRUCTORS) As the class bf(ReadLineHistory) is a singleton class, there are no publicly available constructors, nor are assignment operators available. manpagesection(STATIC MEMBER FUNCTIONS) itemization( itb(ReadLineHistory &instance()) A reference to the bf(ReadLineHistory) object is returned. If any history has been accumulated it can immediately be retrieved. Using this static member will not affect the way the bf(ReadLineHistory) object handles timestamps when saving or retrieving history lines. When initially constructed the tt(ReadLineHistory) object assumes that timestamps are not used. itb(ReadLineHistory &instance(bool useTimestamps)) A reference to the bf(ReadLineHistory) object is returned. If any history has been accumulated it can immediately be retrieved. The tt(useTimestamps) parameter defines the way history lines are read from or written to a stream. When specifying tt(true) the history inserted into a stream will include timestamps (which may be empty if no timestamps were recorded). Likewise, when extracting the history timestamps are extracted too (which may also be empty). When specifying tt(false) no timestamps are read or written. A mismatch between the actual content of the stream from which the history is extracted and the tt(useTimestamps) parameter will results in unexpected behavior. ) manpagesection(MEMBER FUNCTIONS) itemization( itb(ReadLineHistory::const_iterator begin() const) An input iterator pointing to the first history line is returned. itb(ReadLineHistory::const_iterator end() const) An input iterator pointing beyond the last history line is returned. itb(size_t maxSize() const) The maximum number of lines that can be stored in the history is returned. After collecting a history of tt(maxSize) lines, the next line entered will cause the initial history line to be removed from the history, making room for the next line to be added at the end of the history. itb(ReadLineHistory::const_reverse_iterator rbegin() const) An input iterator pointing to the last history line is returned. Incrementing this iterator will access the previous line in the history. itb(ReadLineHistory::const_reverse_iterator rend() const) An input iterator pointing before the first history line is returned. itb(ReadLineHistory &setTimestamps(bool useTimestamps)) xThe current status of the timestamps usage is set according to the value of its parameter. When tt(true) inserting and extracting history will include the timestamps. No timestamps are inserted or extracted when tt(false). It returns a reference to the updated bf(ReadLineHistory) object, allowing constructions like (assuming the availability of tt(ReadLineHistory &history)): verb( cout << history.setTimestamps(true); ) itb(size_t size() const) The number of lines currently stored in the history is returned. itb(bool timestamps() const) The current status of the timestamps usage is returned. When returning tt(true) inserting and extracting history will include the timestamps. No timestamps are inserted or extracted when this member returns tt(false) ) manpagesection(OVERLOADED OPERATORS) itemization( itb(std::istream &operator>>(std::istream &in, ReadLineHistory &his)) The history available at the tt(in) stream is extracted as the current history. The existing history is removed first. The tt(useTimestamp) status determines whether timestams are extracted (if tt(true)) or not (if tt(false)). A mismatch between the actual content of the stream and the tt(useTimestamp) status will result in unexpected behavior. itb(std::ostream &operator<<(std::ostream &out, ReadLineHistory &his)) The current history is inserted into tt(out) stream. The tt(useTimestamp) status determines whether timestams are inserted (if tt(true)) or not (if tt(false)). ) manpagesection(EXAMPLE) verbinclude(../../readlinehistory/driver/driver.cc) manpagefiles() em(bobcat/readlinehistory) - defines the class interface manpageseealso() bf(bobcat)(7), bf(readline)(3), bf(readlinebuf)(3), bf(readlinestream)(3) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/x2a.yo0000644000175000017500000000763014050437223016601 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::X2a)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (X-to-ASCII conversions) manpagename(FBB::X2a)(Objects performing x-to-Ascii conversions) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() bf(FBB:X2a) objects convert values of any (insertable) type to text. The returned text is automatically made available as a standard bf(C++) string. tt(X2a) was developed well before the tt(std::to_string) function became available. In many cases that latter function can often be used instead of using tt(X2a): it is available for standard types. However, if another type must be used then tt(X2a) may still come in handy. includefile(include/namespace) manpagesection(INHERITS FROM) bf(std::ostringstream) manpagesection(CONSTRUCTORS) itemization( itb(X2a(T const &value)) In this constructor tt(T) may be any type that can be inserted into an tt(o[string]stream). itb(X2a(double value, size_t behind)) Double tt(value) is truncated to tt(behind) digits behind the decimal dot. If a value doesn't occupy tt(behind) digits behind the decimal point, then missing digits are added as tt(0). For example, a value of 7.1, will be displayed as 7.10 if two digits behind the decimal dot are requested. A value of 7 will be displayed as 7.00. itb(X2a(double value, size_t width, size_t behind, std::ios::fmtflags flags = std::ios::right)) The value is displayed over tt(width) character positions, extending the amount if the value so requires. The converted value is placed right-aligned into the field of tt(width) characters. ) The copy constructor and the copy assignment operator are available. manpagesection(STATIC MEMBER FUNCTION) itemization( itb(bool lastFail()) This member returns tt(true) if the last conversion failed (i.e., the object's tt(fail()) member returned tt(true) and returns tt(false) otherwise). This member allows checks on the success of the extraction/conversion using anonymous tt(A2x) objects. The member also returns tt(true) when no conversions have as yet been performed.nl() Note that this member is a thread-unsafe em(static) member: in a multithreaded program locks may be required to ensure that the proper conversion result is inspected. ) manpagesection(MEMBER FUNCTIONS) All members of bf(std::ostringstream) are available, as bf(FBB::X2a) inherits from this class. In particular tt(ostringstream::str()) can be used to obtain the content of an tt(X2a) object's text buffer. manpagesection(OVERLOADED OPERATORS) itemization( itb(operator std::ostream &operator<<(std::ostream &ostr, X2a const &x2a)) This conversion operator inserts the textual representation of the tt(x2a) parameter value into the provided tt(ostream). itb(operator std::string const() const) this conversion operator returns the information stored inside the bf(FBB::X2a) object. ) manpagesection(EXAMPLE) verb( string is(X2a(5)); // initializes `is' with "5" string ds(X2a(5.25)); // initializes `ds' with "5.25" cout << X2a(7.0 / 3, 4) << endl; // display a value using 4 digits behind the // decimal dot. cout << X2a(7.0 / 3, 8, 4) << endl; // display a value over 8 positions, right // adjusted, 4 digits behind the decimal dot. cout << X2a(7.0 / 3, 8, 4, std::ios::left) << endl; // display a value over 8 positions, left // adjusted, 4 digits behind the decimal dot. ) manpagefiles() em(bobcat/x2a) - defines the class interface manpageseealso() bf(bobcat)(7), bf(a2x)(3bobcat) manpagebugs() none reported includefile(include/trailer) bobcat-5.09.01/documentation/man/ifilterbuf.yo0000644000175000017500000001377214050437223020246 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::IFilterBuf)(3bobcat)(_CurYrs_) (libbobcat-dev__CurVers_)(Filtering Input Stream Buffer) manpagename(FBB::IFilterBuf) (Filtering stream buffer initialized by a std::istream object) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() bf(FBB::IFilterBuf) objects may be used as a bf(std::streambuf) for tt(std::istream) objects, filtering the information produced by those objects. The class tt(IFilterBuf) was designed with the bf(openSSL BIO) (cf. bf(bio)(3ssl)) in mind. Since the BIO concept was developed in the context of the bf(C) programming language, BIOs do not support bf(C++) streams. Nonetheless, the concept of a filtering device is an attractive one, and is offered by the bf(FBB::IFilterBuf) class. In addition to filtering, bf(IFilterBuf) offers flexible internal buffer management: derived classes can push back characters until the beginning of the internal buffer has been reached, but may then continue pushing back characters until the internal buffer has reached its maximum size. This maximum size is defined by the constructor's tt(maxSize) parameter (see below). The class bf(IFilterBuf) is an abstract base class. It is used via classes that are derived from bf(IFilterBuf), implementing its pure virtual tt(load) member (see below at bf(PRIVATE VIRTUAL MEMBER FUNCTIONS)). includefile(include/namespace) manpagesection(INHERITS FROM) bf(std::streambuf) manpagesection(MEMBER FUNCTIONS) All members of bf(std::streambuf) are available, as bf(IFilterBuf) inherits from this class. manpagesection(PROTECTED CONSTRUCTOR) itemization( itb(IFilterBuf(size_t maxSize = 1000)) This constructor initializes the streambuf. While the streambuf is being used, its internally used buffer is gradually filled. It may be filled with up to tt(maxSize) characters, but the actual number of characters that is stored in the buffer is determined by the member tt(filter) (see below) and by using the member tt(streambuf::sputbackc). ) Copy and move constructors (and assignment operators) are not available. manpagesection(PROTECTED MEMBER FUNCTION) itemization( itb(void setBuffer()) This member initializes the base class's buffer pointers (i.e., tt(eback, gptr,) and tt(egptr)) with the initial range of characters retrieved by tt(filter) (see below). Derived classes do not have to call this member, but if they do they should only call tt(setBuffer) once from their constructors. Once tt(setBuffer) has been called, the tt(peek) member of the tt(std::istream) that is available to bf(IFilterBuf) objects can be called to inspect the next available character, even if no other stream operation has as yet been performed. If it is not called by the derived class's constructor, then tt(peek) returns 0 until at least one character has been retrieved from the tt(istream) object. ) manpagesection(PRIVATE VIRTUAL MEMBER FUNCTIONS) itemization( itb(virtual bool filter(char const **srcBegin, char const **srcEnd) = 0) The tt(filter) member is declared as a pure virtual member: derived classes em(must) override tt(filter) with their own implementation. Derived class objects are responsible for obtaining information (in any amount) from the device with which they interact. This information is then passed on to the tt(IFilterBuf) via two pointers, pointing, respectively, to the first available character and beyond the last available character. The characters indicated by this range are subsequently transferred by the bf(IFilterBuf) object to its own buffer, from where they are then retrieved (or to where they can be pushed back) by the application. The tt(filter) member allows implementations to filter and/or modify the information that is obtained by this member. The bf(EXAMPLE) section below provides an example filtering out a configurable set of characters from a provided tt(std::istream). Bobcat's classes bf(ISymCryptStreambuf)(3bobcat) and bf(IBase64Buf)(3bobcat) provide additional examples of classes derived from bf(IFilterBuf). The tt(filter) member should return tt(false) if no (more) information is available. It should return tt(true) if information is available, in which case tt(*srcBegin) and tt(*srcEnd) should be pointing to, respectively, the first character and beyond the last character made available by tt(filter); itb(int pbackfail(int ch) override) If tt(IFilterBuf's) internally used buffer has reached its maximmum size then EOF is returned. Otherwise, tt(ch) is inserted at the beginning of the internally used buffer, becoming the next character that's retrieved from the object's buffer; itb(std::streamsize showmanyc() override) The sum of the number of not yet processed characters in the internally used buffer and the number of not yet processed characters returned by the latest tt(filter) call is returned; itb(int underflow() override) Once the internally used buffer is empty tt(filter) is called to obtain a new series of filtered characters. If tt(filter) returns tt(false underflow) returns EOF. Otherwise the series of characters returned by tt(filter) are transferred to the tt(IFilterBuf's) internal buffer to be processed by the tt(std::istream) that's initialized with the tt(IFilterBuf) object. ) manpagesection(EXAMPLE) Here is a class, derived from tt(IFilterBuf), filtering out a predefined set of characters. It is used twice to filter digits and vowels, illustrating chaining of bf(IFilterBuf) objects. verbinclude(../../ifilterbuf/driver/driver.cc) manpagefiles() em(bobcat/ifdbuf) - defines the class interface manpageseealso() bf(bobcat)(7), bf(isymcryptstreambuf)(3bobcat), bf(ibase64buf)(3bobcat), bf(ofilterbuf)(3bobcat). bf(std::streambuf) manpagebugs() None reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/cininserter.yo0000644000175000017500000001377514050437223020443 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::CinInserter)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Executing Child Processes) manpagename(FBB::CinInserter)(Runs external programs reading standard input) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() The bf(FBB::CinInserter) class offers a basic interface for calling external programs (so-called child processes) reading their standard input streams. The standard output and standard error streams of the child processes by default are not handled by ttCinInserter) objects. The child's standard input is provided through the tt(CinInserter) object: information inserted into an tt(CinInserter) object is forwarded to the child process's standard input stream. The tt(PATH) environment variable is not used when calling child processes: child process programs must be specified using paths. tt(CinInserter) objects may repeatedly be used to execute the same or different child processes. Before starting the next child process, the current child process must have finished. Arguments passed to child processes may be surrounded by double or single quotes. Arguments surrounded by double quotes have their double quotes removed, while interpreting any escape-sequences that may have been used within. Arguments surrounded by single quotes have their single quotes removed, while accepting their content as-is. In addition unquoted escape-sequences may be specified: those escape sequences are evaluated and replaced by their intended characters (e.g., tt(\100) is converted to tt(@)). When information of undetermined size or structure must be inserted into a child process then the child process cannot determine when to stop. This creates an interesting problem: the child process starts, and the parent process must wait until its child process has finished processing its input. But input can only be forwarded to the child's input stream after the child process has started. To solve this problem tt(InterterFork) offers an overloaded tt(execute) member, passing information to the child process via a separate thread. includefile(include/namespace) manpagesection(INHERITS FROM) bf(FBB::Exec) (private), bf(FBB::OFdBuf) (private), bf(std::ostream). manpagesection(CONSTRUCTOR) itemization( itb(CinInserter(size_t bufSize = 100)) A tt(bufSize) argument may be specified: it defines the internal buffer size used by the tt(CinInserter's) streambuf. By default the stdandard output and standard error streams are not handled. itb(CinInserter(Mode mode, size_t bufSize = 100)) The tt(mode) argument must be tt(CinInserter::CLOSE_STD). It indicates that the standard output and standard error streams are redirected to tt(/dev/null): any standard output generated by child processes is ignored. A tt(bufSize) argument may be specified: it defines the internal buffer size used by the tt(CinInserter's) streambuf. ) Copy and move constructors (and assignment operators) are not available. manpagesection(DESTRUCTOR) The destructor ends the tt(CinInserter's) child process, if it is still active. manpagesection(MEMBERS) itemization( itb(void execute(std::string const &cmd)) The argument specifies the command to execute: the command itself must be specified as a path (the tt(PATH) environment variable isn't used). This member immediately returns, after which information can be inserted into the tt(CinInserter) object which is then forwarded to the childprocess's standard input stream. See also the description of the next (overloaded tt(execute)) member function. Once all information has been inserted, the child process's standard input stream must be closed. This is realized by either calling tt(stop); by calling tt(execute) once again; or by ending the tt(CinInserter) object's lifetime. Arguments specified in the tt(cmd) string are passed to the child process, and may optionally be specified using single or double quotes, as described in this man-page's DESCRIPTION section. itb(bool execute(std::string const &cmd, std::string const &text)) This member is used to forward a limited amount of information (contained in the tt(text) parameter) to the child process specified at tt(cmd) (defined identically as the tt(cmd) parameter of the previous tt(execute) member). This member returns tt(true) if the child process's exit value equals 0. itb(int stop()) This function can be called after all information has been inserted into the tt(CinInserter) object to close the child process's standard input stream. It is not required after calling tt(execute(cmd, text)), or when calling tt(execute) again, or when the tt(CinInseror) object's lifetime ends. This member returns the exit code of the last executed child process, which may also be obtained from the next member: itb(int ret() const) Once a child process has finished this member provides the actual exit code of the child process. Its value equals -1 before the first tt(exectue) call. ) manpagesection(PROTECTED MEMBER) itemization( itb(Pipe &childInPipe()) If derived classes need to override the redirections-members then they probabaly need access to the pipe read by the child process. This member provides a reference to that pipe. By default the parent process inserts information into the pipe, while the child process reads the inserted information from the pipe. ) manpagesection(EXAMPLE) verbinclude(../../cininserter/driver/driver.cc) manpagefiles() em(bobcat/cininserter) - provides the class interface manpageseealso() bf(bobcat)(7), bf(cerrextractor)(3bobcat), bf(coutextractor)(3bobcat), bf(execl)(3), bf(exec)(3bobcat), bf(fork)(3bobcat), bf(pipe)(3bobcat), bf(process)(3bobcat), bf(stdextractor)(3bobcat). manpagebugs() None reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/ofoldbuf.yo0000644000175000017500000002044414050437223017705 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::OFoldBuf)(3bobcat)(_CurYrs_) (libbobcat-dev__CurVers_)(Fold long lines) manpagename(FBB::OFoldBuf)(Folds long lines written to ostream) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() bf(FBB::OFoldBuf) is a specialization of tt(FBB::OFilterBuf) folding long lines written to an tt(std::ostream) object. The tt(OFoldBuf) writes the (folded) lines to a second tt(ostream) (the em(destination stream) which is either used by or opened by the tt(OFoldBuf) object). Internally the tt(OFoldBuf) defines its actions using a little finite state automation distinguishing three states (INDENT, WS and NON_WS) and three character categories (tt(\n), other white space characters (space), and non-space characters). The nine combinations resulting from these two sets are discussed below. tt(OFoldBuf) objects will never fold lines in the middle of series of non-blank characters (called a `word' below) but will always break a line at a white space character. The resulting lines will always appear to the right of a configurable left margin and to the left of a configurable right margin. There is a somewhat pathological exception to this: if a word is too long to fit in between the margins then the word will exceed the right hand margin. The indentation used for the left margins is configurable to either blanks (the default) or tabs. When tabs are used the width of a tab character is configurable, using a default of 8 positions in the destination stream. What follows is a description of the em(Finite State Automaton) (FSA) defining what happens when various character types appear at its three states. The phrase `... is written' means that the described information is written to the tt(ostream) used or opened by the tt(OFoldBuf) object. tt(OFoldBuf)'s initial state is tt(INDENT): DEFINEMACRO(rw)(3)(row(cell(ARG1)cell(ARG2)cell(ARG3))) table(3)(lll)( rw(State)(char.)(description) rowline() rw(INDENT) (\n) (a new line character is written) rw() (space) (the indentation is set;) rw()()(the space character is added to the indentation;) rw()()(next state: WS) rw() (non-ws) (the character is added to the currently stored word;) rw()()(next state: NON_WS) rowline() rw(WS) (\n) (a new line character is written;) rw()()(stored white-space is erased;) rw()()(next state: INDENT) rw() (space) (white space character is added to the currently) rw()()(stored space characters;) rw() (non-ws) (the character is added to the currently stored word;) rw()()(next state: NON_WS) rowline() rw(NON_WS) (\n) (stored white space and word are written;) rw()()(a new line is written;) rw()()(next state: INDENT) rw() (space) (stored white space and word are written;) rw()()(white space character is added to the currently) rw()()(stored space characters;) rw()()(next state: WS) rw() (non-ws) (the character is added to the currently stored word;) rowline() ) includefile(include/namespace) manpagesection(INHERITS FROM) tt(FBB::OFilterBuf) manpagesection(ENUMERATION) The enumeration tt(TabsOrBlanks) is used to select tabs or blanks when writing the indentation. The default is blanks. When tabs are selected the display width of tabs characters can be configured as well (using the default of 8 positions for each tab-character). The enumeration has two values: itemization( itb(BLANKS) The default, indicating that the left margin is specified and written as a number of blanks; itb(TABS) Indicating that the left margin is specified and written as a number of tab-characters. ) The enumeration tt(TrailingBlanks) is used to configure the tt(OFoldBuf) object with respect to any trailing blanks that may appear on the final line. These trailing blanks can appear on the final line it it is not properly terminated with a newline character but instead ends in white space. By default these white space characters are ignored, but they may be kept as well. The enumeration has two values: itemization( itb(IGNORE_TRAILING_BLANKS) This indicates that trailing blanks appearing at the final line if it is not terminated by a newline should not be written to the destination tt(std::ostream). This is the default used by tt(OFoldBuf) objects. itb(KEEP_TRAILING_BLANKS) This indicates that trailing blanks at the final line if it is not terminated by a newline should be written to the destination tt(std::ostream) ) manpagesection(CONSTRUCTORS) itemization( itb(OFoldBuf(size_t leftIndent = 0, size_t rightMargin = 80, TabsOrBlanks tob = BLANKS, TrailingBlanks tb = IGNORE_TRAILING_BLANKS)) This constructor initializes an tt(OFoldBuf) object but does not associate it with a destination stream. It can also be used as the default constructor. itb(OFoldBuf(char const *fname, size_t leftIndent = 0, size_t rightMargin = 80, TabsOrBlanks tob = BLANKS, TrailingBlanks tb = IGNORE_TRAILING_BLANKS)) This constructor initializes an tt(OFoldBuf) object and opens (using tt(std::ios::out)) the destination stream using the name specified as its tt(fname) argument. itb(OFoldBuf(std::ostream &stream, size_t leftIndent = 0, size_t rightMargin = 80, TabsOrBlanks tob = BLANKS, TrailingBlanks tb = IGNORE_TRAILING_BLANKS)) This constructor initializes an tt(OFoldBuf) object and uses as its destination stream the tt(std::ostream stream). ) The destructor writes any buffered information to the destination stream and will then flush the destination stream. Copy and move constructors (and assignment operators) are not available. manpagesection(MEMBER FUNCTIONS) All members of bf(FBB::OFilterBuf), in particular its tt(out()) and tt(reset) members are available, as bf(FBB::OFoldBuf) inherits from this class. itemization( itb(void setMargins(size_t leftMargin, size_t rightMargin)) This member can be used to modify the left- and right folding margins. Note that the left margin may also be modified using the tt(FBB::lm) and tt(FBB::mlm) manipulators. itb(void setTrailingBlanks(TrailingBlanks tb)) This member can be used to modify the currently used tt(TrailingBlanks) parameter. itb(void useBlanks()) This member can be used to select blanks to be used when inserting left margins. itb(void useTabs(size_t tabWidth = 8)) This member can be used to select tab-characters to be used when inserting left margins. The second parameter is used to specify the display width of a tab-character. ) manpagesection(STATIC MEMBER FUNCTIONS) itemization( itb(size_t leftMargin(std::ostreambuf const *buffer)) This member returns the current left margin setting of the tt(OFoldBuf) object passed to it as its argument. The member defines a tt(std::streambuf) parameter which is down cast to an tt(OFoldBuf) and an tt(FBB::Exception) exception is thrown if that cast fails. itb(size_t rightMargin(std::ostreambuf const *buffer)) This member returns the current right margin setting of the tt(OFoldBuf) object passed to it as its argument. The member's parameter is down cast in the same way as tt(leftMargin())'s argument: an tt(FBB::Exception) exception is thrown if that cast fails. ) manpagesection(EXAMPLE) verb( #include #include #include #include using namespace std; using namespace FBB; int main() { OFoldBuf fb(cout, 4, 40); ostream out(&fb); out << lm(4); string line; while (getline(cin, line)) out << line << '\n'; } ) manpagefiles() em(bobcat/ofoldbuf) - defines the class interface manpageseealso() bf(bobcat)(7), bf(lm)(3bobcat), bf(mlm)(3bobcat), bf(ofilterbuf)(3bobcat), bf(ofoldstream)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/level.yo0000644000175000017500000000460714050437223017217 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::level)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Log-manipulator) manpagename(FBB::level) (Manipulator setting the log-level of bf(FBB::Log) objects) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() An bf(FBB::level) object is used to specify insertion `forces' of information that is inserted into bf(FBB::Log) objects. When inserted into tt(Log) objects it defines the `force' of subsequent insertions (or tt(write) calls) into those tt(Log) objects. Conversely, tt(Log) objects may specify insertion `resistances' through their tt(setLevel) members. If the tt(level's) `force' is equal to or exceeds the tt(Log) object's `resistance' then the insertion is performed, otherwise the insertion is ignored. A single insertion statement may contain multiple tt(level) calls. If so, then each tt(level) call updates the `force' of insertions following the tt(level) call. By default insertions into tt(Log) objects not preceded by tt(level) insertions are completed. When a tt(level) object is inserted into another kind of tt(std::ostream) object the tt(level) object performs no actions. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(CONSTRUCTORS) itemization( itb(level(size_t force)) This constructor is used in insertion statements, usually inserting it as anonymous object into an tt(FBB::Log) object. ) Copy and move constructors (and assignment operators) are available. manpagesection(OVERLOADED OPERATOR) itemization( itb(std::ostream &::operator<<(std::ostream &ostr, FBB::level const &force)) If the tt(ostr) can be downcasted to an tt(FBB::Log) object then subsequent insertions are performed if tt(force) exceeds the tt(Log) object's `resistance' as specified by its tt(setLevel) member. If tt(ostr) does not actually refer to a tt(Log) object then tt(ostr) is returned without any further action, and tt(ostr) handles subsequent insertions in its default way. ) manpagesection(EXAMPLE) verbinclude(../../log/driver/driver.cc) manpagefiles() em(bobcat/level) - defines the class interface. manpageseealso() bf(bobcat)(7), bf(log)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/bobcat.yo0000644000175000017500000010736514050437223017347 0ustar frankfrankincludefile(include/header) manpage(Bobcat)(7)(_CurYrs_)(libbobcat-dev__CurVers_) (C++ Classes) whenhtml(center(htmlcommand())) manpagename(Bobcat)(Overview of classes in the Bobcat library) manpagedescription() The classes of the bf(Bobcat) library may be used after including tt(bobcat/classname) in sources. Generally, programs using the bf(Bobcat) library must be at least linked against the bf(Bobcat) library. Refer to section bf(LINKING) for more informatin about linking programs to required libraries. All classes and other elements are defined in the tt(FBB) namespace. For some classes em(manipulators) are available, which are defined in the tt(FBB) namespace. An overview of all manipulators defined in the tt(FBB) namespace is provided by tt(man -e bobcat manipulators). Beyond this section the section bf(CATEGORIES) groups classes that somehow belong together in various categories. The following classes and functions are available: bf(FBB::Align): Specifies tt(Table(Buf)) column and element alignments.nl() Manpage(align) bf(FBB::Arg): Interfaces the command line arguments, allowing for short- and long options. The class is implemented as a tt(Singleton).nl() Manpage(arg) bf(FBB::ArgConfig): Inherits from tt(Arg) and tt(ConfigFile) allowing for options to be specified as command line options and/or configuration file options. The class is implemented as a tt(Singleton).nl() Manpage(argconfig) bf(FBB::A2x): Ascii-to-x conversions of any type supporting extractions from tt(i[string]stream) objects. Manpage(a2x) bf(FBB::BigInt): Wrapper class around the openssl BN_ functions for unlimited integer precision arithmetic. nl() Manpage(bigint) bf(FBB::binary_search): A modification of the STL tt(binary_search) algorithm returning the location of the searched value in a sorted series of values. nl() Manpage(binarysearch) bf(FBB::BinOps): A series of function templates implementing binary operators for classes that implement the matching binary assignment operators themselves. nl() Manpage(binops) bf(FBB::BinOpsBase): A class template implementing binary operators and compound assignment operators for classes that themselves implement swap members and members implementing the basic binary operation on objects of their class types themselves. nl() Manpage(binopsbase) bf(FBB::CGI): a class implementing the facilities accessing the data made available through the Common Gateway Interface.nl() Manpage(cgi) bf(FBB::Cidr): a class testing whether IP4 Internet addresses belong to address ranges defined by Classless Inter-Domain Routing (CIDR) address block specifications.nl() Manpage(cidr) bf(FBB::ClientSocket): a socket for tcp-communication with a server.nl() Manpage(clientsocket) bf(FBB::CmdFinder): Command-function associations.nl() Manpage(cmdfinder) bf(FBB::CmdFinderBase): Base class for tt(CmdFinder).nl() Manpage(cmdfinderbase) bf(FBB::Config): Processing standard configuration files.nl() Manpage(config) bf(FBB::ConfigFile): Processing standard configuration files (deprecated, use bf(Config)).nl() Manpage(configfile) bf(FBB::CryptBuf): Base class for DecryptBuf and EncryptBuf.nl() Manpage(cryptbuf) bf(FBB::CSVTable): Construct tables row-by-row.nl() Manpage(csvtable) bf(FBB::CSV4180): Objects of this class allow for easy handling of comma-separated values (implements RFC 4180).nl() Manpage(csv4180) bf(FBB::DateTime): Manipulations with date and time values.nl() Manpage(datetime) bf(FBB::DecryptBuf): Decrypting information.nl() Manpage(decryptbuf) bf(FBB::DiffieHellman): Computing shared keys using the Diffie-Hellman algorithm.nl() Manpage(diffiehellman) bf(FBB::DigestBuf): Computing message digests.nl() Manpage(digestbuf) bf(FBB::EncryptBuf): Encrypting information.nl() Manpage(encryptbuf) bf(FBB::Eoi): tt(std::streambuf) offering the tt(eoi) manipulator.nl() Manpage(eoi) bf(FBB::Eoi): tt(std::streambuf) offering the tt(eoi) manipulator.nl() Manpage(eoi) bf(FBB::EoiBuf): tt(std::streambuf) offering the tt(eoi) manipulator and a configurable stream buffer.nl() Manpage(eoibuf) bf(FBB::Exception): objects of this class accept tt(ostream) insertions, and are also tt(std::exception) objects.nl() Manpage(exception) bf(FBB::Exec): Executes child processes not expecting input and not producing standard output. nl() Manpage(exec) bf(FBB::CerrExtractor): Executes child processes not expecting input but maybe writing its standard error stream. nl() Manpage(cerrextractor) bf(FBB::CoutExtractor): Executes child processes not expecting input but maybe producing standard output. nl() Manpage(coutextractor) bf(FBB::Field): class template retrieving and modifying position based fields in numbers using configurable number systems. nl() Manpage(field) bf(FBB::Fork): Defines bf(fork)(2) as part of a Template Algorithm Design Pattern. nl() Manpage(fork) bf(FBB::GetHostent): Obtains tt(hostent) struct from hostname or -address. nl() Manpage(gethostent) bf(FBB::Glob): Obtain a list of files matching a certain pattern.nl() Manpage(glob) bf(FBB::HmacBuf): Computing HMAC message digests.nl() Manpage(hmacbuf) bf(FBB::Hostname): Derived from tt(Hostent), allows the initialization from a tt(std::string), or from an tt(FBB::InetAddrress). nl() Manpage(hostname) bf(FBB::IBase64Stream): stream implementing base64 encoding and decoding, using a tt(FBB::Base64Streambuf) stream buffer.nl() Manpage(ibase64stream) bf(FBB::IBase64Buf): tt(FBB::IFilterBuf) specialization implementing base64 encoding and decoding.nl() Manpage(ibase64buf) bf(FBB::IFdStream): stream extracting information from a device whose file descriptor is available. nl() Manpage(ifdstream) bf(FBB::IFdBuf): Input stream buffer initialized by a file descriptor.nl() Manpage(ifdbuf) bf(FBB::IFilterBuf): tt(std::streambuf) specialization implementing an tt(std::istream) filtering design pattern.nl() Manpage(ifilterbuf) bf(FBB::Indent): Class and manipulators performing text indentation. nl() Manpage(indent) bf(FBB::InetAddress): Base class (no public constructor) for objects representing an internet address as used with sockets. Contains address and portnumbers. nl() Manpage(inetaddress) bf(FBB::CinInserter): Executes child processes expecting input but not producing standard output. nl() Manpage(cininserter) bf(FBB::IOStream): class combining tt(std::istream) and tt(std::ostream) features. nl() Manpage(iostream) bf(FBB::IOBuf): tt(std::streambuf) specialization allowing combined input and output operations. nl() Manpage(iobuf) bf(FBB::ISharedStream): tt(std::istream) operations on shared memory.nl() Manpage(isharedstream) bf(FBB::IQuotedPrintableStream): stream implementing quoted printable encoding and decoding, using a tt(FBB::IQuotedPrintableBuf) stream buffer.nl() Manpage(iquotedprintablestream) bf(FBB::IQuotedPrintableBuf): tt(FBB::IFilterBuf) specialization implementing quoted printable encoding and decoding.nl() Manpage(iquotedprintablebuf) bf(FBB::IRandStream): stream to extract random numbers from. nl() Manpage(irandstream) bf(FBB::ISymCryptStream): stream implementing symmetric encryption and decryption, using a tt(FBB::ISymCryptStreambuf) stream buffer.nl() Manpage(isymcryptstream) bf(FBB::ISymCryptStreambuf): tt(FBB::IFilterBuf) specialization implementing symmetric cryptography.nl() Manpage(isymcryptstreambuf) bf(FBB::Iterator): a class template creating a bidirectional iterator returning values of a specified type.nl() Manpage(iterator) bf(FBB::Hash...): Various class templates implementing mapping containers using hashing.nl() Manpage(hash) bf(FBB::Hostent): Wrapper around the tt(hostent) struct. nl() Manpage(hostent) bf(FBB::level): Manipulator setting the log-level of tt(FBB::Log) objects.nl() Manpage(level) bf(FBB::LinearMap): a class template container implementing a map using a linear search algorithm.nl() Manpage(linearmap) bf(FBB::lm): Manipulator setting the left margin of tt(FBB::OFoldStream) objects.nl() Manpage(lm) bf(FBB::LocalClientSocket): a Unix domain socket for tcp-communication with a Unix domain (local) server.nl() Manpage(localclientsocket) bf(FBB::LocalServerSocket): defines a Unix domain socket to which clients on the local host can connect.nl() Manpage(localserversocket) bf(FBB::LocalSocketBase): Base class for tt(LocalClientSocket) and tt(LocalServerSocket). nl() Manpage(localsocketbase) bf(FBB::Log): tt(std::ostream) handling log messages.nl() Manpage(log) bf(FBB::LogBuf): tt(std::streambuf) handling log messages.nl() Manpage(logbuf) bf(FBB::MailHeaders): extracts mail headers from SMTP-email.nl() Manpage(mailheaders) bf(FBB::Manipulators): manipulators defined in the namespace bf(FBB).nl() Manpage(manipulators) bf(FBB::Mbuf): tt(std::streambuf) specialization for inserting messages, mainly used by tt(FBB::Mstream) objects. nl() Manpage(mbuf) bf(FBB::Milter): interfaces the sendmail mail filter facilities.nl() Manpage(milter) bf(FBB::mlm): Manipulator modifying the left margin of tt(FBB::OFoldStream) objects.nl() Manpage(mlm) bf(FBB::Mstream): Inserts messages into streams. nl() Manpage(mstream) bf(FBB::MultiBuf): tt(std::streambuf) specializations performing insertions to multiple tt(std::ostream) objects.nl() Manpage(multibuf) bf(FBB::OMutexStream): Mutex protected tt(std::ostream).nl() Manpage(mxstream) bf(FBB::OFdStream): stream inserting information into a device whose file descriptor is available. nl() Manpage(ofdstream) bf(FBB::OFdBuf): Output stream buffer initialized by a file descriptor.nl() Manpage(ofdbuf) bf(FBB::OFilterBuf): tt(std::streambuf) specialization implementing an tt(std::ostream) filtering design pattern.nl() Manpage(ofilterbuf) bf(FBB::OFoldStream): tt(std::ostream) using an tt(OFoldBuf) as its streambuf. nl() Manpage(ofoldstream) bf(FBB::OFoldBuf): tt(OFilterBuf) (tt(std::streambuf)) specialization folding text lines between left and right margins.nl() Manpage(ofoldbuf) bf(FBB::OHexBuf): tt(OHexBuf) (tt(std::streambuf)) specialization inserting characters into a stream by their hex values.nl() Manpage(ohexbuf) bf(FBB::OneKey): Single keystroke input, not requiring `Return'.nl() Manpage(onekey) bf(FBB::OSharedStream): tt(std::ostream) operations on shared memory.nl() Manpage(osharedstream) bf(FBB::Pattern): Regular expression pattern matching.nl() Manpage(pattern) bf(FBB::Pipe): Defines a system level pipe. nl() Manpage(pipe) bf(FBB::PrimeFactors): Prime-number factorization of (BigInt) values.nl() Manpage(primefactors) bf(FBB::Process): Runs child processes, defining pipes between parents and child processes. nl() Manpage(process) bf(FBB::PtrIter): Input iterator whose dereferenced value returns a pointer rather than a reference to an element. Also offers: a tt(ptrIter) function template. nl() Manpage(ptriter) bf(FBB::RandBuf): implements a tt(streambuf) generating random numbers. nl() Manpage(randbuf) bf(FBB::Ranger): a class template creating ranges that are accepted by range-based for-loops. Also offered: a tt(ranger) function template. nl() Manpage(ranger) bf(FBB::ReadLineBuf): implements a tt(streambuf) using the Gnu tt(readline) library to allow editing an tt(std::istream)'s content. nl() Manpage(readlinebuf) bf(FBB::ReadLineHistory): provides access to the history of lines read from a tt(ReadLineBuf). nl() Manpage(readlinehistory) bf(FBB::ReadLineStream): tt(std::istream) class using a tt(ReadLineBuf) for its tt(std::streambuf). nl() Manpage(readlinestream) bf(FBB::Redirector): Defines system level file redirection. nl() Manpage(redirector) bf(FBB::repeat): Two short extensions of the STL tt(for_each) generic algorithm. nl() Manpage(repeat) bf(FBB::ReverseIterator): a class template creating a bidirectional reverse iterator returning values of a specified type.nl() Manpage(reverseiterator) bf(FBB::Selector): Offers timed delays and multiple file I/O. nl() Manpage(selector) bf(FBB::Semaphore): Dijkstra's (1962) Semaphore data type.nl() Manpage(semaphore) bf(FBB::ServerSocket): defines a socket to which clients can connect.nl() Manpage(serversocket) bf(FBB::SharedBlock): Shared memory data block info.nl() Manpage(sharedblock) bf(FBB::SharedCondition): Shared memory condition variable.nl() Manpage(sharedcondition) bf(FBB::SharedMemory): Shared memory structure.nl() Manpage(sharedmemory) bf(FBB::SharedMutex): Mutex for shared memory.nl() Manpage(sharedmutex) bf(FBB::SharedPos): Shared Memory offset controller.nl() Manpage(sharedpos) bf(FBB::SharedReadme): Background info about the implementation of Bobcat's Shared Memory.nl() Manpage(sharedreadme) bf(FBB::SharedSegment): Shared memory data structure.nl() Manpage(sharedsegment) bf(FBB::SharedStream): I/O operations on shared memory.nl() Manpage(sharedstream) bf(FBB::SharedBuf): tt(std::streambuf) interfacing to shared memory.nl() Manpage(sharedbuf) bf(FBB::Signal): Defines signals, allowing signal handlers to use object's data members c.q. to call object's members functions. nl() Manpage(signal) bf(FBB::SocketBase): Base class for tt(ClientSocket) and tt(ServerSocket). nl() Manpage(socketbase) bf(FBB::Stat): Determines file characteristics.nl() Manpage(stat) bf(FBB::StdExtractor): Executes child processes not expecting input but maybe writing their standard output and error streams. nl() Manpage(stdextractor) bf(FBB::String): Offers extended tt(std::string) functionality.nl() Manpage(string) bf(FBB::StringLine): Offers tt(operator>>) extracting lines from tt(std::istream) objects.nl() Manpage(stringline) bf(FBB::SyslogBuf): streambuf to Buffer generating bf(syslog)(3) messages. nl() Manpage(syslogbuf) bf(FBB::SyslogStream): stream to Output stream inserting bf(syslog)(3) messages. nl() Manpage(syslogstream) bf(FBB::fswap): templates implementing memory bytes based swap functionality nl() Manpage(fswap) bf(FBB::Table): Display tables row- or column-wise.nl() Manpage(CHAR(t)able) bf(FBB::TableBuf): Display tables row- or column-wise.nl() Manpage(CHAR(t)ablebuf) bf(FBB::TableLines): Support class for the class tt(Table(Buf)).nl() Manpage(tablelines) bf(FBB::TableSupport): Support class for the class tt(Table(Buf)).nl() Manpage(tablesupport) bf(FBB::TempStream): Temporary fstream. nl() Manpage(tempstream) bf(FBB::Tty): Controls echoing of characters entered at the terminal.nl() Manpage(tty) bf(FBB::TypeTrait): Traits class template to determine various characteristics of types.nl() Manpage(typetrait) bf(FBB::User): Determines the current user's parameters from tt(/etc/passwd).nl() Manpage(user) bf(FBB::Xpointer): sets and retrieves the X-windows pointer.nl() Manpage(xpointer) bf(FBB::X2a): x-to-Ascii conversions of any type supporting insertions into tt(o[string]stream) objects.nl() Manpage(x2a) COMMENT( bf(FBB::sequence_includes()): Template function implementing a variant of the bf(includes()) generic algorithm, not requiring sorted series. (Manpage: bf(man -e bobcat sequenceincludes)) END COMMENT) manpagesection(CATEGORIES) This section groups classes that somehow belong together. The following categories are offered: itemization( it() bf(COMMAND LINE INTERFACE AND CONFIGURATION FILES) it() bf(CONVERSIONS) it() bf(DATE AND TIME) it() bf(ERRORS AND MESSAGE HANDLING) it() bf(GENERIC ALGORITHM EXTENSIONS) it() bf(INTERNET / NETWORKING) it() bf(OPENSSL AND ENCRYPTION) it() bf(PATTERN MATCHING) it() bf(PROCESSES, SIGNALS, THREADS) it() bf(STREAMS AND FILES) it() bf(SHARED MEMORY) it() bf(TABLES) it() bf(VARIOUS TEMPLATES) it() bf(VARIOUS OTHER CLASSES) COMMENT( it() bf(DEPRECATED CLASSES)) ) itemization( it() bf(COMMAND LINE INTERFACE AND CONFIGURATION FILES) bf(FBB::Arg): Interfaces the command line arguments, allowing for short- and long options. The class is implemented as a tt(Singleton).nl() Manpage(arg) bf(FBB::ArgConfig): Inherits from tt(Arg) and tt(ConfigFile) allowing for options to be specified as command line options and/or configuration file options. The class is implemented as a tt(Singleton).nl() Manpage(argconfig) bf(FBB::CmdFinder): Command-function associations.nl() Manpage(cmdfinder) bf(FBB::CmdFinderBase): Base class for tt(CmdFinder).nl() Manpage(cmdfinderbase) bf(FBB::Config): Processing standard configuration files.nl() Manpage(configfile) bf(FBB::ConfigFile): Processing standard configuration files (deprecated, use bf(Config)).nl() Manpage(configfile) it() bf(CONVERSIONS) bf(FBB::A2x): Ascii-to-x conversions of any type supporting extractions from tt(i[string]stream) objects. Manpage(a2x) bf(FBB::BigInt): Wrapper class around the openssl BN_ functions for unlimited integer precision arithmetic. nl() Manpage(bigint) bf(FBB::CSV4180): Objects of this class allow easy handling of comma-separated values (implements RFC 4180).nl() Manpage(csv) COMMENT( bf(FBB::CSV): Objects of this class allow easy handling of comma-separated values.nl() Manpage(csv) END) bf(FBB::IBase64Stream): stream implementing base64 encoding and decoding, using a tt(FBB::Base64Streambuf) stream buffer.nl() Manpage(ibase64stream) bf(FBB::IBase64Buf): tt(FBB::IFilterBuf) specialization implementing base64 encoding and decoding.nl() Manpage(ibase64buf) bf(FBB::IQuotedPrintableStream): stream implementing quoted printable encoding and decoding, using a tt(FBB::IQuotedPrintableBuf) stream buffer.nl() Manpage(iquotedprintablestream) bf(FBB::IQuotedPrintableBuf): tt(FBB::IFilterBuf) specialization implementing quoted printable encoding and decoding.nl() Manpage(iquotedprintablebuf) bf(FBB::X2a): x-to-Ascii conversions of any type supporting insertions into tt(o[string]stream) objects.nl() Manpage(x2a) it() bf(DATE AND TIME) bf(FBB::DateTime): Manipulations with date and time values.nl() Manpage(datetime) it() bf(ERRORS AND MESSAGE HANDLING) bf(FBB::Exception): objects of this class accept tt(ostream) insertions, and are also tt(std::exception) objects.nl() Manpage(exception) bf(FBB::level): Manipulator setting the log-level of tt(FBB::Log) objects.nl() Manpage(level) bf(FBB::Log): tt(std::ostream) handling log messages.nl() Manpage(log) bf(FBB::LogBuf): tt(std::streambuf) handling log messages.nl() Manpage(logbuf) bf(FBB::SyslogBuf): streambuf to Buffer generating bf(syslog)(3) messages. nl() Manpage(syslogbuf) bf(FBB::SyslogStream): stream to Output stream inserting bf(syslog)(3) messages. nl() Manpage(syslogstream) it() bf(GENERIC ALGORITHM EXTENSIONS) bf(FBB::binary_search): A modification of the STL tt(binary_search) algorithm returning the location of the searched value in a sorted series of values. nl() Manpage(binarysearch) bf(FBB::LinearMap): a class template container implementing a map using a linear search algorithm.nl() Manpage(linearmap) bf(FBB::repeat): Two short extensions of the STL tt(for_each) generic algorithm. nl() Manpage(repeat) it() bf(INTERNET / NETWORKING) bf(FBB::CGI): a class implementing the facilities accessing the data made available through the Common Gateway Interface.nl() Manpage(cgi) bf(FBB::Cidr): a class testing whether IP4 Internet addresses belong to address ranges defined by Classless Inter-Domain Routing (CIDR) address block specifications.nl() Manpage(cidr) bf(FBB::ClientSocket): a socket for tcp-communication with a server.nl() Manpage(clientsocket) bf(FBB::GetHostent): Obtains tt(hostent) struct from hostname or -address. nl() Manpage(gethostent) bf(FBB::Hostname): Derived from tt(Hostent), allows the initialization from a tt(std::string), or from an tt(FBB::InetAddrress). nl() Manpage(hostname) bf(FBB::InetAddress): Base class (no public constructor) for objects representing an internet address as used with sockets. Contains address and portnumbers. nl() Manpage(inetaddress) bf(FBB::Hostent): Wrapper around the tt(hostent) struct. nl() Manpage(hostent) bf(FBB::LocalClientSocket): a Unix domain socket for tcp-communication with a Unix domain (local) server.nl() Manpage(localclientsocket) bf(FBB::LocalServerSocket): defines a Unix domain socket to which clients on the local host can connect.nl() Manpage(localserversocket) bf(FBB::LocalSocketBase): Base class for tt(LocalClientSocket) and tt(LocalServerSocket). nl() Manpage(localsocketbase) bf(FBB::MailHeaders): extracts mail headers from SMTP-email.nl() Manpage(mailheaders) bf(FBB::Milter): interfaces the sendmail mail filter facilities.nl() Manpage(milter) bf(FBB::ServerSocket): defines a socket to which clients can connect.nl() Manpage(serversocket) bf(FBB::SocketBase): Base class for tt(ClientSocket) and tt(ServerSocket). nl() Manpage(socketbase) it() bf(OPENSSL AND ENCRYPTION) bf(FBB::BigInt): Wrapper class around the openssl BN_ functions for unlimited integer precision arithmetic. nl() Manpage(bigint) bf(FBB::CryptBuf): Base class for DecryptBuf and EncryptBuf.nl() Manpage(cryptbuf) bf(FBB::DecryptBuf): Decrypting information.nl() Manpage(decryptbuf) bf(FBB::DiffieHellman): Computing shared keys using the Diffie-Hellman algorithm.nl() Manpage(diffiehellman) bf(FBB::DigestBuf): Computing message digests.nl() Manpage(digestbuf) bf(FBB::EncryptBuf): Encrypting information.nl() Manpage(encryptbuf) bf(FBB::HmacBuf): Computing HMAC message digests.nl() Manpage(hmacbuf) bf(FBB::ISymCryptStream): stream implementing symmetric encryption and decryption, using a tt(FBB::ISymCryptStreambuf) stream buffer.nl() Manpage(isymcryptstream) bf(FBB::ISymCryptStreambuf): tt(FBB::IFilterBuf) specialization implementing symmetric cryptography.nl() Manpage(isymcryptstreambuf) it() bf(PATTERN MATCHING) bf(FBB::Glob): Obtain a list of files matching a certain pattern.nl() Manpage(glob) bf(FBB::Pattern): Regular expression pattern matching.nl() Manpage(pattern) it() bf(PROCESSES, SIGNALS, THREADS) bf(FBB::Exec): Executes child processes not expecting input and not producing standard output. nl() Manpage(exec) bf(FBB::CerrExtractor): Executes child processes not expecting input but maybe writing its standard error stream. nl() Manpage(cerrextractor) bf(FBB::CoutExtractor): Executes child processes not expecting input but maybe producing standard output. nl() Manpage(coutextractor) bf(FBB::Fork): Defines bf(fork)(2) as part of a Template Algorithm Design Pattern. nl() Manpage(fork) bf(FBB::CinInserter): Executes child processes expecting input but not producing standard output. nl() Manpage(cininserter) bf(FBB::Process): Runs child processes, defining pipes between parents and child processes. nl() Manpage(process) bf(FBB::Semaphore): Dijkstra's (1962) Semaphore data type.nl() Manpage(semaphore) bf(FBB::Signal): Defines signals, allowing signal handlers to use object's data members c.q. to call object's members functions. nl() Manpage(signal) bf(FBB::StdExtractor): Executes child processes not expecting input but maybe writing their standard output and error streams. nl() Manpage(stdextractor) it() bf(STREAMS AND FILES) bf(FBB::DigestBuf): Computing message digests.nl() Manpage(digestbuf) bf(FBB::Eoi): tt(std::streambuf) offering the tt(eoi) manipulator.nl() Manpage(eoi) bf(FBB::EoiBuf): tt(std::streambuf) offering the tt(eoi) manipulator and a configurable stream buffer.nl() Manpage(eoibuf) bf(FBB::IFdStream): stream extracting information from a device whose file descriptor is available. nl() Manpage(ifdstream) bf(FBB::IFdBuf): Input stream buffer initialized by a file descriptor.nl() Manpage(ifdbuf) bf(FBB::IFilterBuf): tt(std::streambuf) specialization implementing an tt(std::istream) filtering design pattern.nl() Manpage(ifilterbuf) bf(FBB::IOStream): class combining tt(std::istream) and tt(std::ostream) features. nl() Manpage(iostream) bf(FBB::IOBuf): tt(std::streambuf) specialization allowing combined input and output operations. nl() Manpage(iobuf) bf(FBB::IRandStream): stream to extract random numbers from. nl() (Manpage(irandstream)) bf(FBB::ISharedStream): tt(std::istream) operations on shared memory.nl() Manpage(isharedstream) bf(FBB::lm): Manipulator setting the left margin of tt(FBB::OFoldStream) objects.nl() Manpage(lm) bf(FBB::Mbuf): tt(std::streambuf) specialization for inserting messages, mainly used by tt(FBB::Mstream) objects. nl() Manpage(mbuf) bf(FBB::mlm): Manipulator modifying the left margin of tt(FBB::OFoldStream) objects.nl() Manpage(mlm) bf(FBB::Mstream): Inserts messages into streams. nl() Manpage(mstream) bf(FBB::MultiBuf): tt(std::streambuf) specializations performing insertions to multiple tt(std::ostream) objects.nl() Manpage(multibuf) bf(FBB::OMutexStream): Mutex protected tt(std::ostream).nl() Manpage(mxstream) bf(FBB::OFdStream): stream inserting information into a device whose file descriptor is available. nl() Manpage(ofdstream) bf(FBB::OFdBuf): Output stream buffer initialized by a file descriptor.nl() Manpage(ofdbuf) bf(FBB::OFilterBuf): tt(std::streambuf) specialization implementing an tt(std::ostream) filtering design pattern.nl() Manpage(ofilterbuf) bf(FBB::OFoldStream): tt(std::ostream) using an tt(OFoldBuf) as its streambuf. nl() Manpage(ofoldstream) bf(FBB::OFoldBuf): tt(OFilterBuf) (tt(std::streambuf)) specialization folding text lines between left and right margins.nl() Manpage(ofoldbuf) bf(FBB::OHexBuf): tt(OHexBuf) (tt(std::streambuf)) specialization inserting characters into a stream by their hex values.nl() Manpage(ohexbuf) bf(FBB::OSharedStream): tt(std::ostream) operations on shared memory.nl() Manpage(osharedstream) bf(FBB::Pipe): Defines a system level pipe. nl() Manpage(pipe) bf(FBB::RandBuf): implements a tt(streambuf) generating random numbers. nl() Manpage(randbuf) bf(FBB::ReadLineBuf): implements a tt(streambuf) using the Gnu tt(readline) library to allow editing an tt(std::istream)'s content. nl() Manpage(readlinebuf) bf(FBB::ReadLineHistory): provides access to the history of lines read from a tt(ReadLineBuf). nl() Manpage(readlinehistory) bf(FBB::ReadLineStream): tt(std::istream) class using a tt(ReadLineBuf) for its tt(std::streambuf). nl() Manpage(readlinestream) bf(FBB::Redirector): Defines system level file redirection. nl() Manpage(redirector) bf(FBB::Selector): Offers timed delays and multiple file I/O. nl() Manpage(selector) bf(FBB::SharedStream): I/O operations on shared memory.nl() Manpage(sharedstream) bf(FBB::SharedBuf): tt(std::streambuf) interfacing to shared memory.nl() Manpage(sharedbuf) bf(FBB::Stat): Determines file characteristics.nl() Manpage(stat) bf(FBB::TempStream): Temporary fstream. nl() Manpage(tempstream) it() bf(SHARED MEMORY) bf(FBB::ISharedStream): tt(std::istream) operations on shared memory.nl() Manpage(isharedstream) bf(FBB::OSharedStream): tt(std::ostream) operations on shared memory.nl() Manpage(osharedstream) bf(FBB::SharedBlock): Shared memory data block info.nl() Manpage(sharedblock) bf(FBB::SharedCondition): Shared memory condition variable.nl() Manpage(sharedcondition) bf(FBB::SharedMemory): Shared memory structure.nl() Manpage(sharedmemory) bf(FBB::SharedMutex): Mutex for shared memory.nl() Manpage(sharedmutex) bf(FBB::SharedPos): Shared Memory offset controller.nl() Manpage(sharedpos) bf(FBB::SharedReadme): Background info about the implementation of Bobcat's Shared Memory.nl() Manpage(sharedreadme) bf(FBB::SharedSegment): Shared memory data structure.nl() Manpage(sharedsegment) bf(FBB::SharedStream): I/O operations on shared memory.nl() Manpage(sharedstream) bf(FBB::SharedBuf): tt(std::streambuf) interfacing to shared memory.nl() Manpage(sharedbuf) it() bf(TABLES) bf(FBB::Align): Specifies tt(Table(Buf)) column and element alignments.nl() Manpage(align) bf(FBB::CSVTable): Construct tables row-by-row.nl() Manpage(csvtable) bf(FBB::Table): Display tables row- or column-wise.nl() Manpage(CHAR(t)able) bf(FBB::TableBuf): Display tables row- or column-wise.nl() Manpage(CHAR(t)ablebuf) bf(FBB::TableLines): Support class for the class tt(Table(Buf)).nl() Manpage(tablelines) bf(FBB::TableSupport): Support class for the class tt(Table(Buf)).nl() Manpage(tablesupport) it() bf(VARIOUS TEMPLATES) bf(FBB::binary_search): A modification of the STL tt(binary_search) algorithm returning the location of the searched value in a sorted series of values. nl() Manpage(binarysearch) bf(FBB::BinOps): A series of function templates implementing binary operators for classes that implement the matching binary assignment operators themselves. nl() Manpage(binops) bf(FBB::BinOpsBase): A class template implementing binary operators and compound assignment operators for classes that themselves implement swap members and members implementing the basic binary operation on objects of their class types themselves. nl() Manpage(binopsbase) bf(FBB::Field): class template retrieving and modifying position based fields in numbers using configurable number systems. nl() Manpage(field) bf(FBB::fswap): templates implementing memory bytes based swap functionality nl() Manpage(fswap) bf(FBB::Hash...): Various class templates implementing mapping containers using hashing.nl() Manpage(hash) bf(FBB::Iterator): a class template creating a bidirectional iterator returning values of a specified type.nl() Manpage(iterator) bf(FBB::LinearMap): a class template container implementing a map using a linear search algorithm.nl() Manpage(linearmap) bf(FBB::PtrIter): Input iterator whose dereferenced value returns a pointer rather than a reference to an element. Also offers: a tt(ptrIter) function template. nl() Manpage(ptriter) bf(FBB::Ranger): a class template creating ranges that are accepted by range-based for-loops. Also offered: a tt(ranger) function template. nl() Manpage(ranger) bf(FBB::repeat): Two short extensions of the STL tt(for_each) generic algorithm. nl() Manpage(repeat) bf(FBB::ReverseIterator): a class template creating a bidirectional reverse iterator returning values of a specified type.nl() Manpage(reverseiterator) bf(FBB::TypeTrait): Traits class template to determine various characteristics of types.nl() Manpage(typetrait) it() bf(VARIOUS OTHER CLASSES) bf(FBB::CSV): Objects of this class allow easy handling of comma-separated values.nl() Manpage(csv) bf(FBB::Indent): Class and manipulators performing text indentation. nl() Manpage(indent) bf(FBB::Manipulators): manipulators defined in the namespace bf(FBB).nl() Manpage(manipulators) bf(FBB::OneKey): Single keystroke input, not requiring `Return'.nl() Manpage(onekey) bf(FBB::PrimeFactors): Pprime-number factorization of (BigInt) values.nl() Manpage(primefactors) bf(FBB::String): Offers extended tt(std::string) functionality.nl() Manpage(string) bf(FBB::StringLine): Offers tt(operator>>) extracting lines from tt(std::istream) objects.nl() Manpage(stringline) bf(FBB::Tty): Controls echoing of characters entered at the terminal.nl() Manpage(tty) bf(FBB::User): Determines the current user's parameters from tt(/etc/passwd).nl() Manpage(user) bf(FBB::Xpointer): sets and retrieves the X-windows pointer.nl() Manpage(xpointer) COMMENT( it() bf(DEPRECATED CLASSES) Deprecated classes should no longer be used. Their functionality is better provided by other classes. The deprecated classes are no longer maintained.nl() bf(FBB::CSV): Comma separated values are now handled by the class bf(CSV4180), implementing RFC 4180.nl() END) ) manpagesection(LINKING) To link programs against the shared bf(Bobcat) library (e.g., tt(libbobcat5.so)) it is usually sufficient to merely specify tt(-lbobcat). E.g., verb( g++ --std=c++2a main.cc -lbobcat ) Due to a change in library handling by the linker (cf. lurl(http://fedoraproject.org/wiki/UnderstandingDSOLinkChange) and lurl(https://wiki.debian.org/ToolChain/DSOLinking)), implemented in 2013, libraries that are indirectly required are no longer automatically linked to your program. With some classes (e.g., tt(BigInt)) the tt(libcrypto) library must also be specified, and programs using such classes must be linked against tt(bobcat) and tt(crypto): verb( g++ --std=c++2a main.cc -lbobcat -lcrypto ) Man-pages of classes requiring additional libraries mention these additional libraries in their bf(SYNOPSIS) sections. When using em(static) linking, the situation is slightly more problematic, and no general rule can be provided here. To create a statically linked program the flag tt(-static) must be provided, but in addition the tt(-pthread) flag must often be specified as well. If, when statically linking your program, undefined references to tt(pthread_...) identifiers are reported, then that is a sure sign that you need to provide the tt(-pthread) flag as well. When using static linking additional libraries, not specified at the man-pages, may also be required. E.g., when using the tt(Xpointer) class and using static linking, the command becomes: verb( g++ main.cc -static -pthread -lbobcat -lX11 -lxcb -lXdmcp -lXau ) When encountering undefined references when using static linking missing libraries may be suggested by the linker or by its error messages. Alternatively, the missing libraries may be found by searching the Internet. manpagefiles() itemization( itb(/usr/include/bobcat/) itb(/usr/lib/libbobcat.*) (shared, static libraries) ) manpageseealso() The individual bf(bobcat/3) header files, with man-pages accessible using tt(man -e bobcat class) (all lowercase names) manpagebugs() No Reported Bugs. includefile(include/trailer) bobcat-5.09.01/documentation/man/argconfig.yo0000644000175000017500000004321114050437223020041 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::ArgConfig)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Program Arguments) manpagename(FBB::ArgConfig)(A singleton class processing program arguments) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() Singleton class (see Gamma em(et al.), 1995) built around bf(getopt_long())(3). The class handles short- and long command-line options, as well as configuration files. In addition to the standard command-line options the various tt(option) members also recognize long options as keys, optionally followed by a colon and an option value are also recognized. E.g., an option tt(--input filename) can be specified in the configuration file like verb( input: filename ) or verb( input filename ) Options without arguments should probably not use the colon, although it is accepted by tt(ConfigArg). E.g., for the option tt(--verbose) both forms are accepted: verb( verbose verbose: ) includefile(include/namespace) manpagesection(INHERITS FROM) bf(FBB::Arg),nl() bf(FBB::ConfigFile) manpagesection(ENUMERATION) The bf(FBB::ArgConfig::Type) enumeration is inherited from the bf(FBB::Arg) class. It is used to specify whether or not long options require arguments. It defines the following values: bf(None, Required, Optional). itemization( it() bf(None): the long option does not use an argument; it() bf(Required): the long option requires an argument value; it() bf(Optional): the long option may optionally be provided with an argument value; ) These values are used when defining long options (like tt(--version)), which are defined as objects of the (nested inherited) class bf(FBB::Arg::LongOption) (in the context of tt(ArgConfig) this is identical to bf(FBB::ArgConfig::LongOption). manpagesection(THE NESTED INHERITED CLASS FBB::Arg::LongOption) Long options are defined using objects of the nested class bf(FBB::Arg::LongOption). This class provides the following constructors: itemization( itb(FBB::Arg::LongOption(char const *name, FBB::Arg::Type type = FBB::Arg::None)) This constructor is used to define a long option for which no corresponding short option is defined. The parameter tt(name) is the name of the long option (without specifying the -- characters which are only required when specifying a long option when calling a program). itb(FBB::Arg::LongOption(char const *name, int optionChar)) This constructor is used to define a long option for which a corresponding short option is defined. The parameter tt(name) is the name of the long option (without specifying the -- characters which are only required when specifying a long option when calling a program). ) To define long options use the following procedure: itemization( it() First, construct an array verb( FBB::Arg::LongOption longOptions[] = { c1, c2, ..., cn }; ) Where tt(c1, c2, ..., cn) are tt(n) constructor invocations of bf(FBB::Arg::LongOption()) constructors it() Next, pass tt(longOptions, LongOptions + n) as arguments to an tt(Arg::initialize) member that supports long options. ) Objects of the class tt(LongOptions) are normally used internally by the tt(ArgConfig) object, but they can also be used outside of the tt(ArgConfig) object. For that situation the following members are available: itemization( itb(std::string const &longName() const) returns the tt(LongOption's) long option name; itb(int optionChar() const) returns the tt(LongOption's) option character (or one of the tt(Arg::Type) enumeration values if there is no option character associated with the tt(LongOption)). ) manpagesection(CONSTRUCTORS) Since the class is a em(Singleton), no public constructors are available. Instead, static members are offered to initialize and access the single bf(ArgConfig) object. manpagesection(STATIC MEMBERS) All tt(initialize) members initialize the bf(FBB::ArgConfig) singleton, and can only be called once. An exception is thrown when called multiple times. All tt(initialize) members return a reference to the initialized tt(ArgConfig) singleton object. All tt(initialize) members define the parameters tt(argc) and tt(argv) which are interpreted as tt(main's) tt(argc) and tt(argv) parameters. When an tt(argv) element points to two consecutive dashes (tt(--)) then that element is ignored, and all of tt(argv's) subsequent elements are considered arguments instead of options. itemization( itb(FBB::ArgConfig &ArgConfig::initialize(char const *optstring, int argc, char **argv, [std::string const &fname,] Comment cType = KeepComment, SearchCasing sType = SearchCaseSensitive, Indices iType = IgnoreIndices)) The parameter tt(optstring) is a null-terminated byte string (NTBS) optionally starting with a + character, but otherwise containing option characters. One or two colons may be postfixed to option characters: quote( itemization( it() a single colon (:) indicates that the option requires an option value. it() a double colon (::) indicates that the option has an optional argument. With short options the option value is considered absent unless it is attached to the short option (e.g., tt(-tvalue)). Long options optionally accepting arguments should always immediately be followed by an assignment character (=), immediately followed by the option's value (which must start with a non-blank character). E.g., tt(--value=) indicates an absent option value, tt(--value=text) indicates the option's value equals tt(text). If an option value itself contains blanks, it must be surrounded by single or double quotes (e.g., tt(-t'this value'), or tt(--text='this value')). The surrounding quotes are not part of the option's value. )) When tt(optstring's) first character is + then all non-specified options are considered arguments, appearing in the final arguments list at their current argument positions. E.g., when tt(optstring) is tt(+ab) and no long options are defined, then calling verb( prog -a -z -b -yvalue --long arg1 arg2 ) results in the member tt(argv) returning a vector containing the elements tt(-z, -yvalue, --long, arg1,) and tt(arg2). If tt(optstring's) first character isn't + and an undefined option is encountered then an exception is thrown. The tt(fname) argument is optional. If provided, a configuration file by the specified name is opened (and must exist); if omitted the tt(ArgConfig) is created without using a configuration file. In the latter case a configuration file may be specified later using the tt(open) member inherited from tt(ConfigFile). The final three parameters are tt(ConfigFile) parameters, receiving the shown default values. This constructor returns a reference to the singleton object, allowing code initializing bf(ArgConfig) to use the initialized object immediately. itb(FBB::ArgConfig &ArgConfig::initialize(int accept. char const *optstring, int argc, char **argv, [std::string const &fname,] Comment cType = KeepComment, SearchCasing sType = SearchCaseSensitive, Indices iType = IgnoreIndices)) Acts like the previous member, but in addition defines the parameter tt(accept) specifying an option character from where all subsequent arguments and options are considered arguments. To ignore tt(accept) the value 0 (not the character '0') can be specified or an tt(initialize) members can be used that does not define an tt(accept) parameter. When arguments contain both an tt(accept) option and two consecutive dashes then the first one is interpreted, resulting in all remaining tt(argv) elements being interpreted as mere arguments. For example, when specifying tt(initialize('t', ...)) and calling verb( prog one -ttwo -c -- three ) then the member tt(argv) returns a vector containing the elements tt(one, -tttwo, -c, --), and tt(three) (see also the member tt(beyondDashes) below). itb(FBB::ArgConfig &ArgConfig::initialize(char const *optstring, ArgConfig::LongOption const *const begin, ArgConfig::LongOption const *const end, int argc, char **argv, [std::string const &fname,] Comment cType = KeepComment, SearchCasing sType = SearchCaseSensitive, Indices iType = IgnoreIndices)) Acts like the first tt(ArgConfig::initialize) member, but in addition defines two parameters specifying the range of elements of an array of tt(ArgConfig::LongOption) objects specifying long options. The parameter tt(begin) points to the first element of the range, the parameter tt(end) points just beyond the last element of the range. E.g., after defining verb( FBB::ArgConfig::LongOption longOptions[] = { c1, c2, ..., cn }; ) the arguments passed to tt(begin) and tt(end) could be specified as verb( initialize(..., longOptions, longOptions + size(longOptions), ...); ) itb(FBB::ArgConfig &ArgConfig::initialize(char accept, char const *optstring, LongOption const *const begin, LongOption const *const end, int argc, char **argv, [std::string const &fname,] Comment cType = KeepComment, SearchCasing sType = SearchCaseSensitive, Indices iType = IgnoreIndices)) Acts like the previous tt(ArgConfig::initialize) member, but in addition defines an tt(accept) parameter as defined by the second tt(ArgConfig::initialize) member. itb(FBB::ArgConfig &ArgConfig::instance()) Once an tt(ArgConfig::initialize) member has been called this member can be called from anywhere in the program (and it can be called multiple times), returning a reference to the initialized bf(ArgConfig) object. If it is called before an tt(ArgConfig::initialize) member has been called an exception is thrown. ) itb(FBB::ArgConfig &instance()) Returns the instance of the bf(ArgConfig) object, available after calling one of the bf(ArgConfig::initialize) members. If called before initialization, an tt(FBB::Exception) exception is thrown. ) manpagesection(NON-STATIC MEMBER FUNCTIONS) All public members of the tt(Arg) and tt(ConfigFile) classes are also offered by the tt(ArgConfig) class. As several tt(Arg::option) members were reimplemented by tt(ArgConfig) all tt(option) members are discussed below. All other members inherit straight from the classes tt(Arg) and tt(ConfigFile). Consult their man pages for details. itemization( itb(size_t option(int option) const) Returns the number of times `option' (or its long option synonym, if defined) was specified as command line option or as as a configuration file option. itb(size_t option(std::string const &options) const) Returns the total number of times any of the characters specified in the `options' string (or their long option synonyms) was specified as command line option or as as a configuration file option. itb(size_t option(string *value, int option) const) Returns the number of times the provided option (or its long option synonym) was present as either a command line option or as a configuration file option. If the return value is non-zero then the value of the first occurrence of this option (first checking the command line options; then checking the configuration file) is stored in tt(*value), which is left untouched if `option' was not present. 0 may be specified for bf(value) if the option does not have a value or if the value should not be stored. itb(size_t option(size_t idx, string *value, int option) const) This member acts identically to the tt(Arg::option) member having the identical prototype. It does not consider the configuration file but merely returns the number of times the provided option (or its long option synonym) was present. If the return value is non-zero then the value of the tt(idx)th occurrence (0-based offset) of this option is stored in tt(*value), which is left untouched if `option' was not present or if tt(idx) is or exceeds the number of specifications of the provided option. 0 may be specified for bf(value) if the option does not have a value or if the value should not be stored. itb(size_t option(size_t *idx, string *value, int option) const) This member acts identically to the tt(Arg::option) member having the identical prototype. It does not consider the configuration file but merely returns the number of times the provided option (or its long option synonym) was present. If the return value is non-zero then the offset (within the series of tt(option) specifications) of the first option having a non-empty option value is returned in tt(*idx), while its option value is stored in tt(*value). Both tt(*value) and tt(*idx) are left untouched if `option' was not present. 0 may be specified for bf(value) if the option does not have a value or if the value should not be stored. itb(size_t option(string *value, char const *longOption) const) Returns the number of times the specified long option (not having a single-character synonym) was present as either a command line option or in the configuration file. If found, then the value found at the first occurrence of the option (first considering the command line options, then the configuration file) is stored in tt(*value). The string pointed to by tt(value) is left untouched if the long option was not present. 0 may be specified for bf(value) if the option does not have a value or if the value should not be stored. itb(size_t option(size_t idx, string *value, char const * longOption) const) This member acts identically to the tt(Arg::option) member having the identical prototype. It does not consider the configuration file but merely returns the number of times the provided long option (not having a single-character synonym) was present. If the return value is non-zero then the value of the tt(idx)th occurrence (0-based offset) of this long option is stored in tt(*value), which is left untouched if the long option was not present or if tt(idx) is or exceeds the number of specifications of the provided long option. 0 may be specified for bf(value) if the long option does not have a value or if the value should not be stored. itb(size_t option(size_t *idx, string *value, int longOption) const) This member acts identically to the tt(Arg::option) member having the identical prototype. It does not consider the configuration file but merely returns the number of times the provided long option (not having a single-character synonym) was present. If the return value is non-zero then the offset (within the series of this long option specifications) of the first long option having a non-empty option value is returned in tt(*idx), while its option value is stored in tt(*value). Both tt(*value) and tt(*idx) are left untouched if long option was not present. 0 may be specified for bf(value) if the long option does not have a value or if the value should not be stored. ) manpagesection(EXAMPLE) verb( #include #include #include #include using namespace std; using namespace FBB; ArgConfig::LongOption lo[] = { ArgConfig::LongOption{"option", 'o'}, ArgConfig::LongOption{"value-option", 'v'} }; class X { ArgConfig &d_arg; public: X(); void function(); }; X::X() : d_arg(ArgConfig::instance()) {} void X::function() { if (d_arg.nArgs() == 0) throw Exception() << "Provide the name of a config file as 1st arg"; cout << "Counting " << d_arg.option('o') << " instances of -o or " "--option\n"; d_arg.open(d_arg[0]); // Now open the config file explicitly // (alternatively: use a constructor expecting // a file name) cout << "Counting " << d_arg.option('o') << " instances of -o or " "--option\n"; string optval; size_t count = d_arg.option(&optval, 'v'); cout << "Counting " << count << " instances of -v or --value-option\n"; if (count) cout << "Option value = " << optval << endl; } int main(int argc, char **argv) try { ArgConfig::initialize("ov:", lo, lo + 2, argc, argv); X x; x.function(); } catch (Exception const &err) { cout << "Terminating " << err.what() << endl; return 1; } ) manpagefiles() em(bobcat/argconfig) - defines the class interface manpageseealso() bf(arg)(3bobcat), bf(configfile)(3obcat), bf(bobcat)(7) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/linearmap.yo0000644000175000017500000002272714050437223020063 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::LinearMap)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Linear-search based mapping container) manpagename(FBB::LinearMap)(A mapping container using linear searching) manpagesynopsis() bf(#include )nl() manpagedescription() The class template bf(LinearMap) implements a mapping container using a linear searching algorithm. A mapping container using linear searching is less complex than either the sorted tt(std::map) or the unsorted tt(std::unordered_map) container. For relative small number of elements the linear search algorithm is also faster than the binary search or hashing-based searching algorithms. bf(LinearMap) implements all of the members which are also found in the standard tt(std::map), except for the tt(key_comp) and tt(value_comp) members. These latter two members are not available as ordering the keys is not an issue with the unordered, linear searching method which is used by bf(LinearMap). includefile(include/namespace) manpagesection(INHERITS (PRIVATELY) FROM) tt(std::vector) manpagesection(TEMPLATE TYPES) The full template type definition of bf(LinearMap) is: verb( template < typename Key, typename Value > ) The tt(Key) type must offer tt(bool operator==). Furthermore, tt(Key) and tt(Value) types must support default and copy constructors and overloaded (copy) assignment operators. manpagesection(TYPEDEFS) itemization( itt(typedef std::pair value_type); itt(iterator) - an iterator to a bf(LinearMap) object's elements; itt(const_iterator) - a tt(const_iterator) to a bf(LinearMap) object's elements; itt(reverse_iterator) - a tt(reverse_iterator) to a bf(LinearMap) object's elements; itt(const_reverse_iterator) - a tt(const_reverse_iterator) to a bf(LinearMap) object's elements. ) manpagesection(CONSTRUCTORS) itemization( itb(LinearMap(Iterator begin, Iterator end)) The constructor is initialized using the iterator range rangett(begin, end), where tt(Iterator) is any iterator type pointing to tt(value_type) objects. If identical keys tt(K) are used then only the first occurrence of the tt(value_type) object using key tt(K) is inserted. itb(LinearMap(std:initializer_list initial)) The constructor is initialized with the values stored in the tt(std::initializer_list) of tt(value_type) objects. If identical keys tt(K) are used then only the first occurrence of the tt(value_type) object using key tt(K) is inserted. ) Default, copy and move constructors (and copy and move assignment operators) are available. manpagesection(OVERLOADED OPERATORS) itemization( itb(Value &operator[](Key const &key)) A reference to the tt(Value) associated with tt(key) is returned. If tt(key) was not available prior to the call of the index operator a tt(value_map(key, Value()) object is inserted. ) manpagesection(MEMBER FUNCTIONS) Note that the members of tt(std::vector) are not automatically available, as bf(LinearMap) is privately inherited from tt(std::vector). bf(LinearMap) offers the following member functions: itemization( itb(Value &at(int idx)) returns a reference to the bf(LinearMap)'s tt(Value) that is associated with tt(key). If the tt(key) is not stored in the bf(LinearMap) then an bf(std::out_of_range) exception is thrown. itb(iterator begin()) returns an iterator pointing to the bf(LinearMap)'s first element. itb(size_t capacity()) returns the number of elements that can be stored in the bf(LinearMap) before its capacity is enlarged. itb(const_iterator cbegin() const) returns a tt(const_iterator) pointing to the bf(LinearMap)'s first element. itb(const_iterator cend() const) returns a tt(const_iterator) pointing beyond the bf(LinearMap)'s last element. itb(void clear()) erases all elements from the bf(LinearMap). itb(size_t count(key)) returns 1 if the provided key is available in the bf(LinearMap), otherwise 0 is returned. itb(const_reverse_iterator crbegin() const) returns a tt(const_reverse_iterator) pointing to a bf(LinearMap) object's last element. itb(const_reverse_iterator crend() const) returns a tt(const_reverse_iterator) pointing before a bf(LinearMap) object's first element. itb(std::pair emplace(Args &&...args)) a tt(value_type) object is constructed from tt(emplace)'s arguments. A tt(std::pair) is returned containing an iterator pointing to the object using that key. If the bf(LinearMap) already contains an object having the provided tt(Key) value then the returned tt(std::pair's bool) value is tt(false). If the provided tt(key) was not found, then the newly constructed object is inserted into the bf(LinearMap), and the returned tt(std::pair's bool) value is tt(true). itb(bool empty()) returns tt(true) if the bf(LinearMap) contains no elements. itb(iterator end()) returns an iterator pointing beyond the bf(LinearMap)'s last element. itb(std::pair equal_range(key)) returns a pair of iterators, being respectively the return values of the member functions tt(lower_bound) and tt(upper_bound). itb(bool erase(Key const &key)) erases the element having the given tt(key) from the bf(LinearMap). tt(True) is returned if the value was removed, tt(false) if the bf(LinearMap) did not contain an element using the given tt(key). itb(void erase(iterator pos)) erases the element at iterator position tt(pos). itb(void erase(iterator begin, iterator end)) erases all elements indicated by the iterator range rangett(first, beyond). itb(iterator find(Key const &key)) returns an iterator to the element having the given key. If the element isn't available, tt(end) is returned. itb(const_iterator find(Key const &key) const) returns a tt(const_iterator) to the element having the given key. If the element isn't available, tt(end) is returned. itb(allocator_type get_allocator() const) returns a copy of the allocator object used by the tt(bf(LinearMap)) object. itb(std::pair insert(value_type const &keyValue)) tries to inserts a new tt(value_type) object into the bf(LinearMap), returning a tt(std::pair). If the returned ti(bool) field is tt(true), tt(keyValue) was inserted into the bf(LinearMap). The value tt(false) indicates that the specified key was already available, and tt(keyvalue) was not inserted into the bf(LinearMap). In both cases the tt(iterator) field points to the data element having the specified tt(key). itb(iterator insert(iterator pos, value_type const &keyValue)) tries to insert tt(keyValue) into the bf(LinearMap). tt(Pos) is ignored, and an iterator to the element having tt(keyValue)'s key value is returned. If the specified key was already present, tt(keyValue) is not inserted into the bf(LinearMap). itb(void insert(Iterator begin, Iterator end)) tries to insert the tt(value_type) elements pointed at by the iterator range rangett(begin, end) objects) into the bf(LinearMap). tt(Iterator) is any iterator type pointing to tt(value_type) objects. Already existing tt(value_type) elements having keys equal to the keys of the elements pointed at by the iterator range are not replaced. itb(iterator lower_bound(Key const &key)) returns an iterator pointing to the tt(keyvalue) element having the specified tt(key). If no such element exists, tt(end) is returned. itb(const_iterator lower_bound(Key const &key) const) returns a tt(const_iterator) pointing to the tt(keyvalue) element having the specified tt(key). If no such element exists, tt(end) is returned. itb(size_t max_size() const) returns the maximum number of elements this tt(bf(LinearMap)) may contain. itb(reverse_iterator rbegin()) returns a tt(reverse_iterator) pointing to the bf(LinearMap) object's last element. itb(const_reverse_iterator rbegin() const) returns a tt(const_reverse_iterator) pointing to the bf(LinearMap) object's last element. itb(reverse_iterator rend()) returns a tt(reverse_iterator) pointing before the bf(LinearMap) object's first element. itb(const_reverse_iterator rbegin() const) returns a tt(const_reverse_iterator) pointing before the bf(LinearMap) object's first element. itb(size_t size() const) returns the number of elements in the bf(LinearMap). itb(void swap(LinearMap &other)) swaps two bf(LinearMap)s using identical tt(Key) and tt(Value) types. itb(iterator upper_bound(Key const &key)) returns an iterator pointing to the tt(keyvalue) element having the specified tt(key). If no such element exists, tt(end) is returned. itb(const_iterator upper_bound(Key const &key) const) returns a tt(const_iterator) pointing to the tt(keyvalue) element having the specified tt(key). If no such element exists, tt(end) is returned. ) manpagesection(EXAMPLE) verbinclude(../../linearmap/driver/driver.cc) manpagefiles() em(bobcat/linearmap) - defines the class interface manpageseealso() bf(bobcat)(7) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/eoibuf.yo0000644000175000017500000000772114050437223017361 0ustar frankfrankincludefile(include/header) COMMENT(replace 'classname' by the name of the new class) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::EoiBuf)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (End-Of-Information Base class) manpagename(FBB::EoiBuf)(std::streambuf class offering an eoi manipulator) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() The class tt(EoiBuf) inherits from tt(Eoi) and may therefore be used as a base class of classes specializing tt(std::streambuf). It also provides a configurable character buffer for storing characters received from their devices. Often, when deriving classes from tt(std::streambuf) the derived classes must implement storage to and retrieval from a character buffer. By deriving from tt(EoiBuf) buffer-handling is automatically provided. includefile(include/namespace) manpagesection(INHERITS FROM) tt(Eoi) (and thus from: tt(std::streambuf)) manpagesection(PROTECTED CONSTRUCTOR) Analogously to tt(std::streambuf) only protected constructors are available. itemization( itb(EoiBuf()) The default constructor initializes an empty buffer. itb(EoiBuf(size_t size)) This initializes an empty buffer of a predefined size of tt(size) characters . ) Note that there's no inherent limit to the size of the internal buffer: its size can always be enlarged or reduced. Copy and move constructors (and assignment operators) are not available. manpagesection(PROTECTED MEMBER FUNCTIONS) All members of tt(std:streambuf) and tt(Eoi) are available, as bf(FBB::EoiBuf) inherits from these classes. itemization( itb(std::string &buffer()) A reference to the internal buffer is returned; itb(size_t bufSize() const) The length (size) of the internal buffer is returned; itb(void resize(size_t size)) The size of the internal buffer is changed to tt(size) characters; itb(void setg(unsigned next, unsigned beyond)) The tt(streambuf::eback) member returns the address of the internal buffer's first character, tt(streambuf::gptr) returns the address of the internal buffer's tt(next) character, tt(streambuf::egptr) returns the the address of the internal buffer's tt(beyond) character; itb(void setp()) The tt(streambuf::pbase) and tt(pptr) members return the address of the internal buffer's first character, tt(streambuf::epptr) returns the address immediately beyond the internal buffer's last character; itb(unsigned char *ucharPtr()) The address of the first character of the internal buffer is returned as a pointer to an unsigned character; itb(unsigned char const *ucharPtr() const) Same as the previous member, but this time the address of the first character of the internal buffer is returned as a pointer to an immutable unsigned character. ) manpagesection(PROTECTED STATIC MEMBER FUNCTIONS) The following two static members are provided as convenient functions for derived classes to convert the address of the first character of tt(std::string) objects to pointers to unsigned characters: itb(unsigned char *ucharPtr(std::string &str)) The address of the first character of tt(str) is returned as a pointer to an unsigned character; itb(unsigned char const *ucharPtr(std::string const &str) const) Same as the previous member, but this time the address of the first character of tt(str) is returned as a pointer to an immutable unsigned character. manpagesection(EXAMPLE) Here is an example from the implementation of tt(EncryptBuf): verbinclude(../../encryptbuf/flushbuffer.cc) manpagefiles() em(bobcat/eoibuf) - defines the class interface manpageseealso() bf(bobcat)(7), bf(eoi)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/repeat.yo0000644000175000017500000000520614050437223017364 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::repeat)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (repeated function calls) manpagename(FBB::repeat)(call a (member) function a fixed number of times) manpagesynopsis() bf(#include )nl() manpagedescription() The bf(FBB::repeat) function template allows a function or member function to be called a certain number of times. The functions or member functions may define arguments. Arguments to these functions are specified when tt(repeat) is called, and are perfectly forwarded by the tt(repeat) function template to the (member) function called by tt(repeat). The first argument of the tt(repeat) function template defines the number of times the (member) function must be called. The tt(FBB::repeat) function template are defined tt(inline), allowing the compiler to `optimize away' the tt(repeat) function call itself. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(REPEAT FUNCTION TEMPLATE) The tt(repeat) function template is declared as: verb( template void repeat(Counter counter, First &&first, Params &&...params); ) In this declaration, itemization( it() bf(Counter) represents the counter's type. Usually an tt(int) or tt(size_t). When calling tt(repeat) tt(counter) must be initialized to the number of times tt(repeat) must call the (member) function (see below); it() bf(First) represents the prototype of a function or the name of a class. name of a class. Likewise, tt(first) either is the address (name) of the function to be called or the name of an object of class type tt(First). In the latter case the object may or may not be a tt(const) object. it() bf(...Params) represents the set of parameter types of arguments which must be perfectly forwarded to the called function. If tt(first) represents a class type object, the first argument em(must) be the address of a member function of the class tt(First). ) manpagesection(EXAMPLES) verbinclude(../../repeat/driver/driver.cc) manpagefiles() em(bobcat/repeat) - defines the class interface manpageseealso() bf(bobcat)(7) manpagebugs() Be careful when using overloaded functions, as the template argument resolution mechanism may be unable to determine which function to call. If overloaded functions must be used, a tt(static_cast) is likely required to disambiguate your intentions. includefile(include/trailer) bobcat-5.09.01/documentation/man/coutextractor.yo0000644000175000017500000001062314050437223021011 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::CoutExtractor)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Executing Child Processes) manpagename(FBB::CoutExtractor)(Runs external programs writing standard output) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() The bf(FBB::CoutExtractor) class offers a basic interface for calling external programs (so-called em(child processes)) writing their standard output streams. The standard input and standard error streams of the child processes by default are not handled by ttCoutExtractor) objects. The child's standard output is read through the tt(CoutExtractor) object: information written by the child process to its standard output stream is extracted or read from tt(CoutExtractor) object. The tt(PATH) environment variable is not used when calling child processes: child process programs must be specified using paths. tt(CoutExtractor) objects may repeatedly be used to execute the same or different child processes. Arguments passed to child processes may be surrounded by double or single quotes. Arguments surrounded by double quotes have their double quotes removed, while interpreting any escape-sequences that may have been used within. Arguments surrounded by single quotes have their single quotes removed, while accepting their content as-is. In addition unquoted escape-sequences may be specified: those escape sequences are evaluated and replaced by their intended characters (e.g., tt(\100) is converted to tt(@)). includefile(include/namespace) manpagesection(INHERITS FROM) bf(FBB::Exec) (private), bf(FBB::IFdBuf) (private), bf(std::istream) manpagesection(CONSTRUCTOR) itemization( itb(CoutExtractor(size_t bufSize = 100)) A tt(bufSize) argument may be specified: it defines the internal buffer size used by the tt(CoutExtractor's) streambuf. By default the stdandard input and standard error streams are not handled. itb(CoutExtractor(Mode mode, size_t bufSize = 100)) The tt(mode) argument must be tt(CoutExtractor::CLOSE_STD). It indicates that the standard input and standard error streams are redirected to tt(/dev/null): the child processes cannot read their standard input streams and any standard error output generated by child processes is ignored. A tt(bufSize) argument may be specified: it defines the internal buffer size used by the tt(CinInserter's) streambuf. ) Copy and move constructors (and assignment operators) are not available. manpagesection(MEMBERS) itemization( itb(void execute(std::string const &cmd)) The argument specifies the command to execute: the command itself must be specified as a path (the tt(PATH) environment variable isn't used). This member immediately returns, after which information written by the child process to its standard output stream may be extracted from the tt(CoutExtractor) object. Once tt(execute) has returned it can be called again, either using the same or another command. Arguments passed to the program to be executed as child process may optionally be specified using single or double quotes, as described in this man-page's DESCRIPTION section. itb(int ret() const) Once tt(execute) has returned this member provides the actual exit code of the child process. Its value equals -1 before the first tt(exectue) call. ) manpagesection(PROTECTED MEMBER) itemization( itb(Pipe &childOutPipe()) If derived classes need to override the redirections-members then they probabaly need access to the pipe written by the child process. This member provides a reference to that pipe. By default the parent process reads information from the pipe, while the child process inserts its standard output into the pipe. ) manpagesection(EXAMPLE) verbinclude(../../coutextractor/driver/driver.cc) manpagefiles() em(bobcat/coutextractor) - provides the class interface manpageseealso() bf(bobcat)(7), bf(cerrextractor)(3bobcat), bf(cininserter)(3bobcat), bf(execl)(3), bf(exec)(3bobcat), bf(fork)(3bobcat), bf(process)(3bobcat), bf(stdextractor)(3bobcat). manpagebugs() None reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/localsocketbase.yo0000644000175000017500000000462014050437223021241 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::LocalSocketBase)(3bobcat)(_CurYrs_) (libbobcat-dev__CurVers_) (Base class for Unix Domain sockets) manpagename(FBB::LocalSocketBase) (Base class for Unix Domain socket-constructing classes) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() This class is a base class for the bf(FBB::LocalServerSocket) and bf(FBB::LocalClientSocket) classes. Since it is designed as a base class, its constructor is protected. All its remaining members are protected as well. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(PROTECTED CONSTRUCTOR) itemization( itb(LocalSocketBase()) The default constructor merely constructs a tt(FBB::LocalSocketBase) object. Before the object can be used, its tt(open()) member must be called first. itb(LocalSocketBase(string const &name)) This constructor creates a bf(LocalSocketBase) using the file specified in tt(name) as the Unix domain socket interface. If the socket could not be constructed, an bf(FBB::Exception) exception is thrown. ) Copy and move constructors (and assignment operators) are not available. manpagesection(PROTECTED MEMBER FUNCTIONS) itemization( itb(open(string const &name)) This member initiaizes a bf(LocalSocketBase) object following its construction using the default constructor. The file specified in tt(name) is used as the Unix domain socket interface. If the socket could not be constructed, an bf(FBB::Exception) exception is thrown. itb(size_t size() const) Accessor returning the size of the object's bf(sockaddr_un) (address) itb(int socket() const) This accessor returns the bf(FBB::LocalSocketBase)'s socket value. itb(sockaddr const *sockaddrPtr() const) Accessor returning the pointer to the object's bf(sockaddr). ) manpagesection(EXAMPLE) See the examples presented with the bf(localclientsocket)(3bobcat) and bf(localserversocket)(3bobcat) classes. manpagefiles() em(bobcat/localsocketbase) - defines the class interface manpageseealso() bf(bobcat)(7), bf(localclientsocket)(3bobcat), bf(localserversocket)(3bobcat), bf(socketbase)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/ranger.yo0000644000175000017500000001040714050437223017361 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Ranger)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Error handler) manpagename(FBB::Ranger)(generalizes ranges for range-based for-loops) manpagesynopsis() bf(#include )nl() manpagedescription() The tt(Ranger) class template defines ranges that can be used with range-based for-loops. The standard range-based for-loop requires for its range-specificiation an array or an iterator range as offered by, e.g., containers (through their tt(begin) and tt(end) members). Ranges defined by a pair of pointers or by a subrange defined by iterator expressions cannot currently be used in combination with range-based for-loops. tt(Ranger) extends the applicability of range-based for-loops by turning pairs of pointers, an initial pointer and a pointer count, or a pair of iterators into a range that can be used by range-based for-loops. tt(Ranger) is a class template requiring one template type parameter: tt(Iterator), an iterator or pointer type reaching the data when dereferenced. tt(Ranger)'s users don't have to specify tt(Ranger)'s template type. The function template tt(ranger) returns the appropriate tt(Ranger) object. includefile(include/namespace) manpagesection(FREE FUNCTION) When using the following free functions, any (subrange) of iterators or pointers can be used. With iterators subranges of em(reverse iterators) can also be specified. The bf(EXAMPLE) section below illustrates the use of the tt(ranger) function templates. itemization( itb(Ranger ranger(Iterator &&begin, Iterator &&end)) this function template returns a tt(Ranger) object for the (sub)range defined by two (reverse) iterators; itb(Ranger ranger(Iterator &&begin, size_t count)) this function template returns a tt(Ranger) object for the (sub)range defined by the (reverse) iterator range tt(begin) and tt(begin + count); itb(Ranger ranger(Data *begin, Data *end)) this function template returns a tt(Ranger) object for the (sub)range defined by the two pointers tt(begin) and tt(end); itb(Ranger ranger(Data *begin, size_t count)) this function template returns a tt(Ranger) object for the (sub)range defined by the two pointers tt(begin) and tt(begin + count). ) manpagesection(CONSTRUCTORS) Below, tt(Iterator) refers to the tt(Ranger) class template's type parameter. Although named 'Iterator' it can also be a pointer to some data type (e.g., tt(std::string *)). itemization( itb(Ranger(Iterator const &begin, Iterator const &end)) A tt(Ranger) object can be passed as range-specifier in a range-based for-loop. All elements defined by the range will subsequently be visited by the range-based for-loop. ) Copy and move constructors (and assignment operators) are available. manpagesection(MEMBER FUNCTIONS) itemization( itb(Iterator const &begin() const) returns (a copy of) the tt(begin) iterator passed to the tt(Ranger)'s constructor. Note that if tt(Iterator) was a pointer type (like tt(int *)) the data to which the iterator returned by tt(begin()) can actually be modified, as the member's return type (using tt(int *) for tt(Iterator)) becomes tt(int * const &), so a reference to a constant pointer to an tt(int). This is perfectly OK: if the data themselves should be immutable, then the data type must be defined as tt(int const), which is automatically the case when passing tt(int const *) data. See the bf(EXAMPLE) section for an illustration. itb(Iterator const &end() const) returns (a copy of) the tt(end) iterator passed to the tt(Ranger)'s constructor. ) If reverse iterators are passed to tt(Ranger)'s constructor, then the tt(begin) and tt(end) members return em(reverse iterators). Since the intended use of tt(Ranger) objects is to define a range for range-base for-loops, members like tt(rbegin) and tt(rend) can be omitted from tt(Ranger). manpagesection(EXAMPLE) verbinclude(../../ranger/driver/driver.cc) manpagefiles() em(bobcat/ranger) - defines the class interface manpageseealso() bf(bobcat)(7) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/encryptbuf.yo0000644000175000017500000001654714050437223020277 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::EncryptBuf)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Encrypt information) manpagename(FBB::EncryptBuf) (Encrypts information using various methods into a std::ostream) manpagesynopsis() bf(#include )nl() Linking option: tt( -lbobcat -lcrypto) manpagedescription() bf(FBB::EncryptBuf) objects are bf(std::streambuf) objects that can be used to initialize tt(std::ostream) objects. All information inserted into such a tt(std::ostream) is encrypted and written into an tt(std::ostream) that is given as argument to tt(EncryptBuf)'s constructor. All encryption methods supported by the OpenSSL library that can be selected by name may be used by tt(EncryptBuf) objects. To select a particular encryption method an identifier is passed to the constructor. E.g., tt("aes-128-cbc") indicating the AES (Rijndael) method, using 128 bit sized keys and blocks using `cbc' mode (see below for an explanation). Most modes use em(initialization vectors). Unless provided at construction time tt(EncryptBuf) objects create random initialization vectors. The initialization vector that is actually used can be obtained from the tt(EncryptBuf) object. This is important, as the matching decryption object needs to know the initialization vector that was used when encrypting the data. Initialization vectors are not considered confidential and they can be sent in the clear to the decryption object. What em(is) important, though, is that they contain random data when used `for real'. When an initialization vector is specified that is shorter than expected by the encryption method it is automatically extended with 0-bytes to the required length. includefile(blockciphers) includefile(symcryptciphers) includefile(include/namespace) manpagesection(INHERITS FROM) bf(FBB::CryptBuf), in turn inheriting from bf(std::streambuf) manpagesection(CONSTRUCTOR/DESTRUCTOR) itemization( itb(EncryptBuf(std::ostream &outStream, char const *type, std::string const &key, std::string const &iv, size_t bufsize = 1024)) This constructor initializes the tt(EncryptBuf) object preparing it for the encryption algorithm specified with tt(type). The encryption algorithms that can be used are listed in the abovementioned table. E.g., to use the AES method on 24 bit keys and blocks in CBC mode specify tt("aes-192-cbc"). The tt(key) parameter refers to the key to be used, the tt(iv) parameter refers to the initialization vector to use. Both tt(key) and tt(iv) may contain non-displayable characters. When tt(iv.length()) is zero it will be filled by the tt(EncryptBuf) object with random data. When the tt(iv) is too small for the requested method it is expanded by adding the required number of zero valued bytes. The constructor throws an tt(FBB::Exception) exception if an encryption method is specified that is not supported by OpenSSL. The constructor's first parameter refers to the tt(std::ostream) to receive the encrypted information. Be aware of the fact that the encrypted information most likely contains non-displayable characters. The tt(bufsize) argument specifies the size in bytes of the internal buffer used by tt(EncryptBuf) temporarily storing incoming characters. The provided default argument can most likely be kept as-is. itb(~EncryptBuf()) Normally, once all information has been inserted into the encryption stream the tt(end) manipulator (see below) is inserted to complete the encryption process. Alternatively, the encryption process ends once the tt(EncryptBuf's) destructor is called. E.g., if tt(encStream) is the tt(std::ostream) to receive the information to encrypt and tt(inStream) is the tt(std::istream) containing the information to encrypt then verb( endStream << inStream.rdbuf(); ) completes the decryption once tt(EncryptBuf's) destructor is called. Alternatively, verb( encStream << inStream.rdbuf() << end; ) can be used to immediately complete the encryption process. ) Copy and move constructors (and assignment operators) are not available. manpagesection(MEMBER FUNCTIONS) All members of bf(std::streambuf) are available, as bf(FBB::EncryptBuf) inherits from this class. itemization( itb(size_t blockLength() const) This member returns the block size (in bytes) that are used by the specified method. itb(size_t ivLength() const) This member returns the size (in bytes) of the initialization vector that is used by the specified method. itb(std::string iv() const) This member returns a reference to the initialization vector that is used by the specified method. Be advised that the initialization vector may contain non-displayable characters. itb(size_t keyLength() const) This member returns the size of the key (in bytes) that are used by the specified method. itb(size_t rounds() const) This member can only be used with the RC5 encryption method to query the number of rounds of the algorithm. It returns the currently used number of rounds or 0 if the member is called for another encryption method than RC5. itb(bool setRounds(size_t nRounds)) This member can only be used with the RC5 encryption method to set the number of rounds of the algorithm to 8, 12 or 16. When the number of rounds were updated successfully the member returns tt(true). It returns tt(false) in other cases (e.g., called for other encryption methods than RC5 or the requested number of rounds differ from 8, 12 or 16). ) manpagesection(PROTECTED MEMBER) itemization( itb(EVP_CIPHER_CTX *cipherCtx()) Classes derived from tt(EncryptBuf) may use this member to gain direct access to the tt(EVP_CIPHER_CTX) pointer used by the tt(EncryptBuf) object. This pointer is a pointer to an opaque structure used by many OpenSSL functions to set or query parameters of an encryption method. ) manpagesection(EXAMPLE) verbinclude(../../encryptbuf/driver/driver.cc) To ignore the initial 256 bytes generated by the RC4 algorithm a simple wrapper class around the eventual output stream can be used. Here is an illustration: verb( #include #include class Skip256: public FBB::OFilterBuf { size_t d_count; public: Skip256(std::ostream &os) : OFilterBuf(os), d_count(0) {} private: virtual int overflow(int c) { if (d_count == 256) out().put(c); else ++d_count; return c; } }; ) Next, an tt(Skip256) object is used to define an intermediate tt(std::ostream) that is then passed to the tt(EncryptBuf) object. E.g., only showing the essential steps defining the tt(EncryptBuf) object: verb( Skip256 skip256(std::cout); std::ostream out(&skip256); EncryptBuf encryptbuf(out, "rc4", key, ""); ) manpagefiles() em(bobcat/encryptbuf) - defines the class interface manpageseealso() bf(bobcat)(7), bf(decryptbuf)(3bobcat), bf(ofilterbuf)(3bobcat), bf(std::streambuf) manpagebugs() None reported includefile(include/trailer) bobcat-5.09.01/documentation/man/isymcryptbuf.yo0000644000175000017500000001411514050437223020643 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::ISymCryptStreambuf)(3bobcat)(_CurYrs_) (libbobcat-dev__CurVers_) (Symmetric Encryption Stream Buffer) manpagename(FBB::ISymCryptStreambuf) (Input Filtering stream buffer doing symmetric encryption) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat -lcrypto) manpagedescription() The information made available by bf(ISymCryptStreambuf) objects has been subject to symmetric encryption or decryption. The information to be encrypted or decrypted is made available to bf(ISymCryptStreambuf) object via tt(std::istream) objects. The tt(class ISymCryptStreambuf) is a class template, using a tt(FBB::CryptType) template non-type parameter. Objects of the class tt(FBB::ISymCryptStreambuf) encrypt the information they receive, objects of the class tt(FBB::ISymCryptStreambuf) decrypt the information they receive. See also section bf(ENUMERATION) below. All symmetric encryption methods defined by the OpenSSL library that can be selected by name may be used in combination with tt(EncryptBuf) objects. To select a particular encryption method an identifier is passed to the constructor. E.g., tt("aes-128-cbc") indicating the AES (Rijndael) method, using 128 bit sized keys and blocks using `cbc' mode (see below for an explanation). When providing shorter keys than expected by the method the provided key is extended by adding the required number of 0-bytes. (zero valued bytes, not tt('0') characters). Most modes use an em(initialization vector). The initialization vector must be provided at construction time. The matching decrypting object needs to know the initialization vector that was used when encrypting the data: the application must ensure that the matching decryption object receives the same initialization vector as the one that was provided to the encryption object. Initialization vectors are not security sensitive in the sense that they can be sent in the clear to the decryption object. What em(is) important, though, is that they contain random data when used `for real'. When an initialization vector is specified that is shorter than expected by the method it will be extended with the required number of 0-bytes. includefile(blockciphers) includefile(symcryptciphers) includefile(include/namespace) manpagesection(INHERITS FROM) bf(FBB::IFilterBuf) manpagesection(MEMBER FUNCTIONS) All members of bf(FBB::IFilterBuf) are available, as bf(ISymCryptStreambuf) inherits from this class. Overloaded move and/or copy assignment operators are not available. manpagesection(ENUMERATION) bf(ISymCryptStreambuf) objects either encrypt or decrypt information. bf(ISymCryptStreambuf) objects of the class bf(FBB::ISymCryptStreambuf) encrypt the data they receive, bf(ISymCryptStreambuf) objects of the class bf(FBB::ISymCryptStreambuf) decrypt the data they receive. The values tt(ENCRYPT) and tt(DECRYPT) are defined in the tt(enum CryptType), which is defined in the tt(FBB) namespace. manpagesection(CONSTRUCTOR) itemization( itb(ISymCryptStreambuf( std::istream &in, char const *type, std::string const &key, std::string const &iv, size_t bufSize = 100, size_t filterBufSize = 1000, ENGINE *engine = 0)) This constructor initializes the streambuf. itemization( - tt(ISymCryptStreambuf) objects perform encryption;nl() tt(ISymCryptStreambuf) objects perform decryption;nl() - tt(ISymCryptStreambuf) objects obtain the bytes to encrypt or decrypt from tt(std::istream &in);nl() - The encryption method to use is specified by the tt(type) parameter. E.g., tt("bf-cbc") selects the Blowfish Cipher Block Chaining method;nl() - The symmetric key to use is specified by the tt(key) parameter;nl() - The initialization vector is specified by the tt(iv) parameter;nl() - The tt(FBB::ISymCryptStreambuf) internally used buffer will contain tt(bufSize) characters. The default value is the smallest value that is used. When a smaller tt(bufSize) value is specified, the default value is used;nl() - tt(FBB::ISymCryptStreambuf)'s tt(IFilterBuf) base class is initialized with a buffer of size tt(filterBufSize), using a lower bound of 100;nl() - The parameter tt(ENGINE) can be used to specify a hardware acceleration engine, as supported by the used encryption/decryption method. Its default argument value indicates that no hardware acceleration is available. ) ) Copy and move constructors (and assignment operators) are not available. manpagesection(EXAMPLE) The example shows the construction of an tt(ISymCryptStreambuf) object tt(ebuf) which is used to initialize a tt(std::istream) object. The information read from this tt(istream) is encrypted using the Blowfish CBC method. A tt(ISymCryptStreambuf) object (tt(dbuf) reads the information from that stream and decrypts it again). The tt(std::istream din) object is initialized with the tt(ISymCryptStreambuf) object, and its content is sent to tt(std::cout). The information that is presented at tt(std::cin) and that appears at tt(std::cout) should be identical. verbinclude(../../isymcryptstreambuf/driver/driver.cc) manpagefiles() em(bobcat/isymcryptstreambuf) - defines the class interface manpageseealso() bf(bobcat)(7), bf(encryptbuf)(3bobcat), bf(isymcryptstream)(3bobcat), bf(ibase64buf)(3bobcat), bf(ifilterbuf)(3bobcat), bf(ofilterbuf)(3bobcat), bf(std::streambuf). manpagebugs() Sep/Oct 2013: due to a change in library handling by the linker (cf. lurl(http://fedoraproject.org/wiki/UnderstandingDSOLinkChange) and lurl(https://wiki.debian.org/ToolChain/DSOLinking)) libraries that are indirectly required are no longer automatically linked to your program. With bf(BigInt) this is tt(libcrypto), which requires programs to link to both tt(bobcat) and tt(crypto). includefile(include/trailer) bobcat-5.09.01/documentation/man/omutexstream.yo0000644000175000017500000001076014050437223020642 0ustar frankfrankincludefile(include/header) COMMENT(replace 'classname' by the name of the new class) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::OMutexStream)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Mutex protected std::ostream) manpagename(FBB::OMutexStream)(Offers mutex protected std::ostream facilities) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() In multi-threaded programs output written by different threads to the same output stream may be intermixed due to context switches. This is prevented by using mutexes: before writing to the output stream a mutex lock is acquired, releasing the lock once the output is completed. tt(OMutexStream) supports writing to output streams while handling the mutex locks. The tt(OMutexStream) object itself is initialized with the tt(std::ostream) object to receive the information written to the tt(OMutexStream) object. This object, like tt(std::cout) and tt(std::err) usually is defined as a globally accessible object. When inserting information into the tt(OMutexStream) object tt(OMutexStream) first returns an tt(OMutexStream::Out) object, whose constructor locks the tt(OMutexStream::Out) mutex. The tt(OMutexStream::Out) object's lifetime ends at the end of the insertion statement, and at that time its destructor releases the lock. In many cases this is appropriate. Especially when statements end in newlines (tt('\n') or tt(endl)) this results in clean output. In some cases this approach doesn't work. Consider the situation where the output is produced by a series of iterations in a tt(for)-statement. For these cases tt(OMutexStream) offers the member tt(ostream) returning an tt(OMutexStream::Out) object. As that object also locks the mutex, the lock also remains active during its lifetime. During its lifetime separate tt(OMutexStream) insertions expressions may be executed. E.g., the following code fragment will complete all output forcing competing threads to wait: verb( void fun() { OMutexStream mout{ std::cout }; // create an OMutexStream object { auto out{ mout.ostream() } // locks the mutex (lock #1) mout << "Hello "; // also locks (lock #2, at ; // back to lock #1) out << "world\n"; } // 'out' releases the lock } ) Be careful to restrict the lifetime of the object returned by tt(OMutexStream::ostream()). includefile(include/namespace) manpagesection(INHERITS FROM) (via tt(OMutexStream::Out)) tt(std::ostream) manpagesection(CONSTRUCTORS) itemization( itb(OMutexStream(std::ostream &out)) The tt(OMutexStream) object is initialized with an tt(std::ostream) object. ) Copy and move constructors (and assignment operators) are available. manpagesection(OVERLOADED OPERATORS) itemization( itb(OMutexStream::Out operator<<(OMutexStream const &mstr, Tp &&tp)) This member is a function template. Its forwarding reference is passed on to the tt(OMutexStream::Out) object constructed by tt(mstr). Since tt(OMutexStream::Out) constructors lock the class's mutex, and since tt(OMutexStream::Out) was derived from tt(std::ostream) all insertion and other operations that are allowed for tt(std::ostream) can also be used for tt(OMutexStream::Out) objects. itb(OMutexStream::Out operator<<(OMutexStream const &mstr, Ret &(*manip)(Ret &os))) This member also is a function template. It is used for inserting manipulators without arguments into tt(OMutexStream::Out) objects. ) manpagesection(MEMBER FUNCTIONS) itemization( itb(OMutexStream::Out ostream() const) A tt(OMutexStream::Out) object is returned that has locked its mutex, and will keep the lock during its lifetime. All functionality of the tt(std::ostream) class can also be used for the tt(OMutexStream::Out) object returned by tt(ostream). Be careful to restrict the lifetime of the object returned by tt(OMutexStream::ostream()) to avoid needlessly long mutex locks. ) manpagesection(EXAMPLE) verbinclude(../../omutexstream/driver/driver.cc) manpagefiles() em(bobcat/omutexstream) - defines the class interface manpageseealso() bf(bobcat)(7) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/tablelines.yo0000644000175000017500000000246114050437223020226 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::TableLines)(3bobcat)(_CurYrs_) (libbobcat-dev__CurVers_)(Table support class) manpagename(FBB::TableLines)(A TableSupport specialization writing horizontal separation lines) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() This class is a specialization of tt(FBB::TableSupport) and can be used to write horizontal (and vertical) line separators in tables generated by tt(Table) or tt(TableBuf) objects. includefile(include/namespace) manpagesection(INHERITS FROM) bf(FBB::TableSupport) manpagesection(CONSTRUCTORS) The default, copy and move constructors as well as the copy and move assignment operators are available. manpagesection(MEMBER FUNCTIONS) All public members of tt(TableSupport) are available. The reader should refer to the bf(tablesupport)(3bobcat) man-page for details. manpagesection(EXAMPLE) verbinclude(../../table/driver/driver.cc) manpagefiles() em(bobcat/tableLines) - defines the class interface manpageseealso() bf(bobcat)(7), bf(align)(3bobcat), bf(table)(3bobcat), bf(tablebuf)(3bobcat), bf(tablesuppoer)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/csv4180.yo0000644000175000017500000002307714050437223017222 0ustar frankfrankNOUSERMACRO(CSV4180) includefile(include/header) COMMENT(replace 'classname' by the name of the new class) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::CSV4180)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (CSV4180 convertor) manpagename(FBB::CSV4180)(Converter for comma separated values) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() Objects of the class bf(CSV4180) can be used to convert series of comma separated values to the individual separated values (also called `fields' below). The class implements RFC 4180 (cf. lurl(https://www.ietf.org/rfc/rfc4180.txt), section 2). According to RFC 4180 lines contain comma separated values: comma separated values on one line are processed together, as a series of values. The final comma separated value on a line is not ended by a comma. Comma separated values may be surrounded by double quotes. However, they em(must) be surrounded by double quotes in these cases: itemization( it() if the values contain commas; it() if the values contain double quotes (in which case the double quote is `escaped' by doubling it, e.g., tt("a "" double quote")); it() if the values extend over multiple lines. E.g., verb( "First line second line" ) ) Comma separated values may be empty: the following line defines three empty comma separated values: verb( ,, ) The first empty value starts at the beginning of the line, and continues up to the first comma; the second empty value starts beyond the first comma and continues up to the second comma; the third empty value starts beyond the second comma, and continues up to the end of the line. If the line ends in blank space characters then the third value isn't empty, but contains those blank space characters. By default, values are interpreted as strings. The bf(CSV4180) class also offers facilities to ignore specific fields, or to ensure that they can be converted to integral or floating point values. The second constructor (below) expects a tt(std::string) argument defining how to interpret fields. Options are: itemization( it() tt(I): the field must be convertible to an integral value; it() tt(D): the field must be convertible to a floating point value; it() tt(S): the field is a string: it is used as-is; it() tt(X): the field is omitted from the final set of comma separated values. I.e., if a line contains three comma separated values, and the specification tt("SXS") is used then this results in two comma separated values: the first and third value of three comma separated values encountered on lines. it() tt(-): synonym of tt(X). ) In addition, field specifications may contain blank spaces, which are ignored. When processing comma separated values the first line may be considered a em(header) line. tt(X) specifications also apply to header lines, but otherwise they merely consist of tt(S)-type fields. In addition, when processing multiple input lines all non-header lines are made available in a vector of vectors of fields, whereas the header line itself can be accessed via a dedicated member (tt(header())). includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(CONSTRUCTORS) itemization( itb(explicit CSV4180(size_t nFields = 0, bool header = false, char fieldSep = ',')) The first parameter specifies the number of fields that must be present on input lines. When using the default value the number of fields encountered on the first line determines the number of fields that must be present on subsequent lines. If the second parameter is tt(true) then the first line is interpreted as the header line. The third parameter specifies the character separating the fields. By default it's a comma, but sometimes (not part of the RFC) a semicolon is used. By specifying tt(fieldSep) any character other than a comma can be used as field separator. itb(explicit CSV4180(std::string const &specs, bool header = false, char fieldSep = ',')) The first parameter defines the number and types of the comma separated values on input lines. Specifications can be quote( itemization( it() tt(D): the field must be convertible to a floating point value; it() tt(I): the field must be convertible to an integral value; it() tt(S): the field is left as-is, and can be retrieved as a tt(std::string). it() tt(X) or tt(-): the field is ignored and is not stored inside the bf(CSV4180) object. it() blank space characters are ignored. ) ) An exception is thrown when encountering other than the abovementioned characters are encountered. If tt(I) or tt(D) fields cannot be properly converted, or if a line contains too few or too many comma separated values the input stream's fail status is set. The last two parameters are interpreted as the last two parameters of the previous constructor. ) Copy and move constructors (and assignment operators) are available. manpagesection(OVERLOADED OPERATORS) itemization( itb(std::istream &operator>>(std::istream &in, CSV4180 &csv)) One line of text is extracted from tt(in) and processed by the tt(csv) object. The tt(csv) object may or may not already contain converted comma separated values. When empty, the first line is processed according to the specifications provided to the tt(csv) object at construction time. Otherwise, the comma separated values on extracted lines must match the number and types of the fields, as specified by the tt(csv) object. When input lines do not match these specifications tt(in's) fail status is set. ) manpagesection(MEMBER FUNCTIONS) itemization( itb(void clear(size_t nFields = 0)) The internally stored data (referred to by the tt(data, header,) and tt(lastLine) members) are erased. By default, the required number of CSV fields is reset to 0, but can be set to a specific value by specifying a value for its tt(nFields) parameter. itb(std::vector> const &data() const) A reference to the vector of vectors of fields stored inside the bf(CSV4180) object is returned. The vector returned by tt(data) does not contain the header line. If a header line was requested it can be retrieved from the tt(header()) member. itb(std::vector const &header() const) If the constructor's tt(header) parameter was specified as tt(true) then this member returns the fields encountered on the first line that was processed by the tt(read1) member. Otherwise, tt(header) returns a reference to an empty vector. itb(std::string const &lastLine() const) A reference to the last line that was successfully extracted from the input stream by the tt(read1) member is returned. So once the lines containing the comma separated values have been processed, the next line on the input stream can be obtained from this member. itb(size_t nValues() const) After successfully calling tt(read1) for the first time this member returns the required number of comma separated values that must be encountered on subsequent input lines. itb(size_t read(std::istream &in, size_t nLines = 0)) By default, all lines of tt(in) are read and are processed by the tt(read1) member. By specifying a non-zero value for the tt(nLines) parameter the specified number of lines is read from tt(in). Reading stops once tt(in's) status is not tt(good). When tt(nLines) is specified as zero, then tt(in's) status flags are cleared. The number of successfully processed lines is returned. itb(std::istream &read1(std::istream &in)) One line is read from tt(in) and is parsed for its comma separated values. If parsing fails, tt(in's fail) status is set. After successfully calling tt(read1) for the first time all subsequent lines read by tt(read1) must have the same number of comma separated values as encountered when calling tt(read1) for the first time. The parsed fields are stored in a vector of tt(std::string) objects, and that vector is added to the vector of vectors of strings that is returned by the tt(data) member. itb(std::vector> release()) The vector of vectors of fields stored inside the bf(CSV4180) object is returned. After calling tt(release) the internally stored vector of fields is empty. The vector returned by tt(data) does not contain the header line. If a header line was requested it can be retrieved from the tt(header()) member. Note that this member does not reset the number of expected fields for subsequently processed CSV-lines. If that's what you want, call tt(clear) after calling tt(release). ) manpagesection(EXAMPLE) verbinsert(//man1 ../../csv4180/driver/driver.cc) verbinsert(//man2 ../../csv4180/driver/driver.cc) verbinsert(//man3 ../../csv4180/driver/driver.cc) manpagefiles() em(bobcat/csv) - defines the class interface manpageseealso() bf(bobcat)(7) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/ifdstream.yo0000644000175000017500000000367514050437223020072 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::IFdStream)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (File Descriptor Input Stream) manpagename(FBB::Ifdstream)(Input Stream initialized by a File Descriptor) manpagesynopsis() bf(#include )nl() manpagedescription() bf(FBB::IFdStream) objects may be used to extract information from a device whose file descriptor is available. File descriptors are not defined within the context of bf(C++), but they can be used on operating systems that support the concept. Realize that using file descriptors introduces operating system dependencies. Note that em(sockets) can be used as file descriptors. includefile(include/namespace) manpagesection(INHERITS FROM) bf(std::istream) manpagesection(CONSTRUCTORS) itemization( itb(IFdStream(int fd, size_t n = 1)) The constructor initializes the object to read from descriptor tt(fd), using a buffer of size tt(n), by default having size 1. ) Copy and move constructors (and assignment operators) are not available. manpagesection(MEMBER FUNCTIONS) All members of bf(std::istream) are available, as bf(FBB::IFdStream) inherits from this class. There are no additional members. manpagesection(EXAMPLE) See the bf(clientsocket)(3bobcat) man-page for an example showing how to use tt(IFdStream). manpagefiles() em(bobcat/ifdstream) - defines the class interface manpageseealso() bf(bobcat)(7), bf(ifdbuf)(3bobcat), bf(ofdstream)(3bobcat) manpagebugs() The tt(IFdStream) object uses a tt(IFdStreamBuf) for its tt(std::streambuf). This buffer is associated with the file descriptor passed to tt(IFdStream)'s constructor. When the tt(IFdStream) object goes out of scope the device (file, socket, etc.) to which the file descriptor that was passed to tt(IFdStream)'s constructor is em(not) closed. includefile(include/trailer) bobcat-5.09.01/documentation/man/gs.inc0000644000175000017500000000110214050437223016626 0ustar frankfrank itemization( it() bf(BLOCK_DEVICE) (0060000): the object is a block device; it() bf(CHARACTER_DEVICE) (0020000): the object is a character device; it() bf(DIRECTORY) (0040000): the object is a directory; it() bf(FIFO) (0010000): the object is a named pipe (a queue); it() bf(REGULAR_FILE) (0100000): the object is a regular file; it() bf(SOCKET) (0140000): the object is a socket; it() bf(SYMBOLIC_LINK) (0120000): the object is a symbolic link; it() bf(ANY): any of the above types. ) bobcat-5.09.01/documentation/man/cmdfinderbase.yo0000644000175000017500000000145314050437223020672 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::CmdFinderBase)(3bobcat)(_CurYrs_) (libbobcat-dev__CurVers_)(Base class for CmdFinder) manpagename(FBB::CmdFinderBase) (Base class for the class CmdFinder) manpagesynopsis() see the bf(CmdFinder) manpage manpagedescription() This class is a base class for the class bf(CmdFinder). All its accessible members and features are described in the bf(CmdFinder) manpage. This class supports move and copy construction and assignment operations. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagefiles() See the bf(CmdFinder) manpage manpageseealso() bf(bobcat)(7), bf(cmdfinder)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/semaphore.yo0000644000175000017500000001724114050437223020071 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Semaphore)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Dijkstra's Semaphore) manpagename(FBB::Semaphore) (Implements the Semaphore type designed by Dijkstra) manpagesynopsis() bf(#include )nl() Linking option: tt(-lpthread -lbobcat) manpagedescription() According to tt(http://en.wikipedia.org/wiki/Semaphore_(programming)) a semaphore is a variable or abstract data type that is used for controlling access, by multiple processes, to a common resource in a parallel programming or a multi user environment. The tt(Semaphore) as a data type was designed around 1962 by Edsger Dijkstra. A useful way to think of a semaphore is as a record of how many units of a particular resource are available, coupled with operations to safely (i.e., without race conditions) adjust that record as units are required or become free, and, if necessary, wait until a unit of the resource becomes available. Semaphores are a useful tool in the prevention of race conditions. Semaphores allowing an arbitrary resource count are called counting semaphores, while semaphores which are restricted to the values 0 and 1 (or locked/unlocked, unavailable/available) are called binary semaphores. Both types are supported by Bobcat's implementation. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(CONSTRUCTORS) itemization( itb(Semaphore(size_t nAvailable)) The constructor defines the semaphore's initial state. With a counting semaphore tt(nAvailable) defines, e.g., the number of available locations in a storage area. Locking/unlocking, supporting facilities to notify other waiting threads is implemented via binary semaphores, which are initialized to 1 or 0. A semaphore containing the value 0 blocks. I.e., its tt(wait) member waits until its value is incremented by another thread, calling one of the semaphore's tt(notify) members. ) Copy and move constructors (and assignment operators) are not available. manpagesection(MEMBER FUNCTIONS) itemization( itb(void notify()) The internally maintained tt(available) value is incremented and one waiting thread (cf. the tt(wait) members below) is notified, reactivating that thread. itb(void notify_all()) The internally maintained tt(available) value is incremented and all waiting threads (cf. the tt(wait) members below) are notified. Only one waiting thread will be able to obtain the semaphore's lock and to reduce tt(available), and that particular thread is thereupon reactivated. itb(void set(size_t available)) This member blocks until it has obtained the lock of the tt(std::mutex) which is maintained internally by the tt(Semaphore) object. Next the tt(Semaphore's available) value receives the value of the member's argument, and the lock is released. itb(size_t size() const) Without trying to lock the tt(Semaphore) object's tt(mutex) the current value of the tt(Semaphore's available) value is returned. itb(void wait()) This member blocks for as long as the internally stored value (tt(available)) equals zero. When returning from tt(wait) the current thread holds the lock of the tt(std::mutex) which is maintained internally by the tt(Semaphore) object. tt(Notify) members are used to increment tt(available) and to inform tt(wait) that it may return. When multiple threads are waiting only one thread will stop waiting, while the remaining threads will continue to wait for another notification. itb(bool wait(Fun fun, Params &&...args)) This is a member template, where tt(Fun) is a function (object) receiving the argument passed to tt(wait), and returning a tt(bool). This member blocks until it has obtained the tt(Semaphore's) mutex lock, then, while its tt(available) value equals 0, waits until being notified. Once it has reacquired the lock after being notified tt(fun) is called, receiving tt(wait's) perfectly forwarded remaining arguments. This member returns tt(false) if tt(fun) returns tt(false). It returns tt(true) if tt(fun) returns tt(true) and tt(available) was unequal zero following tt(fun) returning tt(true). The function may therefore perform tasks outside of the tt(Semaphore) local environment, which might even involve updating the tt(Semaphore's) tt(available) value. itb(std::cv_status wait_for(std::chrono::duration const &relTime)) This member blocks for as long as the internally stored value (tt(available)) equals zero and the amount of time specified by tt(relTime) hasn't passed. If the latter happens, tt(std::cv_status::timeout) is returned, otherwise tt(std::cv_status::no_timeout) is returned, in which case the current thread holds the lock of the tt(std::mutex) which is maintained internally by the tt(Semaphore) object. tt(Notify) members are used to increment tt(available) and to inform tt(wait) that it may return. When multiple threads are waiting only one thread will stop waiting, while the remaining threads will continue to wait for another notification. itb(std::cv_status wait_until(std::chrono::time_point const &absTime)) This member blocks for as long as the internally stored value (tt(available)) equals zero and the time specified by tt(absTime) hasn't been reached. If the latter happens (or if tt(absTime) lies in the past) tt(std::cv_status::timeout) is returned, otherwise tt(std::cv_status::no_timeout) is returned, in which case the current thread holds the lock of the tt(std::mutex) which is maintained internally by the tt(Semaphore) object. tt(Notify) members are used to increment tt(available) and to inform tt(wait) that it may return. When multiple threads are waiting only one thread will stop waiting, while the remaining threads will continue to wait for another notification. ) manpagesection(EXAMPLE) verb( #include using namespace FBB; Semaphore produce(10); // storage area size Semaphore consume(0); // # items in store std::queue itemQueue; // storage queue void consumer() { while (true) { consume.wait(); // wait until there's an item in store // mutex lock the queue with multiple consumers size_t item = itemQueue.front(); itemQueue.pop(); produce.notify(); // notify the producer process(item); // not implemented } } void producer() { size_t item = 0; while (true) { ++item; produce.wait(); // wait for room in the storage // mutex lock the queue with multiple consumers itemQueue.push(item); consume.notify(); // notify the consumer } } int main() { thread cons(consumer); thread prod(producer); cons.join(); // ending the threads not implemented prod.join(); } ) manpagefiles() em(bobcat/semaphore) - defines the class interface manpageseealso() bf(bobcat)(7) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/localserversocket.yo0000644000175000017500000001721314050437223021637 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::LocalServerSocket)(3bobcat) (_CurYrs_)(libbobcat-dev__CurVers_) (Unix Domain Server Socket) manpagename(FBB::LocalServerSocket) (Unix Domain Server socket accepting connection requests) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() An bf(FBB::LocalServerSocket) defines a Unix Domain server socket, listening for connection requests from the local host using a Unix Domain socket. Connection requests may be accepted in either em(blocking) or em(non-blocking) modes. When a connection is accepted a socket is returned which may be used to read information from or write information to the client requesting the connection. The socket that is made available is a em(file descriptor) which may be used to initialize a bf(std::istream) and/or bf(std::ostream). The bf(std::istream) is used to read information from the client process; the bf(std::ostream) is used to send information to the client process. Since a socket may be considered a em(file descriptor) the available bf(FBB::IFdStream), bf(FBB::IFdStreamBuf), bf(FBB::OFdStream), and bf(FBB::OFdStreamBuf) classes may be used profitably here. Note that having available a socket does not mean that this defines the communication protocol. It is (still) the responsibility of the programmer to comply with an existing protocol or to implement a tailor-made protocol. The latter situation implies that the sequence of input- and output operations is defined by the programmer. includefile(include/namespace) manpagesection(INHERITS FROM) bf(FBB::LocalSocketBase) manpagesection(ENUMERATION) The following enumeration is defined in th class bf(FBB::LocalServerSocket): bf(enum Socket)nl() This enumeration holds two values: itemization( itb(KEEP) When this value is specified at construction time, the file representing the Unix Domain Socket is not removed when the bf(LocalServerSocket) is destroyed. itb(UNLINK) When this value is specified at construction time, the file representing the Unix Domain Socket is removed when the bf(LocalServerSocket) is destroyed. As a socket cannot be reused, this is the default value used with the bf(LocalServerSocket) constructor. ) manpagesection(CONSTRUCTOR) itemization( itb(LocalServerSocket()) This constructor creates an empty (non-functioning) tt(FBB::LocalServerSocket) object. Before it can be used, the tt(open()) member must be called (see below). itb(LocalServerSocket(string const &name, Socket action = UNLINK) throw (Exception)) This constructor initializes an bf(FBB::LocalServerSocket) object, which will listen for connection requests using the named Unix Domain socket. An bf(FBB::Exception) is thrown if the socket could not be constructed. If the constructor is given a second argument tt(FBB::LocalServerSocket::KEEP), the constructed socket is not unlinked when the bf(FBB::LocalServerSocket) object is destroyed. The construction of the socket does not mean that the bf(FBB::LocalServerSocket) object is actually listening for connections. To start listening, the member bf(listen()) should be called. ) Copy and move constructors (and assignment operators) are not available. manpagesection(MEMBER FUNCTIONS) itemization( itb(size_t accept()) The bf(accept()) member returns an tt(size_t) which is a file descriptor (socket) that may be used to communicate with the client requesting the connection. In more complex programs the returned file descriptor (socket) could be passed to a class derived from bf(FBB::Fork), handling the communication with the child as a separate (child) process. itb(void listen(size_t backlog = 5, bool blocking = true)) The bf(listen()) member defines the way the bf(FBB::LocalServerSocket) will listen for clients requesting a connection. It can be used only once with a bf(FBB::LocalServerSocket). An bf(FBB::Exception) object is thrown if listening fails. The bf(listen()) member's tt(backlog) parameter defines the size of the bf(FBB::LocalServerSocket)'s internal queue in which connection requests may be stored waiting for their turn to be serviced. When tt(backlog) requests are waiting and another request arrives, then that request is lost. The member's second parameter, tt(blocking), is used to control the blocking mode. By default, blocking is used, and tt(listen()) will wait until a connection is established. This is ok in situations where clients connect infrquently and for relatively short time intervals. Otherwise, in more complex programs, an bf(FBB::Selector) object can be used to sense input on the server socket and/or on various client sockets. itb(void open(string const &name, Socket action = UNLINK)) This member prepares a bf(FBB::LocalServerSocket) object for use. It should only be used in combination with the default constructor. Following tt(open()) the tt(FBB:::LocalServerSocket) object will be able to listen for connection requests using the named Unix Domain socket. An bf(FBB::Exception) is thrown if the socket could not be constructed. If the a second argument tt(FBB::LocalServerSocket::KEEP), is provided the constructed socket is not unlinked when the bf(FBB::LocalServerSocket) object is destroyed. The construction of the socket does not mean that the bf(FBB::LocalServerSocket) object is actually listening for connections. To start listening, the member bf(listen()) should be called next. ) manpagesection(EXAMPLE) See also the bf(localclientsocket)(3bobcat) example. verb( #include #include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) try { if (argc == 1) { cerr << "Provide local filename, e.g., /tmp/uds\n"; return 1; } LocalServerSocket server(argv[1]); cerr << "server using `" << argv[1] << "'" << endl; cout << "The server terminates when it receives a single `q' on a line\n" "A connection is terminated when no input is received anymore.\n" "Then another connection is possible" << endl; server.listen(); // listen in blocking mode while (true) { int fd = server.accept(); cerr << "Client FD = " << fd << ", " << endl; IFdStream in(fd); // stream to read from client OFdStream out(fd); // stream to write to client string cmd; while (getline(in, cmd)) { cout << "Got: " << cmd << endl; out << "Got: " << cmd << "\r" << endl; if (cmd[0] == 'q') return 0; } cout << "Ready for another connection\n"; } } catch (Exception const &err) { cerr << err.what() << endl << "Server socket on port " << argv[1] << " can't be opened" << endl; return -1; } ) manpagefiles() em(bobcat/serversocket) - defines the class interface manpageseealso() bf(bobcat)(7), bf(localclientsocket)(3bobcat), bf(fork)(3bobcat), bf(ifdstream)(3bobcat), bf(ifdbuf)(3bobcat), bf(localsocketbase)(3bobcat), bf(ofdstream)(3bobcat), bf(ofdstream)(3bobcat), bf(select)(2), bf(selector)(3bobcat), bf(serversocket)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/blockciphers0000644000175000017500000000267314050437223020133 0ustar frankfrank Block ciphers use one of the following four encryption modes: itemization( itb(CBC (Cipher Block Chaining)) The first block is XOR-ed by the initialization vector and then encrypted using the specified method. Subsequent blocks are XOR-ed by the encrypted version of the preceding block. Due to the initialization vector dictionary attacks are infeasible, as long as the initialization vector is truly random. itb(ECB (Electronic Code Book)) Each block is encrypted by itself, using the specified encryption method. Although an em(initialization vector) may be specified, it is not used. This method is susceptible to dictionary attacks and should therefore be avoided, unless you know what you're doing. itb(CFB (Cipher Feednack)) This method allows a block cipher to be used as a stream cipher. It uses an initialization vector, which should be unique and random for each new stream of data that is encrypted using the method. Encryption can only start after the first data block has been received. itb(OFB (Output Feednack)) This is an alternative way to use a block cipher as a stream cipher. It is somewhat more susceptible to traditional data manipulation attacks, which can usually be thwarted when a message authentication code is added to the information as well. Like CFB it uses an initialization vector, which should again be unique and random for each new stream of data that is encrypted. ) bobcat-5.09.01/documentation/man/hostname.yo0000644000175000017500000000366414050437223017730 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Hostname)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Host Info) manpagename(FBB::Hostname)(Contains name/address info about a host) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() bf(FBB::Hostname) objects inherit from tt(Hostent), and offers information about a host, like bf(Hostent). Apart from being initialized by a hostname or host address, they can also be initialized by a bf(FBB::InetAddress) object. Most of the functionality of an bf(FBB::Hostname) object is available through its parent-class bf(FBB::Hostent). includefile(include/namespace) manpagesection(INHERITS FROM) bf(FBB::Hostent) manpagesection(CONSTRUCTORS) itemization( itb(Hostname()) The default constructor initializes an empty bf(FBB::Hostname) object. itb(Hostname((std::string const &host))) This constructor initializes an bf(FBB::Hostname) object from a string representing the name or dotted decimal address of a host. An bf(FBB::Exception) object is thrown if the hostname information could not be retrieved. itb(Hostname(InetAddress const &inetAddress)) This constructor initializes an bf(FBB::Hostname) object from an bf(InetAddress) object. An bf(FBB::Exception) object is thrown if the hostname information could not be retrieved. ) Copy and move constructors (and assignment operators) are available. manpagesection(MEMBER FUNCTIONS) All members of bf(FBB::Hostent) are available, as bf(FBB::Hostname) inherits from this class. There are no additional members. manpagesection(EXAMPLE) verbinclude(../../hostname/driver/driver.cc) manpagefiles() em(bobcat/hostname) - defines the class interface manpageseealso() bf(bobcat)(7), bf(hostent)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/isharedstream.yo0000644000175000017500000002123514050437223020737 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::ISharedStream)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (std::istream on shared memory) manpagename(FBB::ISharedStream)(std::istream operations on shared memory) manpagesynopsis() bf(#include )nl() Linking option: tt(-lpthread -lbobcat) manpagedescription() This class offers the features of the bf(std::istream) class, operating on shared memory. includefile(include/namespace) manpagesection(INHERITS FROM) bf(FBB::ISharedBuf) (private inheritance),nl() bf(std::istream),nl() bf(FBB::SharedEnum__) (cf. bf(sharedmemory(3bobcat)) for a description of this last base class). manpagesection(SIZEUNIT ENUMERATION) The bf(enum SizeUnit) defines the following symbolic constants: itemization( it() bf(kB), representing 1024 (2**10) bytes of memory; it() bf(MB), representing 1048576 (2**20) bytes of memory; it() bf(GB), representing 1073741824 (2**30) bytes of memory ) manpagesection(CONSTRUCTORS) itemization( itb(ISharedStream()) The default constructor defines a stub a bf(ISharedStream) object that cannot immediately be used to access shared memory. To use it, its member tt(open) must first be called. itb(ISharedStream(size_t maxSize, SizeUnit sizeUnit, std::ios::openmode openMode = std::ios::in, size_t access = 0600)) This constructor creates an tt(std::istream) that interfaces to a shared memory segment having a capacity of at least tt(maxSize * sizeUnit) bytes. By default, the shared memory segment is opened for reading. Different from the open modes used for file streams, creating a shared memory stream with open modes tt(ios::in) is OK. In this case the shared memory segment is created and once information has been written to the shared memory by another process (or object) the information can be read. The shared memory's access rights are defined by the tt(access) parameter, using the well-known (bf(chmod)(1)) way to define the access rights for the owner, the group and others, using octal digits. If construction succeeds the shared memory is ready for use. If construction fails, an tt(FBB::Exception) is thrown. itb(ISharedStream(int id, std::ios::openmode openMode = std::ios::in)) This constructor creates an tt(std::istream) that connects to a shared memory segment having ID tt(id). If construction succeeds the shared memory is ready for use. If construction fails (e.g., no shared memory segment having ID tt(id) exists), an tt(FBB::Exception) is thrown. ) Copy and move constructors (and assignment operators) are not available. manpagesection(MEMBER FUNCTIONS) All members of tt(std::istream), and the tt(enum) values tt(kB, MB), and tt(GB), defined by tt(FBB::ISharedEnum__) are available. itemization( itb(FBB::SharedCondition attachSharedCondition(std::ios::off_type offset, std::ios::seekdir origin)) Returns an bf(FBB::SharedCondition)(3) object, interfacing to a shared condition variable located at offset tt(offset) (relative to tt(origin)) in the tt(SharedMemory) object to which the bf(ISharedStream) object interfaces. This member does not alter the value returned by the stream's tt(tellg) member. An tt(FBB::Exception) is thrown if the tt(FBB::SharedCondition) object could not be constructed. COMMENT( itb(FBB::SharedCondition createSharedCondition()) Returns an bf(FBB::SharedCondition)(3) object, interfacing to a newly created shared condition variable which is created at the current offset of the tt(SharedMemory) object to which the bf(ISharedStream) object interfaces (or at the first offset of the next physical shared memory data block, cf. bf(sharedcondition)(3bobcat)). Creating a tt(SharedCondition) object does not alter the value returned by the stream's tt(tellg) member. Note that this member em(changes) the information within the object's tt(SharedMemory) substrate, which is somewhat counter-intuitive for an em(std::istream) type of stream. An tt(FBB::Exception) is thrown if the tt(FBB::SharedCondition) object could not be constructed. END) itb(int id() const) The ID of the shared memory segment is returned. itb(void kill()) Without locking the shared memory first, all shared memory is returned to the operating system. The bf(FBB::ISharedStream) object is unusable after returning from tt(kill). Other processes that were using the shared memory can continue to do so. itb(void memInfo(std::ostream &out, char const *end = "\n")) Information about the tt(ISharedMemory) object is inserted into the provide tt(ostream) object. The IDs of the shared segments, their sizes, the maximum number of shared memory segments, the number of bytes that can be read from the shared memory, and its actual storage capacity, etc., are displayed. Following the information about the shaed memory, tt(end) is inserted into tt(out). itb(void open(size_t maxSize, SizeUnit sizeUnit, std::ios::openmode openMode = std::ios::in, size_t access = 0600)) This member creates a shared memory segment having a capacity of at least tt(maxSize * sizeUnit) bytes, and connects the shared memory segment to the bf(FBB::ISharedStream). A matching tt(close) member does not exist and is not required. By default, the shared memory segment is opened for reading. Different from the open modes used for file streams, creating a shared memory stream with open modes tt(ios::in) is OK. In this case the shared memory segment is created and once information has been written to the shared memory by another process it can be read. The shared memory's access rights are defined by the tt(access) parameter, using the well-known (bf(chmod)(1)) way to define the access rights for the owner, the group and others, using octal digits. If opening succeeds the shared memory is ready for use. If opening fails, an tt(FBB::Exception) is thrown. itb(void open(int id, std::ios::openmode openMode = std::ios::in)) This member connects the bf(FBB::ISharedStream) object to a shared memory segment having ID tt(id). A matching tt(close) member does not exist and is not required. If opening succeeds the shared memory is ready for use. If opening fails (e.g., no shared memory segment having ID tt(id) exists), an tt(FBB::Exception) is thrown. itb(void remove()) The shared memory is first locked. Next, all shared memory is returned to the operating system. The bf(FBB::ISharedStream) object is unusable after returning from tt(remove). Other processes that were using the shared memory can continue to do so. itb(bool truncate(std::streamsize offset)) If tt(offset) is not exceeding the value returned by tt(seekg(0, std::ios::end)), then this latter value is changed to tt(offset) and tt(true) is returned. Otherwise tt(false) is returned, and the value returned by tt(seekg) is not altered. If the value returned by tt(tellg) exceeded tt(offset), tt(tellg)'s return value it is reduced to tt(offset) as well. Subsequent read operations on the shared memory can only succeed as long as tt(tellg)'s return value hasn't reached the value tt(offset). ) manpagesection(EXAMPLE) See the bf(sharedstream)(3bobcat) man page. manpagefiles() em(bobcat/isharedstream) - defines the class interface manpageseealso() bf(bobcat)(7), bf(chmod)(1), bf(osharedstream)(3bobcat), bf(sharedblock)(3bobcat), bf(sharedcondition)(3bobcat), bf(sharedmemory)(3bobcat), bf(sharedmutex)(3bobcat), bf(sharedpos)(3bobcat), bf(sharedreadme)(7bobcat), bf(sharedsegment)(3bobcat), bf(sharedstream)(3bobcat), bf(sharedbuf)(3bobcat) manpagebugs() Note that by default exceptions thrown from within a bf(std::stream) object are caught by the stream object, setting its tt(ios::failbit) flag. To allow exceptions to leave a stream object, its tt(exceptions) member can be called, e.g., using: verb( myStream.exceptions(ios::failbit | ios::badbit | ios::eofbit); ) includefile(include/trailer) bobcat-5.09.01/documentation/man/tablebuf.yo0000644000175000017500000002544714050437223017701 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Table)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Construct text tables) manpagename(FBB::Table)(Generates row- or column-wise filled tables from information inserted into a std::ostream) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() bf(FBB::Tablebuf) objects are bf(std::streambuf) objects that can be used to create tables. The tables are filled either column-wise or row-wise. Many of the table's characteristics may be fine-tuned by a separate bf(FBB::TableSupport) object, described in a separate man-page (bf(TableSupport)(3bobcat)). When no bf(FBB::TableSupport) object is used, a plain row-wise or column-wise table is constructed which can be inserted into a bf(std::ostream). Displaying a table (e.g., at the standard output stream) involves the following steps: itemization( it() Optionally, a tt(TableSupport) object is created; it() A tt(Tablebuf) object is created (maybe passing it a tt(TableSupport) object); it() The tt(Tablebuf) object is used to initialize a tt(std::ostream) it() The elements of the table are filled by inserting information into that tt(std::ostream) it() The tt(Tablebuf) itself contains the formatted table and may itself be inserted into a tt(std::ostream) like tt(std::cout). ) Tables defined by tt(TableBuf) consist of a (number of element dependent) number of rows and a fixed number of columns, the latter value is specified at construction time. Columns and rows are normally addressed using index values (starting at 0). Before the leftmost column, between the columns and beyond the last column em(separators) are defined. By default the separators are empty, but each separator may be given a (fixed) width or content. The separator before column tt(col) is addressed as separator tt(col), the rightmost separator is addressed as separator tt(nColummns). Likewise, rows can be separated from each other using separators. These separating rows are also empty by default. The row-separator before row tt(row) is addressed as row-separator tt(row). The row-separator following the final row is addressed as row-separator tt(nRows), where tt(nRows) is the value returned by the tt(nRows) member function. Non-default (i.e., non-empty) separators are defined using tt(FBB::TableSupport) objects (cf. bf(tablesupport)(3bobcat)). tt(TableBuf)'s sister-class tt(Table) can be used to insert elements into a table in a more direct way. With tt(TableBuf) em(field separators) are used to switch to the next table-element, and (with row-wise filled tables) a em(row separator) can be used to switch to the next row when it's only partially defined. Instead, with tt(Table) objects each new insertion defines another table element, and no wrapping tt(std::ostream) object is required. includefile(include/namespace) manpagesection(INHERITS FROM) bf(std::streambuf) - allowing tt(TableBuf) objects to be wrapped in tt(std::ostream) objects. bf(FBB::TableBase) - This class implements common elements of the table implementation (the tt(FBB::TableBuf) class is also derived from tt(TableBase)). The tt(TableBase) class is not intended to be used otherwise, and no separate man-page is provided. All facilities provided by tt(Table) inherited from tt(TableBase) are described in this man-page. manpagesection(ENUMERATIONS) The following enumerations are defined in the class bf(FBB::Tablebuf). bf(enum FillDirection)nl() This enumeration has two values: itemization( itb(ROWWISE) When this value is specified at construction time, elements are added row-wise to the table. I.e., the second element inserted into the bf(Table) will be found in the second column of the first row. itb(COLUMNWISE) When this value is specified at construction time, elements are added column-wise to the table. I.e., the second element will be found in the second row of the first column. ) bf(enum WidthType)nl() This enumeration holds two values: itemization( itb(COLUMNWIDTH) This value may be specified when the columns should be allowed variable widths. In this case each column will be as wide as its widest element. This is the default bf(WidthType) used by bf(Table) objects. itb(EQUALWIDTH) This value may be specified when all the table's columns should have equal width (i.e., equal to the width of the widest table element), ) manpagesection(CONSTRUCTORS) itemization( itb(Tablebuf(size_t nColumns, Table::FillDirection direction, Table::WidthType widthType = Table::COLUMNWIDTH)) The table's number of columns, the fill directions and the column width-type must be provided. The number of rows is implied by the combination of this parameter and the number of elements that is actually inserted into the bf(Table) object. The bf(direction) parameter specifies the way new elements are added to the bf(Table) object: row-wise or column-wise. Finally, the tt(widthType) parameter is used to specify the way the width of the table's columns is determined. Each column either defines its own width or all columns have equal widths. itb(TableBuf(TableSupport &tableSupport, Table::FillDirection direction, Table::WidthType widthType = Table::COLUMNWIDTH)) This constructor operates identically to the previous constructor, but expects an additional reference to a bf(TableSupport) object. A bf(TableSupport) object offers additional formatting features used by the table defining elements like horizontal lines between rows, additional separators, etc, etc. The bf(TableSupport) object is passed as a non-const reference as the bf(Table) object must be able to manipulate its data. See bf(tablesuppport)(3bobcat) for more information about tt(TableSupport). ) Copy and move constructors (and assignment operators) are not available. manpagesection(OVERLOADED OPERATORS) itemization( itb(std::ostream &operator<<(std::ostream &out, TableBuf &tablebuf)) This operator inserts a bf(TableBuf) into a tt(std::ostream) object. Note that the tt(TableBuf) object inserted into tt(out) is a non-const object, as the table may have to be completed by adding empty elements for missing ones. The tt(out) stream should not be equal to the tt(std::ostream) object that is used to wrap in a tt(TableBuf) object. itb(TableBuf &operator<<(TableBuf &obj, Align const &align)) This operator is used to change the default alignment of either a column or an element. It is a wrapper around the member tt(setAlign()) (see below for its description). By default, all elements are right-aligned. See bf(align)(3bobcat) for more information about the tt(Align) class. Unlike the insertion operators available for tt(Table) type objects, the insertion operator for tt(TableBuf) objects is only used to define column or cell-alignment. ) manpagesection(MEMBER FUNCTIONS) itemization( itb(void clear()) The content of the table are erased. All existing elements are removed, and the table will be empty. itb(size_t nRows()) The currently available number of rows in the table is returned. Its value is only defined after calling bf(CHAR(d)ef()). itb(TableBuf &setAlign(Align const &align)) The alignment type of either a column or an element of the bf(TableBuf) object is defined using tt(setAlign). The standard alignments tt(std::left, std::right) and tt(std::internal) may be specified, but in addition the alignment tt(FBB::center) may be used if elements should be centered into their column. A construction like verb(tab << Align(2, FBB::center)) requests centering of all elements in the table's column having index value 2 (i.e., the table's 3rd column), whereas a construction like verb(tab << Align(2, 3, FBB::center)) requests centering of element [2][3]. It is the responsibility of the programmer to ensure that such elements exist. By default, all elements are right-aligned. itb(TableBuf &CHAR(d)ef()) After inserting elements into a tt(TableBuf) object its number of elements may or may not be an integral multiple of the number of columns specified at construction time. To `complete' a bf(TableBuf) object to a rectangular object, for which all column widths and alignments have been determined tt(def) may be called. It is automatically called by tt(operator<<(ostream, TableBuf)). In other situations it may be called explicitly to force the insertion of another row in a table using tt(ROWWISE) insertions. With tt(COLUMNWISE) insertions its working is complex, since new elements added to a tt(COLUMNWISE) filled table will reshuffle its elements over the table's columns. itb(setFieldSeparator(char fs)) The default field separator is the `backspace' (tt(\b)) character. After inserting a field separator the next table element will be defined. Inserting two field separators inserts an table empty element and starts the definition of the next element. This field separator character can be redefined by this function. Calling tt(setFieldSeparator) without argument disables the use of a field separator character, and only leaves the use of the tt(fs) manipulator to switch to the next field. itb(setRowSeparator(char rs)) The default row separator is the newline character (tt(\n)). After inserting a row separator the next element to enter into the table will be the leftmost element of the next row. Inserting two row separators adds an empty row to the table. Calling tt(setRowSeparator) without argument disables the use of a row separator character, and only leaves the use of the tt(rs) manipulator to switch to the next field. ) manpagesection(MANPULATORS) itemization( itb(Table &CHAR(d)ef(Table &table)) This manipulator can be inserted into a a tt(TableBuf)'s wrapping tt(ostream) to call the table's bf(CHAR(d)ef()) member. itb(FBB::fs) This manipulator can be inserted into a tt(TableBuf)'s wrapping tt(ostream) to switch to the next field of the table. It is an alternative to using the field separator character. itb(FBB::rs) This manipulator can be inserted into a tt(TableBuf)'s wrapping tt(ostream) to switch to the next row of the table. It is an alternative to using the row separator character. ) manpagesection(EXAMPLE) verbinclude(../../tablebuf/driver/driver.cc) manpagefiles() em(bobcat/tablebuf) - defines the class interface;nl() manpageseealso() bf(bobcat)(7), bf(align)(3bobcat), bf(manipulator)(3bobcat), bf(tablelines)(3bobcat), bf(tablesupport)(3bobcat), bf(table)(3bobcat) manpagebugs() Note that tt(CHAR(d)ef()) will reshuffle elements over the table's columns when new elements are added to the table subsequent to calling tt(CHAR(d)ef()) includefile(include/trailer) bobcat-5.09.01/documentation/man/mlm.yo0000644000175000017500000000515614050437223016675 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::mlm)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (OFoldStream manipulator) manpagename(FBB::mlm)(Manipulator modifying left margins of OFoldStream objects) manpagesynopsis() bf(#include ) or nl() bf(#include ) nl() Linking option: tt(-lbobcat) manpagedescription() The tt(mlm) class implements a manipulator that can be inserted into tt(OFoldStream) objects to modify the stream's left margin by a requested amount. The request cannot result in a negative left margin value. If a negative left margin would be the arithmetic result of the request then left margin 0 will silently be used. Depending on the tab-setting of the tt(OFoldStream) the inserted value represents the number of blank space characters or the number of tab-characters that will be added to the left margin. The request will be processed at the next newline character or tt(std::flush) or tt(std::endl) manipulator that is inserted into the stream. If a line is still empty once an tt(mlm) object and a tt(flush) manipulator are inserted into the stream then the new left margin will be effective at the next word inserted into that line (cf., the example section below) A em(bad_cast) exception is thrown when the manipulator is inserted into an tt(ostream) that is not using a tt(OFoldBuf) buffer. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(CONSTRUCTOR) itemization( itb(mlm(int addValue)) ) Copy and move constructors (and assignment operators) are available. manpagesection(MEMBER FUNCTIONS) itemization( itb(std::ostream &modify(std::ostream &out) const) This member is normally not directly called from user-programs. Instead, it is called by the insertion operator when inserting the tt(mlm) manipulator. ) manpagesection(EXAMPLE) verb( #include #include using namespace std; using namespace FBB; int main() { OFoldStream out(cout, 0, 80); out << "hello world (left margin is 0)" << mlm(4) << "\n" "this uses a 4 character wide left margin\n" << mlm(-10) << flush << "left margin -6 changed to 0, active on this line\n"; } ) manpagefiles() em(bobcat/mlm) - defines the class interface manpageseealso() bf(bobcat)(7), bf(manipulators)(3bobcat), bf(lm)(3bobcat), bf(ofoldstream)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/string.yo0000644000175000017500000002732314050437223017416 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::String)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Operations on std::string objects) manpagename(FBB::String)(Several operations on bf(std::string) objects) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() This class offers facilities for often used transformations on tt(std::string) objects, which are not supported by the tt(std::string) class itself. All members of bf(FBB::String) are static. Initially this class was derived from bf(std::string). Deriving from tt(std::string), however, is considerd bad design as tt(std::string) was not designed as a base-class. bf(FBB::String) offers a series of em(static) member functions providing the facilities originally implemented as non-static members. One of these members is the (overloaded) tt(split) member, splitting a string into elements separated by one or more configurable characters. These elements may contain or consist of double- or single-quoted (sub) strings and escape characters. Escape characters are converted to their implied byte-values (e.g., tt(\n) is converted to byte value 10) unless they are embedded in single-quoted (sub) strings. Quotes surrounding double- and single-quoted (sub) strings are removed from the elements returned by the tt(split) members. includefile(include/namespace) manpagesection(INHERITS FROM) -- manpagesection(ENUMERATIONS) itemization( itb(Type) This enumeration indicates the nature of the content of an element in the array returned by the overloaded tt(split) members (see below). bf(DQUOTE), a subset of the characters in the matching tt(string) element was delimited by double quotes in the in the string that was parsed by the tt(split) members. bf(DQUOTE_UNTERMINATED), the content of the string that was parsed by the tt(split) members started at some point with a double quote, but the matching ending double quote was lacking. bf(ESCAPED_END), the content of the string that was parsed by the tt(split) members ended in a mere backslash. bf(NORMAL), a normal string; bf(SEPARATOR), a separator; bf(SQUOTE), a subset of the characters in the matching tt(string) element was delimited by quotes in the in the string that was parsed by the tt(split) members. bf(SQUOTE_UNTERMINATED), the content of the string that was parsed by the tt(split) members started at some point with a quote, but the matching ending quote was lacking. itb(SplitType) This enumeration is used to specify how tt(split) members should split the information in the string objects that are passed to these members: bf(TOK): the tt(split) member acts like the standard bf(C) function bf(strtok)(3). The essence here is that no empty elements are returned. E.g., a string containing tt("a,,") which is processed using the tt(TOK) mode returns a tt(NORMAL) element containing tt("a"). bf(TOKSEP): the tt(split) member acts like the standard bf(C) function bf(strtok)(3), also returning information about encountered separators. Since tt(strtok) doesn't return empty elements, tt(TOKSEP) uses empty elements to indicate the occurrence of separators. E.g., a string containing tt("a,,") which is processed using the tt(TOKSEP) mode returns a tt(NORMAL) element containing tt("a"), followed by two empty tt(SEPARATOR) elements. bf(STR): the tt(split) member acts like the standard bf(C) function bf(strstr)(3). The essence here is that empty elements are also returned. E.g., a string containing tt("a,,") which is processed using the tt(STR) mode returns an element containing tt("a"), followed by two empty tt(NORMAL) elements. bf(STRSEP): the tt(split) member acts like the standard bf(C) function bf(strstr)(3), also returning information about encountered separators. E.g., a string containing tt("a,,") which is processed using the tt(STRSEP) mode returns a tt(NORMAL) element containing tt("a"), followed by a tt(SEPARATOR) element containing tt(","), followed by a tt(NORMAL) empty element, followed by a tt(SEPARATOR) element containing tt(","), and finally followed by a tt(NORMAL) empty element, ) manpagesection(TYPEDEF) The bf(typedef SplitPair) represents bf(std::pair) and is used by some overloaded bf(split) members (see below). manpagesection(STATIC MEMBER FUNCTIONS) itemization( itb(char const **argv(std::vector const &words)) Returns a pointer to an allocated series of pointers to the bf(C) strings stored in the vector tt(words). The caller is responsible for returning the array of pointers to the common pool, but should em(not) delete the bf(C)-strings to which the pointers point. The last element of the returned array is guaranteed to be a 0-pointer. itb(int casecmp(std::string const &lhs, std::string const &rhs)) Performs a case-insensitive comparison of the content of two tt(std::string) objects. A negative value is returned if tt(lhs) should be ordered before tt(rhs); 0 is returned if the two strings have identical content; a positive value is returned if the tt(lhs) object should be ordered beyond tt(rhs). itb(std::string escape(std::string const &str, char const *series = "'\"\\")) Returns a copy of tt(str) in which all characters in tt(series) are prefixed by a backslash character. itb(std::string join(std::vector const &words, char sep)) The elements of the tt(words) vector are returned as one string, separated from each other by the tt(sep) character; itb(std::string join(std::vector const &entries, char sep, bool all = true)) The tt(first) fields of the elements in tt(entries) are returned as one string, separated from each other by the tt(sep) character. If the parameter tt(all) is specified as tt(false) then elements whose tt(second) fields are equal to tt(String::SEPARATOR) are ignored. itb(std::string lc(std::string const &str) const) Returns a copy of tt(str) in which all letters were transformed to lower case letters. itb(std::vector split(std::string const &str, SplitType mode, char const *sep = " \t")) The string tt(str) is split into substrings, separated by any of the characters in tt(sep). The substrings are returned in a vector of tt(SplitPair) elements, using the specified tt(SplitType) mode (cf. the description of the various tt(SplitPair) values and their effects in the tt(ENUMERATIONS) section). itb(std::vector split(std::string const &str, char const *separators = " \t", bool addEmpty = false)) This member acts like the previous one, using tt(addEmpty == false) to select tt(mode TOK) and tt(addEmpty == true) to select tt(mode TOKSEP). itb(size_t split(std::vector *entries, std::string const &str, SplitType mode, char const *sep = " \t")) Same functionality as the first tt(split) member, but this member stores the tt(SplitPair) elements in the vector pointed at by the tt(entries) parameter, first clearing the vector. This member returns the new value of tt(entries->size()). itb(size_t split(std::vector *entries, std::string const &str, char const *sep = " \t", bool addEmpty = false)) This member acts like the previous one, using tt(addEmpty == false) to select tt(mode TOK) and tt(addEmpty == true) to select tt(mode TOKSEP). itb(std::vector split(Type *type, std::string const &str, SplitType stype, char const *sep = " \t")) Same functionality as the first tt(split) member, but this member merely stores the tt(first) fields of the tt(SplitPair) elements in the returned vector. The tt(String::Type) variable whose address is passed to the tt(type) parameter is set to tt(NORMAL) if the final entry was successfully determined; to tt(DQUOTE_UNTERMINATED) if a final closing double quote could not be found; to tt(SQUOTE_UNTERMINATED) if a final closing single quote could not be found; and to tt(ESCAPE_END) if the final character in tt(str) is a backslash character. itb(std::vector split(Type *type, std::string const &str, char const *sep = " \t", bool addEmpty = false)) This member acts like the previous one, using tt(addEmpty == false) to select tt(mode TOK) and tt(addEmpty == true) to select tt(mode TOKSEP). itb(size_t split(std::vector *words, std::string const &str, SplitType stype, char const *sep = " \t")) Same functionality as the first tt(split) member, but this member merely stores the tt(first) fields of the encountered tt(SplitPair) elements in the vector pointed at by tt(words), first clearing the vector. This member returns the new value of tt(words->size()). itb(size_t split(std::vector *words, std::string const &str, char const *sep = " \t", bool addEmpty = false)) This member acts like the previous one, using tt(addEmpty == false) to select tt(mode TOK) and tt(addEmpty == true) to select tt(mode TOKSEP). itb(std::string trim(std::string const &str)) Returns a copy of tt(str) from which leading and trailing blank characters were removed. itb(std::string uc(std::string const &str)) Returns a copy of tt(str) in which all letters were capitalized. itb(std::string unescape(std::string const &str)) Returns a copy of tt(str) in which the escaped (i.e., prefixed by a backslash) characters were interpreted. All standard escape characters (tt(\a), tt(\b), tt(\f), tt(\n), tt(\r), tt(\t), tt(\v)) are recognized. If an escape character is followed by tt(x) at most the next two characters are interpreted as a hexadecimal number. If an escape character is followed by an octal digit, then at most the next three characters following the em(backslash) are interpreted as an octal number. In all other cases, the backslash is removed and the character following the backslash is kept. itb(std::string urlDecode(std::string const &str)) URL specifications use tt(%xx) encoding to encode characters, except for alpha-numeric characters and the characters tt(- _ .) and tt(~), which are kept as-is. Other characters are encode by a tt(%) character, followed by two hexadecimal characters representing those characters' byte value. E.g., a blank space is encoded as tt(%20), a plus character is encoded as tt(%2B). The member tt(urlDecode) returns a tt(std::string) containing the decoded characters of the url-encoded string that is passed as argument to this member. itb(std::string urlEncode(std::string const &str)) See the member tt(urlDecode): tt(urlEncode) returns a tt(std::string) containing the url-encoded characters of the characters in the string that is passed as argument to this member. ) manpagesection(EXAMPLE) verbinclude(../../string/driver/driver.cc) manpagefiles() em(bobcat/string) - defines the class interface manpageseealso() bf(bobcat)(7) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/primefactors.yo0000644000175000017500000001417114050437223020603 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::PrimeFactors)(3bobcat)(_CurYrs_) (libbobcat-dev__CurVers_)(Prime Factorization) manpagename(FBB::PrimeFactors)(Performs the prime-number factorization of (BigInt) values) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() Integral values fall into two categories: prime numbers, whose only integral divisors are their own values and 1, and composite numbers, which also have at least one other (prime number) integral divisor. All composite integral values can be factorized as the product of prime numbers. E.g., 6 can be factorized as 2 * 3; 8 can be factorized as 2 * 2 * 2. Finding these prime factors is called the prime number factorization, or `prime factorization'. When factorizing a value its prime factors may sometimes repeatedly be used as integral divisors: 8 is factorized as tt(pow(2, 3)), and 36 is factorized as verb( 36 = pow(2, 2) * pow(3, 2) ) The class bf(FBB::PrimeFactors) performs prime number factorizations of tt(FBB::BigInt) values. When factorizing a value prime numbers up to tt(sqrt(value)) must be available, as prime numbers up to tt(sqrt(value)) may be factors of tt(value). Currently tt(PrimeFactors) uses the sieve of Eratosthenes to find these prime numbers. To find the next prime number beyond tt(lastPrime), the sieve of Eratosthenes must be used repeatedly for tt(lastPrime += 2) until tt(lastPrime) is prime. Once determined, prime numbers can of course be used directly to determine the next prime number or to factorize an integral value. To accellerate prime number factorization and Eratosthenes's sieve bf(PrimeFactors) saves all its computed prime numbers in either a tt(std::vector) or in a file. Once determined, these prime numbers may again be used when factorizing the next integral value. After factorizing an integral value its prime number factors and associated powers are made available in a vector of (tt(PrimeFactors::PrimePower)) structs, containing the value's sorted prime factors and associated powers. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(TYPEDEFS AND ENUMS) itemization( itb(struct PrimePower) contains two fields: verb( struct PrimePower { BigInt prime; size_t power; }; ) Here, tt(power) represents the number of times tt(prime) can be used as an integral divisor of the value that was factorized by bf(PrimeFactors). itb(Factors) is a synonym for tt(std::vector)nl() Linking option: tt(-lbobcat -lcrypto) manpagedescription() The class tt(CryptBuf) inherits from tt(EoiBuf) and may therefore be used as a base class of classes specializing tt(std::streambuf). It is used as base class for the classes tt(DecryptBuf) and tt(EncryptBuf), offering a protected member for accessing cipher information. includefile(include/namespace) manpagesection(INHERITS FROM) tt(EoiBuf) (and thus from: tt(std::streambuf)) manpagesection(PROTECTED CONSTRUCTOR) Analogously to tt(std::streambuf) only a protected constructor is available. itemization( itb(CryptBuf(char const *type, size_t bufSize)) The type is a null-terminated byte string specifying the de/encryption method. E.g., tt(aes-128-cbc). For an overview see the bf(encryptbuf)(3bobcat) man-page. The tt(bufSize) parameter defines the initial size of the internally used buffer (defined by tt(EoiBuf)). ) Copy and move constructors (and assignment operators) are not available. manpagesection(PROTECTED MEMBER FUNCTION) All members of tt(std:streambuf) and tt(EoiBuf) are available, as bf(FBB::CryptBuf) inherits from these classes. itemization( itb(EVP_CIPHER const *md() const) A pointer to the cipher information is returned. ) manpagesection(EXAMPLE) Here is an example from the implementation of tt(EncryptBuf's) constructor: verbinclude(../../encryptbuf/encryptbuf1.cc) manpagefiles() em(bobcat/cryptbuf) - defines the class interface manpageseealso() bf(bobcat)(7), bf(decryptbuf)(3bobcat), bf(encryptbuf)(3bobcat), bf(eoibuf)(3bobcat), bf(eoi)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/binopsbase.yo0000644000175000017500000000667214050437223020241 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(binopsbase)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Binary Operators) manpagename(BinopsBase)(Class template offering class-type binary operators) manpagesynopsis() bf(#include )nl() manpagedescription() Classes may overload binary operators. A class named tt(Derived) may overload binary operators to suit its own needs. It could, e.g., allow two tt(Derived) class objects to be added together, or it could define a shift-operation given a tt(size_t) right-hand side (rhs) argument. The available binary operators are *, /, %, +, -, <<, >>, &, |, and ^ (in this man-page they are generically indicated as the `tt(@)' operator). In addition, overloaded tt(operator<<) and tt(operator>>) for stream insertion and extraction are frequently defined. If a class tt(Derived) supports copy and/or move construction and if it offers a swap member (tt(void Derived::swap(Derived &rhs))), and is publicly derived from tt(FBB::BinopsBase) then once tt(Derived) defines a member verb( void Class::operator@=(Rhs const &rhs) && ) defining the compound tt(@)-operator for anonymous, temporary tt(Derived) objects and a tt(Rhs) type for its right-hand side operand the following operators are also available: verb( Derived &operator@=(Rhs const &rhs) & Derived operator@(Derived &&lhs, Rhs const &rhs); Derived operator@(Derived const &lhs, Rhs const &rhs); ) A similar procedure applies to the insertion and extraction operators. Insertion and extraction operators become available once tt(BinopsBase) is declared a friend class of tt(Derived). To make the insertion operator available a private member verb( void Derived::insert(std::ostream &out) const ) must then also be defined, inserting the calling object into tt(out). Analogously, to make the extraction operator available a private member verb( void Derived::extract(std::istream &in) ) must be defined extrating the calling object from tt(in). manpagesection(INHERITS FROM) -- manpagesection(OVERLOADED OPERATORS) For each defined tt(Derived &&operator@=(Rhs const &rhs) &&), defined in the class tt(Derived) the following operators are automatically also available: verb( Derived operator@(Derived &&lhs, Rhs const &rhs); Derived operator@(Derived const &lhs, Rhs const &rhs); ) and verb( Derived &operator@=(Rhs const &rhs) &; ) The insertion operator becomew available once verb( void Derived::insert(std::ostream &out) const ) (inserting the calling object into tt(out)) has been defined. Analogously, the extraction operator becomes available after defining a private member verb( void Derived::extract(std::istream &in) ) (extracting the calling object from tt(in)). manpagesection(FRIEND DECLARATION) To make the insertion and/or extraction operators available the class tt(Derived) must also declare verb( friend FBB::BinopsBase; ) manpagesection(EXAMPLE) verbinclude(../../binopsbase/driver/driver.cc) manpagefiles() em(bobcat/binopsbase) - defines the binary operator function templates manpageseealso() bf(bobcat/binops)(3), bf(bobcat)(7) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/syslogbuf.yo0000644000175000017500000001777014050437223020132 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::SyslogBuf)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Stream Buffer for Syslog) manpagename(FBB::SyslogBuf)(A streambuf object inserting syslog messages) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() Addresses of bf(FBB::SyslogBuf) objects can be passed as bf(std::streambuf) addresses to tt(std::ostream) objects to write messages to the syslog daemon using stream facilities. Multiple separate insertions can be used to create a single syslog message: the message is only sent to the syslog daemon after receiving a tt(flush) command (e.g., after inserting tt(std::flush) or tt(std::endl)). Non-printable characters (like tt('\n')) show up in the syslog message as octal values, preceded by tt(#) (e.g., tt(#012) for tt('\n')). The newline normally inserted by tt(std::endl) is ignored: bf(SyslogStream) objects interpret tt(std::endl) like tt(std::flush). One series of insertions may contain multiple tt(std::endl) or tt(std::flush) manipulators. At each of these manipulators a new message is sent to the syslog daemon, containing all info that has so far been buffered. After sending a message to the syslog daemon, the bf(SyslogStream)'s internal buffer is cleared. includefile(include/namespace) manpagesection(INHERITS FROM) tt(FBB::EoiBuf) and thus from tt(std::streambuf) manpagesection(ENUMERATIONS) The following enumerations are defined in the namespace bf(FBB): bf(Priority): The values of this enumeration match the corresponding priority bf(LOG_xxx) values used with bf(syslog)(3): itemization( itb(EMERG) system is unusable; itb(ALERT) action must be taken immediately; itb(CRIT) critical conditions; itb(ERR) error conditions; itb(WARNING) warning conditions; itb(NOTICE) normal, but significant, condition; itb(INFO) informational message; itb(DEBUG) debug-level message; ) bf(PriorityType): This enumeration has two values fine-tuning the type of messages that are actually processed by the syslog daemon: itemization( itb(SINGLE) Only messages of the priority specified at the tt(setMask) call are processed by the syslog daemon; itb(UPTO) Messages of priority tt(EMERG) up to the the priority specified at the tt(setMask) call are processed by the syslog daemon; ) By default, the syslog daemon processes all messages it receives. bf(Facility): The values of this enumeration match the corresponding facility bf(LOG_xxx) values used with bf(syslog)(3): itemization( itb(AUTHPRIV) security/authorization messages (private) itb(CRON) clock daemon (tt(cron) and tt(at)) itb(DAEMON) other system daemons itb(KERN) kernel messages itb(LOCAL0) reserved for local use. bf(LOCAL1) through bf(LOCAL7) are available as well. itb(LPR) line printer subsystem itb(MAIL) mail subsystem itb(NEWS) tt(USENET) news subsystem itb(SYSLOGBUF) messages generated internally by tt(syslogbufd) itb(USER) generic user-level messages itb(UUCP) UUCP subsystem ) manpagesection(CONSTRUCTOR) itemization( itb(SyslogBuf(string const &ident = "", FBB::Priority priority = FBB::NOTICE, FBB::Facility facility = FBB::USER, int option = 0)) The tt(ident) parameter is usually the name of the program. Its content are prepended to syslog messages. The tt(priority) parameter determines the default importance of the message sent to the syslog daemon. By default messages are sent to the syslog daemon with priority bf(FBB::NOTICE). Syslog messages may be given different priority by inserting a bf(SyslogStream)(3bobcat) manipulator. The priority set at construction time may also be modified using the tt(setPriority) and tt(setDefaultPriority) members. Which messages actually appear in log facilities is not determined by the messages' priorities, but by syslog's em(log mask). The log mask can be set by the static member tt(setMask) (see below). The tt(facility) parameter determines the type of program doing the logging. By default bf(FBB::USER) is used. The tt(option) parameter may be used to specify various options (use the binary `tt(bitor)' (`tt(|)') operator to combine options): bf(LOG_CONS): write directly to system console if there is an error while sending to system logger nl() bf(LOG_NDELAY): open the connection immediately (normally, the con- nection is opened when the first message is logged) nl() bf(LOG_PERROR): print to stderr as well nl() bf(LOG__PID): include PID with each message nl() By default no options are used. ) Copy and move constructors (and assignment operators) are not available. manpagesection(MEMBER FUNCTIONS) All members of bf(std::streambuf) are available, as bf(FBB::SyslogBuf) inherits from this class. itemization( itb(Priority defaultPriority() const) Returns the current default priority. I.e., the priority that will be used for the messages after inserting tt(endl) or tt(flush). itb(void eoi()) If the bf(SyslogStream)'s internal buffer is not empty it is flushed to the syslog daemon. Thereafer bf(closelog)(3) is called. Instead of using this member the tt(eoi) manipulator can also be used. itb(Priority priority() const) Returns the next priority. I.e., the priority that will be used for the next message that is sent to the syslog daemon. itb(void reset(string const &ident, FBB::Priority priority = FBB::NOTICE, FBB::Facility facility = FBB::USER, int option = 0)) Redefines the current identifier, priority, facility and options that are used when sending messages to the syslog daemon. If the bf(SyslogStream)'s internal buffer is not empty it is first flushed to the syslog daemon using the identifier, priority and options that were active just before calling tt(open). itb(Priority setDefaultPriority(Priority priority)) Changes the default priority of the next message that is sent to the syslog daemon after inserting tt(std::eoln) or tt(std::flush). The previously active default priority is returned. itb(Priority setPriority(Priority priority)) Changes the priority for the next message that is sent to the syslog daemon after inserting tt(std::eoln) or tt(std::flush). Subsequent messages will again use the default priority. The previously active priority setting is returned. ) manpagesection(MANIPULATOR) itemization( itb(FBB::eoi) The tt(eoi) manipulator can be inserted into the tt(ostream) instead of calling the tt(SyslogBuf::end) member. It performs the same actions as the tt(eoi) member. If inserted into a plain tt(std::ostream) nothing happens. ) manpagesection(EXAMPLE) See also bf(syslogstream)(3bobcat) verb( #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) { ostream sls(new SyslogBuf(argv[0])); sls << SyslogStream::debug << "Hello world" << flush << SyslogStream::strerrno << endl; } ) manpagefiles() em(bobcat/syslogbuf) - defines the class interface manpageseealso() bf(bobcat)(7), bf(closelog)(3), bf(openlog)(3), bf(rsyslogd)(8) bf(syslog)(3), bf(syslogstream)(3bobcat) manpagebugs() The constructor's tt(option) parameter is an tt(int). Because of this, tt(int) values rather than enumeration values are passed to the constructor. It is the responsibility of the programmer to pass defined option values only. includefile(include/trailer) bobcat-5.09.01/documentation/man/gethostent.yo0000644000175000017500000000776314050437223020302 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::GetHostent)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Host information) manpagename(FBB::GetHostent) (Obtain bf(hostent) struct from hostname or -address) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() bf(FBB::GetHostent) objects produce tt(hostent) structs which may be used by other types of objects. The bf(FBB::GetHostent) class is therefore primarily used as a base-class for other classes and is seldomly used `stand-alone'. The tt(hostent) structs are static structs, but a non-static copy may be obtained using an bf(FBB::Hostent) object. A tt(hostent) struct is defined as follows: verb( struct hostent { char *h_name; // official name of host char **h_aliases; // alias list int h_addrtype; // host address type (always AF_INET) int h_length; // length of address char **h_addr_list; // list of addresses } ) The tt(address) fields are binary values of the addresses, each address requiring tt(h_length) bytes, the last address being equal to 0. These binary values may be converted to character-representations by the tt(addressToString()) member, which uses bf(inet_ntop()), internally. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(CONSTRUCTORS) All members of the class bf(FBB::GetHostent) are static. Consequently, there is no need to construct a bf(FBB::GetHostent) object. manpagesection(STATIC MEMBERS) itemization( itb(hostent const *gethostent(char const *errorprefix, std::string const &nameOrAddress)) The bf(gethostent()) member returns a pointer to a static bf(struct hostent). It contains the information about the host whose name or dotted decimal address was provided as its second argument. Its first argument is an error string prefix, prefixing the error message in an bf(FBB::Exception) object. Such an object is thrown as an exception when the host's information could not be retrieved. itb(std::string addressToString(char const *errorprefix, void const *ads)) This member returns the dotted decimal address of the host whose binary address is provided at bf(ads). Its first argument is an error string prefix, prefixing the error message in an bf(FBB::Exception) object. Such an object is thrown as an exception when the dotted decimal address could not be determined. The class' members can only be used when the host whose name or address is searched can be resolved by a name resolution process, e.g., bf(bind)(1). ) manpagesection(EXAMPLE) verb( #include #include #include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) try { if (argc == 1) { cerr << "Provide a host name or host address to solve\n"; return 1; } Hostent he(GetHostent::gethostent(argv[1], argv[1])); cout << "Hostname: " << he.hostname() << endl; cout << "Aliases:\n"; copy(he.beginAlias(), he.endAlias(), ostream_iterator(cout, "\n")); cout << "Addresses:\n"; for (size_t idx = 0; idx < he.nAddresses(); idx++) cout << he.dottedDecimalAddress(idx) << endl; } catch (Exception const &err) { cout << err.what() << endl; return 1; } ) manpagefiles() em(bobcat/gethostent) - defines the class interface manpageseealso() bf(bind)(1), bf(bobcat)(7), bf(gethostbyaddr)(3) bf(gethostbyname)(3), bf(hostent)(3bobcat), bf(inetaddress)(3bobcat), bf(inet_ntop)(3) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/onekey.yo0000644000175000017500000000541114050437223017374 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::OneKey)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (One keystroke input) manpagename(FBB::OneKey)(Single keystroke input, not requiring `Return') manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() bf(OneKey) objects may be used to realize `direct keyboard input': a pressed key becomes available without the need for pressing tt(Enter). The characters are obtained from the standard input stream. Direct key entry remains in effect for as long as the bf(OneKey) object exists. Once the object is destroyed the standard input stream will return to its default mode of operation, in which input is `confirmed' by a newline character. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(ENUMERATION) The bf(OneKey::Mode) enumeration is used to control echoing of returned characters. It has two values: itemization( it() bf(OFF): returned characters are em(not) echoed to the standard output stream; it() bf(ON): returned characters em(are) echoed to the standard output stream. ) manpagesection(CONSTRUCTORS) itemization( itb(OneKey(OneKey::Mode state = OneKey::OFF)) This constructor initializes the bf(OneKey) input object. By default, entered characters are not echoed. By constructing the object with the bf(OneKey::ON) argument, entered characters are echoed to the standard output stream. This construct throws an tt(Exception) exception if it not properly complete. The constructor may fail for the following reasons: itemization( it() the standard input stream is not a tty (e.g., when the standard input stream is redirected to a file); it() the current state of the standard input stream can't be determined; it() the standard input stream's state can't be changed to the `direct keyboard input' mode. ) ) Copy and move constructors (and assignment operators) are not available. manpagesection(MEMBER FUNCTIONS) itemization( itb(int get() const) Returns the next character from the standard input stream, without the need for pressing tt(Enter). itb(void setEcho(OneKey::Mode state)) Changes the echo-state of the bf(OneKey) object. The argument may be either bf(OneKey::ON) or bf(OneKey::OFF). ) manpagesection(EXAMPLE) verbinclude(../../onekey/driver/driver.cc) manpagefiles() em(bobcat/onekey) - defines the class interface manpageseealso() bf(bobcat)(7), bf(tty)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/field.yo0000644000175000017500000001051114050437223017162 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Field)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Number fields) manpagename(FBB::Field)(sets and retrieves offset based number fields) manpagesynopsis() bf(#include )nl() manpagedescription() Numbers may contain offset-based sub-fields. E.g., a value like 12345 might consist of fields 12 and 345. Such fields can be considered offset-based, using end- and begin offsets in the number representations. In this example 345 begins at digit position 0 (indicating the least significant digit of 12345) and at digit position 3 the next field starts. Likewise, the field 12 begins at digit position 3 and has ended at digit position 5. The tt(Field) class template provides facilities for retrieving and assigning position based values of existing numeric values of (currently) at most 64 bits. To represent such fields the following format is used: verb( Field::function(argument(s)) ) where tt(base) specifies the number system's base value, tt(end) specifies the (0-based) index position where the number field ends, and tt(begin) specifies the index position where the number field begins. Here are two examples, using the decimal number system: verb( Field<10, 3, 0>::get(12345) // returns 345 Field<10, 5, 3>::get(12345) // returns 12 ) The decision to specify the tt(end) offset before (i.e., left of) the tt(begin) offset is based on the consideration that this corresponds to the standard way of looking at digit positions in numbers, where the end offset is found to the left of the begin offset. Values of fields can be retrieved, but they can also be set: to set a field's value the following format is used: verb( Field<10, 3, 1>::set(12345, 99) // returns 12995 Field<10, 1, 0>::set(12345, 0) // returns 12450 ) When values are assigned to fields the maximum width of the destination field is taken into account. When specifying 9999 instead of 99 in the above example the returned value will still be 12995, as the destination field has a width of two digit positions. Likewise, specifying a smaller value sets the remaining (more significant) digits to 0: verb( Field<10, 3, 1>::set(12345, 9) // returns 12095 ) The class templates themselves are unaware of bases of number systems. Since 0xdeaf equals the decimal value 57007 and 0xd equals 13, calling the above function as verb( Field<16, 1, 0>::set(76007, 13) ) returns the hexadecimal value tt(0xdead'). The tt(Field) class template requires three non-type numeric arguments: itemization( itt(base), specifying the base of the number system; itt(end), specifying the 0-based offset of the digit position where the field has ended; itt(begin), specifying the 0-based offset of the digit position where the field begins; ) The class template is specialized for situations where tt(base) is a mere power of 2 (like 2, 4, 8, 16, ...) because in those cases bit-operations can be used which are faster than multiplications, divisions and modulo computation which are required when other number system bases are used. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(MEMBER FUNCTIONS) itemization( itb(uint64_t Field::get(uint64_t value)) tt(value) is interpreted as a value in the tt(base) number system, and using digit positions in that number system the value of the digits from offset tt(begin) to (but not including) offset tt(end) is returned; itb(uint64_t Field::set(uint64_t value, uint64_t field)) tt(value) is interpreted as a value in the tt(base) number system, and using digit positions in that number system the digits from offset tt(begin) to (but not including) offset tt(end) are replaced by tt(field's) value. When the number of tt(fields's) digits (also using number system tt(base)) exceeds tt(end - begin) then those excess digits are ignored. ) manpagesection(EXAMPLE) See the examples in the bf(DESCRIPTION) section manpagefiles() em(bobcat/field) - defines the class interface manpageseealso() bf(bobcat)(7) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/sharedsegment.yo0000644000175000017500000002203014050437223020727 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::SharedSegment)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Shared Memory Data) manpagename(FBB::SharedSegment)(Shared Memory data structure) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat ) manpagedescription() The class bf(FBB::SharedSegment) implements the shared memory data structure used by Bobcat's shared memory classes. Bobcat's tt(SharedMemory) class accesses or defines a shared memory segment, controlling all its read and write operations. The requested amount of shared memory is always a lower bound to the maximum amount of shared memory that eventually may become available. When defining a bf(SharedSegment) object not all of its potentially available shared memory is immediately allocated. Shared memory will be allocated by the bf(SharedSegment) object once needed (up to a calculated maximum). As a fictitious example: assume 100 kB of memory is requested, then the bf(SharedSegment) object, maintains a table of, e.g., 10 entries, each controlling the access to a shared memory block of 10 kB. These 10 kB blocks aren't immediately allocated, but become available once the program reads from or writes to addresses located in these data segments. The class bf(SharedSegment) therefore defines a gateway, controlling access to and allocating required shared memory data segments. The mentioned table consists of tt(nBlocks SharedBlock) (bf(sharedblock)(3bobcat)) values, offering mutexes and IDs of shared data segments. The mutexes control which process has access to a particular block of shared data memory, and the IDs are either -1, meaning that their shared memory data segments has as not yet been allocated, or they contain the IDs of defined shared memory data segments. The class bf(SharedSegment)'s sole responsibility is to offer the framework as described. When used by a tt(FBB::SharedMemory) object different processes may gain access to different parts of the shared memory data without interfering each other's read and write actions. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(CONSTRUCTORS) No publicly accessible constructors have been defined for bf(SharedSegment). A static member function tt(create) (see below) is available, returning a pointer to a shared memory segment, in which a bf(SharedSegment) has been defined. manpagesection(OVERLOADED OPERATORS) itemization( itb(std::ostream &operator<<(std::ostream &out, SharedSegment const &sharedData)) The overloaded insertion operator inserts basic statistics of the shared memory data into the tt(ostream) object. Information about the IDs of the shared segments, their sizes, the maximum number of shared data segments and the number of bytes that can be read from the shared memory are displayed. itb(FBB::SharedBlock &operator[](size_t idx)) Table element tt(idx) of the table of tt(FBB::SharedBlock) block IDs is returned. The behavior of the program is undefined if tt(idx) is or exceeds tt(nBlocks()). ) Copy and move constructors (and assignment operators) are not available. manpagesection(MEMBER FUNCTIONS) itemization( itb(size_t access() const) Returns the access rights of the shared memory segment as a number which is usually interpreted as an octal value, using the well-known (bf(chmod)(1)) way to define the access rights for owner, group and others. itb(void clear()) All the shared memory data blocks are unconditionally deleted and tt(nReadable) returns 0 (the shared memory data blocks are not locked prior to deleting them). After calling tt(clear) all allocated bf(SharedSegment)'s shared memory segments have ceased to exist and can no longer be used. itb(void lock(size_t idx) const) Access to shared data segment tt(idx) is locked. This member itself does not support recursive locking. itb(size_t nBlocks() const) Returns the number of shared memory data blocks that can be used by the bf(FBB::SharedSegment) object. itb(int newData(size_t idx)) Returns the ID of a newly created shared memory data segment. The ID is also stored in the table of shared memory data segments that is maintained by the bf(SharedSegment) object. An tt(FBB::Exception) is thrown if the shared memory data segment could not be allocated. itb(std::streamsize nReadable() const) Returns the number of characters (bytes) that can be read from the beginning of the shared memory. itb(void nReadableLock() const) When returning from this member function a lock has been obtained of bf(SharedSegment)'s mutex controlling access the the object's data member storing the number of characters that can be read from the shared memory controlled by the bf(SharedSegment) object. itb(void nReadableUnlock() const) This member function releases the lock previously acquired by tt(nReadableLock). itb(size_t segmentSize() const) Returns the size (in bytes) of the shared memory data blocks. The bf(SharedSegment) object can accommodate at most tt(segmentSize() * nBlocks()) bytes. itb(bool truncate(std::streamsize offset)) After calling tt(nReadableLock), if tt(offset) is not exceeding the value returned by tt(nReadable) tt(nReadable) is changed to tt(offset) and tt(true) is returned. Otherwise tt(false) is returned, and the value returned by tt(nReadable) has not been changed. Before returning tt(nReadableUnlock) is called. itb(void unlock(size_t idx) const) Releases the lock on the shared memory data segment tt(idx). If the current process does not own the lock of shared memory data block tt(idx) nothing happens and the function immediately returns. itb(void updateNreadable(std::streamsize offset)) The number of bytes that can be retrieved from the shared memory is updated to tt(max(nReadable(), offset)). ) manpagesection(STATIC MEMBER FUNCTIONS) itemization( itb(void *attach(int id)) Returns the address of shared memory segment tt(id), mapped to the calling process's memory area. An tt(FBB::Exception) is thrown if the shared memory data segment could not be attached. itb(SharedSegment *create(int *id, size_t nBlocks, size_t segmentSize, size_t access)) Returns a pointer to a newly created bf(SharedSegment) object, defined in the computer's shared memory. The created shared memory's ID is stored at tt(*id). The remaining arguments define the potential number of shared memory data blocks (tt(nBlocks)); the size of these data blocks (tt(segmentSize)); and the shared memory's access rights (tt(access), using the well-known octal value representation as used by (bf(chmod)(1)) to define access rights for the owner, the group and others). An tt(FBB::Exception) is thrown if the shared memory data segment could not be created. itb(void deleteSegment(int id)) The shared memory segment having ID tt(id) is deleted. After calling tt(deleteSegment) shared memory segment tt(id) doesn't exist anymore. The tt(id) can be the shared memory ID of any segment for which the current user has write permissions. An tt(FBB::Exception) is thrown if shared memory data segment tt(id) could not be deleted. itb(Type *detach(Type *sharedPtr, bool requireOK = true)) This member is defined as a member template. It expects a pointer to a shared memory segment, previously mapped on the calling process's memory space by tt(attach), and detaches it from the process's memory space, returning 0. By default, detaching the memory must succeed or an bf(FBB::Exception) is thrown. Throwing an exception on failure can be prevented by passing tt(false) as the member's second argument. itb(size_t size(int id)) The size (in bytes) of shared memory data block having ID tt(id) is returned. An tt(FBB::Exception) is thrown if the size of segment tt(id) could not be determined. ) manpagesection(EXAMPLE) See the bf(sharedstream)(3bobcat) man page. manpagefiles() em(bobcat/sharedsegment) - defines the class interface manpageseealso() bf(bobcat)(7), bf(chmod)(1), bf(isharedstream)(3bobcat), bf(osharedstream)(3bobcat), bf(sharedblock)(3bobcat), bf(sharedcondition)(3bobcat), bf(sharedmemory)(3bobcat), bf(sharedmutex)(3bobcat), bf(sharedpos)(3bobcat), bf(sharedreadme)(7bobcat), bf(sharedstream)(3bobcat), bf(sharedbuf)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/hash.yo0000644000175000017500000000651514050437223017033 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Hash)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Key hashing containers) manpagename(FBB::Hash)(Various mapping template classes using hashing) manpagesynopsis() bf(#include )nl() manpagedescription() The bf(FBB:Hash) group of template classes offer hashing-based mapping. Various variants are available, all based on the facilities offered by the bf(unordered_map). The hash-map offered in the bf(unordered_map) container has a fairly complex construction interface, and tt(Hash) is an attempt to simplify this part of its interface. In practice, hashing uses a textual key, which may be bf(std::string) or tt(char *) based, and the keys may be used either case sensitively or case insensitively. tt(Hash) merely requires its users to specify the map's value type, while the key may be a tt(char const *) or tt(std::string), used case sensitively or case insensitively. includefile(include/namespace) manpagesection(INHERITS FROM) bf(std::unordered_map), using various instantiations. manpagesection(TYPE) All variants define tt(value_type) as the corresponding tt(unordered_map value_type). In practice a tt(value_type) defines a tt(std::pair), where tt(Key) represents the hash's key-type and tt(Value) represents the hash's value type. manpagesection(CONSTRUCTORS) Variants of the tt(FBB::Hash) container are available for tt(char const *) or tt(std::string) keys, used case sensitively or case insensitively. All variants support default and move construction (as well as move assignment), support construction from initializer lists. and support construction from iterators defining a half-open range of tt(value_type) values. The following variants are available (showing their default constructors). tt(Value) refers to the value type stored in the hash table. itemization( itb(HashCharPtr()) this hash table uses em(case sensitive) bf(char const *) keys; itb(HashCharCasePtr()) this hash table uses em(case insensitive) bf(char const *) keys; itb(HashString()) this hash table uses em(case sensitive) bf(std::string) keys; itb(HashStringCase()) this hash table uses em(case insensitive) bf(std::string) keys; ) manpagesection(OVERLOADED OPERATOR) In addition to the index operator inherited from tt(unordered_map) the overloaded copy and move assignment operators are available for all tt(Hash) containers. manpagesection(MEMBER FUNCTIONS) All members of the tt(unordered_map) container are available, as tt(Hash) inherits from this template class. manpagesection(EXAMPLE) verb( #include #include using namespace std; using namespace FBB; pair ap[] = { pair("one", 1), pair("two", 2), }; int main() { HashCharPtr hcp; HashCharPtr hcp2(ap, ap + 2); HashCharPtr hcp3(hcp2); hcp = hcp2; cout << hcp2["one"] << endl; } ) manpagefiles() em(bobcat/hash) - defines the class interface manpageseealso() bf(bobcat)(7) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/symcryptciphers0000644000175000017500000001016114050437223020722 0ustar frankfrankCOMMENT( method type keysize blocksize identifier) def(ROW)(5)(row(cell(ARG1)cell(ARG2)cell(ARG3)cell(ARG4)cell("ARG5"))) The following table presents an overview of methods that are currently available. Methods for which the block size is specified as N.A. are stream ciphers; other methods are block ciphers: table(5)(lllll)( rowline() row(cell(method)cell(keysize)cell(blocksize)cell(mode)cell(identifier)) row(cell()cell((bytes))cell((bytes))) rowline() ROW(AES) (16) (8)(CBC)(aes-128-cbc) ROW() ( ) ( )(EBC)(aes-128-ecb) ROW() ( ) ( )(CFB)(aes-128-cfb) ROW() ( ) ( )(OFB)(aes-128-ofb) ROW() (24) (24)(CBC)(aes-192-cbc) ROW() ( ) ( )(EBC)(aes-192-ecb) ROW() ( ) ( )(CFB)(aes-192-cfb) ROW() ( ) ( )(OFB)(aes-192-ofb) ROW() (32) (32)(CBC)(aes-256-cbc) ROW() ( ) ( )(EBC)(aes-256-ecb) ROW() ( ) ( )(CFB)(aes-256-cfb) ROW() ( ) ( )(OFB)(aes-256-ofb) rowline() ROW(BLOWFISH)(16) (8)(CBC)(bf-cbc) ROW() ( ) ( )(EBC)(bf-ecb) ROW() ( ) ( )(CFB)(bf-cfb) ROW() ( ) ( )(OFB)(bf-ofb) row(setmanalign(lssss)cell(max key length is 56 bytes, 16 generally used)) rowline() ROW(CAMELLIA) (16) (16)(CBC)(camellia-128-cbc) ROW() ( ) ( )(EBC) (camellia-128-ecb) ROW() ( ) ( )(CFB) (camellia-128-cfb) ROW() ( ) ( )(OFB) (camellia-128-ofb) ROW() (24) ()(CBC) (camellia-192-cbc) ROW() ( ) ( )(EBC) (camellia-192-ecb) ROW() ( ) ( )(CFB) (camellia-192-cfb) ROW() ( ) ( )(OFB) (camellia-192-ofb) ROW() (32) ()(CBC) (camellia-256-cbc) ROW() ( ) ( )(EBC) (camellia-256-ecb) ROW() ( ) ( )(CFB) (camellia-256-cfb) ROW() ( ) ( )(OFB) (camellia-256-ofb) rowline() ROW(CAST)(16) (8)(CBC)(cast-cbc) ROW() ( ) ( )(EBC)(cast-ecb) ROW() ( ) ( )(CFB)(cast-cfb) ROW() ( ) ( )(OFB)(cast-ofb) row(setmanalign(lssss) cell(min key length is 5 bytes, max is shown)) rowline() ROW(DES)(8)(8)(CBC)(des-cbc) ROW() ( )( )(EBC)(des-ebc) ROW() ( )( )(CFB)(des-cfb) ROW() ( )( )(OFB)(des-ofb) rowline() ROW(DESX)(8)(8)(CBC)(desx-cbc) rowline() ROW(3DES)(16)(8)(CBC)(des-ede-cbc) ROW() ( ) ( )(EBC)(des-ede) ROW() ( ) ( )(CFB)(des-ede-cfb) ROW() ( ) ( )(OFB)(des-ede-ofb) rowline() ROW(3DES)(24)(8)(CBC)(des-ede3-cbc) ROW() ( ) ( )(EBC)(des-ede3) ROW() ( ) ( )(CFB)(des-ede3-cfb) ROW() ( ) ( )(OFB)(des-ede3-ofb) row(setmanalign(lssss) cell(Key bytes 9-16 define the 2nd key, bytes 17-24)) row(setmanalign(lssss)cell(define the 3rd key)) rowline() ROW(RC2) (16)(8)(CBC)(rc2-cbc) ROW() ( ) ( )(EBC)(rc2-ecb) ROW() ( ) ( )(CFB)(rc2-cfb) ROW() ( ) ( )(OFB)(rc2-ofb) row(setmanalign(lssss)\ cell(Key length variable, max. 128 bytes, default length is shown)) rowline() ROW(RC2-40)(5)(8)()(rc2-40-cbc) row(setmanalign(lssss)cell(obsolete: avoid)) rowline() ROW(RC2-64)(8)(8)()(rc2-64-cbc) row(setmanalign(lssss)cell(obsolete: avoid)) rowline() ROW(RC4)(16)(N.A.)()(rc4) row(setmanalign(lssss)\ cell(Key length is variable, max. 256 bytes. default length is shown)) row(setmanalign(lssss) cell(Encrypt again to decrypt. Don't use tt(DecryptBuf))) rowline() ROW(RC4-40)(5)(N.A.)()(rc4-40) row(setmanalign(lssss)cell(obsolete: avoid)) rowline() ROW(RC5) (16)(8) (CBC)(rc5-cbc) ROW() ( ) ( ) (EBC)(rc5-ecb) ROW() ( ) ( ) (CFB)(rc5-cfb) ROW() ( ) ( ) (OFB)(rc5-ofb) row(setmanalign(lssss) cell(Key length variable, max. 256 bytes, rounds 8, 12 or 16,)) row(setmanalign(lssss) cell(default # rounds is 12)) rowline() ) The RC4 stream cipher is subject to a well-known attack (cf. lurl(http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Mantin1.zip)) unless the initial 256 bytes produced by the cipher are discarded. bobcat-5.09.01/documentation/man/stat.yo0000644000175000017500000002710014050437223017054 0ustar frankfrankincludefile(include/header) COMMENT( see also getgroups ) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Stat)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Characteristics of object in the filesystem) manpagename(FBB::Stat)(Determines File Characteristics) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() bf(Stat) is a wrapper around the bf(stat)(2) and bf(lstat)(2) system functions. In particular, it offers features to test directly for object characteristics offered by these two functions. To determine whether an object could properly be constructed use the tt(Stat bool) conversion operator. If this operator returns tt(false) then no other member except for tt(error) should be used. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(ENUMERATIONS) bf(Stat::Combine): nl() This enumeration defines the following values: itemization( it() bf(ALL): require all of the specified bf(Mode) or bf(SpecialMode) values to match; it() bf(ANY): require any match of the specified bf(Mode) or bf(SpecialMode) values (one match suffices); ) bf(Stat::Mode): nl() This enumeration defines the following values: itemization( it() bf(UR): the owner of the object has read permissions it() bf(UW): the owner of the object has write permissions it() bf(UX): the owner of the object has execute permissions it() bf(GR): the group to which the object belongs has read permissions it() bf(GW): the group to which the object belongs has write permissions it() bf(GX): the group to which the object belongs has execute permissions it() bf(OR): others have read permissions it() bf(OW): others have write permissions it() bf(OX): others have execute permissions it() bf(READ): equal to tt(UR | GR | OR) it() bf(WRITE): equal to tt(UW | GW | OW) it() bf(EXEC): equal to tt(UX | GX | OX) it() bf(RWX): all of the above. ) bf(Stat::SpecialMode): nl() This enumeration defines the following values: itemization( it() bf(SUID): set UID bit is up it() bf(SGID): set GID bit is up it() bf(SB): sticky bit is up ) bf(Stat::Type): nl() This enumeration, which is identical to the bf(glob)(3bobcat) tt(Type) enumeration, defines the following values: includefile(gs.inc) bf(Stat::Lstat): nl() This enumeration has one value: tt(LStat), which can be specified by construtors and some members when the tt(Stat) object should distinguish regular files and symbolic links (calling bf(lstat)(2)) instead of considering symbolic links as regular files (using bf(stat)(2)). Constructors and members that define tt(Stat::Lstat) parameters call bf(lstat)(2), thus distinguishing symbolic links from regular files, while constructors and members that do not define tt(Stat::Lstat) parameters use bf(stat)(2). The return values of the members tt(statStruct) and tt(type) and tt(typeStr) (see below) only distinguish symbolic links from regular files when the tt(Stat::LStat) argument has been used. The constructors and member functions listed below for which tt([Stat::Lstat,]) is specified as first parameter may optionally specify the tt(Stat::LStat) argument. manpagesection(CONSTRUCTORS) itemization( itb(Stat()) The default constructor, creating an empty bf(Stat) object. It's mainly used as default object when defining, e.g., vectors of tt(Stat) objects. As it doesn't refer to an existing file system entry its tt(operator bool) returns false; itb(Stat([Stat::Lstat,] std::string const &fname)) Initializes a bf(Stat) with a given object name; itb(Stat([Stat::Lstat,] std::string const &fname, std::string const &searchPath)) Initializes a bf(Stat) with a given object name, where the object is searched in the tt(searchPath) directories, which is a colon-separated string of directory names. The filenames are constructed by appending tt(fname) to each of the elements of tt(searchPath) until an existing object is found. This object is then used. If tt(fname) is an absolute path, tt(searchPath) is ignored. ) Copy and move constructors (and assignment operators) are available. manpagesection(OVERLOADED OPERATORS) itemization( itb(operator bool() const) This operator returns tt(true) if the tt(Stat) object holds information about an existing object. Otherwise tt(false) is returned. When tt(false) is returned other members, except for the assignment operators, the tt(error) member, and the tt(set) members should not be used. ) manpagesection(MEMBER FUNCTIONS) itemization( itb(bool access(FBB::User const &user, size_t spec, bool useEffective = true) const) Returns tt(true) if tt(user) has the permissions as specified at tt(spec) (of which only the defined tt(Mode) bits are interpreted). If a combination of read, write and/or execute permissions are specified, then at least one of the read permissions, one of the write permissions and one of the execute permissions must be granted or the function returns tt(false). E.g, when specifying tt(access(user, UW | UR | GR)) then the user em(must) have write permissions, but either the user or the user's group must have read permissions. If multiple read, multiple write or multiple execute permissions are specified (like tt(UR | GR)) then this member returns tt(true) if at least one of the requested read, write, or execute permissions are granted for tt(user). itb(size_t blockSize() const) Returns the blocksize (tt(st_blksize)) for filesystem I/O itb(size_t device() const) Returns the device id (tt(st_dev)). itb(size_t deviceType() const) Returns the device type number, but only if the object type is bf(DEVICE) (tt(st_rdev)). itb(size_t error() const) Returns the error number associated with an error, in cases where bf(operator bool()) returns bf(false). A returned value of 0 indicates `no errors'. To obtain a verbal transcription of returned error numbers the tt(Exception::errnodescr) manipulator (cf. bf(exception)(3bobcat)) can be used. itb(bool isType(Stat::Type probe)) Returns tt(true) if the object has the probed type otherwise tt(false) is returned. itb(size_t inode() const) Returns the inode number (tt(st_ino)). itb(size_t gid() const) Returns the group ID of the object's owner (tt(st_gid)). itb(FBB::DateTime lastAccess() const) Returns an bf(FBB::DateTime) object holding information about the object's time of last access (tt(st_atime)) (using UTC). itb(FBB::DateTime lastChange() const) Returns an bf(FBB::DateTime) object holding information about the object's time of last status change (tt(st_ctime)) (using UTC). itb(FBB::DateTime lastModification() const) Returns an bf(FBB::DateTime) object holding information about the object's last modification time (tt(st_mtime)) (using UTC). itb(size_t mode() const) Returns the object's raw, uninterpreted mode (tt(st_mode & RWX)). Note that this value is usually displayed (and is processed most easily) as an octal value. itb(bool mode(size_t mode, Combine combine = ALL)) Returns true if the object has the indicated mode. Multiple modes may be set, which can be combined by the logical bf(bitor) operator. By default, if multiple modes are specified, the resulting pattern must exactly represent the object's mode for the member function to return bf(true). An optional argument tt(ANY) may be specified if the function should return true if at least one specified mode matches the object's actual mode. An tt(Exception) exception is thrown if the specified tt(mode) contains other values than the defined bf(Mode) or bf(SpecialMode) values. itb(std::string modeStr() const) Returns the standard string-representation of the object's mode (e.g., tt(rw-r--r--)). Special modes (e.g., suid) are indicated by tt(s) instead of tt(x) when the object is user and/or group executable and by tt(S) if the object has the special mode bit(s) set, but is not executable. For the `other' executable mode flag tt(t) is used (`sticky' bit) and tt(T) if the object is not `other' executable. itb(std::string const &name() const) Returns the object's name as specified in the constructor or bf(set()) member function. itb(size_t nBlocks() const) Returns the object's number of allocated blocks (tt(st_blocks)). itb(size_t nLinks() const) Returns the object's number of hard links (tt(st_nlink)). itb(std::string path() const) Returns the object's full pathname. If the full pathname could not be determined, an empty string is returned. itb(bool set([Stat::Lstat,] std::string const &name)) Redefine the bf(Stat) object to represent the information about the indicated object name. itb(bool set([Stat::Lstat,] std::string const &name, std::string const &pathlist)) Redefine the bf(Stat) object to represent the information about the indicated object name, where the object is searched in the tt(pathlist) directories, which is a colon-separated string of directory names. The object names are constructed by appending tt(fname) to each of the elements of tt(searchPath) until an existing object is found. This object is then used. If tt(fname) is an absolute path, tt(searchPath) is ignored. itb(off_t size() const) Returns the object's size in number of bytes (tt(st_size)). itb(bool specialMode(size_t special, Combine combine = ALL)) Returns true if the object has the indicated special modes. Multiple special modes may be specified, which can be combined by the logical bf(bitor) operator. By default, if multiple modes are specified, the resulting pattern must exactly represent the object's mode for the member function to return bf(true). An optional argument tt(ANY) may be specified if the function should return true if at least one specified mode matches the object's actual mode. The non-special modes are ignored but a tt(Exception) exception is thrown if tt(special) contains other values than those defined by the bf(SpecialMode) enum. itb(Stat::stat const &statStruct() const) Returns a reference to the object's bf(stat struct). itb(Stat::Type type() const) Returns the tt(Stat::Type) value of the object. itb(std::string typeStr() const) Returns a textual representation of the object's type as returned by the tt(Stat::type()) member function. itb(size_t uid() const) Returns the user ID of the object's owner (tt(st_uid)). ) manpagesection(EXAMPLE) verbinclude(../../stat/driver/driver.cc) manpagefiles() em(bobcat/stat) - defines the class interface manpageseealso() bf(bobcat)(7), bf(glob)(3bobcat), bf(stat)(2), bf(lstat)(2) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/configfile.yo0000644000175000017500000003500114050437223020205 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::ConfigFile)(3bobcat)(_CurYrs_) (libbobcat-dev__CurVers_)(Configuration File Processing) manpagename(FBB::ConfigFile) (A class processing standard unix-like configuration files) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() This class is deprecated: the class bf(FBB::Config) (cf. bf(config)(3bobcat)) should be used instead. bf(ConfigFile) objects read standard tt(unix)-style configuration files. Lines are stored with initial white-space (blanks and tabs) removed. If a line ends in \, then the next line (initial white-space removed) is appended to the current line. If the tt(rmComment) flag is set to tt(true) blanks lines and information on lines from the first tt(#) are removed. If the comment character (tt(#)) is prefixed by a backslash (i.e., tt(\#)) it is not considered comment, but replaced by a single tt(#) character. Likewise, if the tt(rmComment) flag was set two consecutive backslash characters are replaced by a single backslash character, In the retrieved configuration information it appears as a single tt(#) character. If the configuration file should contain tt(\#) write tt(\\#), this results in replacing tt(\#) by tt(#), leaving tt(\#). All non-empty lines of the configuration file (when comment is ignored comment is not considered to be line-content) are stored in the bf(ConfigFile) object. When line indices should be stored the (0-based) line indices of lines are available as well. At construction time comment handling (keep comment / remove comment), case-sensitive searching (sensitive / insensitive) and index storage (store / don't store) can be specified. It can't be modified using the tt(open) member, but overloaded assignment is supported and comment and letter case handling can be modified by set-members. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(ENUMERATIONS) The following enumerations are defined by the class bf(ConfigFile): itemization( itb(Comment) This enumeration has two values: nl() bf(ConfigFile::KeepComment) is used to indicate that comment on lines must be kept; nl() bf(ConfigFile::RemoveComment) is used to indicate that comment on lines must be removed; itb(SearchCasing) This enumeration also has two values:nl() bf(ConfigFile::SearchCaseSensitive) is used to do case sensitive searches for targets;nl() bf(ConfigFile::SearchCaseInsensitive) is used to do case insensitive searches for targets. itb(Indices) This enumeration also has two values:nl() bf(ConfigFile::IgnoreIndices) when used, the line numbers of the original configuration file are not available;nl() bf(ConfigFile::StoreIndices) when used, the line numbers of the original configuration file are also available;nl() ) manpagesection(TYPES) The following types are defined by the class tt(ConfigFile): itemization( itb(const_iterator) a tt(const_iterator) is an iterator pointing to a line (tt(std::string)) of the configuration file; itb(const_RE_iterator) a tt(const_RE_iterator) is an iterator pointing to lines matching a regular expression. It supports the following operations: itemization( itt(const_RE_iterator &operator++()): the prefix increment operator increments the iterator to point to the next line in the configuration file matching the iterator's regular expression; itt(std::string const &operator*()): the dereferencing operator returns the line of the configuration file the iterator refers to; itt(std::string const *operator->()): the pointer operator returns the address of the line of the configuration file the iterator refers to; ) tt(const_RE_iterator)s can be compared for (in)equality and they can be copy-constructed; tt(const_RE_iterator) objects are returned by the tt(ConfigFile::beginEndRE) member and cannot otherwise be constructed. When two tt(const_RE_iterator) objects are subtracted the number of lines matching their regular expression is returned. E.g., (see below for a description of the functions used in the next example): verb( ConfigFile cf(...) auto iters = cf.beginEndRE("^hello"); cout << "There are " << (iters.second - iters.first) << " lines starting with hello\n"; ) The two tt(const_RE_iterator) objects should refer to the same regular expression. The provided example illustrates how this is realized using tt(beginEndRE). tt(FBB::Pattern) is used to perform the regular expression pattern matching. ) manpagesection(CONSTRUCTORS) itemization( itb(ConfigFile(Comment cType = KeepComment, SearchCasing sType = SearchCaseSensitive, Indices iType = IgnoreIndices)) This constructor is used to create an empty bf(ConfigFile) object. It is not associated with an input stream: the tt(open) member can be used for that. The parameters can be used to specify specific handling of comment, letter-casing and storage of line numbers in the original configuration file. itb(ConfigFile(std::string const &fname, Comment cType = KeepComment, SearchCasing sType = SearchCaseSensitive, Indices iType = IgnoreIndices)) This constructor is used to create a bf(ConfigFile) object, which is filled with the information from a file whose name is provided as the constructor's first argument. The other parameters are used as described with the first constructor. It throws an tt(FBB::Exception) exception if the file could not be opened. ) manpagesection(OVERLOADED OPERATORS) itemization( itb(std::string const &operator[](size_t idx) const) This member returns the (0-based) tt(idx)-th line of the configuration file. ) Copy and move constructors (and assignment operators) are available. manpagesection(MEMBER FUNCTIONS) itemization( itb(ConfigFile::const_iterator begin() const) This member returns a tt(const_iterator) to the first line of the configuration file. itb(ConfigFile::const_iterator end() const) This member returns a tt(const_iterator) pointing beyond the last line of the configuration file. itb(std::pair beginEndRE(std::string const &target) const) A pair of tt(const_RE_iterators) is returned. The tt(first) field of the pair is a tt(const) iterator to the first element (i.e., line) of the bf(ConfigFile) object in which the regular expression tt(target) is found. The tt(second) field is a tt(const) iterator marking the end of the series of lines started at the the first line matching the regular expression specified by tt(target). If the tt(RemoveComment) flag was specified, then comment-text is not searched. The iterator returned in the pair's tt(first) field can be incremented until the iteratr returned in the pair's tt(second) field is reached; all iterators (unequal the iterator in tt(second)) point to lines matching the specified regular expression. The iterator's increment operator searches the next line matching the specified regular expression. Although the difference between two tt(const_RE_iterators) can be computed it is a relatively expensive operation. The difference is obtained by performing repeated regular expression matchings rather than the mere algebraic subtraction of pointer values. If the difference cannot be computed tt(std::numeric_limits::max()) is returned. This member also interprets the tt(SearchCasing) flag. itb(std::pair beginEndRE() const) A pair of tt(const_RE_iterators) is returned, both marking the end of a regular expression search. itb(ConfigFile::const_iterator find(std::string const &target) const) This member returns an iterator to the first element (i.e., line) of the tt(FBB::ConfigFile) object in which tt(target) is found. Note that tt(target) may appear anywhere within a line. If the tt(RemoveComment) flag was specified, then comment-text is not searched. Use the tt(end) member to determine the end-iterator. It is not guaranteed that all lines between the returned iterator and tt(end) contain tt(target). This member also interprets the tt(SearchCasing) flag. itb(std::string findKey(std::string const &keyPattern, size_t count = 1) const) This member can be used to retrieve information from lines having the general pattern `tt(keyPattern value)'. Initial and trailing white space on lines are ignored. tt(keyPattern) itself should not contain initial or trailing white space. At least one white space character must appear between tt(keyPattern) and tt(value). If at least tt(count) lines were found matching tt(keyPattern value) then this member returns the first sequence of non white space characters following tt(keyPattern) after matching tt(count) lines matching tt(keyPattern value) (i.e., `tt(value)' is returned). If tt(value) is empty or if fewer than tt(count) lines match tt(keyPattern) an empty string is returned. An tt(FBB::Exception) exception is thrown if tt(count) equals 0. itb(std::string findKeyTail(std::string const &keyPattern, size_t count = 1) const) This member can be used to retrieve information from lines having the general pattern `tt(keyPattern value)', merely followed by white space. Initial and trailing white space on lines are ignored. tt(keyPattern) itself should not contain initial or trailing white space. At least one white space character must appear between tt(keyPattern) and tt(value). If at least tt(count) lines were found matching tt(keyPattern value) then this member returns the information beyond tt(keyPattern) after matching tt(count) lines matching tt(keyPattern) (i.e., `tt(value)' is returned). This function differs from tt(findKey) in that all information trailing tt(keyPattern) is returned in tt(value). If tt(value) is empty or if fewer than tt(count) lines match tt(keyPattern) an empty string is returned. An tt(FBB::Exception) exception is thrown if tt(count) equals 0. itb(ConfigFile::const_iterator findRE(std::string const &target) const) This member returns an iterator to the first line of the bf(ConfigFile) object matching the regular expression tt(target). After calling this function tt(beginEndRE) returns an iterator pair whose tt(first) field is an iterator to the same line and whose tt(second) field is the end-iterator for lines matching tt(target). If the tt(RemoveComment) flag was specified, then comment-text is not searched. The inherited tt(end) member can be used to determine the end-iterator. It is not guaranteed that all lines between the returned iterator and tt(end) also contain tt(target). itb(size_t index(size_t idx)) This function should only be used when the parameter tt(StoreIndices) was specified at construction time. In that case it returns the original 0-based line index in the configuration file associated with the tt(idx)sups(th) (0-based) index in the current tt(Configuration) object. itb(size_t index(const_iterator const &iter)) This function should only be used when the parameter tt(StoreIndices) was specified at construction time. In that case it returns the original 0-based line index in the configuration file associated with the configuration line in the current tt(Configuration) object pointed to by tt(iter). This may also be an (incremented version of the) iterator returned by the member tt(findRE). itb(void open(std::string const &fname)) This member reads the configuration file having name tt(fname). It redefines the current content of the bf(ConfigFile) object, destroying any information previously stored in it. The configuration file is read according to the latest setting of the comment-flag. It throws an tt(FBB::Exception) exception if the file cannot be opened. This member clears previously available information and reinitializes the object with information read from the new file. itb(void setCommentHandling(Comment type)) This member can be used to change the comment-handling type originally set by the constructor, or set by earlier calls of this function. When called it won't affect the current content of the bf(ConfigFile) object, but new calls of its tt(open) member reads the configuration file according to the last setting of the comment flag. itb(void setSearchCasing(SearchCasing type)) This member can be used to change the handling of the letter-casing originally set by the constructor, or set by earlier calls of this function. When called it won't affect the current content of the bf(ConfigFile) object, but new calls of its tt(open) member reads the configuration file according to the last setting of the letter-casing flag. itb(size_t size() const) This member returns the number of lines in the configuration file. ) manpagesection(EXAMPLE) Assume the configuration file is called tt(config.rc) and contains the following lines: COMMENT(Keep the blank following the backslashes below:) verb( # this is ignored noline: this one too line: this is found this is not a line containing line: at the beginning \ of the line line: this one is line: what about this one? \ it's extending over multiple lines and there may, of course, be more lines in this file ) The following program may be compiled and run as tt(a.out config.rc): verb( #include #include #include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) { ConfigFile cf(argv[1]); cout << *cf.find("this one") << '\n'; // find text within a line // find all lines matching auto [begin, end] = cv.beginEndRE("^line:"); // `^line:' copy(begin, end, ostream_iterator(cout, "\n")); } ) Producing the output: verb( noline: this one too line: this is found line: this one is line: what about this one? it's extending over multiple lines ) manpagefiles() em(bobcat/configfile) - defines the class interface manpageseealso() bf(argconfig)(3bobcat), bf(bobcat)(7), bf(config)(3bobcat) bf(exception)(3bobcat), bf(pattern)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/fork.yo0000644000175000017500000001600714050437223017046 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Fork)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Template Design Pattern around fork(2)) manpagename(FBB::Fork) (Implements bf(fork)(2) using the Template Design Pattern) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() bf(FBB::Fork) objects may be used to implement the bf(fork)(2) call as part of the Template Algorithm Design Pattern. The class was designed as a virtual base class for classes implementing the essential parts of the forking process. The class is a virtual base class. Derived classes em(must) implement the members tt(childProcess) and tt(parentProcess) as part of the `Template Method Design Pattern' (see Gamma em(et al.), 1995). Terminating child processes send tt(SIGCHLD) signals to their parents. The bf(C) library offers the following em(macros) to analyze the em(status) values received by the parent process using a bf(wait)(2) or bf(waitpid)(2) system call: itemization( itb(int WIFEXITED(int status)) This macro returns a nonzero value if the child process terminated normally with `exit' or `_exit'. itb(int WEXITSTATUS(int status)) If `WIFEXITED' is true of `tt(status)', this macro returns the low-order 8 bits of the exit status value from the child process. itb(int WIFSIGNALED(int status)) This macro returns a nonzero value if the child process terminated because it received a signal that was not handled. itb(int WTERMSIG(int status)) If `WIFSIGNALED' is true of `tt(status)', this macro returns the signal number of the signal that terminated the child process. itb(int WCOREDUMP(int status)) This macro returns a nonzero value if the child process terminated and produced a core dump. itb(int WIFSTOPPED(int status)) This macro returns a nonzero value if the child process is stopped. itb(int WSTOPSIG(int status)) If `WIFSTOPPED' is true of `tt(status)', this macro returns the signal number of the signal that caused the child process to stop. ) includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(CONSTRUCTORS) Only the default constructor is available. ) manpagesection(DESTRUCTOR) itemization( itb(virtual ~Fork()) Derived classes may define their own destructor, which is called when the tt(Fork) destructor is activated. ) manpagesection(MEMBER FUNCTIONS) itemization( itb(void fork()) Performs the actual forking. It is implemented in such a way that the corresponding parent- and child- processes are activated from virtual members of bf(Fork). If the forking operation fails, an tt(FBB::Exception) exception is thrown. ) manpagesection(PROTECTED MEMBER FUNCTIONS) itemization( itb(virtual void childProcess() = 0) This member em(must) be implemented by derived classes. It defines the actions that are performed by the child process, following the bf(fork)(2) system call. Just before tt(childProcess) is called, tt(childRedirections) (see below) has been executed. The tt(childProcess()) function should terminate the child process. A good way to do this is to throw an exception which is caught by tt(main())'s function try block. Terminating a process using bf(exit)(2) is deprecated in bf(C++). itb(virtual void childRedirections()) This function em(may) be redefined in derived classes to set up the redirections that are necessary to communicate with the parent process. See also the classes bf(redirector)(3bobcat) and bf(pipe)(3bobcat). By default, tt(childRedirections) does nothing. itb(virtual void parentProcess() = 0) This member em(must) be implemented by derived classes. It defines the actions that are performed by the parent process, following the bf(fork)(2) system call. Just before tt(parentProcess) is called, tt(parentRedirections) (see below) has been executed. itb(virtual void parentRedirections()) This function em(may) be redefined in derived classes to set up the redirections that are necessary to communicate with, e.g., the parent. See, e.g., the classes bf(redirector)(3bobcat) and bf(pipe)(3bobcat). By default, tt(parentRedirections) does nothing. itb(pid_t pid() const) Returns the child's process id in the parent's code (i.e., in the bf(parent-)members below), and 0 in the child's code (i.e., in the bf(child-)members below). Note that the value of tt(pid) is bf(undefined) when called em(before) the member tt(fork) has been called. itb(void prepareDaemon() const) Prepares for a daemon childprocess. This function may (should) be called from tt(childProcess) to ensure that the child process changes its current working directory to the root (/) directory, thus freeing up mount points; that the child process starts a new session/process group to allow the parent (group leader) to kill all its processes without terminating the daemon; and makes sure that the child process closes and reopens the standard streams by associating them with tt(/dev/null) to prevent ghost input and output actions from interfering with the daemon's actions. An tt(FBB::Exception) is thrown if changing directory to the root directory fails. itb(void prepareDaemon(std::string const &out, std::string const &err, mode_t mode = 0600) const) Prepares for a daemon childprocess like the previous member function, but allows redirection of the standard output (tt(out)) and standard error (tt(err)) streams to files. Specify empty strings to redirect these streams to tt(/dev/null). With non-empty strings the specified files are opened in append-mode (and created if not yet existing), by default using mode 0600 (read/write mode for the user only). An tt(FBB::Exception) is thrown if changing directory to the root directory or if using the specified file(s) fails. itb(int waitForChild()) This member may be called by tt(parentProcess) to wait for the completion of the child-process. The return value (exit-code) of the child process is returned as a value between 0 and 255. If the child process terminates before the completion of the parent process, then tt(waitForChild) should be called to prevent em(zombies) from occurring. Alternatively, the parent process may terminate (e.g., using bf(exit)(2)) while the child process is still alive. This is the normal way to create a em(daemon) process. ) manpagesection(EXAMPLES) verbinclude(../../fork/driver/driver.cc) Here's a more extensive example: verbinclude(../../fork/driver/redirectedchild) manpagefiles() em(bobcat/fork) - defines the class interface manpageseealso() bf(bobcat)(7), bf(cerrextractor)(3bobcat), bf(cininserter)(3bobcat), bf(coutextractor)(3bobcat), bf(exec)(3bobcat), bf(fork)(2), bf(pipe)(3bobcat), bf(redirector)(3bobcat), bf(stdextractor)(3bobcat), bf(wait)(2), bf(waitpid)(2). manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/typetrait.yo0000644000175000017500000000623314050437223020132 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::TypeTrait)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Error handler) manpagename(FBB::TypeTrait)(shortdesc) manpagesynopsis() bf(#include )nl() manpagedescription() bf(FBB::TypeTrait) is a traits class. It does not define any member functions or data members, but merely types. It can be used to determine the basic type and other characteristics of (const) plain, (const) pointer or (const) reference types. It was designed after Alexandrescu's (2001) tt(TypeTraits) template class. The bf(FBB::LpromotesR) class template is used to determine, compile-time, whether its second (right-hand side) template type can be promoted to its first (left-hand side) template type. The bf(FBB::Use) class template expects two typenames tt(LHS) and tt(RHS) and defines tt(typename Use::type) as tt(LHS) if tt(RHS) can be promoted to tt(LHS) or it defines tt(typename Use::type) as tt(RHS). includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(TypeTrait) bf(TYPE) is the template type parameter whose characteristics must be determined. tt(TypeTrait) defines the type tt(Plain): the plain type (the type without const, pointer, reference type indication) of any const or non-const plain, pointer, lvalue- or rvalue-reference type. tt(TypeTrait) defines the following tt(bool) values: itemization( itt(isClass): tt(true) if the template type argument represents a class (struct) type, tt(false) otherwise. itt(isConst): tt(true) if the template type argument represents a const type, tt(false) otherwise. itt(isPointer): tt(true) if the template type argument represents a pointer type, tt(false) otherwise. itt(isR_Ref): tt(true) if the template type argument represents a rvalue reference type, tt(false) otherwise. itt(isRef): tt(true) if the template type argument represents an lvalue reference type, tt(false) otherwise. ) manpagesection(LpromotesR) tt(LpromotesR) defines the enum constant tt(yes) as 1 if an tt(RightType) argument can be promoted to tt(LeftType) value or object. The enum value tt(yes) is defined as 0 if no such constructor is available or if such a constructor is defined using the tt(explicit) keyword. manpagesection(EXAMPLES) Here is an example using tt(LpromotesR): verb( int main() { cout << "string promotes char const *: " << LpromotesR::yes << '\n'; // 1 cout << "string promotes string " << LpromotesR::yes << '\n'; // 1 cout << "char const * promotes string " << LpromotesR::yes << '\n'; // 0 } ) manpagefiles() em(bobcat/typetrait) - defines the class interface manpageseealso() bf(bobcat)(7)nl() Alexandrescu A. (2001) bf(Modern C++ Design), Addison-Wesley, Boston. manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/selector.yo0000644000175000017500000001332414050437223017724 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Selector)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Timed Delays, Multiple File I/O) manpagename(FBB::Selector)(Timed delays, Alarms and Multiple File I/O.) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() bf(FBB::Selector) objects are wrappers around the bf(select)(2) system calls and allow timed delays, alarm functionality and/or multiple file I/O. It requires the use of em(file descriptors), which are not an official part of bf(C++). However, most operating systems offer em(file descriptors). Sockets are well-known file descriptors. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(CONSTRUCTORS) itemization( itb(Selector()) This constructor initializes the object. ) Copy and move constructors (and assignment operators) are available. manpagesection(MEMBER FUNCTIONS) itemization( itb(void addExceptFd(int fd)) Adds a filedescriptor to the set of file descriptors that are monitored for exceptions (note these are not bf(C++) exceptions. See tt(man 2 select) for details). itb(void addReadFd(int fd)) Adds a filedescriptor to the set of file descriptors that are monitored for reading. itb(void addWriteFd(int fd)) Adds a filedescriptor to the set of file descriptors that are monitored for writing. itb(int exceptFd()) Returns -1 of no more file descriptors are available in the em(exception) category. Otherwise the next available file descriptor in the em(exception) category is returned. Returning from tt(wait), this function can be called repeatedly until -1 is returned, servicing each available filedescriptor in turn. itb(void noAlarm()) This member prevents any timeout-alarm from occurring. itb(int nReady()) Returns the number of available file descriptors. 0 is returned at a timeout, -1: is returned when tt(select)(2) itself failed. itb(int readFd()) Returns -1 of no more file descriptors are available for reading. Otherwise the next available file descriptor for reading is returned. Returning from tt(wait), this function can be called repeatedly until -1 is returned, servicing each available filedescriptor in turn. Note that the file whose file descriptor is returned by tt(readFd) may also be at its end-of-file position. The file is `ready for reading', but no characters will be returned when trying to read from it due to its end-of-file status. In that case the file descriptor is probably best removed from the set of active file descriptors. itb(void rmExceptFd(int fd)) Removes a filedescriptor from the set of file descriptors that are monitored for exceptions (note these are not bf(C++) exceptions. See tt(man 2 select) for details). itb(void rmReadFd(int fd)) Removes a filedescriptor from the set of file descriptors that are monitored for reading. itb(void rmWriteFd(int fd)) Removes a filedescriptor from the set of file descriptors that are monitored for writing. itb(void setAlarm(int sec, int usec = 0)) This member sets the alarm at the indicated seconds and micro-seconds. If no action occurred on one of the monitored file descriptions following the indicated amount of time, tt(wait) will return with tt(nReady) returning 0. The requested alarm time (tt(sec + usec / 1e+6)) may not be negative and may not exceed tt(std::numeric_limits::max()) or an tt(FBB::Exception) exception will be thrown. A 0 alarm time specification results in tt(wait) returning immediately. To switch off the alarm time use tt(noAlarm). itb(int wait()) This member should be called to wait for activities on the installed file descriptors or timeout-period. The members tt(exceptFd, nReady, readFd) and tt(writeFd) show their defined behaviors only after tt(wait) has returned. It throws an tt(FBB::Exception) exception when bf(select)(2) fails, which may very well indicate the end of any available input. An exception is also thrown if the program received a signal. If tt(wait) returns normally its return value represents the number of available file descriptors. Note that tt(wait) may also return with an input file descriptor returned by tt(readFd) of a file at its end-of-file position. The file is `ready for reading', but no characters will be returned when trying to read from it due to its end-of-file status. itb(int writeFd()) Returns -1 of no more file descriptors are available for writing. Otherwise the next available file descriptor for writing is returned. Returning from tt(wait), this function can be called repeatedly until -1 is returned, servicing each available filedescriptor in turn. ) manpagesection(EXAMPLE) verb( #include #include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv, char **envp) try { Selector selector; selector.setAlarm(5); // every 5 secs: alarm fires selector.addReadFd(STDIN_FILENO); // look also at cin while (true) { if (!selector.wait()) // 0: alarm fires cout << "Are you still there?" << endl; else { string s; if (!getline(cin, s) || !s.length()) return 0; cout << "Thank you for: " << s << endl; } } } catch (Exception const &e) { cout << e.what() << '\n'; return 1; } ) manpagefiles() em(bobcat/selector) - defines the class interface manpageseealso() bf(bobcat)(7), bf(select)(2) manpagebugs() None reported includefile(include/trailer) bobcat-5.09.01/documentation/man/binops.yo0000644000175000017500000001331514050437223017376 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(binops)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Binary Operators) manpagename(binops)(Template functions for class-type binary operators) manpagesynopsis() bf(#include )nl() bf(#include )nl() bf(#include )nl() manpagedescription() Classes can overload binary operators. A class named tt(Class) may overload these binary operators to suit its own needs, allowing, e.g., two tt(Class) type objects to be added after overloading tt(operator+). Operators for the binary operators *, /, %, +, -, <<, >>, &, |, and ^ (in this man-page they are generically indicated as the `tt(@)' operator) can be overloaded by defining the tt(operator@) function. If a class supports copy construction and if it offers binary assignment operators (i.e., it offers members of the form tt(operator@=)), then the matching binary operators can all be implemented identically. The em(move-aware) tt(Class &operator@(Class &&lhs, Class const &rhs)) is easily implemented in terms of tt(operator@=) (note that the class itself doesn't have to be `move-aware' to define this function). The move-aware binary operator one requires a one line implementation, and as its implementation never changes it could safely be defined tt(inline): verb( Class operator@(Class &&lhs, Class const &rhs) { return std::move(std::move(lhs) @= rhs); } ) The traditional binary operator can be implemented using its standard form: verb( Class operator@(Class const &lhs, Class const &rhs) { Class tmp(lhs); tmp @= rhs; return tmp; } ) The implementation in tt(bobcat/binops) is slightly more complex as it allows from lhs or rhs promotions. As the binary operators can all be implemented alike their definitions are perfectly suited for templates: A class offering a particular tt(operator@=) then automatically also offers the matching binary operators after including tt(bobcat/binops). Since the binary function templates are not instantiated until used their definitions can be processed by the compiler even if a class implements only a subset of the available binary assignment operators. manpagesection(NAMESPACE) The binary operator functions templates in tt(bobcat/binops) are em(not) implemented in a particular namespace. This allows sources to include tt(bobcat/binops) in multiple namespaces. If tt(bobcat/binops) is to be used in multiple namespaces then the include safeguard (using the identifier tt(INCLUDED_BOBCAT_BINOPS_)) must be suppressed between inclusions of tt(bobcat/binops) in different namespaces. E.g., to make the binary operator function templates available in a source file using the tt(namespace FBB) and in a source file using the default namespace the following scheme can be used: verb( #include // ensure std::move is available #include // required by binops namespace MY_NAMESPACE { #include // binary operators available in MY_NAMESPACE } #undef INCLUDED_BOBCAT_BINOPS_ // suppress the include guard #include // read binops again so the binary // operators can be used in the // default namespace as well ) manpagesection(INHERITS FROM) - manpagesection(OVERLOADED OPERATORS) The function templates in tt(bobcat/binops) implement all arithmetic binary operators, both move-aware and the traditional binary operators, expecting constant lvalue references. They can be used if the matching binary assignment operators were implemented in the classes for which the templates must be instantiated. The following operators are available: Move-aware operators, using temporary objects for its left-hand side operands: itemization( itb(Class operator*(Class &&lhs, Class const &rhs)) itb(Class operator/(Class &&lhs, Class const &rhs)) itb(Class operator%(Class &&lhs, Class const &rhs)) itb(Class operator+(Class &&lhs, Class const &rhs)) itb(Class operator-(Class &&lhs, Class const &rhs)) itb(Class operator<<(Class &&lhs, Class const &rhs)) itb(Class operator>>(Class &&lhs, Class const &rhs)) itb(Class operator&(Class &&lhs, Class const &rhs)) itb(Class operator|(Class &&lhs, Class const &rhs)) itb(Class operator^(Class &&lhs, Class const &rhs)) ) `Traditional' operators, using lvalue references to constant objects for its left-hand side operands: itemization( itb(Class operator*(Class const &lhs, Class const &rhs)) itb(Class operator/(Class const &lhs, Class const &rhs)) itb(Class operator%(Class const &lhs, Class const &rhs)) itb(Class operator+(Class const &lhs, Class const &rhs)) itb(Class operator-(Class const &lhs, Class const &rhs)) itb(Class operator<<(Class const &lhs, Class const &rhs)) itb(Class operator>>(Class const &lhs, Class const &rhs)) itb(Class operator&(Class const &lhs, Class const &rhs)) itb(Class operator|(Class const &lhs, Class const &rhs)) itb(Class operator^(Class const &lhs, Class const &rhs)) ) The latter group of operators also support promotions. manpagesection(EXAMPLE) verbinclude(../../binops/driver/driver.cc) manpagefiles() em(bobcat/binops) - defines the binary operator function templates manpageseealso() bf(bobcat/binopsbase)(3) bf(bobcat)(7) manpagebugs() itemization( it() The header files tt(utility), defining tt(std::move), and tt(bobcat/typetrait) are required by, but are not included by tt(bobcat/binops). This was a design decision, see the bf(NAMESPACE) section. ) includefile(include/trailer) bobcat-5.09.01/documentation/man/ibase64buf.yo0000644000175000017500000000670614050437223020044 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::IBase64Buf)(3bobcat)(_CurYrs_) (libbobcat-dev__CurVers_) (Base64 converting Stream Buffer) manpagename(FBB::IBase64Buf) (Input Filtering stream buffer doing base64 conversion) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() The information made available by bf(IBase64Buf) objects has been subject to base64 encoding or decoding. The information to be converted is made available to bf(IBase64Buf) object via tt(std::istream) objects. The tt(class IBase64Buf) is a class template, using a tt(FBB::CryptType) template non-type parameter. Objects of the class tt(FBB::IBase64Buf) base64 encode the information they receive, objects of the class tt(FBB::IBase64Buf) base64 decode the information they receive. See also section bf(ENUMERATION) below. includefile(include/namespace) manpagesection(INHERITS FROM) bf(FBB::IFilterBuf) manpagesection(ENUMERATION) bf(IBase64Buf) objects either base64 encode or decode information. bf(IBase64Buf) objects of the class bf(FBB::IBase64Buf) base64 encode the data they receive, bf(IBase64Buf) objects of the class bf(FBB::IBase64Buf) base64 decode the data they receive. The values tt(ENCRYPT) and tt(DECRYPT) are defined in the tt(enum CryptType), which is defined in the tt(FBB) namespace. manpagesection(CONSTRUCTOR) itemization( itb(IBase64Buf(std::istream &in, size_t bufSize = 1000)) This constructor initializes the streambuf. - tt(IBase64Buf) objects perform base64 encoding;nl() - tt(IBase64Buf) objects perform base64 decoding;nl() - tt(IBase64Buf) objects obtain the bytes to encode or decode from tt(std::istream &in);nl() - The tt(IFilterBuf) base class is initialized with a buffer of size tt(bufSize), using a lower bound of 100. The constructor uses a configurable buffer size for reading. Characters that were read into the buffer but are not part of the actual base64 encoded data are unavailable after completing the base64 decrypting. If information beyond the base64 input block should remain available, then specify a buffer size of 1. ) Copy and move constructors (and assignment operators) are not available. manpagesection(MEMBER FUNCTIONS) All members of bf(FBB::IFilterBuf) are available, as bf(IBase64Buf) inherits from this class. manpagesection(EXAMPLE) The example shows the construction of tt(IBase64Buf) objects tt(encode) which are used to initialize a tt(std::istream) object. The information read from this tt(istream) is base64 encoded. tt(IBase64Buf) objects (tt(decode) reads base64 encoded information from tt(std::istream) objects and decodes it again). The tt(std::istream din) object is initialized with the tt(IBase64Buf) object, and its content is sent to tt(std::cout). The information that is presented at tt(std::cin) and that appears at tt(std::cout) should be identical. verbinclude(../../ibase64buf/driver/driver.cc) manpagefiles() em(bobcat/ibase64buf) - defines the class interface manpageseealso() bf(bobcat)(7), bf(isymcryptstreambuf)(3bobcat), bf(ibase64stream)(3bobcat), bf(ifilterbuf)(3bobcat), bf(ofilterbuf)(3bobcat), bf(std::streambuf). manpagebugs() None reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/iterator.yo0000644000175000017500000001247114050437223017737 0ustar frankfrankNOUSERMACRO(Iterator ReverseIterator last max min) includefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Iterator)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Iterator returning plain values) manpagename(FBB::Iterator)(Iterator returning plain values when dereferenced) FBB::ReverseIterator - reverse_iterator for bf(FBB::Iterator) manpagesynopsis() bf(#include )nl() manpagedescription() The bf(FBB::Iterator) class template implements a bidirectional iterator for plain data types. Dereferencing bf(FBB::Iterator) objects returns values of type bf(Type), e.g., tt(char) or tt(int). This iterator comes in handy in case you need to initialize an objects with a range of values, which are of some basic type (see also the bf(EXAMPLE) section). bf(FBB::ReverseIterator) implements a reverse iterator for bf(FBB::Iterator). includefile(include/namespace) manpagesection(INHERITS FROM) tt(std::iterator) manpagesection(CONSTRUCTORS) Constructors for bf(Iterator): itemization( itb(explicit Iterator(Tye const &value)) This constructor initializes the bf(Iterator) object with an initial tt(Type) value. When dereferencing this iterator, tt(value) is returned. ) The bf(Iterator)'s default, copy, and move constructors (and its copy and move assignment operators) are available. Constructors for bf(ReverseIterator): itemization( itb(explicit ReverseIterator(Type const &value)) This constructor initializes the bf(ReverseIterator) object with an initial tt(Type) value. When dereferencing this iterator immediately following its construction, the decremented tt(value) is returned (without modifying the internally stored tt(Type value)); itb(explicit ReverseIterator(Iterator const &iter)) This constructor initializes the bf(ReverseIterator) object with an initial tt(Iterator) object. When dereferencing this iterator immediately following its construction, the decremented bf(Iterator)'s tt(value) is returned (without modifying the tt(Type value) that is stored inside the bf(Iterator)). ) The bf(ReverseIterator)'s default, copy, and move constructors (and its copy and move assignment operators) are available. manpagesection(MEMBER FUNCTIONS) For template parameter type tt(Type) all members of tt(std::iterator) are available, as bf(FBB::Iterator) and bf(FBB::ReverseIterator) inherit from this class. itemization( itb(Iterator &operator++()) The (prefix) increment operator increments the iterator's value and returns a reference to itself; itb(Iterator &operator++(int)) The (postfix) increment operator increments the iterator's value and returns a copy of itself, initialized with the iterator's value before it was incremented; itb(Iterator &operator--()) The (prefix) decrement operator decrements the iterator's value and returns a reference to itself; itb(Iterator &operator--(int)) The (postfix) decrement operator decrements the iterator's value and returns a copy of itself, initialized with the iterator's value before it was decremented; itb(bool operator==(Iterator const &rhs) const) This operator returns tt(true) if the value of the current bf(Iterator) object is equal to the value of the tt(rhs) bf(Iterator) object; itb(bool operator!=(Iterator const &rhs) const) This operator returns tt(true) if the value of the current bf(Iterator) object is not equal to the value of the tt(rhs) bf(Iterator) object; itb(Type &operator*()) The derefence operator returns a reference to the bf(Iterator)'s value. itb(Type const &operator*() const) This derefence operator returns a reference to the bf(Iterator)'s immutable value. ) manpagesection(STATIC MEMBER FUNCTIONS) Static members of bf(Iterator): itemization( itb(Iterator last(Type value)) An bf(Iterator) object is returned initialized with tt(++value), so it can be conveniently be used to create an inclusive iterator range (see also section bf(EXAMPLE)); itb(Iterator max()) An bf(Iterator) object is returned initialized with the value returned by tt(std::numeric_limits::max()); itb(Iterator min()) An bf(Iterator) object is returned initialized with the value returned by tt(std::numeric_limits::min()) ) Static member of bf(ReverseIterator): itemization( itb(ReverseIterator last(Type const &value)) A bf(ReverseIterator) object is returned initialized with bf(Iterator::last(value)), so it can be conveniently be used to create an inclusive reverse iterator range (see also section bf(EXAMPLE)); ) manpagesection(EXAMPLE) verbinclude(../../iterator/driver/driver.cc) manpagefiles() em(bobcat/iterator) - defines the class interface manpageseealso() bf(bobcat)(7) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/bigint.yo0000644000175000017500000010001614050437223017353 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::BigInt)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Big Integers) manpagename(FBB::BigInt)(Arithmetic on Integers of Unlimited Size) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat -lcrypto) manpagedescription() This class is defined as a wrapper class around the em(openSSL) tt(BN) series of functions, offering members to perform arithmetic on integral values of unlimited sizes. Members are offered to generate primes and to perform all kinds of common arithmetic operations on tt(BigInt) objects. Also, conversions to characters and standard numerical value types are offered. Below, the phrase em(the object) may also refer to the object's value. The context in which this occurs will make clear that the object's value rather than the object as-is is referred to. Various constructors accept tt(BIGNUM) arguments. Type tt(BIGNUM) is the type containing an integer of unlimited precision as defined by OpenSSL. tt(BIGNUM's) definition is verb( typedef struct bignum_st BIGNUM; struct bignum_st { BN_ULONG *d; // Pointer to an array of 'BN_BITS2' bit chunks. int top; // Index of last used d +1. // The next are internal book keeping for bn_expand. int dmax; // Size of the d array. int neg; // one if the number is negative int flags; }; ) Signs of tt(BigInt) are handled in a special way. Whether a tt(BigInt) is negative or positive is determined by its sign-flag, and not by a sign bit as is the case with tt(int) typed values. Since tt(BigInt) values have unlimited precision shifting values to the left won't change their signs. Operators return either a reference to the current (modified) object or return a tt(BigInt) object containing the computed value. The rule followed here was to implement the operators analogously to the way the operators work on tt(int) type values and variables. E.g., tt(operator+()) returns a tt(BigInt) value whereas tt(operator+=()) returns a tt(BigInt &) reference. All members modifying their objects return a reference to the current (modified) object. All members not modifying the current object return a tt(BigInt) object. If both members exists performing the same functionality the name of the member returning a tt(BigInt) object ends in a tt(c) (const) (e.g., tt(addMod) and tt(addModc)). Almost all operators, members and constructors (except for the default constructor) throw tt(Exception) exceptions on failure. manpagesection(INHERITS FROM) - manpagesection(TYPE) The class bf(BigInt) defines the type tt(Word), which is equal to the type tt(BN_ULONG) used by tt(OpenSSL) to store integral values of unlimited precision. A tt(Word) is an tt(unsigned long), which is, depending on the architecture, usually 64 or 32 bits long. manpagesection(ENUMERATIONS) bf(Msb)nl() This (most significant bit) enumeration is used when generating a cryptographically strong random number. Its values are: itemization( itb(MSB_UNKNOWN) The most significant bit may be 0 or 1. itb(MSB_IS_ONE) The most significant bit is guaranteed to be 1. itb(TOP_TWO_BITS_ONE) The two most significant bits are guaranteed to be 1, resulting in a product of two values each containing tt(nBits) having tt(2 * nBits) bits. ) bf(Lsb)nl() This (least significant bit) enumeration is used when generating random numbers, ensuring that the resulting value is either odd or even. itemization( itb(EVEN) The random value will be an even value; itb(ODD) The random value will be an odd value. ) manpagesection(CONSTRUCTORS) itemization( itb(BigInt()) The default constructor initializes a tt(BigInt) value to 0. itb(explicit BigInt(BIGNUM const &value)) This constructor initializes a tt(BigInt) from a tt(const BIGNUM). itb(explicit BigInt(BIGNUM const *value)) This constructor initializes a tt(BigInt) from a pointer to a tt(const BIGNUM). itb(explicit BigInt(BIGNUM *value)) This constructor initializes a tt(BigInt) from a pointer to a tt(BIGNUM) (the tt(BIGNUM) value pointed to by tt(value) is em(not) mondified by the constructor. This constructor is a mere wrapper around the previous constructor). itb(BigInt(Type value)) This constructor is defined as a member template. Any type that can be converted using a static cast to an tt(unsigned long) can be used as argument to this constructor. Promotion is allowed, so in many situations where tt(BigInt)s are expected a plain numerical value can be used as well. itb(BigInt(char const *bigEndian, size_t length, bool negative = false)) This constructor initializes a tt(BigInt) from tt(length) big-endian encoded bytes stored in tt(bigEndian). This constructor interprets the tt(char) values pointed at by tt(bigEndian) as unsigned values. Use this constructor to reconstruct a tt(BigInt) object from the data made available by the tt(bigEndian) member. If the number represents a negative value, then provide a third argument tt(true). itb(explicit BigInt(std::string const &bigEndian, bool negative = false)) This constructor initializes a tt(BigInt) from the bytes stored in tt(bigEndian), which must be big-endian encoded. This constructor interprets the tt(char) values stored in tt(bigEndian) as unsigned values. If the number that is stored in tt(bigEndian) represents a negative value, then provide a second argument tt(true). ) Copy and move constructors (and assignment operators) are available. manpagesection(MEMBER FUNCTIONS) itemization( itb(BigInt &addMod(BigInt const &rhs, BigInt const &mod) ) tt(Rhs) is added (modulo tt(mod)) to the current object. itb(BigInt addModc(BigInt const &rhs, BigInt const &mod) ) The sum (modulo tt(mod)) of the current object and tt(rhs) is returned. itb(BigInt::Word at(size_t index) const) Returns the tt(Word) at tt(index). E.g., on a 32 bit architecture, if the bf(BigInt) value equals 2+sups(33), then tt(at(0)) returns 0, and tt(at(1)) returns 2. If tt(index) equals or exceeds the value returned by tt(nWords) an tt(FBB::Exception) is thrown. itb(BIGNUM const &bignum() const) A reference to the tt(BIGNUM) value maintained by the current tt(BigInt) object is returned. itb(char *bigEndian() const) The value represented by the current object is stored in a series of tt(char) typed values in big-endian order. If a value consists of 5 tt(char)s the eight most significant bits will be stored in the tt(char) having index value 0, the eight least significant bits will be stored in the tt(char) having index value 4. When needed simply swap tt(char[i]) with tt(char[j]) (i = 0 .. nBytes/2, j = nBytes-1 .. nBytes/2) to convert to little-endian order. The return value consists of a series of tt(sizeInBytes()) (see below) dynamically allocated tt(char) values. The caller of tt(bigEndian) owns the allocated memory and should eventually delete it again using tt(delete[]). Note that the current object's em(sign) cannot be inferred from the return value. itb(BigInt &clearBit(size_t index)) The current object's bit at index position tt(index) is cleared. itb(BigInt clearBit(size_t index) const) A copy of the current object having its bit at index position tt(index) cleared. itb(BigInt &div(BigInt *remainder, BigInt const &rhs)) The current object is divided by tt(rhs). The division's remainder is returned in tt(*remainder). itb(BigInt divc(BigInt *remainder, BigInt const &rhs) const) The quotient of the current object and tt(rhs) is returned. The division's remainder is returned in tt(*remainder). itb(int compare(BigInt const &rsh) const) Using signed values, if the current object is smaller than tt(rhs) -1 is returned; if they are equal 0 is returned; if the current object is larger than tt(ths) 1 is returned (see also tt(uCompare)). itb(BigInt &exp(BigInt const &exponent)) The current object is raised to the power tt(exponent). itb(BigInt expc(BigInt const &exponent) const) The current object raised to the power tt(exponent) is returned. itb(BigInt &expMod(BigInt const &exponent, BigInt const &mod)) The current object is raised to the power tt(exponent) modulo tt(mod). itb(BigInt expModc(BigInt const &exponent, BigInt const &mod) const) The current object raised to the power tt(exponent) modulo tt(mod) is returned. itb(BigInt &gcd(BigInt const &rhs)) The greatest common divisor (gcd) of the current object and tt(rhs) is assigned to the current object. To compute the least common multiple (lcm) the following relationship can be used: verb( lcm(a, b) = a * b / a.gcd(b) ) itb(BigInt gcdc(BigInt const &rhs) const) The greatest common divisor (gcd) of the current object and tt(rhs) is returned. To compute the least common multiple (lcm) the following relationship can be used: verb( lcm(a, b) = a * b / a.gcd(b) ) itb(bool hasBit(size_t index)) tt(True) is returned if the bit at index position tt(index) has been set, tt(false) otherwise. itb(BigInt &inverseMod(BigInt const &mod)) The inverse of the current object modulo tt(mod) is assigned to the current object. This is the value tt(ret) for which the following expression holds true: verb( (*this * ret) % mod = 1 ) itb(BigInt inverseModc(BigInt const &mod) const) This inverse of the current object modulo tt(mod) is returned. itb(bool isNegative() const) Returns tt(true) if the current object contains a negative value. itb(bool isOdd() const) Returns tt(true) if the current object is an odd value. itb(bool isOne() const) Returns tt(true) if the current object equals one (1). itb(BigInt &isqrt()) The current object's integer square root value is assigned to the current object. The integer square root of a value tt(x) is the biggest integral value whose square does not exceed tt(x). E.g., tt(isqrt(17) == 4). An tt(Exception) exception is thrown if the current object's value is smaller than one. itb(BigInt isqrtc() const) The integer square root of the current object is returned. An tt(Exception) exception is thrown if the current object's value is smaller than one. itb(bool isZero() const) Returns tt(true) if the current object equals zero (0). itb(BigInt &lshift()) The current object's bits are shifted one bit to the left. The object's sign remains unaltered. itb(BigInt lshiftc()) The current object's bits shifted one bit to the left are returned. The object's sign will be equal to the current object's sign. itb(BigInt &lshift(size_t nBits)) The current object's bits are shifted tt(nBits) to the left. The object's sign remains unaltered. itb(BigInt lshiftc(size_t nBits) const) The current object's bits shifted tt(nBits) bit to the left are returned. The object's sign will be equal to the current object's sign. itb(BigInt &maskBits(size_t lowerNBits)) The current object's tt(lowerNBits) lower bits are kept, its higher order bits are cleared. The object's sign is not affected. itb(BigInt maskBitsc(size_t lowerNBits) const) A copy of the current object is returned having all but its tt(lowerNBits) lower bits cleared. The sign of the returned object will be equal to the current object's sign. itb(size_t maxWordIndex() const) Returns the maximum tt(Word)-index that can be used with the tt(at) and tt(setWord) members for the current bf(BigInt) value. itb(BigInt &mulMod(BigInt const &rhs, BigInt const &mod)) The current object is multiplied (modulo tt(mod)) by tt(rhs). itb(BigInt mulModc(BigInt const &rhs, BigInt const &mod) const) The current object multiplied (modulo tt(mod)) by tt(rhs) is returned. itb(BigInt &negate()) The current object's value is negated (i.e., the value changes its sign). itb(BigInt negatec() const) The negated value of the current object is returned. itb(size_t nWords() const) The number of `words' required to store the bf(BigInt) value is returned. Note that the returned value depends on the architecture's number of bytes per word. For 32-bit architectures there are four bytes per word, for 64-bit architectures eight bytes per word. itb(BigInt &rshift()) The current object's bits are shifted one bit to the right. The object's sign remains unaltered. itb(BigInt rshiftc()) The current object's bits shifted one bit to the right are returned. The object's sign will be equal to the current object's sign. itb(BigInt &rshift(size_t nBits)) The current object's bits are shifted tt(nBits) to the right. The object's sign remains unaltered. itb(BigInt rshiftc(size_t nBits) const) The current object's bits shifted tt(nBits) bit to the right are returned. The object's sign will be equal to the current object's sign. itb(BigInt &setBit(size_t index)) The bit at index position tt(index) is set. itb(BigInt setBitc(size_t index) const) A copy of the current object is returned having its bit at index position tt(index) set. itb(BigInt &setBit(size_t index, bool value)) The bit at index position tt(index) is set to tt(value). itb(BigInt setBitc(size_t index, bool value) const) A copy of the current object is returned having its bit at index position tt(index) set to tt(value). itb(BigInt &setNegative(bool negative)) The current object's sign will be set to negative if the function's argument is tt(true), it will be set to positive if the function's argument is tt(false). itb(BigInt setNegativec(bool negative) const) A copy of the current object is return having a negative sign if the function's argument is tt(true) and a positive sign if the function's argument is tt(false). itb(void setWord(size_t index, BigInt::Word value)) Assigns tt(value) to the tt(Word) at tt(index). E.g., on a 32 bit architecture, if the bf(BigInt) value equals 2+sups(33), then after tt(setWord(1, 1)) the value has become 2+sups(32). If tt(index) exceeds the value returned by tt(nWords) an tt(FBB::Exception) is thrown. itb(size_t size() const) The number of significant em(bits) required to store the current tt(BIGNUM) value is returned. itb(size_t sizeInBytes() const) The number of bytes required to store the current tt(BIGNUM) value is returned (returns the same value as the tt(size) member does). itb(size_t constexpr sizeOfWord() const) bf(BigInt) values are stored in units of `words', which are unsigned long values. These values may consist of, e.g., 32 or 64 bits. The number of bytes occupied by a `word' is returned: 4 for a 32 bit value, 8 for a 64 bit value, and possibly other values, depending on specific architecture peculiarities. The value returned by this member, therefore, is architecture dependent. itb(BigInt &sqr()) The current object's value is squared. itb(BigInt sqrc() const) The square of the current object is returned. itb(BigInt &sqrMod(BigInt const &mod) const) The current object's value is squared modulo tt(mod). itb(BigInt sqrModc(BigInt const &mod) const) The square (modulo tt(mod)) of the current object is returned. itb(BigInt &subMod(BigInt const &rhs, BigInt const &mod)) tt(Rhs) is subtracted modulo tt(mod) from the current object. itb(BigInt subModc(BigInt const &rhs, BigInt const &mod) const) The difference (modulo tt(mod)) of the current object and tt(rhs) is returned. itb(void swap(BigInt &other)) The current object swaps its value with tt(other). itb(BigInt &tildeBits()) All the bits in the bytes of the current object and the sign of the current object are toggled. So, after verb( Bigint b(5); b.tildeBits(); ) tt(b) contains the value -250. Also see the discussion with tt(operator~()) below. itb(BigInt tildeBitsc() const) A copy of the current object whose bits are toggled is returned. itb(BigInt &tildeInt()) The `tilde' operation is performed on the current object using the standard tt(int) semantics. E.g., ~5 results in -6. Also see the discussion with tt(operator~()) below. itb(BigInt tildeIntc() const) A copy of the current object is returned to which the `tilde' operation has been performed using the standard tt(int) semantics. itb(unsigned long ulong() const) The absolute value stored in the current object is returned as an unsigned long. If it cannot be represented by an unsigned long it returns tt(0xffffffffL). itb(int uCompare(BigInt const &rsh) const) Using absolute values, if the current object is smaller than tt(rhs) -1 is returned; if they are equal 0 is returned; if the current object is larger than tt(ths) 1 is returned (see also tt(uCompare)). ) manpagesection(OVERLOADED OPERATORS) Except for some operators all operators perform their intuitive operations. Where that isn't completely true an explanatory remark is provided. E.g., tt(operator*()) multiplies two tt(BigInt)s, possibly promoting one of the operands; tt(operator*=()) multiplies the lhs by the rhs tt(BigInt), possibly promoting the rhs operand. Here are the available operators: bf(Unary operators:) itemization( itb(bool operator bool() const) Returns tt(true) if the tt(BigInt) value is unequal zero, otherwise tt(false) is returned. itb(BigInt &operator++()) itb(BigInt operator++(int)) itb(BigInt &operator--()) itb(BigInt operator--(int)) itb(BigInt operator-()) itb(int operator[](size_t idx) const) With tt(BigInt) objects it returns the bit-value of the object's tt(idx)th bit as the value 0 or 1. itb(BigInt::Bit operator[](size_t idx)) With non-const tt(BigInt) objects it returns a reference to the bit-value of the object's tt(idx)th bit. When used as em(lvalue) assigning a 0 or non-zero value to the operator's return value will either clear or set the bit. Likewise, the following arithmetic assignment operators may be used: binary or (tt(|=)), binary and (tt(&=)) or binary xor (tt(^=)). When used as em(rvalue) the value of the object's tt(idx)th bit is returned as a tt(bool) value. When inseerted into a tt(std::ostream) the bit's value is displayed as 0 or 1. itb(BigInt operator~()) This operator is em(not) implemented as it cannot be implemented so that it matches the actions of this operator when applied to tt(int) type values. When used on tt(int) values this operator toggles all the tt(int)'s bits. E.g., ~5 represents -6, and ~-6 again equals five. The -6 is the result of the sign bit of tt(int) values. The obvious implementation of tt(BigInt::operator~()) is to toggle all the value's bits and to toggle its sign bit. For 5 this would result in -250: 5, being 101 (binary), fits in one byte, so ~5 becomes 11111010 (binary), which is 250. Its sign must be reversed as well, so it becomes -250. This clearly differs from the value represented by the tt(int) constant ~5: when constructing tt(BigInt(~5)), the value -6 is obtained. It is possible to change the implementation. E.g., after verb( Bigint b(5); b = ~b; ) tt(~b) could be implemented so that it results in the value -6. But this too leads to unexpected results. While tt(5 & ~5 == 0), this would no longer hold true for tt(BigInt) objects: Assuming tt(b) contains 5 then tt(b & ~b) would expand to (binary) tt(101 & (negative)110) which equals (binary) 100. Since either implementation produces unexpected results tt(BigInt::operator~()) was not implemented. Instead two members are offered: tt(tildeBits()), toggling all the bits of all the tt(BigInt) bytes and toggling its sign (so verb( Bigint b(5); b.tildeBits(); ) changes tt(b)'s value into -250), and tt(tildeInt()) changing the object's value into the value that would have been obtained if a tt(BigInt) was a mere tt(int) (so verb( Bigint b(5); b.tildeInt(); ) changes tt(b)'s value into -6). ) bf(Binary operators:) itemization( itb(BigInt operator*(BigInt const &lhs, BigInt const &rhs)) itb(BigInt operator/(BigInt const &lhs, BigInt const &rhs)) This operator returns the quotient of the tt(lhs) object divided by the tt(rhs) object. The remainder is lost (The member tt(div) performs the division and makes the remainder available as well). itb(BigInt operator%(BigInt const &lhs, BigInt const &rhs)) itb(BigInt operator+(BigInt const &lhs, BigInt const &rhs)) itb(BigInt operator-(BigInt const &lhs, BigInt const &rhs)) itb(BigInt operator<<(BigInt const &lhs, size_t nBits)) See also the tt(lshift) members. If tt(lhs) is positive, itb(BigInt operator>>=(BigInt const &lhs, size_t nBits)) See also the tt(rshift) members. itb(BigInt operator&(BigInt const &lhs, BigInt const &rhs)) This operator returns a tt(BigInt) value consisting of the tt(bit_and)-ed bits and sign flags of lhs and rhs operands. Consequently, if one operand is positive, the resulting value will be positive. itb(BigInt operator|(BigInt const &lhs, BigInt const &rhs)) This operator returns a tt(BigInt) value consisting of the tt(bit_or)-ed bits and sign flags of lhs and rhs operands. Consequently, if either operand is negative, the result will be negative. itb(BigInt operator^(BigInt const &lhs, BigInt const &rhs)) This operator returns a tt(BigInt) value consisting of the tt(bit_xor)-ed bits and sign flags of lhs and rhs operands. Consequently, if exactly one operand is negative, the result will be negative. ) bf((Arithmetic) assignment operator(s):) itemization( itb(BigInt &operator*=(BigInt const &rhs)) itb(BigInt &operator/=(BigInt const &rhs)) This operator assigns the result of the (integer) division of the current tt(BigInt) object by tt(ths) to the current object. The remainder is lost. The member tt(div) divides and makes the remainder available as well. itb(BigInt &operator%=(BigInt const &rhs)) itb(BigInt &operator+=(BigInt const &rhs)) itb(BigInt &operator-=(BigInt const &rhs)) itb(BigInt &operator<<=(size_t nBits)) See also the tt(lshift) members. itb(BigInt &operator>>=(size_t nBits)) See also the tt(rshift) members. itb(BigInt &operator&=(BigInt const &rhs)) This operator tt(bit_and)s the bits and sign flags of the current object and the rhs operand. itb(BigInt &operator|=(BigInt const &rhs)) This operator tt(bit_or)s the bits and sign flags of the current object and the rhs operand. itb(BigInt &operator^=(BigInt const &rhs)) This operator tt(bit_xor)s the bits and sign flags of the current object and the rhs operand. ) manpagesection(STATIC MEMBERS) All members returning a tt(BigInt) computed from a set of arguments and not requiring an existing tt(BigInt) object are defined as static members. The first tt(diophantus) member, returning a tt(long long) value, also is a static member. itemization( itb(long long diophantus(long long *factor1, long long *factor2, long long value1, long long value2)) The integral solution of tt(factor1 * value1 + factor2 * value2 = gcd) is computed. The function returns the greatest common divisor (tt(gcd)) of tt(value1) and tt(value2), and returns their multiplication factors in, respectively, tt(*factor1) and tt(*factor2). The solution is not unique: another solution is obtained by adding tt(k * value2) to tt(factor1) and subtracting tt(k * value1) from tt(factor2). For values exceeding tt(std::numeric_limits::max()) the next member can be used. itb(BigInt diophantus(BigInt *factor1, BigInt *factor2, BigInt const &value1, BigInt const &value2)) The integral solution of tt(factor1 * value1 + factor2 * value2 = gcd) is computed. The function returns the greatest common divisor (tt(gcd)) of tt(value1) and tt(value2), and returns their multiplication factors in, respectively, tt(*factor1) and tt(*factor2). The solution is not unique: another solution is obtained by adding tt(k * value2) to tt(factor1) and subtracting tt(k * value1) from tt(factor2). itb(BigInt fromText(std::string text, int mode = 0)) This member converts a textual representation of a number to a tt(BigInt) value. Conversion continues until the end of tt(text) or until a character outside of an expected range is encountered. The expected range may be preset by specifying tt(mode) as tt(ios::dec, ios::oct,) or tt(ios::hex) or (the default) the expected range is determined by tt(fromText) itself by inspecting the characters in tt(text). By default if tt(text) contains hexadecimal characters then tt(fromText) assumes that the number is represented as a hexadecimal value (e.g., tt("abc") is converted to the (decimal) value 2748); if tt(text) starts with 0 and contains only characters in the range 0 until (including) 7 then tt(fromText) assumes the number is represented as an octal value (e.g., tt("01234") is converted to the (decimal) value 668). Otherwise a decimal value is assumed. If the text does not represent a valid numerical value (of the given extraction mode) then a tt(FBB::Exception) exception is thrown (tt(fromText: text does not represent a BigInt value)). itb(BigInt rand(size_t size, Msb msb = MSB_IS_ONE, Lsb lsb = ODD)) This member returns a cryptographically strong pseudo-random number of tt(size) bits. The most significant bit(s) can be controlled by tt(msb) (by default bf(MSB_IS_ONE)), the least significant bit can be controlled by tt(lsb) (by default bf(ODD)). Before calling this member the random number generator must have been seeded. From the bf(RAND_add)(3ssl) man-page: OpenSSL makes sure that the PRNG state is unique for each thread. On systems that provide tt(/dev/urandom), the randomness device is used to seed the PRNG transparently. However, on all other systems, the application is responsible for seeding the PRNG by calling bf(RAND_add)(3ssl), bf(RAND_egd)(3ssl), bf(RAND_load_file)(3ssl), or bf(RAND_seed)(3ssl). itb(BigInt randRange(BigInt const &max)) This member returns a cryptographically strong pseudo-random number in the range tt(0 <= number < max). Before calling this member the random number generator must have been seeded (see also bf(rand), described above). itb(BigInt setBigEndian(std::string const &bytes)) The tt(bytes.length()) bytes of tt(bytes) are used to compute a tt(BigInt) object which is returned by this function. The characters in tt(bytes) are interpreted as a series of bytes in big-endian order. See also the member function tt(bigEndian()) above. The returned tt(BigInt) has a positive value. itb(BigInt prime(size_t nBits, BigInt const *mod = 0, BigInt const *rem = 0, PrimeType primeType = ANY)) This member returns a prime number of tt(bBits) bits. If both tt(mod) and tt(rem) are non-zero, the condition prime % mod == rem. (E.g., use tt(prime % mod == 1) in order to suit a given generator). The parameter tt(primeType) can be tt(ANY), tt((prime - 1) / 2) may or may not be a prime. If it is tt(SAFE) then tt((prime - 1) / 2) will be a (so-called em(safe)) prime. itb(BigInt pseudoRand(size_t size, Msb msb = MSB_IS_ONE, Lsb lsb = ODD)) This member returns a potentially predictable pseudo-random number of tt(size) bits. The most significant bit(s) can be controlled by tt(msb) (by default bf(MSB_IS_ONE)), the least significant bit can be controlled by tt(lsb) (by default bf(ODD)). It can be used for non-cryptographic purposes and for certain purposes in cryptographic protocols, but usually not for key generation. itb(BigInt pseudoRandRange(BigInt const &max)) This member returns a potentially predictable pseudo-random number in the range tt(0 <= number < max). ) manpagesection(FREE FUNCTIONS IN THE FBB NAMESPACE) itemization( itb(std::ostream &operator<<(ostream &out, BigInt const &value)) Inserts tt(value) into the provided tt(ostream). If the tt(hex) manipulator has been inserted into the stream before inserting the tt(BigInt) value the value will be displayed as a hexadecimal value (without a leading tt(0x)); if the tt(oct) manipulator has been inserted the value will be represented as an octal value (starting with a 0). The value will be displayed as a decimal value if the tt(dec) manipulator is active. If the tt(BigInt) value is negative its value will be preceded by a minus character. itb(std::istream &operator>>(istream &in, BigInt &value)) Extracts tt(value) from the provided tt(istream). Depending on the currently set extraction mode (tt(dec, oct,) or tt(hex)) the matching set of characters will be extracted from tt(in) and converted to a number which is stored in tt(value). Extraction stops at EOF or at the first character outside of the range of characters matching the extraction mode. if no numerical characters were extracted the stream's tt(failbit) is set. The extracted value may be preceded by a minus character, resulting in an extracted negative value. ) manpagesection(EXAMPLE) verb( #include #include using namespace std; using namespace FBB; int main() { BigInt value(BigInt::prime(100)); BigInt mod(BigInt::rand(50)); BigInt inverse(value.inverseModc(mod)); cout << '(' << value << " * " << inverse << ") % " << mod << " = " << ( value * inverse ) % mod << endl; } ) manpagefiles() em(bobcat/bigint) - defines the class interface manpageseealso() bf(bobcat)(7), bf(diffiehellman)(3bobcat), bf(RAND_add)(3ssl), bf(RAND_egd)(3ssl), bf(RAND_load_file)(3ssl), bf(RAND_seed)(3). For tt(BIGNUM): tt(https://www.openssl.org/docs/man1.0.2/man3/bn_sub_words.html) manpagebugs() Sep/Oct 2013: due to a change in library handling by the linker (cf. lurl(http://fedoraproject.org/wiki/UnderstandingDSOLinkChange) and lurl(https://wiki.debian.org/ToolChain/DSOLinking)) libraries that are indirectly required are no longer automatically linked to your program. With bf(BigInt) this is tt(libcrypto), which requires programs to link to both tt(bobcat) and tt(crypto). includefile(include/trailer) bobcat-5.09.01/documentation/man/sharedstream.yo0000644000175000017500000002274714050437223020577 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::SharedStream)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (I/O on shared memory) manpagename(FBB::SharedStream)(I/O operations on shared memory) manpagesynopsis() bf(#include )nl() Linking option: tt(-lpthread -lbobcat) manpagedescription() This class combines the features of the bf(std::istream) and bf(std::ostream) classes, operating on shared memory. As with tt(std::fstream) objects, a tt(seekp) or tt(seekg) member call is required to switch from writing to reading or v.v. As with tt(std::fstream) objects, bf(FBB::SharedStream) objects do not keep separate offsets for reading and writing: the seek-members always refer to the (single) offset maintained by the tt(FBB::SharedMemory) object to which the bf(SharedStream) object interfaces. So, although tt(tellg) and tt(tellp) return identical values, tt(tellg) should not be called after writing to a bf(SharedStream) object, and tt(tellp) should not be called after reading from a bf(SharedStream) object, as calling members related to reading (tt(tellg)) after writing and v.v. put the stream in its fail state. includefile(include/namespace) manpagesection(INHERITS FROM) bf(FBB::SharedBuf) (private inheritance),nl() bf(std::istream),nl() bf(std::ostream),nl() bf(FBB::SharedEnum__) (cf. bf(sharedmemory)(3bobcat) for a description of this base class). manpagesection(SIZEUNIT ENUMERATION) The bf(enum SizeUnit) defines the following symbolic constants: itemization( it() bf(kB), representing 1024 (2**10) bytes of memory; it() bf(MB), representing 1048576 (2**20 bytes of memory; it() bf(GB), representing 1073741824 (2**30) bytes of memory ) manpagesection(CONSTRUCTORS) itemization( itb(SharedStream()) The default constructor defines a stub a bf(SharedStream) object that cannot immediately be used to access shared memory. To use it, its member tt(open) must first be called. itb(SharedStream(size_t maxSize, SizeUnit sizeUnit, std::ios::openmode openMode = std::ios::in | std::ios::out, size_t access = 0600)) This constructor creates a stream inheriting the facilities of an tt(std::istream) and tt(std::ostream) that interfaces to a shared memory segment having a capacity of at least tt(maxSize * sizeUnit) bytes. By default, the shared memory segment is opened for reading and writing. Different from the open modes used for file streams, creating a shared memory stream with open modes tt(ios::in | ios::out) is OK. In this case the shared memory segment is created and once information has been written to the shared memory it can also be read again. The shared memory's access rights are defined by the tt(access) parameter, interpreted as an octal value, using the well-known (bf(chmod)(1)) way to define the access rights for owner, group and others. If construction fails, an tt(FBB::Exception) is thrown. itb(SharedStream(int id, std::ios::openmode openMode = std::ios::in | std::ios::out)) This constructor creates a stream inheriting the facilities of an tt(std::istream) and tt(std::ostream) that connects to a shared memory segment having ID tt(id). Specifying the tt(ios::trunc) flag immediately clears the content of the shared memory. An tt(FBB::Exception) is thrown if construction fails (e.g., no shared memory segment having ID tt(id) exists), ) Copy and move constructors (and assignment operators) are not available. manpagesection(MEMBER FUNCTIONS) All members of tt(std::istream) and tt(std::ostream) and the tt(enum) values tt(kB, MB), and tt(GB), defined by tt(FBB::SharedEnum__) are available. itemization( itb(FBB::SharedCondition attachSharedCondition(std::ios::off_type offset, std::ios::seekdir origin)) Returns an bf(FBB::SharedCondition)(3) object, interfacing to a shared condition variable located at offset tt(offset) (relative to tt(origin)) in the tt(SharedMemory) object to which the bf(SharedStream) object interfaces. This member does not alter the value returned by the stream's tt(tellg) and tt(tellp) members. An tt(FBB::Exception) is thrown if the tt(FBB::SharedCondition) object could not be constructed. itb(FBB::SharedCondition createSharedCondition()) Returns an bf(FBB::SharedCondition)(3) object, interfacing to a newly created shared condition variable which is created at the current offset of the tt(SharedMemory) object to which the bf(SharedStream) object interfaces (or at the first offset of the next physical shared memory data block, cf. bf(sharedcondition)(3bobcat))). Creating a tt(SharedCondition) object does not alter the value returned by the stream's tt(tellg) and tt(tellp) members. An tt(FBB::Exception) is thrown if the tt(FBB::SharedCondition) object could not be constructed. itb(int id() const) The ID of the shared memory segment is returned. itb(void kill()) Without locking the shared memory first, all shared memory is returned to the operating system. The bf(FBB::SharedStream) object is unusable after returning from tt(kill). Other processes that were using the shared memory can continue to do so. itb(void memInfo(std::ostream &out, char const *end = "\n")) Information about the tt(SharedMemory) object is inserted into the provide tt(ostream) object. The IDs of the shared segments, their sizes, the maximum number of shared memory segments, the number of bytes that can be read from the shared memory, and its actual storage capacity, etc., are displayed. Following the information about the shared memory, tt(end) is inserted into tt(out). itb(void open(size_t maxSize, SizeUnit sizeUnit, std::ios::openmode openMode = std::ios::in | std::ios::out, size_t access = 0600)) This member creates a shared memory segment having a capacity of at least tt(maxSize * sizeUnit) bytes, and connects the shared memory segment to the bf(FBB::SharedStream). A matching tt(close) member does not exist and is not required. By default, the shared memory segment is opened for reading and writing. Different from the open modes used for file streams, creating a shared memory stream with open modes tt(ios::in | ios::out) is OK. In this case the shared memory segment is created and once information has been written to the shared memory it can also be read again. The shared memory's access rights are defined by the tt(access) parameter, interpreted as an octal value, using the well-known (bf(chmod)(1)) way to define the access rights for owner, group and others. If opening fails, an tt(FBB::Exception) is thrown. itb(void open(int id, std::ios::openmode openMode = std::ios::in | std::ios::out)) This member connects the bf(FBB::SharedStream) object to a shared memory segment having ID tt(id). A matching tt(close) member does not exist and is not required. If opening succeeds the shared memory is ready for use. Specifying the tt(ios::trunc) flag immediately clears the content of the shared memory. An tt(FBB::Exception) is thrown if opening fails (e.g., no shared memory segment having ID tt(id) exists). itb(void remove()) The shared memory is first locked. Next, all shared memory is returned to the operating system. The bf(FBB::SharedStream) object is unusable after returning from tt(remove). Other processes that were using the shared memory can continue to do so. itb(bool truncate(std::streamsize offset)) If tt(offset) is not exceeding the value returned by tt(seekg(0, std::ios::end)), then this latter value is changed to tt(offset) and tt(true) is returned. Otherwise tt(false) is returned, and the value returned by tt(seekg) is not altered. If the value returned by tt(tellg) exceeded tt(offset), tt(tellg)'s return value it is reduced to tt(offset) as well. Subsequent read operations on the shared memory can only succeed as long as tt(tellg)'s return value hasn't reached the value tt(offset). ) manpagesection(EXAMPLE) verbinclude(../../sharedstream/driver/driver.cc) manpagefiles() em(bobcat/sharedstream) - defines the class interface manpageseealso() bf(bobcat)(7), bf(chmod)(1), bf(isharedstream)(3bobcat), bf(osharedstream)(3bobcat), bf(sharedblock)(3bobcat), bf(sharedcondition)(3bobcat), bf(sharedmemory)(3bobcat) bf(sharedmutex)(3bobcat), bf(sharedpos)(3bobcat), bf(sharedsegment)(3bobcat), bf(sharedbuf)(3bobcat) manpagebugs() Note that by default exceptions thrown from within a bf(std::stream) object are caught by the stream object, setting its tt(ios::failbit) flag. To allow exceptions to leave a stream object, its tt(exceptions) member can be called, e.g., using: verb( myStream.exceptions(ios::failbit | ios::badbit | ios::eofbit); ) includefile(include/trailer) bobcat-5.09.01/documentation/man/manipulators.yo0000644000175000017500000000713514050437223020625 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Manipulators)(3bobcat)(_CurYrs_) (libbobcat-dev__CurVers_)(Manipulators) manpagename(FBB::Manipulators)(Manipulators defined in the FBB namespace) manpagedescription() Various manipulators are defined within the bf(FBB) namespace. This manual page provides an overview of the manipulators that are currently defined in the bf(FBB) namespace. manpagesection(MANIPULATORS) itemization( itb(FBB::center) defined in tt(bobcat/align) This manipulator can be specified when constructing an bf(FBB::Align) object to indicate that a table column should center its content. itb(FBB::decindent) defined in tt(bobcat/indent) This manipulator reduces the indentation level. itb(FBB::def) defined in tt(bobcat/table) This manipulator `completes' a bf(Table) object to a full rectangular object. It can be inserted into a bf(Table) object. itb(FBB::eoi) defined in tt(bobcat/eoi) Inserting this manipulator indicates `end of input' of streams initialized with classes derived from tt(std::streambuf) receiving information from external sources. Examples (non-exhaustive list) are found in the classes bf(EncryptBuf, HMacBuf, OfdBuf, Process). Usually classes supporting the tt(eoi) manipulator also offer a member tt(eoi) performing the same actions as the manipulator. itb(FBB::err) defined in tt(bobcat/msg) Generates an error message. itb(FBB::errnodescr) defined in tt(bobcat/exception) Inserts the textual description of the current tt(::errno) value into the tt(ostream) into which the manipulator is inserted. If tt(errno == 0) nothing is inserted. itb(FBB::fatal) defined in tt(bobcat/msg) Generates a fatal message, followed by an bf(Exception)bf((1)) exception. itb(FBB::fs) defined in tt(bobcat/tablebuf) Starts the definition of the next element in a table. itb(FBB::info) defined in tt(bobcat/msg) Generates an informational message. itb(FBB::incindent) defined in tt(bobcat/indent) This manipulator will increment the indentation level. itb(FBB::indent) defined in tt(bobcat/indent) This manipulator inserts the currently defined number of indentation blanks into an tt(ostream). itb(FBB::indentdec) defined in tt(bobcat/indent) This manipulator will insert, then reduce the indentation level. itb(FBB::indentinc) defined in tt(bobcat/indent) This manipulator will insert, then increment the indentation level. itb(FBB::lm) defined in tt(bobcat/ofoldbuf) This manipulator sets the left margin of bf(FBB::OFoldStream) objects. itb(FBB::mlm) defined in tt(bobcat/ofoldbuf) This manipulator modifies (alters) the left margin of bf(FBB::OFoldStream) objects. itb(FBB::nlindent) defined in tt(bobcat/indent) This manipulator will insert a newline, then indent. itb(FBB::rs) defined in tt(bobcat/tablebuf) Starts the definition of the next row in a table. itb(FBB::spool) defined in tt(bobcat/msg) Generates a (partial) informational message. itb(FBB::warning) defined in tt(bobcat/msg) Generates a warning message. ) manpageseealso() bf(bobcat)(7), bf(columnwidth)(3bobcat), bf(eoi)(3bobcat), bf(equalwidth)(3bobcat), bf(indent)(3bobcat), bf(lm)(3bobcat), bf(mlm)(3bobcat), bf(msg)(3bobcat), bf(table)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/iostream.yo0000644000175000017500000000607314050437223017732 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::IOStream)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (std::istream and std::ostream) manpagename(FBB::IOStream)(Combines std::istream and std::ostream features) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() This class combines the features of the bf(std::istream) and bf(std::ostream) classes. The bf(std::istream) and bf(std::ostream) may be physically different streams. bf(FBB:IOStream) objects may, e.g., be associated with streams wrapped around em(pipes) (see, e.g., bf(FBB::IfdStream) and bf(FBB::OFdStream)), to construct bi-directional pipes. includefile(include/namespace) manpagesection(INHERITS FROM) bf(FBB::IOBuf) (private inheritance),nl() bf(std::istream),nl() bf(std::ostream) manpagesection(CONSTRUCTORS) itemization( itb(IOStream()) The default constructor constructs an empty bf(FBB::IOStream) objects. It should not be used before its tt(open) member (see below) was called. itb(IOStream(std::istream &in, std::ostream &out)) This constructor associates the bf(IOStream) object with a tt(std::istream) and a tt(std::ostream). All output operations will be passed on to the tt(std::ostream), all input operations to the tt(std::istream). The streams passed to tt(IOStream) should outlive the bf(IOStream) object. This constructor performs the actions of the default constructor and then calls the tt(IOStream::open) member ) Copy and move constructors (and assignment operators) are not available. manpagesection(MEMBER FUNCTIONS) All members of tt(std::istream) and tt(std::ostream) are available, as bf(FBB::IOStream) inherits from these classes. Furthermore, when switching between tt(std::istream) and tt(std::ostream) operations, no intermediate tt(seekg()) or tt(seekp()) operation will normally be required, since the base classes will normally be associated with physically different streams. itemization( itb(void open(std::istream &in, std::ostream &out)) This member (re)associates the bf(IOStream) object with a tt(std::istream) and a tt(std::ostream). All output operations will be passed on to the tt(std::ostream), all input operations to the tt(std::istream). The streams passed to tt(IOStream()) should outlive the bf(IOStream) object. If this member is called for an bf(IOStream) object already associated with an tt(std::ostream) object, the already associated tt(std::ostream) object is flushed before setting up the new association. itb(void clear()) This member clears the error states of the associated tt(std::istream) and tt(std::ostream) objects. ) manpagesection(EXAMPLE) See the example provided with bf(process)(3bobcat). manpagefiles() em(bobcat/iostream) - defines the class interface manpageseealso() bf(bobcat)(7), bf(ifdstream)(3bobcat), bf(iobuf)(3bobcat), bf(ofdstream)(3bobcat), bf(process)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/eoi.yo0000644000175000017500000000540714050437223016663 0ustar frankfrankincludefile(include/header) COMMENT(replace 'classname' by the name of the new class) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Eoi)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (End-Of-Information Base class) manpagename(FBB::Eoi)(std::streambuf class offering an eoi manipulator) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() The class tt(Eoi) inherits from tt(std::streambuf) and may therefore be used as a base class of classes specializing tt(std::streambuf). It is particularly useful for classes implementing output operations, as it can be used to specify the `true end' of the generated output. E.g., an tt(std::istream in) object may insert its content into a tt(std::ostream out) object using the familiar tt(out << in.rdbuf()) expression, but that doesn't allow tt(out) to conclude that it has received all of its information. Sometimes additional actions are required to complete the output (this happens with, e.g., tt(EncryptBuf) objects (cf. bf(encryptbuf)(3bobcat)) where after encrypting all input padding characters may have to be added to the encrypted document). If tt(out) is initialized with the address of an tt(EncryptBuf std::streambuf) then the true end of the input can be indicated by inserting the tt(eoi) manipulator. The resulting expression becomes tt(std::cout << in.rdbuf() << eoi), and the manipulator ensures that the correct padding is handled. includefile(include/namespace) manpagesection(INHERITS FROM) tt(std::streambuf) manpagesection(PROTECTED CONSTRUCTOR) itemization( itb(Eoi()) Analogously to tt(std::streambuf) only a default protected constructor is available. ) Copy and move constructors (and assignment operators) are not available. manpagesection(MEMBER FUNCTIONS) All members of tt(std:streambuf) are available, as bf(FBB::Eoi) inherits from these classes. manpagesection(VIRTUAL MEMBER FUNCTION) itemization( itb(virtual void eoi_()) The virtual member function tt(eoi_) is a private member that can be overridden by derived classes. By default it performs no actions. ) manpagesection(MANIPULATORS) itemization( itb(std::ostream &FBB::eoi(std::ostream &out)) If the tt(ostream out's streambuf's) address can be downcasted to an tt(Eoi *) then its tt(eoi_) member is called. Otherwise the manipulator performs no actions, and merely returns tt(out). ) manpagesection(EXAMPLE) See the example provided in the tt(encryptbuf)(3bobcat) man-page manpagefiles() em(bobcat/eoi) - defines the class interface manpageseealso() bf(bobcat)(7), bf(eoibuf)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/decryptbuf.yo0000644000175000017500000001235514050437223020256 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::DecryptBuf)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Decrypt information) manpagename(FBB::DecryptBuf) (Decrypts information using various methods into a std::ostream) manpagesynopsis() bf(#include )nl() Linking option: tt( -lbobcat -lcrypto) manpagedescription() bf(FBB::DecryptBuf) objects are bf(std::streambuf) objects that can be used to initialize tt(std::ostream) objects. All information inserted into such an tt(std::ostream) is decrypted and written to an tt(std::ostream) passed as argument to tt(DecryptBuf)'s constructor. All encryption methods supported by the OpenSSL library that can be selected by name may be used by tt(DecryptBuf) objects. In practice the information has previously been encrypted by an tt(EncryptBuf) object, using the same encryption method. Likewise, the constructor expects a em(key) and em(initialization vector). The key and initialization vector that was passed to the tt(EncryptBuf) object must be passed to tt(DecryptBuf)'s constructor as well. includefile(blockciphers) includefile(symcryptciphers) includefile(include/namespace) manpagesection(INHERITS FROM) bf(FBB::CryptBuf), in turn inheriting from bf(std::streambuf) manpagesection(CONSTRUCTOR/DESTRUCTOR) itemization( itb(DecryptBuf(std::ostream &outStream, char const *type, std::string const &key, std::string const &iv, size_t bufsize = 1024)) This constructor initializes the tt(DecryptBuf) object preparing it for the decryption algorithm specified by tt(type). The decryption algorithms that are available are listed in the abovementioned table. As an example: to use the AES method on 192 bit keys and blocks in CBC mode specify tt("aes-192-cbc"). The tt(key) parameter refers to the key to be used, the tt(iv) parameter refers to the initialization vector that was used when encrypting the original information. The IV is not considered confidential. When using ECB modes no initialization vector is used. In those cases any non-empty initialization vector may be provided. The constructor throws an tt(FBB::Exception) exception if an encryption method is specified that is not supported by OpenSSL. The constructor's first parameter refers to the tt(std::ostream) receiving the decrypted information. The tt(bufsize) argument specifies the size in bytes of the internal buffer used by tt(DecryptBuf) temporarily storing incoming characters. The provided default argument can most likely be kept as-is. itb(~DecryptBuf()) Normally, once all encrypted information has been inserted into the decryption stream the tt(eoi) manipulator (see below) is inserted to complete the decryption process. Alternatively, the decryption process ends once the tt(DecryptBuf's) destructor is called. E.g., if tt(decStream) is the tt(std::ostream) to receive the encrypted information and tt(encStream) is the tt(std::istream) containing the encrypted information then verb( decStream << encStream.rdbuf(); ) completes the decryption once tt(DecryptBuf's) destructor is called. Alternatively, verb( desStream << encStream.rdbuf() << eoi; ) can be used to immediately complete the decryption process. ) Copy and move constructors (and assignment operators) are not available. manpagesection(MEMBER FUNCTIONS) All members of bf(std::streambuf) are available, as bf(FBB::DecryptBuf) inherits from this class. itemization( itb(void eoi()) This member can be called instead of using the manipulator to end the decryption process. It throws an tt(std::exception) if decryption fails (which may happen if the tt(DecryptBuf) object is provided with incorrect (usually improperly padded) input). itb(bool setRounds(size_t nRounds)) This member can only be used with the RC5 decryption method to set the number of rounds of the algorithm to 8, 12 or 16. When the number of rounds were updated successfully the member returns tt(true). It returns tt(false) in other cases (e.g., called for other decryption methods than RC5 or the requested number of rounds differ from 8, 12 or 16). ) manpagesection(PROTECTED MEMBER) itemization( itb(EVP_CIPHER_CTX *cipherCtx()) Classes derived from tt(DecryptBuf) may use this member to gain direct access to the tt(EVP_CIPHER_CTX) pointer used by the tt(DecryptBuf) object. This pointer is a pointer to an opaque structure used by many OpenSSL functions to set or query parameters of an decryption method. ) manpagesection(MANIPULATOR) itemization( itb(FBB::eoi) The tt(eoi) manipulator can be inserted into the decryption stream to complete the decryption process. If it is inserted into an tt(std::ostream) that is not initialized with either a tt(DecryptBuf) or an tt(EncryptBuf) nothing happens. ) manpagesection(EXAMPLE) verbinclude(../../decryptbuf/driver/driver.cc) manpagefiles() em(bobcat/decryptbuf) - defines the class interface manpageseealso() bf(bobcat)(7), bf(encryptbuf)(3bobcat), bf(std::streambuf) manpagebugs() None reported includefile(include/trailer) bobcat-5.09.01/documentation/man/redirector.yo0000644000175000017500000002101714050437223020244 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Redirector)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (System Level File Redirection) manpagename(FBB::Redirector)(Redirects a file descriptor to another descriptor) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() Objects of the class bf(FBB::Redirector) set up a system level file redirection, using file descriptors rather than streams. tt(Redirector) objects are effectively em(wrappers) around the bf(dup2)(2) system call. System level redirection allows the programmer to send output to, e.g., the standard output stream, which actually appears at another stream (e.g., the standard error). tt(Redirector) objects are used to redirect the output sent to a stream having file descriptor tt(x) to another stream having file descriptor tt(y), much like the shell's tt(>) operator redirects the standard output to some file. tt(Redirector) objects can also be used to extract the information from a stream having file descriptor tt(x) in fact from another stream having file descriptor tt(y), much like the shell's tt(<) operator is used to read the information in some file from the standard input. Redirection using tt(Redirector) objects represents a stronger form of redirection than redirection offered by bf(C++) itself, which uses tt(std::streambuf) redirection, and which is, because of that, bound to the program's scope. System level redirection, on the other hand, is applied at the system level, allowing the programmer to redirect standard streams when starting a program. For example, the standard error is commonly written to the standard output using an invocation like tt(program 2>&1). When constructing tt(Redirector) objects a file descriptor is required. The file descriptor specified at the constructor is the file descriptor that is used by the program to read information from or to write information to. Another file descriptor is required to set up the redirection: the file descriptor used here is the file descriptor of the stream that actually holds the information which is extracted from the file descriptor that was passed to the tt(Redirector)'s constructor; or it is the file descriptor of the stream receiving the information which is written to the stream having the file descriptor that was passed to the tt(Redirector)'s constructor. When a tt(Redirector) object goes out of scope, its file descriptor are left as-is. In particular, note that no bf(close)(2) operation is performed on the tt(Redirector's) file descriptors. After setting up redirection using the tt(Redirector's) member functions and passing the tt(Redirector's) file descriptors to code that uses the tt(Redirector's) descriptors, the tt(Redirector) object could in fact safely be destroyed. Formally, file descriptors are not defined in bf(C++), but they are available in many types of operating systems. In those systems each `file' has an associated `file descriptor'. A file descriptor is an bf(int), which is an index into the program's file allocation table, maintained by the system. Another type of well-known entities which are file descriptors are em(sockets). Well-known filedescriptors (defined in, e.g., tt(unistd.h)) having fixed values are itemization( tt() 0 (tt(STDIN_FILENO)), representing the standard input stream (tt(std::cin)); tt() 1, (tt(STDOUT_FILENO)), representing the standard output stream (tt(std::cout)); tt() 2, (tt(STDERR_FILENO)), representing the standard error stream (tt(cerr)); ) Notes: itemization( it() System-level redirections are kept during system calls of the bf(exec)(3) family. it() Destroying a tt(Redirector) object does em(not) undo the redirection set up by that object. ) includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(ENUM) The enumeration bf(StandardFileno) holds the following values: itemization( itt(STDIN) (0) itt(STDOUT) (1) itt(STDERR) (2) ) These values may be used to set up a redirection instead of the plain numbers. manpagesection(CONSTRUCTORS) itemization( itb(Redirector(int fd)) This constructor expects the file descriptor of the file that will be used by the program to access (read, write) another file. The file descriptor that is passed to the constructor is used by the program, and will often be tt(STDIN, STDOUT), or tt(STDERR), allowing the program to use tt(cin, cout), or tt(cerr) to extract information from, or insert information into other streams using its standard input and output streams. ) Copy and move constructors (and assignment operators) are available. manpagesection(MEMBER FUNCTIONS) itemization( itb(void swallow(int otherFd) const) This member function expects a file descriptor which should become a synonym of the constructor's file descriptor. The constructor's file descriptor is redirected to tt(otherFd). After successfully calling tt(swallow) information written to tt(otherFd) is in fact written to the constructor's file descriptor. E.g., if the constructor's file descriptor represents a file on disk and tt(otherFd) is tt(STDOUT_FILENO) then all information sent to the standard output stream is actually sent to the file on disk: verb( information sent to otherFd -> is received at the constructor's Fd (e.g., otherFd = STDOUT_FILENO) ) Conversely, if the constructor's file descriptor represents a file on disk and tt(otherFd) is tt(STDIN_FILENO) then all information extracted from the standard input stream is actually read from the file on disk. verb( information extracted from otherFd <- is read from the constructor's Fd (e.g., otherFd = STDIN_FILENO) ) Following tt(swallow) both file descriptors are open, and refer to the constructor's file descriptor. Before setting up the redirection, the original tt(otherFd) is closed by bf(close)(2). Following tt(swallow) both file descriptors can be used, and refer to the constructor's file descriptor. If after calling tt(swallow) bf(close)(2) is called for one of them, then the other one remains open. If redirection fails an bf(FBB::Exception) object is thrown, whose tt(which()) member shows the system's tt(errno) value set by the failing bf(dup2)(2) function. itb(void through(int otherFd) const) This member function expects a file descriptor which should become a synonym of the constructor's file descriptor. The constructor's file descriptor is redirected to tt(otherFd). The constructor's file descriptor can no longer be used, as it is closed by bf(close)(2). After successfully calling tt(through) information written to tt(otherFd) is in fact written to the constructor's file descriptor. E.g., if the constructor's file descriptor represents a file on disk and tt(otherFd) is tt(STDOUT_FILENO) then all information sent to the standard output stream is actually sent to the file on disk: verb( information sent to otherFd -> is received at the constructor's Fd (e.g., otherFd = STDOUT_FILENO) ) Conversely, if the constructor's file descriptor represents a file on disk and tt(otherFd) is tt(STDIN_FILENO) then all information extracted from the standard input stream is actually read from the file on disk. verb( information extracted from otherFd <- is read from the constructor's Fd (e.g., otherFd = STDIN_FILENO) ) Before setting up the redirection, the original tt(otherFd) is closed by bf(close)(2). Following tt(through) only tt(otherFd) can be used, and it refers to (i.e., reads or writes) the constructor's file descriptor. If redirection fails an bf(FBB::Exception) object is thrown, whose tt(which()) member shows the system's tt(errno) value set by the failing bf(dup2)(2) function. ) manpagesection(EXAMPLE) verb( #include #include using namespace std; using namespace FBB; int main() { Redirector redirector(Redirector::STDOUT); redirector.swallow(Redirector::STDERR); cerr << "This appears at the standard output stream\n" "use `a.out > /dev/null' to suppress this message" << endl; } ) manpagefiles() em(bobcat/redirector) - defines the class interface manpageseealso() bf(bobcat)(7), bf(dup2)(2), bf(execl)(3) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/iquotedprintablestream.yo0000644000175000017500000000562514050437223022700 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::IQuotedPrintableStream)(3bobcat)(_CurYrs_) (libbobcat-dev__CurVers_) (QuotedPrintable encoding/decoding std::istream) manpagename(FBB::IQuotedPrintableStream) (Std::istream performing quoted-printable encoding and decoding) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() bf(FBB::IQuotedPrintableStream) objects may be used to quoted-printable encode or decode information that is available on a separate tt(std::istream). The tt(class IQuotedPrintableStream) is a class template, using a tt(FBB::CodeType) template non-type parameter. Objects of the class tt(FBB::IQuotedPrintableStream) encode the information they receive, objects of the class tt(FBB::IQuotedPrintableStream) decode the information they receive. includefile(include/namespace) manpagesection(INHERITS FROM) bf(FBB::IQuotedPrintableBuf) (private), nl() bf(std::istream) manpagesection(CONSTRUCTORS) itemization( itb(IQuotedPrintableStream(std::istream &in, size_t bufSize = 1000)) This constructor initializes a tt(std::istream) providing it with an bf(FBB::IQuotedPrintableBuf) stream buffer. The bf(IQuotedPrintableBuf)'s constructor receives all arguments that are passed to this constructor. - tt(IQuotedPrintableStream) objects perform quoted printable encodi ng;nl() - tt(IQuotedPrintableStream) objects perform quoted printable decoding;nl() - tt(IQuotedPrintableStream) objects obtain the bytes to encode or decode from tt(std::istream &in);nl() - The internally used tt(IFilterBuf) is initialized with a buffer of size tt(bufSize), using a lower bound of 100. The constructor uses a configurable buffer size for reading. Characters that were read into the buffer but are not part of the actual quoted printable encoded data are unavailable after completing the quoted printable decoding. If information beyond the quoted printable input block should remain available, then specify a buffer size of 1. ) Copy and move constructors (and assignment operators) are not available. manpagesection(INHERITED MEMBERS) Since the class uses public derivation from bf(std::istream), all members of this class can be used. manpagesection(EXAMPLE) verbinclude(../../iquotedprintablestream/driver/driver.cc) See also the example in the bf(iquotedprintablebuf)(3bobcat) man-page. manpagefiles() em(bobcat/iquoted printablestream) - defines the class interface manpageseealso() bf(bobcat)(7), bf(iquotedprintablebuf)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/clientsocket.yo0000644000175000017500000001134714050437223020576 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::ClientSocket)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Client Socket) manpagename(FBB::ClientSocket) (Client Socket connecting to a Server in the Internet) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() An bf(FBB::ClientSocket) may be constructed to connect to some server process in the internet. The socket made available by the bf(FBB:ClientSocket) may be used to initialize a bf(std::istream) and/or bf(std::ostream). The bf(std::istream) is used to read information from the server process to which the bf(FBB::ClientSocket) connects, The bf(std::ostream) is used to send information to the server process to which the bf(FBB::ClientSocket) connects. Since a socket may be considered a em(file descriptor) the available bf(FBB::IFdStream), bf(FBB::IFdStreamBuf), bf(FBB::OFdStream), and bf(FBB::OFdStreamBuf) classes may be used profitably here. Note that having available a socket does not mean that this defines the communication protocol. It is (still) the responsibility of the programmer to comply with an existing protocol or to implement a tailor-made protocol. The latter situation implies that the sequence of input- and output operations is defined by the programmer. A Unix Domain client socket can be defined using tt(FBB::LocalClientSocket). includefile(include/namespace) manpagesection(INHERITS FROM) bf(FBB::SocketBase) manpagesection(CONSTRUCTOR) itemization( itb(ClientSocket(std::string const &host, uint16_t port)) This constructor initializes an bf(FBB::ClientSocket) object, preparing it for a connection to the specified port at the given host. An bf(FBB::Exception) is thrown if the socket could not be constructed. The construction of the socket does not mean that a connection has actually been established. In order to connect to the server, the member bf(connect()) (see below) should be used. ) Copy and move constructors (and assignment operators) are not available. manpagesection(MEMBER FUNCTIONS) All members of bf(FBB::SocketBase) (and thus of bf(FBB::InetAddress)) are available, as bf(FBB::ClientSocket) inherits from these classes. itemization( itb(int connect()) This member returns a socket that can be used to communicate with the server process. An bf(FBB::Exception) exception is thrown if the connection could not be established or if the bf(SocketBase) base class could not properly be constructed. ) manpagesection(EXAMPLE) See also the bf(serversocket)(3bobcat) example. verb( #include #include #include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) try { if (argc == 1) { cerr << "Provide servername and port number\n"; return 1; } size_t port = stoul(argv[2]); ClientSocket client(argv[1], port); int fd = client.connect(); string line; cout << "Connecting to socket " << fd << endl << "address = " << client.dottedDecimalAddress() << ", " << endl << "communication through port " << client.port() << endl; IFdStream in(fd); // stream to read from OFdStream out(fd); // stream to write to while (true) { // Ask for a textline, stop if cout << "? "; // empty / none if (!getline(cin, line) || line.length() == 0) return 0; cout << "Line read: " << line << endl; // Return the line to the server out << line.c_str() << endl; cout << "wrote line\n"; getline(in, line); // Wait for a reply from the server cout << "Answer: " << line << endl; } } catch (Exception const &err) { cerr << err.what() << "\n" << "Can't connect to " << argv[1] << ", port " << argv[2] << endl; return 1; } ) manpagefiles() em(bobcat/clientsocket) - defines the class interface manpageseealso() bf(bobcat)(7), bf(ifdstream)(3bobcat), bf(ifdbuf)(3bobcat), bf(inetaddress)(3bobcat), bf(localclientsocket)(3bobcat), bf(ofdstream)(3bobcat), bf(ofdstream)(3bobcat), bf(serversocket)(3bobcat), bf(socketbase)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/tty.yo0000644000175000017500000000600714050437223016724 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Tty)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Controls echoing of characters) manpagename(FBB::Tty)(Controls echoing of characters entered at the terminal) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() bf(Tty)(3bobcat) objects can be used to control the echoing of characters entered at the terminal (usually at tt(/dev/tty)). Directly reading from tt(/dev/tty) allows programs to read information (e.g., passwords or pass phrases) even if the standard input stream is redirected to a file. Unless redirected, tt(std::cin) is connected to tt(/dev/tty). bf(Tty)(3bobcat) objects may be used as stand-alone objects or (usually anonymous) bf(Tty)(3bobcat) objects may be inserted into or extracted from streams. When inserting or extracting objects the involved streams are not affected; only the echoing of characters entered at tt(/dev/tty) is manipulated. bf(Tty)(3bobcat)'s destructor does not reset the echo-state of tt(/dev/tty) to its original value. If that is required a bf(Tty)(3bobcat) object must be created first, calling its bf(echo(Tty::RESET)) member at the appropriate time. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(ENUM) The tt(enum EchoType) requests the type of echo-handling: itemization( it() bf(RESET) is used to reset tt(/dev/tty)'s state to the actual state when a bf(Tty)(3bobcat) object was constructed it() bf(ON) is used to activate echoing of characters entered at tt(/dev/tty). it() bf(OFF) is used to suppress echoing of characters entered at tt(/dev/tty). ) manpagesection(CONSTRUCTORS) itemization( itb(Tty()) The current state of tt(/dev/tty) is saved. itb(Tty(EchoType type)) The current state of tt(/dev/tty) is saved, and the object's member tt(echo(type)) is called. ) Copy and move constructors (and assignment operators) are available. manpagesection(OVERLOADED OPERATORS) itemization( itb(std::istream &operator>>(std::istream &in, Tty const &tty)) The extraction operator does not affect tt(in), but tt(/dev/tty)'s state is set according to the way the tt(tty) object was constructed. itb(std::ostream &operator<<(std::ostream &out, Tty const &tty)) The insertion operator does not affect tt(out), but tt(/dev/tty)'s state is set according to the way the tt(tty) object was constructed. ) manpagesection(MEMBER FUNCTION) itemization( itb(echo(EchoType type)) tt(/Dev/tty)'s state is set according to the tt(EchoType) value that is passed to this member. ) manpagesection(EXAMPLE) verbinclude(../../tty/driver/driver.cc) manpagefiles() em(bobcat/tty) - defines the class interface manpageseealso() bf(bobcat)(7), bf(onekey)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/ptriter.yo0000644000175000017500000000652014050437223017575 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::PtrIter)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Error handler) manpagename(FBB::PtrIter)(Iterator returning pointer when dereferenced ) manpagesynopsis() bf(#include )nl() manpagedescription() The tt(PtrIter) class template implements an input iterator whose tt(operator*) returns the address of the element the iterator refers to. Consider a tt(std::unordered_map). Its tt(begin) member returns an iterator whose tt(operator*) returns a tt(std::pair (const) &). This is usually what you want, but now assume we want to display the map's content, sorted by its keys. Sorting can simply be performed by defining a support vector containing pointers to the elements in the map, and then sorting the strings the pointers point at. tt(PtrIter) is a tool that can be used to construct such a support vector, as shown in the bf(EXAMPLE) section. tt(PtrIter) is a class template requiring one template type parameter: tt(Iterator), the iterator's type (e.g., tt(vector::iterator)) tt(PtrIter)'s users don't have to specify tt(PtrIter)'s template type. The function template tt(ptrIter), when provided with an iterator returns the matching tt(PtrIter) object. includefile(include/namespace) manpagesection(INHERITS FROM) tt(std::iterator) manpagesection(FREE FUNCTION) itemization( itb(PtrIter ptrIter(Iterator const &iter)) this function template returns a tt(PtrIter) object for the function's tt(Iterator) argument. This function template simplyfies the construction of a tt(PtrIter) as no template parameters need to be specified (see also the bf(EXAMPLE) section) ) manpagesection(CONSTRUCTORS) itemization( itb(PtrIter(Iterator const &iter)) The tt(iter) parameter must be initialized with an existing input iterator, offering tt(operator*, operator++, operator==) and tt(operator!=). As tt(PtrIter) is a class template, its template type parameters must be specified when defining a tt(PtrIter) object. E.g., verb( PtrIter::iterator> PtrIter(mySet.begin()); ) ) Copy and move constructors (and assignment operators) are available. manpagesection(OVERLOADED OPERATORS) itemization( itb(PtrType operator*() const) the address of the entity the iterator refers to is returned; itb(PtrIter &operator++()) the iterator is (pre)incremented to the next position; itb(bool operator==(PtrIter const &other) const) tt(true) is returned if the two iterators are equal; itb(bool operator!=(PtrIter const &other) const) tt(true) is returned if the two iterators are unequal; ) manpagesection(DEFINED TYPE) tt(PtrIter) defines the following type: itemization( itb(typedef decltype(&*Iterator()) PtrType) ) manpagesection(MEMBER FUNCTIONS) All members of tt(std::iterator) are available, as bf(FBB::PtrIter) inherits from this class. manpagesection(EXAMPLE) verbinclude(../../ptriter/driver/driver.cc) manpagefiles() em(bobcat/ptriter) - defines the class interface manpageseealso() bf(bobcat)(7) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/mbuf.yo0000644000175000017500000001645314050437223017043 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Mbuf)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Message handler) manpagename(FBB::Mbuf)(std::streambuf handling messages) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() Objects of this class are derived from tt(std::streambuf), and are used to handle messages in a standardized way. Messages may be prefixed with order (line) numbers and/or labels. By default all messages are inserted into the standard output stream, but other destinations (standard error, a named file, etc.) can easily be configured. bf(FBB::Mbuf) objects themselves are tt(std::streambuf) objects, so they can be used to construct tt(std::ostream) objects. However, they are intended to be used by bf(mstream)(3bobcat) objects, and passing tt(Mbuf) objects to other kind of tt(ostream) objects is deprecated and results in undefined behavior. manpagesection(NAMESPACE) bf(FBB)nl() All elements mentioned in this man-page, are defined in the namespace bf(FBB). manpagesection(INHERITS FROM) bf(std::streambuf) manpagesection(CONSTRUCTORS) itemization( itb(Mbuf()) The default constructor handles messages using the tt(std::streambuf) also used by tt(std::cout). There is no limit to the number of messages that may be inserted. No message or line numbers are shown, no exception are thrown when inserting messages. itb(explicit Mbuf(std::streambuf *buf, size_t maxCount = std::numeric_limits::max(), std::string const &tag = "", bool throwing = false)) This constructor uses tt(buf) to handle messages. By default (using the default argument values) there is no limit to the number of messages that may be inserted. No message or line numbers are shown, no exception are thrown when inserting messages. Specifying any other value than tt(std::numeric_limits::max()) sets the maximum number of messages that can be inserted to that value. The tt(tag) defines the text of the message label (e.g., tt(Error)). When tt(throwing) is specified as tt(true) an tt(FBB::Exception) exception is thrown after completing a message. The generated exception holds the id (see below for the member tt(id)) of the bf(FBB::Mbuf) object from which the exception was thrown as well as the text tt(FBB::Mbuf). itb(explicit Mbuf(std::string const &name, size_t maxCount = std::numeric_limits::max(), std::string const &tag = "", bool throwing = false)) This constructor creates a tt(std::ofstream) from the provided tt(name) parameter that receives the messages handled by the constructed bf(FBB:Mbuf) object. It throws an tt(FBB::Exception) exception if the stream cannot be opened for writing. If a file by that name already exists it is rewritten. The remaining parameters are identical to those of the previous two constructors. ) Copy and move constructors (and assignment operators) are not available. manpagesection(MEMBER FUNCTIONS) itemization( itb(size_t count() const) returns the number of inserted messages (if tt(setCount) has been called: the value set by the last tt(setCount) call plus the number of inserted messages since that call). itb(bool lineExcess() const) returns bf(true) after attempting to insert an additional message after tt(maxCount()) number of messages have been inserted. itb(std::string const &lineTag() const) returns the currently used line-tag (by default `tt(Line)'). itb(size_t maxCount() const) returns the maximum number of messages that can be inserted. If the returned value equals tt(std::numeric_limits::max()) then there is no limit to the number of messages that can be inserted. itb(void noLineNr()) calling this member will suppress the display of a line number if it is called after calling tt(setLineNr) (see below) but before a message is being (or has been) inserted. itb(void reset(std::streambuf *buf, size_t maxCount, std::string const &tag, bool throwing)) messages inserted into bf(FBB::Mbuf) objects are handled by tt(std::streambuf buf). By specifying tt(std::numeric_limits::max()) for tt(maxCount) there is no limit to the number of messages that may be handled by this tt(std::streambuf). The tt(tag) defines the text of the message label (e.g., tt(Error) or the empty string for no message label). When tt(throwing) is specified as tt(true) an tt(FBB::Exception) exception is thrown after completing a message. itb(void reset(std::string const &name, size_t maxCount, std::string const &tag, bool throwing)) messages inserted into bf(FBB::Mbuf) objects are handled by a tt(std::ofstream) created using the provided tt(name) parameter. It throws an tt(FBB::Exception) exception if the stream cannot be opened for writing. If a file by that name already exists it is rewritten. The remaining parameters are identical to those of the previous tt(reset) members. itb(void reset(FBB::Mbuf const &mbuf)) the current object is reset using the parameters of the tt(mbuf) parameter. Following the reset all of the current object's parameters can independently be modified from those used by tt(mbuf). itb(void setCount(size_t count)) assigns the value tt(count) to the object's message counter. itb(void setLineNr(size_t lineNr)) specifies the value tt(lineNr) as the message's line number when the next line is displayed (see also tt(noLineNr)). This value is em(not) changed by the bf(FBB::Mbuf) object. To display another line number the member will have to be called again (i.e., the line number is not displayed automatically again at every new line). itb(void setLineTag(std::string const &tag)) specifies the tag prefixing line numbers. By default the line tag equals `tt(Line)'. itb(void setMaxCount(size_t maxCount)) defines tt(maxCount) as the maximum number of messages that can be inserted into the bf(FBB::Mbuf) object. itb(void setTag(std::string const &tag)) specifies the tag prefixing messages. By default the tag is empty. If not empty the tag is enclosed by square brackets. E.g., specifying the tag `tt(Error)' will prefix messages with tt([Error]). itb(std::string const &tag() const) returns the currently used message tag (by default an empty string). itb(bool throws()) returns tt(true) when the bf(FBB::Mbuf) object will throw an tt(FBB::Exception) exception at the next completed message. The generated exception holds the id (see earlier for the member tt(id)) of the bf(FBB::Mbuf) object from which the exception was thrown as well as the text tt(FBB::Mbuf). itb(void throwing(bool ifTrue)) modifies the behavior of bf(FBB::Mbuf) objects at completed messages. After passing tt(true) bf(FBB::Mbuf) objects will throw an tt(FBB::Exception) exception at the next completed message, otherwise this exception is not thrown. ) manpagesection(EXAMPLE) See the bf(mstream)(3bobcat) example. manpagefiles() em(bobcat/mbuf) - defines the class interface manpageseealso() bf(bobcat)(7), bf(exception)(3bobcat), bf(mstream)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/iquotedprintablebuf.yo0000644000175000017500000001152614050437223022156 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::IQuotedPrintableBuf)(3bobcat)(_CurYrs_) (libbobcat-dev__CurVers_) (QuotedPrintable converting Stream Buffer) manpagename(FBB::IQuotedPrintableBuf) (Input Filtering stream buffer doing quoted printable conversions) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() The information made available by bf(IQuotedPrintableBuf) objects is either quoted-printable encoded or decoded. The information to convert is read by bf(IQuotedPrintableBuf) objects via tt(std::istream) objects. The class bf(IQuotedPrintableBuf) is a class template, using a tt(FBB::CryptType) template non-type parameter. Objects of the class bf(FBB::IQuotedPrintableBuf) encode the information they receive, objects of the class bf(FBB::IQuotedPrintableBuf) decode the information they receive. See also section bf(ENUMERATION) below. Quoted-printable encoding is sometimes used in e-mail attachments (See also lurl(https://en.wikipedia.org/wiki/Quoted-printable) and lurl(https://www.ietf.org/rfc/rfc2045.txt) (section 6.7)). Its main characteristics are: itemization( it() Lines are at most 76 characters long; it() Lines longer than 76 characters are split into sub-lines, using tt(=\n) combinations to indicate `soft line breaks'. Lines not ending in soft line breaks indicate true end of lines. it() All printable characters, except for the tt(=) character and (final) blank characters just before the end of lines, are copied as-is, all other characters are escaped by writing tt(=XX) sequences, with XX being the ascii-character representation of the hexadecimal value of the escaped character (e.g., the tt(=) character is encoded as tt(=3D), a final space before end-of-line is encoded as tt(=20), a final tab as tt(=09)). Only capital letters are used when escaping characters. )nl() includefile(include/namespace) manpagesection(INHERITS FROM) bf(FBB::IFilterBuf) manpagesection(MEMBER FUNCTIONS) All members of bf(FBB::IFilterBuf) are available, as bf(IQuotedPrintableBuf) inherits from this class. Overloaded move and/or copy assignment operators are not available. manpagesection(ENUMERATION) bf(IQuotedPrintableBuf) objects either encode or decode quoted-printable information. bf(IQuotedPrintableBuf) objects of the class bf(FBB::IQuotedPrintableBuf) encode the data they receive, bf(IQuotedPrintableBuf) objects of the class bf(FBB::IQuotedPrintableBuf) decode the data they receive. The values tt(ENCODE) and tt(DECODE) are defined in the tt(enum CryptType), defined in the tt(FBB) namespace. manpagesection(CONSTRUCTOR) itemization( itb(IQuotedPrintableBuf(std::istream &in, size_t bufSize = 1000)) This constructor initializes the streambuf. - tt(IQuotedPrintableBuf) objects perform quoted-printable encoding;nl() - tt(IQuotedPrintableBuf) objects perform quoted-printable decoding;nl() - tt(IQuotedPrintableBuf) objects obtain the bytes to encode or decode from tt(std::istream &in);nl() - The tt(IFilterBuf) base class is initialized with a buffer of size tt(bufSize), using a lower bound of 100 characters. The constructor uses a configurable buffer size for reading. Characters read into the buffer which are not part of the actual quoted-printable encoded data are unavailable after completing the quoted-printable decoding. If information beyond the quoted-printable input block should remain available, then a buffer size of 1 should be specified. ) Copy and move constructors (and assignment operators) are not available. manpagesection(EXAMPLE) The example shows the construction of tt(IQuotedPrintableBuf) objects tt(encode) which are used to initialize a tt(std::istream) object. The information read from this tt(istream) is quoted-printable encoded. tt(IQuotedPrintableBuf) objects read quoted-printable encoded information from tt(std::istream) objects, decoding the information. The tt(std::istream din) object is initialized with the tt(IQuotedPrintableBuf) object, and its content is sent to tt(std::cout). The information that is presented at tt(std::cin) and that appears at tt(std::cout) should be identical. verbinclude(../../iquotedprintablebuf/driver/driver.cc) manpagefiles() em(bobcat/iquotedprintablebuf) - defines the class interface manpageseealso() bf(bobcat)(7), bf(isymcryptstreambuf)(3bobcat), bf(iquotedprintablestream)(3bobcat), bf(ifilterbuf)(3bobcat), bf(ofilterbuf)(3bobcat), bf(std::streambuf). manpagebugs() None reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/xpointer.yo0000644000175000017500000000462314050437223017756 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Xpointer)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Sets the X-pointer) manpagename(FBB::Xpointer)(Sets the location of the X-windows pointer) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat -lX11) manpagedescription() This class allows programs running within the X-graphical environment to set and retrieve the X-windows pointer location. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(CONSTRUCTORS) itemization( itb(Xpointer()) The default constructor. Connects to the Display. throws an bf(Exception) exception if the display cannot be opened. With multiple bf(Xpointer) objects, the connection to the display is opened only once. This constructor throws an tt(Exception) exception if it could not connect to the Display. ) Copy and move constructors (and assignment operators) are available. manpagesection(MEMBER FUNCTIONS) itemization( itb(bool get(int *x, int *y) const) Returns in its arguments the currnet pointer coordinates relative to the root-window. On success tt(true) is returned; tt(false) is returned if the pointer could not be moved. itb(bool set(int x, int y) const) Sets the pointer to a location whose pixel coordinates are given with respect to the root-window. A negative x-coordinate is measured from the right screen-margin of the root window (going left), a negative y-coordinate is measured from the bottom screen-margin of the root window (going up). On success tt(true) is returned; tt(false) is returned if the pointer could not be moved. ) manpagesection(EXAMPLE) verb( #include #include #include using namespace FBB; int main() try { Xpointer xpointer; xpointer.verify(); if (!xpointer.set(100, 200)) throw string("Set pointer failed"); int x; int y; if (!xpointer.get(&x, &y)) throw string("Get pointer failed"); cout << "Pointer now at " << x << ", " << y << '\n'; } catch (string msg) { cout << msg << '\n'; return 1; } ) manpagefiles() em(bobcat/xpointer) - defines the class interface manpageseealso() bf(bobcat)(7) manpagebugs() Note that tt(-lX11) must be specified as well. includefile(include/trailer) bobcat-5.09.01/documentation/man/ohexbuf.yo0000644000175000017500000001175514050437223017552 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::OHexBuf)(3bobcat)(_CurYrs_) (libbobcat-dev__CurVers_)(Write hex values) manpagename(FBB::OHexBuf)(Writes characters written to an ostream as hex values) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() bf(OHexBuf) is a specialization of tt(FBB::OFilterBuf) inserting all the characters it receives to a destination file as 2-character wide hexadecimal values. Optionally a maximum linelength can be specified. Note that all information received by an tt(OHexBuf) object is inserted as (a series of) hexadecimal values, not only plain characters. E.g., when inserting the value 123 the characters tt('1', '2') and tt('3') are successively inserted and so this will result in the string tt(313233) being inserted into the destination stream. includefile(include/namespace) manpagesection(INHERITS FROM) tt(FBB::OFilterBuf) manpagesection(CONSTRUCTOR) itemization( itb(OHexBuf(std::ostream &stream, size_t width = 0, std::string const &separator = "")) The hexadecimal characters produced by the tt(OFilterBuf) object are inserted into tt(stream). Optionally the maximum line width (in number of characters) may be specified using tt(width). The (default) value 0 indicates that no line breaks are requested. The parameter tt(separator) defines the separator that's inserted between hexadecimal character values. By default no separator is used. ) Copy and move constructors (and assignment operators) are not available. The destructor writes any buffered information to the destination stream and then flushes the destination stream. Finally, the destructor restores the original formatting flags of the receiving tt(ostream). manpagesection(MEMBER FUNCTIONS) All members of bf(FBB::OFilterBuf), in particular its tt(out()) and tt(reset) members are available, as bf(FBB::OHexBuf) inherits from this class. itemization( itb(void eoi()) This member completes the current hexadecimal character conversion, clears the separator, and no longer uses a the maximum output line width. Instead of calling this member the tt(eoi) manipulator (see below) can be used. itb(void separator(bool reset = true)) This member clears the separator that's inserted between hexadecimal character values. When the tt(reset) parameter is set to tt(true) (which is the default) the currently used output width is reset to 0. itb(void separator(std::string const &separator, bool reset = true)) This member resets the separator that's inserted between hexadecimal character values to tt(separator's) value. When the tt(reset) parameter is set to tt(true) (which is the default) the currently used output width is reset to 0. itb(void setWidth(size_t width)) This member sets the width of the generated output lines to tt(width) characters. No maximum line width is used when tt(width = 0) is specified. itb(size_t size() const) This member returns the next column offset where the next hexadecimal character will appear. If a maximum line length is requested and tt(size()) does not return 0 then the last line inserted was not terminated by a tt('\n') character. See also the example below. This member's return value is undefined if no maximum line length was requested. ) manpagesection(MANIPULATOR) itemization( itb(FBB::eoi) The tt(eoi) manipulator can be inserted into the tt(ostream) to complete the hexaecimal conversion. It acts identically to calling the tt(end) member. If inserted into a plain tt(std::ostream) nothing happens. ) manpagesection(STATIC MEMBER) itemization( itb(std::string text2bin(std::string const &in)) This static member converts a series of hexadecimal characters generated by a tt(OHexBuf) object back to their binary form. E.g, when called as tt(OHexBuf::text2bin("736d616c6c206976")) then the returned tt(std::string) will contain 8 characters, having respectively the binary values 0x73, 0x6d, 0x61, 0x6c, 0x6c, 0x20, 0x69, and 0x76. This function does em(not) verify whether its argument is properly formed. A properly formed argument consists of an even number of hexadecimal number characters ('0' until '9', 'a' until 'f' (or uppercase)). For improperly formed arguments the return value is undefined. ) manpagesection(EXAMPLE) verb( #include #include using namespace std; using namespace FBB; int main() { OHexBuf ohex(cout, 40); ostream out(&ohex); out << cin.rdbuf(); if (ohex.size()) cout << '\n'; } ) manpagefiles() em(bobcat/ohexbuf) - defines the class interface manpageseealso() bf(bobcat)(7), bf(ofilterbuf)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/user.yo0000644000175000017500000000576214050437223017071 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::User)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (/etc/passwd user info) manpagename(FBB::User)(Provides the tt(/etc/passwd) info of the current user) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() This class retrieves the information of the current user from the information in tt(/etc/passwd). The class is a simple wrapper class around the bf(getpwent)(3) function. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(CONSTRUCTORS) itemization( itb(User()) The default constructor determines the current user's data. This constructor throws an tt(Exception) exception if it did not properly complete because the current user name could not be found in tt(/etc/passwd). itb(User(size_t uid)) The data of the user whose user-id is tt(uid) are determined. If the data could not be found an tt(Exception) is thrown. itb(User(std::string const &name)) The data of the user whose user-name is tt(name) are determined. If the data could not be found an tt(Exception) is thrown. ) Copy and move constructors (and assignment operators) are available. manpagesection(MEMBER FUNCTIONS) itemization( itb(size_t eGroupid() const) Returns the user's tt(effective) group-id. itb(size_t eUserid() const) Returns the user's tt(effective) user-id. itb(size_t groupid() const) Returns the user's group-id. itb(std::string homedir() const) Returns the user's home directory (including a trailing tt(/)). itb(bool inGroup(size_t gid, bool useEffective = true) const) Returns tt(true) if the current user is a member of group tt(gid), otherwise tt(false) is returned. The user's effective group id is also checked if tt(useEffective) is specified as tt(true) (which is provided as default function argument). itb(std::string name() const) Returns the user's user-name. itb(std::string password() const) Returns the user's encrypted password. But see also the bf(BUGS) \ section. itb(std::string realname() const) Returns the user's real name, as listed in the tt(/etc/passwd)'s \ em(gecos) field. itb(std::string shell() const) Returns the user's shell. itb(size_t userid() const) Returns the user's user-id. ) manpagesection(EXAMPLE) verbinclude(../../user/driver/driver.cc) manpagefiles() em(bobcat/user) - defines the class interface manpageseealso() bf(bobcat)(7), bf(getpwent)(3) manpagebugs() If the user is a member of multiple groups, only the group id listed in tt(/etc/passwd) is returned by bf(groupid()). If shadow passwording is used, the string returned by bf(password()) will probably not contain the encrypted password. includefile(include/trailer) bobcat-5.09.01/documentation/man/ofoldstream.yo0000644000175000017500000001512214050437223020421 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::OFoldStream)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Fold long lines) manpagename(FBB::OFoldStream)(Folds long lines) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() bf(FBB::OFoldStream) folds long lines written to it. The tt(OFoldStream) writes the (folded) lines to a second tt(ostream) which is either used by or opened by the tt(OFoldStream) object. tt(OFoldStream) objects never fold lines in the middle of series of non-blank characters but will always break a line at white space characters. The resulting lines will always appear to the right of a configurable left margin and to the left of a configurable right margin. There is a somewhat pathological exception to this: if a word is too long to fit in between the margins then the word will exceed the right hand margin. The indentation used for the left margins is configurable to either blanks (the default) or tabs. When tabs are used the width of a tab character is configurable, using a default of 8 positions in the destination stream. tt(OFoldStream) is implemented as a wrapper class around tt(std::ostream) and tt(FBB::OFoldBuf) and a more complete description of the folding process can be found in the bf(ofoldbuf)(3bobcat) man page. includefile(include/namespace) manpagesection(INHERITS FROM) std::ostream,nl() (and privately from FBB::OFoldBuf) manpagesection(ENUMERATION) The enumeration tt(TabsOrBlanks) is used to select tabs or blanks when writing the indentation. The default is blanks. When tabs are selected the display width of tabs characters can be configured as well (using the default of 8 positions for each tab-character). The enumeration has two values: itemization( itb(BLANKS) The default, indicating that the left margin is specified and written as a number of blanks; itb(TABS) Indicating that the left margin is specified and written as a number of tab-characters. ) The enumeration tt(TrailingBlanks) is used to configure the tt(OFoldStream) object with respect to any trailing blanks that may appear on the final line. It is the same enumeration type as used with tt(OFoldBuf) (cf. bf(ofoldbuf)(3bobcat)) having two values: itemization( itb(IGNORE_TRAILING_BLANKS) This indicates that trailing blanks appearing at the final line if it is not terminated by a newline should not be written to the destination tt(std::ostream). This is the default used by tt(OFoldStream) objects. itb(KEEP_TRAILING_BLANKS) This indicates that trailing blanks at the final line if it is not terminated by a newline should be written to the destination tt(std::ostream) ) manpagesection(CONSTRUCTORS) itemization( itb(OFoldStream()) This constructor initializes an tt(OFoldStream) object but does not associate it with a destination stream. It uses the values 0, 80, tt(BLANKS), and tt(IGNORE_TRAILING_BLANKS)for, resp. its left margin, right margin left-margin characters and tt(TrailingBlanks) handling mode. itb(OFoldStream(char const *fname, size_t leftIndent = 0, size_t rightMargin = 80, TabsOrBlanks tob = BLANKS, TrailingBlanks tb = IGNORE_TRAILING_BLANKS)) This constructor initializes an tt(OFoldStream) object and opens (using tt(std::ios::out)) the destination stream using the name specified as its tt(fname) argument. itb(OFoldStream(std::ostream &stream, size_t leftIndent = 0, size_t rightMargin = 80, TabsOrBlanks tob = BLANKS, TrailingBlanks tb = IGNORE_TRAILING_BLANKS)) This constructor initializes an tt(OFoldStream) object and uses as its destination stream the tt(std::ostream stream). ) The destructor writes any buffered information to the destination stream and will then flush the destination stream. Copy and move constructors (and assignment operators) are not available. manpagesection(MEMBER FUNCTIONS) All members of bf(std::ostream) are available, as bf(FBB::OFoldStream) inherits from this class. itemization( itb(void close()) This member flushes any pending information to the destination stream and then closes the destination stream. itb(void open(char const *fname, openmode mode = std::ios::out)) This member associates the tt(OFilterStream) object with an tt(std::ofstream) object whose filename is provided and that should receive the folded information. itb(void open(std::ostream &out)) This member associates the tt(OFilterStream) object with the provided tt(ostream) object. itb(void setMargins(size_t leftMargin, size_t rightMargin)) This member can be used to modify the left- and right folding margins. Note that the left margin may also be modified using the tt(FBB::lm) and tt(FBB::mlm) manipulators. itb(void setTrailingBlanks(TrailingBlanks tb)) This member can be used to modify the currently used tt(TrailingBlanks) parameter. itb(void useBlanks()) This member can be used to select blanks to be used when inserting left margins. itb(void useTabs(size_t tabWidth = 8)) This member can be used to select tab-characters to be used when inserting left margins. The second parameter is used to specify the display width of a tab-character. ) manpagesection(STATIC MEMBER FUNCTIONS) itemization( itb(size_t leftMargin(std::ostream const &os)) This member returns the current left margin setting of the tt(OFoldStream) object passed to it as its argument. The member defines a tt(std::ostream) parameter since in many cases the tt(OFoldStream) object will be used in functions themselves defining tt(std::ostream) parameters. Internally, the tt(std::ostream)'s tt(std::streambuf) is down cast to an tt(OFoldBuf) and an tt(FBB::Exception) exception is thrown if that cast fails. itb(size_t rightMargin(std::ostream const &os)) This member returns the current right margin setting of the tt(OFoldStream) object passed to it as its argument. The member's parameter is down cast in the same way as tt(leftMargin())'s argument: an tt(FBB::Exception) exception is thrown if that cast fails. ) manpagesection(EXAMPLE) verbinclude(../../ofoldstream/driver/driver.cc) manpagefiles() em(bobcat/ofoldstream) - defines the class interface manpageseealso() bf(bobcat)(7), bf(lm)(3bobcat), bf(mlm)(3bobcat), bf(ofoldbuf)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/sharedreadme.yo0000644000175000017500000001603614050437223020533 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(SharedREADME)(7bobcat)(_CurYrs_) (libbobcat-dev__CurVers_) (Bobcat Shared Memory README) manpagename(SharedREADME)(Description of Bobcat's shared memory classes) manpagedescription() itemization( it() bf(SharedLock)(3bobcat) The class bf(SharedLock)(3bobcat) is a wrapper around a tt(pthread_mutex). bf(SharedLock) has member functions tt(lock) and tt(unlock), with tt(lock) throwing an exception when it fails to obtain the lock (i.e., calling tt(pthread_mutex's lock) member fails, otherwise it waits until tt(pthread_mutex's lock) succeeds). bf(SharedLock) is a convenience class for other shared memory classes. By itself bf(SharedLock) is unrelated to shared memory. it() bf(SharedBlock)(3bobcat) The class bf(SharedBlock)(3bobcat) defines a small object consisting of a bf(SharedMutex) and a (shared segment) id. If offers functionality to set and retrieve the id, and to lock and unlock the bf(SharedMutex). bf(SharedBlock) objects are used by bf(SharedSegment)(3bobcat) objects to keep track of which segments actually contain the shared memory data. It's a bookkeeping helper class. it() bf(SharedSegment)(3bobcat) The class bf(SharedSegment) (cf. figure tt(images/sharedsegment1.jpg)) interfaces to actual shared memory. Its main member function is the static member tt(create), returning a pointer to a newly allocated tt(SharedMemory) object. The member tt(create) receives as its input parameters the number of blocks, the size of the segments allocated by bf(SharedSegment), and the segment's access mode (as used by, e.g., bf(chmod)(1)). It returns a pointer to the allocated tt(SharedSegment), and its ID (set using a pointer to an tt(int), passed as its first parameter). Although the bf(SharedSegment) class defines an array of a single bf(SharedBlock)(3bobcat) object, in fact it will contain tt(d_nBlocks) bf(SharedBlock) objects. The member tt(create) first allocates a block of raw memory of the required total size. Next it initializes the first part of this raw, shared memory, using the tt(SharedSegment) constructor and placement new. Next, the remaining amount of raw shared memory is initialized with tt(d_nBlocks - 1) bf(SharedBlock) objects, again using placement new (cf. figure tt(images/sharedsegment2.jpg)). it() bf(SharedPos)(3bobcat) The class bf(SharedPos)(3bobcat) monitors position information in the shared memory segments managed by bf(SharedSegment) objects. bf(SharedPos) only has a default constructor, but offers a bf(reset) member receiving at construction time a pointer to a bf(SharedSegment) object. it() bf(SharedMemory)(3bobcat) The class bf(SharedMemory)(3bobcat) offers the standard interface to shared memory, defining members like tt(read, get, write) and tt(put). It interfaces to a tt(SharedSegment) object, and uses a tt(SharedPos) object to keep track of the tt(SharedMemory's) offsets. A bf(SharedMemory) object itself resides in a program's working memory, and not in the computer's shared memory area. At any time the bf(SharedMemory) object only loads at most one actual block of the shared memory block managed by bf(SharedSegment). The current position in the shared memory managed by bf(SharedSegment) is monitored by the bf(SharedMemory)'s tt(SharedBlock d_pos) member. Following read/write operations the offset is updated accordingly. There's only one offset, which is used by tt([IO]?SharedStream) objects when requesting or updating offsets. a bf(SharedMemory) object offers safeguards against inappropriate use. E.g., if no memory has been allocated yet it may thow exceptions. Also, offsets can never exceed the tt(SharedMemory's) maximum possible offset. it() bf(SharedMutex)(3bobcat) The class bf(SharedMutex) implements a non-recursive mutex that can be stored in shared memory. It merely offers tt(lock) and tt(unlock) members. Within one thread tt(lcok) should never be called repeatedly unless tt(unlock) is called first. The tt(unlock) member may safely repeatedly be called; once the mutex has been unlocked, repeated requests to unlock the mutex are simply ignored. When a bf(SharedMutex) is destroyed it calls tt(unlock). Use tt(SharedMemory's install) member to define a bf(SharedMutex) object in shared memory, and use tt(ptr->~SharedMutex()) (with tt(SharedMutex *ptr) pointing at the tt(SharedMutex) object) to destroy it again. it() bf(SharedCondition)(3bobcat) The class bf(SharedCondition) implements a condition variable and an associated mutex, both created in shared memory controlled by a bf(SharedMemory) object. It offers all the functionality of tt(std::condition_variable). A bf(SharedCondition) object itself is defined in a thread's working memory, but interfaces to a tt(`Condition') object containing a condition variable and a mutex which are installed in shared memory. The size of this tt(`Condition') object is returned by the static member tt(SharedCondition::size). bf(SharedCondition) members ensure that the thread has access to the tt(`Condition') object, and that the shared memory's offset has not changed when returning from the bf(SharedCondition's) members. it() bf(SharedBuf)(3bobcat) The class bf(SharedBuf) implements a tt(std::streambuf) specialization interfacing to a tt(SharedMemory) object. In addition to a default constructor which is an empty stub the class offers constructors which immediately interface to a tt(SharedMemory) object, as well as a member to (re)associate a bf(SharedBuf) object with a tt(SharedMemory) object. it() bf(SharedStream, ISharedStream, OSharedStream)(3bobcat) These stream classes offer stream-facilities operating on shared memory maintained by a tt(SharedMemory) object. The bf(SharedStream) class uses the tt(SharedMemory's seek) member for both tt(seekp) and tt(seekg), and uses tt(SharedMemory's offset) member for both tt(tellp) and tt(tellg). All shared stream objects, including bf(ISharedStream), offer a member to initialize a tt(SharedCondition) ) An overview of currently defined shared memory segments is shown by the command tt(ipcs -ma). To remove a defined shared memory segment the command tt(ipcrm -m ) can be used, where tt() is the shared memory segment's ID. manpagesection(EXAMPLE) See the bf(sharedstream)(3bobcat) man page. manpagesection(FILES) Images referred to in this man-page are located in the source distribution in tt(bobcat/documents/images), or they can be found in the standard location of documentation files in your distribution (e.g., they are located in tt(/usr/share/doc/libbobcat5/images)). manpageseealso() bf(bobcat)(7), bf(ipcs)(1), bf(ipcrm)(1), bf(isharedstream)(3bobcat), bf(osharedstream)(3bobcat), bf(sharedblock)(3bobcat), bf(sharedcondition)(3bobcat), bf(sharedmemory)(3bobcat), bf(sharedmutex)(3bobcat), bf(sharedpos)(3bobcat), bf(sharedsegment)(3bobcat), bf(sharedstream)(3bobcat), bf(sharedbuf)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/hostent.yo0000644000175000017500000001067414050437223017575 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Hostent)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (struct hostent wrapper) manpagename(FBB::Hostent)(Wrapper around a bf(struct hostent)) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() bf(@CLASS) objects are wrappers around bf(hostent) structs which may be used by other objects. A bf(struct hostent) is defined as follows: verb( struct hostent { char *h_name; // official name of host char **h_aliases; // alias list int h_addrtype; // host address type (always AF_INET) int h_length; // length of address char **h_addr_list; // list of addresses } ) The tt(address) fields are binary values of the addresses, each address requiring tt(h_length) bytes, the last address being equal to 0. The bf(@CLASS) objects offer a bf(C++)-like interface to this struct. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(CONSTRUCTORS) itemization( itb(Hostent(hostent const *hostentPtr)) This constructor initializes an bf(@CLASS) object from an existing bf(hostent) struct. Functions like bf(gethostbyname)(3) and bf(gethostbyaddress)(3) return pointers to bf(hostent) structs. ) The default, copy and move constructors (and the copy and move assignment operators) are available. manpagesection(MEMBER FUNCTIONS) itemization( itb(size_t addressLength() const) This member returns the length of the binary addresses in bytes. itb(size_t addressType() const) This member returns the type of the address. Currently this is always bf(AF_INET). itb(char const *alias(size_t index) const) This member returns alias `tt(index)' of the host. The first alias has tt(index 0). If alias `tt(index)' does not exist, 0 is returned. itb(char const * const *beginAlias() const) This member returns an iterator to the first alias. The hostname itself is not included in the list of aliases. itb(char const *binaryAddress(size_t index) const) This member returns the binary address `tt(index)' of the host. The first address has tt(index 0). If address `tt(index)' does not exist, 0 is returned. The pointer to the binary address points to a series of bf(addressLength()) bytes. Note that the returned address is in em(network byte order). It can be converted to host byte order by the functions described in bf(byteorder)(3). itb(std::string dottedDecimalAddress(size_t index) const) This member returns address `tt(index)' as a dotted decimal address in a string. The first address has tt(index 0). If address `tt(index)' does not exist, an empty string is returned. itb(char const * const *endAlias() const) This member returns an iterator pointing beyond the last alias. itb(char const *hostname() const) This member returns the standard (first) name of the host. itb(size_t nAddresses() const) This member returns the number of addresses that are available. When requesting a particular address, the requested index should be less than the value returned by this member. itb(size_t nAliases() const) This member returns the number of aliases that are available. When requesting a particular alias, the requested index should be less than the value returned by this member. itb(void swap(Hostent &other)) The current tt(Hostent) object's content are swapped with the other object's content. ) manpagesection(EXAMPLE) verb( #include #include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) { Hostent he(gethostbyname("localhost")); cout << "The local hostname = " << he.hostname() << endl; cout << "All aliases: " << endl; copy(he.beginAlias(), he.endAlias(), ostream_iterator(cout, "\n")); cout << "Addresses:\n"; for (size_t idx = 0; idx < he.nAddresses(); idx++) cout << he.dottedDecimalAddress(idx) << endl; } ) manpagefiles() em(bobcat/hostent) - defines the class interface manpageseealso() bf(bobcat)(7) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/diffiehellman.yo0000644000175000017500000002331614050437223020675 0ustar frankfrankincludefile(include/header) COMMENT(replace 'classname' by the name of the new class) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::DiffieHellman)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Diffie Hellman key computations) manpagename(FBB::DiffieHellman)(Diffie-Hellman PKI, computing shared keys) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat -lcrypto) manpagedescription() The class bf(FBB::DiffieHellman) computes shared keys (shared secrets) using the Diffie-Hellman (1976) algorithm. The Diffie-Hellman algorithm uses public and private information. The public information consists of a em(prime) (e.g., a prime number consisting of 1024 bits), a em(generator) (for which the value 5 is commonly used), and (using tt(**) to represent the power operator on integral values) the value tt(generator ** private mod prime), where tt(private) is a randomly selected large number, which is the private information. The Diffie-Hellman algorithm is commonly used to compute a shared key which can be used to encrypt information sent between two parties. One party, which in this man-page is called the em(initiator) computes the prime and defines the generator. The prime is computed by bf(FBB::DiffieHellman)'s first constructor, while the generator is passed to this constructor as one of its arguments. For the generator the value 5 is often used. Next the initiator passes its public information, consisting of the prime, the generator, and the value tt(generator ** private) mod prime) to the other party, which in this man-page is called the tt(peer). The public information is written in binairy, big-endian form to file using the member tt(save). The initiator may optionally save the private information to a separate file as well. The peer thereupon receives the initiator's public information. The initialor's public information is read by a bf(FBB::DiffieHellman) constructor either expecting the name of a file or a tt(std::istream) containining the initiator's public information. Having obtained the prime and generator, the peer's public (and, optionally, private information) is saved by also calling tt(save). This results, among other things, in the value tt(generator ** private mod prime), but now using the peer's private information. At this point the peer is already able to compute the shared key. The key is returned by calling the tt(key) member, which returns the shared key as a series of bytes stored in a tt(std::string). Before the initiator can compute the shared key the peer's tt(generator ** private mod prime) value must be available. The peer sends the saved public data to the initiator. The initiator then passes the peer's public data either by file name or by tt(std::istream) to the tt(key) member, returning the shared key. bf(Perfect Forward Secrecy and Ephemeral Diffie Hellman) If the initiator and peer decide not to save their private information em(Perfect Forward Secrecy) and em(Ephemeral Diffie Hellman) may be obtained. Here, the procedure is applied as follows: itemization( it() Initiator and peer have agreed upon and securely exchanged a long-lasting common secret, which may be used in combination with, e.g., symmetric encryption methods. it() Applying the abovementioned procedure, the private information is never saved on file. Consequently, the shared key, once computed, cannot be reconstructed anymore. it() The value tt(generator ** private mod prime) is not sent to either peer or initiator `in the clear', but encrypted using the long-lasting common secret. As the current implementation saves all public information on file, it's probably easiest to encrypt the file containing the public information. it() The recipients, having received the other party's encrypted public information, decrypt it using the long-lasting shared secret and compute the the shared key. it() As the secret information is not kept, the shared key cannot be reconstructed, while a Man-In-The-Middle attack is prevented by only exchanging encrypted public information. it() The shared key can now be used to encrypt a communication session ) includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(PUBLIC ENUMERATION) The enumeration tt(FBB::DiffieHellman::SecretKey) has two values: itemization( it() tt(DONT_SAVE_SECRET_KEY), indicating that the secret information should not be saved on file; it() tt(SAVE_SECRET_KEY), indicating that the secret information should be saved on file; ) manpagesection(CONSTRUCTORS) itemization( itb(DiffieHellman(size_t primeLength = 1024, size_t generator = 5, bool progress = false)) This constructor computes a prime of the specified length, and initializes the public information with the indicated generator. If tt(progress) is tt(true), the progress of the prime construction process is shown to tt(std::cout) by a series of dots, minuses and plusses. Generating a suitable prime may fail, resulting in an tt(FBB::Exception) being thrown. Unless the generator is specified as 2 or 5 the warning tt(cannot check the validity of generator ...) is inserted into the bf(mstream)(3bobcat)'s tt(wmsg) object. A warning is also inserted if the provided generator is not a generator for the computed prime. This constructor should be called by the initiator to start the Diffie-Hellman shared key computation procedure. itb(DiffieHellman(std::string const &initiatorPublicFileName)) This constructor should be called by the peer, after having received the initiator's public info. It makes the initiator's public information available to the peer, after which the peer's public and private information can be computed. itb(DiffieHellman(std::stream &initiatorPublicStream)) This constructor acts like the previous constructor, expecting a tt(std::istream) rather than a file name. It should be called by the peer, after having received the initiator's public info. It makes the initiator's public information available to the peer, after which the peer's public and private information can be computed. itb(DiffieHellman(std::string const &initiatorPublicFileName, std::string const &initiatorPrivateFileName)) Unless the initiator's tt(DiffieHellman) object is still available, this constructor should again be called by the initiator, to load the initiator's public and private data. itb(DiffieHellman(std::stream &initiatorPublicStream, std::stream &initiatorPrivateStream)) This constructor acts like the previous constructor, expecting tt(std::istreams) rather than file names. It should be called by the initiator, to load the initiator's public and private info. ) Copy and move constructors (and assignment operators) are available. manpagesection(MEMBER FUNCTIONS) itemization( itb(std::string key() const) This member should be called by the peer. It returns the shared key. If the key cannot be computed, or if the key is not resistant to the small group attack (i.e., if the key equals 1, or is at least equal to the public prime value, or if tt(key ** ((prime - 1) / 2) mod prime != 1)), then an tt(FBB::Exception) is thrown. itb(std::string key(std::string const &peerPublicFileName) const) This member should be called by the initiator. It skips the data referring to the prime and generator found in tt(peerPublicFileName) and then reads the peer's tt(generator ** private mod prime) value. If this value cannot be read or if the key is not resistant to the small group attack (cf. the description of the previous tt(key) member) then an tt(FBB::Exception) is thrown. It returns the shared key. itb(std::string key(std::istream const &peerPublicStream) const) This member should be called by the initiator. It acts like the previous tt(key) member, reading the peer's tt(generator ** private mod prime) value from tt(peerPublicStream). It returns the shared key. itb(void save(std::string const &basename, SecretKey action = DONT_SAVE_SECRET_KEY)) This member should be called by the initiator. It saves the public information on the file tt('basename'.pub). The information is written in binary, big-endian format, using the following organization: - the size of the prime in bytes;nl() - the prime's bytes;nl() - the size of the generator in bytes;nl() - the generator's bytes;nl() - the size of the public info (tt(generator ** private mod prime)) in bytes;nl() - the public info's bytes.nl() If tt(action) is specified as tt(SAVE_SECRET_KEY) then the private information is written in binary, big-endian format, using the following organization: - the size of the private information in bytes;nl() - the private information bytes. ) manpagesection(EXAMPLE) When called without arguments, the example program generates Diffie-Hellman parameters writing the initiator's public and private information to, respectively, tt(init.pub) and tt(init.sec). When called with one argument, tt(init.pub) is read, and the peer's public and private information is written to, respectively, tt(peer.pub) and tt(peer.sec). Next, the (peer's) shared key is written to tt(peerkey). When called with two arguments, tt(init.pub) and tt(init.sec) are read, as well as the peer's public information (on the file tt(peer.pub)). Next, the (initiator's) shared key is written to tt(initkey). The files tt(peerkey) and tt(initkey) should be identical. verbinclude(../../diffiehellman/driver/driver.cc) manpagefiles() em(bobcat/diffiehellman) - defines the class interface manpageseealso() bf(bobcat)(7), bf(bigint)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/glob.yo0000644000175000017500000001334614050437223017033 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Glob)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Files matching a pattern) manpagename(FBB::Glob) (Wrapper around bf(glob)(3) to find files matching a pattern) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() The bf(FBB::Glob) class is a wrapper around the bf(C) function bf(glob)(3). It returns a list of files matching a certain pattern provided to bf(FBB::Glob)'s constructors or members. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(ENUMERATIONS) bf(Glob::Type): nl() This enumeration, which is identical to the bf(stat)(3bobcat) tt(Type) enumeration, defines the following values: includefile(gs.inc) These values are also used by bf(stat)(2) and bf(lstat)(2). Although they can be combined using the tt(bitor) operator, they are not uniquely recognizable when combined. E.g., the value of tt(CHARACTER_DEVICE | DIRECTORY) is equal to the value of tt(BLOCK_DEVICE). It's also possible to combine tt(Type) values in a tt(std::unordered_set), which avoids the confusion that may result from using the tt(bitor) operator. bf(Glob::Flags): itemization( itt(NO_FLAG): Equals 0, and can be used to avoid having to specify 0. It has no further use. itt(ERR): Return on read errors; itt(MARK): Append a slash to each name. itt(NOSORT): Don't sort the names. itt(NOESCAPE): Backslashes don't quote metacharacters. itt(PERIOD): Leading tt(.)-characters can be matched by metachars (i.e., tt(*) and tt(?)). itt(NOMATCH): When specified the constructors won't throw exceptions when no files matching their glob-patterns could be found. Instead they will return normally, and tt(Glob's size()) member (see below) will return 0. ) bf(Glob::Dots): itemization( itt(FIRST): Filenames starting with a dot will be listed first. Within this set and in the leftover-set the relative ordering is maintained. itt(DEFAULT): Return filenames as they appear in the globbing process. ) manpagesection(CONSTRUCTORS) itemization( itb(Glob(std::string const &pattern = "*", int flags = PERIOD, Dots dots = FIRST)) This constructor (which can also be used as the default constructor) determines all elements matching tt(pattern). An tt(Exception) exception is thrown if the constructor could not properly complete it tasks. Multiple flags may be specified, separated by the tt(bitor) operator. This constructor properly completes its task if only defined bf(Flag) values were specified and if the bf(glob)(3) function returned without errors; itb(Glob(Type type, std::string const &pattern = "*", int flags = PERIOD, Dots dots = FIRST)) This constructor determines all elements of tt(pattern) when their types `tt(elementType)' are equal to the value of tt(elementType & type). The specified tt(type) value may consist of any tt(bitor)-ed combination of enum values defined by the tt(Type) enum. Note that this may produce confusing results. E.g., when specifying tt(DIRECTORY), elements that are tt(BLOCK_DEVICEs) or tt(SOCKETs) are also accepted. The next constructor can be used to avoid this confusion; itb(Glob(std::unordered_set const &typeSet, std::string const &pattern = "*", int flags = PERIOD, Dots dots = FIRST)) This constructor determines all elements of tt(pattern) when their types are found in tt(typeSet). Different from the previous constructor, for an element to be accepted its type must exactly match a type value in the tt(typeSet) set. ) Copy and move constructors (and assignment operators) are available. manpagesection(OVERLOADED OPERATORS) itemization( itb(char const *operator[](size_t idx) const) The element at index position tt(idx) is returns as a bf(C) string. It returns an empty string if tt(idx) is or exceeds bf(size()). ) manpagesection(MEMBER FUNCTIONS) itemization( itb(size_t size() const) Returns the number of elements that were detected; itb(char const *const *begin() const) Returns a pointer to the first element that was detected. This pointer can be used in generic algorithms as an output-iterator supporting pointer arithmetic; itb(char const *const *end() const) Returns a pointer beyond the last element that was detected. This pointer can be used in generic algorithms as an output-iterator supporting pointer arithmetic; itb(void swap(Glob &other)) Swaps the content of the other object with the current object. ) manpagesection(EXAMPLES) verb( int main(int argc, char **argv) { if (argc == 1) { cout << "Provide glob-expression as 1st arg\n"; return 1; } cout << "General:\n"; Glob general; for (size_t idx = 0; idx < general.size(); idx++) cout << idx << ": " << general[idx] << endl; cout << "Pattern: " << argv[1] << "\n"; Glob pattern(argv[1], Glob::PERIOD, Glob::DEFAULT); for (size_t idx = 0; idx < pattern.size(); idx++) cout << idx << ": " << pattern[idx] << endl; } ) manpagefiles() em(bobcat/glob) - defines the class interface manpageseealso() bf(bobcat)(7), bf(stat)(3bobcat), bf(glob)(3) manpagebugs() No Reported Bugs. includefile(include/trailer) bobcat-5.09.01/documentation/man/pattern.yo0000644000175000017500000002461014050437223017561 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Pattern)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Pattern matcher) manpagename(FBB::Pattern)(Performs RE pattern matching) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() bf(Pattern) objects may be used for Regular Expression (RE) pattern matching. The class is a wrapper around the bf(regcomp)(3) family of functions. By default it uses `extended regular expressions', requiring you to escape multipliers and bounding-characters when they should be interpreted as ordinary characters (i.e., tt(*, +, ?, ^, $, |, (, ), [, ], {, }) should be escaped when used as literal characters). The bf(Pattern) class supports the use of the following (Perl-like) special escape sequences: nl() \b - indicating a word-boundary nl() \d - indicating a digit (tt([[:digit:]])) character nl() \s - indicating a white-space (tt([:space:])) character nl() \w - indicating a word (tt([:alnum:])) character The corresponding capitals (e.g., bf(\W)) define the complementary character sets. The capitalized character set shorthands are not expanded inside explicit character-classes (i.e., tt([ ... ]) constructions). So tt([\W]) represents a set of two characters: tt(\) and tt(W). As the backslash (tt(\)) is treated as a special character it should be handled carefully. bf(Pattern) converts the escape sequences tt(\d \s \w) (and outside of explicit character classes the sequences tt(\D \S \W)) to their respective character classes. All other escape sequences are kept as-is, and the resulting regular expression is offered to the pattern matching compilation function bf(regcomp)(3). This function interprets escape sequences. Consequently some care should be exercised when defining patterns containing escape sequences. Here are the rules: itemization( it() Special escape sequences (like tt(\d)) are converted to character classes. E.g., verb( --------------------------------------------------------- Specify: Converts to: regcomp uses: Matches: --------------------------------------------------------- \d [[:digit:]] [[:digit:]] 3 --------------------------------------------------------- ) it() Ordinary escape sequences (like tt(\x)) are kept as-is. E.g., verb( --------------------------------------------------------- Specify: Converts to: regcomp uses: Matches: --------------------------------------------------------- \x \x x x --------------------------------------------------------- ) it() To specify literal escape sequences, Raw String Literals are advised, as they don't require doubling escape sequences. E.g., the following regular expression matches an (alpha-numeric) word, followed by optional blanks, a colon, more optional blanks and a (decimal) number: verb( R"((\w+)\s*:\s*\d+)" ) ) includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(TYPEDEF) itemization( itb(Pattern::Position) A nested type representing the offsets of the first character and the offset beyond the last character of the matched text or indexed subexpression, defined as tt(std::pair). ) manpagesection(CONSTRUCTORS) itemization( itb(Pattern()) The default constructor defines no pattern, but is available as a placeholder for, e.g., containers requiring default constructors. A bf(Pattern) object thus constructed cannot be used to match patterns, but can be the em(lvalue) in assignments where another bf(Pattern) object is the em(rvalue). However, it can receive a pattern using the member bf(setPattern()) (see below). An bf(FBB::Exception) object is thrown if the object could not be constructed. itb(Pattern(std::string const &pattern, bool caseSensitive = true, size_t nSub = 10, int options = REG_EXTENDED | REG_NEWLINE)) This constructor compiles tt(pattern), preparing the bf(Pattern) object for pattern matches. The second parameter determines whether case sensitive matching will be used (the default) or not. Subexpressions are defined by parentheses pairs. Each matching pair defines a subexpression, where the order-number of their opening parentheses determines the subexpression's index. By default at most 10 subexpressions are recognized. The em(options) flags may be: REG_EXTENDED: nl() Use POSIX Extended Regular Expression syntax when interpreting regex. If not set, POSIX Basic Regular Expression syntax is used. REG_NOSUB: nl() Support for substring addressing of matches is not required. The nmatch and pmatch parameters to regexec are ignored if the pattern buffer supplied was compiled with this flag set. REG_NEWLINE: nl() Match-any-character operators don't match a newline. A non-matching list ([^...]) not containing a newline does not match a newline. Match-beginning-of-line operator (^) matches the empty string immediately after a newline, regardless of whether eflags, the execution flags of regexec, contains REG_NOTBOL. Match-end-of-line operator ($) matches the empty string immediately before a newline, regardless of whether eflags contains REG_NOTEOL. ) Copy and move constructors (and assignment operators) are available. manpagesection(MEMBER FUNCTIONS) All members of bf(std::ostringstream) and bf( std::exception) are available, as bf(Pattern) inherits from these classes. itemization( itb(std::string before() const) Following a successful match, bf(before()) returns the text before the matched text. itb(std::string beyond() const) Following a successful match, bf(beyond()) returns the text beyond the matched text. itb(size_t end() const) Returns the number of matched elements (text and subexpressions). bf(end()) is the lowest index value for which bf(position()) returns two tt(std::string::npos) values (see the bf(position()) member function, below). itb(void match(std::string const &text, int options = 0)) Match a string with a pattern. If the text could not be matched, an bf(Exception) exception is thrown , using bf(Pattern::match()) as its prefix-text. Options may be: REG_NOTBOL: nl() The match-beginning-of-line operator always fails to match (but see the compilation flag REG_NEWLINE above) This flag may be used when different portions of a string are passed to regexec and the beginning of the string should not be interpreted as the beginning of the line. REG_NOTEOL: nl() The match-end-of-line operator always fails to match (but see the compilation flag REG_NEWLINE) itb(std::string matched() const) Following a successful match, this function returns the matched text. itb(std::string const &pattern() const) This member function returns the pattern that is offered to bf(regcomp)(3). It returns the content of a tt(static) string that is overwritten at each construction of a bf(Pattern) object and at each call of the tt(setPattern()) member function. itb(Pattern::Position position(size_t index) const) With em(index == 0) the fully matched text is returned (identical to tt(matched())). Other index values return the corresponding subexpressions. bf(std::string::npos, std::string::npos) is returned if index is at least bf(end()) (which may happen at index value 0). itb(void setPattern(std::string const &pattern, bool caseSensitive = true, size_t nSub = 10, int options = REG_EXTENDED | REG_NEWLINE)) This member function installs a new compiled tt(pattern) in its bf(Pattern) object. This member's parameters are identical to the second constructor's parameters. Refer to that constructor for details about the parameters. Like the constructor, an bf(FBB::Exception) exception is thrown if the new pattern could not be compiled. itb(void swap(Pattern &other)) The content of the current object and the tt(other) object are swapped. ) manpagesection(OVERLOADED OPERATORS) itemization( itb(std::string operator[](size_t index) const) Returns the matched text (for index 0) or the text of a subexpression. An empty string is returned for index values which are at least bf(end()). itb(Pattern &operator<<(int matchOptions)) Defines match-options to be used with the following overloaded operator. itb(bool operator<<(std::string const &text)) Performs a bf(match(text, matchOptions)) call, catching any exception that might be thrown. If no em(matchOptions) were set using the above overloaded operator, none are used. The options set this way are not `sticky': when necessary, they have to be re-inserted before each new pattern matching. The function returns bf(true) if the matching was successful, bf(false) otherwise. ) manpagesection(EXAMPLE) verbinclude(../../pattern/driver/driver.cc) manpagefiles() em(bobcat/pattern) - defines the class interface manpageseealso() bf(bobcat)(7), bf(regcomp)(3), bf(regex)(3), bf(regex)(7) manpagebugs() Using tt(Pattern) objects as static data members of classes (or as global objects) is potentially dangerous. If the object files defining these static data members are stored in a dynamic library they may not be initialized properly or timely, and their eventual destruction may result in a segmentation fault. This is a well-known problem with static data, see, e.g., tt(http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.15). In situations like this prefer the use of a (shared, unique) pointer to a tt(Pattern), initializing the pointer when, e.g., first used. includefile(include/trailer) bobcat-5.09.01/documentation/man/isymcryptstream.yo0000644000175000017500000000774114050437223021371 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::ISymCryptStream)(3bobcat)(_CurYrs_) (libbobcat-dev__CurVers_) (Symmetric en- and decryption) manpagename(FBB::ISymCryptStream)(Istream performing symmetric encryption) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat -lcrypto) manpagedescription() bf(FBB::ISymCryptStream) objects may be used to encrypt or decrypt information that is available on a separate tt(std::istream). The tt(class ISymCryptStream) is a class template, using a tt(FBB::CryptType) template non-type parameter. Objects of the class tt(FBB::ISymCryptStream) encrypt the information they receive, objects of the class tt(FBB::ISymCryptStream) decrypt the information they receive. All symmetric encryption methods defined by the OpenSSL library that can be selected by name may be used in combination with tt(EncryptBuf) objects. To select a particular encryption method an identifier is passed to the constructor. E.g., tt("aes-128-cbc") indicating the AES (Rijndael) method, using 128 bit sized keys and blocks using `cbc' mode (see below for an explanation). Refer to the bf(isymcryptstreambuf)(3bobcat) man-page for a description of available encryption methods. includefile(include/namespace) manpagesection(INHERITS FROM) bf(FBB::ISymCryptStreambuf) (private), nl() bf(std::istream) manpagesection(CONSTRUCTOR) itemization( itb(ISymCryptStream( std::istream &in, char const *type, std::string const &key, std::string const &iv, size_t bufSize = 100, size_t filterBufSize = 1000, ENGINE *engine = 0)) This constructor initializes a tt(std::istream) providing it with an tt(FBB::ISymCryptStreambuf) stream buffer. The tt(ISymCryptStreambuf)'s constructor receives all arguments that are passed to this constructor. - tt(ISymCryptStream) objects perform encryption;nl() tt(ISymCryptStream) objects perform decryption;nl() - tt(ISymCryptStream) objects obtain the bytes to encrypt or decrypt from tt(std::istream &in);nl() - The encryption method to use is specified by the tt(type) parameter. E.g., tt("bf-cbc") selects the Blowfish Cipher Block Chaining method;nl() - The symmetric key to use is specified by the tt(key) parameter;nl() - The initialization vector is specified by the tt(iv) parameter;nl() - The tt(FBB::ISymCryptStreambuf) internally used buffer will contain tt(bufSize) characters. The default value is the smallest value that is used. When a smaller tt(bufSize) value is specified, the default value is used;nl() - The internally used tt(IFilterBuf) is initialized with a buffer of size tt(filterBufSize), using a lower bound of 100;nl() - The parameter tt(ENGINE) can be used to specify a hardware acceleration engine, as supported by the used encryption/decryption method. Its default argument value indicates that no hardware acceleration is available. ) Copy and move constructors (and assignment operators) are not available. manpagesection(INHERITED MEMBERS) Since the class uses public derivation from bf(std::istream), all members of this class can be used. manpagesection(EXAMPLE) verbinclude(../../isymcryptstream/driver/driver.cc) manpagefiles() em(bobcat/isymcryptstream) - defines the class interface manpageseealso() bf(bobcat)(7), bf(isymcryptstreambuf)(3bobcat) manpagebugs() Sep/Oct 2013: due to a change in library handling by the linker (cf. lurl(http://fedoraproject.org/wiki/UnderstandingDSOLinkChange) and lurl(https://wiki.debian.org/ToolChain/DSOLinking)) libraries that are indirectly required are no longer automatically linked to your program. With bf(BigInt) this is tt(libcrypto), which requires programs to link to both tt(bobcat) and tt(crypto). includefile(include/trailer) bobcat-5.09.01/documentation/man/cerrextractor.yo0000644000175000017500000001065214050437223020774 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::CerrExtractor)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Executing Child Processes) manpagename(FBB::CerrExtractor)(Runs external programs writing standard error) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() The bf(FBB::CerrExtractor) class offers a basic interface for calling external programs (so-called em(child processes)) writing their standard error streams. The standard input and standard output streams of the child processes are by default not handled by ttCerrExtractor) objects. The child's standard error is read through the tt(CerrExtractor) object: information written by the child process to its standard error stream is extracted or read from tt(CerrExtractor) object. The tt(PATH) environment variable is not used when calling child processes: child process programs must be specified using paths. tt(CerrExtractor) objects may repeatedly be used to execute the same or different child processes. Arguments passed to child processes may be surrounded by double or single quotes. Arguments surrounded by double quotes have their double quotes removed, while interpreting any escape-sequences that may have been used within. Arguments surrounded by single quotes have their single quotes removed, while accepting their content as-is. In addition unquoted escape-sequences may be specified: those escape sequences are evaluated and replaced by their intended characters (e.g., tt(\100) is converted to tt(@)). includefile(include/namespace) manpagesection(INHERITS FROM) bf(FBB::Exec) (private), bf(FBB::IFdBuf) (private), bf(std::istream) manpagesection(CONSTRUCTOR) itemization( itb(CerrExtractor(size_t bufSize = 100)) A tt(bufSize) argument may be specified: it defines the internal buffer size used by the tt(CerrExtractor's) streambuf. By default the standard input and standard output streams are not handled. itb(CerrExtractor(Mode mode, size_t bufSize = 100)) The tt(mode) argument must be tt(CerrExtractor::CLOSE_STD). It indicates that the standard input and standard error streams are redirected to tt(/dev/null): the child processes cannot read their standard input streams and any standard output generated by child processes is ignored. A tt(bufSize) argument may be specified: it defines the internal buffer size used by the tt(CinInserter's) streambuf. ) Copy and move constructors (and assignment operators) are not available. manpagesection(MEMBERS) itemization( itb(void execute(std::string const &cmd)) The argument specifies the command to execute: the command itself must be specified using an absolute path (the tt(PATH) environment variable isn't used). This member immediately returns, after which information written by the child process to its standard error stream may be extracted from the tt(CerrExtractor) object. Once tt(execute) has returned it can be called again, either using the same or another command. Arguments passed to the program to be executed as child process may optionally be specified using single or double quotes, as described in this man-page's DESCRIPTION section. itb(int ret() const) Once tt(execute) has returned this member provides the actual exit code of the child process. Its value equals -1 before the first tt(exectue) call. ) manpagesection(PROTECTED MEMBER) itemization( itb(Pipe &childOutPipe()) If derived classes need to override the redirections-members then they probabaly need access to the pipe written by the child process. This member provides a reference to that pipe. By default the parent process reads information from the pipe, while the child process inserts its standard error output into the pipe. ) manpagesection(EXAMPLE) verbinclude(../../cerrextractor/driver/driver.cc) manpagefiles() em(bobcat/cerrextractor) - provides the class interface manpageseealso() bf(bobcat)(7), bf(cininserter)(3bobcat), bf(coutextractor)(3bobcat), bf(execl)(3), bf(exec)(3bobcat), bf(fork)(3bobcat), bf(process)(3bobcat), bf(stdextractor)(3bobcat). manpagebugs() None reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/tablesupport.yo0000644000175000017500000003046214050437223020632 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::TableSupport)(3bobcat)(_CurYrs_) (libbobcat-dev__CurVers_)(Table Support Base class) manpagename(FBB::TableSupport)(Defines protocols for Table-support classes) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() This class is designed as a (non-pure) base class for objects handling some of the functionality of tt(FBB::Table) and tt(FBB::TableBuf) objects. By overriding its virtual functions users have control over the way the actual layout of tables is defined. By default the virtual members of this class do not separate the columns of the table from each other The Bobcat library offers the specialized class tt(TableLines) extending the basic facilities of tt(TableSupport) by allowing rows to be separated from each other by (partial) horizontal lines (see the bf(tablelines)(3bobcat) man-page for a description). When more specialized handling is required a class should be derived from bf(FBB::TableSupport) overriding those members that violate the programmer's current intentions. An object of this derived class may be presented to a tt(FBB::Table) or tt(FBB::TableBuf) constructor, to activate the special handling. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(ENUMERATION) The enum tt(ColumnType) defines the following values (see also the description of the tt(struct HLine), below): itemization( itb(SKIP) a section of a row-separating line should remain empty. This value is normally not used by applications; itb(USE) a section of a row-separating line should be used (e.g., by writing a (horizontal) line); itb(LEFT_FULL) a (horizontal) line should be written over the total width of the separator to the left of a series of columns itb(RIGHT_FULL) a (horizontal) line should be written over the total width of the separator to the right of a series of columns; itb(LEFT_MID) a (horizontal) line should be written over the right-half part of the width of the separator to the left of a series of columns; the left-hand part remains blank; itb(RIGHT_MID) a (horizontal) line should be written over the left-half part of the width of the separator to the right of a series of columns; the right-hand part remains blank; ) The value tt(SKIP) should always be used by itself; remaining values of the enum may be combined using the binary or (tt(|)) operator. manpagesection(PUBLIC TYPE) itemization( itb(struct HLine) This struct has the following fields: verb( size_t d_row; size_t d_begin; size_t d_end; size_t d_type; ) It offers two constructors: itemization( itb(HLine(size_t row, size_t begin, size_t end)) itb(HLine(ColumnType type, size_t row, size_t begin, size_t end)) ) Objects of type bf(TableSupport::HLine) may be inserted into a bf(TableSupport) object to indicate section(s) of a horizontal separator between table rows that should be displayed or skipped. E.g., to specify that a separator should be written in row 1 between columns 2 up to (not including) 5, extending the separator to the left by half the width of the separator between columns 1 and 2 and to the right by the full width of the separator between columns 4 and 5 the following tt(HLine) object should be inserted into the tt(TableSupport ts) object: verb(ts << HLine(LEFT_MID | RIGHT_FULL, 1, 2, 5);) Multiple tt(HLine) objects may be inserted into a tt(TableSupport) object, their ordering is irrelevant. When column ranges overlap then their tt(ColumType)s are merged. ) manpagesection(PROTECTED TYPES) itemization( itb(const_iterator) This type is defined in the class's protected section. bf(TableSupport::const_iterator) is an input-iterator returning pointers to bf(struct Field) (see below) objects for table columns and column separators (see below at the tt(begin) and tt(end) members) itb(struct Field) This type has two data members: tt(width) and tt(type), representing, respectively, the width and tt(ColumnType) of a column or separating column. Although column types can be combined when inserting them using tt(HLine) objects, tt(type) values of tt(Field) objects returned by tt(TableSupport) members only contain single values (like tt(SKIP) or tt(LEFT_MID)). ) manpagesection(CONSTRUCTORS) The default, copy and move constructors as well as the copy and move assignment operators are available. manpagesection(OVERLOADED OPERATORS) itemization( itb(TableSupport &operator<<(TableSupport &support, size_t width)) This operator defines a column-separator of tt(width) space characters. The argument tt(width) may be zero, in which case no visible separator is used. The first separator inserted refers to the separator to the left of the table's leftmost column. Subsequent separators separate subsequent columns. At most tt(nColumns + 1) separators can sensibly be inserted. Additional separators are ignored when a table is inserted into an tt(ostream). itb(TableSupport &operator<<(TableSupport &support, std::string const &sep)) This operator defines a separator as a piece of text. The string may be empty, in which case no visible separator is inserted into the table. The first separator inserted refers to the separator to the left of the table's leftmost column. Subsequent separators separate subsequent columns. Textual and numeric separator may be intermixed. At most tt(nColumns + 1) separators can sensibly be inserted. Additional separators are ignored when a table is inserted into an tt(ostream). itb(TableSupport &operator<<(TableSupport &support, HLine const &hsep)) This operator defines how a section of a horizontal separator of a specified row should be displayed (see the description of tt(ColumnType) in the tt(ENUMERATION) section). ) manpagesection(PUBLIC MEMBER FUNCTIONS) itemization( itb(void hline(size_t row) const) When inserting a table into a tt(std::ostream) tt(Table) and tt(TableBuf) objects call this member just before the indicated row (offset) is inserted into a tt(std::ostream). It calls tt(v_hline), passing it tt(row). itb(void hline() const) When inserting a table into a tt(std::ostream) tt(Table) and tt(TableBuf) objects call this member just after inserting the table's final row. It calls tt(v_hline) without arguments. itb(void setParam(std::ostream &ostr, size_t nRows, size_t nColumns, std::vector const &align)) This member provides the bf(TableSupport) object with values that are essential for its proper functioning. It is called from the tt(Table) and tt(TableBuf)'s tt(def) member or manipulator. A tt(TableSupport) object can be used before that to specify widths and types of separators, though. This member's parameters are initialized by the tt(Table) and tt(TableBuf) class objects as follows:nl() bf(ostr) is a reference to the bf(std::ostream) into which the table will be inserted; nl() bf(nRows) specifies the number of rows used by the table;nl() bf(nColumns) specifies the number of columns if the table;nl() bf(align) is a reference to a constant vector of (column) alignment specifications. itb(void vline(size_t col) const) When inserting the data elements of the rows of a table into a tt(std::ostream) tt(Table) and tt(TableBuf) objects call this member just before inserting the data elements of column tt(col). Its intended task is to write a column separator just before the data elements themselves. It calls tt(v_vline) passing it its tt(col) parameter. itb(virtual void vline() const) When inserting a table into a tt(std::ostream) tt(Table) and tt(TableBuf) objects call this member after inserting the data elements of the rows of the table. It is called at the end of each row. It calls tt(v_vline) without arguments. itb(size_t width() const) Returns the total width of the table. ) manpagesection(PROTECTED MEMBER FUNCTIONS) The following members are available to classes derived from bf(TableSupport). Except for tt(sep) and tt(sepWidth) their values are only defined after tt(setParam) has been called. This latter function is called from the tt(def) member or manipulator of tt(Table) or tt(TableBuf) objects. itemization( itb(std::vector const &align() const) A reference to a vector of tt(Align) objects, defining the alignments and widths of the table's columns is returned. itb(const_iterator begin(size_t row) const) An iterator returning information about the first column element when displaying the horizontal separator preceding line tt(row) is returned. To obtain the information about the separator beyond the last row tt(nRows()) should be used as its argument. The `column elements' of the table are its separators and data columns. Dereferencing the returned tt(const_iterator) provides access to a tt(Field) struct defining the type and width of a column element. Dereferencing the iterator returned by tt(begin) provides information about the leftmost column separator. By incrementing the iterator all subsequent column elements are visited. The iterator's value becomes undefined once it reaches the value returned by tt(end) (see below). itb(size_t colWidth(size_t col) const) The width of the indicated column is returned. itb(const_iterator end(size_t row) const) An iterator indicating the end of the iterator range starting at tt(begin(row)) is returned. itb(size_t nColumns() const) The number of columns of the table is returned. itb(size_t nRows() const) The number of rows of the table is returned. itb(std::ostream &out() const) A reference to the stream into which the table is inserted is returned. itb(std::vector const &sep()) A reference to the separators that are defined for the table's columns is returned. Element tt(col) refers to the separator to the left of the table column tt(col), element tt(nColumns()) refers to the separator to the right of the rightmost table column. itb(size_t sepWidth(size_t col) const) The width of the indicated separator is returned. Element tt(col) refers to the separator to the left of the table column tt(col), element tt(nColumns()) refers to the separator to the right of the rightmost table column. ) manpagesection(VIRTUAL MEMBER FUNCTIONS) The following member functions can be overridden by derived classes to redefine the way horizontal and vertical separators are displayed. itemization( itb(virtual void v_hline(size_t row) const) This member is called from tt(hline(size_t row)), receiving its tt(row) parameter. Its task is to write a horizonal separator for row tt(row). By default nothing is inserted. It may do so by iterating over the range defined by the tt(begin) and tt(end) members, deciding what to do on the basis of the tt(Field) objects referred to by the iterators. itb(virtual void v_hline() const) This member is called from tt(hline()). Its intended task is to write a (partial) horizontal line beyond the table's last line of data elements. By default it calls tt(hline(nRows)). itb(virtual void v_vline(size_t col) const) This member is called from tt(vline(size_t col)), receiving its tt(col) parameter. Its task is to write a separator before data column tt(col). By default it inserts tt(separator[col]) if if is available. If that separator is not defined, no action is performed. itb(virtual void v_vline() const) This member is called from tt(vline()). Its intended task is to write a column separator, terminating a line of the table. By default it inserts a new-line (tt(\n)) character. ) manpagesection(EXAMPLE) See the example in the bf(table)(3bobcat) man-page. manpagefiles() em(bobcat/tableSupport) - defines the class interface manpageseealso() bf(bobcat)(7), bf(align)(3bobcat), bf(table)(3bobcat), bf(tablebuf)(3bobcat), bf(tablelines)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/randbuf.yo0000644000175000017500000000344714050437223017532 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::RandBuffer)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (random number streambuf) manpagename(FBB::RandBuffer)(std::streambuf generating random numbers) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() bf(FBB:RandBuffer) objects may be used as a bf(std::streambuf) of tt(std::istream) objects to allow the extraction of random numbers from the stream. includefile(include/namespace) manpagesection(INHERITS FROM) std::streambuf manpagesection(CONSTRUCTOR) itemization( itb(RandBuf(int min, int max, size_t seed = 1)) This bf(RandBuf()) constructor initializes the random generator. The seed is used to initialize the random number generator.Random values between tt(min) and tt(max) (inclusive) are returned. ) Copy and move constructors (and assignment operators) are not available. ` manpagesection(VIRTUAL MEMBERS) itemization( itb(int underflow()) This function is called by tt(std::istream) objects using bf(RandBuf). It produces the next available random number, separating the random numbers by one blanks space. Random values between tt(min) and tt(max) (inclusive) are returned (see the description of the constructor). ) manpagesection(INHERITED MEMBERS) Since the class uses public derivation from bf(std::streambuf), all members of this class can be used. manpagesection(EXAMPLE) verbinclude(../../randbuf/driver/driver.cc) manpagefiles() em(bobcat/randbuf) - defines the class interface manpageseealso() bf(bobcat)(7), bf(irandstream)(3bobcat), bf(rand)(3), bf(srand)(3), bf(std::streambuf) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/sharedmutex.yo0000644000175000017500000001056714050437223020443 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::SharedMutex)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Shared Memory Mutex) manpagename(FBB::SharedMutex)(Mutex for shared memory) manpagesynopsis() bf(#include )nl() Linking option: tt(-lpthread, -lbobcat ) manpagedescription() Shared memory may be used by multiple processes. To synchronize access to shared memory an bf(FBB::SharedMutex) may be defined inside a shared memory segment. bf(SharedMutex) objects allows clients to lock a shared memory segment before reading or writing its content. E.g., the Bobcat class tt(FBB::SharedSegment) defines a bf(SharedMutex) in its shared memory segment. The bf(SharedMutex) class uses the facilities offered by the tt(PThread) library to implement (non recursive) shared memory locking. To force unlocking a (possibly) locked shared memory segment, its destructor can be called. bf(SharedMutex) mutexes are non-recursive, resulting in deadlocks if their tt(lock) member is called twice from the same thread of execution without an intermediate call to tt(unlock) the mutex. If this causes concern, a variable can be defined indicating whether the lock has already been obtained. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(CONSTRUCTORS, DESTRUCTOR ) itemization( itb(SharedMutex()) The default constructor initializes an bf(FBB::SharedMutex) object to a shared memory mutex (using the tt(PTHREAD_PROCESS_SHARED) attribute). As an bf(FBB::SharedMutex) object will normally be defined inside a shared memory segment the object's memory is already available. In this case placement new should be used to call the constructor. E.g., if a shared memory segment is attached to the current process at tt(d_shared), and an bf(FBB::SharedMutex) should be defined at tt(d_shared)'s address, then the bf(FBB::SharedMutex) object can be initialized like this: verb( new (d_shared) FBB::SharedMutex; ) Caveat: when using placement new to initialize a bf(SharedMutex) make sure that the bf(SharedMutex) fits inside a block (i.e., tt(shared.blockOffset() + sizeof(SharedMemory) < shared.dataSegmentSize())). If not, use tt(seek) to switch to an offset where this equality holds true, or simply use tt(SharedMemory::create) like this: verb( FBB::SharedMemory::create(); ) itb(~SharedMutex()) The class's destructor releases all of the current process's nested shared memory segment locks. To destroy an bf(FBB::SharedMutex) object that has been constructed using the placement tt(new) operator use verb( d_sharedMutex->~SharedMutex(); ) (assuming tt(SharedMutex *d_sharedMutex) points to the location where placement new has previously initialized the bf(FBB::SharedMutex) object.) ) Copy and move constructors (and assignment operators) are not available. manpagesection(MEMBER FUNCTIONS) itemization( itb(void lock() const) When returning from this member, the current process has locked the shared memory segment. Note that bf(SharedMutex) objects are non-recursive. itb(void unlock() const) The object's lock of the shared memory segment is released. This member can also be called if the bf(SharedMutex's) lock has not been obtained. ) manpagesection(PROTECTED MEMBER FUNCTION) itemization( itb(pthread_mutex_t *mutexPtr()) A pointer is returned to the tt(pthread_mutex_t) object used by the bf(SharedMutex) object; ) manpagesection(EXAMPLE) See the bf(sharedstream)(3bobcat) man page. manpagefiles() em(bobcat/sharedmutex) - defines the class interface manpageseealso() bf(bobcat)(7) bf(isharedstream)(3bobcat), bf(osharedstream)(3bobcat), bf(sharedblock)(3bobcat), bf(sharedcondition)(3bobcat), bf(sharedmemory)(3bobcat), (e.g.,) bf(pthread_mutex_init)(3posix), bf(sharedpos)(3bobcat), bf(sharedreadme)(7bobcat), bf(sharedsegment)(3bobcat), bf(sharedstream)(3bobcat), bf(sharedbuf)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/inetaddress.yo0000644000175000017500000001143514050437223020412 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::InetAddress)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Network Byte Order) manpagename(FBB::InetAddress) (Converting between host byte order and network byte order) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() Computers differ their word-byte order, called `endianness'. A little-endian computer has its least significant byte at the byte having the lower address of a two-byte value, whereas a big-endian computer has its least significant byte at at the byte having the higher address of a two-byte value. In order to allow these computers to communicate over over Internet, em(host byte order) was designed. Objects of the class bf(FBB::InetAddress) may be used to convert between network byte order and host byte order (and vice versa). The class only has a few public members. Most members are protected, and bf(FBB::InetAddress) is therefore primarily used as a base class from which other classes are derived. In practice there will be little need to construct objects of the class bf(FBB::InetAddress), which is primarily a support class for the bf(FBB) socket-classes. Internally, all data are stored in network byte order. As the class' constructors depend on the proper functioning of members of the bf(FBB:GetHostent) class, the class' objects can only be constructed when the host whose name or address is searched can be resolved by a name resolution process, e.g., bf(bind)(1). Objects of the class bf(FBB::InetAddress) store address information about a host in a bf(struct sockaddr_in) data member. A bf(struct sockaddr_in) is the data type used to represent socket addresses in the Internet namespace. It has the following members: itemization( itb(sa_family_t sin_family) This identifies the address family or format of the socket address. It holds the value bf(AF_INET). itb(struct in_addr sin_addr) This is the Internet address of the host machine stored as a binary value. itb(size_t short int sin_port) This field holds the port number. ) includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(PROTECTED CONSTRUCTORS) itemization( itb(InetAddress(std::string const &host, uint16_t port)) This constructor expects a host name or dotted decimal address and and an (size_t) port number, and determines the host's address information. An bf(FBB::Exception) exception is thrown if the address could not be determined. itb(InetAddress(uint16_t port)) This constructor constructs the `generic' address information that is used when constructing, e.g. server sockets. itb(InetAddress(sockaddr_in const &address)) This constructor constructs an bf(FBB::InetAddress) object from an initialized bf(sockaddr_in) object. It is primarily used to promote a bf(sockaddr_in) to an bf(FBB::InetAddresss). ) The (public) copy and move constructors (and assignment operators) are available. manpagesection(MEMBER FUNCTIONS) itemization( itb(uint16_t port() const) Accessor returning the object's port value. itb(std::string dottedDecimalAddress() const) Accessor returning the object's Internet address as a dotted decimal string. If the address could not be determined, an bf(FBB::Exception) object is thrown. itb(size_t size() const) Accessor returning the size of the object's bf(sockaddr_in) (address) information. itb(sockaddr const *sockaddrPtr() const) Accessor returning the pointer to the object's bf(sockaddr) data member. itb(sockaddr_in const *sockaddr_inPtr() const) Accessor returning the pointer to the object's bf(sockaddr_in) data member. ) manpagesection(PROTECTED MEMBER FUNCTIONS) itemization( itb(sockaddr *sockaddrPtr()) This member returns the object's address information as a pointer to a modifiable bf(struct sockaddr). This allows (contrary to the public member having the same name) derived objects to manipulate the object's address information directly. itb(sockaddr_in *sockaddr_inPtr()) This member returns the object's address information as a pointer to a modifiable bf(struct sockaddr_in). This allows (contrary to the public member having the same name) derived objects to manipulate the object's address information directly. ) manpagesection(EXAMPLE) verbinclude(../../inetaddress/driver/driver.cc) manpagefiles() em(bobcat/inetaddress) - defines the class interface manpageseealso() bf(bind)(1), bf(bobcat)(7), bf(gethostent)(3bobcat), bf(socketbase)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-5.09.01/documentation/man/fswap.yo0000644000175000017500000002106714050437223017227 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::fswap)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Fast swap function) manpagename(FBB::fswap)(generic template fast swap function) manpagesynopsis() bf(#include )nl() manpagedescription() The information stored in objects frequently needs to be swapped. A well-known example is the swapping operation required when implementing an overloaded assignment operator. For example, the generic form of the operator assignment operator is: verb( Class &operator=(Class const &other) { Class tmp(other); swap(tmp); return *this; } ) The swap functionality merely swaps the content of the current object and another object. The standard tt(std::swap) function calls the class's tt(operator=) function to swap objects. Newer implementations might use move-operations to increase the speed of the swapping operation, but in both cases some form of the assignment operator must be available. Swapping, however, might be possible when assignment isn't. Classes having reference data members usually don't offer assignment operators but swapping might be a well-defined operation. It is well known that objects can be installed in a block of memory using em(placement new), using a block of memory the size of the object to construct the object it. This is the foundation of the template function tt(FBB::fswap) (fast swap). This swap function merely uses the memory occupied by objects to implement the swapping operation and it may therefore be used with classes having const data members, reference data members, ponters to allocated memory etc, etc. The function simply uses a spare block of memory the size of the object to be swapped. It then uses bf(memcpy)(3) to swap the information contained in the two objects, using the spare block of memory as a placeholder. Classes may define data members that do not support fast swapping. If such data members can be swapped using either tt(std::swap) or their own tt(swap) member, then overloaded versions of tt(fswap) can be used to fast-swap objects of such classes. Also, classes may inherit from base classes that do not support fast-swapping, but that either offer their own swap members or can be swapped using tt(std::swap). For these cases overloaded versions of tt(fswap) are also available. The classes tt(std::string) and tt(std::unordered_map) are examples of classes whose objects might not be swappable using a fast swap method. Therefore, in practice, classes defining members of such classes should use one of the overloaded tt(fswap) functions for swapping their objects. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(ENUMERATION) The enumereation tt(SwapMode) is used to specify a specific swapping-method: itemization( itt(SWAPMEMBER) is selected by default, but it can also explicitly be specified. It indicates that selected members are swapped using their own tt(swap) member function having prototpype tt(void Type::swap(Type &rhs)). itt(STDSWAP) can be specified to indicates that selected members should be swapped using tt(std::swap). ) Specific members not supporting fast swapping can always be swapped using a specific swap-method. E.g., when tt(SWAPMEMBER) is selected, but a particular data member does not offer a tt(swap)-member, then tt(std::swap) can be specified for just that member. manpagesection(SWAP FUNCTIONS) itemization( itb(fswap(Type &lhs, Type &rhs)) This template function swaps the content of two objects. It can be used with classes having const data members, reference members, pointer members or standard value-typed data members; itb(fswap(Type &lhs, Type &rhs, member, ...)) This function is provided with a list of member names (i.e., members of the class tt(Type)) that do not support fast swapping. Those members are swapped using their tt(swap) member, while all other members are fast-swapped. When using lists of members, the selected members em(must) be listed in their declaration order or a tt(std::runtime_error) exception is generated when the function is used. itb(fswap(Type &lhs, Type &rhs, member, ...)) This function acts identically as the previous function, but explicitly specifies its default swapping method. Each of the members specified in the list of members can be specified by their names, in which case the specified swapping method is used. Alternatively tt(stdswap(member)) can be used, in which case tt(std::swap) is used for swapping tt(member); or tt(swapmember(member)) can be used, in which case that tt(member's swap) member function is used for swapping tt(member); itb(fswap(Type &lhs, Type &rhs, member, ...)) This function is also provided with a list of member names that do not support fast swapping. Those members are swapped using tt(std::swap). As with the previous function, members can be specified by their names, or tt(stdswap(member)) or tt(swapmember(member)) can be used; itb(fswap[swapMode](&firstMember, Type &lhs, Type &rhs [, member, ...])) This function's first argument is the address of tt(Type's) first data member (usually specified as tt(&d_first)) inside tt(Type's) own tt(swap) member). It is used when tt(Type) is derived from a base class that itself does not support fast swapping. This function may optionally be provided with a tt(SwapMode) template non-type argument (by default SWAPMEMBER) is used), and may also be provided with a list of members (optionally using tt(stdswap) and tt(swapmember)). ) manpagesection(EXAMPLE) verbinclude(../../fswap/driver/driver.cc) manpagefiles() em(bobcat/fswap) - defines the class interface manpageseealso() bf(bobcat)(7), bf(memcpy)(3) manpagebugs() The tt(fswap) functions should not be applied mechanically to swap objects of classes having pointer data members defining, e.g., a linked list. Consider a list of four objects like: verb( A -> B -> C -> D ) fast-swapping B and C would result in the following corrupted list: verb( +------+ | | A -> C -+ +-> B -+ +-> D | | +-------------+ ) However, classes implementing a data structure like a linked-list might still benefit from fast swapping operations: by implementing their own swap member they could first use fast swapping to swap the objects, followed by another fast swap to unswap their `next' pointers. The tt(fswap) function should also not be used for objects defining (back-)pointers to their own data. Consider the following objects using pointers to data and (back-)pointers to the original objects: verb( Before fswapping: A B +--------+ +-----------+ +--------+ +-----------+ | | | | | | | | +--> *Aimp------> *A (back)--+ +--> *Bimp------> *B (back)--+ | | | | | | | | | | | | +--**Aimp | +-----------+ | +--**Bimp | +-----------+ | +--------+ <---------------+ +--------+ <---------------+ After fswapping: +-------------------------------+ +--|-------------------------------|-+ +-------------|--|-----------------+ | | | A | v | B | v | +--------+ | +-----------+ | +--------+ | +-----------+ | | | | | | | | | | | | +-----> *Bimp---+ | *A (back)--+ +---> *Aimp---+ | *B (back)--+ | | | | | | | | | | | | | +---**Bimp | +-----------+ | +---**Aimp | +-----------+ | | +--------+ <---------------+ | +--------+ <---------------+ +------------------------------------+ ) After the swap tt(**Bimp) should point to tt(Bimp)'s address (now at A), but in fact it points to tt(Aimp)'s address (now at B). Likewise, the back pointers still point at their original objects rather than at their swapped objects. All tt(stream) classes define such pointers and can therefore not be swapped using tt(fswap). The bottom line being that tt(fswap) should only be used for self-defined classes for which it can be proven that fast-swapping does not corrupt the values of its pointer data. includefile(include/trailer) bobcat-5.09.01/documentation/images/0000755000175000017500000000000014050437223016222 5ustar frankfrankbobcat-5.09.01/documentation/images/molds/0000755000175000017500000000000014050437223017340 5ustar frankfrankbobcat-5.09.01/documentation/images/molds/README0000644000175000017500000000044014050437223020216 0ustar frankfrankCopy figure.odp to the intended figure name, design the new figure using loimpress, save as pdf, run '2jpg new-figure' (w/o extension). The jpg figure appears in ../ (i.e., bobcat/documentation/images) Any .jpg images are stored in /usr/share/docs/bobcat5/images by 'build install man' bobcat-5.09.01/documentation/images/molds/sharedsegment2.odp0000644000175000017500000004135414050437223022766 0ustar frankfrankPKQ³D3&¬¨//mimetypeapplication/vnd.oasis.opendocument.presentationPKQ³DN馔”Thumbnails/thumbnail.png‰PNG  IHDR€k× ][IDATxœí]{lE_!bA%"ÈCŠ64Byˆ€PPä¥TPQð ÒQVä! Z j@ƒy$ŒÐµå¡"òÒª`«D”§øýÒóq2Ý»ìÝÝ»;÷îüþ¸Ù™¹{ÎÌ™9gΩúßÿQEÕ° ¡&4hDš4" Í‘†fHC3€F¤¡@#ÒÐ  ihЈ44hDš4" Í‘†S8çœsÚ xÓÌ8fm7ª‘P„2ÈjH#ÒÐ àfÍšUµjÕfÍšuëÖÍK=O?ýôÁƒãÊñûï¿_rÉ%Râo¼ñÄOœõYo½õÖã?^^^îü‘d„fðí·ß>óÌ3óæÍ»á†<Þ,Æ7ß|Ó¯_?4¦gÏž—^z)§ßwß}Æ ‹«%C‡½÷Þ{qñå—_¶oßþÅ_ܲeËÒ¥KévÑ¢E›7onÙ²åƒ>øÏ?ÿ ã›6m:ï¼ó¾øâ‹:¼ùæ›_ýuvvöáÇo¹å–;v\~ùåùùù<ð@aaá©S§¤âj˜¿Ž,G¦¤ÆªU«Ö¬Yƒ¯>dÈãǃ@ÅÜ}ûöeff¾óÎ;Ï?ÿüc=öñÇ/^¼xäÈ‘—]vÙ¾}ûÔ©SQàí·ß~ï½÷0ÜŠÏ‚‚ÓÒÒ®¾úêO>ùK¯›o¾¹oß¾bV‹-øÕ¯¿þ:×¹lÙ²ï¾ûŽi3Æ5×\ƒ‹‹.º¿S¦LÙ½{÷\ÀåûôéóðÃÐwíÚ…Æà] Ôk¯½vÅŠ­Zµ¢JÚµk‡ßóÏ?íá[”ìÕ«×­·ÞŠë•+W>ôÐCøEm×_½QÁ< zü!ŸþyïÞ½ñ'<ùä“ÿþû/²Z·nMÕŠ5„ˆ€ ÖÈ”ÔÀx†\«V-”9·I“&G½ýöÛï¸ãŽAƒRÁcÇŽÅx Þ˜0aˆî¼óNˆÄ(†¡ƒaõôéÓ *fÊB"¿ZªS¬gÏž=üñ†XÐ4nǺˆåï¹ç@#A‹5jÔ€ØS·n]ðvFF†p®*==‘oÁcëÖ­£ëÏ>û À®¼òÊmÛ¶á"++«¨¨Ll›XCˆðÄ<˜à¤dçÎæ‘éÓO?]½z5À¨0bÄ<èWg¨ðÈ‘#7Ñ5ËÝ ÚC{ä‘GÀ6 6ûšQ•smâþe‰¯6×  \Ìž=´¾`Á‚Ñ£GãöÜsÏÅãæòÍ›7Ÿ`õrÕUWaØ®]»6JJMÂ,”““ƒ!ŒnѪ®]»–””;v œƒq $þÃ?ð¿±wï^>•ó@àÉÍÍ+ä6lhÿo$ž@Ñ=i Ùºu«ydÅc5FÀ˜¾ýèE8€Ð¾`3ã"2>9þbiHÃø… ƒ_°=¥`öÃp€îãú‰ëׯ§,sæÌÉËË«^½:$oÜÎ;לE¯îÑ£‡X'f ˆ×®FU§Nˆ^wÝuè£~qq1rQÃO?ýÄå.\ˆÈâx ãÛѧD/ Õ ë«¯¾‚t‡‹ÒÒR´E2 f3°Ø |öÙg‘Ò´iS\ £b½Ž×¡ò 6@èŸ8q"ʃC…Û“'OŠ5à]‰ÿV1ቤ!PHðmÌ#“XÀË«U@ß Ðuÿþýé‚'4 Üâ/S9†üb0L ñ–ë·Ébñ‰ê$Æ#|ðÁtÁD&Ö@åiaݦMÈiœ…q ¿Ÿzå•WÌ•pÍW@ÊŲ¡cÇŽ¸xá…Ä,utJž€‡Àúõë¦ÄrdÂ:Œ `ÆàñRC#xbq$žÞÞ’F&’G šú5Â…ÖhDš4" Í‘†fHC›BTBR4Ò R¦#‰Fb`Ê”)øýè£-ZäÐ_nÍš5£GþóÏ?Ú6/\»víöíÛKKKÿþûoÞñvdÓ¦M6lØ¿•*U¦OŸ`KBbıqãÆë®».33Ól Ñ»wo¤çææ>|˜´‰Æ-¶C4*42‰Þ*uÑÈ:ÜxãÄSx\ƒŽx;R«V-”9tèP¯^½ˆéHH8`š8q"§H¦G¹7jÔˆiKB¶.Y³fMPÕ´iÓæÏŸL# ÞŽddd`›}š,ç–/_~÷Ýw`+ᢑ#GŽü±»wˆAG¼t„eLIIÉøñã)E‘މÄ2À»ï¾Ë×–¦FÅaBñ ²A Û¾‡‹FJ­R„hâíˆùŒ˜" aêèÀÄêÕ«b3ì‘t‚”鈿“Z´h¡ŽYl,$E# e:â/âf€äõ%~þäí…‘¢ nféXvCÁt)…‹yôhKçJé.ü‘ØÃ¦#ÉEXד¤ •;¤~†G&±û‹éñú#Ñî@A*·IÅÍ›7'&+V¬`$'Ož$g!'NœX¼x±k>ì/: éÓ§ëbé-ä$;;[t@Y¨œÞ…‰(''‡ª­Y³f‡222>üðÃÑ£GOš4‰ïjø—  &•;O7cÔ¨Qìƒdÿþýä,ì1þ|{×&ô¸ä€Dù#Ù¸q£¨—¥¬лÀ`\mQQÑÚµk¿ÿþû#GŽ”••…ë:*µá†T£fïÔO|€úÍŒnHD$ _N'÷$äÄÆ!Þ%úhÙ²åÌ™3»téÒ¸qã÷ߟ¬Ü4¯‹`†jTîúiw|Ë–-sçÎe$BŒŠ3þ `ÃÖµ öÇ€ òתU‹j¦trAþH†.ée~—Xmaaa•*UÈD#\Ÿµ#îà@5*w>öóîxVV–èƒDràaãÚ„t®Ï=÷œT3ëbÅgÍÀʲ$ï&mÛ¶¥[Ì*N:¢á>0€jT¯ä£exeÕ¨\S¿F\ˆº@#∺ tÜvÛm«W¯»Ñ…Ö„ 3õ?~|ݺueee¸îÖ­yÞÕH´àÿ°Œga>S+°ÔÏš5kÁ‚]»vÍËË›7ožØúeµñÆQCaa¡)£{÷î´Ñ4mÚ4Ź7u=Ã2ž…ùL­TÀRü裂î5jÄ'­$°ÚåóóóéÕ)¹`4^o€€¨ëb·ÑÝŠŠ³þøÇ,--ÅXÎå«V­J1‚ SÜ 3fÌÀ$S­Z5u®¤0<-‚mn•MËx¢·wZÌÌúã6mÚtêÔ ó†Xÿ°aÃ^zé%*ú¦¸ô‹‹‹é(#GÊèׯ_AAf˜›nº)®.h¸€§Àr”% ø™3gÆeŸPOfN˜!V< 1l„¹€Q9†'6hРgÏžbýäqdìØ±Få¸K–,1ÎÄ× ÇiñðÛo¿uîÜy×®]®z¬áþ‰¤ˆœqÅåL±zC‡E÷«W¯îîñzõêaue÷¤I“üm˜†þ0€d"/f‰û$k)¨Þ† @ë\ž¬ç7nœ››K[.?ÿü³h^o$•ݼò1àÇ5â‚{=€xk©SÜ'Á-Õ;pàÝ&~¸E2¯O´Ý¼‚±Ô!â«[·n‚ê×0¼èD°þÉû$Õƒ`m._ZZÊ[.%%%fózÃo»yö& õK]ªŠ xQi‘Xˆ‰§€X¨,üш¶ì´Ú£y|Û¶mâ> ~)¨FwѤ¾mÛ¶íÛ·?tèÐ!CŒÄÕ«WÓ> ›×'Ânž½ÉrŠM,õúõë·iÓ†ôbX›6jÔˆc©‹U‰º3f¢JˬkËIŠ6V‡‘XˆN¡¿RÀw áÏ@²e§Ð™ ƒ{qŸ„®Áby£rpOC°ÇH„ݼٛ¬M,upczz: iyyy;vìc©sUXŸ° —––&ª´Ìº6¬…$E›8žÂîÚŸ·Ôð‚HGˆ‘¼É¶±Ô A/†!YŠ¥ÎUáqä–/_n£Ò²?$I C•öŠ3 /ˆ4ˆÞdi¥aKòëÅš5k&ÆRoݺ5W…ug(#ª´Ìº6dIŠ61p<Ç|ç€ï‹‹‹Ãù³Rþ0€;÷O‰ÞE9+Do².ÌgÅXê{í¥è†K]¬Šug’JËR×&BJg±gÀäÉ“=ôXC†? àb Ũ¼‹’’Ð*-õáI íNÐ fQ/Æ»(333iÇÃíŠ+Ä]ÃÊ Ù¼IâÚ9h•–úð¤v'h  éÅhkJ»´ãQ·nÝU«V‰»(†³M_¬‘54žôÒîm¡Vz1,àÄÚµkK»(–oñÑ98·çÓ1LÕ§5ïN@ò)..¦-”¢¢"QWÅ»(¢iqnn®´‹b8Û$qmœh8·çK1Ë¿d‡'ÍzéÂRWE»( KÑ´xĈ†°‹bÄ0HáÅ9^@B#»=0!æ^i`Ý"êkÅUyÃe£½úõëC¤ jåÊ•\¸JZ.`ðÔ˜1c¼´\#.¤ À£52,Mv{˜|zõê%®4¤ã‹±Œö01’õ¿T¿"–;^/ÍÖˆ)Ⱦ콀.Énn¥•CZ±7\¢c>)ÕF%ÍÕjê)Ⱦ`Þ¼yd·×£Gq¥A Ö×"u´ÕªU›:ujçÎ3K>™Íµeddp SËLˆ½Ž ü9@àXCYYY‰°b·Ü<±q,UVVæº}+@× YóJƒ~E-k»xDAŠ,ÿ¤§4‚„?çŒÊ±† ïܹÓòY×&òâæÉ«¯¾jœ1¾·q«Ö©S§XÍÐÐ xÒ@ð¥M kȨXÞ‚ž¸¸¸âÙD~ïÞ½5jÔ8«/*Þrá Cl|’XòbŠtéÒ%??B9?NÍHy˜Ç£¸n†jn*=­0Ó&†(!&+ö &Œ7Îl"ïЕd"oÆ÷ƒ&[º… â-ø8p ?þ×_yé]²Àr×8®Û€AoW„ ¼ºE±qAÅ;$¿üò‹ù³ú¢2Îl³˜íøé¤XÓ¦MÏjaÏòÄ5û8`ûh¥k_•˜ëeé<<1€xÖ‘c aL¹¬'NOO·4‘w苊·\Ø>žïwïÞmT˜ïc®ÀÀrS|ÜþŒ¼Ä·8¥ÓùÚ²¼4²ˆœ0ƒx@Ùµ•.žm׮ݢE‹8°uëÖeË–ÙT%š'×ÒËé8Öì'6L&òqù¢âÍÑøž²°Dæ‰;„j.=:Î:»³Ò峦ÑùZÔ^CîõåÈ=yò䀰3*[ “c5´@Ay©Ü&Ý Hg½XéBÈD¤Ù§žzʨ¬½HnH³fͺâŠ+Œä9Çì§À T3‘W“ʧ[BZ#y±ÒçtìØ‘Ì ¢x&i¸6l¸dÉ’qãÆ•uä¢cÕà› ¡5ûåìš×HâAçx­ti—âµ×^Ãã/¿ü2–¸E–¸ðc}yƒ Œ ©iúôéà=Ô&žcvÞòàá[|çÀç€h¹Ÿ¤¡¼jÔ죫wóÉ•.8ñ^‚¹¢¾œrñqéVÔ‘«Œl0Õò1sÊ+EÍÉâ)Ùš1=-- K%Ì›|~—t½¢2Øì%7qPÊ5õ€Ð`ìØ±-[¶\¿~½ùü®½—ÜA5*˜úý=Ï™D¡/Cc|ÝÓ§Oc­&ß=uꔸ/ËK®¿PÊ=êâ…ïç9“…ú`Μ9{Œ Å!ŸßeCyÞ—0{Éõ R¹G=@¢Ïsâ[Lš4‰ÕaâScÆŒ! EÔ–ÊŠ0C‘øÅó»¬ëe'˜^\þ;šTî<݉>Ï)©ÃħŒ ù§¼¼<•a<%»*@5jök=ÀyNsÒyÎTV„‰[Ë ÕˆCJ7óª" snƒDŸçR?kpžil¢“XªxEüw6o¾”e>{ÉjfÕ õá7Ìߎ°wóæÍKÌži,£“–ˆ’Š—Ào,Ñ›kÉ·xö“û³AÍñv'ÑÐz€æ{GD ®¥gÃ*:‰Ãe¯!8¼ÉÊʲ GBâ/y¿4Μ½ŒU³ ÐzEì®#ñBëmp¬tÍþBëÔjX`z‚åÙÅ$:ÐèZ Pæ~#ÆÙEs¢ë¨êCë’5]J}RtÊ:´°°P<'I¥ÄîÝ»sTj̾}ûÌ•›c;Hì{ ´@‰†yûùP¢èè“¢+Ø«¨ÊËË›TDiàs’t QJܳgGu 76qÛA*pÖŽ­¿a~uDrô)åRUf•̘1#VT±ò³¾]ÁE¼Ö„Ü0_:Âj)stÕÒ¥K3~ùœ$Ù«I‰ýúõã¨ôF‡±¤ .ÌÏÏwØ©`àrls«lº T£òxõ|(QrôÉã®CEE…û÷ïo˜[b¢Õ걬ÜáÛÕAÜ  íˆà‘2lŒPÁÖ£ªÉ0¡¢}RH6N™Ž„…8 ÅX_CÃpÎz¤ÑHIDTÒÐ hЈ44hDš4" Í‘†fHC3€F¤¡@#ÒÐ  ihЈ44hDÿBsÝ÷[˜ÔIEND®B`‚PKQ³D settings.xmlÝZ[sÚ8~ß_‘aöawv†\Z˜„ŽC˜cœ„7a+ "KIÆ_¿’”‚I©w:ËC²ô}GGÇçfß}YzøbG”Ü犗ZˆLïs#«™ÿœûRý㎾¾"V\ê$"Ï¡r ¿Ë ¯¬/ßçF*pÄ+xW„S¡>$Ûe•ÝÙ•ˆl=²ÄˆÌïs3!üJ¡†áexuIÙ´P,—Ë…èêvªÏ —P@DŸF¸»f—Ö¡äMOEYÏÞ]O)}Z-Xo,¼¤i×…õïílî!|*—š›w¨çK™'ø]‚¼SaÔ܃]¯¥úXöò»ì›ÃÚ1‘R®ºµ‡­Tï6ÊYå‘€ž²‘‹Í°’ñ>')+ ÃwëÉÅ­ûq¸R€Î °¨ŸÛ^+_^DDäªùÒÍÕ§»Â!Ð/wૈE¿Ò´ÔàOȳ8ôRQ»JÿÑt+}ñæJ+ŠŸ÷€ŸGÄ…KèîsÁ0þ°¢5ÒÞØê‰aØv÷Ää‚IKÈU•]“i¢ÅÛæ}ìÁO(Å\õ`Óà7%û:>z› ð-ªX2„ïƒ)ì6E„c,HI¢þvG)ΰ‘ÇÉ7èˆ&“ƒ™³ô©¼‹²ÙLüC®ã¬2´_e»òŸÓ¡¼×ðñãInF"@À>Å«Hm9 tEºÕ6?äÊâˆ6çÑ+ùöñ‡·×5)[媅“?Ÿï“ÉÒ—>R€ßEšuæÐý¹(…ŸCõ¨.d˜dq€=Z§˜Š˜ÞØÍC–eÄQÎú«ŒÄû±rF™¼wÞ8Cˆ¥Kƒ®?+p›G¶Ð¥îQ]¤ - H-×1ræ\ ÃEGÃpšˆ >d Mº.28Ù!F.ä}ÈLÆÂuB,Õ¢N`(dPlßt"§›ð|·Ð=*BÇ9pU¤A|þš:7þŸ éóqÑp•€!pÐÁÛ žPªÖàÕÜJŒ`÷ÃõièÏ p‘K|ÿL“i~“ßóÊЛ4u€Ïïg€p’;†YÒhÿ2¢siWý€8"Ȫjló¨T£tŽa6Mè]‚pæY”Ø»¶ÓS“È`žM'uÎ@¨,*+é›H|”†¥ß@|Å}N‚(Ô¨Mdò´!âˆkGœq À‡ÞúŒJ;½¬žbD Â0[C²P&ò«0)£ebž”–ׄÀ¥ïgçêêÊÒv™LÆ<Û HØýëËœnÊ€?ž—UŠN|ŒÄ¾zÒ´#XÈÚ2Q/0È¥V‡Þi{ꘆyYÒP¨m¦¢Œ¹û¶,z¿¬µz/ÁŠ`¿`øñiÍtúðOA3£Æ<ìZµ†5ÕëÏ hFo¾1(ê7݆´ëcSŸt½«ûß·õæx$¿ç“®½22[Míe¨/뤶O7Úø¹]6ÞàÑÒ—]£÷X÷ÊrÜ\9<•ƒ¾][8Ä\½þ eûµÆSÔ8*¼¡T8ö[õ_PKRr>'PKQ³Dmeta.xmlSAoÛ ½ïWX¬WŒÁŽ#Û•vØ©Ó&-=WДÎ pýûagÎM‘¸À÷ÞûòáØµÑ»0VjU' Ši.Õ¡O»¯p êO¥~y‘LP®ÙÐ å`'\yª²t.U`0ŠêÆJKUÓ K£ºj¡Ð5š†Fóɱ•êW^ë)Bã8Æcks@¸( ª ”³3®LPœ!ÑŠ©ƒE8ÆhÁNo55a×–z#¬¯6. å65g­¥µ>›žhó‚u’$š÷ Úv²½µã„…Lw½ï¹o/fÚ(ÙÝ*3a?¸>ÎÛkâ=§ÈO½q |—bü .bðÿÛçÛžb° õ’²é9ê2< 3"xƒ¾¡¨I‚ˆ LÒ!4Å4Û”è næ .1äƒ µúÇão›Ÿ'ʇò%‹ýf­°õý?èÓqÉ],e0Ù@\ì0¡~‘û8ÏòÍvëW‰ج}JøfÚÔroÄ÷p]”Å8Îcr÷(Õp|>nóhU}î~Ì¡ ']r÷e-‡ädê¯Þ¬þžvÊ¡u’Eá\ï' Ÿ•A¹ ¤9@u‰.†®}ðúPKaªaÚ¹PKQ³D content.xmlí[[sÛ¸~ï¯àp§}ã]÷ÆÞÙ4›';³gÛN_< JHH‚@–µbûÿúKöà]¢DÅ—ÄÞúAs€ƒç Âo~¼Oã3Nhvaz¶k8 iD²Õ…ùë§÷ÖÌüñò/oh“/"nRœ +¤™€o¸3¾Ð½æ†e Š8á‹ ¥˜/D¸ 9ÎJ®E“z¡æÒ-\ì’Á슸É-ð½Ê,i[¼h9|fEÜäŽÚe–´j“=¦C™ïybÅPOs$HGŠû„d_.̵ùÂq¶Û­½ lÊVŽ7ŸÏÕ[ Vtù†%Š* œ`9w<ÛsJÚ 4T>IÛ)Û¤KÌCƒÚÛÕœa$°\©˜Ãjò´ôën5X»îV=0‡kÄë™"n«J W• jò¦H¬{öwæ\C§ú¸¾ªõŠ¥Cç’´-¨BFòÁËÔÔM~Ji%ªdÐÆ®Äõ]wäèçõö(ù–Yƒ<}tdŸ%C>µb¦Fªã›—e^£ýwª†ò+F!¶"&üòŽOU³¡Ÿ¥Üæ["¸`¥Æ?¤Û—þ ÂHI ƹ»0ÿ†rÊÿ¾G©›M£5¼ä°V80ÀÝ1š¢¬E‘B@¸CŒ( tÎÏ{|(¢,SéÂ…ù¯6 bO+ÿ\Bi¯qƒ2Þ+|‡î9 ý@Òå†å8Æ:7®z¥Û'}F%§eÓTÏ!Ö;üýss|;4Dâ;.pú ™%‘Æà=J’% ¿ô˶Oû,2¾g÷€Öèz¨NŸ,ÚÑFP™)„–§òŽê³%o”{Õd…œEdåh…Í’³Ùhåàì1s£•ÐK”WL†2ˆïœ¨ÂM° Dà>2ºüŒCÁ’G„ç ÚAyE…,YŽ(éÊÒ&F ï#„X‹-AÒrF‰i¢cxù‡W)Í£èÄʾ‹Å¯Øž²¬Ê×$,›sÄäáƒz°4“Ìš#Ä¢ š‚¥‰ŠDKUþÀެ5eä7*s %d©Àç $Þ™Â;ÉÖd)ÌTÒ,P³-ÀKVkQbrÆj÷¶úW“D&ÉlÛ¬[,ÕPŒõ6C¹õÝÛÑX~¾Ã+ð \þü‰pŒïµà QƒÜ‡~†ŒfX»XÝÅUBAípÕŸÙÄXÓÖ—¤±ú; c‚cÑ‹Ž¶ÇNç–Dò<@÷Åt‘’¬bpôj+èdÓøŽž\+9MHôȾ‘æÿTÞirþju¸Ý±¦!wv°ÁEˆ—~ª°8ÙI ɰrNð„#ùëÖŸÝB®rëÏo[Z*»íŽ¥ 6Ð#(‡8S…Û0ÁÂrÉCrKÐ\NëÓÂôÊŽ%BAê“F/{ü‰ßéa…]glØôÙãÓìÓk V³—¸'θ7ïÛª#ûPl"ƒä9!8ùí íÈ÷ÓÝf>}DEÞámae0/tïNîl=ßOƒsÐüeeˆ!%`%nÕÒf–*ÓqÊ{óª·x á,íÓ"Ïl$ø'zËM’`aèNÙk3õ£î²äk› óÿý½³1H-gU¥+aÛò·ŠòÐþ›]º¤I ȆK{Ë"]QS¯¥"]˜£ñ_ÕÒ-挥ú_µTÍÃsy °Ä1eX:Љ47Õ#%AK੼ÈD«ÊËC(x4„<Û•¡Ù«DhühùöèU"4y4„‚W‰Ïôñðy¥~zöh^©Ÿž?"B¯ÓO{î£A4~YŽºÑ]¤ÓNï{¢cI£]õÐ,R.ߨBB¾Ð%EQÚÀ³WÕ¤uá¢^©ÖqÈì‹— Í¢¦óR¡ù ©´£Q0ýtå}rÍBŠj|šZ|r¼?·z»P¥­zꗲƖo7ôº.¶Ñ›Ø¾ç—ÕqYÍloR¶ÝQù{§ê˜;…€8[Ë+>‘µÂ4Å‚í±¼«ò–»k¸†ïMÜâ³”v—ƒˆ L”­ª³‰j¨\Ý »6$óUÁÞƨ¿]ã?Æ¥!{x „ЄàIf³.‚c{îÍ›Úþ¸ c`»®ß€²°¿öÌ/ߘ̇€ NÂçÛÁ¼‹žg»Þ´…^àΛJh{ªp/fW»¶¤÷%˜—!ÃHàEáòRðšÎ©¥¨!£iÈØßÓOCFjMå!„ÏNjÈ%JÂZ¹"õ‚ñÀŽŒ§”í†±ÐØÐ÷8^É+27à—uÃ0þåD¬I_ˆVŸÒ‰ñ“{ ¨&ƒ í6Æãnã›ô^Þ(Åz YÜá52¤‡À Ê Â‡ñ@þ‚òÞÃxNÉH¶’Êo¿8}|—MöÂ|×Íú¶Wû©|v§£#nöFàÜðÎr³O½°˜élÔ^Ãhzj ÁYkHHvp “¯q÷^aæu|ƒ– Øyù*O›úuá+ÞNÆœJ¼ïÅMìñÈïø¯ÉÉ ¦Mj’5–am˜mëpfl8˜÷0í®ntD+ÖÙþjÓzäÿ;¯BÕFó cø³S†ï[׿1kÛ½ï·Ì²Â mõÞ_ìùd/Lx.;͆Àžy-Ûõü ºFѺ¡éuRÂq®Of*g¨w­EÖ”;gÎE¦¶?õöä.ß72¦q«0 J¶CBê÷Úƒ …xM“ú&kgÿÎ&:û»XRH:»Ì±;7hS*OߪÛÃõõƒGaNë´Ìéù—ÙË?PK²´:ëD s;PKQ³D-Pictures/10000000000000200000002000309F1C.png­R½J^Qœ`#‚¤R>RÙR&¥Mä3æƒ`D´û –—tŠ/°2uj˯²ÉV>7ØÌl^!çrî½{öoföÜ]œŸíï½Ù°¿ù¼¾Ô÷È{wGïõÏû'`_®NáµèÁ²,ó·ÌÞn·@ëAwÏ_ÿÛ(ŸÛ&DEô¸ˆ@*ÐÍD$2Q‰žd¢…*ôÔb#Ù(÷riº’R+§;i™d‘=eG0ƒìÁ!w$3YÉXŠŽb«ØƒRÉÑÌf5{@Ó…Q „Â誤TÅš’´2¢"zª±į̀ŒÂÂ!wVTEÁRtvTG´6CìE×êÐ YÊbÑ}TX•”jíhË«2{¤C5–]•=ÊŠ°pÈ]=BÓCO2KWëNKåä2{&äZeŒž Ý֥˕<$ÚéNZ=3“”b¨Æ²{FHO[]eø¾À#2ÿ´ê’Ù¦•3ʲž7ÍÏ Ë=~…9” û6ᦤßÃÇÆÿXÏ_WúnÖ¯n|{y‹Õ§ƒ‡w«ë÷—ÀïëãW^¿üqäæô|ýëäæû_PKÏ£€ï¶[PKQ³D styles.xmlí]Í’Û¸¾ç)TÚÚ­ä@Š?úõx+»[NRe;®µ79º ’¸¦Ifö”7È!‡¼_ž$? A )q$y†ã*ÏÝ º?F£¾úá~öîp’$ºíÛ¦ÕïáÈ#~-oû¿~zcLû?¼þÃ+²X¾ñ‰·Yã(3Òì!Äi*Gé 'Þö7ItCP¤7Zãô&ónHŒ#YéFå¾aMñö°ºÕ³Z;Ã÷YÝÊ”·PÍë·Ì˜ÕÚ~‚¶u+S^ÀT­¾ u+ß§¡± †GÖ1Ê‚=)îà úrÛ_eY|3l·[sëš$YìÙl6`Ô\`/ç‹7Iȸ|o€CLK¶i$ïg¨®|”W)Ú¬ç8© ÊP©Wã§ÀêÒqYïAjÂøº[Ö]wË ˜½Jj3Æ\*®_¨¸¾Zw²UEÿNï€Èþ{÷v7®’uݶ(o*/ âÚjrnµ>!$•Và“‰ëXÖpÀ?+ÜÛƒìÛ$Èp¢°{Ù=z9âd­ øìpøŽù\ïuÖÖx+ Š‚ÚÐSÞÒPM(ø•Ž ŽI’å€,ê]hÅÉMÆ*[‡Õ&ƒR%ë2ñ}-+ˆãÀ|Àä5î¼ý¦_X „ÙÞ@`¦õ±*ŒIµ½+ØÖ€òäÓ†Æn¡H–ùR¶ ›ÈçýÀÄ÷1NJB!«vSx‚Ú[!9â‘býSžP03iêf:¼?ý2 4ƒ.a`¤ÅS”•Ûé¿–Ëô‚À½@6|ì…éëWܼæÅ=þ™ wÛÿ1ÈÒ,ÁhÝû‰Z-:ÝÀ Jfë·ýïPLÒïKœ¼¸ß+<žÖ0–8a¶&d¢Gdس;”¬C ųO’ù$‰ØjwÛÿ/7!JžVþ·,…l0ô>¢(­~ïоÖóMÚû…>§÷žÌzo+¥+³žQ@ŠÇã²q®sˆõ3þ ýcs¸;ž"¥i†×'É”Àç¼Aa8GÞ—jÙʼg‘ñM‚qh éT UFP”ó­ËëWtu€å ùXƒûÄÅü‹(ûìXŸ'}Nñƒ4уQäèI²ØÁ€¯©=e`ƒÀO xÂßXìG`yÎ öS¨DŽÒ \lËúV©¤§ hI[—OŸ“ħÞ7ÐB͘T ¡Ó©‚Ãýÿg¼„HéŸÿ |¬UšUé G=ÁÜS8…þi@%eZÍᑊèfÑ2GÖÔ[‹ò„HW8²ªÅþ+- RÚZ¹gŸ"”åhdÚI´Âпm‰ hÙŸZ0Á@Ec²›U‚ÁwûxÙ6-ÛRå·kÍÞØ?™q´”U³‡˜iµŽ™7ÄÊÒu¤1ìº|Y„àÑ(N½%ÈÏ5X£ä NTéÿœ$dËç$uä~$÷ qÏê9Vϵx9ì]Ö6”6-[9Öïùó`Å%_`Ž¡´ÐS?ÃgЇ£ÅƒR{N±Ÿìe’™d© C\ýh„8ZÒP¡(É)r:œûüˆo`.³©娧}v¦ŸÁÐ|vfŸµJÑ=ÎÞû#0þé8ýìÙäے̬07¯>^ M(¢0Ò K -^^_òŠÏFœ€‹œdLܹÙB©Ab>¼#bÐÏ»çÇ(A¬žZ‹“¨ûi MFÒQÁÀΊÂx…¤qŽ7ð|öìÝ€åtj)9øj_€’uÏ$…nù`ÆkâS‹šÙ¼`ñƒÈÇtC£Pì)T­Z 0Źް[|HœÒ%¡Z­œêUÒv“bc -’­Áæ#K6¸ Tµ?X3Ž4ø8œaœ±²lö¬LÚˆx°gÈè¿_?–žlÀöEû~ÇŽ‡>[òðÈ¢Iû}%)¢5Iøé}¹MºÁ ñý#­æ\Úvsê*Øo9'ýí}×C…-»Fåh:+|”øýæc_™òð~¿·o Ö‹š?AÛ¾4+#jW’v]á¦Öà‹z^Ùus›T`ð`DÓe›ã]úÔg6]¬ŠJ²åKëy0Šô†ŒjGˆñ±uÙ¨X’wK¤Q¹:*V°Q¤±©À÷é U ð#Sœ÷¬3öjH⃖(‘ŸZô SÁʹÊâ;rfc¾ Cœõ8‘–³…}ä$ƒ†!oûÿûï¿ó¡Â@ýø°ž“°_Ç@mßpÄV°Á!e¨ê¥*¯ÃÖ.cŽ$aþÀ˜v£¬ƒÈÑêäómÌ}…¯!·5„lÓy– [Dhú,µ†cŸ%BãÖrŸ%>“öðy¦vzÚBÃgj§g-"ô<í´mµÑèë2Ô YìU›¿ƒá h¶SKª0ß(ˆ]‚(LŠ;QÊ7"Ų|"ŠYBîdxÔJr cpÖJLkG"XE²ÉhƒùFP!1A²UB6Ë•!‚R‰t‘ Ý¡Û~ßÖ?sãÆŸÜΙÛÞH±§"¬²kŽª–¬Q¸[néT•a½ðP’ Š|ÜVt|ž˜N8e Ø~G,ø¤ =¸Š ®æG²fÕÁˆ¤ïp«ˆqK]&¨EÍP0Ô‹! ur¾# ÈëV‚sTóT‘Ó«¡¨`a# ¯ãâCµ4áô, 4,ÉnTê„-ØÙ%¢öH$ÌÃ^¶ 2˜¼ü@P“Q]”à½ù¬D)ÅÜta5»qT-?¼8o›·ñ‰[m㦹)šÜØ<%œÂšÝi0Ï·ÚŽP¡9,@4‚÷„ªó°&›µåû;“† ©ŒôwDèÿôYô74½+¤“J Z<âáéÑgô"Ò£µ{P•þ­VzÂéíÀÑ8PÃñuH9'þÃ%%=ìà ¿c «Ec­~Û¤0EpåéÅù´«r„ù!_,am§Ò‹‡æjrçöz•làíu¹ª G…5 uòpØh S•ìKèTy–eñõªáÚèZKÄòÚXqo£nw8Í»ÃyšîО~îŽÉöÎ=o6»®>¨3Éy+û›zÓ®ØÖçMÿ6ÛÙ;Ým´˜¬0ò/írÔ‚^ 9tªàtìú5›£‹˜ªËTŒ†ÈðÅœ„~sèžÈ¬\-tCM )È`’{§"ºÆ(Ý$瘯vØ–’âÐtí83M≶fa­ÖSúWšu0ê›(ÈÄF¼n?9MìÀÏ"«ˆ&:/úåŒý^P¿9vâ¸=:Áå‘°6àx|Çžž„DjŸ1ßæ,G$ç¡Ú꾆Ÿ™ÖÜÙ\Û1ÄÞ÷?ô'íýcßé°ºÓ…“N8€*‘-o/ït¡ˆg{º m¢°%?¼õe—&¦°¾mó%¦˜›»(fuºJ‚è ý Ťb–ôxò”L}žâÁ ¡Ù•Ì_ “Ó6GÏ!}&ç¿þsLÞÁü—éÙš\k&çsÍ¡Ògr3†®&A¨å1Ô^&çø™f*¶—Ë9y¦yxíårΞ%>íerÚÖ35Ô-¦rÚöµ˜êKårLÐdÞbð(u–ët“À.àQÄK x”NÏ ê#M¼¡k7lpÎZJƒUÃyZâ.È5=ælF¨ê¶ƒ˜ÓbnÓéJÄ´ÄâwçElØbn;ˆ9 +C†ŒËÔcµƒØ°Äšd?\ ±q;ˆ^b“v¿Ħí 6y9ˆÍÚAlúK7smnëPTq@w´¦‡B™ ¸|?Ä5Ï™rq»«?º«?º«?º«?®çÀ¨»ú£»úãüÇEÝÕ/õغ»ú£»ú㺮þ`ŠŸòµŸh(»ƒ¥°;Xê–ºƒ%øš¢]£ at!Œ.„Ñ…0®¡.„Ñ…0ºFÂèB_}C—èBånÑÝðÐ… ê‡ †¥\¶‚¨â™„ Ô˜‚ÓKBô† °Óÿó[ë“Cs” o^ŽC0È+ÂTéüʉÛþ ÍÙPðî–74§Ã´Fyõ'}µ9ºò³0ݶeŽFùý òÛ½†e:®ÈÒ5œoö'«ñt“1Ãú“ÍqÍ™mïkåš#kr ²JöUU÷NÝi-l­ ì`ï…Ÿâ#½#€¾xÛ3$AúUzÐ?¼³úž#räŠÅuΚbå&Ç6G3µ\bâLÌsz% w’•Û>}gx‚5qN7+°Pquž­ÀÖ`ë°L×ѓз@9”ýÎK—VÐ9}m}@Ž‹ZX ¹ï.]N(Ck»wGÕ;G…J_Ji¤Pa‚ËË‘émq»»´µ, B²GXXSÑf=WÞc§eôQ›Ž€Ý}Ù莦wËärw>ö¾Ê»Kè䀙‘vÓMõù2¹Ü5~i]yÔÄÆ“c—GDÃ4êò•j×2N†ÃYC,NýÂÚõbÑ|\œúU´scqé™ô¡<‘d¤ªÿXÄM½}³"î 'î^ÜÑè;tï>”GzIØ:6ùÍî=vå±{”vÍn­>£‚ŸJcŠv±av(âÝÛ3\vM!í.¢Ëèr ®¡.¢Ëèr ºˆË"Ôå@t9õs ûÓι®ßý °ëœíÎÙîœí«A¨s¶;g»s¶;g»s¶¯¡ÎÙVŽ+óbaÒŒ½Œ—²c¤=Ð"úÄÝg~ÂÄÝtžYAÒÓ•wqÕà‘'h•¬àð‡xÿÍ‚d\ƒ}=8à" ÌàJóªRŒB6d~2¸O§‰Dò ï!?.dBèEE–¶òNÙ±ÛNhjVÕÌtdzRR•éÎÆ²ð^¤›ˆÔ,öw/DiÊ߈)9“kNîÅŒÅLÙTPaE†Oö~jo#Ô´žü;–=¸ky°Ãð<Öñ´Óqê`š'¶4Õi kÞÌS ë\j¤:csÄ3uÐòü£§®¼3ƒúôÃõ0°JÖV룖Wß5ðú»0ûžÿùÝ2û^b«0 ={F¶‚‡D(!êˆäKÑ¡9-¤SXbEo×®Ìy³óÕë|âØ6Å=øçnzfŽgîùš¶k¤é‰ 5näKí+ðtÎt‰„ÿGÅÓÝópÈá±õ]tx fEeÝ»õ¢>"öØN'C7vUHÌ™=V1]gXeç„ U™ïÂ'ß³€ƒj3ÿ¨Ò»—æª7tôäÞŽ9³¦Uz 1Ρ9OÆlÅ{€­ýxºƒeŽöÿÔº•ëÜQ¾Ys¢5ßìH”Ý&(Ì©5~ å tŨ.ÊÍÝ4÷BnÚ‘ø6r×êâ¡i»µþêݵ‚RìeË7Üúµõ Vל•ûʶÌáD]…]sj,¯íìªÜ9¨¹hˆ·O7¦ç¤ü5+ÇMEnt4S—JWVÓI.¤8ËŠq±ýæ3ˆŒ‰k!ia·‹”\Ü.brâ<(¯ÁùRÙ,îŽöNd±O¼Í:ÿúLúúÿPK½"úÞs¼PKQ³DConfigurations2/images/Bitmaps/PKQ³DConfigurations2/toolbar/PKQ³DConfigurations2/floater/PKQ³DConfigurations2/toolpanel/PKQ³DConfigurations2/menubar/PKQ³DConfigurations2/progressbar/PKQ³DConfigurations2/popupmenu/PKQ³D'Configurations2/accelerator/current.xmlPKPKQ³DConfigurations2/statusbar/PKQ³DMETA-INF/manifest.xml­TÁŽÂ ½û ÷‚º—ÝÆêÁij÷X:­$0ŒþýÒ&j7Í6+˜yïå °Úœ­)N¢vX³Ÿ³P¹FcW³Ïî|g›õle%ê"U×E‘ë0Þš¥€•“QÇ ¥…X‘ªœlœJªŸùÕÀt‹F–l=+î|­6Pæúp¹g·É˜ÒK:ÖL<¹o[h´,éâ¡fÒ{£•¤œ&NØðA0ëä>@ÌóÃÄ-‡c²_(µ‰‚®Kî±{ E[ÙèÏ'±D Ê͉<ú™àL¢?žläËA•Cê]}5î^+J¹Sb1åh~›ìÛ' ˜è;] ¼Þõ­ÃVw) ÷-.…T äСRÏÍû×ILØKàIs5FèÉWâ×ϰþPKxþ+TPKQ³D3&¬¨//mimetypePKQ³DN馔”UThumbnails/thumbnail.pngPKQ³DRr>' settings.xmlPKQ³DaªaÚ¹—meta.xmlPKQ³D²´:ëD s; †content.xmlPKQ³DÏ£€ï¶[-(Pictures/10000000000000200000002000309F1C.pngPKQ³D½"úÞs¼ *styles.xmlPKQ³D¿:Configurations2/images/Bitmaps/PKQ³Dü:Configurations2/toolbar/PKQ³D2;Configurations2/floater/PKQ³Dh;Configurations2/toolpanel/PKQ³D ;Configurations2/menubar/PKQ³DÖ;Configurations2/progressbar/PKQ³D<Configurations2/popupmenu/PKQ³D'H<Configurations2/accelerator/current.xmlPKQ³DŸ<Configurations2/statusbar/PKQ³Dxþ+T×<META-INF/manifest.xmlPK‘E>bobcat-5.09.01/documentation/images/molds/sharedsegment1.odp0000644000175000017500000004151014050437223022757 0ustar frankfrankPKËK³D3&¬¨//mimetypeapplication/vnd.oasis.opendocument.presentationPKËK³DHQßßThumbnails/thumbnail.png‰PNG  IHDR€k× ]¦IDATxœí{lUÆZ®‰@ ,*Å6E¹ Dklµ oE " ñFL ¹Ø‚P‘¨Z5`ñNˆŒ’¡-¥ ŠT‰€ ‰zõ{¾¾ôp8sÙÙÝÙÙeç}þ؜ݙ9sæìyΜíüú¾ ÿý÷Ÿ`±üª„h7€ÅЦØ,_‹ ÀòµØ,_‹ ÀòµØ,_‹ ÀòµØ,_‹ ÀòµØ,_‹ ÀòµØ,_Ë©.¹ä’ˆ¶ƒÅr]N@Ï î̲."9œ²ƒ[Å÷}€îCý ^GI|{›e¥(ü~ûí·§Nú믿zjKS pÿý÷?ðÀÞŸ7tâĉV­ZEåÔ<ï˜ÊS|õÕW~øá 7Ü`Üô裶mÛ¶Aƒ_ý5²~ýz”?ŽÂ}÷ÝwêÔ©uëÖa–””ôÓO?]ýõ8êùçŸÏËËC¡yóæÃ‡÷æ*þúë¯7¢a(2íqxàž={FŽùôÓO:´uëÖ‘l£‰ü<ïØÈSŒ7níÚµ©©©999Ú¦§žzª¶¶ö‡~xî¹ç6mÚ´eË–fÍšuêÔiÇŽ(4iÒ#~Ú´iM›6Å4vë­·ž}ÕUWaÌQbÄcºÅˆ‡‹:·¼þúë•••eee(Lž<¹ªªÊõ8p€œ[>óÌ3d¿-Z`Lc á¼W_}õüqÇw å÷Þ{/†/ ðÈ#H¯bë]wÝ•••h•›zVGmTƈöÙgzÞØ†Ï>û¬¼¼Ý£Âê¼£¶ <6@~~>Fù„ PÞ¾}{Ïž=å&, 0â‹ÁÀ‰/iذa˜Ï¨‘‘ñꫯâmff&vÀv÷Ýw§¥¥aLTTT €á‰’ÓŽ9"í÷Þ{ïa®…9—,Y¢íO"S½jüãÒÙ³gþßí¦žWË8už§6০²:ï¨msµ«.Vyj€Gê„Bvv¶¶INøšÕÏgΜIL`˜Þ¨Œù @‘k-ˑӒ““¥ýpÒ+V`¢½å–[¶n݊ݰÞu« ¼âéÕêêjQ÷ˇ>Ç|ܯ_¿¹sçNš4©eË–¦ž‡Õ—.]Jå)S¦8ñ¼± hÛüùóQ@KÄ…óƽ¬Sv£ŸMkhYÆ#Š-±ÒÇLÕiƒ *((øå—_nºé¦ýû÷ËW¾b K¯ åá V’•çau¬[´–Øx§3¶A•ͼà Úz`„Ån$ª„®¸â ,ôñ#röìÙÑn +\g€x} ”Œ?gY¯‡fùZ Ãßß|(†áÎ)¾½Í²’ûK o˜S¨æöÛo_·n]$NBÍ‹/NHHèܹó!C¨µo¾ùæ´iÓ~ûí·€Ç:ßSU¤{>Š Sä侜3'®@5¯½ö>ùä“OÊËË#4ú¡`kþæ›oм¥K—0@m­ä ìõàƒ:ÜSUÀž¹ÃE´A¦ÈÉMذnaB5Ø9++«K—.’«‘PÍ’%K6oÞÜ«W/ì‰pòäÉ#F¤§§†Ã½È6£~\×Í7ßLÕîÚµËHÔ`¿IKKÃh£§­ô /|ÿý÷˜ã•È36oÞ\ÝS¥††>qâD ôýû÷£f:¼GZÏ«U%&&Ò‰ èy :oiÕáÚUÄÜ4€ ë>Tƒ!bÊÕÀ˜“òòòÆŽKwÿåË—ã,xÍη{‘m3f ƽ¬VÔ=ZÒjž4i’ŠßØT;sæL e kc%òŒÄùÈ=Uj¨´´íÁ>è¨ÌÌL:¼M›6ZÏ«U]wÝut"Q÷l›:\˜ADeee;<Îä¦lX·ð¡cÕ\~ùåëׯÇ Ï+**pîÔ©S˜Ü‹lóäÉ“Õj­¦â7V­E]duuÚåž*5D"&BŽ9^ëyµ*¹'úʪéý{L^EÜÈÍ‹±aÝ„j‡ W#¡Ô€A‰©«l:|ø0¦.Lc˜5ÕÃCà^d›±hÆÊ +à  ZÜ Œ5ã¿Á2 ¯ÕÕÕÝ»wGZKë=Ü(ðZUUe¬Džׂ3Ê=UjˆnAp£z¸±çeUÍš5KII¡=7nŒ;u¸°€ˆ¬:\™B±)7 `Ü„Õh›$Tóî»ïj;àçš<‘zx°RÛ¼råJµý÷ÖIÝyDäÛ®]»ª·ÙZõ°8Ñ*1öí©QC?ü0^{÷î­®õ¼¬ŠD{j"Ò>WA¦¸QogY7†j<w¸QÁpY7¹‚gENqü[6d1 Çòµ˜:/¶·Å,Ð9Å··YV ëG°»ð‰±¶+V̘1C"1¡2¡,öç ¶%¡µÜTD%É‹r)ÙtB°œ’[в(,„O¶mÛÖ¯_¿ùóçWWW¯Zµ*ØÚÆGò# ™òòòÁƒïÝ»7))©¨¨(77·²²R}þ2ÁbOãËê„Æö˜ Ã]½(ãè7?6§d.‡ÆY¢¬°ÂK$@Ò·o_|ذaÔ”qaPšo¿ýVò-'N”µ©ÜKii)>A7µhÑBþICh²²²V¯^Â?ÿüƒ­4úé‰,½Á¢uäÈ‘cÇŽaO|ssæÌ±¹L•ðiÔ¨‘ ÝCg9sæÌèÑ£kkkÇŒ#êõÀ±ýû÷OMM]³fÍäÉ“gÏžM®D=Û“““cÅÛÐnÆ0¶ˆÿÙ¹sç®]»Nžù¤FãÈØA*4ü±"¦D hÊ4ØÚµk%Î$ÅÂÝiÖ¬YÆfF¶J^#¡'^æ, S‘2€—´œpðÝ+S¨IݤA/Ba–TæÔ©Sã¶4ÎèÑ£¬ˆ)qaŠ1#4eš ,77WÅ™ìãÁÛ¦)̨*Ók£%fÉÀ¨}ø -à1%AS¦Žš‰LŠ;¤žZ;Pc«ä!eÓŸ±£HÀKZN8øîƒ•5©p@ô"fI`ˆ±ÁQ½{÷†ÒbIàG=ÜŠ˜Ú¾}»ºI…¦ŒÄ”¤Ndö±6mÚ…ü1;d•ÂÌÈVÉkÄšP# ¹ç=V¤ à-×§Oáà»VÔDß1ÁEâB¦ÅóhQƒÔMZø u“~Ô€?6Ä”,H­Êêö¢žNawÈ*…™)[EõhÁˆ. EÊžÑrÂÙwÏb™Ê ›i9VÌÊkè"ÊÉòƒ˜bùZÌÛÛ‡bèœâÛÛ,+yú/ÉÁ¢AîF§b±ŒòÔÑ òòò¾}ûÿüóÏ;wî,--u1:UDå:êb¢HžGlä‘lòçit}xüøqzÂ% ùç4¢Ë4:•7¥Ê- ”‚ PÒËE^¼óˆ÷òÈ6ùóŒtÐØ±c›6mZXXøÄO@¦]¦Ñ©Â—Ñ–­©©1¥AE=“‡vZÑ ÂàgJÒKzZ¢H9w\tóˆ÷òÈA¡AøVHàIÈ40Ë4:Uø õLÞòåË­hP(<›LzIoÃI óHìË#ØäÏSé … âõ7ÞÀWõòË/›F§’DWûöí…EtªHÈ Õ@ Œ0{TØ¡ZÒËpEÆÂ<ûòÈ6ùó4:ˆ¦+ ™F§’§Mtª0¥A{h¤B1J„%ZN¡V4¨°BéZ(é¥L.ØD‘VÅæ<kŠNdÆØ§ƒŒÐžmÃN8P •eÍÃ6@¨0KzZ¢HB5£>ľ¢c€Øô,Šc±|-†áX¾Ãpç¥ÚÛæßvYñ$†áÎIó6ýÅPÄïõ²HÞý¶OHÑv xééémÛ¶¥OŽ=J”¤g™á‹†>ß â[ÞÀ> d@"EÛ!;;ãrÆ óæÍÃ:tè Aƒ0ôQvË,?È ØpÂÒIbF™6 ·”>ø…Q£FQŠ$+(yaN’@:IÌxå•WÒÛšššŽ;Â-ðàBXñ'/ `OÂiI …ƒÄŒò9Z§N~üñGŽBdÚΊsyaN\Ój×®]**#,3b]DÇ.Z´héÒ¥TðàBXñ'/ `CÂcZuíÚUEeL3ÒÛÒÒÒôôôÁƒÓ[ùW ˹¼fÜÂàŒšlÛ¶í˜:…\'ˇòÚŒÁ±bJ ñ|­ a¸x}2ÊÆö§˜bùZ¡,ØRÑ õB0«¦ú|Ø2ë5U©Mýûï¿ÝjRˆ @V7½`³Ú‡è‘e›=jÈ ,BŒÙ)ÕABIV9uêTúD6Õ­&ÅØ.(öã|±¬ÄpA<è/^±þ/þ¸g 6Ëçbôœø&àO1 wNñjl–½x ÄòµØ±(«Ô‘AÉ&q¥Ãœ–'NœhÕª•ñs3XF]l€˜“1udh²I\é$§åž={Fމ– :´uëÖÂ¥ –Û¶mëׯßüùó«««W­ZEo‹‹‹+**ºuë6~üøÚÚZ\8NÑ Aƒ­[·öïßÿ­·ÞÚ½{wNNNjj*>}²²²ÐÓ§O§”mBQ+q.6@LHËÙh”15¥Zå´”÷ŒÙ)i>‘§ÖrQjmp1ƒerr2î0²fØlãÆTÞ´i<‰EšJ\_sÍ5”O êÞ½{UUî 0˜Ú<µçbÄ„´œ$I¡e Zí)ïiÿÛ@›ÔSëÄê¿F¨ìbKÜ…fÍš…[½E« tèС?ÿü¶Í0¾<(;¤¦¦FæÄÎð<ùùùj²’:Ø÷‰*6€<{8 s6fdd­‰%2f\,siKÕÔ”¸H?šÅ…9-eÍ2q¥rOnÂRJžZÍE‰ÛÖX\áÖѲeKáRKœ¯ÇŽC# iSRR§¡«q%'B’â¼;vì šËÊʰèÇ]‡P8d¼=sæŒZ Îå¼çÙ–òòÉ€iêH9ú…25B „|jvUßÚd§”Ÿk¹(%ÎMr+ƒå”)SD}.W­%rìN­“ñŠÖ …9sær‚øI°¹Œs??*ŽKq’{…Œ#Jî ås­p‰C]Df÷…±Õ*Þ>Wÿ¸£//È—:‰(r(„ìÂÏäpÂ+ëË÷…€‘ ñ äáT¨ÉvXe·w%"[·,1"‹ûÂ\¿R*…ax~:§lV*ëº^Š®n»ú r Ddðq„»cviJ^ÐìX”uïÝñ”Òw£Õ€õÄ"Ã/4í²´þ½íÍ=„åR}‹õ|ióÿ°V€ ïXÕ÷`Ök«>¶]·}³Y;.rQ¨nýaëÕ»Í⬿ŠH@OùÈÙ¦YÙx_”•WÃwï)ÄûqŒ¸ZƒA`Q¿°½(V¾¼ˆˆ(T‹å›ÛÛ»Ò!Ð/wወC¿)k™±Ÿ+æqàåÛÛ˜þÑlk|ùÓÍåå±øEøED\¸„î> ã÷*#Ý­Ž±†wÏL.˜t„BU¹E9ÝJ´r;|³{ðSJ1¤P}˜Ã,ø-FÉþŸ½ÃGøU,9ÂÀ ö›!“X 2’¨¿]D`"Å &ò8ýÑb²1w–•wQ>“à€?âbÈ ‚UŽþ«|WþÓ``6’÷NÞžôÐÄÈC8 x-[W6CÑÅLWZÊcµÃ¹òØ¢Í~tÁJ¾}|ÀáõeMÁV…jéèÏí}:[òŒàw±¦KtnJéçP}j¦yl`ŸÖ)¦‡&fwv3ÀåqÔaýEFâýX9§LÞ;)oœÄòHƒ®?)p‡G¾Ð£nâZd - ÈU®cä,,¸M%†á,4A}È št)ä°³#Œ\È™4Œß„£åÚÞ,—EíÀHÈ ؾëD‡nÊýÝB÷©8§ÀUañú5³6þæ zÎ9ÃUz¥\§€q˜lýÅMʵùþí™Ð[Rº&~ý)â(äd«3A+½ýµ/e9r4 ¡‘øŠgÉÁ½s<ÿóxÎg ^EÓ$J¯å‘Ñ)ôtõ„Rï‘ĈƒclŽiÜ­ $]Þâ;p(ޝ*­Åí_)/¾WcYpz]QCBNÔR¾06» µ?ÿ ¤oJ|ÂÏ9¦c•2†©õXzªô© w–¤<©ì‹Ôuê™9éH€ÏSsº)9á °´#¯&Ò‡¦7…n‹ž*…M.áµ(›"×…äÝ7²ôºR,1ÙÄf# IëXâO@RjÀ8¨àmPHUkp†ˆ*n¥Fh÷ÃñYÑŸG@à" –úþ™¥[ù¾ç”¡7éêŸþœ}ÂI0ÌÓ†û/ƒK¿ÄA^Yc‡G ¥ ó)BïÔ€³È#ÅÞåø°œž™Dó|*©ktBåQyYßB"¥;’ >ã>%AjÔ$ryÚqÄ•#N8…Ç@àÃÓú„juúy=ň,„a¾Žd¡\ìWaRFËÔçyZZ \—¼¯>NUÕ•¹í2)Æ<[ HYýHM7cÀŸÏË+ E;> Fby²”#XÈ:Rƨ÷¤@é‚Õáé´ÝuLâLi(Ô43QÆÜ}[–F} ke­ÞÏD0‚"ØO~|Z3›=üSÒÌÆ¸±{V­aÍŒßú3,ÛÃñ›ß–«^£µË¤®O†Ñ3üï¿;Fk2–ß‹éÐ0FžŽÌvK{Ë:©­ÀÓ•6ùÚÑÍføhË^³ÿX÷tÙn®ìžô``×^b®žŸ°V÷ú¯NcçM[Ö½òÜñ\ê™s@ì7·]ÆS2Ô{õ0ì6 .­ø6½X¾:ž‰“¬Ž&9ߦmûbòêòz8iO“¯ÿùb¬÷†ßû»þ6±´°ŽkCiÛ딘6͹Ûn~·[db÷}语¶­¹m{%ç72šýe×jvKoÚv­gÚók¬7Íá¥a¶ì¡Õ´Ÿ¿–íÇ‘v5°µË”OáFàÚëwrISžÇAüþ¸"^1l ×éÀǾ+eš‚ž= Ù’µBbá¨tð‚R)é¶ê¿PK_ÝîÛ@'PKËK³Dmeta.xmlSMsÛ ¼÷Whh®ˆÉŽÅHÊL=¥ÓÎÔ9gd ©@±ûï‹åʧã#¼Ý}ûKùpìÚä]Z§Œ®I1H¤æF(½¯ÀÓö+Ü€‡úSi^^—L>tR{ØIß$ª›J¬f¦qÊ1ÝtÒ1ϙ饞)l‰f±Ñtsl•þUWï{†ÐápHYjì‘¢(P¬ÎPÁϸ~°mD Žd+Ç‘” ;:¼ÕÔˆ]Zê­t¡Úø¸”Û4–œ¥–1ælz¤M ˆÖ)Æ9šÎ3Úuª½µãˆ…Üt}è¹k/vÚhÕÝ*3b?¸Þ[!Úk]—‚³ÙRñ ’"ˆ³ 3š¥÷9.ð†®‹ͰI{/µ ÍŒ­ÕÎÊïq\”§$]§ôîQéáø|ܬ“Eõ¹·æMrr‚;|÷eP­€ôdê¯Þ¤þžnÌ¡óŠ'ñÞìF‰•Aû ä ºDËF×>xýPKôý;t¹PKËK³D content.xmlí[Ûrܸ}ÏW°f<$Å;ç\»ëõ“äÚ²œT*©” C‚3°I‚0ÍþDóù’à H‡ÔŪX%=H$Ð tŸnt7@èí»»41n!¡gë‰k9f!ŽP¶]Oþòùƒ¹˜¼»øÝ[Ç(„«‡ûfÌ qÆø_ƒsgt¥zד=ÉVPDWH!]±p…s˜•\+z%çR-”“Ñì’XçfðŽe´ ^°?³$Ö¹#c™-UgñXæ;š˜1樧9`¨%Å]‚²¯ëÉŽ±|eÛ‡ÃÁ:ø&[Û].—¶ì­+º|OI…6L ˜ŒÚ®åÚ%m +Ÿ ÕEÊöé’ÑÐ:VÍ ¤œ„«+sÜ@:Oÿn·£½ëvÛs¸d´ŸI⦫øÑxWñ#7l×cß…}Å;寫ËÚ¯H:v.AÛ€*$(­¦¢Öù1Æ•¨‚A-v)®ç8­Þ5êÃYòA <ÈÌÁNJN½ÑÌy°‡„!HFA/PÞ‘Êx~§HnÜÙó ÜG†7_`ÈèYòÑ<G¾½ÂLlYÎHéÊ­M ÚGÈs-4J˦Dçðòž¯RšÑ€fÿÊoIÇY¶ä;–Í9 âðA¾˜ŠITÍ QMÁ¢£"Ð’;ÎÌ&è7,j $hËK/{ÊP|œ´o{X“¥ˆWž° kÀänvàð¢íŽ•˜ÜCÛŽ©_´¶þýµUË÷€ØïYŒ’dPm^¼à¯bº›èM¦háAeðÆsnÞó7‰§oqÃcß·¼QAµ ? HlºË™†i1T ÈWH¸ˆ¼4ª üÙ¢MÁw;§û…ëI†3؆¿k§f²”g¦s#qlg2œ‹y]_Ϋul0cbS|ª/1=ÞÌoõeð²ë&¾¡ƒ—–Ö°¦œ”€ì©È5YÄA—”…a*àe£p¤õ$˜þ^ª~N™{¨ê=HUÅCs±+ØÀ(V×L,9Ù#%ÎS-½™r•ï!ÿÉr-ïE"ªçÂs»f;ñÅ?2·§‘£$Ÿ®œÝ1ÃsgNñ»ö˜s ß_‚l[m«¡ryUäÊÌ—{c£þë7>JéÀ5AïN­ùtÖFбîB‡Ðò4=Ë]øÅâkÎ{ÝP¸ß'¯ù"(¼;…üa«·!ÀABJ_±~Ö¾å.Ç }‚ ßê®öœâõÇ¡Xî|zÔ_¸×ÄÛ›kˆÏ,OÚcñM‚ïÿpþù ø<Ü[hˆOyâåã? È_ù#CÊb ÜßO˜ ì$ªþCP½s%ZAPáÅæ–3«"Ä')êRúè H=Þ¬¡íJ¸o%çÌZΖm9]]NN¸m9Ý9cÂg?%h0èŒ3+ðý¶3º–ãÎ5gœ[Þ´±÷°Ü©ª+j6ø®ñ¢(— UÅ)Ž´g·xìZ…Ç«3·µ¤gÔqüPß8‹àœ:¼ì7pl°4¸…†Ï¤•ëXN°VËuf¡^ý9{F-™Ãf†¸²­Á°RòYµ[XËn<R.àÊÍÎ(§î «‘¢Ê2Ä $ôٜѓ…àbÓi3³ÎÏ9c­ØµtÅv‚ýÖ¹CŠ®FËÅRÓ¨Œq}UUƒ5ÊÖÓGdkÇšºA[eÏš×ùFªìÏMe^z~øD4ÛdÍ#y?Z%X=ñºÎ¢ÎâBAq÷AR¾‹—Æœwò·•ç…æ†/‡2ÓóbÄ׆8‰jz² øÙ˜2ÝKJ>Eýäò¡|ö8aùìîÌ“OA!»xªÛJºiõ4ÓFšk#-ÔäÍÊãcéað_{ui[;0Œ«k9˜¤û¬'oÃöê¢é{‚ç<‡×æz™ƒlþI6éy¾ # ;À1=5ÓŸ†gšäTlÞf“¦dqšoXÎå “ýÑײlß]Nýƒw¼¤œwYÏËC”qF=óÕI‘ú·Bå¡oÊqŠ~‹jhÍe(Ý‹ s=ýàNõ ÷7¡\ÊÆ÷‘ª€S—@u¦šD>Yêu{_>ÕÏ\Ïý|7øgJ[†øŸˆ Þ„€YåÓ/?¾¿úedVi|!— N}jðJ äg¶ã™9(9Ål¸ÆóùÞ [ã9V0×?ø|ŸØ<À–‰Æ¨å(oT»­a(U_N*ÏR¦kérçdÄw QåtKîòFW)7tª\Ý‚í”êÞYëCM³Õ'õÍó–ýí–í®K BËÊ2Q·n¼§X|«nû×w”O~ª²_³ìžq¿øPKOè&ƒR #?PKËK³D-Pictures/10000000000000200000002000309F1C.png­R½J^Qœ`#‚¤R>RÙR&¥Mä3æƒ`D´û –—tŠ/°2uj˯²ÉV>7ØÌl^!çrî½{öoföÜ]œŸíï½Ù°¿ù¼¾Ô÷È{wGïõÏû'`_®NáµèÁ²,ó·ÌÞn·@ëAwÏ_ÿÛ(ŸÛ&DEô¸ˆ@*ÐÍD$2Q‰žd¢…*ôÔb#Ù(÷riº’R+§;i™d‘=eG0ƒìÁ!w$3YÉXŠŽb«ØƒRÉÑÌf5{@Ó…Q „Â誤TÅš’´2¢"zª±į̀ŒÂÂ!wVTEÁRtvTG´6CìE×êÐ YÊbÑ}TX•”jíhË«2{¤C5–]•=ÊŠ°pÈ]=BÓCO2KWëNKåä2{&äZeŒž Ý֥˕<$ÚéNZ=3“”b¨Æ²{FHO[]eø¾À#2ÿ´ê’Ù¦•3ʲž7ÍÏ Ë=~…9” û6ᦤßÃÇÆÿXÏ_WúnÖ¯n|{y‹Õ§ƒ‡w«ë÷—ÀïëãW^¿üqäæô|ýëäæû_PKÏ£€ï¶[PKËK³D styles.xmlí]K“Û¸¾çW¨´µ[ÉzÎz¼µr’*Ûq­½¹º ’¸& Ifö”Cùù%i¼(P$%RâH²†ã*ÏÝ º?F£¾úá1ð{8N<Þ÷MÝè÷pè× —÷ýß>½Ñ¦ý^ÿéY,<ß¹ÄY8Lµ$}òqÒƒÊarlj÷ýuÞ”xÉ]ˆœÜ¥Î‰p(+Ý©Üw¬)^ÂV·:cVk§ø1­[™òæê¢yý–³ZÛѦneÊ ˜ªÕ¤nåÇÄ×DsH¡ÔÛ‘âÑ÷Â/÷ýUšFwƒÁf³Ñ7¶NâåÀœÍfFÍv2¾hûŒËuØÇ´±d`êæ@ò8Eu壼ªHá:˜ã¸64(E…^bœ ¨KÇe½©urãëaY{t=,+`vV(®=Îs~¨Øný¡b»jÝ¥«ŠþÞ‘ý÷îív\ÅAݶ(o*'ö¢Újrnµ>!$•Và“‰kÆpÀ?+Ü›½ì›ØKq¬°;{Ùä;â$( øÌphøùLïÀókk ¼ƒ…^mè)oa¨ÆüJ GƒG$N3@õ.´be&c•~µÉ TɺŒ]·”ı`>`òjÞ|ÓÏ­ûÂlg 0Óz¨ cRmïÞ ¦1 <Ùô…¡±](âe¶”-È:ty?pñc„c’ϪÝåž ö–OŽx¤Xÿ”'äÌL’ØiÞŸ~PšF—00Òâ)ÊÊmõ_ËezA`‰^ k.vüäõ+n^³âÿL…»ïÿä¥Icô~¦V‹N7°‚’ÆúÓ}ÿ;‘äû'/î÷r§5´%Ac˜­1 P˜ãˆ¼Ô{ö€buè ¡xæIò!—Ä![íîû¿âåÚGñóÊÿÖƒ¥ †ÞG&•ÂïðÚ÷^0_'½_észïɬ÷¶Rº"ë¤x–sC¬_ðïèŸëýÝ©ðÔ)yJRœ$SL<—cðùþ9_ªe+òžEÆ71Æ )¤S%TAQη.¯_ÑÕ–7äz` zìó¯¢ì³e|žô9Åõ’ÈGOZž£'Éb¾6¦öD” ?Á'à c°A‚å9#,ØO®Ž¦8L¼p1 ã[¥R9…KÚº|úœÄ.õ¾>j®À¤êø7Z@4Kdäž™×.ñh;¢¬T/xHŠBº4tÃrQéÇ™D Ï÷5p€–X ,x€"\-˜` ¢±ÍÝ*Æà}ðœt ÞÿÀ4ÔKùm³7æÏz.eÕô)bZs+XY²¢)†í‹+‹<¥ÀI·¹™Š¿àX•þÇ8&>¸©Gôy{FÏ2z¶ÁËa˜P¦™´ledσ¥‹|ÁŠ’\OýŸ)V)”Ú³òýc'•Ì$ML+êGÍÇá’î(r}DIVžÓªàÜíä ¼IA ¢RTK´ ,½½±*#cZW—«¢ /o¤ ýë³5ý öç³5û|H¹ÞŸñ/Ç©hÎ&ß„f…$þÍOc´8Ü ߉=aŒÌÚ£JeU‡+ÏV/ÐÚA'iýÅÂÖŒ#ñþk¥¬Ì‡%j ¶LkÈ Ø"¥1ôßo OÖ`7‹Â]7kËCŸ-yx dш¤ý±’Ñš$üü¾Ø&ÝÏûøñ@«Wi»uåí¶œ‘þþ¾¿í¡ÜÀ–]£Žr4.ŠÝ~ó±¯xñ½í´ÎŒEn¡‹” m•%òSƒþƒaÊÂï>zmÏ WÙ|ü€}άÍ×¾Ó'Òr¶®°œ¤Ñ¨ë}ÿÿýw6#”‡l'Å ÊJã%ç×G¨Ÿ‚9ñûu dÞö GleìS¦ªÖQªò:líÒæxAb¶¼ŽiG1Jà…šæP'›ocuåýš²[CÈÔ­›DhØ"BÓ›DhÔB–>¼I„Æ­!dß$>“öð¹Q;=m ¡áÚéY‹ݦ6Ö }]†Z!‹]ã jó·7¼mÃvjIæ±K…q~'"JùF$_–íAD1 RÈ RC)CÎca ÎZ‰iíH«HÖ)m0Û*$&HºŠÉz¹ÒD+$aY$£ìŒq·oë1òãOnçˆqg¤˜SVÙ6GU‹äoÁ–[:UeFXC/Ä<”¤‚"·]'Ÿ'¦NAY ¶ß! >•†„n„â‚«ù9™¬Yu$é[Ü*¢FÀB— j^s”= õbHBŒï²º• dÕ0d,@dôj(*XØÃA´B|¨&\Œ}žØ†%y(•e Âlí‚Q;I#óß±“n¼&/?«) ¨É¨.ŠñÎ|V¢bnea5³qT-;bÚo›ì·ñ‰[m㦹)šÜØ<'œÂš=x‰7Ï!ÛŽP¡9,@4‚÷Œªó°&›µåû“† ©ŒôwHèÿôYô74½-¤“J š?âéÑgôBÒ£µ{P•þ­VzÆéíÀÑ8PÃñuH9'îÓ%%Ýïà ¿c «Ec­~_'0EpåéÅù´«r„ù!Ÿï-am§Òz‹§æjrçöz•làíçu¹ª ‡—ú5 uòpØh S•ÌKèTy–eðõªáÚhí[ ÄâÚXqo£nwXÍ»Ãzžî(=ýÜ“íœ':Îlv]}Pg’óVv7õºY±­Ï%ýÛlgŸït»Ñb²ÂȽ´ËQ zæÐª‚Ó2ëcÔlbHŒ.bª.R>"Ãsâ»Í¡{&³rµÐ KI^ “Ü9Ñ£dŸc¾îÙaJŠCÓ}´eÍJOJkævÐj=¥¥Y£¾½TlÄëö“ÕÄü"²Šh^÷2¦ßEÙíõ‹r'ŽÛ£\€KŽ'@ÀwìÉIH´¡öóm΂pHR|ª­îkø™iÍ͵Cì|Ý¥ü¢ýo»ì:FwºpÒéP%²åíå.Tq³§ Ò& kPðÃ[_vibºëÛ&[bòù°)¸‹bV'«Ø ¿ÐÏP| ³ Ç³§d–ç)îÍš]ÙÁü29M}t“•grþë?ÇdáíÍ™ž ¡ÉµfrÞjUy&ç1cèj„ZCíerŽo4S±½\ÎÉæáµ—Ë9»I|ÚËä45Ô-¦ršæµ˜êKårîMÐdÞbð(t–mu“À.àQÄK xNÏrê#Ÿ’xC ÖnØàœµ«†óJ‰Û ×ô˜³¡ªÝbV;ˆÙ O¦++%æ¿;,bÃv³ÛAÌj€X!º7d\ ¤‹Ø¨Ćí Ö$ûáRˆÛAlôr›´ƒØøå 6m±ÉËAlÖbÓ€X²ž—æá¶~EÄ‘ö@k:È— ‚çº>®yΔ‰Û]ýÑ]ýÑ]ýÑ]ýq=FÝÕÝÕç?.ê®þx©ÇÖÝÕÝÕ×uõSü”¯ýÔ@C©Ø,ùÝÁRw°Ô,±ÈÀ×ÅèB]£ at!Œ.„q½u!Œ.„Ñ…0ºFÂøêC%q‰.Qì–²ºDýİËöBC@ÜHB)h½´ÁGO`r;ýߟ,š£”{ÑtäƒA^¦J/GàWNÜ÷WlΚ‚÷°¼£9º1šÈ«?é›üôÉЖŸ…é6 }4Êî•ßîÕ Ý²E–æi2˜°p˜Ö……Ø|Æ­L—âBì2MÍKqœƒýó©á|3?§›ŒÖŸl–­ÏLsW+[“cU²¯ªºwjOkÉ`Ú€lM`;ï7éô=ãŽ& Ò¯*ýÃ;£_ÂsDŽ\¾¸ÎYS¤Ü¤c™úh¦–KL¬‰>cN¯ÄãNbO¢rß§¯H‘§&Ε ÁJ̆T\g–`–`–`è¶ULBsÜÅPö;7*\ZA#äôµaô.ja!ä¾½tI8¡ü…´íÞUï*|)¥‘B¹ ./G¦·ÅmïÒ.eY’`aM…ë`®¼Ç®”ÑE)l:GzAØ:6ºÍî=vű{”vÍn­>£‚Ÿ cŠv±a¶/âÝÛ3\vM!í.¢Ëèr ®¡.¢Ëèr ºˆË"Ôå@t9õs öûÓÖ¹®ßý °ëœíÎÙîœí«A¨s¶;g»s¶;g»s¶¯¡ÎÙVŽ+ób!@IÊ^ÆKÙ1’žh}âö3?aân:Ϭ •Ó•wqÕà‘'h•¬à‡xÿÍ‚d\ƒ]=8à" LãJçóªR´\6dv2¸K§‰Dò ï);.dBèE E%,,m!;äË6²c·­*e ©YU3ÝÏ IUº=ËÂG‘n"R³Øß9% C Ž¥äL®9ys03eGPA… –0|2wSÛxÙ ¦õäß‘ìÁm˃-†§àiµŽ§ié–UÓ,±¥ ¬VcX³fžYëR#Õë#žÉX-Ï?zÞáÊÛ83¨Ï?\÷«dmµ>jyõm¯¿óÓïùŸß-Óï%¶ ñгg¤+xHˆ<¿¢–H¾TêãaÑ\:õˆ%Vô¶íÊœ73[½Î'ŽiQ܃î¦gúxfŸ¯i¸F%=q¡æÏ|¡}þA™ó#]"áÿQñÊîyØçð˜å™wxrfEeݹõ¢>"æXN'%†nl«è3s¬"¢ÛÖ°ÊÎ ª2ß…O¾cÕfþ ÒÛ—æª7tôdŸÞ–>3¦Uz 1Ρ9OÆlÅ{€­ýxº‹ƒ¡ööÿTÚ•ëÜQ¾Ys¢5ßìH”í&(ô©1>„òºbTåænš}!7íH|¹kõFñP7íÚõîZN)ö²å½îòµõV[ŸûÊ4ôáD]…m}jæ,¯iííªÌ9¨¹hˆ·O7¦ç¤ø5+KM,Ent4S—J[V+“\Hq–ãbû͈Œ‰k!ia»‹”\Ü.brâ<(®ÁÙRÙ,nvNd±Kœu}}&yýPKkõ t|½PKËK³DConfigurations2/images/Bitmaps/PKËK³DConfigurations2/toolbar/PKËK³DConfigurations2/floater/PKËK³DConfigurations2/toolpanel/PKËK³DConfigurations2/menubar/PKËK³DConfigurations2/progressbar/PKËK³DConfigurations2/popupmenu/PKËK³D'Configurations2/accelerator/current.xmlPKPKËK³DConfigurations2/statusbar/PKËK³DMETA-INF/manifest.xml­TÁŽÂ ½û ÷‚º—ÝÆêÁij÷X:­$0ŒþýÒ&j7Í6+˜yïå °Úœ­)N¢vX³Ÿ³P¹FcW³Ïî|g›õle%ê"U×E‘ë0Þš¥€•“QÇ ¥…X‘ªœlœJªŸùÕÀt‹F–l=+î|­6Pæúp¹g·É˜ÒK:ÖL<¹o[h´,éâ¡fÒ{£•¤œ&NØðA0ëä>@ÌóÃÄ-‡c²_(µ‰‚®Kî±{ E[ÙèÏ'±D Ê͉<ú™àL¢?žläËA•Cê]}5î^+J¹Sb1åh~›ìÛ' ˜è;] ¼Þõ­ÃVw) ÷-.…T äСRÏÍû×ILØKàIs5FèÉWâ×ϰþPKxþ+TPKËK³D3&¬¨//mimetypePKËK³DHQßßUThumbnails/thumbnail.pngPKËK³D_ÝîÛ@' jsettings.xmlPKËK³Dôý;t¹ämeta.xmlPKËK³DOè&ƒR #? Ócontent.xmlPKËK³DÏ£€ï¶[-^(Pictures/10000000000000200000002000309F1C.pngPKËK³Dkõ t|½ o*styles.xmlPKËK³D;Configurations2/images/Bitmaps/PKËK³DX;Configurations2/toolbar/PKËK³DŽ;Configurations2/floater/PKËK³DÄ;Configurations2/toolpanel/PKËK³Dü;Configurations2/menubar/PKËK³D2<Configurations2/progressbar/PKËK³Dl<Configurations2/popupmenu/PKËK³D'¤<Configurations2/accelerator/current.xmlPKËK³Dû<Configurations2/statusbar/PKËK³Dxþ+T3=META-INF/manifest.xmlPK‘¡>bobcat-5.09.01/documentation/images/molds/figure.odp0000644000175000017500000002602214050437223021327 0ustar frankfrankPKàM—=3&¬¨//mimetypeapplication/vnd.oasis.opendocument.presentationPKàM—=Configurations2/statusbar/PKàM—='Configurations2/accelerator/current.xmlPKPKàM—=Configurations2/floater/PKàM—=Configurations2/popupmenu/PKàM—=Configurations2/progressbar/PKàM—=Configurations2/menubar/PKàM—=Configurations2/toolbar/PKàM—=Configurations2/images/Bitmaps/PKàM—=Ï£€ï[[-Pictures/10000000000000200000002000309F1C.png‰PNG  IHDR D¤ŠÆPLTE€€€€€€€€€€€€ÀÀÀÿÿÿÿÿÿÿÿÿÿÿÿ3f™Ìÿ333f3™3Ì3ÿ3f3fff™fÌfÿf™3™f™™™Ì™ÿ™Ì3ÌfÌ™ÌÌÌÿÌÿ3ÿfÿ™ÿÌÿÿÿ333f3™3Ì3ÿ333333f33™33Ì33ÿ33f33f3ff3™f3Ìf3ÿf3™33™3f™3™™3Ì™3ÿ™3Ì33Ì3fÌ3™Ì3ÌÌ3ÿÌ3ÿ33ÿ3fÿ3™ÿ3Ìÿ3ÿÿ3f3fff™fÌfÿf3f33ff3f™3fÌ3fÿ3fff3fffff™ffÌffÿff™f3™ff™f™™fÌ™fÿ™fÌf3ÌffÌf™ÌfÌÌfÿÌfÿf3ÿffÿf™ÿfÌÿfÿÿf™3™f™™™Ì™ÿ™3™33™f3™™3™Ì3™ÿ3™f™3f™ff™™f™Ìf™ÿf™™™3™™f™™™™™Ì™™ÿ™™Ì™3Ì™fÌ™™Ì™ÌÌ™ÿÌ™ÿ™3ÿ™fÿ™™ÿ™Ìÿ™ÿÿ™Ì3ÌfÌ™ÌÌÌÿÌ3Ì33Ìf3Ì™3ÌÌ3Ìÿ3ÌfÌ3fÌffÌ™fÌÌfÌÿfÌ™Ì3™Ìf™Ì™™ÌÌ™Ìÿ™ÌÌÌ3ÌÌfÌÌ™ÌÌÌÌÌÿÌÌÿÌ3ÿÌfÿÌ™ÿÌÌÿÌÿÿÌÿ3ÿfÿ™ÿÌÿÿÿ3ÿ33ÿf3ÿ™3ÿÌ3ÿÿ3ÿfÿ3fÿffÿ™fÿÌfÿÿfÿ™ÿ3™ÿf™ÿ™™ÿÌ™ÿÿ™ÿÌÿ3ÌÿfÌÿ™ÌÿÌÌÿÿÌÿÿÿ3ÿÿfÿÿ™ÿÿÌÿÿÿÿÿ¸ÿ¸ÒOIDATxœcà'FŒ*U0RËU<4àðIEND®B`‚PKàM—= content.xmlÍXM£8½ï¯@Ìdº“ $#­V{ê^vg¤ÕÞcÀ3€‘mò1¿~ËBÂH{Ø>`¿²Ë¯^U9½ýt. çH¸ ¬Ú¹¡¿pRa–Ð*Û¹_¿üî­ÝOû_¶,M)&qÂpS’Jz˜U>°®DÜÎî܆W1C‚ЏB%±Ä1«Ie¬bë½Ú!/Åls ¶­%9Ë¹Æ ;°E‡ù;k°mptšk¬°@ªmž²¹ÆgQx)ÖËIzãŹ Õ÷›KYÇAp:üÓÒg< ÂÍfèÙÞaÜãꆕà€Dm&‚Ѓ-‰DsýSXÛ¥ª)„ϦI4Šj͉W sÞB¶Í@_Çl¶ºŽÙÍ8G|¶Î4x(•e2_*ËĶ-‘Ì'â»ÞaR?Þß®ºâåܽv@æ´ž}ÌmÛ3ÆzW•A›ìÚÝh±ø´ïúô~âTnÁñC8Fîgå=Ò€ðÈQI¾O"E„˜0ˆ‚vº‹dré¿ßßþÂ9)ÑLŸƒ=Z ‰ª+3¢¤Åì(vB´¨¢³¥ °£ÔáJ “Œ¿œÔŒË>@éü&»D=G¹,‹é¦f 4ãIr î,(gPL¼#%§î ;=ææF˜ºÔ?3Ñ >é()L†÷ØŽr® §êô¨P"öJa³:¶¬‡½—çyË)1³$½]ñ&±±Ky·/jÎS­Š·“u%€(iÒcÉQ%Ôº]QîÖ‚È _GÜS®êEÛU Ÿ@êˆBà_ēԇwonmõA?€ÉÔâØÓí@ì·m[ÐO§ý®(عIºÝ@Š@þj¬W£Œ¸ÆÒôj`‡pI‰pâ€ð÷Œ³¦J@8‚êä „v Æß–â!<¡¢.Ðú6“ª>€hïLÏLQ!¦€ nâIZšºÀ¢è_ÑÇ—ñ&'(yr²ÿÅá3>KÆQSl†kÄÕ­V¿x­‘*Ç âIOMgb³¢ØÒWJ0G^Î8ýÁTRz¨ $È·FHš^ÜàQ™ã+¬¤]¤C©ð@f' —f¹4œüÄiG¡6§}p”Žá°§ ?~bËzL°Á,ÿFRÔÒ«`_ñ”ê”ªÑ ”ò!Õ“¬µŠKY\Òª #ÿeµÄåü£}Ÿ q¤ìÝíGl‡agpcLTuïL–¾nâÀ’Kÿb³ºßê“«ôi9èbïaÇŠÍ´®˜z´„Ë6á]ÞÙQp»%1È–•žÈQMÆ élê=ˆæg3骲>X—¸TÇ'š¨[ìÂ_½ÿzÈDe퇯f z^¸† ™w <„ïû­þåV‹¤ÊÕm)ñ2ÂàÇ¿h°jû¿2Xbá,œ(|]tOãï¥'9UYŸpýRµ¾f¿;Êø­3,ã\?Î?Î:š#ÆöÛAõÒʾŽÈµ"èÉ*`…hqðè)­áÒß¼®o‰ þÇ•MíÒ_‡³‘F*œ«¦‡7EHˆV]® BÊÁ¿!Ìö»æÏå®ühŽü6ijüG_6¶$–Æìž“m1NAÁ$gŵau‡Ð">°sK}*xGÑ  7QDJè›7²d ×KµßMç`ñÁÄ¿\öÿPKkKkÂÔ³PKàM—= styles.xmlí]K“Û6¾ï¯P)µ¹ñ­ç$ãT•Ý­²]®ØÙk "!‰1_ER£Ÿöìaûÿö—lãE"(‘Ž$kèTź!vh4øýa0xÀiæÇÑýÐÒÍáGnìùÑê~øû§_µÙð‡7ù>^.}ßy±» q”kYþàl£ìŽ4º‹Qægw qv—»wq‚#ÑéNæ¾£b-ôËšv§Ìrï?æM;ÞR_´hþdÊ,÷öR´mÚ™ð¦r÷eÜ´óchËXsã0A¹¿'ÅcàGŸï‡ëÂ+‹mÂNCƒrTÕ$Ű€ºÄ.›}‘ܧd_«ÆÖõ°ªÙ]£´±Q沩8^sSq<¹oˆòuÍøÎŒw@¤ÿ{÷vgWiØôY„·•›úIc5·Ü?ŽãBTÒMv*®mš#ƒ}–¸·Ù·©ŸãTbw²»(p ÄãPðYphø˜|¡wèµÞ#A‘ßzÂ[1Õ”€_«áØHq§yȲ¹Ó…§Ø…ËXçaPï2U°®RÏS²‚8Žî&¯öàãí7ÃÒjpØæ{†@]ë±.”©˜ŽYæä*¹>ýfšF\=83¾ÚH+ @•ºËSedp'ÿ ËtЍF¤ _ʾü£m€/ÎØ[Ú©·ÔáÃðXÙšøæ{âê7äù€ÿ€~"Cs?üoûÃ6ÿ˜Åó³$@OZ™c È|i'ŽQZ´s bp±ß˜ô'Á¸„%ýSêãG9Ž2?Ló¯R'5E+òtñí‹8õˆ[ºÁÕ\£Ü]Ë:þ4-¥‚”<°ÊÚe>yoSê_’£ˆÄ¦nÚnÈ›ÓX,f!ÑÒ fÖ Ëbýäç!Jp½`œˆF—Ì»uŠav}ðÝ|ËŠa™ò[úÛ1ç¿Z?ëI´]ó§„j&Ô^i[¶&®úè‰&_ràŒ£·1ò B”~Æ©,ýio‡XœîÈTû)~æÀ6ŽÉÚau -hÓ,Ò¶¶Í/Å÷eyÆš‡²ÒHýŸ ¶BØåqJ±› æ8Ï,°ù£àhE–ªÒ’]æ´k8÷`q‡—hð¨sÀÚ–Ü0˜+L´dí»CÁ› Ñ6-Iaþ¦¹q*#— ¡Mg "ñ=3V$k4älÉ&¢#†¥m¼JF'“Q[¤AÔØúF!ËزÆ™´©–/iGdþy˜øfAÓo!‚ÐH{‰‚ :€§]ã$Œzµ v¢WEÛM†59½x«Ñ‡ó‰•§Ðd3‰Šß¢$ξ{M6ø-Q4xÏoY{I ÖE[áƒî`„»Ä‘ø0Éï‡(õ™ËOËü/€‹=JrÚ€ÙÀD…yÑ7ÞDy âüþQõHðÉ(²þ‚ÿDÿÜ >‚?*¤è™=e9«² úNb‰ƒ-˜èÜ ¸ô‚öe-(\ Aøù½J4@øñ$uоµ õ*,J¥ êÚßW« ýãýpg ¥9*,Sž°Ì¯)î¡Ô™Æü³lÖ’3ƒï‰ßö\É­¿Èi[ßþfLŽDR.8ÌklÙ,:;Ná¬J .Lh²0²Y\b ‹ëþtÁVô&«XYIº®)×vJñ†VjP>º`k5kõníÔj—M‰GèU(%ÑÖØ_­sN„© ä4ðj ‹ ƒDXÄyNBv-ÀKòUz…ò‡p ³†5òè¶Â÷<âW¤F "µ çÚ#Œ½‚ø¤$ äg&ùÌ”¦X²´F.³°ã³¶ØÎŒHÚéI?2’Fv÷Ãÿý÷ßÅŒ¾d7)Œº5`ßÁCýø.â`Øf}`{4¦ŸqH™ªÚ'©ÊúÐ¥[[`ˆÛi 0!E)¡iZ@Ÿb¾Mä âkBÈé !زÜ$B£šÝ$BãβõÑM"4é !ç&ñ™v‡ÏúéYgnÔOÏ;Dè6ý´evÑøërÔ™ïºÍßÁì<¶S+¢0Û(ð]oLË;ÞÊ6"å¶b›iŽFìdX^Z)r>Íâ0ÖZLà&uŒ79y`±”HT|Æ›ÕZãÙ¸(Žj9°oƒÝ-Fáàgr…SENÛ°ü†W›€$˜»ÌóX3žçÙ=ŽH†(Øá(vkLIå œ²$™Jß-ñ}|¦à”Õ`gÑ´šŒñue’8•áàÔ²V’®.¯T£bA¯W²†…Ú“5b&Û ížâÀ'YûŠ1Å*[R1ðɹ›¨RŠëHj+^ü‰Ý|ëç0åX¾^™áYf”â½Y(¥ Z%ÁTy.«uš«8f8›Î±éVŸþb¾²-šÌE¼$œÜ=ø™¿(¢ºN 9¬$¥ö‚ª³<#å#æ ÆÍæè³¤\ÄÞÓ%%=iñUr^²µVn20 \›F?Ÿvu;l ü¬VDZùÔ^Me]¯’-ÂÎrÔ(bñ†pø¹´Ò^©!F­ ™¨d]B§ÚC“ùé–k‚}hM¨«kBóYÄVÙ¦Ãa·ûe†Cy ·;¯Ù;ØrÝùüºÆ É$gOÙß]êVÍþ² (Ʒݳ<èN«Åd‘G‚ÞË{–#Ðs4Gvœ¶Õ£vC`tWu9Ê{w±Ù^Ä׺r+W ÝH‘öðs˜äîs 1Ê6é9æë¥)µ·Ý?Úö\Q¡ìYÚ9Êý¤ñnœú&òs¾m:Nv?ð /oY ÷ó*7Q%ô–«ÏŸi·'WZÉD*ÓcÏ€€íT³g!Ñ…Úg,ü8 ÂQœãç¡Ú龆Þ5ÛÙhGŽXëRâ¼¶‘$B_¨¬ÑìÓÝõ…“æÍ§»kT¼Ùt·pV|ŽVäÎ×CR¹­Á³-|¹b2‡8ŽÏÅlúÑgòšëUôxñ¢=u%ÛÁ’ù•Ý^ ÖÏÒÇ7‰ºÖï_ÿ9¥Në`…ÄìlM¯µÖïV«lÔµ~§ØÐÕ”tlCÝÕúMn´–­»j¿éVjuWí7¿I|º«õ³ÌuÔûYÖµ¸êKUû,á£Ñâ+LC8vŸ†¨MC0pn: Q£âkICT›JiˆúE 4jq,Y©–”ÓgJâ.õ4;å(ƒ«êtƒ˜Ý bN˃ÜZÄ”ÄòožOElÔ bN7ˆÙ-«¤(¦h«éÍSwƒØ¨ÄÚ \ ±I7ˆ_bÓn›¼ÄfÝ 6}=ˆÍ»Alö Ë6 eÙjçÇBDq@i¤§‹QOúžà†§?…¸ý• ý• ý• ý• ×sŒÓ_ÙÐ_ÙpþCœþʆ×z˜Ü_ÙÐ_Ùp]W6PÅŸó+™hHûãžþ¸§?î¹î㞯)·Ð'úÄBŸXè }bázê }b¡O,ô‰…>±ðÕ'Ù‚W˜©®!èŒaT©»¹Ä@Š7’wúZBîÐLÏÒþûÇ·æ'›Ôó”^ ˜à&×q>(Øm÷Ã5O°!à=¬îHýƒnާâ6Eò‚,}:rÄgîP-S‹+ÅïS5S·^Ñø<,pç–}a!ö€Hn'Ó¥€¸„û@€L3ëÒ@œ&„qx>ÃÞÛíøGòclò⧓ħþî%¤äÍ‹)òåZ¨RǰZPsy˜¥ÀR`©0uÇV¶bM: š}ç%•Ûøûp©­¸È•|íîÚá°×v{{N³$4(TùA+…J3\¼xÜ—µ»EWɲŒãü }”x/S•ŒÊ!bõéí­n©y·J/wÚ±—aÕ^A&ÌŒÂÚug>m5æ«ôr™Óºöœ‚9Ç&©ZDËÊØê¥R×b'£Ñ¼%Ïý ÒõbÑÞ.žûë¢scqé™ô¡:‘Dšcx,]#ß?X³ñUwWö·úYÔ»UK¯Û$Kƒ#¯ÝíŠçÑ®j»'i×îÞÞ3*ø©bkD´‹™Ù¡£ôwoÏp/Ó5åCûôþ½?@¿„úôþ½?@ïÐ/‹P€Þ 7?@?OÛ}<ÝÇÓ}<ÝÇÓ}<}•õñtO÷ñtO÷ñôµÄÓFmé '„(Ëé;X+=) Ði"߸ûÌ‘X$Ί'ˆ@jºô¡<⬖ÕÒ88ÀÁ_2Eêñ(—±¯œ×#iLér‰A]5‘VªË+ÿöé¤VHœå='‚´è‚ ½L¡IÁB+Šs¼Ò"=YÛ©¢M®œšëÎd¾_8EŽó&¢ñ‘W”ðò+úï n€²Œ½ §Br*×"~äs0á3eOPN… )>Yû5ì…Q“~â߉ÁÝ“†ÏÁÓîOËÖm» ¦EíJXíÖ°y díKYª=ÑǬvT-+1zYseÏ83¨/o®‡• ³:·ZÖ}÷€7ßùwìŸß®òï¶éÐÓïÈ×ð%òƒVˆÚ¼¾RBt¤OF%DK…½ãùî}ó¥²6«X½Î'Že‘ß)~îGÏõÉÜ9ߣ-à+FâB?7ò•çKðªàG„D<þ#â©î8ðXê€Ç*<%·"³îÝŠÐk¢fS…£›82$úܚȈèŽ=ªós\†ºêv“ïy@£ÞÍUz÷²çê ==¤·­ÏÍYÞ\ŒshÎê-;‰`k?™íã`êãƒã?ÓGNí:wRlÖ>†è,6;e§ Êc}fNŽ¡<…¡7E¹}˜æ\(L;ßVáZ3+é–Óà¯>\+)Eß({pí^[_`Åqôyu¬,SMåUØÑgVÉóZöÁ¡*‚ƒ†‹Ån ¹azN­ŠÜ¶>žÚ’Ü èx./•Žè¦’œKq–ãbûÍÈŒœˆkŸ!éa§Ï”\Ü>còÌ%ب®ÁÅRÚ,îŽöND³»›°ø…LöæÿPK,O‚¶±PKàM—=ɸK?hhmeta.xml 2010-12-03T22:31:45PT00H11M05S62010-12-23T10:47:00OpenOffice.org/3.2$Linux OpenOffice.org_project/320m19$Build-9505PKàM—=Thumbnails/thumbnail.pngë ðsçå’âb``àõôp b``28˜€döu…X @Ÿ§‹cHÅœ··6r2;ò08rß©?½IzCå–ej¢ÜyÆ{Ë¿³†¾_.Ïà/Äɤà˰„³Á„q‚Ã%‡Y ÂA™œ´º^=¹œ Í>½o¶ÎDUV]#D8yy ì·ïΖƫX~¶³ÀïÕ¿øŸâÉÓÕÏeSBPK‰²õ ¥ÇPKàM—= settings.xmlÝZ]sÚ8}ß_‘aöawvIÓ˜IèÀ|…—Žl P#K®$Ç!¿~%)“ït–,éœ+ÝkÝ£k_}yqñÉ3dQr)œæ3'ØÔAdvôìeæKù+:"–jû.$"Ë¡² ?‘à /-›¯3>#% 8â%\ÈKÂ.Q’õ°ÒfïRH¶¼ò‚yºÎÌ…ðJ¹\§ÁÙ)e³\AÓ´\غîê1È%¡Á‡nŽÙ¤µ)™¢Ù¡(ËÞ›ã)¥oF«ˉ…†óùóÜò÷º7w>”KõÍÚÔõ¤Íþi­Aî¡0ªïά—V½o»öfûÊY!RÌ”×ñ°ƒòÕjq–²H@WÅÈÉê²²ñ:#)KÏoÑ“‰÷ó˜!âjtAŸz™u£Xx²‘)gÏ ŸóW¹] ·àTD£ç“ƒ#æQèżVøœ¾Ñli}áâ\ÓÅϺÀË"âÀèlsÁ ÚYáolqˆÅ0h8[frÁd$dÊ*. ñV¢ÆÓà«õØ‚·(ÅLy 0‡Ið FÉö½ÁM¼>U,)ÂwÀ Þ6C„ïcÌOH¢¾[ˆÀ½G˜Èƒõ ÚÂ`òbê,*ï¢t&ÓÁ>¯â`Èu€EŠñ«bWþsÃÀÌ”÷Þïžøp‹‘‹°Cñ"\¶–¼ tE¹1}Š»­6ø.W.Zù£2ómã/Î+Ò¶È”s.¯ãÙÒ‘{¤¿‹5-j?Açצä~ Õ¦º ÀJÃmZ¥˜îš˜<Ø{>†,ÍŒ£6ë¦ÌÄÛ¹rN™¼wbÞ8&ÄrKƒŽ?*pƒ‡±pOtv¯ š­vÊ42× õ¥«ÙO}ø"n´7Ë'¡ ªs@f°G—'‘ËÄȼYÑ>>¹¿ËeQ6…ô`Û‘îé1Ãg ݦbÇÃÇÀU±CýhyœXzÿOÏ$—©žIbç~¥‘«0÷Z_(Æ]øàïØžÝÒx¯ágŸ’!ï·:´ÒáÑã¶ïBe)rÜ@BCqÍ’à„øÆñøÌã1y4x(¨Í-Qz0£BOA·O(uH„ø8 ½F\Ü,<ìk^Õ2¢;p(¯Z-/ø,ÌÛ)_鞇Ù àøº¢‚„œh_… ×ÚSZùó/_ð÷Š ÇW)ü”S+«”1 H)ɪÔU¥UUìKÊ£ªÊP¼Çž™ôðylN'&'œ IkŠh5ñ‘¬³¿ˆgPf!ÇäÍ}ÉKz-©gýˆóÄj­ ‰ë{_ñïA˜1Õ `ìÔðV¨V+p†ˆ*oÅF¸%λã“îs¿ÎQÀA,vˆÏâ­üJ‚ó:eè•ðñ·Â:vü{w7!7!#:—qÕñ‰-ü´v Ö€*”>a˜Nz“ ì§4NÁ›ïÔ“È|›N5b‰Î@ "*-ë $ÞSJÉ'}(>&A˜jÔ$R©Ú„Qƒ#NáÁxw·>"ZvZÏ1B†>Â0Ý@ê£TìWiRfËØûy\Z œ%x[}«®+OŸdRŒ¹ ò°³@בšnÆ€77}×M+ …ïú#±½ELRY`gnu|ƒ‹’š¡©±¹ÁÉÑÙáéòú &/8AKT]gqz„Ž˜¢¬¶ÁËÕàëõ !-8COZfr~Š–¢®ºÇÓàìù -;HUcq~Œš¨¶ÄÓáðþ +:IXgw†–¦µÅÕåö'7HYj{Œ¯ÀÑãõ+=Oat†™¬¿Òåø 2FZn‚–ª¾Òçû  % : O d y ¤ º Ï å û  ' = T j ˜ ® Å Ü ó " 9 Q i € ˜ ° È á ù  * C \ u Ž § À Ù ó & @ Z t Ž © Ã Þ ø.Id›¶Òî %A^z–³Ïì &Ca~›¹×õ1OmŒªÉè&Ed„£Ãã#Ccƒ¤Åå'Ij‹­Îð4Vx›½à&Il²ÖúAe‰®Ò÷@eНÕú Ek‘·Ý*QwžÅì;cвÚ*R{£ÌõGp™Ãì@j”¾é>i”¿ê  A l ˜ Ä ð!!H!u!¡!Î!û"'"U"‚"¯"Ý# #8#f#”#Â#ð$$M$|$«$Ú% %8%h%—%Ç%÷&'&W&‡&·&è''I'z'«'Ü( (?(q(¢(Ô))8)k))Ð**5*h*›*Ï++6+i++Ñ,,9,n,¢,×- -A-v-«-á..L.‚.·.î/$/Z/‘/Ç/þ050l0¤0Û11J1‚1º1ò2*2c2›2Ô3 3F33¸3ñ4+4e4ž4Ø55M5‡5Â5ý676r6®6é7$7`7œ7×88P8Œ8È99B99¼9ù:6:t:²:ï;-;k;ª;è<' >`> >à?!?a?¢?â@#@d@¦@çA)AjA¬AîB0BrBµB÷C:C}CÀDDGDŠDÎEEUEšEÞF"FgF«FðG5G{GÀHHKH‘H×IIcI©IðJ7J}JÄK KSKšKâL*LrLºMMJM“MÜN%NnN·OOIO“OÝP'PqP»QQPQ›QæR1R|RÇSS_SªSöTBTTÛU(UuUÂVV\V©V÷WDW’WàX/X}XËYYiY¸ZZVZ¦Zõ[E[•[å\5\†\Ö]']x]É^^l^½__a_³``W`ª`üaOa¢aõbIbœbðcCc—cëd@d”dée=e’eçf=f’fèg=g“géh?h–hìiCišiñjHjŸj÷kOk§kÿlWl¯mm`m¹nnknÄooxoÑp+p†pàq:q•qðrKr¦ss]s¸ttptÌu(u…uáv>v›vøwVw³xxnxÌy*y‰yçzFz¥{{c{Â|!||á}A}¡~~b~Â#„å€G€¨ kÍ‚0‚’‚ôƒWƒº„„€„ã…G…«††r†×‡;‡ŸˆˆiˆÎ‰3‰™‰þŠdŠÊ‹0‹–‹üŒcŒÊ1˜ÿŽfŽÎ6žnÖ‘?‘¨’’z’ã“M“¶” ”Š”ô•_•É–4–Ÿ— —u—à˜L˜¸™$™™üšhšÕ›B›¯œœ‰œ÷dÒž@ž®ŸŸ‹Ÿú i Ø¡G¡¶¢&¢–££v£æ¤V¤Ç¥8¥©¦¦‹¦ý§n§à¨R¨Ä©7©©ªª««u«é¬\¬Ð­D­¸®-®¡¯¯‹°°u°ê±`±Ö²K²Â³8³®´%´œµµŠ¶¶y¶ð·h·à¸Y¸Ñ¹J¹Âº;ºµ».»§¼!¼›½½¾ ¾„¾ÿ¿z¿õÀpÀìÁgÁãÂ_ÂÛÃXÃÔÄQÄÎÅKÅÈÆFÆÃÇAÇ¿È=ȼÉ:ɹÊ8Ê·Ë6˶Ì5̵Í5͵Î6ζÏ7ϸÐ9кÑ<ѾÒ?ÒÁÓDÓÆÔIÔËÕNÕÑÖUÖØ×\×àØdØèÙlÙñÚvÚûÛ€ÜÜŠÝÝ–ÞÞ¢ß)߯à6à½áDáÌâSâÛãcãëäsäü儿 æ–çç©è2è¼éFéÐê[êåëpëûì†ííœî(î´ï@ïÌðXðåñrñÿòŒóó§ô4ôÂõPõÞömöû÷Šøø¨ù8ùÇúWúçûwüü˜ý)ýºþKþÜÿmÿÿÿÛC       ÿÛC ÿÀèÍ"ÿÄ ÿÄX  !"1#7Av–´Ó235QWXa”Õ6BCEV$%Hdqsu‚‡³µÅÒRU‘•¥Ô '4bfS¡¤ÿÄÿÄÿÚ ?Û›±;!a²y>~ÍàÒeIÅj^}÷±èkq× ¢¥)E¾T¢I$žä<}ï» úÀ~Bû=~!vÛæ…?ÔšÓþï}Ø_ÐŽôjÙèûßvô#€ý…özÑ @ûßvô#€ý…öz>÷Ý…ýà?F¡}žŸôh>÷Ý…ýà?F¡}ž½÷aB8Ѩ_g§ÐãeÅ2Iq) Ryîç‚Gæ<ü޾´{îÂþ„p£P¾ÏGÞû°¿¡èÔ/³ÓþÞû°¿¡èÔ/³Ñ÷¾ì/èGú5 ìôÿ£@÷¾ì/èGú5 ìô}ï» úÀ~Bû=?èÐ }ï» úÀ~Bû={îÂþ„p£P¾ÏOú4{îÂþ„p£P¾ÏGÞû°¿¡èÔ/³ÓþÞû°¿¡èÔ/³Ñ÷¾ì/èGú5 ìôÿ£@÷¾ì/èGú5 ìô}ï» úÀ~Bû=?èÐ }ï» úÀ~Bû={îÂþ„p£P¾ÏOú4{îÂþ„p£P¾ÏGÞû°¿¡èÔ/³ÓþÞû°¿¡èÔ/³×,­’ðãLXs¶mãÈž²ÜV €…¾°ž¢”$·Êˆ’=‡:X{Äuí®íöÓilssÉÑŠO™pDÇå%ô3-Ø‘Cj3k!k[så¸SÔ”…ïj3uüMn¬üÿhkíYIJè0ª.¦Ka×hS¹‡£%„V Ž¾ë¤ Ž ä+ž8Ð^¿{îÂþ„p£P¾ÏGÞû°¿¡èÔ/³Óþ³NAâó.¨ƒº6Ð6Êt ¢šãYÇ ˆÙ1[ˆÔ·a(¸´²ïYlô§„öYWª×ûßvô#€ý…öz>÷Ý…ýà?F¡}ž”ño–w;‰`YØM¡¸4“o1‹5Ú1%rŠ[Èa¿ÿ~\––8[ƒÖãžAãŒø—¾¬¾Á™Ì6š^;M¸Y,Œb¤Í²è¸eô §¤×©eÑJJó„%ÆÉ«ÇÞû°¿¡èÔ/³Ñ÷¾ì/èGú5 ìõVÛø°Í£EÝ ´~ì,YÚY®³xW‘EeN°Ü6å©qÒ¢ã§:¼³Ò•‘|ÒZÑ縄 ¸ñÑ.Ÿ#­jR’ÒT—£Hh(%h<‚ ÁÇr;èYØ_Ò[ócì¾ÞºŽ¥'©ä%RH#ß´Aý ëïï}Ø_ÐŽôjÙë,xnÞ‹žqìž×k›mªr;èvÕ¶h*ã9‘MoÒ Ð;jZRz+ WGZ.Ã|.í³Ü·o¶«o)³WïJ·M{I‘!¯9¨q”ïœùk…¯-´õ 9$$&\Ø_Í8ÛNì¾Þ¡o(¥´«„ È—Üð íò¯¿½÷aB8Ѩ_g¬ëžî;»;±áK|¶«‰i:ònJÔ/txƒ!)M,Ä»÷ƒn- Ó©t-!+HWG‚l¼aB…>ãÊvê«r+2:Üf>0ÜöŸnÁûœz†eð”ú2šbBÖâ€Ã€ «¥* +ï}Ø_ÐŽôjÙèûßvô#€ý…öz]Vóî\H·0¬vðÞWäPh!"¥H­œ‰IB½ì´þ Êr]¥sÊŸ_ á¢Mꄉm©™Jm³ÁBÈPSiRJHàžÚß½÷aB8Ѩ_g£ï}Ø_ÐŽôjÙê#ÃNæníí.1gøDz t5v={oµ<ÈŒ—VêO¬ÂyP! %@(OQÖ ­dîŽU¶x>ÍüœM<{Ä.é1§tOKKóâÅ /Îe¦žB–µ­¡ÊV”õ+{ áù×i­—ÛÕ­•¸”ã‰A òû=þB5÷÷¾ì/èGú5 ìõ˜pœú×Ãåï‰ì‹Ù†-ñ¼_.UÝ£P¬bÕµ+TÞ|°×Ióà8áOJ粊Ñw›¿“ºý;{¶[Ä´ÆÕ“®Úây«¬ŽÇ-†ã)iáéKuÊR„)EcŽá'÷¾ì/èGú5 ìô}ï» úÀ~Bû=VŒxĉgˆìöemuå¤=àY¦å°‡¢KôgžòT•Ý…'Ì%(õ(€–¾&&Ó\Wà6ø}6våBï-*îrÆ"À®Œd8Ë 3RÚü×_--HB씨¸[á=@ï÷¾ì/èGú5 ìõð…ðüã®2ÞËíêœd€âŽB*G#‘Èòûr;é#ñeIb[wcaó-2MÉ6 ®¥zcl"¹î)«eIa,2êz:ÛCŠZ–ßJWlþŠ™ØõŽ 0êZÀí¨¢3wœ>æDVáÎoL„>Ԉ茵¹ÃË @ ZÕÔÜ×_{îÂþ„p£P¾ÏGÞû°¿¡èÔ/³ÖdÂrÉÛ¡²0¶'sò¬ŽÙPQ'r«gd³íkÚªT?ZCé˜êÐÌIRC~WJÔIä$ê?·£Ç¼cdt¹nIºKÆNÚÁȽ͡¹Èßa™Ê²šÛ¯`8C -2Úx! ú¿!$è/Ͻ÷aB8Ѩ_g£ï}Ø_ÐŽôjÙê¹K»gáleXÎ]{c;2-¿Š½“X92T97o§Ð#8ó«ZÖÜc)±Ê”xi’T®V£¼%ØË¶Â󯙾ekZí•ë´Æá6Ï7:}<‘é5ÒŒ¦%jee²¤,XPçAkýï» úÀ~Bû={îÂþ„p£P¾ÏY×ÃÖ”gž 1 ч»{pÆÝ´fêVYc=—&#Ì(ôˆr^r3Í„… ·ÏO=%$ó¥ÍÐÏ7/Äg†½Ý½¯Ê²?9Ë¥Ê!ªK©±¢I•ŠâaЏèsËu§&W4Ÿ]+WAéä‚y [÷¾ì/èGú5 ìô}ï» úÀ~Bû=g¯ûïm¹Þ`äG’ZcÖYnk›»:®S±æUÁ¬¯T—’‡[)Zé¦Uw¥×{ö஽)4ù_…ä^曫&³2À­çä VäÙç¬%·µÖ[Q^[¤¥ÉOž¤ŽXÕJ@ O÷¾ì/èGú5 ìõMî…`û£6ˆRcìI ­qæªëÚˆ‡V$NJ ¤;ruextfšÃ¸Î±Œ—2°£ÉíßvžÆT·«ú¶e8·‡Š·úyJžP!ËmöÝd÷ù†'â=¦Pñ“n¹9„Æ¥=Ò„ùªfCëh,%¦Ð”…§¤žFƒ5lŒÿ[Á†mf÷ÓØºÜ»Ëh—Y§rÇ["™ç™P[ª –[-4¢–”>­”•¸¢Tu½[“AųmØÛ¼ÿ9¼z‹pë+ã^5/Üú*æ¤(R*Q Î鞥¼•È1øRœWŸ/i {E‹ß¹ŽÓ[Ö‡,½Ù÷*.EbÕBgy…Ã!5É|D +!Gà¸êJUÇ#GÛøJØKÈ÷ðlq &´7vPÈìØ†»ò2ÛŽÜ„´ÃåÆÒ¯1¤¡\õwõ•ÈVx¦;a?Æn÷ß=šeêN1IˆM[Ë¢<”©nú2Û =Mu%])wug¹QÒîÈÏñ%¼fÖo}=‹­Ë¼¶‰uJw,qU²)žqI•º Ùe²ÓJ)iCázÙI[Š%GZ@lfÛ£pXÝ6+íãå Á‹Zäèù ‹>™9QeÚCá¹}%jõŸK„óÜFÐøkÚ,^ýËüvšÞ´9eîϹQr+ª;Ì. ®Kâ YY ?ÇRR®9èñ|6ê‹6Ëò™û…uw #v¡RÌò½2ÉBÓ¡!\:HZº‰îËÉ-ºTÆv¿ Ãó,·?ÇêWó9v#×’L—\WŸ%’¥7Ò‚G çžO'MzFFFFFFFF ù¶û_¿;'o•c386A„_ä“rÙ6öóaØS™®—¤0Xn+ÍÊB]RÔ†d¢~Q!´Ûm¼86a¼y-œ5¿»ËwhËò¥y¢ [jKjŠ×%޵) $t€xêÕç£@»·ŠÜa4êÝTP#-1Á¶Mîx“ÈcÎøNž8ü.üó¬÷?awÊf+âB5Ø*]Þs+Ü…œŠgL1"­ºóéÜú©lº::º‰èõZ›Fƒ7«fw©Ìÿc2´ÄÃcÇÛ|bΆä¢úJÞ.Ín+%è©T—Ch†—p·Ö§ HOZ‘)|,ï´*=±jÖ·mgä¸i&¹É\»œ» ©-µ1¢ä‡— N2ïL”«Ë*yŽ”©´¡ ì½ Ïd÷²=Wˆh«¬Â Û´ûÒ)@ÈeôÇ.×3¦IôSÂZ.ò€¾Ià_W>Îc™µŽ–³Zݵ4J©>çKrLe˜í% ´8ãM(…%D’¢Ÿ[Ž¢ã£A“±Ï {½'Ãò|0æ/á°ñiöönnkìåK›&ºMÃÓÕ˜ÎEi ¸´:.—Vë(%GŽØÛÕÛ]ÏÜ\ãj¢â÷P7pì‡wg& «-XŽ˜Êp˜{ÎaÆÛiE?¤©$R QyhÐeª? ¹¶ØUl-½ŸC|æÑͼŸkî¼×ëSbýœIHyl–Ø‘å>c‹P<$ò}ºðÌ<)î^K’Lßx™>9uÓ“ÔdÑ?ºJÌJø¯ÅEk¯‡œ7.Z— 6“Ôâ@l%=õf|Ý<ÄnìcØûVU¸ _¸ù,;+,a¬–{õ·õÈmÔ½T±µ„•­§Ñ޶Ék‡:Ásí¶Àç¸þC½NÞWá”Ô»¥€Å §—î[U·L–U¤) ¨8•$«ÿñ£ž¢ôh*ß ˜–æmæÏâÛk¹µØÃ2ñ XQ¥ÑZȘÜÖ£0–C«KÑ™,¨†ÒzAprOqØj»Ý¯Ûƒº¹Ò.dÑáõVÙ-u–5ž@±y‹ºÚ–—ra)”Frœè’ØJßSE/õ ¥´h2Ü­„Þ鸟‰:``í?¼Â_¸«NA-H‰çÖ5^}'û€ô¡²÷¨É!¾Ãá5Ób÷¥¬×ȯë0 –¢Ÿ ƒ{‰mq-È´vŒ:zìa·èeTã]•¥‡G–—I:Óz4ï ðÓâ ÛíÄ[·Ódìի󥸬–kMØ6¨²c 7ýîQB¤õA£€O<‹/?ÙÜöû ñÛŠlC%MÍ|rú‡%–ì$ôÇ}Ç#Ë%¸ò:VŸ=Ô­µ5Â’Á öß:4ï5Ú]åw+ÛèÂ!`Íf„[J»\msdG©›]9ÆÖ¦Ù––ãn¶¦!ÂÇJÉY(H i^ãa7úâ·Äj_·âføV3 QMKU‡Üd×/ÍQ€Ku…$3Žékž«4h3žA²¦ívÊç˜ì\QÁÚ ¨3a®ÖG YջƓKC€¨%‡‘ÔÇJ\Gžõؽ¾ßxþ#­7¶.)€È; ƒ‰¢¹dÆÝ fd‰Jx¨V©=$È( ÿôêäsÒ4uW¾9v{{çbÛk#o±ÛYv1)"Ü<ðˆ•BnVÒÊ«[mô²•Mp¨r¹(à¤2ž¶+¹8Oˆöwsdðí½‰ÌÅ•]ÕÈ·‘X¹Î!òüi mˆ¶…´¥º‚®IZ<ðRh ±¶[1âðãŽøs‡'o(ÌuÓMË#[ͱËk* r4Ca%Εž•.@ P¥c¶œßÙ ‹ kd0ݤ¥ ^#µV^—!v×/ǘë^åN¯!n+ˆqgÓÔú”¥  §„…u&ôÑ É1<æ8® ¿¸Æ+sK`­È‹kI†Ä°–ìh¸ýM‚_yæÊÊI'JYBR°´4Ç+Iì‰:Ý—ñY•lvJŒo^M‰ØãÒÙ9\Ôús²X†Àqµ{˜z‘+¸$— {tõ+QèÐ"mä Ð{'6­Åéén/¸õTS—,4ù[îL}×9êun´xáC”(ö*W5–ô|l¿óv»ë3µ¢5÷£ãeÿ›µßY ²|>üBí·Í ©5§ý x}ø…ÛošÿRkOúF\®ÙÖ³5º×¬#7-äõ7N¤8±ß¸O<‘ØÿäuկϘ4Ø^Ú×XíW-©°ceÎØÄÞÐYÊK¶ zܛз+JCL!·Aà¤h?A´k:ÐîföZx¦ÜÌ,MÅÂ0ªÌnSÌÉDƒ!¸ò„çy¥ p^RZA^  7Ò9ë*ZÃü`幪p,Ƈ?Î/¢×Hô–&ƶºS…¶,ÿâ¬'–œu €…¨VQÔCWèÖ_o{|Md7qŒ?Û‡ÚË¥BLYNÎó-ZX—å%ià4áK¥!Â’®B@ê7¶Õn ^ìí¦-¹´ÑÝ )¨‹lË÷[!æ’¿-GÉI%$ŽÄŽGm9y”¼˜êuÕ¥KJ ‡R’’ {HIäþÑùõ÷¬ÃY…bØÿPXR1Úva¿q´÷3'¼ –ä—ݬµ¨•9 x°vÕäÔýÌ;¦õc¸õ"vý4Iy«DÍY°U·ŸÁ`±ÓÒò}n®yêàw䄃f4444ù^c‰à”ëÈ3L’¶Žµ KFU„¤0ÙqG„ )DrµÉHä¨öqá[“€n;d`y•Eòk_ôi¢´:¸¯qÏ–êAêm\w@;û5SøžÛÁË2¶Î¶žÏ“–må¤Û¸XÎA!MDºmqUÞžT‡šÛ%(S€¨ŽF©-Úß)ž|E䘾'w´»Á×Âg3ƒ&Be>Ø[%¸®FÚü¢…±æ>ØJ½Bxä%Z Ó£Y¯p7u° ßÙº‹|’Û)bÚòÆò¢Š'ǯˆ#¡,FŽêŒ~µ; :àXJ€A* J®iºž'±=–Uõ¼ÓŽÝCܺìv¾eµ4W¸£™6+MH}†œòšp .¶ ßGQg‘ÑÕ΃_j-Íðü ±79®M[I ÇS·§IC)qÕsÒÚ:¬³Áá#’x=µNbYŽê`þ%cì®y›³™Òå8¬¬Ž¦jªØ….¶DI ´óxCŒ­2¤¬§¨)%$«Û«qq½³fÊ‹x÷ æ¡9¶¢uŒ 'æ8Ë0DˆÊ!kHPCœ´²A>¯è&ðÜë ÜJDä˜UUU­Å³éu²Ñ! ê;-²¤Ò{žù@Ôî³VÇíöá=_½;»Ž6Þs»¶fÏg©5­³ 1ãM•¨¼ú“ç¸Ñ…®¤ ‹ÆÈ!ãU12Ë8Ö7ŒAŽÝœÈ¬y É––Òu¶ù=R”Éà9PSÎXç¨/lMuÅŸ‡M”gÃî|ccT⽫G²J’äÛ ¨ÁmIŠÄg‹ˆ)%$”X4644444³¾ô|l¿óv»ë3µ¢5÷£ãeÿ›µßY ²|>üBí·Í ©5§ýQæK¯ð,Äøž*6Ó%æee4âiùJ’¡Ý*îÓŸ¼×ÝVÿH¬¾ßAbhÕQ{³»OHÃÞ;©S%/ʇ ¬ŠÇÌçð9‘ÀwRd€I×öæ2Þ»fÚLÙ ó äVA–3m?ž‘ÿhúÊ<“Çd¤-mfF¼+îmþÎ×øsÜÝߤ¾À!·$·ãã1si;¨u ºû³iµ6”­Ô¶T¤ƒÀBPµýà6»þê·úEeöúMf0ÒÝtø´k¨”µÒ v–ídV=RB¸\8¤¿Ç ‚—žÝ´|/Z˜ ¦öO$«ßŒ“wqìæ­º|Ö®®³" °¡\¥¾ ùáµÇ”™-†J‘%i!M:>^ý€ŒÚMÝœ­­ÛÌsx*äm多¸31•;pÌâ– Þ”R:P1‹ŽAA¯Þk¿î«¤V_o® ­šÚ(^™2ªéek 2ËY’éüÛO¤zÊ<Ø$ 3æÔ5m»«â_ ÛýëÅê+îr¶Ûš˜uè°µôeTÃaçâ½éA¦‡P-.;¡+J¹äú©×˜^!C·ø}& ‹ÄôZ|z¾=dy䡆[@'å=)Ÿi0Ž—l/áZ‰2ˆ)ˆÖGbYˆìm'Ïåjÿ´³í>ÀRÞð]ÿu[ý"²û}ìý—܉>""o´mËÆšb?#j¡x£ëY€ôÆd¬ª@°½Ìt$,49Q(=€zkϺ22‡sô¯ rZÅýËhìCåjé|ù„¸oÊã§ùÞÝ"Xl¦ÞÝØ9ãp®DeØÙ' °Pòù-rù x‚9ä€y<’”–x}ÚÆÐ–ÓUpB@«$²QíùÉ‘Éÿ)ÐXÚ5XZì¦ÏÒÀvÎγ1Ù©_tj$’”¥)|©kRˆJRT¥$® /˜TÇœ»¼«ºˆHLZÁ’X¯o.©2[ÊíÕÁ(G)ç…8à[Ú5]ûÀmwýÕoôŠËíô¡“m62ÑXFYdnJ¹Ó—b¶*W±ÅHáo(såµòþ¸@îžVuþ6º!—òK(/ÈÉlTë„{T£çÉ=û?0¶¿³v7h«a½aaÊ4hͩמw$±JBG%J&Gòè,½ª|>)(¬Ì Fnшr¹L@bû®¼ÄGŽ´¤ùªRÐ Z—УԞ²®@—ÝY™º.=ev÷ÝFä “ 1×ü„UO“ПIeÖÇ.Fk“ÐO€G:}ÍÙ³¸^/žÓnCˆäx‹ K«nÍ»ié >̦JÒ}¢’ž’’9çäÔ ß æ¸X†Wsy7t™C9=ü§ÙE„Û^[¿)¤°ÊYHø4% y* *QW&îýÒm.;5¾»9Æž‹$Ç hË›*Cq£3ÖkHSÏ6 ¸=)êWŽ5Õ·øü˪™ïŸ¼ù m£3Þn8¦4²c¿±iÞ\©B² J’Gµ<ƒÁ®EáÆ6K_ŒI²Ýœåy†óîÑfAu赌‡›Kn°âQ1_eaëC¬+¨¤yŠãÅÆ’Öld Vîãf—3óŠ5YG¥6“¢´Å„gu-B‡è졦š+JK!*P<¥jQé÷¶ÌÿX,û÷*áº=í³?Ö >ýʃønƒËÚŠ:L¢NêNÈòL£&·¬j½™Ziøµý^hŠÜvXa¸é+!KPqJJzÉ)Do¯‡ZÝù—Ë´Üüó¼¥NˆÆ92#L¹+·—!ÔHŒð[p|µvè*$wà‰Ï{lÏõ‚Ï¿r þ£ÞÛ3ý`³ïܨ?†è±_ ÈÅêó˜¯ožéÞÚg4Ñé»¶·Œ©õL±é^Rá8ÄfƒK šòú”ëû8ïkcTÇÇ*±å[XZ¸LB3¬^ó¥ÊòÛóžsÖâºz”®*$évyW.º‰LÚ4›y*‰§ccé\§ÒË)¶Á­õ”eÕ?šÚ°k³ÞÛ3ý`³ïܨ?†èôj´ºÃï1ºyÙ ÿ‰LÚ¾²²;’æK“m¨ì6’¥¸µÞ”¤Iöªët,÷Oo7+lðæ7c.QŸÜ»JíŠÞ¤nL7‘D‘ÓS”­1ÇQu$ÇIöè4† {Ûf¬}û•ðÝöÙŸëŸ~åAü7@ÿ£HöÙŸëŸ~åAü7G½¶gúÁgß¹P Ð?èÒ½¶gúÁgß¹P Ñïm™þ°Y÷îTÃtú5Y^à™Å]œâ‰çЄ¤©(*ñZ6ííÄì‹Ʋ 5¥s,éáL¤¤$)×BÔ@€äžÚ TV;`œ÷+ΰíèÍ1Cœ=Eä Ö<ÊÞb#Qu…IˆãŒ/ÉaG©@wÛ±—å[¹wŒWn]þ5YQŽSÏmЍµ«ó_•&É-j—å~ F@ )ƒØ“®ÿ{lÏõ‚Ï¿r þ X°ð«·ÃÛ¼ ¼ÈðµmtǦãÓéd°¹M­ö]j@tÌeô<¸\+AR”¢yžzl¼;G9ÌýÅ÷W5Ãîï¢F‰‘»Pk–ÝÚ£µåµ!ædÄy¦äô§Ìe ú© ãŽ8ž÷¶ÌÿX,û÷*áº=í³?Ö >ýʃøn‚“ÜÌk “âÏk Ò[îMT*L.ÞžVOY.zD‡Ý…ä6üɤEåa—µž8R=e'žm¦Ùc[UE&“TÙ ±žýµœùò òìgýʃønÿF=í³?Ö >ýʃøn{lÏõ‚Ï¿r þ Ѥ{lÏõ‚Ï¿r þ£ÞÛ3ý`³ïܨ?†èôiÞÛ3ý`³ïܨ?†è÷¶ÌÿX,û÷*áºý@÷¶ÌÿX,û÷*áº=í³?Ö >ýʃønÿF=í³?Ö >ýʃøn rºìç¶kx²«¦¦duµ’`Ùè :ćƒkäDŽӀ€®AJÇp9ävÐ[ºÎûÑñ²ÿÍÚï¬ÎÖˆÖwÞ—þn×}fvƒ¯üÿÙü›WUíëŒ7ðJ™)~T8mqæHsŽxöêQì :¥ÈðJG'Þ‡°çŽ¼Ú¸è¨Ÿˆû—WO·*æR:uùqÛçà ÷‚Oµduæ¥ QQ?÷.®ŸnṲt:ê9òã·Ï!†AîŸjÈê?ÍJfôi"ÂÂv:F;ŽÌz% GUÞÞ:ÊâO ‡c¸ ‚—_Iø>í¶|Þ¥0…„ìþtŒw˜ôJŽª=½¼u”9!Äž"ÇpA.¾“ð}Ûlù½Ja¾¾¾ LõupÙ‰#Ia†@Cm6‘ÂR”ŽÀh¯¯ƒS=]\6bCˆÒXa†ÛM¤p”¥#°𺺅E Ó&y‹+Xi–ZOS²?‚Ûiþrö $Hêê/L™æ,­a¦Yi=NÈtþ m§ùÊ<Ø$">––k³~é2O-vkAC !]M@hû[lÿ9gÖçµDp8HE-,×fýÒdžZìÖ‚†Bºš€Ñö¶ÙþrÏ­Ïjˆàp§ô–쬧_N{Çd©„0®‹+$p}·>K\ö/}½Ã`òy%)<ö²ò+™–.ó¦!é·µoŽ˜d€Dv‰ì© Iå ¤…+º›J˜«k`ÔAf¶¶2XŒÂzP„ò~^I$÷$’I'’I$’N€­­ƒQšÚØÉb3 éBÉùy$“Ü’I$žI$’I:þZÚÀ¥€íœ€Ìv@êWIQ$”¥)H*ZÔ¢”¤)D hµµKÛ;9˜ìÔ®’¢I!)JRTµ©D%)H*Rˆ@Ô=UTû‰ídÙ4rËŒ’ªÚÕ((A\p‚R¹ I ¨–ÒJO+[ UUO¸žÖM“G,¸É*­­R‚„AÇ%+¤’ )m$¡òµºÇ£J6Mi2ÑXF¶ÍÉBW:rÑÖÅC ö8±ì[Êùm|¿„®;“dÖ“-„a lÜ”%s§-lT0¯c‹ż¡Ï–×ËøJá¼Î3ŒÕâui««C„©çßy}oÊ}]Öó«=ÖµäÿÎ3W‰Õ¦®­V§Ÿ}åõ¿)õw[ά÷ZÔ{“þ@8ß6l:ØoXXJj4hͩמua(m •(žÀòè ³aÖÃzÂÂSQ£FmN¼ó« ChHä©Dö—Kð¡LÊæ3yyØÕ‘œKÕµ¯ ¥kZO)•%'¸X<Ú?‹ìµ3¥,¡LÊæ3yyØÕ‘œKÕµ¯ ¥kZO)•%'¸X<Ú?‹ìµ3¥,³è+½¢ü¥¸¿<äýR&½w'ùgµ?;äÿÀ-µå´_”·真ªD×®äÿ,ö§ç|Ÿø¶‚¬ñïCU}³t,ÚÆ/!ö*€êÐ8rÚ;k礎yBÔ?g<Ž}E7…c3üY·²Ù];/àttÕ¦-ŽOQ‘T·lDÙJmÕ(<óIòP:‹iw‘Ó×ÉÐÙ–ÝíþâÄb¿ppl{'‹Ï9†.kšÛNvõ’—R •vÇ~ÚóȶÏnrêØÙN[À«ODÓkYy¸‰èè)i*I ‚T„ð {{;h0µô‹›¿·ÑWlå>-¿ñ±ì*Ñ«­ÁH.¡´ÛÜŸ9 ­rXB—×ÂZ¿›O}v[o1MÄØ¬w®³!Ïç FÚ¼ž/̨–·:Ö^ê=ji]ýo[žz•μÚ]ªÉèk±l—lñKjZ€‘_[:š3ñaô€ä´´7ÀŽ8àkùo´[Q.™Ëí°Ä¬•޶ÛTæe,gr!1úÐ|Çm$Ëv—¯ÇüePF¯ššÝ¹®÷[‰îœ¯&Ž[˜ÛS–ìTy-(È|¤{Oàò5hK™Šî–s‰â—´­å—õ{WæÙ¼²Ð5A ,Å$é`¶ãÎëa`ºŸ-(l]J—Æ´¶3dÖo ö{QÉÇ„ãѺƒ¬9ÄŸƒø])W¯Ï¬öFÇl 4Ê?„sŽ ·L~çâ{R\óJcüÀ0•ðŽ=cÏ·¾ƒmí6ça¾ÜÇdÜ&Ñ»¸2Þ™=ä©àŠy…„…ƒÕÖ†À<õ{ŽÚ°wVй÷;…wŽWg›s÷C‹ã¨‘ kˆ¿À¦°¨L°ÄdºŒëβã‰eHpúJú‚Ƶ û²2q¦0¹;9ƒ»E˜lX©^=PÚ–Aô°[èKœ:Àêàžúõ²ûC!FYk±F.[[."sTñÐò\e¶VÏZ„«ð’‘Ò´GÿPºøö wGÒZÌjs!¾•©<-.#‚zHäOcÈÒ®úm†ÞSå^0ìjµLcÖ›)÷c ‡ƒ”“y!àç_J’”‚¸)äwóª-éêr ©tWÕq,«l\ipæ0—˜ÊÇ mÆÖ V’ $AÒc^6 †«Ycd0Û¦t¿Z„cP‚a8H%l€ßÁ¨)àö qœØÛì¾?â‡ÚéòñÌr“0ØH%ï.’¾Â%q³}’ÖÂJ]uJSdTžžFˆÙíž°Á÷qy´£ ¯¥¼Å}ãX¼W#ǰu[6…*yajBq²âSʃèêQàskWífØÔ[]ßUmÎ/ Ï%Kˆº›¢;oÙ¥g•‰.%OÜ,ž~]xàûCµ;dä—¶çm1l]É€¦C”õá­äõô©M!%I $€{“/⻉u»Øvm”Qe™É®–¨SÞŽ§bš™®)®P¡ÇQHC…ø*Iàˆœ£ ÚTîüM’Ç0˜ÖhÃðwì]«ÉíÔœv¦É«>˜Ó.!×^˜ÓƒÌIBZh”ù¨* ÖƒËö¯l7\IùîÜbù,šðDG­éãÌr?>ß-N¡EÓìãÛ¯L‹l¶ß/»¯Ér;Ʈ­ê@,,jX“& §\AS~° õHî9öè0¾!&¾Ã_…™³‚rð¹0«rK9­zBýÈ™çDm×–®T¡C‘œA$ô²žäó(ˆ™Bò›]ƒÜa"lÏë¥Í¡E˜ß˜*–© 7q['Ÿ-Q ÆŽPö,¤ƒÎ¶Œ ¬Û¼Qü³nqx˜Ô§ ÏÓ1Q¸.¸TT¦€Ú•Ô”«’žyH?&¦ePQN·Í¥"Ò­·Úƒ9ØÈ\ˆ¨{§ÎKNÔ€¿-A$t'žxûúø8UTð¡B¨z³š××n´ÿ¤ _¬Çæ†5õÛ­?è 4h 4h 4h 4h 4h 4h 4h W{×ù7ùçGõ´jÄÕw½“q?žt[F‚ÄÖwÞ—þn×}fv´F³¾ô|l¿óv»ë3´àþÈ¿äÚ¿uA€_û"ÿ“jsw.K†-&=SycU2Ù4råR8Ãr¥Ê)qJ‡×Þeé ,= ,ø-·Ë½J`ì,'gó¤c¸ìÇ¢PÄuQíí㬡É$ð¸q;‚)uôŸƒîÛgÍêS õõðj`Ç««†ÌHqK 0Âi´Ž”¤vH5ùÎIS=]_‡â$8%†bN>†Úm#„¥)\¯s¹YŸêûŸþûAüK@áuu ЦLóV°Ó,´ž§d:¶ÓüåìH‘KK5Ù¿t™'–»5 ¡†®¦ 4}­¶œ³ÀësÚ¢8$¤ œÏ8]²îr†ÍŸ·!ˆíXP©¸,(ñÒß6@’®ŸYÂQDë;Ÿ–Èi/±°Yã¬r•¢}J‡çY÷ÐX:Nºº´É­$aØtµFôe\Ü €|†y+”¤{‚–’BÖ (BÕòŒ÷u¬â³YìnsZ™.tLŸéÔ%øìpy, Ø”—Od…/ÕG=\/ŽƒÛK—ßãµq驼9g‘¡ÆI ¶'Q(òIR”¥*Ì©kR‰R”¢T¥¢I$è©ijñÚ¸ôÔÑdÛ`•I*R”¥¥­J%JR‰R”J‰$“¯»[X°³³ŽÈJé*$’”¥)KZ”BR”‚¥(€$ %ûäæ«î}ûíñ-AÇËsé·F÷!ØåÃÅŠ¸Î¡SQSÁOœ®l‡SëI «Ž•#ÚâÝŠª©÷Úɲhå—%UµªPP‚ ¸á¥r’AP%-¤” žV·Xôï“™þ¯¹÷ï´ĵ“n.ìH¬1qM…Ì¢Í}ilË•2‰B+gðCbćà¡E)'¹<2äÙ5¤ËEaBÛ7% \éËG[ +ØâDZo(såµòþ¸@ï3Œã5xZjêÐájy÷Þ_[òŸWu¼êÏu­G¹?ä€8ÎI}‰Õ¦®¯ÃÞáV§Ÿ}ë ¿)õw[άÙrµ¨÷'ü€pWß'3ý_sïßh?‰h&͇[ ë MFµ:óά% ¡#’¥Ø>]/Â…3+˜ÍåäWcVFq/VÖ¼‚•­i<¦T”žá`ð[hþ/²Ö<Δ²–þ[Ÿ\] —›œªº¨r¾s¨T•ºžÿ6C•%_‹Gt¤§Ì%Kèò§=òs?Õ÷>ýöƒø–ÿPw·²˜”Š š‘s!°àY†É$zCüzy @!N)$”¥ÇQµÜ­ÈôE'‡ÌÓÓUÂZT©Ô^R9 ¨&Ë•tŽO@)ê '©õ*“ˆ9] ÿh³šÑ}k‹›ïy³Pm=èó–¾ Hl¥ JR”$;uÎnG'I˜â3)EÉã«1b•(ð’}T€‘ìH;÷'ùgµ?;äÿÀ-µå´_”·真ªD×®äÿ,ö§ç|Ÿø¶ÿIYþômnÖOª«ÜÒ«µ­ºöäõs!iJ”R’ð…prG’@Ó®³Ç‰…OVìì,¨XÖKe“2zÊÊE]ÙÌÃŒºÙ‘Òã®0ÒÒæºÚx$ÔGH$ž0ü6³O.õÝЈˆµ¯®5ˆ0¥‡«Ö’£)Ÿ+ÌŒžVŸ]Ô¡'žÄéã(Ý\ ô[Þ)×íc¹2ZØoØÉ‘%o¡ˆ¨qÅ2ž´u8Ð:ÓÉCœ¥•Æ»šÇ¶``9²ÎcLˆøøN#f³ßsÍÀPýÏðÇÒ‰O(ç·.~,ëʲšÆ‡sñ=ÊÌ©wZ&'}¶t¸Ëqú‹dL©³‚ûÞtYØhËm·KÉ(Yk¡JO·Ž•Ò–ž$ö*–¯º³ÜÚf`f-¨¤u©MÎOB— Aõ¸B‡Iá]C§Ž®Ú…sƆÖiåÞ»ºµõƱ°õzÒRe3åy‘“ÊÓ뺔$óØT1áÒ<7Tí®Þn 8Ö?›Y]HnF9g)ø1äDZJŸ”CKS=r$…;Ò´¥Ôõ%˜œ®5ÜÖ”JyG=¹sñ`¯A«2}ØÀ1ªâ[_¦]2¹5Ыb?c.[Ky¨ñPã«i!I%ÀžÔžHäj:Ç~öv«¥Îgî[t9 ¶àÖÎ R›~BÜ ½PJT= ¥\…pAնȶÀ·{Ýü›˜Ư6š¯fB1«%SØ@µ¿øihÈe.õ…!e •©¾ «oó:ý‚ÉÞµÛÜ¥ñ¸;èÆs_A•:T*Ci Å™1ã¶ç’TÛÈSk_ RG_PÐjz¯û#{‘Õb”¹t©öW“®­LjIî5*C@)Ô¡ä±å„).)]])mIp‚\1­ÃÅrë܃¢‘=Ùø¼±ÕÕÊŒ†$%aÇ[J%µ¶àèR¹C¬z«I5/‹H’åmføâ0äª÷kçÄΫZu…ÆôV‡¢-·\Av²[-(%]e €¡ÚÆÙ¼^ÛÁ£¹“4„dw¿{xA )e× þrY K?öFƒÁ{õ´­ÑeÙ*ó“[É\L‰óð+ÝCiuAièê 6´¯© Ž“Ï:î¾ÝݾÆáPβ¼uϺ†‹ôÑ À“6\ö’Ðun5†Öò–Ô•)A$)=Dr5”sådÔo»m#osy÷;}Ž.jñ©³¢Ù´ö<ÔP%–ÔÒ—›RJ¤¨žBŠ€,¹µ\+ì_g&¥ÝÏÁrÜw}Ê,¦§Ÿ(À—åDiúÙÐ}aï)* <”ú?¨y#µ½X¶G¹Ø$|Oy隨¶¢°ºz…u.9"Þ/”…µ%¹G ŽT¤)<¨,m{ÅñqáÎjàˆ›£^ëv~ã5!1äz:'y¥ Ã¯y~[ +$8¤õ{G#¾©zk}Û»>ò]ÄÛ;ê«j<7!NTŠlV{µÕræ±ÈkÌe•4…(²ï(JÏ–¤”«ŽÜ¤Ì®ÉŸð1¸˜z6놌~¾%g™ÇJOH%+!$6i¾{Y·¶«2̨E‘S «+0Ô9S[Å)-¿-l¶´ÆmE án”‚³Ï $3ã9N=™S3âÖÑìëd•¤°®P¾ƒþQ¬w¼²ƒ›¡¸Ñp˜N ÜìF$MÀr« væ]#¾äÆií=C¤8µ¶ë/)-(µë‘­U´Ø5ÞÖâ–gfl1SSš‰*ëë\VÛ £¬,…€Ž‚΂c/þIÝÿ£¤ÿºV¢6‡â› ù»[õfõ/—ÿ$îÿÑÒÝ+QCñM…|Ý­ú³zê_¬Çæ†5õÛ­?é—ãë1ù¡}vëOúFFFFFFFUÞõþMÄþyÑým±5]ï_äÜOçÖÑ ±5÷£ãeÿ›µßY­¬ï½/üÝ®úÌíR’à ¡\ð­¡àðxþ¥üúrÜÚø5.m•]\6bC‰—Ca†@Cm6˜r‚R”ŽÀi;üÿÙü›Nû¾´¦Ïn”Vi$í>‡,ð?ðÿ-ª#q|Kßm³6ÙEîÓK‹‡Òå±wgβô[ Šôv}252Q"0\”€¯=*W–áé<›ßXÛ;ð§¾n)Ÿãr‘·—W^ÖAU—ÛÚL6~ç3ic‹G¢,ECm°ZIeŶ4 Ô 'ÄäøªßÚ©½C°®vÖŠM”eÂiMMyNÙ8ò xqD!©@“ÒŸÌ5üðá¼ a>¼:í½ ¾Ì3lM…UÀT±;QâÆmrdÉ¥e¦€:[ZÔ¥¤%'¹ ƒk·½ÙŸnz(peA˰êüvÕŠ›’˰랆ÃÐØy¤:Ò¼¿9`9øDÎx¾«É3Ü"Û¸HÊp¼E¬Á¸ÕWâdY‘V·‘å©çeLº•0yJ›>ªò_Ã!³÷k(ÙÌKdì¯î±ÚÊû„8.cE&$—^GYZû6G®”T¢Gd¤)iðÜ_÷ÛlͶQ{´Òâáô¹D,]Ùó¬½Âb¤=ŸL… L”HŒ% +ÏJ•å¸z@O'·Û}ϪñG•îÜÊü\â¹%m w2`Ï¡®S‰t°bÏZ¤¥%>pé '•~ª ïžøe¸¦ÊFÞ]\d9{YV_oi0ÙûœÍ¤iŒV-ˆ± ¶Ái%—ØpÐ+R€[®x“Oœnž#—a‘«ÛJh÷ÍÈfÕo»qHxÇ,²c£…ÂÛPëWK½(OX!z0ÿ“w&ÔÎÄ0˜Ï#q¢Ê•9™–ÊbEaô¦oRÂÃÞKªò¬Ž]Si=!EHçÜ]„ÈóÝëÀwI«JúêøU¾çfu¡ç3Ú)‰ða^ZBƒSYWR–ÔÓ‹>±ôÙmºÛ ÕÜ,¾Îöêy￈Ák¬9RÄç½2Í 6a $Ž–{RðÕm¾’cäÆ&L}¶c0¤q×\XJBe$•(žÀ $êÉÕi¿0aÙÑbð,#7"3Ù•\iÄõ!cÓxP=ˆüàö?.ƒŸanaä(Ïn«’÷¢KÌe8Âh¶\oÑbô¬%]ÂT8PäAJnOòÏj~wÉÿ€[kËh¿)n/Ï9?T‰¯]ÉþYíOÎù?ð mþ¼ÔûyÖóiuÄ©Hl¨('Ž¢´Èçü£X{0̱ø{±¹¸W‹»4Á%äÎEÛl•6vqèÕ¦3B1Œüg[e÷˜ëÅÕ$¨ô$«¤é«2¬±Áü]mUž%‹ÆÌ2™;gu\ðó0\µS.Ö¡%I_RŠ@ê#ñª|A'A®ôjļGÝf{l¼ª—h.ßÉcfàó¨’‡›`ÄÃ矖ÚT ¾’µ¾–ÔB}ˆ=¹†´ñlý»×ö›oçÜlÓèEÝ}mÛr#HepÑ).±)m¶O¨¾‚ÐRTàü¢4j¼ñ1/¡ší´Šr;˜Š&ÜÆJ­ž’ÓŽ)O÷þâm¦ÚS‹Sœß±%Ï‚Ô}ŒL:5FâËË*Ùn~Ü9X™LcÖmÛ±h,yDÂ¥®·y+g¡iAJÓÜôž­ü·ØmÖØ[Í¥×A- ¨/oåã‘ν5’n˜É%xÜÙŸ.Û,s´´ÆrĹ"¾ÌN™) µ¥™nÍYë=!+uºçJ‡µUî’ÓäSç퇈ÝÇÍöÓ~§dÒdUÙØYØÄ­–Âg¨Åj§Ë}¸ŽÆ1‚-r Ôµ’•¨ó ×¹¶ÐÔgÙm.K{“äé…N‘æcÑ켺‹¡Ô<Ó’£ôòê›q´)<) ñÒ ¤’=ê†Ü´Ø}þeŽãU4×°È»EŽFÍZÝylz@‰ +BÌ™’…(+Ël[O˜TT$׈Öòˬ_Ú\HdVFŒýtl=Íeª·KiŽ°Ûª/:·8 éHBŠ–=P ¹ôk2ÔøÎŸc›i“Qlu옻£dýUJq ·ûL>â‚Á_Fu$’8é$uz©W͇‹ìæ¶“ræIðõ4Ym[ùl_ºX¾KqDLC±]èê¥GQs¡M·ÀOED œÑªS'ñ=Á¿¨ÄqV*%\ÚcŒeK÷ÓÄ‹òS+x¡Ò_uIs¥´¡@–V¤ž¥ØÞ1™»Æ6«'Äv²Úá­Ó°—K‘g•A±Œ™>s++WJÒ•Ãxy‰<ޤõAáÿÕ‘³¬‹;Ä·4ÅËÝjEü ™1 K›e,¥Þ$GuÆòЄ•Ç[J=)<òøž)`ØÕn!‰Õµ[OQ1aÅl’–›Hì9Q*QùJ”I$’I$gÆñy™b{C½§jÓSm2nEkÖÌ„S*:]‹1/%(.µÂù-ô¥| §±ä¥Æú]ýU£^%·'›ŽFÛ¼;'©¢Y¢{²ZQ%#Ë)B”RBOʱÉöpæ_ü“»ÿGIÿt­DmÅ6óv·êÍé3Ý,Ÿs0ËKK,"¾º–ÇEÍ]µe賋%/¡Ð¨êXe°—›èa%hõÇ :sÚŠl+æíoÕ›ÐGRü}f?41¯®ÝiÿH¿YÍ kë·ZÐ4hÐ4hÐ4hÐ4hÐ4hÐ4hÐ4hЮ÷¯òn'óÎëhÕ‰ªïzÿ&â<èþ¶‰¬ï½/üÝ®úÌíhg}èøÙæíwÖgh:”HðHI$m°|¿ÞmNîE‚ï¶ó"È”“dî_¶£¶¾¦ ²bÊ%¤ç(’µñë8á þì‹þM§Ýü¥·_<ã}R^‚ÄÕ}µ{Åtí³Z61Kª¸5Úhç±h¨ÊZÝ1šƒ×PPPòxõ¹üà@¢7s,˰í鸷ܛ¼ÊßϹ ƒŒäøÅ•_>/Á¶‚ÒÑÚKëR|÷PòB$4‘ÑÀÒ>IGr+üdgô;‰—c–xu¬ËªÔÒXˆq±È¡n„§©ä’„¤¡d£§žz´ÃF³%ŽO;qòŒC9~iqlî߯¸±ÆqiFdK(ò­eX!æzG-¼Ú#3žTç”BAÕ]ˆníg›Sá# ‘ºù }¦w=Ê«ù1VØôÖ“]5eÅ  ¥OrÂRHP )WpCvhÖKµqú9áÖŽÓ*È(q,.=çT¬ÅÚ»;gIGžôæ‘ç:†Ê[B åd¹æž?µv{ÜÖE²ž·k9“ Òâ³!¶É,ê'yr혯}´Bˆ™IB…©—Úq÷Y-(¢H^k¼·/Îð‘ˆÝÐYíý„Zû¬Õ^q‘2Zq³çRP¦–…T:€PI"ÃÖkðÑEñâN–› G¿Ç °°~tƒÕC|)÷Ö·ÁQ©G€€×ÖêEÊo|Zá;ss \w!Ã.çÏS`˜È[±¤BCe*+lðòùZù” †’ѯÏÙWû§Eáÿ/Ü¿~üòeîÙîʱ¥¿b"Uk9#|¹%°%)l¾®¥»Ô®Ržƒdd7›Í¼Û£½n,å¤TàïD¢ ÷?,r”×Hz½¹"{Ͷ‚e•¸ÿd»ÔÐC rV¥ºÑ¬¡q v.7óiöï9Ý,’¥ûí¶°›•ÃÇ,#Ö±U^‡ƒ}m¤¸óÄ-+àŽ A Õ’¯÷N‹Ãþ_¹~ýùäËݳݕb5K~ÅDªÖrF ùsK`JRÙ}]Kw©\¥<?@´k8cNä{ß½ÛÍŒd™–MCW€J­¤¡ƒIhõrÙSð’僥®ŸHZÔèK½m·ø’MMŽîÎïn®á+™¸w4¹¶MgŽß9X–ÙfÁˆÌY JòT’·=·SÏSi+%@Ctj»Þ¿É¸ŸÏ:?­£T¾n½ƒxvï2Êw;9´ÛÛXÔvn^ä’å5Ù .\I.·Ösª;2£„”tõ–As— ÚqÌ£Ù|"U³×3ò;œÆžÙè——Reª’'„]}n) ÇBÛd”õyEd-j%Afíå-Åùç'ê‘5ë¹?Ë=©ùß'þm® Ž6#›€ÍŒÿM”3)EçÃa´­f,RzP éHç„‚IT£Ê~äÿ,ö§ç|Ÿø¶‚«Ê¶÷Ħ[„n&Íd´¸&CK˜ÎºMnCg{!Ã_W6CªŽÓ=×v+k@BRðI-£áG:ì¥ØmÁÄwj/h•C?ÛŒì-ÉSî$"ÖPq1¤y)Š¦Ê“èc^EÂyO£A"økñÞ#:÷pr™›µcŸO¢ ïs¯j¦¼û«­–ð„•§ËS­(-Ö-Ž´Û_7¾÷ªn3⦥ÛZÖw’õ±âÜKb=Bš¬jÛR…¥>YPZBzþT7Ï`èÐPÛ¥²»¸û·“c'¬Ï6êâ=Ô8re=:šam—c9׋ ºë¨õ†z¾8 •rîÍîvòm%î-mIƒíõò¥TÛãæšcÖm5aJe ËqQ£u¶\BÒ†ÉJJÔ¢BFƒÑ Ï ÛßÙ†öm^íçT}PÎö¶Î fC6[Žúz"§ÒS›¼b|•qÒøUBTòMñ¼›]áßzbaŽyJ¯M¦rÍ쉳žC†TXª†ÑnR :”è+QcÕ:Ï_!ÆËŠd8’âR¤óÜÏÌx?ù{f·3Þ,ß:ÛìcËè·ø¶S!d–WÉ©±f*c©m:ÜI!æC-‚¤¬ž O±Gxj®·#{1]³ÃÆk3ì7×r^aTÍ•t¿2?¹ñ„ê$ª:_gÎX=HAKòT¡­i¥œ¿lv×p\ˆö}·¸ÎJäuEUÅLy†9üí—P®ƒþN4›Ç÷wê6z÷Ûl©ÙüÂÂ<˜ dMEfMwUjÑ ^k óJÒµ„P¤‘üýN_ì&ö]#ÄÛhƒ„47®µ(ÉÈ%ŸD"©R¸}_Q*{„uúÜ7ì>hÓÑ£G‡¨pØm†B[i¦Ð†Ð‘ÀJ@ì¾Ã—Èq%Ĥ)I縞 ˜ðò: Á[°»¿ˆæÖèRã›{j¼:¿ ÉñëKy‰Ä'VcM‡;Ж¾®—Wæ6¸àÀJ¹J`Ü ­Þ\º÷g/àÐàd/ß[DfâTvxr<¨áˆÜC_˜R‰)Yqa¾µ!^¢»h ¡¹^·srâ6µ÷1 Ø»U_ŠJ-¤¾óAgÊkÒš1”%ÑÊ”P· |pœò/)Cyî6®Õ‡êðê|õèNµ ¶lߟRdtzŠqÇ"¶àB•Ï)òWÒ?íû4û£Aœvßb,öÖ÷rsØØõG“ãÍ4q ~ÅÉp‹bB¤X¦Ym¥¸•´ØKH¥¾µzÊéMÁ´?ØWÍÚß«7©|¿ù'wþŽ“þéZˆÚŠl+æíoÕ›ÐGRü}f?41¯®ÝiÿH¿YÍ kë·ZÐ4hÐ4hÐ4hÐ4hÐ4hÐ4hÐ4hЮ÷¯òn'óÎëhÕ‰ªïzÿ&â<èþ¶‰¬ï½/üÝ®úÌíhg}èøÙæíwÖgh:ÿÀ/ý‘É´Ë»¬Ë˶þ– ‘èyŒc6BHò£¬Ã”PÉ?Ît…tÁO]=m…¬‘Ï€¢9#¡öô6›÷&ª*öÖ²²8f;9”~”õLYjR”¥¥­J%JR‰R”I$’Nƒ¦w‡ý°³È§ä––’iköm{—sU["Æ?•äÉT"ïVŸ!“ÇGIShQI _{&ÎûœÔªžõq7$(e ¹•[/ݤ% ä™$·ÔÚÙòÊylyg”zºu´Ï°ZKؘµÖiCæO¢×J²e©R: òÚR‚×ÉçUáîöMs¼Ò6/lóüO¸§§u*UÌQ,Ì~L¥¡ªöÛó› –£º¥¨u,y¬ôßhG†mœj΢éšv§ÒÓ£bKY-¢z±R„€e²O‘æ Oàž5ÂFÅ@§Åè+è2•øL—%ãÌÇÌnZ®­*J”ÉL°S긴Ï+PF›sì¯*Ç2}¾©Çª"M‡“äNÕ[:÷_\HÉ­›,:ŽžÀõÄB=nGÂí<‰j­ÁÀ¯/¥b´™½…Ô¿J­‹d˲˜è!*ëi*+O€y‚xÐAîÉmÖåÝÔå%mƒ´h[0-éî&TÏi•¨ôˆn´êš_Hå²¢Ÿiàúɼ:m&]Ðc43ËX´¥Î¥Ÿêsp$¬¨¸ósÛxJ YRŠÔ\%dúÜ麟<Á²+™¸î?™ÑYÛW!زôˆÜ+¤ù¡EHáDÈÏñVämÚ.žÆÕžã‚Þ1Pz´cÒ[éã«©®®¡ÇRyävä~}F²{s¶7×¹>UaÏ',*âD›©ÓL×i-6ë‚CËIw¡ Î:ÕÜ©D’OÕÎÌmýþâ×nÅœ+ue1ƒ [7ö 6Ìw:|ÆÄvßK%+(AP(<”$žHR—•·Xñ”/óìr°Àò½+Ó-XgÈó9 õõ¨tõt«§ž9àñì×»æ *ö>/3¢væSSȱeRd£¬8†‚ºÔ‚[¨8ïìÐW‹ð™±Žáwzõó”÷iÈ좹—\(ɲyÞ§ ¯3¨½Ãª@)Ä¡jIIWÞv«!È#å’`ä®Ú¯j¥û*¬¦Òº\ø$†Ú˜ôir_O<…<¥«žý^Þ\l³Ìšþ+q™ÑA»°)+dزԩG„ùm)AkäöÉ×ÎämÞ8©hÈsÜr­Uå±,M´aƒÌ$7æu¨tu«§ž9àñìÐ@»°»bæeEŸ¦ªÕ›¼f´ÓÕ= ±e¨°ŠP•2Cᢕ›ê娡$ò@:€_„ÍŒw ¸Ûר/œ ¿»NGe̺áFM{Îô…8eyEîP N% P*JHoÉ÷ƒlpÉXÌ\›7¨€s–Í2Ý–€Ü®˜ÎH.óÒòÚW®OI*Byåi"føäù^ëd;I³Xö=m/¨¯¶¸´¹·r4Pg¥ÅDa„²Ëªw© ©ÞÉ@),«°1_x}Û Šs–“«®X&­šYÓ ä61$YBhÛSeô®WJõÝ+_ Xêájç#ðñ´™Cx›±Ù°˜ÁB~离ŸTÍaKjh›†óI6µ#ž éQÃÆ¢¡nžâ[c;qlþ5ŒâW95²#ßPävÎ3*=¹–xÖ=>Ò.$© y¦´Ü  €ã°=Ç·TÆG<ÚýsĦ5»y&K:›n,-çÖÎäÈ“܈™ Ì ECJ PDvÛµpxZ~d8–>+2bÉmL¾ÃÈ mÖÔ8RT“ÙI AìAÕoƒxnÚ ¸(k¡µb -<Äz©Y”ڸͺ•%ijD…Æd­iá §²ˆö4ÖAošm?°»ƒS¸YKie48îNÕƒ²¡Ú³hÒ‹²ŒO—L¨Qèèm!RT !fÂ}‘Õø¡–½òÜHOíÍœ§1£Ü2ˆkn–<´õ%j<ÅZY(é'„…½i [þÒáÖ”¶´¸ôµ+BÛ¡6ÞdÈ´éZJUèqßumG= Ò PJB=]x5á¯hÙ‰šÂj®ü3¸„«%uvÄÏ%)A=^“ËD¶„¶Ke$¶:)õtót·qÜ Æ·[.™˜9·S6Æ Û™¸E±?¸…<弘l­§%F ôp9Zt–<êwkqws_[µlÖêf.C­Ç0™PUÌ6Ħ_jÅÀ•£ …7Ï+J{p]Y<•[C®Ì&¨EVBš×iÙÇ¥Á9]ª£Î­d¸Z% CÈ@yÄ€¾~ ^Yå¿SS³¶'læçÇsÛ©³®ÉŠ·¥U_XW"DVJ‹M¼ÄgÛiÐŽµt•¡DÀ<ÀPÞéslïkr ÷+Þœú\ºܦ Ú™TvfJa¢÷J:q (_Pèè@HO­× E¸'c¼æ/çWʳË2J:Ûç ÕñhÃõ“tHÒã žOæ?ŸZolökoö†ºÆ£¯²‹ÖS³eG›w:ŵ>ë‹q×™O8RÖâÔ²Ž:Éå\ð8H«ðm°4ñj ADzáãöâîŽ*rët±O(€a¶™!1Ñîr†ÀIêî àö¾6uâ:£2͜ݬ¼¦ÜiÕÑë$¸#UÀ¬šôGaõ%§ÖûhRœ[ÁÃð㧤%(–7ccã?{ïÌóŒf“™²%‘CR¤Y¹è«l$õ5Ô•t |®¬÷*:·§ølÙéù…¦tš Jûk×[~ÜUdVUÑlÜBzBåD!ä+ŽÄºÚº¾^u-/e¶ò^æ{ð Û(¹b¢± ù°nçDn[ ©Ji¹Ùy,H +WjØñìàh2tÈܪïÕÞ3Ïo§g®—îצsÊ©ËÖaU"¿ÊPsÊ J<ÿ0ùŠ=“²ô¹–o¼µ Þ,Ýʼ ?Šš˜ OCm­º#ëaóÑËŒꇔ:S”O*éR-(þvn-‹Å^bÛ*ùŠƒi-U,Ø©Âá’ŠòÏ0— ð— Z@Y*2¸>ËmöÝd÷ù†'â=¦Pñ“n¹9„Æ¥=Ò„ùªfCëh,%¦Ð”…§¤žFçFŒ¿ù'wþŽ“þéZˆÚŠl+æíoÕ›Ô¾_ü“»ÿGIÿt­DmÅ6óv·êÍè#©~>³š××n´ÿª}ýÄÀñ?¸®M˜TV\䨶:Å5|©ˆnEƒˆ™sÔlž§8êO<ÝCŸhÓ4MôÙÉè̇¹xóÉÛõ©¼¤¢r¦RTâT$÷ø" .[åm_›@õ£HR÷ïe Õâ÷S7Cflèc’¹í†í\*Jzc«ž=KHà|¤k¶6ðmlÌ¢ÿ ‹ŸQ»}‹E3®«“1E|p”¨¸ò9å i<ŸûC@á£UÄÏû _AÝ)»»‹1ˆÙM5Ðî—d؆ü K(sž’°s·ÿ¢¿6§½ôöãßÞ§îÚŸîÇÑ}7Ü?JO¦yuyžW=]u׋B²Ï÷2`è–P•†ü²Ï˜}Wz‚z{û{¯£Hò·«l¡e¸Þ '%è¼Ë¡¦}4_C})‚•(/¬7ÐŽÈQájIíìÔk#¶fM.[³™uWà²DK÷½Î–= Òál'¤µÔç®’9l(vçÙ ²µ]ï_äÜOçÖѯ©{ÿ´pQ„9/- §qÖ”c$Á’}=JSI³É}¡ð…û »»»y—äpvïÈ}/!Æs:/u!ú#íú?÷j々÷#ðTt¦³¾ô|l¿óv»ë3µ¢5÷£ãeÿ›µßY ëÿ¿öEÿ&ÓÎîþRÛ¯žq¾©/HªPO€’£Ïhyì9?‘¿0ÔÞáÄ·°¿Û¬Šü9G0ŽˆUÀS³W*w¤”­õÜ‚Rê žVã¡´Âñýñ'nüˆžø—ù&H¯s%«+•HJ½ÄT¸>’ߣ¦?”B›P% ”ðØÖ>¯“¨÷n5c¸P¶¯ nÈ<ôwæØé—éËIü2úUÒVG¬I<5¶ m©iuM¤­„¨ŽãŸoÿ }h9¬#¶2ÛêD$.G!JOJO%#óôò;~~5ùáHÊkvùí¥Ø|Žs¡HÚÜ–Çoò:p–rh:†O ÏòV¦”ëëq(mÑÐéy•õR¥Ñy´Ã –m²êË‹èHJ>Õ=§°ï Èdó|‹g¯ñÝügw…UÊ‹W‰C‰ ,¨-»µ&$Öl>Êá*áÞ‘æ¶Ù䕪ۉ·s.°¿Yþw„D‡¶{6Â=ÅŸœÜܲBÕ!ÏGCo0#•8ìÒËÊSŠŽ°ë$ÐY˜‘L~ BRT—ÑèY%==]C¿W`üÚ q_ u›gS±9næC¿ÛŠ'a˜‘Žˆ¶3B_a‰…´´¶ßR›ŽÓŠ ü0I$  …•ãwv£åÊÀÖÌl™2`¨|2RôÿLêëü-y¾ÂQÕÛQÛiy´¸÷†ŸÙ"®1Ë&7"l'™™}´& ôʹÈP® s¨ð:™ ö£_¦z4ŸµX^KO»ÛE¿»úp\’Û:²Ÿ>ªDhMÙOhËUÌ€·›/È„EK%ž®-($q«6{'7Ç>í#%Vùc§2Dã^YCÓÕ8¯¯ÙÒ×–^çØžž¾Ük\Û.%âÚK‰IJUÇp€1àä5õ üÑÛݧNÞx@Ê3KL]ìVŠÿ( ´°±u‡aB*ƒ=0¢Èq|¥õ0P•‘íB¾Puqnм*î.æe/IÝ6vsp¶ò-|*¼²Ÿ%b¶Dú× 3-…¡’¯.\Aé_AB¹òÊR¤‚5³5àü2ŸbL˜l:ôbK.8ØRš'ŽJIîžxÏÍ ÂáØÜíß„¬»eÑÔn4Ç&zç!˜Z˜ö¢RÚ_JÙmÄú+‹O J\u) ½/sïù>ñÝÝ][bõ›s²·³¬›©ntqa•f.ÈT‰C.,8ë1Ÿ}Ï-?‚¹ QO)l¼´h?>+j°¼–Ÿw¶‹wôà¹%¶ue>}TˆÐ›²žÑ–«™o6_Š–K=]ZPHãZç}ë+ì(±È"6ìy¹•d¶S꼓) !cùÀ¤}£±í«0¶Ùq/Ò\JJR®;€xäùÿ!ª÷zÿ&â<èþ¶óhMŽâ% 3) òrDÔˆ·7—öÑͪ…ŽJɆ`ç¢5É~<q-<Ï1l6ã€ôuð“ʸÉÔîÑ~RÜ_žr~©^»“ü³ÚŸòàÚU?¾w˜óIªÁ¾â—X>l&{¨Õ‡C¼¦#^O”ã~G¬âо’áéä$W­üFWc9µ•ÍnÖÅ ß3Z­çˆkˆ¢µØ¸¨áL¨4ø àêç¿õeZZWRWI··šÌHQSϾò‚PÚä’N•éàÛf6 e,gàÕ° åM3É)Y ‚™rÒ¥äÛGñ]”¯…à4 µW^#íZÂ'}Ê`0¢ÊåÈ•e92O(õ 7èþ·#Ì!/–ÔGXJŠ’™^ñ»¼Ñ¹ÛxÍ:a9÷ò&NrJåô«£ÝËIJ*èçÉZ”Wò8°õ{{)‰H  i©2à%˜l’G¤?Á§ ”â’@)J\q°®lo|I1Y‰P×µ¶’s'ä8öP€'ûŸ¿ÍXmÖ=iRç©À¾R…© ÿýä÷ÁŸÇÜgÜ7 @ÿò½ÖôÞ”ñæÿCåuuþ­ÇOíÓ Z(«i§]‘"C…ùrß ½)â.,€<@ JR”¤%)vÉ“wfL}¶a q×\XJBG%J'°I: µé>&aí„™–íK³ …Õ®Á4­×¥ ©K'Ⴣ…Ž5ÕŽä›É•æ5Wµx¬]·r1™éI¸–ðBø‘¾<´GRü®ï®P®ÝIíFëHjÒчÃZ]ƒÔ®åi<¦Cé=Äp@-´²Ö8éN¬ ^Çß7÷)’úO½‡Ý7¥·÷7åû¡è>æ3Ó9øO3ËêéòûuqÏm|dwÛëYg€×TÇÀæHœÓc*Š£0:Vߤ;ŽÈaKõßïÝ´€¥©(SÝýù«,WWE­çz>¾BxêuÅp|¶QÔž¥ð}©JB–¤!_T ?.\£:ÖqJ¦ÍR:K¥<ô¡ äùm#©A ‚xåD•-KZB¹þ™k=ºmáƒðg_Jü¥Y•=ãŸ/©,ø=ÇNÆñ qìI ]í¨½ng9c‹«žb=¯ÙG[Nt|®©ÄõwãŽÚ²´¤IÜP‚F* Pþ¹ýƒüSóŸéÿÌþ8èm·§ Î2k(3°“·j¯-âÎýÑz–×Ã<çå;Ìóø(B´ô’ç3‘ãzÕK>“çùÜôúÅΟomZ €”€>MAe™d|b; 5Ëk–+kXPËtOsÙHõ–áõPžç¿‚V[“o1žT¤aÖ8Ìøf:)Y…(^M²Q*eâ÷ÜdŸ-KRÛ= åD”ƒ÷ƒÄoÜ6C ^ãa_u²§%Ê)íã¯ú½h*iöLާ×ÐHX[c•$ôö ´âxœŠ¹ä™$¶ìrKJ”„Ôvå1£¤÷C)?ë-^²»ð>‚©Îé÷½qk¤AÍñV©!Ò8œž3”Ž®EŒ€Ê¼ÅFp>dÜçÛÛ»FÐüSa_7k~¬Þ£ói²òÜ~þ²šK‘éâÔÔû•Ò¹% CØ.:?º|Î¥3ݳ4ÆÑ`ì²Ú[m¼n±(BG JDVÀ`Ð@ࢳñ’ZÙRÀ—6»ÇKñ㱊¦Üò[Y ž<ì°“MN("ªDâL®Hóý¿‡ÛÖöŸo>Ó¤Ê_¬Çæ†5õÛ­?è3»ÛÉ—f“7›Ú<^ú·ilߥq6¶.G“afà ¾üxl3ß($8„%Å~‡€Ô~eîíÆ7¿Ø>UÇ1<ǰÉlÄêÿE_!…BB›•1ÇBžd¨Zl‚?%)º¶»xîåoFÔnÄ­¤ÞÌjÖÞ™úꫦ–þI>½å±¹U êÓ'ÊAl%¾³æ¤ò²8Ót¼†—,ñ]°p÷œeŒ¹í±³zÖ’cŒ-P®$å–RÒÉ!}AðÇQJÇ ž÷[lÃ’{§‹¹‰4“)üèæ¹ (¤¸çʨ¨usíäkækµ–Uon v[ŠJ®ŽTÃ×lÏŒ¶ P©]#€G «åÂØ^åíf?µöŒÇÄgÔÖí×XÊŸÓK‹|$H`ú#­<³ð@2ÙSm-KO+JG:ŒÏ²¼V ãf-Æq‹Û¿c¶Â¹ä%˜ÍNut,%2"2¥«©*sÕC‰RúÈ-E\ßí\m‹n!3i‹ªAK÷ %øå¨eH Jä$å (ñÈû5ïŽ\mþcœ“´Ç¯"Ã&3SëŸbKl”Ží¥ÆÉ à(z ööë'o•^W´›?móÕ0$eu33ê(lNkÑÙ%,K–¤¥bCLO[kZœëés×Wt’!7j—i7pv¿w^ݺy˜«¹Ç¸3Ì ˜Ò‚fy^„ž…ºä"àx¥–›G 9 ¢ÓÄ4é¾%ð±ÛìëÊ1ì–šöT¸pM. qËAéM>âR‡Tú€BTŸ)]×ìJì¯{…Q¶9®ð]ì•Ç6ó'²ÇoÑ2qùÁ0eú3òc4å{Mº:¸RP§[%<ûÂ^îöÆäþ*<=ZíÖ}‰L¡‡Žf“"¶k$p¦+‹Qú’BXJUð'… qÊSÈæ”­±ÙŸi·¢ÉÍëWÝC{—™ÛbØýeú'7k53Ü~“OðÏK‹ò”™ZHéP#€°~êfq¼MaûjÄŠ‡± ¯³¾m>çºÜö_ŒìD'©âñB¡$žŸ)%•¥*JJœRZ=+ê<ço¤âÞóÍÄ“cqw[‚½Ý§¯‹hÛȉ`ÒØmŠä¹ÛÎqè¬ë!=*rJÀå<Ù»8=»;‚VâÓj2̳Ψ³›¨l\DŒå¤–¬„Ë%É!´’µºP´€”ƒØ É'}©Ñ"²’» Ëlrk*×nN6Ì6Z±‰–‹òï6ÓIRÁJ§:œ!] WJúc¡xšÛûêl&Ï ®½É¦n¤ÓU@ŒÓRÔÜ4»é.4ÓE‡–Ö•8Z‚Rªg: 7}Øß+m¨•S‹Ã¢° ÷r¡ô3"Ê}m=Ò¹‰ŠëN&I è¥#§«¸$\÷Àï±Ü+oc¥QVÔŵŸQ'Ê+aÜâvÎÉJÑå¼™!>•8ã… u¯0²SëÔxfU 8Å*rúØs¢E·ˆÜ¶˜œÇ“!¤¬sÒâ9=*Â9:šÕi²×÷u;K‰Vîö{CešF©ŽÝä¦f³Òì°ÖyI Q±P §OºüOûQQûë_õh%ôj#î¿þÔT~ú×ýZ>ëñ?íEGï­Õ —Õ_â \È8Ö9.¾¹všËé P°‚óž–Ž”uÉñÊ`9?&ž~ëñ?íEGï­Õ¤ßȱû˜ŒXµò^VeFRÛ2µ% ž<è>¶«–‘ž§!•û˜ÊT…FAC!f,SÒ€{ô§žOr'¹×nìØBªÉ¶¾ÆÆKqãGË$­×VxJR(-µõ´_”·真ªD×Þæ¶Û¹ŽÔ%ÖÒ´ŒÁõ¡ÈäQZÊ~Ñ ”I+-²‰‘d¬:ÌNêêº(•!?+£Ú†ÏfϬAp$¶Û£Pw·²˜”Š š‘s!°àY†É$zCüzy @!N)$”¥ÇööS‘A@ÓR.d6ÀK0Ù$H‚O!A()Å$€R”¸ã}TTQh¢­¦vD‰åË|‚ô§ˆ¸²ð %)JR”¤QQE¢Š¶šuÙ$8_—-ò Òž âÈsÀ$”¥)JBRsﱇ%Jy¶YeÇqA)B@䨓Ø;ó }ˆ¬9*SͲË(.8㊠J%DžÀß(=RwÆ%ܶóXÓ¥èõë>é©=Òì„‘Ï” CGŽ®–dŽ–7}» \f•‡"Dq%*œ yKï$÷ ƒÁCgÛÙJô¥-ZP÷÷欱]]N·œèpúúA ã©×ÁòÙGRz—Áö¥) Z…÷欱]]N·œèpúúA ã©×ÁòÙGRz—Áö¥) Z…}PP €ü¹rŒëYÅ*›5Hé.”óÒ„'“å´Ž¥6 ã•Tµ-j‚€TåË”gZÎ)TÙªGIt§ž”!<Ÿ-¤u(!°O¨’¥©kT¶)w” ‘ŠƒÂ”?®`ÿüçúó?Ž“¸$¡ŒT¡ýsûø§ç?Óÿ™üs` % “@ % “PYfYŽÃMDrÆÚÅeŠÚֲݓÜöB=e¸}T'¹ïÀ e™d|b; 5Ëk–+kXPËtOsÙHõ–áõPžç¿óbxœŠ¹ä™$¶ìrKJ”„Ôvå1£¤÷C)?ë-^²»ð‰âr*ä?’d’Û±É,P*RCQڔƎ“Ý ¤ÿ¬µzÊïÀ úJÒ¥JÌe=QQ%ØôÑÜS6 ¬¡r“ÂãGXî8 ¥Ç‡tžPƒæu)’T©YŒ§ª*$»š;ŠfÂÁ•”.BÒx\hëǸðî“Ê|Î¥2É,X1Y… 3QãÇm-2ËHChHá)JG`; ˆÉbŃ„ÚÂ…¨ñãÕ>Ó,´€„6„²BR”ŽÀvQ»CñM…|Ý­ú³zèÜ‹¨T˜U»òºÖãðß;IêvCÊie-¶Ÿ”ð $ð”©J)JT¡Í³¥ghð‚âBVqÊÞ  Eo‘ÏË ¥øúÌ~hc_]ºÓþ)~>³š××n´ÿ ðT*˜›C`ËB<´¾[`G·¤+ÛÇsÛöëßJÛ‰¹ÆØRGºÉž£a9ŠªØq/J°œñ!¨Ì6? ÅpO´¥*RŠR•(#«Å߇zr l––ÚŠú&2ºYPäÙ–ršK‘£Åòq§ÔâÈ(p„„¨¬ $Sм ªË¥æ˜þQIk„Ö·smFü&žœšç:Â&5ä:ã.±ÔÛ‰+C¤%I)WIà,_Äf#’îNÝ?‹åôSò:Ù´2nj XÖ¬1å—¼’TV• :…:„+¤óÇr®¾[m¶[K,¶”6„„¥)ì|ƒUl/øÅ®Bí=6'•Ø×±LÅ—wK„-"¡ÅHc§ÍôUL¸ß™äùeié =´‰‡x×ÅïvŽ÷yoöÏ9© ¡]«¯IMWœÓ‘¡Îz0Rs¡¥§°BºÓÔzy!£[m¶Qå´ÚPIá#ÜòÿzúÕ3g⟠¨«o Ÿ†g,Òɵ©©‡hí/•bì\ 0ó*ZÒVÐqIJ”ó’ •%E™ýï n&E¶·*›U;Ǖϛ5´µ5ŠqÆËÁÞ¯bT˽\€A: _>[~a{ËO˜SÒUÇ~?7?›T¢üXaM7CøNpÌ[\znQK!Ê”ôÚÀŠ”)Å6„¸\eE!iL„2JUÏì×6 âËÈ6{Ý\³ɱÅälT7_^õzœrÖ}ƒ!Æ£Wðy“Éêád t޵t§’öѪһ~±‰32Z\!¦ÉqZöíçcÓ#4äõÁp¨7%Ç}²¤-M¸®• ¥]'_C¿ø®öǯ³Â±¼¬SZS¢â-Ìê•1Ð¥$éx¨…<ž±ÊG)ì°JbЇ¦ÜHRTRHä~C¡¶Ûe´²ËiChHJR‘ÀHÀÈ5GÌÝŒ/ߌå̇2Í+›Ãð$]ÚUΊFÕ{o¼¥ØÇ>kŽü¨R‡))oÉNÛ{»QwÁÊÔá9E‚®%Ôu[ÇŽ”J‰$¬4´)—_®¦×Òây¤s |Õw½“q?žt[F¬MW{×ù7ùçGõ´h,Mg}èøÙæíwÖgkDk;ïGÆËÿ7k¾³;AÔ Uà ¤(¤¡à(qÈþòû{êÚ…·˜|ltc(âÚÂ[¦LŸtÚD¥K’O*}â°zÜ'¹Q˜TßàþÈ¿äÚ½¦Í‡[ ë MFµ:óά% ¡#’¥Ø>]”ݮ٪ØoXXmÎ4fÔëÏ;O(m •(”p. «6onr9Í_Úmf5¹ƒÕ]\ºHí¸áã"Jz ãð?øKgJYj… fW1›ËȮƬŒâ^­­y+ZÒyL©)=ÂÁà¶Ñü_e¬y)eŸ@£ïC´ß¢üKÿDÿF¡/v÷l”Š ªÃd\Èl8”‘Ë0Ù$H„ƒÓÈPJ qI ¥.8Ûmíì¦%"‚¦¤\Èl8€–a²IÿžB‚PSŠI¥)qÆú¨¨¢ÑE[M:ì‰/Ë–ùéOqd9àJR”¥!)Hi¶3i)á&/½Þ51Õ(¸ü™4ñ”ëîêR¸lû‘ÂRꓵ[=;³&m¾à !N:ë”ñR†Ð‘ÉR‰G $é¶L˜ðã»2cí°ÃSŽºâÂPÚ9*Q=€IÒ$hÒ7ZCV–Œ8ÆÂÒì. ¥w+Iå2Iî#‚m£ø}–±ÇJtÊ|5ì¦îçTÛ§k´´qj1öÖŠV} È÷W©A^‘":xmL…$)¤¸‚£øg„“l{Ðí7è¿ÿÑ#ѦíCßßš²ÅutQ:ÞpW¡Ãëé'ާ\WËeIê_Ú”¤)jB WûµeŠêí¥Äg[Î ô8~ãÆH!ô;Mú/Ä¿ôHßôiY­©ÚìâB‡¶Ø³8Ó+ 7O+¶X<Ž’ÈŠöÇ|Ÿøæ¢Nà’„1PxR‡õÏì⟜ÿOþgñÍ€€”€>MÚ ¦†×â?ú$oú5{·Û?HÃý¨ÅeL”¿*6©bù’ãž(à;©G²@$éºöõŠFø%L”¿*6¸ó$9Ç<{u(öHsÑQ?÷.®ŸnṲt:ê9òã·Ï!†AîŸjÈê?ÍJANƒaöÆÚÜíÞ%*ÖpOœQNÇÂGà²ÊJ=T{«€¥ŸY_"RÇ[¶›qM9›:}¿ÆàÌŽ®¦dFªa§[gR™ý˜•díÆz#í¼ØÍ¦7Ö…r:“*T9(P þÐFº·'ùgµ?;äÿÀ-µË²ñbÁ“ŸÂ…¨ñãåòe–†Ð˜qR”ŽÀv^{Ê.Õ}¶Ç +ËŸCL ,¶M¨+RSÝ})%A§¨€ž¤sÔŸ$Ê&1bÖ)аÌËù-¥åùÀ˜õщ#Òdtx%* ¶SªI¥)qÆå(¨¢ÑE[M:ì‰/Ë–ùéOqd9àJR”¥!)HÇÆ âðW3¯J“)Ó&té$*DÙ§]PÂR% JP€”%)¾ÄV•)æÙe”qÅ¥ ’¢O`ï΀}ö"°ä©O6Ë, ¸ãŽ(%(H•{~t²Ãæï·a`ËŒÐ2°äHŽ$¥S”)}äžá°x(lû{)Cž”¤a‡ówÛ°°eÆhXr$GR©Ê”¾òOpØ<6}½”¡ÏJRÕ 5~jËÕÑDëyÁ^‡¯¤ž:q\-”u'©|jR¥©Q~jËÕÑDëyÁ^‡¯¤ž:q\-”u'©|jR¥©Wը˗(εœR©³TŽ’éO=(By>[HêPC`ž9Q%KRÖ ((@~\¹Fu¬â•Mš¤t—JyéBÉòÚGR‚ñʉ*Z–µKhÒ‘'pIB ¨<)CúçöñOΧÿ3øà ;‚JHÅAáJ×?°Š~sý?ùŸÇ6Rpù4Rpù5–e‘ñˆì4ÔG,m¬VX­­a@;-Ð9=Ïd!#Ö[‡ÕB{žüY–GÆ#°ÓQ±¶±Yb¶µ…ì·@ä÷=„YnU î{ð6'‰È«þI’KnÇ$±@D©HI GhS:Ot2“þ²Õë+¿ž'"®Cù&I-»’Å¥!$5 yLhé=ÐÊOúËW¬®üÏ 4­*T¬ÆSÕ]MÅ3a`ÊÊ!i<.4uŽã‚ \xwIå>gR™%J•˜Êz¢¢K±é£¸¦l,YBä-'…ÆŽ±ÜpAKé<¡ÌêS,‘bŃ˜P£5T…,„‚žär—·bƒt÷qœ?¬Ú Š;=´Ìad-P]ZV7ü—Ø”†•CÑÛq(|-¢ãÉ RH>_!CGhÐc ÿÙíàÞ; ÏÜŠm¯·‡"×k¤m¾;G"ƹ3&½&W¤»5ãéC  ¡¤$K‡— @õA°rws-·‡ÃöSioÓWˆÀ´nýõϪç.dDFBV‘0©Â… ­e àè#¤©\ híyI}c»)Ô¸¤2…8 ÛjqdÉéBARæ}€h2¶5µÛ{êsüo² ¸—;)°pP-£;Žä2C2‘QšéôEÛjI/y¿Í Y‡¶[ã]àÃq<69²—ä/£&‡Q9‹jƒÍ2¤0깉q !=AÔ Ž“À'¶µ6Ùn¦»Ôs2,"\ס×ÚK¦’&×H‚û2ã/¡æ–Ì„!Ô)*䤂 ŽF›´ë~0­ÅÜ_ U±¼kyE×Üìé±’ÿ¹ÓØyÆͺäpµ¡•0Y!E'³ªÝmùÜÜþÆÇko°ºÁÙÁ„Ű´ŸXâàX S^âK1¥:°’$7ø°çcܤò°µá6l:ØoØØJj4X­-÷Þua(i´‚T¥(öI'ä 3°ÞŒ«jÕf»c‹[eúiv˸¬z¥oˆŠe Œ#¾¹+_Iéq†ú£Ü”ðkz}¬ÞK=ŒØhó6žÊ§-؉ÔNÉ¥ŸiXãwŒÅ€¸2LG™ãi_BüÖüòÐä’9ëNÛÛÅ÷IË1ŒÁ¾eªÁÄ¿gO" sߘ̈åä'Ím@ã¸#¸¹uÐg0}ÃÊ·³)ßù›}oU&Þ;ƒÒP½6 ¬mz_¤½%A/–@(i x(ü!POª ‡„Œs1¼:à¸{‡ÎÇ/1zxµâÊ“ÿ1l´€§[\gAlž@ê)WªyHoèÐeüóÝY~!÷<«ØÉy †Ö7ˆÃn}…bb[ÌjdÉ aM™^bYu¹ lŸX ”úÚ›ðÙ¶™†ÝfY$jjܯÚ‡ªàŠ,c'³ftŠë/1ã$D(yå17ä$6·¯ÖP8*к4«½ëü›‰üó£úÚ5bj»Þ¿É¸ŸÏ:?­£Abk;ïGÆËÿ7k¾³;Z#Yßz>6_ù»]õ™Ú¢B|Om'ÿFÕ¯ Ì®c7—‘]YĽ[Zò Vµ¤ò™RR{…ƒÁm£ø¾ËXó:RÍSþì‹þM«÷@jööS‘A@ÓR.d6ÀK0Ù$H‚O!A()Å$€R”¸ãeíì¦%"‚¦¤\Èl8€–a²IÿžB‚PSŠI¥)qÆú¨¨¢ÑE[M:ì‰/Ë–ùéOqd9àJR”¥!)H *(´QVÓN»"D‡ òå¾AzSÄ\Yx€”¥)HJRí“&<8î̘ûl0Â㮸°”6„ŽJ”O`’tI“wfL}¶a q×\XJBG%J'°I:DFëHjÒчÃZ]ƒÔ®åi<¦Cé=Äp@-´²Ö8éN€FëHjÒчÃZ]ƒÔ®åi<¦Cé=Äp@-´²Ö8éN¬ ‡¿¿5eŠêè¢u¼à¯C‡×ÒON¸®–Ê:“Ô¾µ)HRÔ„( ûóVX®®Š'[Î ô8}} „ñÔëŠàùl£©=KàûR”…-HB¾¨(@~\¹Fu¬â•Mš¤t—JyéBÉòÚGR‚ñʉ*Z–µ ?.\£:ÖqJ¦ÍR:K¥<ô¡ äùm#©A ‚xåD•-KZ¥´”‰;‚JHÅAáJ×?°Š~sý?ùŸÇÁ%$b ð¥ëŸØ?Å?9þŸüÏã› )8|š€ɨÛÛÖ)oà•2Rü¨pÚãÌçð9ìÔ£Ù t^Þ±HÃä©’—åC†×d‡8çÏ`î¥É“®z*'â>åÕÓíʹ”އ]G>\vùä0È=Âà“íYGù©HTOÄ}Ë«§Û•s)ºŽ|¸íóÈa{„Á'Ú²:óR™½V•*Vc)ꊉ.ǦŽâ™°°ee ´ž:ÇqÁ.<;¤ò„3©L*T¬ÆSÕ]MÅ3a`ÊÊ!i<.4uŽã‚ \xwIå>gR™d‹,¬Â…¨ñã¶–™e¤!´$p”¥#°€Ñ,X1Y… 3QãÇm-2ËHChHá)JG`;®;ËÈt0Ó&Jyל EŠÂBž”ñ¥¦ÒHDy$%)J”¢”¥J™´_”·真ªD×®äÿ,ö§ç|Ÿø¶¸68Ù©ÍÀ]Â#71y”¥8Ür¥6Ù1b€¥pWÒ8\'«ŽzSÏHìÝØ‹–ml©O6Ë,å’œqÇ”$P[¢O`ïÎù÷ØŠÃ’¥<Û,²‚ãŽ8 ”¡ rTIìùÒË ?›¾Ý…ƒ.3@ÊÑ"8’•NP<¥÷’{†Áࡳíì¥zR‘†ÍßnÂÁ— eaÈ‘IJ§(RûÉ=Ã`ðPÙööR‡=)KV€Ô=ýù«,WWE­çz>¾BxêuÅp|¶QÔž¥ð}©JB–¤!Eýù«,WWE­çz>¾BxêuÅp|¶QÔž¥ð}©JB–¤!_T ?.\£:ÖqJ¦ÍR:K¥<ô¡ äùm#©A ‚xåD•-KZ€  ùråÖ³ŠU6j‘Ò])ç¥O'ËiJlÇ*$©jZÕ-£JDÁ%$b ð¥ëŸØ?Å?9þŸüÏã€$î (A#…(\þÁþ)ùÏôÿæØH HÀäÐH HÀäÔY–GÆ#°ÓQ±¶±Yb¶µ…ì·@ä÷=„YnU î{ðfYŽÃMDrÆÚÅeŠÚֲݓÜöB=e¸}T'¹ïÀ<Øž'"®Cù&I-»’Å¥!$5 yLhé=ÐÊOúËW¬®übxœŠ¹ä™$¶ìrKJ”„Ôvå1£¤÷C)?ë-^²»ð>€Ò´©R³OTTIv=4wÍ…ƒ+(\…¤ð¸ÑÖ;Ž)qáÝ'” ùJd•*Vc)ꊉ.ǦŽâ™°°ee ´ž:ÇqÁ.<;¤ò„3©L²E‹ VaBŒÔxñÛKL²ÒÚ8JR‘ØÀh±bÁŠÌ(Qš;ii–Z@BBG JR;Ø Gd¹-v-\'Ï:·\Lx‘#¤.DÉ ¡–‘ÈêYàžä€¥(¥)R’䵨µpŸ<<êÝq1âD޹$(†ZG#©g‚{”¢”¥J˜Ö5b»˜æ%—o]mM0ÃJ+UDÃ$Ô£ÂKŽ „ÉBP„cV+±9ŽbYvõÖÔÓ 4¢¸õQÔA,2HJ<$¸é¸@ì”%KN-ÙYN¾œö;ŽÉSa]VHàú7n|–¹ì^ û{†ÁäòJRA_q/-2꼇Ã¥*4H0ä7wrŽþA bG>ÅH#ð•ìh•d7³L·h0f!¼n± ’x[¹îñ×}ÍMmgQQ ¸°ãVIKM6;ƒQ'ó’I$“Ü’IäqíÅ6óv·êÍè#©~>³š××n´øò\[+CNùkRHJúyéJùêž 4áâWwó½¸ÏÙc–Úà ¬hªa©ðÈ–û‰KŽ8ÓÆ4`ÚX!A õË©éR^ 1{š,« Nínv#“ß ›ÜOWú< NDոÎÄ[½ ØW”µ©±Ô¯Wž’–üëÃã9úï£ÚîŽ`ÍV[@Î9Ö³èLøÈK©RÁTb¶q/¸—Ñ@ Ž”¡IJ€Uû×¼™ÖY¹X¶Ú/ e̸µu’hj LbÊÙÈ ÊS³)\¦1/´„¡ž…p•¬¸z’”´Ñn^ìî~åÓíCÒÎÞLªÀê²ÌÀÃTæì§)hM|uH²†ÚS•¸[p«àÂJ{¨´LðÙK 4—œm¶àå»y.ÚZûˆøú ¹ŸÌù1Ö¶¦Æ”<Ûa¶¢„ž}£Ó(ðéWu™Qn>9¸Ù–'–SS£~â®DWÞµ®Jºƒ31‡Úx…•,8Pµ{ñ OðAL7s!M²zÆD}ÛÌZvcèmHZl–â’ÚR€¥I JR ìí¨Ürßtgø¹ÞŸÝY1±|2Ÿ™î2jÚu·c:›VÒ •Ëk= êtzËåöm [»;³»+_WA’äÑòéÙâáæ[2åº]¡m´…•«Ÿ„+Wÿ··žy Ø»Ëa½t9ÆQMew }Õ\EÃ]u£PÔé`¼‡£¸êTó‰êiÖÏóòHP¹ýÍK‰‘é-°Vô•FCà8–ñG $ò€÷ƒl+wŸn/6ÆîúÞ¢¯!Џ3Þª1Ó!qÖ’•¶ûN¥!@ûBz‡ÈF‚—FaºT9VÓx}‰Ÿ¡ssË Û ‰51š‘®Â"Åe]L©Õ8ðcˆ_JA<®g»û»˜~â?‰”Å'ÙJØW•yÕ¬©sáM†ä†šÂBZ!lº…- RzBI#WÞÄÔ^DÂä?™dmd¸wÜ\™¥DDô¡Öü·šuÆœ@BV‚ÈËB‡JÒ¨K }îßçX=–e•¹/sNUù± Š<ÊZåQË ¶†€BÓ( ‘Š”Ax2ß[oµõ›‰v©Þ›ä8Ä&àeµF¯jl¶£¾ÚWæ¼’©]*%*é-…Xv>"Ÿñ’ì»ë1‘‡ÁÌ Ý'‰é‘\zT˜¦(GW”¦BØzÈSœpž°yQ²sßp·n(vÛ ÜÜÉ1¨gñEŒtÖ"d§¢>—ãy¼Ã,ðÚÛG £¨'ÖêäóìÞôÖíXï;{¡˜‹ëi¼YMôVz31SŽ6´#Ðú¼Ä¼óŽ‚¥)%JáI(*L~sÍÄØýÌ®· ·ŸœÄyûÆêjÕ2îÅM0°\?&BO„-õ)¥%¶Éà£Böòï^m²¸úšÏäÒÜEßȘ ‹4Õ´Ô©pÙ½K-)ö’B¾5´•ð¤¥sâ^ ±L³‰Šn¶àWÎÛxÓ«¨­åZ䦾Xo͆òW²ó]M%i*l¸Éëã€:Wàï8MÎÞ}œ·Ó3N}p™S*®D¿J/GuQP.ŽH|=ÛØG·Asc÷utQ d™»–L¤‰ˆˆÞy*$)¥<oÍÏˤýëü›‰üó£úÚ4ëE[2¢¢5m…üû¹ #¥Ë èa$IêXŽÛMßQ´ŽÞÏ—I[×ù7ùçGõ´h,Mg}èøÙæíwÖgkDk;ïGÆËÿ7k¾³;A×þì‹þM«†ööS‘A@ÓR.d6ÀK0Ù$H‚O!A()Å$€R”¸ãt꺀’@W½bG qµvQQE¢Š¶šuÙ$8_—-ò Òž âÈsÀ$”¥)JBRTQh¢­¦vD‰åË|‚ô§ˆ¸²ð %)JR”¤Û&LxqÝ™1öØa„)Ç]qa(m •(žÀ $è“&<8î̘ûl0Â㮸°”6„ŽJ”O`’t‰4ÖÕ¥£1†0´» ¨)]ÊÒyL‡Ò{ˆà€[hþe¬qÒ4ÖÕ¥£1†0´» ¨)]ÊÒyL‡Ò{ˆà€[hþe¬qÒX5~jËÕÑDëyÁ^‡¯¤ž:q\-”u'©|jR¥©P÷欱]]N·œèpúúA ã©×ÁòÙGRz—Áö¥) Z…}PP €ü¹rŒëYÅ*›5Hé.”óÒ„'“å´Ž¥6 ã•Tµ-j((@~\¹Fu¬â•Mš¤t—JyéBÉòÚGR‚ñʉ*Z–µKh )w” ‘ŠƒÂ”?®`ÿüçúó?Ž ;‚JHÅAáJ×?°Š~sý?ùŸÇ6Rpù4 % “Q··¬R0ßÀ9*d¥ùPáµÇ™!Î9àsØ;©G²@$è½½b‘†þÉS%/ʇ ®<ÉqÏžÀÝJ=’'\ôTOÄ}Ë«§Û•s)ºŽ|¸íóÈa{„Á'Ú²:óR(¨Ÿˆû—WO·*æR:uùqÛçà ÷‚Oµduæ¥3z4­*T¬ÆSÕ]MÅ3a`ÊÊ!i<.4uŽã‚ \xwIå>gR™T©YŒ§ª*$»š;ŠfÂÁ•”.BÒx\hëǸðî“Ê|Î¥2É,X1Y… 3QãÇm-2ËHChHá)JG`;¢,X°b³ f£ÇŽÚZe–†Ð‘ÂR”ŽÀv\·WP¨¡zdÏ1ek 2ËIêvC§ð[m?ÎQàþÀ$€ á’䵨µpŸ<<êÝq1âD޹$(†ZG#©g‚{”¢”¥JØÅ·¦¹–eζåÔ¦ËMFeeQë#’É u(’ã¤â’;% BPcR×l¼Ã)Z¹u j+)=LÖFQ²×çR¸IqßjÔì„¡)gÐW{EùKq~yÉú¤M7V; ¯j¢ÏŠÔ†U˜<¢Û¨ I)¢µRI·bÿÃ_ÍŸZ±Üe6´¨ ÒZyžâ,PGþ¯}ÉþYíOÎù?ð mþ¡ïïÍYbºº(o8+Ðáõô‚ÇS®+ƒå²Ž¤õ/ƒíJRµ! /ïÍYbºº(o8+Ðáõô‚ÇS®+ƒå²Ž¤õ/ƒíJRµ! ú  ùråÖ³ŠU6j‘Ò])ç¥O'ËiJlÇ*$©jZԨ˗(εœR©³TŽ’éO=(By>[HêPC`ž9Q%KRÖ©mR$î (A#…(\þÁþ)ùÏôÿæ'pIB ¨<)CúçöñOΧÿ3øæÀ@J@&€@J@& ²Ì²>1†šˆåµŠËµ¬(eº'¹ì„$zËpú¨Os߀@Ë2ÈøÄvj#–6Ö+,VÖ° –èžç²‘ë-Ãê¡=Ï~æÄñ9rÉ2ImØä–(•) !¨íÊcGIî†RÖZ½ewàÄäUÈ$É%·c’X "T¤$†£´)'ºIÿYjõ•߀ô•¥J•˜Êz¢¢K±é£¸¦l,YBä-'…ÆŽ±ÜpAKé<¡ÌêS$©R³OTTIv=4wÍ…ƒ+(\…¤ð¸ÑÖ;Ž)qáÝ'” ùJe’,X°b³ f£ÇŽÚZe–†Ð‘ÂR”ŽÀv@E‹ VaBŒÔxñÛKL²ÒÚ8JR‘ØÀkŽöò?^©ÒÐëª* ±„…=%Óø-6’G+<|¤Ü’$}]]B¢…é“<Å•¬4Ë-'©ÙŸÁm´ÿ9Gƒû’$GÒÒÍvoÝ&Iå®Íh(a„+©¨ kmŸç,ð:Üö¨Ž h9q¬jÅv'1ÌK.ÞºÚša†”Wª:ˆ%†I©G„— ’„¡ iÑ¥»+)×ÓžÇqÙ*a +¢ÊÉFíÏ’×=‹ÄopØ<žIJHVS¯§=Žã²TÂWE•’8>ÛŸ%®{ˆ>Þá°y<’”™ªÚØ5Y­­Œ–#0ž”!<Ÿ—’I=É$’Iä’I$“¢¶¶ Dkkc%ˆÌ'¥O'åä’OrI$’y$’I$ëââ⺆½Ë;Gü¦)Há%KZÔ ”6„ŽTµ©D%)H*Rˆ@ÐEî¤|ö}‹á¦“ôÄ©kR P„¤wR”¢”€I$ :àÙũ͢ÁÜ[JmJÆë B¸êIôVû ØH×=ÍDû+|Ÿ'd7)ºÙ~ç×õ¢¹ e@¨JW!I$)`Kh$­Þ­¡ø¦Â¾nÖýY½u/ÇÖcóCúíÖŸôKñõ˜üÐÆ¾»uªe¶Ã½Ý½ö³Ÿ ÂÖN¸æãßµ“äD–š˜o¥!À¥8®YPé% ¥…¹Ñ¬)áãËwgnv³{¥î%[’FÈâYä†;âòd£!MΦ’êž ~bã¦9OCÒDeÛcˆÛá¾2¯g³dìü&mŽ:ù·—Í\¦qèÒ›yæp…‡‡%`uê“ÓÛAú£X㤧À÷ÿÃÞMJ¹ñeføE/*©²d9n¶cV¾‡$­EÕ¥ÇPW^·ÀªgR>¿{±·Õ‚¾&i¹«ô{û;”ÊÊo`JbÅo&zšm(òAHh¸÷–”°ƒÐRS ÜîG’Ûe=-Æ 2š¶™øÍÕÚ½-—[¹CŒ…¸ãm •´_(!`{ØÉ¬º”Ñ+qo•°Ÿ°iŠfël `ùTy ÇØ}JJÊú»ºâ×ÓÏŸg³V?Ü5·¾"v"^ÄÚ÷sš ‚¿$X²’â­[n´·Ô· –â¥Âz‡$sÙ<‘Á²<—%‰jþO‚ÌŃo.VdËfA›¥ðÔÄ–‰ C£¸B½dû™5ùÕgI2ˆ-K´eº/ÔÁ[6’[u˜‡&f?–K}šõA*ä{A¾¯ü¡ÛW8Ž ÚªKýµbî}z$º¶°jÍl¦OJÔ@p¶áJ”;«€O~I -£XÀ¤çy5¶A÷ÂÁw |Œÿ-k#a]@PyõÅBZ|Nu.7"km ²Y!*å “¢Õ}"‰öÚùv7WÚ[/d{Pãn$¥hVA¥I=ˆ »ÜhÑ ú x“íPÿèb}¶+À×öŸj¾‘Dûm4>‹àSÍýÑí?šÐ÷A«§žxçÍös¯¯+À×öŸj¾‘Dûm4kÀÉŸjˆ?ÿCíµòÔo¬4†YÈö¡¶ÛHJœ‚ JR;w°Ñ£AõåxþÓíWÒ(Ÿm¯•Eð(·ò²=§.7ÈBŽA”óíàù½¹ãFוàkûOµ_H¢}¶+À×öŸj¾‘Dûm4 XŽæøXÀªM¹»gM^^\ƒ&A´)ÕqÔ³ÃÔxÏ~Ãók‹:܂͑Lã~%1Š ´FÒÚ¼Ž¥N¡ÓøÊ2RójIjK£‚Žyà‚8Ñ£@¹"ÚˆSfY1ã¨úTõ ÈywXª” Â ƒê¡<¨„ –®9R‰ìû¸Û×ÃÿxÅ?ø:4h9-²=ª»€å]—޵;þÍ{·Š¥.¤JÄ!ÔƒÇ I줒•’Aê¾Û$§Çpø§oÿáÑ£Aýû¸Û×ÃÿxÅ?ø:m´1¯eäÈñÌUe1”G\‡.ñe”2Ÿcmƒ†ÑϬBx]Ï'F—ÝÆÛþ¾ûÆ)ÿÁׄì³l¬a½ÿO%©-¬³{‹4¾“Øô­‚’xùRA!FÔ\»k Åf/íG´´Ë-ZâhChHá)JDì½~î6ßõðÿÞ1Oþ5ä[På«wNøê.Ke’ÃK]Ö*CI'•t'ÐxIWnT$ à v}Üm¿ëáÿ¼bŸü4f›ló+e^<–âJJ‘uŠ%C‘Ç ˆ<ƒûuã[“mMDkk|s¥ˆÌ'¥MÆ(~^I$Áä’I$žI$’I:4h:~î6ßõðÿÞ1Oþ£¦\í…´ ¹Þ9Ëò«ž‡×w‹2µŽ•8”zO™ÓÊBÈê RÒ XQ£A×3-Û ñƒ/Çg˜Ä–ÔÓ©÷gHPàŽDGcòiÖƒz<g¼y*%+£Z3*‘±YÕ;˜îoã£!ªyANAµ•‡Ë޲=„¶íz’Häüš4h!Ãü*Ƶ§½â_ jËi,TLC8R_®m$”¢;‚»©”‚IÉ×ÍfáJ’šã¦ñ)…ÀªÈJM¼¬a-G±é$Hm5¡/pT¢:ÁîOçÑ£Aá o¼#×bÒ0x>#p†qÙ‹mÉ5Ic ôI BzP·÷7¥j°R?·],aþcZÓÞÆñ/†µe4–*&!œ)/×6’JQÁ]ÔÊA$€‚äèÑ æ‹·ž WI¨â+‹lÖ,dÆ m§å²¢¦_ZSZœB”¢•HêW¹Ó²òm–°Y'%ñ—ú-\ö,›ƒ2ûi—e]m•˜ñšs€ cž;ò;hÑ °þø-…ý7`?Ia}¦©½ÀÎ0¬ãtf̲úLˆÔ­¼í]ƒRÐÒ̉Ä%Eµ“Ç~ÿÙbobcat-5.09.01/documentation/images/sharedsegment1.jpg0000644000175000017500000011232414050437223021641 0ustar frankfrankÿØÿàJFIFHHÿâ ICC_PROFILE mntrRGB XYZ acspAPPLöÕÓ, descü|cprtx(wtpt bkpt´rXYZÈgXYZÜbXYZðrTRC gTRC bTRC desc"Artifex Software sRGB ICC Profile"Artifex Software sRGB ICC ProfiletextCopyright Artifex Software 2011XYZ óQÌXYZ XYZ o¢8õXYZ b™·…ÚXYZ $ „¶Ïcurv #(-27;@EJOTY^chmrw|†‹•šŸ¤©®²·¼ÁÆËÐÕÛàåëðöû %+28>ELRY`gnu|ƒ‹’š¡©±¹ÁÉÑÙáéòú &/8AKT]gqz„Ž˜¢¬¶ÁËÕàëõ !-8COZfr~Š–¢®ºÇÓàìù -;HUcq~Œš¨¶ÄÓáðþ +:IXgw†–¦µÅÕåö'7HYj{Œ¯ÀÑãõ+=Oat†™¬¿Òåø 2FZn‚–ª¾Òçû  % : O d y ¤ º Ï å û  ' = T j ˜ ® Å Ü ó " 9 Q i € ˜ ° È á ù  * C \ u Ž § À Ù ó & @ Z t Ž © Ã Þ ø.Id›¶Òî %A^z–³Ïì &Ca~›¹×õ1OmŒªÉè&Ed„£Ãã#Ccƒ¤Åå'Ij‹­Îð4Vx›½à&Il²ÖúAe‰®Ò÷@eНÕú Ek‘·Ý*QwžÅì;cвÚ*R{£ÌõGp™Ãì@j”¾é>i”¿ê  A l ˜ Ä ð!!H!u!¡!Î!û"'"U"‚"¯"Ý# #8#f#”#Â#ð$$M$|$«$Ú% %8%h%—%Ç%÷&'&W&‡&·&è''I'z'«'Ü( (?(q(¢(Ô))8)k))Ð**5*h*›*Ï++6+i++Ñ,,9,n,¢,×- -A-v-«-á..L.‚.·.î/$/Z/‘/Ç/þ050l0¤0Û11J1‚1º1ò2*2c2›2Ô3 3F33¸3ñ4+4e4ž4Ø55M5‡5Â5ý676r6®6é7$7`7œ7×88P8Œ8È99B99¼9ù:6:t:²:ï;-;k;ª;è<' >`> >à?!?a?¢?â@#@d@¦@çA)AjA¬AîB0BrBµB÷C:C}CÀDDGDŠDÎEEUEšEÞF"FgF«FðG5G{GÀHHKH‘H×IIcI©IðJ7J}JÄK KSKšKâL*LrLºMMJM“MÜN%NnN·OOIO“OÝP'PqP»QQPQ›QæR1R|RÇSS_SªSöTBTTÛU(UuUÂVV\V©V÷WDW’WàX/X}XËYYiY¸ZZVZ¦Zõ[E[•[å\5\†\Ö]']x]É^^l^½__a_³``W`ª`üaOa¢aõbIbœbðcCc—cëd@d”dée=e’eçf=f’fèg=g“géh?h–hìiCišiñjHjŸj÷kOk§kÿlWl¯mm`m¹nnknÄooxoÑp+p†pàq:q•qðrKr¦ss]s¸ttptÌu(u…uáv>v›vøwVw³xxnxÌy*y‰yçzFz¥{{c{Â|!||á}A}¡~~b~Â#„å€G€¨ kÍ‚0‚’‚ôƒWƒº„„€„ã…G…«††r†×‡;‡ŸˆˆiˆÎ‰3‰™‰þŠdŠÊ‹0‹–‹üŒcŒÊ1˜ÿŽfŽÎ6žnÖ‘?‘¨’’z’ã“M“¶” ”Š”ô•_•É–4–Ÿ— —u—à˜L˜¸™$™™üšhšÕ›B›¯œœ‰œ÷dÒž@ž®ŸŸ‹Ÿú i Ø¡G¡¶¢&¢–££v£æ¤V¤Ç¥8¥©¦¦‹¦ý§n§à¨R¨Ä©7©©ªª««u«é¬\¬Ð­D­¸®-®¡¯¯‹°°u°ê±`±Ö²K²Â³8³®´%´œµµŠ¶¶y¶ð·h·à¸Y¸Ñ¹J¹Âº;ºµ».»§¼!¼›½½¾ ¾„¾ÿ¿z¿õÀpÀìÁgÁãÂ_ÂÛÃXÃÔÄQÄÎÅKÅÈÆFÆÃÇAÇ¿È=ȼÉ:ɹÊ8Ê·Ë6˶Ì5̵Í5͵Î6ζÏ7ϸÐ9кÑ<ѾÒ?ÒÁÓDÓÆÔIÔËÕNÕÑÖUÖØ×\×àØdØèÙlÙñÚvÚûÛ€ÜÜŠÝÝ–ÞÞ¢ß)߯à6à½áDáÌâSâÛãcãëäsäü儿 æ–çç©è2è¼éFéÐê[êåëpëûì†ííœî(î´ï@ïÌðXðåñrñÿòŒóó§ô4ôÂõPõÞömöû÷Šøø¨ù8ùÇúWúçûwüü˜ý)ýºþKþÜÿmÿÿÿÛC       ÿÛC ÿÀè"ÿÄ ÿÄT !"W–Ó1#27AXv”•—´ÔÕQUVÒ8Basu²µ $35b³%4CRqTcrw‘“¥ÿÄÿÄÿÚ ?׺ÿ_ôïRéß\Ú­ZZ¨ýWõø&â-êmÞ:téÃtJ_d© ÎcÞcþÑÏOÕ9~ië~ì ò1þŽZ+ýå+þVù ð3çª:rüÓÖýØäcÕ9~ië~ì ò3Aã>z£§/Í=oÝ~F=QÓ—æž·îÀ¿#403çª:rüÓÖýØäcÕ9~ië~ì ò3Aæ~Ü}C)UÙúÆŸAØ4i ±ÜЬX`ý—2­Ó;w*™r™7!à H%:óP¾ÑÁóꎜ¿4õ¿vùõGN_šzß»üŒÐy²l]}MxÚ:ß{¯A»z^æÈIJ ÙEƒž9!T0 ƒŸ//ËOz£§/Í=oÝ~F=QÓ—æž·îÀ¿#.Ë-¾§LdI+…¢" ¢‡ðÈâIêMS1øí(`GöpK_¨°­l“·Hè‡ÀQjýÜ’(¶\ ^â‰1€¦ä¾aÀ!çMz£§/Í=oÝ~F=QÓ—æž·îÀ¿#.I‹ý½ÖË?vˆ|²$‘E²ýÅî/b§0܇˜p#ÈyçÔÕî[…md±\ ââöz3÷²( Ùnò÷±S˜ nâù‡æaLú£§/Í=oÝ~F=QÓ—æž·îÀ¿#-É}¡­+ì#¥g¶f5”Áz£§/Í=oÝ~F=QÓ—æž·îÀ¿#403çª:rüÓÖýØäd²Ÿªzn¼WZYà´•#О €@qThŠ¥2j3”Ä2@%9 ý™kåw ?Ìâ2ÿõ'8¿WÝ îFƒðÓ/—«î…÷#Aøi—ËÉþ0 WÝ îFƒðÓ/—«î…÷#Aøi—ËÉþ0 WÝ îFƒðÓ/—«î…÷#Aøi—ËÉþ0 WÝ îFƒðÓ/—«î…÷#Aøi—ËÉþ0 WÝ îFƒðÓ/—«î…÷#Aøi—ËÉêŠ&‘@ʨRL0ðˆ€ùÿhçÖêû¡}ÈÐ~eòñõ}оäh? 2ùy?Æêû¡}ÈÐ~eòñõ}оäh? 2ùy?Æêû¡}ÈÐ~eòñõ}оäh? 2ùy?Æêû¡}ÈÐ~eòñõ}оäh? 2ùy?Æêû¡}ÈÐ~eòñõ}оäh? 2ùy?Æêû¡}ÈÐ~eòñõ}оäh? 2ùyDz÷#-ah£W%ª3o½Î¥^i(ÔÍ}«ÅURb`[̈(`$bû< €Dl<Õ÷Bû‘ ü4Ëåãêû¡}ÈÐ~eòòŒÕ÷Bû‘ ü4Ëåãêû¡}ÈÐ~eòòŒÕ÷Bû‘ ü4Ëåãêû¡}ÈÐ~eòòŒÕ÷Bû‘ ü4Ëåãêû¡}ÈÐ~eòòŒÕ÷Bû‘ ü4Ëåãêû¡}ÈÐ~eòòŒÕ÷Bû‘ ü4Ëåãêû¡}ÈÐ~eòòŒÕ÷Bû‘ ü4Ëåãêû¡}ÈÐ~eòòŒÕ÷Bû‘ ü4Ëåãêû¡}ÈÐ~eòòŒÕ÷Bû‘ ü4Ëåãêû¡}ÈÐ~eòòŒÕ÷Bû‘ ü4Ëåãêû¡}ÈÐ~eòòŒ #{h!¤6önŒÙÓj¬²È.y™IB³TJb˜ä¦ó dã¨/Ä.Éý˜þ \`Wqè墿ÞR¿åoš(jü-Šc¦]B­be^ݪJ‹0pš&Y$@çA€ðöˆd×îÿhû†—ý»óp,Lew÷´}ÃKþÝù¸û¿Ú>á¥ÿnÆüÜ ]ýßípÒÿ·c~n>ïö¸iÛ±¿7ó¨Äîëh-ˆ–¶+“ZOX’,H5ÿÇ"Üý€—ÿÌçðõq™Fŵúz•¤ô³«­uÄYÀìXBºEdÒZ#ˆ¹7„ò3uEQàAP)Ž`0‡w9«þïö¸iÛ±¿7>IzÙ©‰…=*Q9»Äähwöß|ÇËÆÌ!Ôú¥ ãªZ‚Y¨Ï’” ]£"EÍ[ŠH•Öl£4L¡SIºBª‰÷¦š¦ä9Å!([Ÿuv{¼£þ¨_ê¹bÅ_7)#’oF½ZD¨&Ôk1’'[´;Ì™ ¹ŒR ¹(˜ÂÀÛ›ê"ƒXÝt›¶à¶Äµ¥OièØº•†Eêe‡MñT7­úI¾ô“… wœ¢b¥ÛȈC± =£5Q0ަ¥! 5ÍjHM{,ùЧÝR¾\dPMÊÞÁTž€âpñ!@ `í Ò_wûGÜ4¿íØß›»ý£î_öìoÍÀËj+­õÞý4^Ëך±}xŒEat›«'+ç Õ7/@É‘EÑOÈ›•ˆBv˜ÀP 摬k½{^Ô µQ01Ó”¨ËD­QýÅ$Fv=òzcc˜ ¤îL¨¨ß̨”D;È>zqKÖÍT Ut©Êr4Cü_´Cý¡Ÿ*ÝöS€ / $ÔÎ ¾n4{Laƒ•|„?·Ù.èT˜mêšU𕦢i;¨­ ýâf Áܪ›HõÅrG8ª™{H`0¹NxÏè}AZ5cE)'f‰…Š‚íy }èÜyr_Áÿ=ße(ªk) $Ì¢""™Í7&'!Àð>/—!土wûGÜ4¿íØß›bc+¿»ý£î_öìoÍÇÝþÑ÷ /ûv7æàX˜Êïîÿhû†—ý»óq÷´}ÃKþÝù¸&Wzñ\Çþ#/ÿRs»ý£î_öìoÍÎþš¯ÎV5ÜtM‘‰YH‚ï\®Ü«_Çv²Å œ¾É„  ˆysÎ×2>ܶ[©Û¦b_dÍܘk÷ó0 k6zÄÁ^\ Ü«±–b‘Éäås˜¾:¤X G ;8 ×\¾éÿXIØŸÙ$#%RU´ëØõ&Þš5Ä‹ ÁrfB¯€'/€ˆñÙÚ&L† ›£&z•Þл–ºrá–&í'^TÖÅGÆ%ûÁ+W1ÄHɸ™S,8ŠãÚ$(¡ Þs›06&Ñ­(ÿ`·^¢ÙÞ¨oSBšÏLàåUÁ¸x}Åx£RÓŒN8Fç”é¯QJÚ¥®†—böÀr«2„]ŠF=”ª¥€(é£eÈ‚çí/h‰È=À"îç*[[÷%¾khéI[ôk²·B“5cB,ÐŒÁ¹ÄŠ˜£ÍÜu{ÉKÀ€€éiÓld+*=§fÎÎY¶=NÕŸ ‘Jr´U'† 5 =‰€˜é÷()”çö¾ÎÑúLÑŠÒæ5êÐÊ@OÍ–Ç$ÕKtÁ…Ì-ãzA”^'p­Â¦0”)`¢RØg76æÚ;¢›VRQ©hë4‚€õ}±HQŽp´znAúɦAbuò*½Ér'1»’­6¼¶þÔÚòõ³ìq‹Ïki¶¶UÙlÑiV¦"†@À˜2Š‹, r OÀ‡P¸'ºqÕV{c–6SiG¥¼”U¦R9Ûö‰A4ž,ÙÁwÛÏ eŒssçÝöóßú Öav€ØiÄÉ¥;WõLJ©OH&‹f|nUÁÞ}Àbp¢nDp1å±íÒÅ©ãi»2Øðµ®¥#©ˆI™øûˆâË·2:À^TU.ò‰N?ë&Cyë¯D#Q®7Šq=#"“Î',èprò&*¨€ðÇ<ý™\ýT4aªó´åëRîbìs)X¤æÑ*²Æ”M@P¯\îETïˆ#MÚP0ˆY°L a›À³Q놓Š2×|¹Ê"">"ÎuT1ó9„xòû01“Mlk%¤oµKÕòÁwØæ‰{e•t-"ì®U4ÛÄ Ç* ¨¤TÕðQ0‚ kÄîÉίmzê:"åvSmXê“ÛôDsxÇ*h¶A?DUŸqR\ë¦CC¬ ß÷´ R‚Ǥ= «.ƒ*Ü™eàÛ’Õ, ĺ(¨=ÌËé<6(øÊrš]¤0”@¥ãÖÓfžp”½R>ZuT×—«”sY5^Ð;¦œ»ƒqä"ªfîü¼àU½µë¨è‹•ÙMµcªNClgÑÍ㨠¢ØF=ýV}ÅIs®™ e°(?ÞÐ)HØÉž¥w´î宜¸ce‰»IÄו5±FQñ‰F¾ðJÕÌq2nB$&TËŽ"¸ö‰ (h—ý6iç÷ KÑ`%#å§UMypбIG5“P…íºhÙÁ¸7B*¦nïËÎ|Êtר¥mR×CK±{`9U™B.Å#ÊUR@tѲäAsö—´DäàwsKíËeººf%öLÝɆ¿3Ƴg¬LÑõåÀÍÊ»f)žNW9‹ãªEŠp‘C³€Ä²Ý^ß­bw ÝɇÝæ@)¶Ƀ:¬ÌGøN¼"Í“8&ÕÊd'"'HN¢ˆAQ猼Ÿtÿ¬$ìOì’’Ž )*Úuìz“oMâE¿…à¹3!WÀ—ÀDxìí&C ŠOú»8Òy„d¢ÊFI»šjömë¶qïœø¾:íÛ,©’HæñÖ㴾NJp'`܇ƒÖ$µ‚»Ó&Ç´Ul²p2ðpäY½ŽXXФ™ŒPîà|¹ûxàÛ•Dzé¾u8›Ãb¯³kŽì+,NN»1U#·¦ˆ&')¼O’€}œˆŽ–غꥵê+ÓO ¥S^µo 埤$ dÌvêâA÷p?”#ÁÓþ± MRèvSêÌÒ(Æ ÊÖ™U=;|B äH¯x€qP ' È —ëûWi£I¯êÿ»ùÅ +¾fõºÖgJ‚’IB´]ÙÈ—¤vó*¸$ w „¼‹)Ù[våÓŽÇÙµjÛé[VŸy±#›Í=^AHé6ÎLÜô•ŒeŒ‚À%PH¡Œ%ˆÑӔЮMÔЬH/`— ÔÞØ$œ%*wþl} FûÂØŸ;ÿ6X™Þ;Y¾˜Öïï&‡<»´×iE¼zýÛ„Û¶GÄàÝ…2ª“¸Üi{‡ã²µ­\Ùl¦ö´…±Ãs*wþl} FûÂØŸ;ÿ6P_ZíòËWImyšm 64«ÈQìÌtðë½T’äŽUÃ3ˆQ(dÌR( ra‘FU±:¤°¶·ì*–ºB(ŽuÚI rIBÈH Ô‘Ú•È´HZp HR(‰|cø‚'9€“¸áiý FûÂØŸ;ÿ6>…#}álOŠÿ›+gópØ6&º¥SéÕÈt¶%ka>èŒëÒâTL Ñ]À½æ(»íù ˆ”DL^;FkêWz?Õ± ñªÃÜšnV:ÖmBuX¬!&’}è€NT–LÅ)û„NRý¼(_nõ çvûf_› ŸÊ«ntB‘à9?æ þóªÿZÓ¢¢ÂnSnÝǦñÅÑÂhœÀRyŽöŒb€yùˆ€Û”îô®î½•@ÜÝBßmTëðOØLÖ+„&’YÂbIF¬œˆ ÃrŠ OÃ/r‚^9Èüý»LAô'yÑTêÍ®‹!xj¼½zÉ(§ñÜ«Tn›2¦Oè,©ŽÞ90`i/¡Hßx[â§æÇФo¼-‰ñS¿óe_¿·QÖtcéqtgÎl“í hÐ.Ú9YüÏsDråUSrB7E™×y…?`ˆ”G‘P¼õnýQÛZØïUZP)®š·AÐ;ƒ’|I¹c´+“µo舘DŠ ¨*™A‚w-¯¡Hßx[â§æÇФo¼-‰ñS¿ódž‡gVíF®Üׄy ¤ôKI3Ç=(•Ã#.‰T9;»LæäîàWB‘¾ð¶'ÅNÿÍœÚ)ü”–±Œ^^MÜ‹”ÜÈ6.ÕP‰=]"wœ|Ì B91ã'Ù]èÅsøŒ¿ýIΉŒfséרk¾ó]98¥¤lü'*ÀUÛMÕßR•³g`¢‚e@å÷( Ó( }žð 34šêÃJ³~F®h¹›.UA%ÓHÂQÓ”|„£æöçs2Ö¥¼ìGšêÉ#A§ë*k¸½e¶<ê–-ìÈ8’1TŽ¢ª.Š1„ÁÁT1„8(ç™Zêçe%ª ï—šÜKlKXAQTlÁâ$qá(¨Ë:oÞªÀAITMyÃÂKâ ˆãOh­½kØvKµVÍš©UÔ`¤u¤;ÈÆrÍÝ& ‰Jƒ¡1Ȫ'Då8‡˜ùwqŸV]­o–ÝçÑÙ†¢ë‰Ùf¦¦¬é»dÖ\è¶l›t”HTPæIC‰…R Pà#ÁBͱY *0î,‰–qQ­@¾3§k$È&0¡ÈþS@ hˆ€" ÁN¸Õöf>åJœi1 *—ŒÍëS÷$±9ý `03_÷vÇÛsÚ–.¿;[ÛòuiönÖYV*ÌGFºU%bÍŒE¹@}²œSH#š¾á%b¥êY©Øf0¤ˆ…q F"è‰E8û}‚p0þA|ÄDp=+náІ4—k”,æ]‘Œq$¦Þ¸9ŠR¤‰L *DåöJ>y!Ì/~´n+—DúÖé²W$¤§%µÔ£Y™dNäë=d¡ŒìD¢RÆ1DE" @DÜ@2ú¢ííŒßwÚ4ÞØcWUÕÜXÉAzIHVйpÜè¬E„Â')›ˆÊ ê€v3(SúÁ¶ÝKB¸ÀÖ[¿¯^'šÇ #xI‘Žt ¦„‚¯¿ùSyIER‡0§w «Ô–æ{¤)ð¶Ddݤ¥…¤4ŒÔƒeœ2j©1ß9M)Œ™E2§øi—¹b ŽPÀœÛv„1¤»\¡`2ìŒc‰ õ4õÁÌR•$JaPâ'/²PóÉdž¥l6Û/L°SÓªòϗص³G<ƒr!"Ø'›ƒUÊp2˜(@ ˜ÊvˆÜe…SÛ»u ÇoÓWŠÝ^RR2žÚãxÖlW$YÖàÍap&ŸÄoÀ*ƒr%°ôÆfš?Q÷É­IÖ–t)wwj쬊è×ÔPßsÒlˆÜÊ1]ÁVY'@¹ˆ' &nSîì0õ(ýMmYibÝ÷ªÕJ:—Fsfo:›%œ« óÕŠ¸M33(û|S˜La ;ÃPäv籨é»7WÛ¤%y)%fÈdß&ßÒ—0€IÄC!ì—‘Ê:‡Ô¥âf÷KˆŸ„y p`õÃóÆBÉ!÷.º-EÉáÛ€ð$b‘D¼R‘Tìà¢ÊǨ=‹²wGH*í¯½ J°NÖFÄšî%náG^1HêAH8†íïy€ng°lé”+-Â*ÌëØ(‡’M¢Û‚ÏÕE¨Fäà{”È|ÌCöfs‹êþM–¡•ܯ%éHiÙ‚Ð]¢íçž¹ôqxšª,¢@™ÎˆŠ†L‡íïHD¢¯œë}I[›Y­QVH$ìpðt§Vô&!kò‰øÍN´iÈìOÞ±ŠtΙÊ`îS’çÖúƒÜòö-EHÊ‘6åmÍ53´†ˆ$‚Æ"Šw)é¹"`¨ ñ À”;ÀӘÌr¯UýA3ÔNw‹ŠN¿Zä­VJ57¯HéÑgÕ…Y%D¢DD2b b+ÜÆö'º’¹ë ®Æ¬îèšòÌétvë`¸íEW(¨Ôä\G¹^öÂ8 J `ò PÑØÌÙCê7cÙ/tºóªôd‹;³ª®ðÒmËZx“QrŠn]®“¤N:^)ˆøœ@ÜdLTo´tóýìþ§A ýfÚâf9Þã–¨Ëú‹ ¡¸"G/‘€†€y(ðL ŒÏU}…¼ì=Wì}~ÑÍP)Õ•LÝÁWô‚¤ïÓŽ¢©¡À¬pL `?°š}¾}â:ŒcŒcŒcŒcŒcŒcŒcÔâdþˆL®1ÔâdþˆL®0+¸ôrÑ_ï)_ò·Í”m\uðt±­K²›º^$õêáM¢ÖpgbÝ@#@ÄýüqØÿúÏ;ÕÝ=ÿ„6¯ì ‡ÊÀÐyÞZŽ3xkY=y#0î î”lñŒ›@)–`õ²ä]»‚ÞFìU2”|Œ‡—<åsêîžÿÂWöÃåcÕÝ=ÿ„6¯ì ‡ÊÀå>›ÙÅØtMÛµ÷}QÉõ´tËw`Ú¨x掻MuQùü V½Æ?š`ä™{DM?úÁh_}Ô‰Y|Ì®T‰éÝdÌŠÔͦtÎQ)ŠjýÀ@À?hx^a¸¾–ýÙìO…­¿'ÚuÓ…ŠÙp©X6}æ} =üÜK„ NÚQd\ÉÅã88 tÊç´Å! ø)rí7kRhý£§#cuåspE¸×NŠ1l^VL¬Â,C ïJŒB‡iAl*v‡ /ÕÝ=ÿ„6¯ì ‡ÊÇ«º{ÿm_Ø•DX- ضFÄÜUûu:½µà_/ ¯gêmäå’4ê¦ÍFþi=;ïˆB¨@8%å¥êmƒgÜtîòÕ ¼iÌCšñáTt`3ßGQÀzY]9"ÊKŽ;¹çð½]ÓßøCjþÀ¸|¬z»§¿ð†ÕýpùX Þo’:rëªî(Rç{²)ÓÖl¡äÉ"£r¢2ÜQ]$ŠS ÀA08Æ–b–ÙÕ]…=°õ–Ô€‰^î“EmQò•e_2ZIÀ‡§2!¢£s©¦S$u(yäL™êîžÿÂWöÃåcÕÝ=ÿ„6¯ì ‡ÊÀ‘½Ò·WÛ—¸\lˆÅ‰T¯º€]еãxÏÊä[uÅr:)8±D ‰J0po!½"]Óì0Ž÷Af$vK]Ÿ"Ú¦¡a$“”וnwÇ„B€‰˜=¡7 íz»§¿ð†ÕýpùXõwOá «ûáò°=É-a½ØilºÞשzsÊãJü´sú»³0PÈ9t¹^6!$ÈœAÏaˆc)Üï%béRONX5|6ËdÎFëo-ÚÓ4ê¼g™"[;ÿ»·MÒ@Ý>æh¦1• <Ì&>z>®éïü!µ`\>V=]ÓßøCjþÀ¸|¬ÃîŸö‹­Á5¹Ë¶« L<ƒFiî, `/.¨’Hœe‡Ä1ɸ*dà£Ýñ^éëgë»CëV´ÜÑ©9´0ŽJÖŠ¶¤’o¤š4+oY¡á¼@誩ROÄ!Ž¡D@Mø^cÅêîžÿÂWöÃåcÕÝ=ÿ„6¯ì ‡ÊÀ¾b›½gͤ”ˆÈ;AÓpìR*Bá@(”Ù/p€hy<v³>z»§¿ð†ÕýpùXõwOá «ûáò°4Wzñ\Çþ#/ÿRsWt÷þÚ¿°.+-½djI¨ÑGI Uà*…fC$²g(‚§å\P?‰ßÜîîyÀ½AW,×lƒ“7UTŽB,PäS0€€û@|ò“¨tùlg°ë›Zûzƒ™µÕ+.ëmdc«ê1ROÇð?ï2gJ~ßG*@b”¦QS½ ^xÀË/z<ØzÎŬî¨CFÛ¯Ž®“„J ºi¿EË£:qr„x7:¢˜ Šp8¦SD{ÄBOné²õy22Ó{› Êô”\µ5hjá›1‚pÑ7 ¢®ÕÓ]'&MBÓÒ(_øÀŠQ"¶\zn—Ùw89ÇK•E(X%#¶íï\¸QCLbp‚€÷Å­šri]´žì׸ø+ð?s’ˆIEó)…XV@æ"k"¡IC©Á€â!Ä‚‚bÚ˜ÀÍ)tƒ;!P›¯mäå`î’mä…hÎ 52õPXÝ©;D­Ñ•0‰A$ù9¸í eƒmg®JÖž(¢må™.ÅS§ÇqHªbCsùx0祌 Ìç¥}ªûCT4SíÙYU­)Ü‘òAH\ª¨Þ)T”l’¤ .ÓEÊc—·’¸(÷ù®–²ýanÙ[¤;¶Töµ0d€P†2H¬²â¨8FL³…}‘HCÃí/" '5·Œ CRhý£§#cuåspE¸×NŠ1l^VL¬Â,C ïJŒB‡iAl*v‡  îŬެ„sG·ÇD5⊿g'w­%[ê‹$bð'*€nLJ >S,`f™dÒìuCaDÃ;§Ý³·­f¾’a FÍ‘Ú`Õ¹T)HïP@ö÷›={ÿLvM‹°®w mžÑ“ ¦ºú=pÎ> Tœ¶K¹u=)7"ìC»Ær ö B‚<òs_øÀÏPÝ6ì¦Í]p·++9Õñà™µiJ;VŽZºA²F0¦Wâ)ªŠAä¦ðøà ™x7£­úhq^Ô7]+±íñöªýÍÌÂë e#D²k®³’÷Êàn ¿ ˜¢^ÎG¼G½1SëMm¹*¬c*×½ i­D53&J©šHÈ7|4ÁÛ‘v¢bbóÉ…$‰ "!ÉŠ5cžŽvHéuúuc¾#ID`õ‹šÿ¥ÔŒâMš $x‹EÜÂtŠ(J’jqÚ"~ %6«Ævåe±Ñe+ÐvÀ€ž|ÀíÛÍ7h'ŽD¼åDTyöx€‘ã¤3ÆÉ÷ \ –/!ȇ7QJQze«GZnÑS²©Ê?M‚ áPEW '/Š`YTŠ çH‚nï#*˜qçåMîE#µR jYKŠV +fM½1Ë ò°£y#ÀÊDT >Cä?—)-˰于éã¿gc±4;:¥=»g b”Ÿ¯#›P€%`\² ,Œ?`‡ý"r³Ö ž9pÁeÑ"ª4pdÅVæ1@E3Šf9Åà{ bòÁ„8â}5î9„Œ“fÎeÜ™£•P wK•2i€þ$U8€ª™‡ì ÎÕÖ°õ¥· åÕE&2ºöû†ë¸búLWÁ cpñ™ÓXUkWÚ/C‰ßRRA¼ O5vgV'Œ>ªztÊ&)À{…P/Ü#Ày‡–ô‡‰œÑ¦·áÝš®MåQU[ÆÄWO"åeá¡Ï¦þ?µbøgΰ™Èr~ôÈA8 Pàê6•%OƒÖ[2‚á­ëpWëJzÝÊ©¾NÉ ”p$þITLnÓ¦2g@ÝÂcR¢åP{Cpew ?Ìâ2ÿõ'8éöVAéúÉ4ÒÍU^±Më7Éï…B€™uLªakÑÞ ƒ@~+˜ÿÄeÿêNp£\kl›Xó3qår݃&+¾|è¤L¦YR6l™Õ¸;Ží/pr!ÈdO¬Ö’R.l¸H9y‰IšóÈæ b£\>p»…R1HPMÜÿ¬!Ú”C+úùä)}AÇî©ê½­ÍRɬ˜Wš»J· «˜—¬Ý(ª­WfT… °(SÆHÆO·'x^Jn\J´EÍ‹GqVý$숣¥Ÿ¸ö¹A)•QRö)Ü™H&/aû€;MÅCzÝg±ì]!9©¶sÅë[“êÌäZm"J»ª‹dÒ+&ª% œ€y“ž)Z%fj½» Ôu\ZÞÓæî×i …a³¹JóIpf ‚Êò§¡ªeHB郟h½Ü€Lú‡nÛcHêºÆ¯²)ìÆç"ýìÌ5 ûW1å^1Ú&2gh> Œ»‚™bA1ü€@ Ë{ê§µ» À,çm Uv£ WÏcÝ4I$PR:%“/Š *b}ÃÞ%/Æn™±*—ð’ Ó·‡ZÉYÈ6{僆Ë2¨R)¦¡y!È`/ Ìí\«/ÓKý¼5-Ñ«º´„}~QÅR úh¹E¨™¼ôj¨"pP %IÑÈŸqÈr(/3¥õ¶p´¹°¾È<ž‹a4“zÝžRÕRsŒA¢"*ºC±>ñMA2%_°¾(%ÜÇ!8Ý:ÞVÁl«µœrI2B½…71ŽÛ‘‚}¢bœê*‘S˜…1È%0÷åî/žp8ܺêF>¤v—Ç&Ç@°ú6)â¸ñ ¡N$Ä©ˆ¨>0¤9ޤ?ÞçÖ7}GÇýËÖݹ«mÚò5Û›ÖéœQfHÇ…rr`ö@³]ëBˆ"cò€ñôç¯n4í‹e®Û+ j:…ivt·&l¡Ó‘g.äñEªM¨v¶¡8 Žz§ª³¥ú›um¡ydRí7^Aëö€^ïUví]FÈ‘²1 @(Ãçíã/+ÆëÖzåÓ–VÛ›¬Á˜H¿#f.^z½ ‰€:ôtÏèȈü(¯aG°ü²µc©%X¢Ü™U«ZÖB¼šËÀ¾]áPcý³—`™Ò*€›s„ʈ cr!Ì—¤#0&* I®bB¨E.îðû >YSÌÍ.ãªë¥ÅuäðŽuHD6[ÂUù¾\ÍÈ>í]!à9ó7oá€@#žé¥hGzúøÕ+MuÌÃ2SeTs“$T#µL­Äé”P(C…Æìï7©lCiÊŒ‹øÛ ÕƒùÉ>ˆáFlž*R™6˺"b‚*˜AÎp7¶O/h¼Éä¯u8Š[†úe"×›2¦9} ÝÞP—ØŽbm†5¨ù¯E‘{n_JJÛP´Y'!êŠË‚i®šòMëuD[ ’ï0¶Pɉ–'y0Ù—r}Új©ôë '!ëÚû¢Ç#•ÇŒØÞ”~Î Ü^ý¸'Tšjù¬PÚÍ­Œˆ36]A¤£e] ‹n8Ua0öR÷Ƚ܇3:nʦ_\I1­JªwðçL’ï.ÅëO½ÉŠ­œЧ)„ àxàs$EGZ,<ôÖý®¿»øúZN´µº¼ú°ý›ÞÖѧfªÍÑY2 ÁAS x‚%äÜÖÅ*.^õÕô¦í…„™Ž¨Gkäê"æR1hóJÈGÒ»’Ir‘S¦‚`%ñ @(™Á€‚<uµú‡Öz^ÅR¬Þ¥lîÞéÃv¾uH‹eW:Êvg)0àÝÊË´ bÕ ú‡£u}¿mIT¡¨AX`Ù¯U ×Ò•yâŠ)µn ™ "I™@9Š„`òÏ©å¡w„Ù)Õ¬Suk Áfƒ‡s(»2;‡rÝ%LƒbQOÄ9@ƈ!ÏÚùÔéµëd\—ª\уyDƒA´‚µB ºÍUz²é&anu E’á2òcÝ¥ »Y§R‚¼#llö"Ð Œ"ŒQÚ²br …+d)•Xý…9„„ ˜ C€GR‘}¨ìhOº*\ÒrLJåfj˜:J á‰ET”¨’„0‡)L”<Ã0F­¥\kۦ˥³XAÒ+³u«3X¨‰ÓnÜuè¤Lª€•çD†à „ñ±ôf^°½¡Ã[˜·Ÿ°8–|µ»Æï½:(&£MàrA";ˆND†î0z–á¬*Ö5ª“6E "ÑfMÞ¼{§(±UÙ€­Hét“2MŒ¨˜½€©ˆ&CÈ@sâýõEVeh9ëjm–hñ¼sÕÁ£…±t¸“ÁAÓ¢Pl¡üDÄ©È" xàÀ#žöK Lvè°Ü4ÄuÍ¥ºFÑÂÁW”¯¸w\µ0 4OÖept|&†A₩·‘š Q1НëJû;+Loº¶àVvÛ5*Š0 %\ÄØ˜=x.T«4(·IB‚©‘@]DĆ r=¡Ü«n›ÏVkÙÑ–ËP5qÉ))0I›‡%h¡ŒT×vtS9[&a!ø:¢P!Çž "ž¤te}´#ٕٽê'©Œq#³¦‚çØ0¬!Àr"™ãz‘fgÁÒT´HÃl:»x݈´Xl+C.Dé¢D–!‘YFK¨q)“_ŽÔN ˆ)žÝæb«8¿KS:š6Íc¦BÎâR°ˆÚ0±.™¤wMxf™ U;N"&´Të¦ÔaÝΫ´¬jçm"ÉØ-r‰@Âé Äl^N_mR£ÏŽN-V…OôKÎUå[¨ñ“XÖkȹpØ€Q:äA©PÈ—¼Ê{¼¼ˆw9JÖÚmêm¢Âƒv8ÜaˆÞ¾¨É€K-÷<›oû¿ß‡Ò„KÉ9òåOü0çd4Œϩ쫔.ÖiSžÖpµ”×â%ˆò&MŠëxÍ^3A!všjŠÅRì1‹öñÚa +'ÔŽ‹‡¬ÌHìÈt˜Ü“ñ`œÌr? @}®`í ܼwyg`êÓHÂj›vÝmh<ŒU(Ê7“j“E‘z›Â V¦Ab‘B(~â{À¥óäDBž±Ö+ôç7Dë]y°Q­WîÒSNq\“t»î[Ȕ˺HæG½Ã0^Ó”ª—¸¤,SwÕ®d:Ç€«ÐmÎYáaFº¶ùeUdÔr •Q¦àà R”1…@w”9Ú›åSbÃ~›+ëXÍÅoD¾øPíP¥7Ø`óã<÷óÂ¥ÜcopØbãgX"°ö‹y¨Wqn“7"AÒi¨sÇp”D3ÝÀcÀcÀcÀ€uø…Ù?¢Á+Œuø…Ù?¢Á+Œ $e†G¦]:âµ\w:æ)JMF-n’Ê ŠhA ¸Q4ù€pç/<•ÙlO®pŽ«6þ—m³‘‰áºa"zë–ë—žx:g‘˜90ûC"’vî™tëzÕÜ™Vu(Å4Eº«&‚É E€á5äJ"‰Ž|¼ò}ômsüà¯ß©@MÀ¯[ų×SœÔ} ™¥†5¡XGxsQ]…Q1ÑHºQDÉ÷ÅOÚ1„yã¸LM¶ïS2NޱtVä‘NŽT_—ȇ&+s "a)TÑ`LP7Ø"ó–ѵÏó‚¿~¥ý7F×?Î ýú”ôÜÜVºêÐú‘ÓÂÈ/ꊧ¢ªè  UÌ—§v@âÁÜ>~y܆ƒ©WlhÜ+ý½Œžlˆ7FQœ}]‰$ðÀ…XÀå/`‰xã·ËìÉѵÏó‚¿~¥ý7>¯m‰ªšê"öUUÈ- Çãíà=[çÇ!ÎušqQÒóVþ§IÙ2S/B´E¤ˆo#ƒ„‡*ƒ€þyà9ç€ÎN¿P¡ ýµ#¢‰¥R;wäcXl’8ˆ™5{‡yLod܇Ÿq“?£kŸç~ýJún>®œûõ(é¸xz¥¼´kˆ†ÖŒVÁÆœ]U2\ÀR™TD€S8bð"(~@ÎÔMo')-7'ЉÞHO M(åÄUUU T*€+Ï„T„?&çÚ)GíŸý\ÿ8+÷êPÓqômsüà¯ß©@MÀ†É@Sæe=1Ñ+ÇÒggêã=sVUs4ðÅ/T3ñ0§á˜Äìç·´Âp‰_Nžm2L*î}(”K½øöGØgìòò ™)®­È¦e–êøDÈQ1ŒfpûDGÕ¾AŸ¤×Uêúb˜J`g ?”?ønd[•Øz9—û¢Ž@­YËú-gÓ["Rö•4×õ‡ˆB|€  ygÜ}vË‹F2r°Åx´ˆG=eX]°;UC*ªþ߉À{?g—gt[ŒҖAèæ\eÖcêµú-gÒNϳ³ÑÅ_Xw ]žÏg=¼yqÆIþ®œûõ(é¸ú6¹þpWïÔ ?¦àxTר먯ëî’¬5ˆ³,gÆ:Û&â©€ÇðÒ){„ Pã‘à?³$zRr[ÇGY"‹‘/ܪÍeRQDg‹*B˜Èœé‰»/=¦0sùs‡èÚçùÁ_¿R€þ›œÚRjr[ÇHÙ%Ö”‘/Û*ñd’MEÁ‹$C¨‰»/=¥(sù0'8Æ0Æ0Æxûõ`¶~ö‰nˆ°¶‹|¤cÅã&å4¤1Ð1ˆ"r•B—žC¸9À÷ñŒ`1Œ`1‘KÕÖõ+<=.ËuˆŽŸY6ñ±ë¹)Wp¡û¼0ý¡Þ)œ #ÀJ ˆq’¼1Œ1‘Ø@žµÉÑ î’6(DʬœSWɪé‘L<¬™DLŸ#ù >a"Æp¼xÒ=¢ïߺE³VÉ™e×XàDÒL¡ÉŒc‘J"#äæT.U-^km£Y#gá™R¶‘ŽrG —Ô2GìP‚%0Èrˆ€ñÉG³eÒõV1;eææÖkzñü½I7½ZºŽÎ'tPPˆ‘SÂdÒpBy¼ƒ¸y·Ù³kÑ [¦Ý³dÊŠ(¦P)!C‚” @ž4Eú`²ËS nÒ3°Lұͦ³†â=€ºe2b=£À|³ßÀc¶ì:cIv¹BÁeÙÇAêh냘¥*H”¡ÄN_d #ç!Æ1€Æ1€Æ1U/ÓôckÕŠ÷RØ·J¢ÖõRq>Â%ËAi ²h•«Ã†ê¨‚žQ;s¤aí(óÈ„þ§T¯Q«Qµ œZQ°ñ ÊÕ›TÄD©&PòL"cåDDDDDDDsÖÆÆÆÆÆÆÆ¨/Ä.Éý˜þ \c¨/Ä.Éý˜þ \`Wqè墿ÞR¿åoš3äGú9h¯÷”¯ù[æƒÀcÀ‰m]™^Ô9=gMÚÌ£"³2Ü»p²¥Eè”ÂeUB "Ƀ‘äs;M!duÖæ‘³Ûµ•r­))Y¶Gò`ùã¢&“Ô]¨ ’{Ç´ uIʪv˜>Ó]GjY=Óª_Ó+óˆÃÎ$ñ„Ä;× Šˆ$ý“¤Ü¡â”<Å3 )¸ó0ˆr bëÞ¡®³Uí»Ô¾ˆFÂv6MŒe…ëµôò5/¤"e&æØGÁ7 !÷Óˆ4>fé~¬.Íší°}?ÈH£©^ªŒàžÄÕ*‚lÓvc·(¢€’Þö€€phiÌìôžìoÔ3SÆRm´ºÎ!@,.û[Š±È°¹@ä¼!W’ùpíàG7MÚ ¶öѶ¹M‹j¯Ò/5{ ¤Šh[$£Z.TPŽQ‘Γw! Pr ˆ”žáîp{]4lIÞ¾Ú»ßs™•Ô0’îä铳ŽUxõXD[œÅTLºè•b* ^T8ù˜¹Í]қͅëBX$b(…aªk/«’¾‘â‹9ô¤Y e(Ç”£ØV}àC½Â§oq@½ææC¦kRM÷F¢:°¥ÕÛmy 6®PzªrPNß4*nˆF¾¤¢bà¾1xX€Çä£Ï´è¯£d-5Šü¥A ¬d„„"³¨JÉV­EسxÑ2”pt ”¢¥ï LÀç·SêyþÇ¥ë›æ´û˜{¯»Ÿ‰L²þ”é¡[•¨Ùûs"˜¶X à¾E2¥î!ÊÞr9­z‘w­k·l5­Ri(pí®Ð/ÜêŽE¡’né&ÂÑ?E7ˆb˜â ¨%í?gáÅñé=;íH—¨¯ŠÓµ”4XÉh¹Ôb&^,¼‰Þ¢Ð‡}ã(ȆY^æÆM_kÚäV0˜{C¡ÔîÄ>åéëzFÕõt=‚­O‡žŽu59 D‹ë6mñ–`ÜXU3eÉC™¾¦ AòïË»±.•úe±PÖÆ˜âŠÖeÔ¼œˆÆD DÒD€ÛÒ¹rq0˜1JP! a8}™_½é÷Ak­Á¢)¦¢ÉSöXÜBËÊJ;jú$òÄXʶY²mT"å*ËŸµPT‚D‡®×EnTnõ+ Ôu Ñ Ja^õ,ij³¶„”AAñ$Y§è‚›“(Ÿ`œ¨*ª¢8k^ÆÜ;¤mù@£µR^Ê¥€í‘X–*f‚v&n£¢¦¡2¼ÞE7ÑúÕŒ’+¤ŠJ$ÙÀ:\L`0÷‡À´Ýòºj»´Gg×â÷XêæÕ±=œ”+jà„«DÝ5A²È6vgFH£á·3s Ì €÷«¶ö‰šäÍ!ýuH¼¯#/ öL¨# ,Úff)…C1Ô RJ Ä Ó/TísKK3ÕñLdvdÃÚôŒlªÎ[(ÑãtÞŒNâŠÜâÏÄ1LqI@à¦9šIôë'Y¼Áìo§=Œ­´§¼“†<¤kØ–§jQLŽU5‘¨Póv˜<óöÿ£ö}êKZÏ«¶ R–×ÒëÎeêJ*“÷* áÐM7Éø(•'/qÏÉ &9‡žB[9~œÕZVgdîE*þ¯öVTWÑÖ"s”¨ÞØÄ)ƒq><ò»S{lúKm_lÚ0•ÂÁm ˆøAŠMr¼€{ A32¨ªª ^¸% TјÀ`)Š—Eê™±©s´ KaqcŽqù2VLH~ÑÿTÀü‚?“*V]9Ú¥‰®àöfÌgb®ëÍ%bš¶ô7R™¦dÙ®õa]B›Âwö¤š@uJSO§åv5ƒ¨êæy»¨fw6­ï*Çv!ÐÌʇ!Ø/y¹óA·œžï]¹°õµÓZV©•¨)do“kAŸÓÝ*Šˆ¬ Ü8)ÀŦw7ö”GŒïê;kÖ×­‰n™¼ÄÍ6Ø›;6°*2Qšål‹r”3µABxhì(÷ Î|n}9oÙvý}k­^áà.¤Ú(>¯«!ék²Í»Lb;C´‹˜xîxòÀ„Ou |¯ÝiÉ·UHë||OOK·†’“'Œåd™·A²&*ÝÇ"':‡:€Tø(+Ýì÷¢7Ö˲jzs[¯PÍatñ–JÒ¹“kvæY"6ª¨Ýg ådKáyD©¨SwØ2[¾–µ¸Ûm÷f¨¾ÇÖ¬+Ä'_šk- i8ùF)¬eQ1’MÃu]#*·iʧí0—BÙ¢¶Žá®öb[Z$-´T%›ª£ú¹œÆ½+ð SjGi±ÓÊR1»9)ÄýÂ"º¿Vö[ºUµfýâobÈëˆÄÒUfñ®jªýò•M·@êŠ~g ;¹çÒO[Wál“hé¸Õ˜£ÉH´—âYø‘x˯ÚaP  ›·ƒÙžÉ:7°¡ZzÍ®ã*66{æÉ­N’¾;î”TÎt¤ "r®¡ àùö€g¡;ÒÝöõh·Û/û†9G7mvz‚PuµXTüW*Ãcâ¦/r=ÄSÄîàÞÑ@ÀR‡¾ê>ç#·¨šÎØö,¥ÚNEâU³œç®È²+c*ÉWºÉ:ãÇ1䇹>á €2 Ó;[jhŽcöû8úÌÝÇ`Rj0É.Œ©šÈõ5œ ¿ˆ)ä‰#$^JAöù2ð®ôß°£®š¦å5µë®Í«bßA Å…8Ì[»déÉ@ ôâŠÜ5(÷raÈ$^MçÖúIŸeªÛh‹^Óe)¯Ë.îQó&UÓ3}$’òjH 5œÒ¥E{á¤C0í‘ä<‰‹ô6«ê‹zì« R6±ªàe\¦@TQ4W“8€>]Æíà9D9Ïg]u²l:5vZ„„eÙ›µzªI¬¹I·¤&›‡NÂt™ÊEñJDyS³‚ˆ=™þ™Þ\vnõÜ.Q¯ªûª•BJ EQr“4ÏaÓyéFW—G7ƒÇ²^£ç’-W¯·U%x ~ã…²@@£è¨Uc4’|‰RìKÒœ‹µ|ÄRA18¢"˜¢Û¶kTjpuØ„d¬×»Èdœ˜ÅlЇME•r¸”;…4‘EC‰Kæa—’€‰ËFõK!¹O©Ÿ°ØpUã v˧»#©Û#,ÜÒlÍܪ&:çl%TL˜ˆ˜ü€w Þ[×K—rBA–6Ò½bËR›oa¯M"ÔŽ½ ê@býñˆÉ5!Óî/ o´8ȆÍÑ[£lÒ[U­[¢¦›¦ÓÑSepÎŽºmÃБÊdM&còu(¨‡hpRy0‡5OníÔ7¿M^+uyIHÊ{kŒ!àWY±\‘g[ƒ5…À˜ ¿¨p^ È”>ÀŽÑú¾HíjN´°;¡K»»WedWF¾¢†ûž“dFæQŠî ²É:ÌA93rŸw`€׿ôÇdØ» çp–Ùí0ºk¯£× ãàÕIËd»—SÒ“r.Ä;¼g*`¤!áH#Ï'7 7M»)…³W\íÊÊÎu|Cø&mZRŽÕ£–®l‘Œ)•øŠj‡¢y)¼>8¦^L:KroݳêâzU18¸y[ 3¶h¾pWr.®ºz1ŽšD2‰¦2£È÷À—¿Ï¤u1lSjRuýÚF$[}rVV@µÃ(¡«o˜¹Öf²àºÉ;íÎA91îO»°ÀíRºd°Ai þ³lÖÏÙ]6ªR10ªF¹`yE\*¸ûN–@¦\ì{%7ww!ׅ颸ÞÛ«m6=¥[~ž³ˆ_$s*i™5|ÁÚ ’P;}4þÜ6/´Éð ‘x0rë­»¾vµr—µ©´ÊÈÓ®/SÕ¯Uè"žŒùG§b‡9ˆ‘ŒÒª ´M•æ´êƒo@ôØÿ}mvÕ¹¦Îfd¢á™ÇøèºYùì 0l‚¦˜„nAà½Å)”Ó9ùZzoDì­'@­î(ךîÙÏú®'–jÈT ȃ°LÉ—‘(ÍDý£À8ìGHRhéÛ†žÙ輪¸•u5[pÎZÊÂàòàxÀìU·æË•·Øi¥Šˆœ#Z’–8Ùä ¤âX$銚¬ÈœLq*„P‡!ƒ¸¥S’Žr=ÔÆô?MHu1)BªŒ;êÄ|“xÆ'xáâ.\8A5*RÀ-IUW2dîS±ö€L ¹LÞËÁIF]vÝRIȵcÚ9V‰¦0¥8!ŸœÊŸ°;2$9‡Ì¼xt-#³5΃¬ê þÚŠ$½@ÑèÇM¸ªh®Í©“nå·¦ ┇!ÎEH8/³í—IÞ¦¶û «U6Ñ «¢zŽr¯ÜFï[Š)˜þ"F]aIB**J*û "ã,l¬t¾•oª$nÖG«'|š$Ô‚LŒ{eÙ$¨ *@Æ»ÔPMʇ9Œ Pà¡g`1Œ`1Œ`1Œ`1Œ`1Œ`@:‚üBìŸÑ à•Æ:‚üBìŸÑ à•ÆNC’é[^)²¨Ê>±_~wiÉ8`vë&ÝHå]¹È¡ÛÇiƒ‘<ùã<\tÃï‚Ñûİ7‚¡¥þPÿÝcš>zã¦|Þ%ƒù¼zã¦|Þ%ƒù¼ÐxÀÏž¸é‡ß£÷‰`þo:òKô£1ê"[iØ^1|‰Û9l¾ÀŸQ%’9D§!Ê.ø1LQ!ÍŒ qôÿgÿÂG|K/üÆXž¸é‡ß£÷‰`þo/YŧÄ:ZµÅü¡jÙóônªŸ§X‰*dËÿ¨8ÿ³!¸é‡ß£÷‰`þo¸é‡ß£÷‰`þo4t¦_º‹‹s Æìºè½6,މW\ûH+¨š`?ÿQÊíÀ¢}qÓ¾ GïÁüÞ=qÓ¾ GïÁüÞ}VúΤÎÕ¨·ù uz€¨ì7Íãaç¤P3R¹pq#t×#wЬˆpŒŸ`{F/!ÌÆ©·''7ÝÓLJÕ˜±B± 4ÎE¼‘Üâ.Õp@2$LQn>È@óîü€Ï\tÃï‚Ñûİ7\tÃï‚Ñûİ7šó×0ûà´~ñ,Íã×0ûà´~ñ,ÍäÇLmËɱlzÕ’«îƒc$ dÎõ7%34•^󢈀ˆ.%ìòã“}£i`gÏ\tÃï‚Ñûİ7\tÃï‚Ñûİ7šó×0ûà´~ñ,Íã×0ûà´~ñ,ÍæƒÆ|õÇL>ø-¼Kóyiê•õÐÓ[°ÕÒi>‚YT r=UÙŠ°œTPªÆ2†8™A0‰Ì#ídÃ+½Eÿ™l_Ó7?Â4À±1Œ`1Œ`1Œð ¯Ô{DüåV·nˆ•˜¬æX³xšËG^ÿ ‹”¢"™áŸ‚›öGË߯1€Æ1€ÆGo[‘¬ T³ßíðQi€¸x° `)Ž%(}§7iLnÒ€0ñÀ{’qóQ­&"¢ñ‹ôrÕʦ²G(‡)ƒÈJ%û@p;XÏBéN‰ƒyg•¶C2†Ž/sÉÒM³pòóQS@ó´Cí ìWlPVè&zijYH™Dé“Öªˆ¸DáÉNC”CÌÑÆ1€Æ3£9;Xˆu`²Ì±‰‹`˜¬éëçAº ‡Úc¨q”¿íÀïc<ºÅ¢¹u€ej¨Í²˜‡’OÆfù’ÅUÉȇq_# >aœÓ“°uˆ‡V ,˘¶ ŠÎž¾pD ˜}¦:‡)KþÑ ö3ίX`­llÕ™v’‘2hË7­p‘ƒ’œ‡#CÌ3ÑÀc<+¥ò“® U´l lEr!úQâm‘{Î aàx(y@9ì º.MËuJ¢KLå@Åäû091Œ`1Œ`1Œ`1Œ`1Œ`1Œ`1Œ`1Œ`1Œ`@:‚üBìŸÑ à•Æ:‚üBìŸÑ à•ÆvOô4¢Àjû¬sAåÉ„”—FÔ”"#ȹN³Wr š$*,¡ô5OØ@ó0aà<ÇŒœ}5Æû½ØŸ »ÿ.‰Œ®þšã}ÞìO…]ÿ—Mq¾ïv'®ÿËbc+¿¦¸ßw»áWåÇÓ\o»Ý‰ð«¿òàTU&ô½­Ô^î‰Ý(FË©IZ5¬$Ø•V‘ðÇ`’Ç|’ †Us¬qÛÜ™ Ü^3Þÿ³ûý 5Gü¿ûªg§gÓ7[u²ãÓ¤ääÜ?¯‘‘×Ê9r×î C¤&/óÈ|ÃÏ<¶¬ž°IµWGtžý:ÚixÞ n`ÒIÁŒnò•²,T'¿qåȇï]q¨=Ôµ÷]ê %z¬ EZ=Y²…"ÒÍ“PÉ£ÈÂóÈsÈžu¨5aÖ”ÍFŠÕX¨Iýj„Ûøò9Tè+ ”™Ñ+žÓ˜@Ô˜ÁænGÏ‘Òwæ;e¢±ûû¤ç«5`¢kF æ¾¼úfP{»ÍÚ»$Á#´œwò?goŸ§ ž„–˜RÅ+Òû÷²«5+8Ö¾#ƒ¶*~"*0¦ € #Ço—y`dJü}’›Ð6ÜëÜÓ±µ©*J_Ê2DJH ï &¢>…T2‰Œ¡;ŠdÀ ný©9r¬îΤìZõ5eŒÓ1.¢ü"Ô+’TÄ1 ?„bˆw|ùàyã,zÛžé²Mfiý+º‚b®£u5Yä@‡M1y<óÓi7¨£íël=O6´¹Óˆëã’A@0 àñäß—™™®Ð«=3]´Ã²©h·Ú`XHÈ·q⻳D»ju%za1Œì ˜ 9Ä™ˆQ(‡Ø=ýCR¤ï¦.goÏ9ox¬ì§Þ’ðŠÕýy£€höíÔlÔè‚"NÐWÄTDLae©]”Óµ¥lu^ž'¡åW!ÓQë ~¢ ‰n󗼉¸1½£< ¼Ç‘óÎ Åtm¢ÐÞËÓ<œµ¸Q—}®w©ö~jçDTßÉÀù~L Ñc”nÓqíV.¶ÕΞy·£SµI‘qÙ9†ÇÆ “„Ù «*UÞÙJ<&'ïší¨†­§9²¦«1r¥Ž±E¢Ü t¨™’H7f‘Š$;UY4 C¤Ÿ8•¾Ð4@rÿùÊ•/¬õ£Õl¶äGSËÇÊ¢ýZŠÇõ‡ ”JÙ3$áùþ!€Æîä½ ŸÜz‰ØìèýDÏ -lÒ:]ËÁ`NÕÁ­Ð‹Iÿ û}Ýâ 9(€r½×ÕY>ï) Úì’®ÇÐÖGÑ<@ðÓ¾—\;Š"Èœ¼p?7N—/“R[Š:§¶¢¡ª»¡ŠÉ˳yZ3׌©V'Q²àé"øfL„1ˆtÌ<€L^{ƒÖƒéë`El]ys´+Î…UqT„ª.Ÿ¦¢·£÷«Þ/Íá˜=.´Áæ·í ßë]¾Yjé-¯3M¡¦Æ•y =™‚žwª’\‘ʸfq*%,™ŠEN@ "`ò(ú‘ í#õqÔ õSÚ²2)W©g2sí\,Šçd¼4ÀÈ(AH{¹?ãË‚äî=éù#§.º¡Îâ.w±¼+"=`ÊL’*7*# =ÅÒH¥0œ€Œ`9fhhýŸ³n[>³¶ cßÞ¢!#dˆ¥IEýXô×'ŽÔEðâåC* ^'ày,WZcj¨ë#`‘¯Øö yu߃æ®$›Â-Ç¢¼ûÓnÕºá4À ˜ DÇ1‹Ú7·U{^+Q/{ }´ŒVÂkKqé;b„»W›&‹æI.rÈè¡Â‡”éœ;Œ’×](·«Åë§Z^è¥nͬ›¾i#,ËÖhJ ôAG©¿Hª"eeÊU„é1)ÄÂPÜïíM´¶Î½gQÛ•ô¤›ÙXXNù*ŠžŽÉÂ.l“N”½èòse nóqÚP³(¦Ø¦Œvm˜•q9z µ$‹´”HU °ÆT¼ÀS@ È”)E:…ÙÖZnÈÛšþºj¦¹’•`œt‰ôë#ÀõTœåM  ˆ©$·p““‰x.‡#ôØ6NUËwH‰ åfè”T æ"f9Ä…r Q9„@Æã‘¢tËec~×Ô]œÚ •±äŸHȳ<8/Çé²qã2Q˜ž"*xF9¸îÐ(@í—˶ÍêKGX5 À)?®¥ìÑhÎ`MÈÇ÷¨¡û)Iæ ê€ùÎÉêç]ßï:i 欆k(xù¸§Ò5“;+$§â[.S¸‹ñG‚&UHP(óÁD %!ã9ÒéâJmëûå>Ý\×µ…jL+êA*²†`§£w:eœ Ñ0 ø"<¼¸“îmyq¿4«¼¡ÞVfªvçÐQäzZ>µrÜÍ\$šÈ˜S09rä¦!Gã”ÓöM qµÞ%éúò[Yl–ᎰS¤¡ŠT­Æ:N»'k‚÷«â^Á(p—"9mm¯¬´ŸLd¡êN©W”âjI¦‚®}hÙUc×Y'"¡€£¹>ÎKÈßh]¬ô5ÅýÊÁ¶í·˜77ÉJ¨Ó£VgªQ‘‘æ[ÇP:œêða0¬@à…”¾Ðš0Ï¥+à e¥µË}µ#¦æÚK ôõ5‡Ö@Õ²­ÐLɃð𽇠‰Ì7q»€Qs¨Mõ±µ!.òìÔ¢ÄÇU+ž½‡i2¹?´4•UÊH¢Šé¨Ð©ød'ˆdÕN}’”q=¾¶ÓýG kú¥XR¿ÒÙÙ9•t¿,KÑyÁ0ò¥p w@¾dçÒÅ¢Ã1¹µ™FÃî¨À–EÝoÓ±\7wé$J oé·“ö‚nàïBôõ°âö>¸Ø m*êÿp5•jÊ4-Mrz{eLØUP2à¨%j@(öœ &0ˆÈ+‡}eßÏWœ¸AÖâ¥S—43ªóIGn§Ñb¡ ³7DI¸x¥qঢjÅL‚q Ÿ´¶ò7al=t¡jÿ¹È˜í~£VsL×|.ä—nWŒŠ ,‡aID„ê™C™NÐ'²&…oDl½m5eiª6ÜLE>Ñ0ê|ñr•ƒH;‹xé@QÈ2pWI©œæPàUQTaÅä¹Ïô|¬mÛFÇÕ{B>2úfÎ,pÒ"íJ€;d©\#à*dˆB˜*©òP0”!@×*ozHèÎnn†ÊÆà·8æ*"1è8r塙ʜíCÅà C„0¦&‰ŠQ0 ¸4W¨àöþôƒ€w®Pš€k-®Ý²ôS&‚Iª‹‰tÓK¹¡JºÇ)¨qä€*öœ@¡$ˆé`Àë ;¬â÷-{ÂÓóˆN´vâš¹ÌýTSr‘¡K"P!{©Ï"&ˆp 3†zÖâéaÛ6½)z•¬¡á½xÍbã#Œ¿Œr•§¥eNu¦1ŒçýB@¡ÈU=;í™ø!ÓV™¢Ç°RÉu¥•ùŸÈ¦¢­"ãÙ7DVXé&bc˜ë&™L"'Keú´’¡ÆìúýÒ®ÖJí­ä¡#B(çEœÙ¦D¥ŒPâ¡Û÷Æ*¤0¨$ðŒbŠœ”±NéFÁI«ê’Fì¨ÓÛµ%áâ¥þçLF²K"D•jí°º1ÄÃá&pP‹´åˆ ŠnÔÏHqJ¶Èo¸¬ö۳ǿ?ĬË´pÕ¥hŽ ”ˆÜC˜æ:¼˜Ü"ÝQ=Þ ôó¼!¶,UaÍxºõæ3PåQ±…é“PhfꪩÌRÅ[’÷qÛÏL"`( @7Nó¤w¦ÍÔvUxÞ•g!d‡RÏÙÑn%"€QuÖç·°SLÂ"™¼€;Nžm4›ò·Ê¾ÉŽ=‚ë|r²¯[—± &åb-_{0ˆ¬“¸9(‘ÓwP· èù»õSÛ D^…‚®’k¡=VvEHVíÝUy[¼¢§r€‚Eî/³ÜÎhŒ¤(ý>ØØìº¾ØÙHyÛN¸æ¸“è¨3Ç/*U…çŽw ¦o즦QCpnü1Œ1Œ1Œ1Œ1Œ1Œ1Œ1ŒP_ˆ]“ú!1ü¸ÇP_ˆ]“ú!1ü¸ÀŒRn.è](Ðí "”tÞ«]A‹:ɨ¢É6D½Ê@!‡€û2Oë­õîÚƒñ»ßé9]“ý (Ÿð‡þëÐx]o¯vÔÞÿIÇ®·×»jÆï¤äÿ]o¯vÔÞÿIÇ®·×»jÆï¤äÿ<+ÅÚ¯®*rw‹¤©#abñݹ1 ~ÒòRÇ1Œ%)JPÆ ï®·×»jÆï¤ã×[ëݵãw¿Òr”’¹ÏLõ‘§œ'[ØF3õË:Ž˜ÍÉYÈ 2V);U4TOÅPMÞ’J}ð½ÝÂΪÀ€zë}{¶ ün÷úN=u¾½ÛP~7{ý'3æ£ÝÁ§ß­ð›ÇY¬lù2«.šŠLcãÌ%8®¹œŠIò¢‚ àBˆdÚB|¯úÉÖ’5«T›¨ V¼›’–p¤s "ñþŽá6âqD¦ìXÞÙ`7˜–›ë­õîÚƒñ»ßé8õÖú÷mAøÝïôœ£ÕF·^9­´OŒöT°­î‡l‘aÔte¼ûB§Ž™~ˆ"&áN;Û¨Êeõš<°vÔ¨ÔålÞ¤j’ÁÝB‰ÓñEEîPÉ”Ê)w«ØnÀL·®·×»jÆï¤ã×[ëݵãw¿Òr‹Ù±Ô.¢¶íÍÄ­žN®…µbF1IÜÅråð Z7t¨#©ÂE*ìäÜ¥îßÛöYëNÓéâ¼¢–Ú¬EÖRt&b (¤kÅFÄS\ì–î(•DÓ?iTÿa¿Ö.¡ë­õîÚƒñ»ßé8õÖú÷mAøÝïôœ¯ì–{=»¨æ];U®²Õ¨*Å,–Y§ŒLšÒ•YȶhÛÇrED¥)RUUÀœâdÀMÇ>^®´Ímjǧl;$»»§³ÊÀ^*EÌ:²$E¬ÑÒ ÉDŠ'2K@öf1ŒaûDG,Œ®·×»jÆï¤ã×[ëݵãw¿ÒrŒ®·×»jÆï¤ç£¬îr×xGÏg`ZDHFË>‰pÙ£ó=G½ºÆLNEL’F7ð)‡ñçöä»+½)ÿ–Û?Lç?‹>¢ÞþáGTšÔlëÒ¬+G²¦`i„™Á@Êr!€…DDåãÏÏ×Û'`µ|Dcä!æa—“’i•7±Ë @ņ1C”@ÄU33”y)‡âY•Ëö-Øõ"Т’ÓT¹d_‰G€\¬ßG‹nïíý9×oöxÆþÜ ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆ¨/Ä.Éý˜þ \c¨/Ä.Éý˜þ \`WdÿCJ'ü¡ÿºÇ4f‹SÙ¨¾a&+îå¥#)5éŒZ´;¥\*ªRD1ùy€ùå±ê]õï&ƒðCßêØüdÔ»ëÞMà‡¿Õ±ê]õï&ƒðCßêØü¨z«Ö¶í©¦_רehµ„”\ì{GŠømÞ¬Áê.²‡û x"P0ù‰D|€sßõ.ú÷“Aø!ïõlz—}{É ü÷ú¶N忱z…Ó{FCCXëÕxË$|Ϭe¢TYªï“dTÎAÙÅDynp—“"™C´M¥ò¶–ªoiˆ§‘+m:[tÞ·Q±–iP~‚éÊ%&¡%€Éœ9ä Qó ­>«»kó’—ÿý¶ëx<5+vÖ¢·õ./Q¹vçf\e¤ eÝJǧ›Gq­‘w=«™Ñ@¦EC e@Æ€qÝÈs1Ò÷:náÓð‘4ÉÉjeZ»¡<±"î= ªF)¦·„£[€+C‰»S0€‰{@ùsú—}{É ü÷ú¶=K¾½äÐ~{ý[5­¢·¯I z+wAYªÉ™¼ «‚oÙ„PE ø‹zrdȬtIÀ"(€‚¢=ÆìöÍcB@m+½vmŽSÉß*›)Û ¶Ï!d£Pwñ&‰µU»„Þ¸oÞ‚E9™Ž%íärÎõ.ú÷“Aø!ïõlz—}{É ü÷ú¶jÙš#sìÝõjÙôùÚ”«*ä š„ÉæY«ëØÕ],d]6I×zÍÔ ˆD92†'šG²îÒkî–­›J´:ýñf,^³e)$ÑDÚ,5ç%ªtŒA9»J"`0ùrPã//Rï¯y4‚ÿVΫúŽç•!S“¼kw… òR¯Bv ´;¥GŒm®­b§õߨÚMEåÒÅPN³.ÊË`x¤ä\4xˆ8U4ÖLÀª‰œ@0}èÀþ:ʦ}E¯vUÏj½Š­Ïm ­‘fdáˆ*RlËÅîìUR¢Lq ˆ Îp(˜ –Jp;ÙÊŠ;_‘2 R–Žð `z×È3Ï×ûZÐÝ6vkN®—A#ø‰¤ÿ^¹pBàÊð"ÿ·¤ïôXÓÿoëßôä2ÕÊígwÇ´Aƒ þ»lÕ²eE¢¼"i&Pà¥)BW‚”È3—Ô»ëÞMà‡¿Õ°'øÈ©w×¼šÁ«cÔ»ëÞMà‡¿Õ°'ù]éOü¶Ùúg9üYó—Ô»ëÞMà‡¿Õ³ÀéK«.÷`À-6æÝ>¢ÈŠ¬Êª~°X©.šJ‰ŽTÔL¥P¼˜À `0‡odkñõNý²ÿ “ü€M~>©ß¢_ãap'øÆ0Æ0Æ0Æ0Æ0Æ0Æ0Æ0Æ0Æ0Æ0Æ0Æ0Æ0Æ0Æ0Æ0Æ0Æ0Æ0 A~!vOè„ÇðJãA~!vOè„ÇðJãÖÚ÷£Š{j-Ú>£8z…{Ñf_˜¥A¯ 6÷ Š`öˆ y™Ã/l̶É-wÐe]ÆÖ‰œ“¬+X©µvÖ³ÓTQe¤‡‡ÞrÉs¤&äÁì¸ä|‡M`1Œ`1Œ`1Œ`1Œ`1Œ`1Œ`1Œ`1Œ`1Œ`2¾Ñ,,‘úåº6½”Òù i #ŒËEtN½[Â@¦/Š$íHÜò=é˜ìË*¾˜£¯¤ ëšÔ¤·2n›Çɨ'rŠŠÈ8Qq8‰Œ>ÒÆTàùÀ\qjeucxÝ–ü¡ƒµ }Y²2ncùGâ%`DòœRAs~Ñ**ØQË+ øæ¾ê¹R}]{=?9 ™k¬cÞ“´ž¤§¦Ñ}¦„@ ':Þ|{;T#…ŸŒéúîÜ­VÅŽßØQvÙ!™ â} è4ÔPÚàCËï…EG¸{)zýEÙíT­±-ôtŽ¥‚³"ö7±>óÂmÎb þ°”C»ËÇ ÷lzºÙ­¢ZÔãd¡¯v”*Ω(¢NY.ª)ÈÜ1'kcòaT¢%Ñ O1¾¡¨cb:R¸QK));°¡ÖRÈeJæNa3ž:ë.èÂ*¬"¯`Ÿ¸Â7hyymüVÛsw3Ô2u8É ¢xns ÀF­,<0~¢JªDTô—H˜¼‘MÜ$ÞÀ"”ÁuMau•µ+WH§2Ñ RkÏLÁy>Œ.q S«á‚€P?/i¸äœr^Ñ«¢ÝX¬Ý2tŽEìï‹&I¬z2‹v¹pB ÚiŒo`"dhŒ K Ô·ÚÄ%*N.óAj“·•Û*é3ñQX‡: ËAt˜¤ &~ NóCƒ£å’=²Ü:z´×‰$Z–¨vÒ¦dE…R·H숻Žxç€çû3=ÒR—¡õ5µuÔŒókÃ˾%žZÔ»b#$ÉT•3fÑk•åKÂ2ФI#yL ÷äOYú¿G:ÞÚq5 rõÓ¦ ›þé/*Ù›s5jä¼€(RˬTŒS™>D¦ìöC{esÔ.ÍŸÓ:rÑ´ëÕ¨ùå«ëI,Éì‰Ùè¦A1ħ"*‰Ž(òœ¿ndm“s·kXn¥ªúîeüV½¬X* [ºTLôŸ >¾I¡Š<  ¤rHQW8—³ý[©]M©©];îk¶·r“!±kG Â:=á=^å²9ˆôˆ“ÉEGÆ™q €J>~a«aŸŒ¬;C$ ‹ÆÉ8óÛÞP7þ^9Îæbšk¨‰ÇÛi=°«y¶SJ„4ëud#ë‹32M$ثؙÔPŠ@\ü€r”œ”… ¯K ¾âvU‹U[õ„eVõVˆUãúë±Zy‡Œå4_LR¨“£(šÀ -Ü¡€ =æçݽnhúâWAÖ%m7 ¶%’‹Ž: ƒhôNDÔváUÔ!OÄP‰—Žãæð¯­TMDÐÞbujÈ †”yèé¹DÐuáW¨5Å]'%ånàûê~Ïçø9ñ¹5¥kkîæ¨Ñvm‡^n:ma)“q¨&º Äâpyˆ€ GÌ-¿Iêû“]þÔ}ü¾‰Œ®ý'¨_îMwûQ÷òøôž¡¹5ßíGßËàX˜ÊïÒz…þä×µ/Iêû“]þÔ}ü¾‰Œ®ý'¨_îMwûQ÷òøôž¡¹5ßíGßËàX˜ÊïÒz…þä×µ/Iêû“]þÔ}ü¾‰Œ®ý'¨_îMwûQ÷òøôž¡¹5ßíGßËàX˜ÊïÒz…þä×µ/Iêû“]þÔ}ü¾‰Œ®ý'¨_îMwûQ÷òøôž¡¹5ßíGßËàX˜ÊïÒz…þä×µ/Iêû“]þÔ}ü¾‰Œ®ý'¨_îMwûQ÷òøôž¡¹5ßíGßËàX™ÕilthQimÇ1®-…ñý`¤hpØß~?…Ùäý/ Ëíç<Iêû“]þÔ}ü¾x$Õ"h½=Tiph8Iœnãȃ… dž,C˜T*i»Œ7àí㌠+éÄQ6ÿ¥®dˆ*'O³%‽„ä'<ÿà2ÁÈ×ãêú!eþ6Ÿ‚`˜@Cü¹ûŒ íN?Fª¢Ñú6€ÝE_PÆN¶Ì^ _ŸÉBÏÁ¾Ðï7í>wݯQ¾áªÿù µqŒÕ:åë¥nsš†šÒÕ;èónŒláuATø]ºŽ…"ÂcÜbp>Ò‡ÅJ‰H*Àppàà8˜cņ¥S«µÑ¨@U!ã`ŒE4cF)$ÐÄSŸ"” nG»ËÏ‘çžr*Ó§>žØE>‚c¢5ãxÙ3Ï™¥WbD G’Š©‚]§0îã,L`B¤´–™™g1¨éošD³V>=0 M£UC…H¦LA4Ïþ± ÁGò€ç«P×ÔZuÚÑéÐÐ)º áÉ4LasÚ""ÔðÆ)Qð"(Oq¦kMq®Hñ={¯ëurȪ<h¤ƒL%2žKÞ '?<ñÜ?Ú9Ьim;IŸqj§jª„Ó£ëHÇB6näâp?*€ok´9|ÇÌ|ògŒ ý÷OzNRZnOIÐÞHO M(åÅu¢ª>¨UV1“P|Bü›Ÿh¥´CòS§~Ÿæä–šÑšùûç)‚+:uYdªª&pSɈ‰C€òãÈ2ÁÆR{SêËT ÍŸZU%áℌ{øfÎ5û$ŽA)>Àü³>,:‡TÛA‘m:Ò­.­Ê͘>ˆn¸7nQIÞAíL¥Àöy(A’ì`xVª%õ‹½6à !Â:V9m»ˆ|%JbrÇ–GË ´IQŠn]+C N*E+ŒûXG¸L€x|$<ùò^<üò{Œ4ÖŠÒ–97SsºŽœúMë¢>pýh6Æt«’°‹nÎñP"P?=ÀQ猕ÁÁAÖb›ÁVá˜ÄÆ3(‘»6-È‚”DD@‰¥DG€´G;ØÀcÀcÀcÀcÀcÀcÀcÀ€uø…Ù?¢Á+Œuø…Ù?¢Á+Œ î#ý´WûÊWü­óAæ|ˆÿG-þò•ÿ+|Ðx c c c c c c c c c ®ôâ¹üF_þ¤ç,L®ôâ¹üF_þ¤çÄÈ×ãêú!eþ6'ùZ%(…—¨B£Q]MeëWóM'’.¬‹n~Ϩ²_´¥]åä,¼c c c c ð¬·Ê5,ÍÉq¹ÁAàˆ7 9ZŠÜöx†îCìþÐÏw1×ݤê~Rº¤˜ˆˆFö„bKXž6’•ÏA*gfÑs‰’9tˆ~á:À<›ÊØ;‚Ë7¹WѺÇ`Ô«ñÌ&Ü»™lêî]ˆ°M?1›ªc˜;Žª= |ßyŽ(sZ!‡YW÷¨:ªú,F¹®<`A*J8CÑLøê™4Äo4!0x…/g!öf¦×÷ú–Ò¦Dì$·¬à'ô¦üQñ’äC»±R”åóò1@p>fvF»®Ù,7ÚäY£Å0ve@[ø‚ Ÿ‰Þ`ìî›·ž9àxû3™ åÔëz»kœ³.HGE:U'x(D€Ýæ “Úîã?³2ã3h‡Ýoí´îJQM 0:õ‰Ù†b¬ÿÓ{„ÿ‚ ˜§âˆð Q'w—FkIÍK^é§£k!¦*1’Hl…~."ºd+åt ©ÈíNáà;‘}¤Àþˆ¾Øºú.È6N÷^i>äÄ*1KÊ ›ÅDÿ€DƘMù8?ÉŸ“;#]× ì–ír,Ñâ˜;²ˆ -üAOÄï0vw MÛÏð<}™€÷–ɦÎj­¸ŒSº½1Û¬ÁÔeAQÄêî›MG¢¤»¥W†¨¨Šd9|4¼2_Dâ\·ëoôDï[›Mä³ÊƒckÈUÌ«…ªA *üï&7!À")Qÿì ¼¸À×LÞ4hƒö‘rÕÊeYÑ85S0rSÁäbˆyPúK¨rMLìJ®á¾R˜LÖïïké$rÆãDš³Q1* ®¡Î~÷'(‰L #Çftÿìû›‡˜é2Œ4ÃGéÅìqÁ»’­èþµ|4L #Ú ‰’óí1ì¦Ìé羬¨wßSËMNìÄ£« B9–‘TÑ Jص/+þ7waˆÉ€ÃÉ{D@6ÍšãQ¥1$ÊÓÍE"8“|“TŒq@ e #À—<ùeK¶7„¥néÖZ*¨P/kK¥,ñÙ81 Ú-wh®›Á\*bb&˜óùçÆTúù9Q¾(Ϻ’hÈZéX˜hɉ‡d+$æP7ÿL)Â`äàœG¸ tŠÐ‡5îË¢íJÛ]ÌÆb=û6ïˆfëTM5ÓSü$Œ%Á8€@@CÇa= sê?f2-æ©s^Í£“E¡àÚ‘&RNQxÿ”ÛÅ[ÒL˜vò`QA(û"%íí «¡y[1ÓN¾ xþ´âA•J¥„±FGÒ~›"B;ý¢ª*¡÷Ï1áÿn½+ºmóû~ͦu5Z ü•.-„ŒëùÙUZ šAS5l’i"©Ô*F9Ôò)JMÀDçwÖÕ‘ÑÒs4øûüè«,$›e”ydY¼\T#³"•?û±GÛn%îà,†n`é£`íû©¬›AM5´µÑY°okcdJ1óÖk2IÚfnÇm€Î ‘ˆrDS1@Åä2/¸V:DsÔ³ˆ6¶‰+k§r¬¥ÓE¨¸n dlíFªñáø¡èÆí€E@ <á­[*·8ᘧÙb§X†D]F½MÒ  —½1÷róæÒÙîÒýÜUbû\—{C(í³ D*Ü¥7iŒ¡aÈD@8,Ê5 …›|ë58XûXC‘R­å4•xTëè‘Úd"^d1—På(˜ªwrpã"ôËÖ½s¼ºl|ß`kõ«Ä¤X¡Ñk=‘ñhz$p¡£••9—T¥"‚Cû‘ãÈm¦wúƒ–ŒãîÐ.\?Ñ$d‘9ÜxÂþ@ÜŸÃãÛãžßËÆ}Ö/4›¨:56ã< NTÝ d‚.¼<þ‡´Gà°sùÝ K³ti°¥5¼|$ÄÜNÃ’s2xdP}$Ú¼k ¢¹!{ŽTNÄ$^ ¢FX 0ÚgZ¹Âì]› º‚KalEuDœ$k8²($qT@Ç+Bc’("$P@à*(_#v…¥¸ú†R«³õ>ƒ°hÒAc¹¡X°Áû.e[¦vîU2å2nCÁJt æ¡}¢þ ¸Ã¨}ÆöǵkPZJ®ýΪY©—îÝtÏ"EÙ&ôž o @Ó˜¼8îãÛÊFŵúz•¤ô³«­uÄYÀìXBºEdÒZ#ˆ¹7„ò3uEQàAP)Ž`0‡w9õê47nÝêÆ¿¬w:ìç%Xö’­ÌŒ§…Õ#¦¸S#㣨d”LJ&1{Šl ÂßÕi™tÕ^êfFBvp"Ì£ 9cƸn¢Ð€Fë”æ"Ë€ðC´†‰¼€gÐ×¶7ØÚ­«WÁµˆ}íÚÓ1e_ƒ%’2@’+"«$<`QQ!Ša¼>ÌÉû›tiëÏýž‘HAËÖ+K*¥E‹ŠË9Ú«é†å‘RïR|%‡ÏƒþA³”Üý0tùa°^î¶óéÚ#Ò"k,ÊŒÂ1³×a]Õ«Þ œ+…(}ðx ÜRlõ6ë§Õ+ª¤È#3 ñW”žK6" »`BñÀ™&ÎÛ(&îû|Bˆr\ììmÍ~¨nzn¢¯kªü¸]ØJ¾c"öγ/ ÕåneˆªDb·úI;§7</—9fVmšë§Sv¥nNN—>–ÆZ ‘Aó·«ò¬Q}ãŽC"åÒ$ w);@¡Å‰²7~œ”꟧»ƒM§Ta¬[Ý™éæ‘$’r”w€e c‡gb€^î9Ì£À[P{ÊÀîë'§l´høŽ„PÎDÇ­6ebf˜‚ž•Aù[x€$?’„;`P½Å0Åàèt›ÔÂ]NÐZÝÓMQ˜p‚o!O  šZ"í¢à§†Ÿ$U ˜=€óŸåròÍZÚÝWV7¥nÂÜš×RÕe‘”·ª¸#õãáL…nƒ“ð›‚&™Cª™Œ˜¦ÝÃÆRTÔìP•] ãT./Øu« µ¬Û¸ÕÊ¡be˜³HLôâàE¤ËÛæ`;R€€pl /£:¨´ïÛFɃ©jè¦lé&iê·Ï쪓×I=Ld¸Œèé*ØA^îå;ˆS‰‹õ­ú‹Ü[3PÔ·,Œ¯­kQ‘‰…ÑcÈ"Ýg%EUA3G5ÅEŒ_9"FàyòÈON× aWꇩö­®Èøˆ£ÔÁ.é4HŠ C"ÝQî1ø$§jG08L #ÆV+Yº~¢t×§¶¬þàçhÑNŸ¹®°](éE[¹oà#»Ÿ ~ü^ÂGÌÈ +¨/Ä.Éý˜þ \c¨/Ä.Éý˜þ \`Sµ …¦í:k*ùz£Wåáá믈¢òìÕ2Z ‰ûDË¢QÏ{éQ‡ç§ª¿Waüî1€úTaùéê¯ÕØ;¥Fžžªý]‡ó¸ÆéQ‡ç§ª¿Waüî>•~zz«õvÎã¥Fžžªý]‡ó¸úTaùéê¯ÕØ;Œ`>•~zz«õvÎãéQ‡ç§ª¿Waüî1€úTaùéê¯ÕØ;¥Fžžªý]‡ó¸ÆéQ‡ç§ª¿Waüî>•~zz«õvÎã¥Fžžªý]‡ó¸úTaùéê¯ÕØ;Œ`>•~zz«õvÎãéQ‡ç§ª¿Waüî1€úTaùéê¯ÕØ;¥Fžžªý]‡ó¸ÆéQ‡ç§ª¿WaüîH5ÖÑÐô*{²AÐä”juÕU٧إ⨲ÇXâD ÊÈðyã÷=« n‘†[© ô:>1UUXk£FN(€¦+Nò”yäD‚SrÁƒÏŸº†Îénƒ•r´µ¼\zG2¾66|¨¡‡“ª¡…Q2Š|Ìsˆ˜Ãæ"#çŒ`{_X- ﺃñ+/™¬…÷ÝAø•—ÌÆ0X- ﺃñ+/™¬…÷ÝAø•—ÌÆ0X- ﺃñ+/™¬…÷ÝAø•—ÌÆ0X- ﺃñ+/™¬…÷ÝAø•—ÌÆ0X- ﺃñ+/™¬…÷ÝAø•—ÌÆ0X- ﺃñ+/™Ÿ„ßú 24÷^¿)J(Yä¾c¿X- ﺃñ+/™¬…÷ÝAø•—ÌÆ0X- ﺃñ+/™¬…÷ÝAø•—ÌÆ0X- ﺃñ+/™¬…÷ÝAø•—ÌÆ0>Tߺbxjî­~rˆ€ðk!!ä?úŸÛŸ_X- ﺃñ+/™Œ`>°ZßuâV_3X- ﺃñ+/™Œ`>°ZßuâV_3X- ﺃñ+/™Œ`p/¼úwtº\îtªÍ„E°±1’ã‘(Šœ—žìþÌçúÁh_}Ô‰Y|Ìcõ‚оû¨?²ù˜úÁh_}Ô‰Y|Ìcõ‚оû¨?²ù™òžýÐ)J–ê×ä(˜L [ DDDñ>ÑöŽ1€&ýÐ)‰…=Õ¯Ê'7q¸±²áþÑûç˜ùg×Ö Bûî üJËæc…ßú¢cuëð&²2ó8ä~ùý€ÿë?~°ZßuâV_3À}`´/¾êĬ¾f>°ZßuâV_3À}`´/¾êĬ¾f>°ZßuâV_3À}`´/¾êĬ¾f>°ZßuâV_3Àƒïmí¤$4†Ã`ÃrQœºsU–E°³:ЍfjJR‚œ˜Â"b#ŒcÿÙbobcat-5.09.01/documentation/overrides0000644000175000017500000000054014050437223016701 0ustar frankfrankhmacbuf/hmacbuf randbuf/randbuf digestbuf/digestbuf ohexbuf/ohexbuf multibuf/multibuf xsputn ofdbuf/ofdbuf tablebuf/tablebuf iobuf/iobuf xsputn ifdbuf/ifdbuf xsgetn sharedbuf/sharedbuf xsputn decryptbuf/decryptbuf ofoldbuf/ofoldbuf syslogbuf/syslogbuf readlinebuf/readlinebuf ifilterbuf/ifilterbuf encryptbuf/encryptbuf bobcat-5.09.01/documentation/esr.html0000644000175000017500000036331614050437223016450 0ustar frankfrank Time, Clock, and Calendar Programming In C

Motivation

The C/Unix time- and date-handling API is a confusing jungle full of the corpses of failed experiments and various other traps for the unwary, many of them resulting from design decisions that may have been defensible when the originals were written but appear at best puzzling today.

The purpose of this document is to help C programmers develop a clear mental model of how it all works so they can step lightly over the corpses and avoid the traps. In the process it also explains, historically, why things are the way they are - because in this case it’s much easier to understand the mess we’re in when you know how it got that way.

This document is intended to supplement rather than replace your system manual pages. Accordingly, some details - notably, feature macros you might have to enable for certain functions to be visible to your program - are omitted. Our hope is that this document will enable you to read the relevant Unix manual pages with better understanding and less tendency to feel smothered under details.

Scope

The functions we will cover are the following:

int adjtimex(struct timex *);
int adjtime(const struct timeval *, struct timeval *);
unsigned int alarm(unsigned int);
char *asctime(const struct tm *);
char *asctime_r(const struct tm *, char *);
clock_t clock(void);
int clock_getres(clockid_t, struct timespec *);
int clock_gettime(clockid_t, struct timespec *);
int clock_settime(clockid_t, const struct timespec *);
char *ctime(const time_t *);
char *ctime_r(const time_t *, char *);
char *ctime_rz(timezone_t restrict tz, const time_t *clock, char *buf)
int ftime(struct timeb *tp);
double difftime(time_t, time_t);
struct tm *getdate(const char *);
int gettimeofday(struct timeval *tv, struct timezone *tz);
struct tm *gmtime(const time_t *);
struct tm *gmtime_r(const time_t *, struct tm *);
struct tm *localtime(const time_t *);
struct tm *localtime_r(const time_t *, struct tm *);
struct tm *localtime_rz(timezone_t tz, const time_t * restrict clock, struct tm *result);
time_t mktime(struct tm *);
time_t mktime_z(timezone_t, struct tm *);
int nanosleep(const struct timespec *, struct timespec *);
int settimeofday(const struct timeval *tv, const struct timezone *tz);
unsigned int sleep(unsigned int);
size_t strftime(char *, size_t, const char *, const struct tm *);
char *strptime(const char *, const char *, struct tm *);
time_t time(time_t *);
time_t timegm(struct tm *tm);
time_t timelocal(struct tm *tm);
int timer_create(clockid_t, struct sigevent *, timer_t *);
int timer_delete(timer_t);
int timer_gettime(timer_t, struct itimerspec *);
int timer_getoverrun(timer_t);
int timer_settime(timer_t, int, const struct itimerspec *, struct itimerspec *);
void tzset(void);
useconds_t ualarm(useconds_t, useconds_t);
int usleep(useconds_t);
timezone_t tzalloc(const char *zone);
void tzfree(timezone_t restrict tz);
const char *tzgetname(timezone_t restrict tz, int isdst);
long tzgetgmtoff(timezone_t restrict tz, int isdst);

Most of these functions are declared in the system header time.h and are portable across all modern Unix-like systems. Exceptions to this general rule will be noted.

The following summary table may prove useful as a quick reference:

Table 1. Summary of functions
Function name Group Data structure #include Standard Obsoleted Removed Replacement

sleep

Delay

int seconds

unistd.h

POSIX.1-1988

usleep

Delay

useconds_t

unistd.h

SUSv1

POSIX-1.2001

POSIX.1-2008

nanosleep

nanosleep

Delay

struct timespec

time.h

POSIX.1b-1993

alarm

Delay

int seconds

unistd.h

POSIX.1-1998

ualarm

Delay

useconds_t

unistd.h

SUSv1

POSIX.1-2001

POSIX.1-2008

timer_settime

getitimer

Delay

struct itimerval

sys/time.h

SUSv1

POSIX.1-2008

timer_gettime

setitimer

Delay

struct itimerval

sys/time.h

POSIX.1b-1993

POSIX.1-2008

timer_settime

timer_create

Delay

timer_t

time.h

POSIX.1b-1993

timer_delete

Delay

timer_t

time.h

POSIX.1b-1993

timer_getoverrun

Delay

timer_t

time.h

POSIX.1b-1993

timer_gettime

Delay

timer_t

time.h

POSIX.1b-1993

timer_settime

Delay

timer_t

time.h

POSIX.1b-1993

timerfd_create

Delay

sys/timerfd.h

Linux only

timerfd_settime

Delay

struct itimerspec

sys/timerfd.h

Linux only

timerfd_gettime

Delay

struct itimerspec

sys/timerfd.h

Linux only

time

Clock

time_t

time.h

POSIX.1-1988

difftime

Clock

time_t

time.h

C89

clock

Clock

clock_t

time.h

C89

gettimeofday

Clock

struct timeval

sys/time.h

SUSv1

POSIX.1-2008

clock_gettime

settimeofday

Clock

struct timeval

sys/time.h

4.3BSD/SVr4

clock_settime

clock_gettime

Clock

struct timespec

time.h

POSIX.1b-1993

clock_settime

Clock

struct timespec

time.h

POSIX.1b-1993

clock_getres

Clock

struct timespec

time.h

POSIX.1b-1993

tzset

Date

time.h

POSIX.1-1998

ftime

Date

struct timeb

time.h

SUSv1

POSIX.1-2001

POSIX.1-2008

clock_gettime

gmtime

Date

struct tm, time_t

time.h

POSIX.1-1988

gmtime_r

Date

struct tm, time_t

time.h

POSIX.1c-1995

gmtime_rz

Date

struct tm, time_t,timezone_t

time.h

4.xBSD

localtime

Date

struct tm, time_t

time.h

POSIX.1-1988

localtime_r

Date

struct tm, time_t

time.h

POSIX.1c-1995

gmtime_rz

Date

struct tm, time_t,timezone_t

time.h

4.xBSD

mktime

Date

struct tm

time.h

POSIX.1-1988

mktime_rz

Date

struct tm, time_t,timezone_t

time.h

4.xBSD

timelocal

Date

struct tm

time.h

GNU only

timegm

Date

struct tm

time.h

GNU only

asctime

Date

struct tm

time.h

POSIX.1-1988

POSIX.1-2008

strftime

asctime_r

Date

struct tm

time.h

POSIX.1c-1995

POSIX.1-2008

strftime

ctime

Date

time_t

time.h

POSIX.1-1988

POSIX.1-2008

strftime

ctime_r

Date

time_t

time.h

POSIX.1c-1995

POSIX.1-2008

strftime

strftime

Date

struct tm

time.h

POSIX.1-1988

strptime

Date

struct tm

time.h

SUSv1

getdate

Date

struct tm

time.h

SUSv1

getdate_r

Date

struct tm

time.h

GNU only

tzalloc

Date

timezone_t

time.h

4.xBSD

tzfree

Date

timezone_t

time.h

4.xBSD

tzgetname

Date

timezone_t

time.h

4.xBSD

tzgetgmtoff

Date

timezone_t

time.h

4.xBSD

The "Standards" column shows the oldest standard that describes the call, otherwise the earliest (non-standardized) implementation. Some relevant abbreviations:

Table 2. Standards and origins

C89

ANSI X3.159-1989 "Programming Language C."

POSIX

IEEE 1003, aka ISO/IEC 9945. Development began in 1988, with significant revisions in 1996, 2001, and 2008.

SUS

Single UNIX Specification. Merged with POSIX in 2001.

GNU

Unstandardized calls in the very widely used GNU C Library.

4.xBSD

The 4.2 (1983) and 4.3 (1986) versions of BSD Unix invented some API elements still in occasional use.

SVr4

System V Release 4 (1988). Basis for later Unix standards.

A manual page reference with the section part "(2|3)" means you may find pages with the identified name in both sections 2 or 3; usually this happens because there is both native system-call documentation in section 2 and a POSIX page in Section 3.

Unix time and UTC/GMT/Zulu

Internally, Unix time is represented as SI (Système International) seconds since midnight of January 1st 1970 at the Greenwich meridian, without leap-second correction. This is time counted in seconds as though it had been incremented every second in constant-length days of 86400 seconds each since then.

This is sometimes described as "UTC time" or "UTC seconds" because it is based on the same zero meridian and uses the same SI second as Coordinated Universal Time (abbreviated UTC to be neutral between this and the French 'Temps Universel Coordonné'
[It has been alleged that "CUT" was avoided in part because it sounds like a rude word in Dutch]
), the modern standard [UTC].

The detailed history of UTC and its antecedents is out of scope for this document (a summary is as [TIMESCALES]), but a few points about it are relevant. One is that leap seconds were not introduced into UTC until 1972. Another is that UTC was then and still is occasionally confused with a previous international time standard, Greenwich Mean Time (GMT) [GMT]. This is why one of the principal Unix time functions is named gmtime(3).

There is one subtle but important difference between Unix UTC and the official UTC standard time. Official UTC time is by definition solar calendar time (year/month/day/hour/minute/second) rather than a seconds counter from an epoch like Unix UTC time. The difference becomes, as we shall shortly see, significant near leap seconds. But the relationship with solar UTC time remains close, and in the rest of this document we shall continue to speak of Unix UTC.

In U.S. military usage dating back to WWII GMT/UTC is referred to as "Zulu" time; the word "Zulu" means nothing in this context but was chosen to abbreviate to "Z" in order to avoid colliding with any existing timezone designation. Use of the "Zulu" designation spread to international aviation and has left a mark on the ISO-8601 international standard for representing calendar time and date, which uses Z as a suffix to indicate UTC rather than local time. Thus, the Unix epoch (zero second) is formally represented as 1970-01-01T00:00:00Z.

The standard Unix type for holding this UTC/GMT/Zulu seconds counter is time_t. It is integral and signed, and negative values designate seconds before 1970-01-01T00:00:00Z. The current time_t value is returned by the time(3) function. (Note that ANSI C allows for time_t to be a float value, but this choice seems never to have been made in a real operating system
[It is rumored that early versions of BeOS used float time, but the experiment was quickly abandoned.]
and is excluded in later POSIX revisions. There have been a few approximately Unix-like systems on which time_t was unsigned and could not represent dates before 1970, notably QNX.)

The absence of leap-second correction means that occasionally, in order to stay synchronized with solar time, the Unix time counter has to skip or duplicate a second when it crosses UTC midnight during a leap-second insertion or deletion. A very detailed explanation of these discontinuities can be found at the Wikipedia page on Unix time [UNIX-TIME]. The rationale for excluding leap-seconds can be found at [POSIX-TIME].footnote[Note however that one major assertion in [POSIX-TIME], "most systems are probably not synchronized to any standard time", is now incorrect; synchronization to Internet time via NTP became routine within a few years after it was written in 1996.]

In practice, almost the only way these discontinuities could be an issue is if you are computing with differences in timestamps taken on opposite sides of one or more leap-second insertion or deletions. In that case actual elapsed time could be a second or more different than the result of subtracting the older Unix timestamp from the newer.

Unix time and NTP correction

Most Unix systems rely on Network Time Protocol servers to correct their timebase so that the computer’s top-of-second closely matches that of atomic-clock UTC time - usually as defined by the U.S. Naval observatory, but there are other national time authorities which all try to stay in synchronization with each other.

Periodic NTP adjustments are required because the clock oscillators in individual computers are subject to frequency drift due to thermal and other physical effects.

A detailed description of the adjustment process is beyond the scope of this document. The main thing for programmers to know is that NTP almost always tells your local clock to resynchronize by minutely speeding it up or slowing it down until it matches NTP time (rather than skipping or inserting clock increments). In rare situations, like after prolonged network outages or CPU sleep periods, NTP may skip or repeat clock increments.

Thus, in the presence of NTP correction, Unix seconds are of slightly variable width in real time. The maximum divergence is very small (at most a few microseconds) and the typical variation is smaller than that.

Thus, the variability should have no effect except in hard real-time situations. In those, you shouldn’t be using an NTP-corrected clock but a native monotonic timer designed for real-time use; we’ll see later that the time API provides flexible ways to do this.

Unix kernels have provided NTP with a system call to use in adjusting clock frequency since 4.3BSD; it is adjtime(3). This call is not formally standardized. There is a native Linux variant, adjtimex(2). These are both intended solely for NTP’s use, and that is all we will have to say about them in this document.

Unix time and machine word length

During the evolution of the Unix time API from 1968 onwards, typical machine word lengths have changed twice - from 16 to 32 and then to 64 bits, which is typical today (in 2017) and seems unlikely to change in the foreseeable future.

The changes in word lengths have left some scars in the Unix API. At the very beginning time_t was defined as a signed 32-bit quantity, so it couldn’t be held in the 18-bit registers of the PDP-7 or the 16-bit registers of the later PDP-11. This is why many of the Unix time calls take a pointer to time_t rather than a time_t; by passing the address of a 32-bit span in memory the design could get around the narrowness of the register width. This interface glitch was not fixed when word lengths went to 32 bits.

A more serious problem is that 32-bit Unix time_t counters will turn over just after 2038-01-19T03:14:07Z. This is expected to cause problems for embedded Unix systems; it is difficult to anticipate their magnitude, but we can only hope the event will be the same sort of damp squib that the Year 2000 rollover turned out to be.

Modern Unix systems use a signed 64-bit time_t. These counters will turn over approximately 292 billion years from now, at 15:30:08 on Sunday, 4 December 292,277,026,596. No problems with this are presently anticipated.

Register length limits have also affected the representation of time at subsecond precision. As a workaround against them, and to avoid floating-point roundoff and comparison issues, the C API traditionally avoided representing fractional-second times as a scalar float or double quantity. The reason had to do with the precision offered by different float formats:

Table 3. Float precision
Word size Mantissa Exponent Historical name

32-bit float

23

8

Single precision

64-bit float

52

11

Double precision

128-bit float

112

15

Quad precision

(The sums look off-by-one because of the sign bit. You can learn more about the IEEE754 floating-point formats that give rise to these numbers at [FP]. They originated on the VAXen that were the workhorse machines of Unix in the early 1980s and are now implemented in hardware on Intel and ARM architectures, among many other places.)

When the Unix time API first had to represent subsecond precision, microsecond resolution was required to represent times comparable to a machine cycle.

The problem was that a microsecond count requires 20 bits. A microsecond-precision time with 32 bits of integer part is on the far edge of what a double-precision float can hold:

seconds:       32 bits
microseconds:  20 bits
               --------
total:         52 bits

That would barely have fit and seemed likely to be a bit flaky in actual use due to floating point rounding. Doing any math with it would lose precision quickly. Trying to go finer-grained to nanosecond resolution would have required 11 more bits that weren’t there in double precision.

Thus, quad-precision floating point would have been required for even 32-bit times. Given the high cost of FPU computation at the time and the near-waste of 64 bits of expensive storage, this took float representation out of the running.

This is why fractional times are normally represented by two-element structures in which the first member is seconds since the epoch and the second is an integral offset in sub-second units - originally microseconds.

The original subsecond-precision time structure was associated with the gettimeofday(2) system call in 4.2BSD Unix, dating from the 1980s. It looks like this:

struct timeval {
   time_t      tv_sec;     /* seconds */
   suseconds_t tv_usec;    /* microseconds */
};

Note the microsecond resolution. The newer POSIX time functions use this:

struct timespec {
   time_t      tv_sec;     /* seconds */
   long        tv_nsec;    /* nanoseconds */
};

(No, that’s not a paste error. The struct timespec members really do have tv_ prefixes on their names. This seems to have been someone’s attempt to reduces required code changes. It was probably a bad idea.)

This has nanosecond resolution. The change is related to the tremendous increase in machine speeds since the 1980s, and the correspondingly increased resolution of hardware clocks. While it is conceivable that in the future we may see further generations of these structures in which the subsecond offset is in picoseconds or smaller units, some breakthrough in fundamental physics would be required first - at time of writing in 2014 processor cycle times seem to be topping out in the roughly 0.1ns range due to quantum-mechanical limits on the construction of electron logic.

Although the timeval and timespec structures are very useful for manipulating high-precision timestamps, there are unfortunately no standard functions for performing even the most basic arithmetic on them, so you’re often left to roll your own.

Another structure, used for interval timers and describing a time interval with nanosecond precision, looks like this:

struct itimerspec
{
    struct timespec it_interval;
    struct timespec it_value;
};

While the C time API tends to shape the time APIs presented by higher-level languages implemented in C, these subsecond-precision structures are one area where signs of revolt are visible. Python has chosen to instead accept the minor problems of using a floating-point scalar representation; Ruby uses integral nanoseconds since the Unix epoch. Perl uses a mixture, a BSD-like seconds/microseconds pair in some functions and floating-point time since the Unix epoch in others.

On today’s true 64-bit machines with relatively inexpensive floating point the natural float representation of time would look like this:

seconds:            64 bits
fractional seconds: 48 bits
                    --------
total:              112 bits

offering sub-picosecond resolution with plenty of headroom to avoid serious roundoff issues. So the scripting languages are heading in a direction that the C API could in theory eventually follow.

Delay and interval-timing functions

The simplest portions of the Unix time API are clock and delay functions that only deal with the basic second- and fractional-second-oriented time structures.

First we’ll survey the delay and interval-timing functions, then the clock functions. If you are mainly interested in clock/calendar/timezone issues, you can safely skip this section.

sleep(3), usleep(3), and nanosleep(3)

#include <unistd.h>

unsigned int sleep(unsigned int seconds);
int usleep(useconds_t usec);

#include <time.h>

int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);

These functions are the poster children for the mess created by having multiple time representations. All three simply delay execution of the calling program for some span of time; what differs is how that time is specified.

The oldest, sleep(3), takes an integer argument in seconds; usleep(3) takes microseconds, and nanosleep(3) takes a struct timespec with nanosecond resolution. All three may be interrupted by an unignored signal. The nanosleep(2) function takes a second timespec which is filled with time remaining if it was interrupted.

The usleep(3) call originated in BSD Unix and, though it was carried forward in POSIX, was deprecated in favor of nanosleep(2) in POSIX.1-2001/SUSv3 and then removed entirely in POSIX.1-2008/SUSv4. It’s probably best not to count on it being portable.

Of these three functions, only nanosleep(3) is guaranteed not to have any interaction with signals (the other two may be implemented using some signal and a hidden handler). It is is thread- and signal-safe.

The sleep(3) function is required by POSIX to be async-signal-safe and thread-safe. The thread-safe requirement means sleep(3) can’t be signal-based in multithreaded programs, but can be in single-threaded programs.

These functions should not be mixed with the ones in the next group.

alarm(2|3), ualarm(3), getitimer(2|3), and setitimer(2|3)

#include <unistd.h>

unsigned alarm(unsigned seconds);
useconds_t ualarm(useconds_t usecs, useconds_t interval);

#include <sys/time.h>

int getitimer(int which, struct itimerval *value);
int setitimer(int which, const struct itimerval *restrict value,
              struct itimerval *restrict ovalue);

The alarm functions are another case of call proliferation due to multiple time units. The oldest, alarm(2|3), sends SIGALRM after a specified number of seconds; ualarm(3) sends SIGALRM after a specified number of microseconds (and a second argument, if nonzero, causes SIGALRM to be sent at regular intervals afterwards).

The getitimer() and setitimer() functions come from the Single UNIX Specification before 1996, when SUSv2 was merged with POSIX.1-1996 to develop POSIX.1-2001/SUSv3. They are now deprecated in favor of the POSIX timer_* calls in the next section.

These have three advantages over the traditional alarm calls: (1) they use timeval structures, so have microsecond resolution; (2) they can trigger the sending not just of SIGALRM but of more specialized profiling signals; and (3) they give you options about what derivative of the system hardware clock you want to use.

The gory details about the interval timer functions are best learned from their manual pages. For our purposes, the important thing to cover is how they fit with the rest of the time and calendar API. Bluntly, that is not very well.

The manual pages are full of ominous "unspecified behavior" warnings if you mix uses of the sleep group, the alarm group, and the itimer group in the same program. The reason for this is historical.

The sleep and alarm function groups developed by accretion in early Unixes. The sleep(3) group was often implemented with alarm(3) and a specialized SIGALRM handler; likewise for usleep(3) and ualarm(3).

The itimer functions were the result of a later effort to specify a more general facility that could subsume these, starting from a clean sheet of paper. They were declared obsolete in POSIX.1-2001/SUSv3 in favor of the timer_* group.

Thus, it is possible that your system’s implementation of sleep and alarm functions is a thin layer over POSIX itimer calls (or, possibly, the timer_* group documented next) using the ITIMER_REAL clock. When that isn’t the case, legacy implementations of the sleep and alarm calls won’t necessarily play well with interval timers - in particular SIGALRMs might be flying around when you don’t expect it, or setting an implied signal handler through the sleep functions might be interfered with by setitimer(2|3).

It’s best not to go there. Heed the warnings and don’t mix up these function groups.

The POSIX timer_* group

#include <signal.h>
#include <time.h>

int timer_create(clockid_t clockid, struct sigevent *restrict evp,
                 timer_t *restrict timerid);
int timer_delete(timer_t timerid);
int timer_getoverrun(timer_t timerid);
int timer_gettime(timer_t timerid, struct itimerspec *value);
int timer_settime(timer_t timerid, int flags,
                  const struct itimerspec *restrict value,
                  struct itimerspec *restrict ovalue);

There is a group of POSIX functions timer_create(2|3), timer_delete(2|3), timer_settime(2|3), timer_gettime(2|3), and timer_getoverrun(2|3) that can be used to set per-process interval timers even more flexibly than the itimer group. In particular, they allow setting a function-call hook to be called directly at the end of an interval without going through either an explicit or implicit signal.

These functions were introduced in POSIX.1b-1993. After POSIX and SUSv2 merged in 2001 getitimer(2|3) and setitimer(2|3) were declared obsolete.

Neither the native Linux nor POSIX man pages document interactions with the older calls. A prudent programmer should assume that the alarm and sleep group is implemented in terms of one of the two groups of newer POSIX interval-timer functions, and not mix any of them.

If you want to avoid interval variability due to NTP frequency adjustments, you probably want to use these with CLOCK_MONOTONIC.

The Linux timerfd_* group

#include <sys/timerfd.h>

int timerfd_create(int clockid, int flags);
int timerfd_settime(int fd, int flags,
               const struct itimerspec *new_value,
               struct itimerspec *old_value);
int timerfd_gettime(int fd, struct itimerspec *curr_value);

These functions are Linux-specific (not standardized), offering a way to monitor timer expiration via selecting or polling on a file descriptor rather than via signal handler.

They are mentioned here for completeness, but should be avoided in code intended for portability. Consult the Linux manual pages for details.

A full discussion of the select(2) and pselect(2) system calls would be beyond the scope of this document, as they are not used for time/calendar programming. We mention them only to note two points:

  1. select(2) takes a struct timeval argument, reflecting its origins in BSD Unix. The resolution to which you can specify a timeout is thus limited to a microsecond.

  2. The later pselect(2) call takes a struct timespec.

Clock and time-of-day functions

These are functions for interacting with the system clock that avoid timezone issues by returning time in seconds since the Unix epoch.

time(3)

#include <time.h>

time_t time(time_t *tloc);

The most basic function is time(3), which returns the current Unix second. All the previous caveats about leap-second discontinuities and tiny variabilities due to NTP correction apply.

difftime(3)

#include <time.h>

double difftime(time_t time1, time_t time0);

The function difftime(3) attempts to return the elapsed time between two time_t counters as a double - however, it is not aware of leap-second discontinuities (a fact the man page does not document!).

This call was added in C89 as a way to encapsulate time arithmetic on operating systems where time_t is not a normally encoded integral or float type; it is possible (even likely) that no such environments actually exist.

While on POSIX systems where time_t is required to be an integral type holding a count of seconds it might appear equivalent to just subtracting the first argument from the second, it is not quite superfluous. It is defined to handle correctly some edge cases where naive subtraction would cause an integer overflow.

clock(3)

#include <time.h>

clock_t clock(void);

We mention the function clock(3) here only for completeness, because it is declared in time.h. It is little used, returning an approximation of processor time used by the running program. This return is not a time_t, but an integer in microseconds * CLOCKS_PER_SEC (the latter being a constant in <time.h>)

This function is very portable, but you probably want the finer-grained statistics from getrusage(2) instead.

gettimeofday(2|3)/settimeofday(2)

#include <sys/time.h>

int gettimeofday(struct timeval *restrict tp, void *restrict tzp);
int settimeofday(const struct timeval *tv, const struct timezone *tz);

This is the two oldest Unix interface that deals with subsecond time, dating from 4.2BSD (the other being ftime(3)). With it you can get time since the epoch to microsecond precision (it uses a struct timeval, not the newer struct timespec), or (with root permissions) set the system clock to microsecond precision.

Though restricted versions were carried forward in POSIX, these calls are obsolete, and are documented here mainly so you’ll understand how they fit in when reading old code. It is best to use clock_gettime(2) and clock_settime(2) (which support nanosecond precision) instead of these.

(Some systems may still require you to use gettimeofday(3); notably this is true of Mac OS X up to and including 10.9.5 Mavericks, which conforms to POSIX.1-2001/SUSv3 rather than the POSIX.1-2008/SuSv4 in which clock_gettime(3) became mandatory.)

In the POSIX documentation, behavior if the gettimeofday(3) historical second argument is non-null is undefined. The Linux native gettimeofday(2) (and possibly other implementations) attempts to preserve more of the original BSD semantics, returning some timezone-related information; however, this feature is marked obsolete and should not be relied on.

The settimeofday(2) call was never standardized at all, though it was carried forward in System V Release 4 and de-facto standard for some time.

clock_gettime(2), clock_settime(2), clock_getres(2)

#include <time.h>

int clock_getres(clockid_t clk_id, struct timespec *res);
int clock_gettime(clockid_t clk_id, struct timespec *tp);
int clock_settime(clockid_t clk_id, const struct timespec *tp);

These are the modern, POSIX-standardized functions for interacting with the system clock at subsecond precision. They use the nanosecond-precision struct timespec and allow working with multiple clocks.

The most interesting (and only portable) clocks are identified as CLOCK_REALTIME and CLOCK_MONOTONIC. CLOCK_REALTIME is the familiar UNIX time since the epoch, with leapsecond discontinuities and NTP adjustments. CLOCK_MONOTONIC is a monotonically increasing nanoseconds and seconds counter that cannot be set; note that unlike an interval timer it is subject to leapsecond discontinuities and NTP adjustments.

The call clock_getres(2) is available to query the actual resolution of the system clock.

Date and timezone-aware functions

Now we come to the part that is the most interesting to application programmers and (probably) the most confusing. Unfortunately, most of the difficulties here cannot readily be solved in software.

The calendaring parts are not problematic. The Unix time API supports the Gregorian calendar, which is well standardized and now in sufficiently universal use worldwide that any conversion problems to local standards can be handled locally.

The real difficulties arise from timezones, especially when a program must deal with or report times from a zone other than the one configured as local on the machine where it is running.

The tragedy of timezones

Before the mid-19th century, clocks were set (more or less haphazardly) to indicate local solar time. The goal was essentially for noon to coincide with the average time of the Sun’s maximum declination. Humans moving by foot, horse, or ship did not move quickly enough to make time synchronization between regions with different mean solar times a problem (with a very limited technical exception for marine navigation).

The impetus for standard time came from rail travel. The railroads needed standardized time in order to set and publish precise schedules
[In the mid-19th-century British clocks were sometimes made with two sets of hands, one for mean solar time and the other for railroad time.]
. While there were significant commercial advantages to adopting railroad time as a civil standard wherever it reached, human beings did not want to give up rough synchronization of their clocks and watches to local mean solar time.

Time zones developed as a compromise. By partitioning the globe into hour-wide longitudinal bands with a fixed time offset from one world reference time, two desirable properties could be achieved. First, rough synchronization with mean solar time would be maintained everywhere. Second, the relationship between standard time and any local time would remain easy to compute.

The actual time zone system never approximated this ideal very closely. Adoption was slow and patchy after the development of the first railroad standard time system (in 1847 in Great Britain) and was not roughly complete until the early 20th century.

From the beginning, various time authorities showed a tendency to move timezone borders to avoid putting regions they were closely tied to off into a different timezone, even if that meant accepting large clock deviations from mean solar time in outlying regions. Some regions adopted half-hour or even quarter-hour offsets. These meant, unhappily for computer programs and programmers, that the time offset of a location is not a simple function of its longitude.

Worse, the time zone system has been unstable over time as the political and commercial pressures on it resulted in frequent changes to the definitions of zones. And still worse than that was the partial and unstable adoption of Daylight Saving Time, aka DST, aka Summer Time, in which the time definition within a zone endures further changes, by another hour twice a year, so people get up an hour earlier and thus get an extra hour of daylight in the evening.

As a final wrinkle, some jurisdictions use different timezone names when DST is in effect; this is common in the U.S. where, for example, the Eastern timezone uses Eastern Standard Time (EST) as its basic designator but Eastern Daylight Time (EDT) during summer months. But this is not necessarily true everywhere.

More historical details can be found at [TIME-ZONE]. The result of this mess is the following:

  1. Every computer has to be configured with (at least) a local time offset - that is, the difference between its local time and UTC.

  2. In order to display and/or interpret local times from other (named) timezones, any computer that wants to do it needs a database of named-timezone-to-offset mappings and DST start/end times for each zone. Each zone may in fact require a series of such mappings spanning different historical and future ranges of UTC time; the database needs to be updated whenever a zone changes its rules.

  3. There was a lot of pressure from early on in the development of software standards to abandon named timezones in computer date formats in favor of transmitting dates as local time plus the originating location’s numeric offset from meridian time, usually in the form +hhmm or -hhmm. While this still required every computer to configure the local offset (and perhaps change it twice a year for DST) it at least removed the requirement for a timezone database.

  4. Past timestamps using named time zones have to be interpreted with caution, in particular because it may not be evident whether DST was in effect or not.

  5. Embedded systems often evade the whole issue by wiring themselves to Zulu time no matter where they’re deployed.

For an entertaining video lecture about the messy consequences of this history, see [COMPUTERPHILE]. As he says near the end, your only sane option (assuming you don’t go the everything-is-UTC route) is to trust that tzdata or whatever other timezone history your operating system subscribes to is properly maintained and then simply refuse to worry about that level of the problem, because you’d go mad if you tried.

Timezone selection and representation on Unix

In the earliest Unixes, a machine could handle exactly one timezone other than UTC. A timezone offset and name string (actually, a pair of name strings, one for summer and one for winter time) were configured into the kernel and available to C programs.

Later (by System III in 1982) it became possible to set a login session’s notion of the local time zone by modifying an environment variable named TZ and calling a function tzset(3). The rules for interpreting the zone specification in the value of TZ became part of the POSIX standard. They were complex [OLDTZ] and now mainly of historical interest. We mention this history mainly because it has left remnants in the manual pages - notably of tzset(3) - that may confuse the uninformed reader about what is going on.

V7 and older BSD Unixes had various other methods for configuring the local timezone that didn’t involve using or interpreting TZ. These have left no traces on modern Unixes. They shared a fatal flaw with POSIX TZ interpretation, which was that they weren’t designed to cope with the historical instability of the timezone system. They could not express an entire set of historical offset/DST rules in order to get past local times as well as present ones correct.

On modern Unix systems the TZ variable might not be set at all, but the system default timezone can be overridden by explicitly setting TZ in any process. The timezone designator configured at boot time, or via an overriding value of TZ, is a geographical location (usually but not always an area/major-city pair) such as "America/New_York", or "Europe/Vienna" or "Asia/Taipei". If the designator is set via TZ it may need to be preceded by a colon; this is for backwards-compatibility with the POSIX standard, to distinguish it from an old-style timezone specification. (Not all implementations enforce this.)

The location-based zone naming scheme [IANA-ZONES] is managed by IANA, the Internet Assigned Numbers Authority. It is intended to supersede (in computing, anyway) the system of customary names we’ll refer to later in this document as "civil timezone names".

Civil timezone names such as EST/EDT are ambiguous: they have name collisions in different countries, and some civil zones have multiple names. They tend to be short (at least under Unix/Linux, though not necessarily under Windows). They may change without notice. Some of them are official (in that they appear in officially-approved legislative documents in the jurisdictions where they apply), but many of them reflect mere ad-hoc conventions.

The IANA names, on the other hand, are intended to be unique, future-proof, and for use by system administrators and knowledgeable users to set the time zone they wish to apply.

IANA timezone designators are looked up through a locally-installed copy
[The IETF is working on a protocol for pushing updates of the databases over the Internet.]
of a time zone database ("tzdata") maintained by IANA, the Internet Assigned Numbers Authority [TZSOURCES], [TZDATA]. You may hear the name "Arthur David Olson" used in connection with this database; he was the founding contributor.

The contents of the database entry for the designator describe the history of the zone name, zone offset and the DST start/end times (if any) for the location, as those have changed over time since 1970
[The IANA database used to try to cover pre-1970 history as well, though some of this is being phased out since they have learned that their primary source for very old time zone history - a book on astrology - just made some stuff up.]
. The timezone system is sufficiently chaotic in ways previously noted that some of the comments on this history make entertaining reading.

Unix date formats

The Unix time API evolved when many system designers and software standardizers were still trying to hang on to named timezones, which were thought to be more human-friendly. Internet protocols evolving around the same time, however, abandoned named timezones early.

The results of this history are visible as a plethora of different date presentation formats. Thus, for example, the output of the date(1) command looks like this: "Wed Sep 24 15:32:27 EDT 2014" (with named timezone), while a date in an SMTP mail header is more likely to look like this: "Wed, 24 Sep 2014 15:32:27 -0400" with an hhmm numeric offset.

Here is a table duplicating this example in a number of presentation formats commonly found on Unix systems:

Table 4. Date formats

1414179147

Unix UTC seconds

Fri Oct 24 15:32:27 EDT 2014

date(1) output

2014-10-24 15:32:27-0400

date(1) output with -rfc-3339 option

Fri, 24 Oct 2014 15:32:27 -0400

e-mail RFC-822/RFC-2822 format

Fri, 24 Oct 2014 19:32:27 GMT

HTTP (RFC-2616/RFC-7231) format

20141024192327.000000Z

LDAP (RFC-2252/X.680/X.208) format

2014-10-24 15:32:27

Modified ISO-8601 local time

2014-10-24T15:32:27

Strict ISO-8601 local time

2014-10-24T19:32:27Z

RFC-3339 time, always UTC and marked Z

Of these, the last is the most recent and (so far) least widely adopted presentation format; ISO-8601 was not promulgated until 1988 and RFC-3339 not published until 2002 [ISO-8601], [RFC-3339]. However, it has the best properties of any (human readability, non-ambiguity, compactness, fixed length, single token, string sort order matches time order) and we strongly recommend it.

All of these presentation formats are straightforwardly constructible using the strftime(3) function which we’ll be meeting in a few paragraphs (although parsing them can be trickier).

(See also Randall Munroe’s ISO 8601 and Supervillain Plan.)

Some Unix time API functions deal in numeric zone offsets, others in named timezone and DST. Still others (generally older ones) evade the whole issue by not reporting timezone at all. We will be more specific when we discuss individual calls.

Just to add to the hilarity, the IANA database, RFC-822/RFC-2822 dates, and Unix date(1) consider offsets east of Greenwich to be positive and west of it to be negative, but POSIX time-zone formats inexplicably reversed this.

$ TZ=MST+7 date +%z
-0700

Broken-down time

Unix represents calendar time using the following structure, which is consumed or emitted by several key functions:

struct tm
{
    int    tm_sec;   /* seconds [0,60] (60 for + leap second) */
    int    tm_min;   /* minutes [0,59] */
    int    tm_hour;  /* hour [0,23] */
    int    tm_mday;  /* day of month [1,31] */
    int    tm_mon ;  /* month of year [0,11] */
    int    tm_year;  /* years since 1900 */
    int    tm_wday;  /* day of week [0,6] (Sunday = 0) */
    int    tm_yday;  /* day of year [0,365] */
    int    tm_isdst; /* daylight saving flag */
};

Many of the most common problems with using the Unix time API can be traced to the rather confused and inadequate design of this structure. In what is probably unintentional humor, various manual pages and standards documents refer to it as "broken-down time".

The most notable pain points include:

  • tm_isdst is easily misinterpreted as a flag when it’s actually three-valued: 0 = DST off, 1 = DST on, -1 = DST status unknown. (Actually, values < -1 are usually treated as -1 and values > 1 treated as 1 - but do not count on this, as buggy implementations may treat values outside this range as offsets in hours.)

  • The tm_year base value of 1900 rather than zero - easily forgotten and confusing, especially when interpreting negative values.

  • Inconsistency about 0- vs. 1-origin in month and day numbers. The number of programmers who have gotten tm_mon wrong as a result is staggering.

and, worst of all,

  • No timezone offset!

There is a potential overflow problem with tm_year on systems where sizeof(int) < sizeof(time_t); historically this was often true on 32-bit systems and may remain a hidden problem in embedded deployments. The year derived from a time_t can be so large that it won’t fit in an int, which means localtime(3) and gmtime(3) could silently fail on valid time stamps in the far past or far future. A subtler problem is that when tm_year > INT_MAX - 1900 the Gregorian year doesn’t fit in an int; a lot of code gets this wrong. Because INT_MAX on a 32-bit system is 2^31 = 2,147,483,647 this is unlikely to be a problem for normal historical dates.

Some versions of BSD remedied the last and most serious problem by adding two additional fields specifying the timezone used to generate the instance:

    long int tm_gmtoff;  /* time offset in seconds east of UTC/GMT */
    const char *tm_zone; /* name of timezone */

The GNU C library, used on most open-source Unixes, supports these members. The POSIX/SUS/OpenGroup standards allow them, but do not mandate them; in a strict ISO-C environment they will not be visible. You may have to #define _BSD_SOURCE before including time.h to make them visible.

The GNU C library documentation says this: "[The tm_gmtoff] field describes the time zone that was used to compute this broken-down time value, including any adjustment for daylight saving; it is the number of seconds that you must add to UTC to get local time. You can also think of this as the number of seconds east of UTC. For example, for U.S. Eastern Standard Time, the value is -5*60*60."

With the offset member (but not without it) a broken-down time specification is unambiguous.

The tm_zone member is less useful. The zone name strings it points to are not standardized and can be somewhat haphazard. They’re not the IANA geographic designators. Under Linux and BSD they’re typically the familiar (but ambiguous) three- and four-letter abbreviations (EDT, CEST, etc.), but under Windows they’re longer strings like "W. Europe Standard Time". (And they’re sometimes brain-bending monstrosities like "GMT Daylight Time", which is Microsoft’s own special name for what the Brits call British Summer Time.[MTZ])

tzset(3) and ftime(3)

#include <time.h>

void tzset (void);

extern char *tzname[2]; /* time zone name */
extern long timezone;   /* seconds west of UTC, *not* DST-corrected */
extern int daylight;    /* nonzero if DST is ever in effect here */

The tzset(3) call computes the timezone offset for purposes of local-time computation. This information is expressed as three global variables (you may have to set feature macros to expose them).

These values are derived from system administrative settings and (if it is present) the value of the environment variable TZ, in ways too complex to delve into here; consult the manual pages for details. The key point is that after a tzset(3) call, the local timezone information should be available.

Note that the timezone offset does not include DST correction and is of opposite sign to the tm_gmtoff member.

The tzname variable is a pair of strings; tzname[0] is the zone name without and and tzname[1] is with DST correction. These will be civil zone names (like GMT/GST or EST/DST) not the IANA naming scheme.

tzset(3) is required by POSIX to be thread-safe, but access to the globals it sets is intrinsically thread-unsafe.

It should usually not be necessary to call tzset(3) directly, as it is called at the beginning of processing by most of the functions in this section. Exceptions will be noted below.

This part of the Unix time interface is very old; tzset(3) goes back to System III, and at least one of the globals it sets traces back to V6. Later portions of the Unix API design almost completely avoided predefined global variables in favor of returns from function calls.

Some early Unixes (including V7) had a a different way of fetching similar information; ftime(3). This call filled in a structure with members containing information similar to the exposed globals above:

struct timeb {
   time_t         time;      /* seconds since epoch */
   unsigned short millitm;   /* milliseconds part of current time */
   short          timezone;  /* local time offset, minutes west of GMT */
   short          dstflag;   /* if nonzero, local zone uses DST */
};

The Single UNIX Specification carried this forward, but implementations were weak and defective. POSIX.1-2001/SUSv3 said that the contents of the timezone and dstflag fields are unspecified and should not be relied on. POSIX.1-2008/SUSv4 removed ftime(3) entirely. The archaic tzset(3) interface remains.

Final warning: some BSD Unixes do not implement timezone at all!

gmtime(3) and localtime(3)

#include <time.h>

struct tm *gmtime(const time_t *);
struct tm *gmtime_r(const time_t *, struct tm *);
struct tm *localtime(const time_t *);
struct tm *localtime_r(const time_t *, struct tm *);

These are the basic functions for making a broken-down time structure struct tm from a time_t.

The difference between the gm* pair and the local* pair is this:

The local* pair computes the local time corresponding to the input Unix UTC time, taking the local time zone and all DST corrections into account. It does this by, in effect, adding the local timezone offset to the UTC seconds before performing the same computation performed by gmtime, although in a high-quality implementation it’s more complicated than that, because of the possibility that the addition could overflow.

  • Implementations that have a time zone history database, such as glibc with tzdata, apply the historical offset that was in effect at the time being converted according to the current revision of the IANA timezone history. This is normal on Unix systems. There is more detail on this behavior under the discussion of mktime(3)

  • Implementations that lack such a database, such as Visual Studio runtime on Windows, apply the offset that would have been in effect at the time being converted according to the rules at the time the software shipped.

The gm* pair applies no such offset, so the output struct tm expresses Unix UTC seconds as UTC time.

The names of the gm* pair are a historical error, since they actually convert to UTC. These systems are not actually identical; for real GMT we would incorporate the DST bit, but for UTC it must be ignored.

The functions gmtime(3) and localtime(3) return a pointer to internal static storage that is overwritten on each call (in the GNU C library this static storage is shared among both functions). This is not thread-safe. The *_r functions are, on the other hand, re-entrant, with the user being required to pass in the address of the storage to be modified, and can thus be thread-safe.

POSIX implies that localtime(3) is required to behave as though tzset(3) has been called, but that localtime_r(3) is not (this is almost certainly because tzset(3) sets globals if localtime_r(3) also set them its callers could well become thread-unsafe".

For portable code tzset(3) should be called before localtime_r(3) - but note that this can lead to subtle errors when processing historical date/times because of the historical-date problem described under mktime(3).

Now that we’ve gone through the terchnical details, here is a less formal but more evocative way of summarizing them: localtime(3) is a pit of horrors that wants to be your personal hell - avoid. This is especially true if you are concerned about reproducibility (e.g. in unit and regression tests) where timezone- and DST-related problems can introduce random glitches like off-by-one-hour errors with no cause in your visible code.

mktime(3), timelocal(3), timegm(3)

#include <time.h>

time_t mktime(struct tm *tm);

The mktime(3) function inverts localtime(3), turning an input struct tm into a time_t. It is standardized.

There is no analogous standardized mkgmtime() function that inverts gmtime(3), but see the description of timegm(3) below.

The mktime(3) function has a side effect that can trip you up seriously if you’re not aware of it. In addition to returning a Unix seconds value, it also modifies the contents of the struct tm.

This means, in particular, that calling mktime(3) a second time on the same struct tm won’t necessarily return the same value as it did on the first call! The most likely error is for the second return to be 3600 seconds off because the first call set the tm_isdst member.

The manual page says:

"The mktime() function modifies the fields of the tm structure as follows: tm_wday and tm_yday are set to values determined from the contents of the other fields; if structure members are outside their valid interval, they will be normalized (so that, for example, 40 October is changed into 9 November); tm_isdst is set (regardless of its initial value) to a positive value or to 0, respectively, to indicate whether DST is or is not in effect at the specified time. Calling mktime() also sets the external variable tzname with information about the current timezone."

The last sentence is fairly subtle: it means that the implicit tzset(3) call at the beginning of mktime(3) can behave differently from an ordinary tzset(3) call, in that the implicit call can take advantage of knowing the time stamp that the caller is interested in, and can set global variables to values that are tailored for that time stamp. For example, if the time zone is Europe/London and the time stamp argument to mktime is circa 1970, mktime can set the global variables to values appropriate for a location that is at UTC+1 year round, which is what London was observing back in 1970; whereas if the time stamp is circa 2014, mktime can set the global variables to values appropriate for a location that is at UTC in winter and UTC+1 in summer, which is what London was doing in 2014.

The normalizing side-effect of mktime(3) makes it useful for various kinds of date/time arithmetic on broken-down time structures. For example, you can increment a tm_day member, call mktime(3) on it, and expect overflow beyond the end of month to be handled (but beware that this will be done without adjusting for leap-second discontinuities).

#include <time.h>

time_t timelocal(struct tm *tm);

time_t timegm(struct tm *tm);

These are GNU C Library extensions, not standardized. They are modeled on calls introduced in BSD and still present in FreeBSD/NetBSD/OpenBSD.

The timelocal(3) function is identical to standard mktime(3) (except for assuming tm_isdst is initially negative, which mktime(3) does not) inverting localtime(3). The timegm(3) function inverts gmtime(3).

The GNU C Library documentation recommends against using these functions, as they introduce a dependency. It recommends this as a portable alternative (but note that it is thread-unsafe):

#include <time.h>
#include <stdlib.h>

time_t
my_timegm(struct tm *tm)
{
     time_t ret;
     char *tz;

     tz = getenv("TZ");
     if (tz)
         tz = strdup(tz);
     setenv("TZ", "", 1);
     tzset();
     ret = mktime(tm);
     if (tz) {
         setenv("TZ", tz, 1);
         free(tz);
     } else
         unsetenv("TZ");
     tzset();
     return ret;
}

asctime(3) and ctime(3)

In older Unixes the following functions were available to report time and date as a string. They wired in bad design choices (the date string is of unpredictable length and includes a trailing "\n"), are not locale-aware, and have undefined behavior for years before 0 or after 9999.

#include <time.h>

char *asctime(const struct tm *);
char *asctime_r(const struct tm *, char *);
char *ctime(const time_t *);
char *ctime_r(const time_t *, char *);

These functions are obsolete and should not be used in production code; use strftime(3) instead. If you are curious about the details, read their manual pages.

strftime(3)

#include <time.h>

size_t strftime(char *, size_t, const char *, const struct tm *);

This is the modern function for formatting timestamps into string representations; read its manual page. Here are some potentially interesting recipes that illustrate usage patterns:

/* RFC-3339 format */
strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%SZ", gmtime(t));

/* ISO-8601 local time */
strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", localtime(t));

/* RFC-822/RFC-2822 format */
strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S %z", localtime(t));

RFC-822/RFC-2822 specifies English month and weekday names, but %a and %b are locale-aware; thus, the third recipe will deliver interestingly nonstandard results in a non-Anglophone locale.

Some of the format specifiers need to be used with caution; older implementations may not support all of them. Unit-test your formatting, checking carefully for %z and the other Single UNIX Specification and glibc additions (%C, %D, %E, %h, %n, %O, %P, %r, %t, %T, %V) if you must rely on them.

If called with a manually populated struct tm with all Standard C members populated, but without the tm_gmtoff and tm_zone members populated, strftime will, on some systems, not give sensible results for %z or %Z. Worse, it directly reads from the possibly-uninitialized tm_zone pointer.

More generally, %z and %Z for anything other than an immediate localtime(3)/strftime(3) pair can get wacky. In particular:

  • If you’re on a system without tm_gmtoff and tm_zone, they’ll print the local time zone even for a gmtime(3)-initialized struct tm.

  • If you change the value of TZ between mktime(3) and strftime(3), if you have tm_zone, %Z will use a random zone for the new zone, not the abbreviation for the old one. If the new zone has fewer abbreviations than the old one, tm_zone (and thus %Z) can even end up pointing into freed memory!

  • If you’re constructing struct tm instances by hand before passing them to strftime (or, for that matter, mktime/gmtime), it’s best to zero them out first, with memset or the equivalent.

  • If you can help it, only call strftime on struct tm instances that localtime/gmtime have constructed for you. If you must construct them by hand, try to limit your strftime format specifiers to the "normal" ones that obviously correspond to fields you have set.

strptime(3) and getdate(3)

#include <time.h>

char *strptime(const char *, const char *, struct tm *);
struct tm *getdate(const char *);
int getdate_r(const char *string, struct tm *res);

The strptime(3) function is a near-inverse of strftime(3) function, with one painful exception; it does not parse timezones. (If only because the misdesign of the standardized struct tm leaves it no place to put the information.) The full list of strftime(3) specifiers not supported are %F, %g, %G, %u, %v, %z, and %Z.

Do not use the %y specifier. Its interpretation differs incompatibly among implementations.

Test code that uses strptime(3) carefully on real data. Implementations are bug-prone.

The getdate(3) function and its re-entrant twin getdate_r(3) are complex and dubiously-designed attempts to do adaptive date parsing. We recommend against attempting to use them. See their manual pages for details.

Berkeley multiple-timezone API

#include <time.h>

timezone_t tzalloc(const char *zone);
void tzfree(timezone_t tz);
const char *tzgetname(timezone_t tz, int isdst);
long tzgetgmtoff(timezone_t tz, int isdst);
char *ctime_rz(timezone_t tz, const time_t *clock, char *buf);
struct tm *localtime_rz(timezone_t tz, const time_t * clock, struct tm * result);
time_t mktime_z(timezone_t tz, struct tm *restrict tm);

Some Berkeley Unixes have a group of functions designed to avoid any dependence on the system timezone globals, thus making it easier to handle multiple timezones in one program. This approach is also good for re-entrancy.

Because these functions are not standardized, this section is only a sketch intended to convey the style of the interface; for more details consult their manual pages.

tzalloc() takes a timezone specification and returns a timezone_t structure, which should later be freed by tzfree(). It is passed to *_rz functions which behave like the corresponding *_r functions, except that a hidden reference to system timezone globals is replaced by looking at a first argument which must be a pointer to a timezone_t.

This is how it should have been done in the first place…

Good programming practice

As previously noted, localtime(3) is a pit of unreproducibility horrors due to the hidden and time-variable rules for computing timezone offsets. Avoid it.

To stay out of trouble, convert dates to Unix UTC on input, do all your calculations in that, and convert back to localtime as late as possible. This reduces your odds of introducing a misconversion and spurious timezone skew.

Any time you find yourself writing code that knows how many days there are in a month, something is probably very wrong. Reexamine your assumptions. You may want to bite the bullet and use timegm(3), even though it’s nominally not portable.

Be very careful if you find yourself trying to do anything fancy with dates and times. If it’s not obvious already, date and time processing is rather outrageously complex, and there’s almost always one more quirk or gotcha lurking around the next bend that you haven’t thought of yet. Whenever possible, offload the work to the standard library functions — their implementations have most of the bugs worked out by now.

A potentially useful reference on good practice in dealing with timezones and DST is [DSTBP]

Improvements

The author welcomes corrections and improvements. This document has been written in the editorial we because he hopes to attract domain experts to cooperate on future revisions.

Acknowledgments

Yuri Khan, Geoff Clare, Gary E. Miller, and Paul Eggert rendered substantial help with the beta revision of this document. Steve Summit wrote substantial critiques of versions 1.2 and 1.3.

Revision History

1.7: 2017-09-09

Emphasize that localtime(3) is a horror to be avoided.

1.6: 2016-06-06

Note difference between UTC and GMT. Note that NTP does not offer leap-second correction.

1.5: 2016-05-29

Remove some buggy code pending better unit testing.

1.4: 2016-05-04

Add information on Berkely multiple-timezone API.

1.3: 2016-04-24

Various minor corrections and clarifications, mostly around timezones.

1.2: 2015-01-22

Note that timezone is not necessarily supported by *BSD. Add a gotcha in the interpretation of the DST bit. More detail under mktime(3) on how historical dates are handled.

1.1: 2015-01-08

Explain the contents of tzname better. New section on good programming practice.

1.0: 2014-10-09

First production release.

0.9: 2014-09-29

Beta version circulated for critique.


bobcat-5.09.01/encryptbuf/0000755000175000017500000000000014050437223014265 5ustar frankfrankbobcat-5.09.01/encryptbuf/blocklength.cc0000644000175000017500000000016214050437223017067 0ustar frankfrank#include "encryptbuf.ih" size_t EncryptBuf::blockLength() const { return EVP_CIPHER_CTX_block_size(d_ctx); } bobcat-5.09.01/encryptbuf/prepareiv.cc0000644000175000017500000000037414050437223016575 0ustar frankfrank#include "encryptbuf.ih" void EncryptBuf::prepareIV() { if (not d_iv.empty()) return; d_iv.resize(EVP_MAX_IV_LENGTH); IRandStream irs{ 0, 255, static_cast(time(0)) }; for (auto &ch: d_iv) setChar(ch, irs); } bobcat-5.09.01/encryptbuf/overflow.cc0000644000175000017500000000026214050437223016437 0ustar frankfrank#include "encryptbuf.ih" int EncryptBuf::overflow(int ch) { flushBuffer(); if (ch != EOF) { *pptr() = ch; pbump(1); } return ch; } bobcat-5.09.01/encryptbuf/keylength.cc0000644000175000017500000000016014050437223016563 0ustar frankfrank#include "encryptbuf.ih" size_t EncryptBuf::keyLength() const { return EVP_CIPHER_CTX_key_length(d_ctx); } bobcat-5.09.01/encryptbuf/encryptbuf.ih0000644000175000017500000000144714050437223016776 0ustar frankfrank#include "encryptbuf" #include #include #include #define CERRX std::cerr << __FILE__": " << #include #include #include #include #include "../exception/exception" #include "../randbuf/randbuf" #include "../irandstream/irandstream" #include "../ohexbuf/ohexbuf" #if OPENSSL_VERSION_NUMBER < 0x10100000L #ifndef BOBCAT_EVP_CYPHER_CTX #define BOBCAT_EVP_CYPHER_CTX inline EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(void) { EVP_CIPHER_CTX *ret = new EVP_CIPHER_CTX; EVP_CIPHER_CTX_init(ret); return ret; } inline void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx) { EVP_CIPHER_CTX_cleanup(ctx); delete ctx; } #endif // BOBCAT_EVP #endif // OPENSSL_VERSION using namespace std; using namespace FBB; bobcat-5.09.01/encryptbuf/wikipedia/0000755000175000017500000000000014050437223016233 5ustar frankfrankbobcat-5.09.01/encryptbuf/wikipedia/encrypt.cc0000644000175000017500000000230114050437223020222 0ustar frankfrank#include "main.ih" int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key, unsigned char *iv, unsigned char *ciphertext) { EVP_CIPHER_CTX *ctx; int len; int ciphertext_len; /* Create and initialise the context */ if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors(); /* Initialise the encryption operation. IMPORTANT - ensure you use a key * and IV size appropriate for your cipher * In this example we are using 256 bit AES (i.e. a 256 bit key). The * IV size for *most* modes is the same as the block size. For AES this * is 128 bits */ if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv)) handleErrors(); /* Provide the message to be encrypted, and obtain the encrypted output. * EVP_EncryptUpdate can be called multiple times if necessary */ if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len)) handleErrors(); ciphertext_len = len; /* Finalise the encryption. Further ciphertext bytes may be written at * this stage. */ if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) handleErrors(); ciphertext_len += len; /* Clean up */ EVP_CIPHER_CTX_free(ctx); return ciphertext_len; } bobcat-5.09.01/encryptbuf/wikipedia/handleerrors.cc0000644000175000017500000000013214050437223021226 0ustar frankfrank#include "main.ih" void handleErrors(void) { ERR_print_errors_fp(stderr); throw 1; } bobcat-5.09.01/encryptbuf/wikipedia/main.cc0000644000175000017500000000321614050437223017470 0ustar frankfrank#include "main.ih" // Room for Args initialization int main() try { /* Set up the key and iv. Do I need to say to not hard code these in a * real application? :-) */ /* A 256 bit key */ unsigned char *key = (unsigned char *)"01234567890123456789012345678901"; /* A 128 bit IV */ unsigned char *iv = (unsigned char *)"01234567890123456"; /* Message to be encrypted */ unsigned char *plaintext = (unsigned char *)"The quick brown fox jumps over the lazy dog"; /* Buffer for ciphertext. Ensure the buffer is long enough for the * ciphertext which may be longer than the plaintext, dependant on the * algorithm and mode */ unsigned char ciphertext[128]; /* Buffer for the decrypted text */ unsigned char decryptedtext[128]; int decryptedtext_len, ciphertext_len; /* Initialise the library */ ERR_load_crypto_strings(); OpenSSL_add_all_algorithms(); // OPENSSL_config(NULL); deprecated... /* Encrypt the plaintext */ ciphertext_len = encrypt (plaintext, strlen ((char *)plaintext), key, iv, ciphertext); /* Do something useful with the ciphertext here */ printf("Ciphertext is:\n"); BIO_dump_fp (stdout, (const char *)ciphertext, ciphertext_len); /* Decrypt the ciphertext */ decryptedtext_len = decrypt(ciphertext, ciphertext_len, key, iv, decryptedtext); /* Add a NULL terminator. We are expecting printable text */ decryptedtext[decryptedtext_len] = '\0'; /* Show the decrypted text */ printf("Decrypted text is:\n"); printf("%s\n", decryptedtext); /* Clean up */ EVP_cleanup(); ERR_free_strings(); } catch (...) { return 1; } bobcat-5.09.01/encryptbuf/wikipedia/main.ih0000644000175000017500000000056514050437223017507 0ustar frankfrank#include #include #include #include void handleErrors(); int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key, unsigned char *iv, unsigned char *ciphertext); int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key, unsigned char *iv, unsigned char *plaintext); bobcat-5.09.01/encryptbuf/wikipedia/decrypt.cc0000644000175000017500000000227514050437223020222 0ustar frankfrank#include "main.ih" int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key, unsigned char *iv, unsigned char *plaintext) { EVP_CIPHER_CTX *ctx; int len; int plaintext_len; /* Create and initialise the context */ if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors(); /* Initialise the decryption operation. IMPORTANT - ensure you use a key * and IV size appropriate for your cipher * In this example we are using 256 bit AES (i.e. a 256 bit key). The * IV size for *most* modes is the same as the block size. For AES this * is 128 bits */ if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv)) handleErrors(); /* Provide the message to be decrypted, and obtain the plaintext output. * EVP_DecryptUpdate can be called multiple times if necessary */ if(1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len)) handleErrors(); plaintext_len = len; /* Finalise the decryption. Further plaintext bytes may be written at * this stage. */ if(1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) handleErrors(); plaintext_len += len; /* Clean up */ EVP_CIPHER_CTX_free(ctx); return plaintext_len; } bobcat-5.09.01/encryptbuf/setchar.cc0000644000175000017500000000021714050437223016225 0ustar frankfrank#include "encryptbuf.ih" // static void EncryptBuf::setChar(char &ch, IRandStream &irs) { int value; irs >> value; ch = value; } bobcat-5.09.01/encryptbuf/iv.f0000644000175000017500000000010614050437223015047 0ustar frankfrankinline std::string const &EncryptBuf::iv() const { return d_iv; } bobcat-5.09.01/encryptbuf/rounds.cc0000644000175000017500000000027714050437223016114 0ustar frankfrank#include "encryptbuf.ih" size_t EncryptBuf::rounds() const { size_t nRounds; return EVP_CIPHER_CTX_ctrl(d_ctx, EVP_CTRL_GET_RC5_ROUNDS, 0, &nRounds) ? nRounds : 0; } bobcat-5.09.01/encryptbuf/cipherctx.cc0000644000175000017500000000013014050437223016557 0ustar frankfrank#include "encryptbuf.ih" EVP_CIPHER_CTX *EncryptBuf::cipherCtx() { return d_ctx; } bobcat-5.09.01/encryptbuf/eoi.f0000644000175000017500000000005614050437223015211 0ustar frankfrankinline void EncryptBuf::eoi() { eoi_(); } bobcat-5.09.01/encryptbuf/flushbuffer.cc0000644000175000017500000000105014050437223017103 0ustar frankfrank#include "encryptbuf.ih" void EncryptBuf::flushBuffer() // called by overflow when d_buffer is // full and by end() { int srcLen = pptr() - pbase(); int encryptedLen; if ( not EVP_EncryptUpdate(d_ctx, ucharPtr(d_encrypted), &encryptedLen, ucharPtr(), srcLen) ) throw Exception{ 1 } << "Encrypt update failed"; d_outStream.write(&d_encrypted[0], encryptedLen); setp(); // reset the buffer } bobcat-5.09.01/encryptbuf/destructor.cc0000644000175000017500000000017314050437223016773 0ustar frankfrank#include "encryptbuf.ih" EncryptBuf::~EncryptBuf() { if (not d_eoi) eoi(); EVP_CIPHER_CTX_free(d_ctx); } bobcat-5.09.01/encryptbuf/encryptbuf1.cc0000644000175000017500000000107114050437223017035 0ustar frankfrank#include "encryptbuf.ih" EncryptBuf::EncryptBuf(ostream &outStream, char const *type, string key, string const &iv, size_t size) : CryptBuf(type, size), d_ctx(EVP_CIPHER_CTX_new()), d_encrypted(size + EVP_MAX_BLOCK_LENGTH, 0), d_iv(iv), d_key(key), d_outStream(outStream) { prepareIV(); if ( not EVP_EncryptInit_ex(d_ctx, md(), 0, ucharPtr(d_key), ucharPtr(d_iv)) ) throw Exception{ 1 } << "Encrypt initialization failed"; setp(); } bobcat-5.09.01/encryptbuf/eoi.cc0000644000175000017500000000051114050437223015345 0ustar frankfrank#include "encryptbuf.ih" void EncryptBuf::eoi_() // overrides Eoi::eoi_() { flushBuffer(); int restLen; if (not EVP_EncryptFinal_ex(d_ctx, ucharPtr(d_encrypted), &restLen)) throw Exception{ 1 } << "Encrypt finalization failed"; d_outStream.write(&d_encrypted[0], restLen); d_eoi = true; } bobcat-5.09.01/encryptbuf/ivlength.cc0000644000175000017500000000015614050437223016416 0ustar frankfrank#include "encryptbuf.ih" size_t EncryptBuf::ivLength() const { return EVP_CIPHER_CTX_iv_length(d_ctx); } bobcat-5.09.01/encryptbuf/encryptbuf0000644000175000017500000002425314050437223016377 0ustar frankfrank#ifndef INCLUDED_BOBCAT_ENCRYPTBUF_ #define INCLUDED_BOBCAT_ENCRYPTBUF_ // https://wiki.openssl.org/index.php/EVP_Symmetric_Encryption_and_Decryption #include #include #include #include "../cryptbuf/cryptbuf" namespace FBB { class IRandStream; class EncryptBuf: public CryptBuf { EVP_CIPHER_CTX *d_ctx; std::string d_encrypted; bool d_eoi = false; // eoi() was called std::string d_iv; // maybe initialize iv ourselves std::string d_key; std::ostream &d_outStream; public: EncryptBuf(std::ostream &outStream, char const *type, std::string key, std::string const &iv, size_t bufSize = 1024); ~EncryptBuf() override; size_t keyLength() const; // bytes size_t blockLength() const; // bytes size_t ivLength() const; // bytes bool setRounds(size_t nRounds); // RC5 8, 12 or 16 size_t rounds() const; // RC5 std::string const &iv() const; void eoi(); // .f protected: EVP_CIPHER_CTX *cipherCtx(); private: int overflow(int ch) override; void eoi_() override; // .cc void prepareIV(); void prepareKey(); void setMD(char const *type); void flushBuffer(); static void setChar(char &ch, IRandStream &irs); }; #include "iv.f" #include "eoi.f" } // FBB /* EVP_enc_null() Null cipher: does nothing. DES: Avoid, unless required, uses 8 byte buffer and 8 byte key EVP_des_cbc(), EVP_des_ecb(), EVP_des_cfb(), EVP_des_ofb() DES in CBC, ECB, CFB and OFB modes respectively. 3DES: Uses 8 byte buffer and 2x8 byte key for the two keys EVP_des_ede_cbc(), EVP_des_ede(), EVP_des_ede_ofb(), EVP_des_ede_cfb() Two key triple DES in CBC, ECB, CFB and OFB modes respectively. 3DES 3keys: Uses 8 byte buffer and 3x8 byte key for the 3 8 byte keys. EVP_des_ede3_cbc(), EVP_des_ede3(), EVP_des_ede3_ofb(), EVP_des_ede3_cfb() Three key triple DES in CBC, ECB, CFB and OFB modes respectively. DESX: --> BOOK !! EVP_desx_cbc() DESX algorithm in CBC mode. const EVP_CIPHER *EVP_des_ecb(); const EVP_CIPHER *EVP_des_ede(); const EVP_CIPHER *EVP_des_ede3(); const EVP_CIPHER *EVP_des_ede_ecb(); const EVP_CIPHER *EVP_des_ede3_ecb(); const EVP_CIPHER *EVP_des_cfb64(); # define EVP_des_cfb EVP_des_cfb64 const EVP_CIPHER *EVP_des_cfb1(); const EVP_CIPHER *EVP_des_cfb8(); const EVP_CIPHER *EVP_des_ede_cfb64(); # define EVP_des_ede_cfb EVP_des_ede_cfb64 #if 0 const EVP_CIPHER *EVP_des_ede_cfb1(); const EVP_CIPHER *EVP_des_ede_cfb8(); #endif const EVP_CIPHER *EVP_des_ede3_cfb64(); # define EVP_des_ede3_cfb EVP_des_ede3_cfb64 const EVP_CIPHER *EVP_des_ede3_cfb1(); const EVP_CIPHER *EVP_des_ede3_cfb8(); const EVP_CIPHER *EVP_des_ofb(); const EVP_CIPHER *EVP_des_ede_ofb(); const EVP_CIPHER *EVP_des_ede3_ofb(); const EVP_CIPHER *EVP_des_cbc(); const EVP_CIPHER *EVP_des_ede_cbc(); const EVP_CIPHER *EVP_des_ede3_cbc(); const EVP_CIPHER *EVP_desx_cbc(); RC4: EVP_rc4() RC4 stream cipher. This is a variable key length cipher with default key length 128 bits. #ifndef OPENSSL_NO_RC4 const EVP_CIPHER *EVP_rc4(); const EVP_CIPHER *EVP_rc4_40(); #endif RC4_40: EVP_rc4_40() RC4 stream cipher with 40 bit key length. This is obsolete and new code should use EVP_rc4() and the EVP_CIPHER_CTX_set_key_length() function. IDEA: EVP_idea_cbc(), EVP_idea_ecb(), EVP_idea_cfb(), EVP_idea_ofb() IDEA encryption algorithm in CBC, ECB, CFB and OFB modes respectively. #ifndef OPENSSL_NO_IDEA const EVP_CIPHER *EVP_idea_ecb(); const EVP_CIPHER *EVP_idea_cfb64(); # define EVP_idea_cfb EVP_idea_cfb64 const EVP_CIPHER *EVP_idea_ofb(); const EVP_CIPHER *EVP_idea_cbc(); #endif RC2: EVP_rc2_cbc(), EVP_rc2_ecb(), EVP_rc2_cfb(), EVP_rc2_ofb() RC2 encryption algorithm in CBC, ECB, CFB and OFB modes respectively. This is a variable key length cipher with an additional parameter called "effective key bits" or "effective key length". By default both are set to 128 bits. #ifndef OPENSSL_NO_RC2 const EVP_CIPHER *EVP_rc2_ecb(); const EVP_CIPHER *EVP_rc2_cbc(); const EVP_CIPHER *EVP_rc2_40_cbc(); const EVP_CIPHER *EVP_rc2_64_cbc(); const EVP_CIPHER *EVP_rc2_cfb64(); # define EVP_rc2_cfb EVP_rc2_cfb64 const EVP_CIPHER *EVP_rc2_ofb(); #endif RC2-40: RC2-64: EVP_rc2_40_cbc(), EVP_rc2_64_cbc() RC2 algorithm in CBC mode with a default key length and effective key length of 40 and 64 bits. These are obsolete and new code should use EVP_rc2_cbc(), EVP_CIPHER_CTX_set_key_length() and EVP_CIPHER_CTX_ctrl() to set the key length and effective key length. BLOWFISH: EVP_bf_cbc(), EVP_bf_ecb(), EVP_bf_cfb(), EVP_bf_ofb(); Blowfish encryption algorithm in CBC, ECB, CFB and OFB modes respectively. This is a variable key length cipher. #ifndef OPENSSL_NO_BF const EVP_CIPHER *EVP_bf_ecb(); const EVP_CIPHER *EVP_bf_cbc(); const EVP_CIPHER *EVP_bf_cfb64(); # define EVP_bf_cfb EVP_bf_cfb64 const EVP_CIPHER *EVP_bf_ofb(); #endif CAST: EVP_cast5_cbc(), EVP_cast5_ecb(), EVP_cast5_cfb(), EVP_cast5_ofb() CAST encryption algorithm in CBC, ECB, CFB and OFB modes respectively. This is a variable key length cipher. #ifndef OPENSSL_NO_CAST const EVP_CIPHER *EVP_cast5_ecb(); const EVP_CIPHER *EVP_cast5_cbc(); const EVP_CIPHER *EVP_cast5_cfb64(); # define EVP_cast5_cfb EVP_cast5_cfb64 const EVP_CIPHER *EVP_cast5_ofb(); #endif RC5: EVP_rc5_32_12_16_cbc(), EVP_rc5_32_12_16_ecb(), EVP_rc5_32_12_16_cfb(), EVP_rc5_32_12_16_ofb() RC5 encryption algorithm in CBC, ECB, CFB and OFB modes respectively. This is a variable key length cipher with an additional "number of rounds" parameter. By default the key length is set to 128 bits and 12 rounds. #ifndef OPENSSL_NO_RC5 const EVP_CIPHER *EVP_rc5_32_12_16_cbc(); const EVP_CIPHER *EVP_rc5_32_12_16_ecb(); const EVP_CIPHER *EVP_rc5_32_12_16_cfb64(); # define EVP_rc5_32_12_16_cfb EVP_rc5_32_12_16_cfb64 const EVP_CIPHER *EVP_rc5_32_12_16_ofb(); #endif #if 0 # ifdef OPENSSL_OPENBSD_DEV_CRYPTO const EVP_CIPHER *EVP_dev_crypto_des_ede3_cbc(); const EVP_CIPHER *EVP_dev_crypto_rc4(); const EVP_MD *EVP_dev_crypto_md5(); # endif #endif #ifndef OPENSSL_NO_AES const EVP_CIPHER *EVP_aes_128_ecb(); const EVP_CIPHER *EVP_aes_128_cbc(); const EVP_CIPHER *EVP_aes_128_cfb1(); const EVP_CIPHER *EVP_aes_128_cfb8(); const EVP_CIPHER *EVP_aes_128_cfb128(); # define EVP_aes_128_cfb EVP_aes_128_cfb128 const EVP_CIPHER *EVP_aes_128_ofb(); #if 0 const EVP_CIPHER *EVP_aes_128_ctr(); #endif const EVP_CIPHER *EVP_aes_192_ecb(); const EVP_CIPHER *EVP_aes_192_cbc(); const EVP_CIPHER *EVP_aes_192_cfb1(); const EVP_CIPHER *EVP_aes_192_cfb8(); const EVP_CIPHER *EVP_aes_192_cfb128(); # define EVP_aes_192_cfb EVP_aes_192_cfb128 const EVP_CIPHER *EVP_aes_192_ofb(); #if 0 const EVP_CIPHER *EVP_aes_192_ctr(); #endif const EVP_CIPHER *EVP_aes_256_ecb(); const EVP_CIPHER *EVP_aes_256_cbc(); const EVP_CIPHER *EVP_aes_256_cfb1(); const EVP_CIPHER *EVP_aes_256_cfb8(); const EVP_CIPHER *EVP_aes_256_cfb128(); # define EVP_aes_256_cfb EVP_aes_256_cfb128 const EVP_CIPHER *EVP_aes_256_ofb(); const EVP_CIPHER *EVP_aes_256_ctr(); In cryptography, Camellia is a block cipher that has been evaluated favorably by several organisations, including the European Union's NESSIE project (a selected algorithm), and the Japanese CRYPTREC project (a recommended algorithm). The cipher was developed jointly by Mitsubishi and NTT in 2000, and has similar design elements to earlier block ciphers (MISTY1 and E2) from these companies. Camellia has a block size of 128 bits, and can use 128-bit, 192-bit or 256-bit keys - the same interface as the Advanced Encryption Standard. It is a Feistel cipher with either 18 rounds (if the key is 128 bits) or 24 rounds (if the key is 192 or 256 bits). Every six rounds, a logical transformation layer is applied: the so-called "FL-function" or its inverse. Camellia uses four 8 x 8-bit S-boxes with input and output affine transformations and logical operations. The cipher also uses input and output key whitening. The diffusion layer uses a linear transformation based on an MDS matrix with a branch number of 5. On June, 18 2008, support for the adopted Camellia cipher was added to the final release of Mozilla Firefox 3.[citation needed] http://en.wikipedia.org/wiki/Camellia_(cipher) const EVP_CIPHER *EVP_camellia_128_ecb(); const EVP_CIPHER *EVP_camellia_128_cbc(); const EVP_CIPHER *EVP_camellia_128_cfb1(); const EVP_CIPHER *EVP_camellia_128_cfb8(); const EVP_CIPHER *EVP_camellia_128_cfb128(); # define EVP_camellia_128_cfb EVP_camellia_128_cfb128 const EVP_CIPHER *EVP_camellia_128_ofb(); const EVP_CIPHER *EVP_camellia_192_ecb(); const EVP_CIPHER *EVP_camellia_192_cbc(); const EVP_CIPHER *EVP_camellia_192_cfb1(); const EVP_CIPHER *EVP_camellia_192_cfb8(); const EVP_CIPHER *EVP_camellia_192_cfb128(); # define EVP_camellia_192_cfb EVP_camellia_192_cfb128 const EVP_CIPHER *EVP_camellia_192_ofb(); const EVP_CIPHER *EVP_camellia_256_ecb(); const EVP_CIPHER *EVP_camellia_256_cbc(); const EVP_CIPHER *EVP_camellia_256_cfb1(); const EVP_CIPHER *EVP_camellia_256_cfb8(); const EVP_CIPHER *EVP_camellia_256_cfb128(); # define EVP_camellia_256_cfb EVP_camellia_256_cfb128 const EVP_CIPHER *EVP_camellia_256_ofb(); #ifndef OPENSSL_NO_SEED const EVP_CIPHER *EVP_seed_ecb(); const EVP_CIPHER *EVP_seed_cbc(); const EVP_CIPHER *EVP_seed_cfb128(); # define EVP_seed_cfb EVP_seed_cfb128 const EVP_CIPHER *EVP_seed_ofb(); #endif */ #endif bobcat-5.09.01/encryptbuf/driver/0000755000175000017500000000000014050437223015560 5ustar frankfrankbobcat-5.09.01/encryptbuf/driver/build0000755000175000017500000000246314050437223016612 0ustar frankfrank#!/bin/bash # ln -s .. bobcat # ln -s ../ohexbuf/ohexbuf bobcat # # g++ -I. --std=c++2a -O2 -Wall -o driver driver.cc -lssl -lbobcat \ # -L../../ohexbuf/tmp -L../tmp -lencryptbuf -lohexbuf # # rm bobcat/ohexbuf bobcat # echo g++ --std=c++2a -O2 -Wall -o driver driver.cc -lbobcat # g++ --std=c++2a -O2 -Wall -o driver driver.cc -lbobcat # echo g++ -I. --std=c++2a -O2 -Wall -o driver driver.cc -L../tmp -lencryptbuf \ # -lssl -lbobcat # # g++ -I. --std=c++2a -O2 -Wall -o driver driver.cc -L../tmp -lencryptbuf \ # -lssl -lbobcat tput clear LIBS=" -lbobcat -lcrypto" GPP="g++ --std=c++2a" # Using the standard bobcat library #CMD="$GPP -o driver -Wall driver.cc ${LIBS} -s" # Using the library in ../tmp/ #CMD="$GPP -o driver -Wall driver.cc -L../tmp -lencryptbuf ${LIBS} -s" # Using the library in ../tmp/ and bobcat as /tmp/libbob.a #CMD="$GPP -o driver -Wall driver.cc -L../tmp -lencryptbuf -L /tmp -lbob -lcrypto -s" # Using libraries in ../tmp/, and /tmp (-> boblib) CMD="$GPP -o driver -Wall driver.cc \ -L../tmp -lencryptbuf \ -L../../cryptbuf/tmp -lcryptbuf \ -L../../eoibuf/tmp -leoibuf \ -L../../eoi/tmp -leoi \ -L../../ohexbuf/tmp -lohexbuf\ -L../../randbuf/tmp -lrandbuf\ -lbobcat -lcrypto -s" echo ${CMD} ${CMD} bobcat-5.09.01/encryptbuf/driver/driver.cc0000644000175000017500000000230114050437223017356 0ustar frankfrank#include #include #include #include #include #include "../encryptbuf" #include using namespace std; using namespace FBB; int main(int argc, char **argv) try { if (argc == 1) throw Exception(1) << "1st arg: method, 2nd arg: key, 3rd arg: (opt): iv, " "stdin: file to encrypt (to stdout)\n" "e.g., driver aes-128-cbc somekey < driver.cc > /tmp/enc\n"; string key(argv[2]); string iv; if (argc > 3) iv = argv[3]; EncryptBuf encryptbuf(cout, argv[1], key, iv, 50); ostream out(&encryptbuf); size_t ivLength = encryptbuf.iv().length(); cerr << "Block length: " << encryptbuf.blockLength() << "\n" "Key length: " << encryptbuf.keyLength() << "\n" "Max Key length: " << EVP_MAX_KEY_LENGTH << "\n" "actual IV length: " << ivLength << "\n" "IV =\n"; OHexBuf ohb{ cerr, ivLength << 1 }; ostream outHex(&ohb); outHex << encryptbuf.iv(); cerr << '\n' << dec; out << cin.rdbuf() << eoi; } catch(exception const &err) { cerr << err.what() << endl; return 1; } bobcat-5.09.01/encryptbuf/driver/run0000755000175000017500000000025714050437223016316 0ustar frankfrank#!/bin/bash if [ $# -eq 0 ] ; then method=aes-128-cbc else method=$1 fi ./driver $method theKeyOfRunAES 1234567890qwertyuiop < driver.cc > /tmp/enc ls -Fla /tmp/enc bobcat-5.09.01/encryptbuf/driver/extra/0000755000175000017500000000000014050437223016703 5ustar frankfrankbobcat-5.09.01/encryptbuf/driver/extra/endecrypt.cc0000644000175000017500000000573114050437223021215 0ustar frankfrank#include #include #include #include #include #include using namespace std; EVP_CIPHER const *md; string encrypt(string const &in, string const &key, string const &iv) { EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); EVP_EncryptInit_ex(ctx, md, 0, (unsigned char *)&key[0], (unsigned char *)&iv[0]); cerr << "key len: " << key.length() << ": " << key << '\n'; cerr << "iv len: " << iv.length() << ": " << iv << '\n'; // string ret(in.length() + EVP_MAX_BLOCK_LENGTH, 0); string ret(1000, 0); int buflen; if (!EVP_EncryptUpdate(ctx, (unsigned char *)&ret[0], &buflen, (unsigned char*)&in[0], in.length()) ) return ""; int tmplen; if (!EVP_EncryptFinal_ex(ctx, (unsigned char *)&ret[buflen], &tmplen)) return ""; ret.resize(buflen + tmplen); cerr << "IV: " << hex << setfill('0'); for (unsigned char ch: iv) cerr << setw(2) << static_cast(ch); cerr << '\n'; cerr << "ENCRYPTED: " << hex << setfill('0'); for (unsigned char ch: ret) cerr << setw(2) << static_cast(ch); cerr << '\n'; EVP_CIPHER_CTX_free(ctx); return ret; } string decrypt(string const &in, string const &key, string const &iv) { EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); EVP_DecryptInit_ex(ctx, md, 0, (unsigned char *)&key[0], (unsigned char *)&iv[0]); // string ret(EVP_MAX_BLOCK_LENGTH, 0); string ret(1000, 0); int buflen; if(!EVP_DecryptUpdate(ctx, (unsigned char *)&ret[0], &buflen, (unsigned char *)&in[0], in.length())) return ""; int tmplen; if(!EVP_DecryptFinal_ex(ctx, (unsigned char *)&ret[buflen], &tmplen)) return ""; ret.resize(buflen + tmplen); EVP_CIPHER_CTX_free(ctx); return ret; } int main(int argc, char **argv) { if (argc < 4) { cout << "specify method (1), key (2) and iv (3), opt: text to " "en/decrypt\n"; return 0; } OpenSSL_add_all_ciphers(); if ((md = EVP_get_cipherbyname(argv[1])) == 0) { cout << "method `" << argv[1] << "' not supported\n"; return 1; } string key{ argv[2] }; // {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; string iv{ argv[3] }; // {1,2,3,4,5,6,7,8}; string text; if (argc == 5) text = argv[4]; else { cout << "Enter string to encrypt: "; getline(cin, text); } string encrypted = encrypt(text, key, iv); if (encrypted.length() == 0) { cout << "encryption failed\n"; return 1; } string decrypted = decrypt(encrypted, key, iv); if (encrypted.length() == 0) { cout << "decryption failed\n"; return 1; } cout << "After decryption: " << decrypted << '\n'; } bobcat-5.09.01/eoi/0000755000175000017500000000000014050437223012660 5ustar frankfrankbobcat-5.09.01/eoi/eoi2.cc0000644000175000017500000000040014050437223014017 0ustar frankfrank#include "eoi.ih" namespace FBB { std::ostream &eoi(std::ostream &out) { Eoi *buf = dynamic_cast(out.rdbuf()); if (buf != 0) buf->eoi_(); // call the appropriate return out; } } bobcat-5.09.01/eoi/eoi0000644000175000017500000000134714050437223013364 0ustar frankfrank#ifndef INCLUDED_BOBCAT_EOI_ #define INCLUDED_BOBCAT_EOI_ #include #include #include namespace FBB { class Eoi: public std::streambuf { friend std::ostream &eoi(std::ostream &out); protected: Eoi() = default; private: virtual void eoi_(); // this function implements the actions // 1 // of the eoi-manipulator in derived classes. This allows the // eoi-manipulator to perform only one check, after which it // can call eoi_ to perform the correct eoi actions. // By default it performs no actions at all }; std::ostream &eoi(std::ostream &out); // 2 } // FBB #endif bobcat-5.09.01/eoi/eoi1.cc0000644000175000017500000000004714050437223014025 0ustar frankfrank#include "eoi.ih" void Eoi::eoi_() {} bobcat-5.09.01/eoi/eoi.ih0000644000175000017500000000017314050437223013757 0ustar frankfrank#include "eoi" //#include //#define XERR std::cerr << __FILE__": " using namespace std; using namespace FBB; bobcat-5.09.01/eoibuf/0000755000175000017500000000000014050437223013355 5ustar frankfrankbobcat-5.09.01/eoibuf/eoibuf0000644000175000017500000000202414050437223014547 0ustar frankfrank#ifndef INCLUDED_BOBCAT_EOIBUF_ #define INCLUDED_BOBCAT_EOIBUF_ #include namespace FBB { class EoiBuf: public Eoi { std::string d_buffer; protected: EoiBuf() = default; EoiBuf(size_t size); // 2.f void resize(size_t size); void setp(); void setg(unsigned next, unsigned beyond); // begin is fixed std::string &buffer(); size_t bufSize() const; unsigned char *ucharPtr(); // 1.f unsigned char const *ucharPtr() const; // 2.f static unsigned char *ucharPtr(std::string &str); // 3.f static unsigned char const *ucharPtr( // 4.f std::string const &str); }; #include "eoibuf2.f" #include "buffer.f" #include "bufsize.f" #include "resize.f" #include "ucharptr1.f" #include "ucharptr2.f" #include "ucharptr3.f" #include "ucharptr4.f" } // FBB #endif bobcat-5.09.01/eoibuf/eoibuf.ih0000644000175000017500000000007514050437223015152 0ustar frankfrank#include "eoibuf" using namespace std; using namespace FBB; bobcat-5.09.01/eoibuf/ucharptr3.f0000644000175000017500000000017614050437223015443 0ustar frankfrank// static inline unsigned char *EoiBuf::ucharPtr(std::string &str) { return reinterpret_cast(&str[0]); } bobcat-5.09.01/eoibuf/setg.cc0000644000175000017500000000024714050437223014631 0ustar frankfrank#include "eoibuf.ih" void EoiBuf::setg(unsigned next, unsigned beyond) { char *begin = &d_buffer[0]; streambuf::setg(begin, begin + next, begin + beyond); } bobcat-5.09.01/eoibuf/resize.f0000644000175000017500000000010714050437223015023 0ustar frankfrankinline void EoiBuf::resize(size_t size) { d_buffer.resize(size); } bobcat-5.09.01/eoibuf/ucharptr1.f0000644000175000017500000000015114050437223015432 0ustar frankfrankinline unsigned char *EoiBuf::ucharPtr() { return reinterpret_cast(&d_buffer[0]); } bobcat-5.09.01/eoibuf/buffer.f0000644000175000017500000000007614050437223015000 0ustar frankfrankinline std::string &EoiBuf::buffer() { return d_buffer; } bobcat-5.09.01/eoibuf/bufsize.f0000644000175000017500000000011014050437223015163 0ustar frankfrankinline size_t EoiBuf::bufSize() const { return d_buffer.length(); } bobcat-5.09.01/eoibuf/ucharptr4.f0000644000175000017500000000022014050437223015432 0ustar frankfrank// static inline unsigned char const *EoiBuf::ucharPtr(std::string const &str) { return reinterpret_cast(&str[0]); } bobcat-5.09.01/eoibuf/eoibuf2.f0000644000175000017500000000010214050437223015050 0ustar frankfrankinline EoiBuf::EoiBuf(size_t size) : d_buffer(size, 0) {} bobcat-5.09.01/eoibuf/setp.cc0000644000175000017500000000015114050437223014634 0ustar frankfrank#include "eoibuf.ih" void EoiBuf::setp() { streambuf::setp(&*d_buffer.begin(), &*d_buffer.end()); } bobcat-5.09.01/eoibuf/ucharptr2.f0000644000175000017500000000017314050437223015437 0ustar frankfrankinline unsigned char const *EoiBuf::ucharPtr() const { return reinterpret_cast(&d_buffer[0]); } bobcat-5.09.01/exception/0000755000175000017500000000000014050437223014102 5ustar frankfrankbobcat-5.09.01/exception/open3.f0000644000175000017500000000050514050437223015275 0ustar frankfranktemplate void Exception::open(StreamType &stream, std::string const &name, std::ios::openmode mode) { if (stream.is_open()) stream.close(); stream.open(name, mode); if (!stream) throw Exception{} << "Can't open `" << name << '\''; } bobcat-5.09.01/exception/data.cc0000644000175000017500000000006014050437223015316 0ustar frankfranknamespace FBB { thread_local int g_errno; } bobcat-5.09.01/exception/exception0000644000175000017500000000735414050437223016034 0ustar frankfrank#ifndef INCLUDED_BOBCAT_EXCEPTION_ #define INCLUDED_BOBCAT_EXCEPTION_ #include #include #include #include #include namespace FBB { extern thread_local int g_errno; class Exception: public std::exception { template friend Exception &&operator<<(Exception &&tmp, Type const &value); std::string d_what; public: enum { STRERROR_BUFSIZE = 100 }; enum Protection { ANY, EQUAL }; Exception(); // exception.f explicit Exception(int errnoValue); // exception1.cc ~Exception() noexcept(true) override; static size_t protection(std::string const &name, size_t protect, Protection type = EQUAL); template static StreamType factory(std::string const &name); // factory1.f template static StreamType factory(int errnoValue, // factory2.f std::string const &name); template static StreamType factory(std::string const &name, // factory3.f std::ios::openmode mode); template static StreamType factory(int errnoValue, // factory4.f std::string const &name, std::ios::openmode mode); template static StreamType factory(std::string const &name, // factory5.f std::ios::openmode mode1, std::ios::openmode mode2); template static StreamType factory(int errnoValue, // factory6.f std::string const &name, std::ios::openmode mode1, std::ios::openmode mode2); template static void open(StreamType &stream, // open1.f std::string const &name); template static void open(int errnoValue, StreamType &stream, // open2.f std::string const &name); template static void open(StreamType &stream, // open3.f std::string const &name, std::ios::openmode mode); template static void open(int errnoValue, StreamType &stream, // open4.f std::string const &name, std::ios::openmode mode); template static void open(StreamType &stream, // open5.f std::string const &name, std::ios::openmode mode1, std::ios::openmode mode2); template static void open(int errnoValue, StreamType &stream, // open6.f std::string const &name, std::ios::openmode mode1, std::ios::openmode mode2); private: char const *what() const noexcept(true) override; }; #include "exception.f" #include "open1.f" #include "open2.f" #include "open3.f" #include "open4.f" #include "open5.f" #include "open6.f" #include "factory1.f" #include "factory2.f" #include "factory3.f" #include "factory4.f" #include "factory5.f" #include "factory6.f" // Free functions std::ostream &errnodescr(std::ostream &out); #include "opinsert.f" // Exception << Type } // FBB #endif bobcat-5.09.01/exception/errnodescr.cc0000644000175000017500000000070414050437223016560 0ustar frankfrank#include "exception.ih" namespace FBB { std::ostream &errnodescr(std::ostream &out) { if (errno != 0) { char *buffer = new char[Exception::STRERROR_BUFSIZE]; if (char *cp = strerror_r(errno, buffer, Exception::STRERROR_BUFSIZE)) out << cp; else { out << "internal error: strerror_r failed with errno = " << errno; } delete[] buffer; } return out; } } // FBB bobcat-5.09.01/exception/opinsert.f0000644000175000017500000000030614050437223016113 0ustar frankfranktemplate inline Exception &&operator<<(Exception &&tmp, Type const &value) { std::ostringstream out; out << value; tmp.d_what += out.str(); return std::move(tmp); } bobcat-5.09.01/exception/open2.f0000644000175000017500000000045514050437223015300 0ustar frankfranktemplate void Exception::open(int errnoValue, StreamType &stream, std::string const &name) { if (stream.is_open()) stream.close(); stream.open(name); if (!stream) throw Exception{errnoValue} << "Can't open `" << name << '\''; } bobcat-5.09.01/exception/exception.f0000644000175000017500000000006314050437223016246 0ustar frankfrankinline Exception::Exception() { g_errno = 0; } bobcat-5.09.01/exception/factory3.f0000644000175000017500000000044414050437223016005 0ustar frankfranktemplate StreamType Exception::factory(std::string const &name, std::ios::openmode mode) { StreamType stream{ name, mode }; if (!stream) throw Exception{} << "Can't open `" << name << '\''; return stream; } bobcat-5.09.01/exception/factory1.f0000644000175000017500000000034714050437223016005 0ustar frankfranktemplate StreamType Exception::factory(std::string const &name) { StreamType stream{ name }; if (!stream) throw Exception{} << "Can't open `" << name << '\''; return stream; } bobcat-5.09.01/exception/exception.ih0000644000175000017500000000027314050437223016424 0ustar frankfrank#include "exception" #include #include #include #include #include #include using namespace std; using namespace FBB; bobcat-5.09.01/exception/open6.f0000644000175000017500000000072514050437223015304 0ustar frankfranktemplate void Exception::open(int errnoValue, StreamType &stream, std::string const &name, std::ios::openmode mode1, std::ios::openmode mode2) { if (stream.is_open()) stream.close(); stream.open(name, mode1); if (!stream) { stream.clear(); stream.open(name, mode2); } if (!stream) throw Exception{errnoValue} << "Can't open `" << name << '\''; } bobcat-5.09.01/exception/open1.f0000644000175000017500000000041014050437223015266 0ustar frankfranktemplate void Exception::open(StreamType &stream, std::string const &name) { if (stream.is_open()) stream.close(); stream.open(name); if (!stream) throw Exception{} << "Can't open `" << name << '\''; } bobcat-5.09.01/exception/protection.cc0000644000175000017500000000252414050437223016602 0ustar frankfrank#include "exception.ih" size_t Exception::protection(std::string const &name, size_t protect, Protection type) { if (protect > 0777) throw Exception{} << "Protection for `" << name << "' " "may not exceed 0777 (requested: 0" << oct << protect << dec << ')'; struct stat statbuf; // no: create it with the requested protection if (stat(name.c_str(), &statbuf) != 0) // bits { if (errno != ENOENT) // stat error, but not non-existing file throw Exception{} << "Cannot obtain details about `" << name << '\''; int fd = ::open(name.c_str(), O_CREAT, protect); if (fd < 0) throw Exception{} << "Can't create 0" << oct << protect << dec << ' ' << name; close(fd); return protect; } size_t mode = statbuf.st_mode & 07777; // get the actual mode if (type == EQUAL && mode != protect) throw Exception{} << "Protection of `" << name << "' (0" << oct << mode << ") differs from required 0" << protect; return mode; } bobcat-5.09.01/exception/what.cc0000644000175000017500000000015314050437223015353 0ustar frankfrank#include "exception.ih" char const *Exception::what() const noexcept(true) { return d_what.c_str(); } bobcat-5.09.01/exception/factory2.f0000644000175000017500000000040114050437223015775 0ustar frankfranktemplate StreamType Exception::factory(int errnoValue, std::string const &name) { StreamType stream{ name }; if (!stream) throw Exception{errnoValue} << "Can't open `" << name << '\''; return stream; } bobcat-5.09.01/exception/factory6.f0000644000175000017500000000066714050437223016017 0ustar frankfranktemplate StreamType Exception::factory(int errnoValue, std::string const &name, std::ios::openmode mode1, std::ios::openmode mode2) { StreamType ret{ name, mode1 }; if (not ret) { ret.clear(); ret.open(name, mode2); } if (!ret) throw Exception{errnoValue} << "Can't open `" << name << '\''; return ret; } bobcat-5.09.01/exception/open4.f0000644000175000017500000000052114050437223015274 0ustar frankfranktemplate void Exception::open(int errnoValue, StreamType &stream, std::string const &name, std::ios::openmode mode) { if (stream.is_open()) stream.close(); stream.open(name, mode); if (!stream) throw Exception{ errnoValue } << "Can't open `" << name << '\''; } bobcat-5.09.01/exception/open5.f0000644000175000017500000000064514050437223015304 0ustar frankfranktemplate void Exception::open(StreamType &stream, std::string const &name, std::ios::openmode mode1, std::ios::openmode mode2) { if (stream.is_open()) stream.close(); stream.open(name, mode1); if (!stream) { stream.clear(); stream.open(name, mode2); } if (!stream) throw Exception{} << "Can't open `" << name << '\''; } bobcat-5.09.01/exception/destructor.cc0000644000175000017500000000010314050437223016601 0ustar frankfrank#include "exception.ih" Exception::~Exception() noexcept(true) {} bobcat-5.09.01/exception/exception1.cc0000644000175000017500000000014414050437223016467 0ustar frankfrank#include "exception.ih" Exception::Exception(int errnoValue) { g_errno = errno = errnoValue; } bobcat-5.09.01/exception/factory4.f0000644000175000017500000000047614050437223016013 0ustar frankfranktemplate StreamType Exception::factory(int errnoValue, std::string const &name, std::ios::openmode mode) { StreamType stream{ name, mode }; if (!stream) throw Exception{errnoValue} << "Can't open `" << name << '\''; return stream; } bobcat-5.09.01/exception/driver/0000755000175000017500000000000014050437223015375 5ustar frankfrankbobcat-5.09.01/exception/driver/build0000755000175000017500000000077614050437223016434 0ustar frankfrank#!/bin/bash tput clear GPP="g++ --std=c++17" # CMD="$GPP -o driver -Wall -I../ driver.cc -L../tmp -lerrno -lbobcat -s" # CMD="$GPP -o driver -Wall -I../../tmp driver.cc -L../../tmp/lib -lbobcat -s" # CMD="$GPP -o driver -Wall -I../ driver.cc -L../tmp -lerrno -s" # CMD="$GPP -o driver -Wall *.cc ../*.cc -s" CMD="$GPP -o driver -Wall *.cc -lbobcat -s" # system bobcat library CMD="$GPP -o driver -Wall *.cc -L../tmp -lexception -s" # local exception lib echo $CMD $CMD || exit 1 echo Ready... driver bobcat-5.09.01/exception/driver/driver.cc0000644000175000017500000000331314050437223017177 0ustar frankfrank#include #include "../exception" #include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) { string hello = "hello world"; try { try { // throw exception in which data of // various types were inserted throw Exception() << hello << ' ' << 12.34 << "..."; } catch(exception const &e) { cerr << "first: " << e.what() << '\n'; throw; // may be rethrown, which is standard } } catch(exception const &e) { cout << "second: exception caught: " << e.what() << '\n'; } try { // throw exception in which data of // various types were inserted throw Exception(5) << "third: exception with errno value set"; } catch(exception const &e) { cerr << "fourth: " << e.what() << '\n' << "Exception == " << errno << '\n'; } try { ofstream out; Exception::open(out, "out"); Exception::open(out, ""); } catch(exception const &e) { cout << "fifth: " << e.what() << '\n'; } try { ofstream out; Exception::open(out, "out", ios::in | ios::out); } catch(exception const &e) { cout << "sixth: " << e.what() << '\n'; } try { throw Exception(E2BIG) << "Error: " << FBB::errnodescr; } catch(exception const &e) { cout << "eighth: " << e.what() << '\n'; } cout << "end of program\n"; } bobcat-5.09.01/exception/factory5.f0000644000175000017500000000063514050437223016011 0ustar frankfranktemplate StreamType Exception::factory(std::string const &name, std::ios::openmode mode1, std::ios::openmode mode2) { StreamType ret{ name, mode1 }; if (not ret) { ret.clear(); ret.open(name, mode2); } if (!ret) throw Exception{} << "Can't open `" << name << '\''; return ret; } bobcat-5.09.01/exec/0000755000175000017500000000000014050437223013030 5ustar frankfrankbobcat-5.09.01/exec/exec.ih0000644000175000017500000000024214050437223014274 0ustar frankfrank#include "exec" #include #include #include "../exception/exception" #include "../string/string" using namespace std; using namespace FBB; bobcat-5.09.01/exec/childprocess.cc0000644000175000017500000000037214050437223016023 0ustar frankfrank#include "exec.ih" void Exec::childProcess() { vector words = splitSource(); execv(words[0].c_str(), const_cast(String::argv(words))); throw Exception{} << "childprocess `" << d_cmd << "' failed"; } bobcat-5.09.01/exec/execute.cc0000644000175000017500000000016714050437223015005 0ustar frankfrank#include "exec.ih" bool Exec::execute(std::string const &cmd) { d_cmd = cmd; fork(); return d_ret == 0; } bobcat-5.09.01/exec/splitsource.cc0000644000175000017500000000020014050437223015703 0ustar frankfrank#include "exec.ih" vector Exec::splitSource() const { String::Type type; return String::split(&type, d_cmd); } bobcat-5.09.01/exec/exec0000644000175000017500000000160214050437223013676 0ustar frankfrank#ifndef INCLUDED_BOBCAT_EXEC_ #define INCLUDED_BOBCAT_EXEC_ #include #include #include namespace FBB { namespace IUO { struct CloseMode { enum StdMode { CLOSE_STD }; }; } class Exec: public Fork { std::string d_cmd; int d_ret = -1; public: bool execute(std::string const &cmd); int ret() const; protected: static void noClose(); int setRet(int retVal); private: std::vector splitSource() const; void childProcess() override; void parentProcess() override; }; inline void Exec::noClose() // static {} inline int Exec::ret() const { return d_ret; } inline int Exec::setRet(int retVal) { return d_ret = retVal; } inline void Exec::parentProcess() { d_ret = waitForChild(); } } // namespace FBB #endif bobcat-5.09.01/exec/driver/0000755000175000017500000000000014050437223014323 5ustar frankfrankbobcat-5.09.01/exec/driver/build0000755000175000017500000000010614050437223015345 0ustar frankfrank#!/bin/bash g++ `cat ../../c++std` -Wall -odriver driver.cc -lbobcat bobcat-5.09.01/exec/driver/driver.cc0000644000175000017500000000072514050437223016131 0ustar frankfrank#include #include using namespace std; using namespace FBB; int main() { ExecFork ef; if (ef.execute("/bin/cp driver.cc /tmp")) cout << "driver.cc now copied to /tmp\n"; else cout << "could not copy driver.cc to /tmp\n"; cout << "Again:\n"; if (ef.execute("/bin/cp driver.cc /tmp")) cout << "driver.cc now copied to /tmp\n"; else cout << "could not copy driver.cc to /tmp\n"; } bobcat-5.09.01/extractorbase/0000755000175000017500000000000014050437223014752 5ustar frankfrankbobcat-5.09.01/extractorbase/execute.cc0000644000175000017500000000020714050437223016722 0ustar frankfrank#include "extractorbase.ih" void ExtractorBase::execute(string const &cmd) { d_iChildOutPipe = Pipe{}; Exec::execute(cmd); } bobcat-5.09.01/extractorbase/extractorbase1.cc0000644000175000017500000000017214050437223020210 0ustar frankfrank#include "extractorbase.ih" ExtractorBase::ExtractorBase(size_t bufSize) : istream(this), d_bufSize(bufSize) {} bobcat-5.09.01/extractorbase/extractorbase.ih0000644000175000017500000000015614050437223020144 0ustar frankfrank#include "extractorbase" #include using namespace std; using namespace FBB; using namespace IUO; bobcat-5.09.01/extractorbase/extractorbase0000644000175000017500000000154314050437223017546 0ustar frankfrank#ifndef INCLUDED_BOBCAT_EXTRACTORFORK_ #define INCLUDED_BOBCAT_EXTRACTORFORK_ #include #include #include #include namespace FBB { namespace IUO { class ExtractorBase: public CloseMode, protected Exec, private IFdBuf, public std::istream { // the child process inserts into the pipe, size_t d_bufSize; Pipe d_iChildOutPipe; // cout written by the CHILD public: ExtractorBase(size_t bufSize = 100); void execute(std::string const &cmd); using FBB::Exec::ret; protected: Pipe &childOutPipe(); private: void parentRedirections() override; }; inline Pipe &ExtractorBase::childOutPipe() { return d_iChildOutPipe; } } // namespace IUO } // namespace FBB #endif bobcat-5.09.01/extractorbase/parentredirections.cc0000644000175000017500000000021614050437223021164 0ustar frankfrank#include "extractorbase.ih" void ExtractorBase::parentRedirections() { reset(d_iChildOutPipe.readOnly(), IFdBuf::CLOSE_FD, d_bufSize); } bobcat-5.09.01/fbb/0000755000175000017500000000000014050437223012635 5ustar frankfrankbobcat-5.09.01/fbb/fbb.ih0000644000175000017500000000007214050437223013707 0ustar frankfrank#include "fbb" using namespace std; using namespace FBB; bobcat-5.09.01/fbb/fbb0000644000175000017500000000026614050437223013315 0ustar frankfrank#ifndef INCLUDED_BOBCAT_FBB_ #define INCLUDED_BOBCAT_FBB_ namespace FBB { enum CryptType { DECRYPT, ENCRYPT, DECODE = DECRYPT, ENCODE }; } // FBB #endif bobcat-5.09.01/field/0000755000175000017500000000000014050437223013167 5ustar frankfrankbobcat-5.09.01/field/field0000644000175000017500000000125714050437223014202 0ustar frankfrank#ifndef INCLUDED_BOBCAT_FIELD_ #define INCLUDED_BOBCAT_FIELD_ #include #include namespace FBB { template struct Field { static_assert(base >= 2, "Field: 'base' must be >= 2"); static_assert(begin < end, "Field: 'end' must be > 'begin'"); static constexpr uint64_t set(uint64_t src, uint64_t value); static constexpr uint64_t get(uint64_t value); }; #include "fieldtype.f" #include "get.f" #include "set.f" #include "exp1.f" #include "exp2.f" #include "get0.f" #include "set0.f" #include "get1.f" #include "set1.f" } // FBB #endif bobcat-5.09.01/field/fieldtype.f0000644000175000017500000000102714050437223015323 0ustar frankfranktemplate struct FieldType { static constexpr uint64_t set(uint64_t src, uint64_t value); // 0.f static constexpr uint64_t get(uint64_t value); // 0.f }; // handle get/set if base is a pure power of 2: // template struct FieldType<1, base, end, begin> { static constexpr uint64_t set(uint64_t src, uint64_t value); // 1.f static constexpr uint64_t get(uint64_t value); // 1.f }; bobcat-5.09.01/field/set.f0000644000175000017500000000053214050437223014131 0ustar frankfranktemplate inline uint64_t constexpr Field::set(uint64_t src, uint64_t value) { return FieldType<((base - 1) & base) == 0, base, end, begin>::set(src, value); } bobcat-5.09.01/field/exp1.f0000644000175000017500000000032614050437223014214 0ustar frankfranktemplate struct exp1 { enum { value = base * exp1::value }; }; template struct exp1 { enum { value = 1 }; }; bobcat-5.09.01/field/exp2.f0000644000175000017500000000026114050437223014213 0ustar frankfranktemplate struct exp2 { enum { value = 1 + exp2::value }; }; template <> struct exp2<1> { enum { value = 0 }; }; bobcat-5.09.01/field/set0.f0000644000175000017500000000114314050437223014210 0ustar frankfranktemplate inline uint64_t constexpr FieldType::set(uint64_t src, uint64_t value) { // value is: | A | B | C // e b return src / exp1::value // src: A -> * exp1::value + // A | ... | ... value % exp1::value // value % b..e -> B * exp1::value + // ... | B | ... src % exp1::value; // ... | ... | C } bobcat-5.09.01/field/get.f0000644000175000017500000000031214050437223014111 0ustar frankfranktemplate inline uint64_t constexpr Field::get(uint64_t value) { return FieldType<((base - 1) & base) == 0, base, end, begin>::get(value); } bobcat-5.09.01/field/field.ih0000644000175000017500000000007514050437223014576 0ustar frankfrank#include "field" using namespace std; using namespace FBB; bobcat-5.09.01/field/get0.f0000644000175000017500000000036714050437223014203 0ustar frankfranktemplate inline uint64_t constexpr FieldType::get(uint64_t value) { return value / exp1::value % exp1::value; } bobcat-5.09.01/field/get1.f0000644000175000017500000000035014050437223014174 0ustar frankfranktemplate inline uint64_t constexpr FieldType<1, base, end, begin>::get(uint64_t value) { return (value & ((1 << end * exp2::value) - 1)) >> (begin * exp2::value); } bobcat-5.09.01/field/set1.f0000644000175000017500000000223414050437223014213 0ustar frankfranktemplate inline uint64_t constexpr FieldType<1, base, end, begin>::set(uint64_t src, uint64_t value) { // consider src as | C | B | A | // e b return ( src & ( ~( // all C bits ( (1 << end * exp2::value) - 1 // (all B, A bits) ) ) | // and also: ( (1 << begin * exp2::value) - 1 // all A bits ) ) ) | // and also: ( ( value & ( // # bits from b..e (1 << (end - begin) * exp2::value) - 1 ) ) // value's at most b..e bits << (begin * exp2::value) // moved into b's offset ); } bobcat-5.09.01/field/driver/0000755000175000017500000000000014050437223014462 5ustar frankfrankbobcat-5.09.01/field/driver/main.cc0000644000175000017500000000137014050437223015716 0ustar frankfrank#include #include "../field" using namespace std; using namespace FBB; int main() { cout << Field<10, 3, 1>::get(12345) << " <- 34\n"; cout << Field<10, 2, 0>::get(12345) << " <- 45\n"; cout << Field<10, 3, 1>::set(12345, 99) << " <- 12995\n"; cout << Field<10, 2, 0>::set(12345, 999) << " <- 12399\n"; cout << hex; cout << Field<16, 3, 1>::get(0xabcd) << " <- bc\n"; cout << Field<16, 2, 0>::get(0xabcd) << " <- cd\n"; cout << Field<16, 3, 1>::set(0xabcd, 0x11) << " <- a11d\n"; cout << Field<16, 2, 0>::set(0xabcd, 0x222) << " <- ab22\n"; cout << oct; cout << Field<8, 3, 1>::get(076543) << " <- 54\n"; cout << Field<8, 2, 0>::get(076543) << " <- 43\n"; } bobcat-5.09.01/fmt/0000755000175000017500000000000014050437223012672 5ustar frankfrankbobcat-5.09.01/fmt/left2.f0000644000175000017500000000022614050437223014055 0ustar frankfrankinline FMT left(std::string const &size, unsigned precision = ~0U) { return { FMT::LEFT, static_cast(size.length()), precision, 1 }; } bobcat-5.09.01/fmt/fmt3.f0000644000175000017500000000010314050437223013704 0ustar frankfrankinline FMT::FMT(unsigned nCols) : FMT(HLINE, 0, ~0U, nCols) {} bobcat-5.09.01/fmt/join1.cc0000644000175000017500000000051114050437223014216 0ustar frankfrank//#define XERR #include "fmt.ih" // handles, e.g., join(3, FMT::left, precision) // when inserting width in fact is precision FMT FBB::join(unsigned nCols, FMT::Align align, unsigned precision) { FMT::lrcFun(align); // ensure the correct alignment request return { align, precision, 0, nCols }; } bobcat-5.09.01/fmt/data.cc0000644000175000017500000000041014050437223014105 0ustar frankfrank//#define XERR #include "fmt.ih" char const *FMT::s_align[] = // follows the Align enum values { "unused", "center", "hline", "left", "right", }; FMT::FMTFun FMT::s_lrcFun[] = { 0, center, 0, left, right, }; bobcat-5.09.01/fmt/fmt0000644000175000017500000000712114050437223013404 0ustar frankfrank#ifndef INCLUDED_BOBCAT_FMT_ #define INCLUDED_BOBCAT_FMT_ #include #include namespace FBB { struct FMT { // update s_align (data.cc) enum Align // when this enum is altered { UNUSED, // extraFMT's d_align is not used // when an ios_base manipulator // has just been inserted. CENTER, // FMTFunCH HLINE, LEFT, // FMTFunLR RIGHT, }; typedef FMT (*FMTFun)(unsigned, unsigned); typedef FMT (*FMTHline)(unsigned); friend class CSVTabDef; friend class CSVTabIns; friend std::ostream &operator<<(std::ostream &out, FMT const &fmt); // when inserting and used with arguments the current column fmt // is altered for that insertion, when defining: the next column // is defined as specified. // When used without arguments and inserting then the alignment // of then next column is altered as specified. Instead of // FBB::left and FBB::right std::left and std::right can also be // used. friend FMT center(unsigned width, unsigned precision); // 1.f friend FMT left(unsigned width, unsigned precision); // 1.f friend FMT right(unsigned width, unsigned precision); // 1.f friend FMT center(std::string const &width, unsigned precision); // 2.f friend FMT left(std::string const &width, unsigned precision); // 2.f friend FMT right(std::string const &width, unsigned precision); // 2.f friend FMT hline(unsigned nCols); // when inserting: // the next nCols (not exceeding d_format.size()) are formatted // as specified by fun, using precision ~0U // omit 'nCols' to join all remaining columns friend FMT join(unsigned nCols, Align align, unsigned precision); private: Align d_align; unsigned d_width = 1; // width of a single column (nCols == 1) // if <= d_width then precision is also unsigned d_precision = ~0U; // used // if > 1: use the widths of subsequent cols unsigned d_nCols = 1; // + the width of in =-between separators static char const *s_align[]; // Align labels static FMTFun s_lrcFun[]; // L,R,C function given Align spec public: Align align() const; unsigned width() const; unsigned precision() const; unsigned nCols() const; static FMTFun lrcFun(Align align); static char const *align(Align value); private: FMT() = default; FMT(Align align, unsigned width, unsigned precision, // 1.cc unsigned nCols = 1); std::ostream &insert(std::ostream &out) const; }; #include "align1.f" #include "width1.f" #include "precision.f" #include "ncols.f" #include "insert.f" #include "align2.f" #include "opinsert.f" #include "hline.f" // when inserting d_size specifies the precision and // d_precision is copied from d_format[d_idx].d_precision // when defining, 'size' is the width #include "center1.f" #include "left1.f" #include "right1.f" #include "center2.f" #include "left2.f" #include "right2.f" FMT join(unsigned nCols, FMT::Align align, unsigned precision = ~0U); // 1.cc #include "join2.f" } // FBB #endif bobcat-5.09.01/fmt/opinsert.f0000644000175000017500000000014314050437223014702 0ustar frankfrankinline std::ostream &operator<<(std::ostream &out, FMT const &fmt) { return fmt.insert(out); } bobcat-5.09.01/fmt/hline.f0000644000175000017500000000015014050437223014134 0ustar frankfrankinline FMT hline(unsigned nCols = ~0U) { return { FMT::HLINE, 0, ~0U, nCols == 0 ? 1 : nCols }; } bobcat-5.09.01/fmt/lrcfun.cc0000644000175000017500000000040414050437223014470 0ustar frankfrank//#define XERR #include "fmt.ih" // static FMT::FMTFun FMT::lrcFun(Align align) { FMTFun ret = s_lrcFun[align]; if (ret == 0) throw Exception{} << "Alignment must be FMT::LEFT, FMT::RIGHT, or FMT::CENTER"; return ret; } bobcat-5.09.01/fmt/precision.f0000644000175000017500000000010314050437223015026 0ustar frankfrankinline unsigned FMT::precision() const { return d_precision; } bobcat-5.09.01/fmt/center2.f0000644000175000017500000000026414050437223014405 0ustar frankfrankinline FMT center(std::string const &size, unsigned precision = ~0U) { return { FMT::CENTER, static_cast(size.length()), precision, 1 }; } bobcat-5.09.01/fmt/left1.f0000644000175000017500000000015414050437223014054 0ustar frankfrankinline FMT left(unsigned size, unsigned precision = ~0U) { return { FMT::LEFT, size, precision, 1 }; } bobcat-5.09.01/fmt/align1.f0000644000175000017500000000007514050437223014216 0ustar frankfrankinline FMT::Align FMT::align() const { return d_align; } bobcat-5.09.01/fmt/fmt2.f0000644000175000017500000000016114050437223013707 0ustar frankfrankinline FMT::FMT(unsigned width, unsigned precision, unsigned nCols) : FMT(RIGHT, width, precision, nCols) {} bobcat-5.09.01/fmt/ncols.f0000644000175000017500000000007314050437223014157 0ustar frankfrankinline unsigned FMT::nCols() const { return d_nCols; } bobcat-5.09.01/fmt/fmt1.cc0000644000175000017500000000035214050437223014050 0ustar frankfrank//#define XERR #include "fmt.ih" FMT::FMT(Align align, unsigned width, unsigned precision, unsigned nCols) : d_align(align), d_width(width == 0 ? 1 : width), d_precision(precision), d_nCols(nCols == 0 ? 1 : nCols) {} bobcat-5.09.01/fmt/fmt.ih0000644000175000017500000000016214050437223014001 0ustar frankfrank#include "fmt" #include "../xerr/xerr.ih" #include using namespace std; using namespace FBB; bobcat-5.09.01/fmt/align2.f0000644000175000017500000000013114050437223014210 0ustar frankfrank// static inline char const *FMT::align(FMT::Align value) { return s_align[value]; } bobcat-5.09.01/fmt/width2.f0000644000175000017500000000010314050437223014234 0ustar frankfrankinline void FMT::width(unsigned nChars) { d_width = nChars; } bobcat-5.09.01/fmt/width1.f0000644000175000017500000000007314050437223014241 0ustar frankfrankinline unsigned FMT::width() const { return d_width; } bobcat-5.09.01/fmt/insert.f0000644000175000017500000000041314050437223014343 0ustar frankfrankinline std::ostream &FMT::insert(std::ostream &out) const { return out << "align: " << s_align[d_align] << ", width: " << d_width << ", precision: " << static_cast(d_precision) << ", nCols: " << d_nCols; } bobcat-5.09.01/fmt/center1.f0000644000175000017500000000016014050437223014377 0ustar frankfrankinline FMT center(unsigned size, unsigned precision = ~0U) { return { FMT::CENTER, size, precision, 1 }; } bobcat-5.09.01/fmt/right2.f0000644000175000017500000000023014050437223014233 0ustar frankfrankinline FMT right(std::string const &size, unsigned precision = ~0U) { return { FMT::RIGHT, static_cast(size.length()), precision, 1 }; } bobcat-5.09.01/fmt/right1.f0000644000175000017500000000015614050437223014241 0ustar frankfrankinline FMT right(unsigned size, unsigned precision = ~0U) { return { FMT::RIGHT, size, precision, 1 }; } bobcat-5.09.01/fmt/join2.f0000644000175000017500000000021414050437223014057 0ustar frankfrank // join all remaining columns inline FMT join(FMT::Align align, unsigned precision = ~0U) { return join(~0U, align, precision); } bobcat-5.09.01/fork/0000755000175000017500000000000014050437223013045 5ustar frankfrankbobcat-5.09.01/fork/preparedaemon2.cc0000644000175000017500000000110514050437223016255 0ustar frankfrank#include "fork.ih" void Fork::prepareDaemon(string const &out, string const &err, mode_t mode) const { if (chdir("/") < 0) // free up mount points throw Exception{} << "Fork::prepareDaemon: chdir(\"/\") failed\n"; setsid(); // create new session/process group ::close(STDIN_FILENO); // close and reopen std file descriptors ::close(STDOUT_FILENO); ::close(STDERR_FILENO); open("/dev/null", O_RDONLY); // reopen stdin reopen(out, mode); reopen(err, mode); } bobcat-5.09.01/fork/fork.ih0000644000175000017500000000033314050437223014327 0ustar frankfrank#include "fork" #include #include #include #include #include #include #include "../exception/exception" using namespace std; using namespace FBB; bobcat-5.09.01/fork/preparedaemon.cc0000644000175000017500000000103614050437223016176 0ustar frankfrank#include "fork.ih" void Fork::prepareDaemon() const { if (chdir("/") < 0) // free up mount points throw Exception{} << "Fork::prepareDaemon: chdir(\"/\") failed\n"; setsid(); // create new session/process group ::close(STDIN_FILENO); // close and reopen std file descriptors ::close(STDOUT_FILENO); ::close(STDERR_FILENO); open("/dev/null", O_RDONLY); // reopen stdin open("/dev/null", O_WRONLY); // reopen cout open("/dev/null", O_WRONLY); // reopen cerr } bobcat-5.09.01/fork/forkfork.cc0000644000175000017500000000064214050437223015201 0ustar frankfrank#include "fork.ih" void Fork::fork() { if ((d_pid = ::fork()) < 0) throw Exception{} << "Fork::fork(): " << errnodescr; if (d_pid == 0) // childprocess has pid == 0 { childRedirections(); childProcess(); throw Exception(1); // we shouldn't come here: childProcess should // exit } parentRedirections(); parentProcess(); } bobcat-5.09.01/fork/fork0000644000175000017500000000173214050437223013734 0ustar frankfrank#ifndef INCLUDED_BOBCAT_FORK_ #define INCLUDED_BOBCAT_FORK_ #include #include namespace FBB { class Fork { pid_t d_pid; public: virtual ~Fork(); void fork(); protected: pid_t pid() const; // .f virtual void childRedirections(); // do child redirections virtual void childProcess() = 0; // must be implemented virtual void parentRedirections(); // do parent redirections virtual void parentProcess() = 0; // must be implemented void prepareDaemon() const; // prepares for a daemon void prepareDaemon(std::string const &out, std::string const &err, mode_t mode = 0600) const; int waitForChild(); // returns the status private: static void reopen(std::string const &out, mode_t mode); }; #include "pid.f" } // FBB #endif bobcat-5.09.01/fork/waitforchild.cc0000644000175000017500000000020314050437223016026 0ustar frankfrank#include "fork.ih" int Fork::waitForChild() { int status; waitpid(d_pid, &status, 0); return WEXITSTATUS(status); } bobcat-5.09.01/fork/childredirections.cc0000644000175000017500000000013614050437223017052 0ustar frankfrank#include "fork.ih" void Fork::childRedirections() // do child redirections {} bobcat-5.09.01/fork/parentredirections.cc0000644000175000017500000000014014050437223017253 0ustar frankfrank#include "fork.ih" void Fork::parentRedirections() // do parent redirections {} bobcat-5.09.01/fork/destructor.cc0000644000175000017500000000004514050437223015551 0ustar frankfrank#include "fork.ih" Fork::~Fork() {} bobcat-5.09.01/fork/reopen.cc0000644000175000017500000000046114050437223014645 0ustar frankfrank#include "fork.ih" void Fork::reopen(string const &out, mode_t mode) { if (out.empty()) open("/dev/null", O_RDONLY); // reopen stdout else if (open(out.c_str(), O_CREAT | O_APPEND | O_WRONLY, mode) == -1) throw Exception{} << "Cannot open " << out << ": " << errnodescr; } bobcat-5.09.01/fork/pid.f0000644000175000017500000000006514050437223013771 0ustar frankfrankinline pid_t Fork::pid() const { return d_pid; } bobcat-5.09.01/fork/driver/0000755000175000017500000000000014050437223014340 5ustar frankfrankbobcat-5.09.01/fork/driver/build0000755000175000017500000000005414050437223015364 0ustar frankfrank#!/bin/sh g++ -o driver driver.cc -lbobcat bobcat-5.09.01/fork/driver/driver.cc0000644000175000017500000000141614050437223016144 0ustar frankfrank#include #include #include using namespace std; using namespace FBB; class Background: public Fork { public: void childProcess() override; void parentProcess() override; }; void Background::childProcess() { for (int idx = 0; idx < 3; ++idx) { cout << "Hello world # " << idx << endl; sleep(1); } throw 0; // caught in main() } void Background::parentProcess() { cout << "Waiting for the child process to end...\n" "The child returns value " << waitForChild() << endl; } int main() try { Background bg; bg.fork(); cout << "This is from the parent\n"; } catch(int x) { cout << "The child terminates with: " << x << endl; return x; } bobcat-5.09.01/fork/driver/redirectedchild0000644000175000017500000000340314050437223017401 0ustar frankfrank#include #include #include #include #include #include #include #include #include #include class ChildIO: public FBB::Fork { FBB::Pipe childInput; // child reads this FBB::Pipe childOutput; // child writes this public: void childRedirections() override; void childProcess() override; void parentProcess() override; }; using namespace std; using namespace FBB; void ChildIO::childRedirections() { childInput.readFrom(Redirector::STDIN); childOutput.writtenBy(Redirector::STDOUT); } void ChildIO::childProcess() { // The /bin/cat program replaces the // child process started by Fork::fork() Process process(Process::DIRECT, "/bin/cat"); process.start(); // this point is never reached } void ChildIO::parentProcess() { // Set up the parent's sides of the pipes IFdStream fromChild(childOutput.readOnly()); OFdStream toChild(childInput.writeOnly()); // write lines to the child, read its output string line; while (true) { cout << "? "; line.clear(); getline(cin, line); if (line.empty()) { kill(pid(), SIGTERM); break; } toChild << line << endl; getline(fromChild, line); cout << "Got: " << line << endl; } cout << "The child returns value " << waitForChild() << endl; } int main() try { ChildIO io; io.fork(); return 0; } catch(exception const &exc) { cerr << "Exception: " << exc.what() << endl; } catch(int x) { cout << "The child terminates with: " << x << endl; return x; } bobcat-5.09.01/fswap/0000755000175000017500000000000014050437223013224 5ustar frankfrankbobcat-5.09.01/fswap/fswap.decl.f0000644000175000017500000000032314050437223015417 0ustar frankfrank // declaration of the the class FastSwap: elements of SwapModes types // are swapped using an available swap-function. // template class FSwap; bobcat-5.09.01/fswap/fswap.friends.decl.f0000644000175000017500000000022514050437223017051 0ustar frankfrank#include "fswapfun.friends.f" // class FSwap // template friend class FSwap; bobcat-5.09.01/fswap/fswapbase.imp.f0000644000175000017500000000560314050437223016136 0ustar frankfrank // Raw memory swapping of a block of size bytes // template void FSwapBase::rawswap(FSwapPOD &pod, char *two, int size) { memcpy(pod.d_buffer, pod.d_from, size); memcpy(pod.d_from, two, size); memcpy(two, pod.d_buffer, size); } // shortcuts for reinterpret_casts // template constexpr char *FSwapBase::addr(Type &type) { return reinterpret_cast(&type); } template constexpr char *FSwapBase::addr(Type *type) { return reinterpret_cast(type); } // use specified swap method // template void FSwapBase::explicitSwap(FSwapPOD &pod, FSwapMode &&member) { typedef typename FSwapMode::MemberType MemberType; MemberType &rhsSwap = // stdSwap's address in the rhs object *reinterpret_cast ( addr(member.member()) - addr(pod.d_lhs) // shift wrt lhs, and + // add to addr(pod.d_rhs) // &rhs ); int const shift = pod.d_from - addr(pod.d_lhs); // #bytes from lhs to from // size: #bytes to rawswap // size == 0 happens if the last data member uses std::swap and // also if two subsequent data members usestd::swap int const size = addr(member.member()) - pod.d_from; if (size > 0) rawswap(pod, addr(pod.d_rhs) + shift, size); else if (size < 0) throw std::runtime_error( "fswap: members must be specified in order of declaration"); if (member.mode() == SwapMode::STDSWAP) std::swap(member.member(), rhsSwap); // MemberTypes do std::swap else member.member().swap(rhsSwap); // otherwise: use a swap member pod.d_from = addr(member.member()) + sizeof(MemberType); } // raw swapping up to a specified member // template ReturnType &FSwapBase::preRawSwap(FSwapPOD &pod, Member &&member) { ReturnType *ret = reinterpret_cast ( addr(&member) - addr(pod.d_lhs) // shift wrt lhs, and + // add to addr(pod.d_rhs) // &rhs ); int const shift = pod.d_from - addr(pod.d_lhs); // #bytes from lhs to from // size: #bytes to rawswap // size == 0 happens if the last data member uses std::swap and // also if two subsequent data members usestd::swap int const size = addr(&member) - pod.d_from; if (size > 0) rawswap(pod, addr(pod.d_rhs) + shift, size); else if (size < 0) throw std::runtime_error( "fswap: members must be specified in order of declaration"); pod.d_from = addr(&member) + sizeof(ReturnType); return *ret; } bobcat-5.09.01/fswap/fswap.std.f0000644000175000017500000000075614050437223015314 0ustar frankfrank // STDSWAP by default: Use std::swap on the member at the head of the // list. // template class FSwap, Type, Member, List...>: private FSwapBase { static void swap(FSwapPOD &pod, Member &&member, List ...memberSpecs); #include "fswap.friends.decl.f" }; #include "fswap.std.imp.f" bobcat-5.09.01/fswap/fswappod.imp.f0000644000175000017500000000056314050437223016006 0ustar frankfrank template FSwapPOD::FSwapPOD(char *buffer, char *from, Type &lhs, Type &rhs) : d_buffer(buffer), d_from(from), d_lhs(lhs), d_rhs(rhs) {} template inline FSwapPOD PODfactory(char *buffer, char *from, Type &lhs, Type &rhs) { return FSwapPOD(buffer, from, lhs, rhs); } bobcat-5.09.01/fswap/fswap4.f0000644000175000017500000000016014050437223014574 0ustar frankfranktemplate inline void FSwap::Xch::fswap(Tp &lhs, Tp &rhs) { tswap(lhs, rhs); } bobcat-5.09.01/fswap/fswap.std.imp.f0000644000175000017500000000134014050437223016066 0ustar frankfrank // STDSWAP: Use std::swap on the member at the head of the list. // template void FSwap, Type, Member, List...>:: swap(FSwapPOD &pod, Member &&member, List ...memberSpecs) { typedef typename std::remove_reference::type MemberType; std::swap(member, // std swap `member' and the member preRawSwap( // in the rhs object pod, std::forward(member) ) ); // then do the tail... FSwap, Type, List...>:: swap(pod, std::forward(memberSpecs) ...); } bobcat-5.09.01/fswap/fswap.end.imp.f0000644000175000017500000000063414050437223016047 0ustar frankfrank // End-specialization: nothing more to swap using swap functions: // rawswap anything that's left // template void FSwap::swap(FSwapPOD &pod) { int const shift = pod.d_from - addr(pod.d_lhs); // 'from' location in lhs int const size = sizeof(Type) - shift; // # bytes beyond 'from' rawswap(pod, addr(pod.d_rhs) + shift, size); } bobcat-5.09.01/fswap/fswap6.f0000644000175000017500000000023214050437223014576 0ustar frankfrank // overloaded fswap function swapping pointers // template inline void fswap(Type *&lhs, Type *&rhs) { std::swap(lhs, rhs); } bobcat-5.09.01/fswap/fswap.f0000644000175000017500000000016314050437223014513 0ustar frankfranktemplate void fswap(Type &lhs, Type &rhs) { FSwap::Xch::fswap(lhs, rhs); } bobcat-5.09.01/fswap/fswappod.f0000644000175000017500000000103014050437223015210 0ustar frankfranktemplate class FSwapPOD { friend struct FSwapBase; char *d_buffer; char *d_from; Type &d_lhs; Type &d_rhs; FSwapPOD(char *buffer, char *from, Type &lhs, Type &rhs); // FSwapPOD constructing function // template friend FSwapPOD PODfactory(char *buffer, char *from, Tp &lhs, Tp &rhs); template friend struct FSwap; }; #include "fswappod.imp.f" bobcat-5.09.01/fswap/fswap.std.explicit.f0000644000175000017500000000077614050437223017136 0ustar frankfrank // STDSWAP by default, but an explicit swaptype specification for a member // template class FSwap, Type, FSwapMode, List...>: private FSwapBase { static void swap(FSwapPOD &pod, FSwapMode &&member, List ...memberSpecs); #include "fswap.friends.decl.f" }; #include "fswap.std.explicit.imp.f" bobcat-5.09.01/fswap/fswap1.f0000644000175000017500000000103214050437223014570 0ustar frankfrank // The full fswap function template, requiring an explicit first member // address // template void fswap(First *firstAddr, Type &lhs, Type &rhs, MemberList &&...swapList) { char buffer[sizeof(Type)]; FSwapPOD pod{ PODfactory( buffer, FSwapBase::addr(firstAddr), lhs, rhs ) }; FSwap, Type, MemberList ...>:: swap(pod, std::forward(swapList) ...); } bobcat-5.09.01/fswap/tswap.f0000644000175000017500000000066014050437223014533 0ustar frankfranktemplate void FSwap::tswap(Type &lhs, Type &rhs) { static_assert(sizeof(SwapType) == sizeof(Type), "BOBCAT DESIGN ERROR: " "FSwap::tswap(): sizeof(SwapType) != sizeof(Type)"); SwapType tmp = *reinterpret_cast(&lhs); *reinterpret_cast(&lhs) = *reinterpret_cast(&rhs); *reinterpret_cast(&rhs) = tmp; } bobcat-5.09.01/fswap/fswapfun.friends.f0000644000175000017500000000070214050437223016654 0ustar frankfrank // fswap1.f // template friend void fswap(First *addr, Tp &lhs, Tp &rhs, Lst &&...list); // fswap2.f // template friend void fswap(Tp &lhs, Tp &rhs, Lst &&...list); // fswap3.f // template friend void fswap(Tp &lhs, Tp &rhs); bobcat-5.09.01/fswap/fswap.member.explicit.imp.f0000644000175000017500000000101214050437223020357 0ustar frankfrank // SWAPMEMBER, but an explicit specification for the member at the head // of the list. // template void FSwap, Type, FSwapMode, List...>:: swap(FSwapPOD &pod, FSwapMode &&member, List ...memberSpecs) { explicitSwap(pod, std::forward>(member)); FSwap, Type, List...>:: // do the tail swap(pod, std::forward(memberSpecs) ...); } bobcat-5.09.01/fswap/swapmode.f0000644000175000017500000000021614050437223015211 0ustar frankfrankstruct SwapMode { enum Enum { STDSWAP, SWAPMEMBER }; }; template struct ModeType {}; bobcat-5.09.01/fswap/fswap2.f0000644000175000017500000000063614050437223014602 0ustar frankfrank // the shorter overloaded version, calling fswap1.f with // firstAddr = &lhs, thus not using any shift to the address of the // first data member // template inline void fswap(Type &lhs, Type &rhs, MemberList &&...swapList) { fswap(FSwapBase::addr(lhs), lhs, rhs, std::forward(swapList) ...); } bobcat-5.09.01/fswap/fswapswap.f0000644000175000017500000000036014050437223015405 0ustar frankfranktemplate // how to swap this type? class FSwapSwap { Type &d_member; public: typedef Type type; FSwapSwap(Type &member); Type &member(); }; FSwapSwap< #include "fswapswapimp.f" bobcat-5.09.01/fswap/fswap.member.explicit.f0000644000175000017500000000077314050437223017610 0ustar frankfrank // SWAPMEMBER by default, but an explicit swaptype specification for // the member at the head of the list. // template class FSwap, Type, FSwapMode, List...>: private FSwapBase { static void swap(FSwapPOD &pod, FSwapMode &&member, List ...memberSpecs); #include "fswap.friends.decl.f" }; #include "fswap.member.explicit.imp.f" bobcat-5.09.01/fswap/fswap3.f0000644000175000017500000000044014050437223014574 0ustar frankfrank // traditional fswap operation // template void fswap(Type &lhs, Type &rhs) { char buffer[sizeof(Type)]; FSwapPOD pod{ PODfactory(buffer, FSwapBase::addr(lhs), lhs, rhs)}; FSwapBase::rawswap(pod, FSwapBase::addr(&rhs), sizeof(Type)); } bobcat-5.09.01/fswap/fswapbase.f0000644000175000017500000000171014050437223015345 0ustar frankfrankclass FSwapBase { #include "fswapfun.friends.f" protected: template // swap using memcpy static void rawswap(FSwapPOD &pod, char *two, int size); template static constexpr char *addr(Type &); // does reinterpret_cast template static constexpr char *addr(Type *); // does reinterpret_cast // use specified swap method template static void explicitSwap(FSwapPOD &pod, FSwapMode &&member); // actions before using a // specific swap method template static ReturnType &preRawSwap(FSwapPOD &pod, Member &&member); }; #include "fswapbase.imp.f" bobcat-5.09.01/fswap/fswap.end.f0000644000175000017500000000046414050437223015264 0ustar frankfrank // End-specialization: nothing more to swap using swap functions // but rawswap anything that's left // template class FSwap: private FSwapBase { static void swap(FSwapPOD &pod); #include "fswap.friends.decl.f" }; #include "fswap.end.imp.f" bobcat-5.09.01/fswap/fswapfun.decl.f0000644000175000017500000000063014050437223016131 0ustar frankfrank // fswap1.f // template void fswap(First *firstAddr, Type &lhs, Type &rhs, MemberList &&...swapList); // fswap2.f template inline void fswap(Type &lhs, Type &rhs, MemberList &&...swapList); bobcat-5.09.01/fswap/fswap.member.imp.f0000644000175000017500000000126014050437223016544 0ustar frankfrank // SWAPMEMBER: Use member.swap() on the member at the head of the list. // template void FSwap, Type, Member, List...>:: swap(FSwapPOD &pod, Member &&member, List ...memberSpecs) { typedef typename std::remove_reference::type MemberType; member.swap( // use the swap member with the // member in the rhs object preRawSwap(pod, std::forward(member)) ); FSwap, Type, List...>:: // then do the tail swap(pod, std::forward(memberSpecs) ...); } bobcat-5.09.01/fswap/fswap.std.explicit.imp.f0000644000175000017500000000100114050437223017700 0ustar frankfrank // STDSWAP, but an explicit specification for the member at the head // of the list. // template void FSwap, Type, FSwapMode, List...>:: swap(FSwapPOD &pod, FSwapMode &&member, List ...memberSpecs) { explicitSwap(pod, std::forward>(member)); FSwap, Type, List...>:: // do the tail swap(pod, std::forward(memberSpecs) ...); } bobcat-5.09.01/fswap/fswaptype.imp.f0000644000175000017500000000122714050437223016203 0ustar frankfrank template FSwapMode::FSwapMode(SwapMode::Enum mode, Type &member) : d_mode(mode), d_member(member) {} template inline SwapMode::Enum FSwapMode::mode() const { return d_mode; } template inline Type &FSwapMode::member() const { return d_member; } template inline FSwapMode stdswap(Type &member) { return typename FSwapMode::FSwapMode(SwapMode::STDSWAP, member); } template inline FSwapMode swapmember(Type &member) { return typename FSwapMode::FSwapMode(SwapMode::SWAPMEMBER, member); } bobcat-5.09.01/fswap/fswap0000644000175000017500000000272714050437223014277 0ustar frankfrank#ifndef INCLUDED_BOBCAT_FSWAP_ #define INCLUDED_BOBCAT_FSWAP_ #include #include #include namespace FBB { #include "swapmode.f" // specific swap modes #include "fswapfun.decl.f" // dclare fswap() functions with default // arguments #include "fswappod.f" // swap plain old data #include "fswaptype.f" // how to swap using specific swapmodes // (stdswap(member), swapmember(member)) #include "fswapbase.f" // utility functions for FSwap classes #include "fswap.decl.f" // class FSwap declaration #include "fswap.end.f" // end-specialization (no SwapModes) #include "fswap.std.f" // do std::swap for the head of the list #include "fswap.std.explicit.f" // do std::swap by default, but explicit // swap for the head of the list #include "fswap.member.f" // do .swap() for the head of the list #include "fswap.member.explicit.f" // do .swap() by default, but explicit // swap for the head of the list #include "fswap1.f" // fswap's full implementation #include "fswap2.f" // the shortcut w/o 1st address #include "fswap3.f" // the direct memory swap #include "fswap6.f" // the overload swapping pointers } // namespace FBB #endif bobcat-5.09.01/fswap/fswap.member.f0000644000175000017500000000074514050437223015767 0ustar frankfrank // SWAPMEMBER by default: Use member.swap at the head of the list. // template class FSwap, Type, Member, List...>: private FSwapBase { static void swap(FSwapPOD &pod, Member &&member, List ...memberSpecs); #include "fswap.friends.decl.f" }; #include "fswap.member.imp.f" bobcat-5.09.01/fswap/fswap5.f0000644000175000017500000000016014050437223014575 0ustar frankfranktemplate inline void FSwap::Xch::fswap(Tp &lhs, Tp &rhs) { tswap(lhs, rhs); } bobcat-5.09.01/fswap/fswaptype.f0000644000175000017500000000110114050437223015406 0ustar frankfranktemplate class FSwapMode { SwapMode::Enum d_mode; Type &d_member; public: typedef Type MemberType; FSwapMode(SwapMode::Enum mode, Type &member); SwapMode::Enum mode() const; Type &member() const; }; // FSwapMode constructing functions: // for std::swap // template inline FSwapMode stdswap(Type &member); // for .swap() members // template inline FSwapMode swapmember(Type &member); #include "fswaptype.imp.f" bobcat-5.09.01/fswap/driver/0000755000175000017500000000000014050437223014517 5ustar frankfrankbobcat-5.09.01/fswap/driver/driver.cc0000644000175000017500000000653214050437223016327 0ustar frankfrank#include #include "../fswap" using namespace FBB; // Demo class, members d_v3 and d_v4 cannot be memcpy-fast swapped // class Demo { size_t d_v1; size_t d_v2; std::string d_v3; std::string d_v4; size_t d_v5; public: Demo(size_t value = 0); void show(char const *msg); void swap(Demo &rhs); }; Demo::Demo(size_t value) : d_v1(value), d_v2(value + 1), d_v3(std::to_string(value + 2)), d_v4(std::to_string(value + 3)), d_v5(value + 4) {} // fast-swap 2 objects, except for d_v3 and d_v4, which are // swapped by either std::swap or their own .swap() members // void Demo::swap(Demo &rhs) { // This is OK, after commenting out the // fswap(*this, rhs); // string members // specifying members that should be swapped // using std::swap. These members MUST be // specified in their class declaration order fswap(*this, rhs, d_v3, d_v4); // fswap(*this, rhs, d_v4, d_v3); // this won't work... // same, explicitly requesting the // swap-mode // fswap(*this, rhs, d_v3, d_v4); // explicitly requesting another // swap-mode // fswap(*this, rhs, d_v3, d_v4); // default, starting at a begin-member // NOTE: the example does NOT swap d_v1 // fswap(&d_v2, *this, rhs, d_v3, d_v4); // use fastswap, but start at the // member d_v1 (use this for derived // classes whose base class do not // support fast swapping. // Before using this example comment // out the class's std::string members // fswap(&d_v1, *this, rhs, d_v3); // same, explicitly requesting the // swap method, swapping all // fswap(&d_v1, *this, rhs, d_v3, d_v4); // explicitly requesting another // swap-mode // fswap(&d_v1, *this, rhs, d_v3, d_v4); // use stdswap by default, but not // for d_v4, for which .swap() is // used // fswap(&d_v1, *this, rhs, d_v3, swapmember(d_v4)); // same // fswap(&d_v1, *this, rhs, d_v3, // swapmember(d_v4)); // explicitly requesting the already // default swap method is OK // fswap(&d_v1, *this, rhs, swapmember(d_v3), stdswap(d_v4)); } void Demo::show(char const *msg) { std::cout << msg << ". " << d_v1 << ", " << d_v2 << ", " << d_v3 << ", " << d_v4 << ", " << d_v5 << '\n'; } using namespace std; int main() { Demo d1(10); Demo d2(20); d1.show("This is d1:"); d2.show("This is d2:"); cout << "swapping...\n"; d1.swap(d2); d1.show("This is d1:"); d2.show("This is d2:"); } bobcat-5.09.01/gethostent/0000755000175000017500000000000014050437223014270 5ustar frankfrankbobcat-5.09.01/gethostent/gethostent0000644000175000017500000000156114050437223016402 0ustar frankfrank#ifndef INCLUDED_BOBCAT_GETHOSTENT_ #define INCLUDED_BOBCAT_GETHOSTENT_ #include struct hostent; struct in_addr; struct sockaddr_in; namespace FBB { class GetHostent { static struct sockaddr_in s_sa; static in_addr s_address; static char *s_addressPtr[]; static std::string s_name; static struct hostent s_hp; public: static hostent const *gethostent(char const *errorprefix, std::string const &nameOrAddress); static std::string addressToString(char const *errorprefix, void const *ads); private: static void hostError(char const *prefix); // throws Exception() static void solveAddress(char const *prefix, std::string const &host); static void solveName(char const *prefix, std::string const &host); }; } // FBB #endif bobcat-5.09.01/gethostent/solvename.cc0000644000175000017500000000072614050437223016575 0ustar frankfrank#include "gethostent.ih" void GetHostent::solveName(char const *prefix, string const &host) { struct sockaddr_in addr{AF_INET}; inet_pton(AF_INET, host.c_str(), &addr.sin_addr); s_address = addr.sin_addr; char name[NI_MAXHOST]; if (getnameinfo( reinterpret_cast(&addr), sizeof(addr), name, NI_MAXHOST, 0, 0, 0) != 0) hostError(prefix); s_name = name; s_hp.h_name = &s_name.front(); } bobcat-5.09.01/gethostent/data.cc0000644000175000017500000000341214050437223015510 0ustar frankfrank#include "gethostent.ih" // struct addrinfo // { // int ai_flags; // int ai_family; // int ai_socktype; // int ai_protocol; // socklen_t ai_addrlen; // struct sockaddr *ai_addr; // char *ai_canonname; // struct addrinfo *ai_next; // }; // // struct sockaddr { // unsigned short sa_family; // address family, AF_xxx // char sa_data[14]; // 14 bytes of protocol address // }; // // // struct in_addr { // unsigned long s_addr; // load with inet_pton() // }; // // struct sockaddr_in { // short sin_family; // e.g. AF_INET, AF_INET6 // unsigned short sin_port; // e.g. htons(3490) // struct in_addr sin_addr; // char sin_zero[8]; // zero this if you want to // }; // // struct hostent // { // char *h_name; // official name of host // char **h_aliases; // alias list // int h_addrtype; // host address type (always AF_INET) // int h_length; // length of address // char **h_addr_list; // list of addresses // } namespace { char *nullPtr = 0; }; string GetHostent::s_name; in_addr GetHostent::s_address; char *GetHostent::s_addressPtr[2] = { reinterpret_cast(&s_address), 0 }; struct hostent GetHostent::s_hp { 0, // set to &s_name.front() &::nullPtr, AF_INET, 4, // Size of binary IP4 addresses s_addressPtr }; bobcat-5.09.01/gethostent/addresstostring.cc0000644000175000017500000000036014050437223020015 0ustar frankfrank#include "gethostent.ih" string GetHostent::addressToString(char const *prefix, void const *ads) { char buffer[100]; if (!prefix || !inet_ntop(AF_INET, ads, buffer, 100)) throw Exception{} << prefix; return buffer; } bobcat-5.09.01/gethostent/solveaddress.cc0000644000175000017500000000073214050437223017277 0ustar frankfrank#include "gethostent.ih" void GetHostent::solveAddress(char const *prefix, string const &host) { s_name = host; s_hp.h_name = &s_name.front(); struct addrinfo hints{0}; hints.ai_family = AF_INET; // hints.ai_socktype = 0; // SOCK_STREAM; struct addrinfo *res; if (getaddrinfo(host.c_str(), 0, &hints, &res) != 0) hostError(prefix); s_address = reinterpret_cast(res->ai_addr)->sin_addr; freeaddrinfo(res); } bobcat-5.09.01/gethostent/hosterror.cc0000644000175000017500000000104414050437223016625 0ustar frankfrank#include "gethostent.ih" void GetHostent::hostError(char const *text) { string msg = text; msg += ": "; switch (h_errno) { case HOST_NOT_FOUND: msg += "Unknown host"; break; case TRY_AGAIN: msg += "Name server unreachable, try again later"; break; case NO_RECOVERY: msg += "Unrecoverable error"; break; case NO_ADDRESS: msg += "Missing address for hostname"; break; } throw Exception(h_errno) << msg; } bobcat-5.09.01/gethostent/gethostent.cc0000644000175000017500000000075714050437223016774 0ustar frankfrank#include "gethostent.ih" hostent const *GetHostent::gethostent(char const *prefix, string const &host) { // 4 series of . separated digits. Pattern address("(\\d+\\.){3}\\d+"); try { address.match(host); // numeric address if match succeeds solveName(prefix, host); // solve name from address } catch(...) { solveAddress(prefix, host); // solve address from name } return &s_hp; } bobcat-5.09.01/gethostent/gethostent.ih0000644000175000017500000000040614050437223016776 0ustar frankfrank#include "gethostent" #include #include #include #include #include #include #include "../exception/exception" #include "../pattern/pattern" using namespace std; using namespace FBB; bobcat-5.09.01/gethostent/driver/0000755000175000017500000000000014050437223015563 5ustar frankfrankbobcat-5.09.01/gethostent/driver/build0000755000175000017500000000014014050437223016603 0ustar frankfrank#!/bin/bash g++ `cat ../../c++std` -Wall -o driver driver.cc -L../tmp -lgethostent -lbobcat -s bobcat-5.09.01/gethostent/driver/driver.cc0000644000175000017500000000170714050437223017372 0ustar frankfrank/* driver.cc */ #include #include #include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) { if (argc == 1) { cerr << "Provide a host name or host address to solve\n"; return 0; } try { Hostent he(GetHostent::gethostent(argv[1], argv[1])); cout << "Hostname: " << he.hostname() << '\n'; if (he.beginAlias() != he.endAlias()) { cout << "Aliases:\n"; copy(he.beginAlias(), he.endAlias(), ostream_iterator(cout, "\n")); } cout << "Address(es):\n"; for (size_t idx = 0; idx < he.nAddresses(); idx++) cout << he.dottedDecimalAddress(idx) << '\n'; } catch (exception const &err) { cout << err.what() << '\n'; return 1; } } bobcat-5.09.01/GITNOT/0000755000175000017500000000000014050437223013110 5ustar frankfrankbobcat-5.09.01/GITNOT/dstcorrection1.cc0000644000175000017500000000054414050437223016365 0ustar frankfrank//#include "datetime.ih" // //int DateTime::dstCorrection() //{ // if (d_type == UTC) // return d_dst = 0; // // bool ok; // d_dst = dstCorrection(&ok); // // if (!ok) // { // localtime returns dst info // d_errno = errno; // d_ok = false; // } // // return d_dst; //} // bobcat-5.09.01/GITNOT/setseconds.cc0000644000175000017500000000023714050437223015573 0ustar frankfrank//#include "datetime.ih" // //bool DateTime::setSeconds(int seconds) //{ // TM ts = d_tm; // ts.tm_sec = seconds; // // return updateTime(ts); //} // bobcat-5.09.01/GITNOT/dtm2dtm.cc0000644000175000017500000000047114050437223014774 0ustar frankfrank//#include "datetime.ih" // //void DateTime::d_tm2d_tm(int displayZone) // shift in minutes //{ // d_dst = 0; // d_tm.tm_isdst = 0; // // d_tm2utcSec(); // UTC seconds matching d_tm in d_time // // setDisplayZone(zoneSeconds(displayZone)); // utcSec2timeStruct(&d_tm, d_time); //} // bobcat-5.09.01/GITNOT/setdisplayzone.cc0000644000175000017500000000023114050437223016470 0ustar frankfrank//#include "datetime.ih" // //void DateTime::setDisplayZone(time_t displayZone) //{ // d_zone = (d_type == UTC) ? 0 : displayZone; //} // // // // // bobcat-5.09.01/GITNOT/utcsec2timestruct.cc0000644000175000017500000000046014050437223017113 0ustar frankfrank//#include "datetime.ih" // //void DateTime::utcSec2timeStruct(TM *ts, time_t time) //{ // time += d_zone; // add local time shift (if any) // // tm2cout(__FILE__" pre", d_tm); // // d_ok = gmtime_r(&time, ts); // // tm2cout(__FILE__, d_tm); // // ts->tm_isdst = d_dst != 0; //} // // bobcat-5.09.01/GITNOT/updatetime.cc0000644000175000017500000000117214050437223015561 0ustar frankfrank//#include "datetime.ih" // //bool DateTime::updateTime(TM &tm) //{ // if (!d_ok) // return false; // // time_t utcSec = d_time; // TM dtm = d_tm; // int dspShift = d_zone; // this also allows for DST // // d_tm = tm; // // d_tm.tm_sec -= dspShift; // tm back to UTC // d_tm2d_tm(dspShift / 60); // add the display shift for loc. time // // if (d_ok) // { // if (dstCorrection()) // d_tm.tm_isdst = 1; // d_dst = 0; // } // else // { // d_time = utcSec; // d_tm = dtm; // d_zone = dspShift; // // } // // return d_ok; //} // bobcat-5.09.01/GITNOT/dtm2timetype.cc0000644000175000017500000000022714050437223016047 0ustar frankfrank//#include "datetime.ih" // //void DateTime::d_tm2timeType() //{ // d_tm.tm_isdst = 0; // d_tm2utcSec(); // // displayShift2d_tm(); // //} // bobcat-5.09.01/GITNOT/displayshift2dtm.cc0000644000175000017500000000055214050437223016713 0ustar frankfrank//#include "datetime.ih" // //void DateTime::displayShift2d_tm() //{ // if (d_type == UTC) // { // d_dst = 0; // setDisplayZone(0); // } // else // { // time_t shift = defaultDisplayZone() + dstCorrection(); // d_time -= shift; // setDisplayZone(shift); // } // // utcSec2timeStruct(&d_tm, d_time); //} // bobcat-5.09.01/GITNOT/dstcorrection2.cc0000644000175000017500000000052614050437223016366 0ustar frankfrank//#include "datetime.ih" // //int DateTime::dstCorrection(bool *ok) const //{ // TM ts; // // tzset(); // see the localtime_r manpage: tzset() required // TM *ret = localtime_r(&d_time, &ts); // // if (not (*ok = ret)) // 0: can't compute // return 0; // // return ts.tm_isdst == 1 ? 3600 : 0; //} // bobcat-5.09.01/GITNOT/setdst.cc0000644000175000017500000000021214050437223014720 0ustar frankfrank#include "datetime.ih" int DateTime::setDst(time_t time) { TM ts; return d_dst = localtime_r(&time, &ts)->tm_isdst ? 3600 : 0; } bobcat-5.09.01/GITNOT/parsetime.cc0000644000175000017500000000056714050437223015420 0ustar frankfrank//#include "datetime.ih" // // // supported formats: // // // // 1: Mon Dec 3 13:29:11 2018 // // 2: Mon Dec 3 13:29:11 CET 2018 // // 3: Mon, 3 Dec 2018 13:29:11 +0100 // // 4: 2018-12-03 13:29:11+01:00 // //DateTime::Parse DateTime::parseTime(string const &timeStr) //{ // istringstream in(timeStr); // // return parseStream(in); //} // bobcat-5.09.01/GITNOT/setyear.cc0000644000175000017500000000024114050437223015070 0ustar frankfrank//#include "datetime.ih" // //bool DateTime::setYear(size_t year) //{ // TM ts = d_tm; // ts.tm_year = year - 1900; // // return updateTime(ts); //} // bobcat-5.09.01/GITNOT/dtm2utcsec.cc0000644000175000017500000000022514050437223015473 0ustar frankfrank//#include "datetime.ih" // //void DateTime::d_tm2utcSec() //{ // d_time = timeStruct2utcSec(&d_tm); // d_time += defaultDisplayZone(); //} // bobcat-5.09.01/glob/0000755000175000017500000000000014050437223013027 5ustar frankfrankbobcat-5.09.01/glob/mend.f0000644000175000017500000000013714050437223014122 0ustar frankfrankinline char const **Glob::mend() const { return const_cast(d_share->end); } bobcat-5.09.01/glob/glob1.cc0000644000175000017500000000016514050437223014344 0ustar frankfrank#include "glob.ih" Glob::Glob(string const &pattern, int flags, Dots dots) : Glob(ANY, pattern, flags, dots) {} bobcat-5.09.01/glob/mbegin.f0000644000175000017500000000014314050437223014435 0ustar frankfrankinline char const **Glob::mbegin() const { return const_cast(d_share->begin); } bobcat-5.09.01/glob/glob5.cc0000644000175000017500000000127014050437223014346 0ustar frankfrank#include "glob.ih" Glob::Glob(unordered_set const &type, string const &pattern, int flags, Dots dots) try : d_share(new GlobShare { glob_t{}, 1, type } ) { if (flags & ~Flags::mask) throw Exception(flags) << "Glob: unknown Flag specified"; int err = glob(pattern.c_str(), flags & ~NOMATCH, 0, &d_share->globStruct); if (err != 0) { if (not (err == GLOB_NOMATCH and flags & NOMATCH)) throw Exception(err) << "Glob: glob() failed"; } accept(); if (dots == FIRST) stable_partition(mbegin(), mend(), isDot); } catch(...) { delete d_share; throw; } bobcat-5.09.01/glob/glob0000644000175000017500000000412314050437223013675 0ustar frankfrank#ifndef INCLUDED_BOBCAT_GLOB_ #define INCLUDED_BOBCAT_GLOB_ #include #include #include #include namespace FBB { class Glob: public GS__ { struct GlobShare; GlobShare *d_share; public: enum Flags { NO_FLAG = 0, // to avoid having to use 0 // These flags are equal to the ones used in ERR = 1 << 0, // Return on read errors. MARK = 1 << 1, // Append a slash to each name. NOSORT = 1 << 2, // Don't sort the names. NOESCAPE = 1 << 6, // Backslashes don't quote metacharacters. PERIOD = 1 << 7, // Leading `.' can be matched by metachars. NOMATCH = 1 << 8, // No matches are OK (size() returns 0) mask = (1 << 9) - 1 // all of the above flags }; enum Dots { FIRST, DEFAULT }; Glob(std::string const &pattern = "*", int flags = PERIOD, // 1 Dots dots = FIRST); Glob(Type type, std::string const &pattern = "*", // 2 int flags = PERIOD, Dots dots = FIRST); Glob(Glob &&tmp); // 3 Glob(Glob const &other); // 4 Glob(std::unordered_set const &type, // 5 std::string const &pattern = "*", int flags = PERIOD, Dots dots = FIRST); ~Glob(); Glob &operator=(Glob const &other); Glob &operator=(Glob &&tmp); size_t size() const; char const *operator[](size_t idx) const; char const *const *begin() const; char const *const *end() const; void swap(Glob &other); private: char const **mbegin() const; // .f char const **mend() const; // .f void accept(); static std::unordered_set fillSet(Type type); static bool isDot(char const *cp); }; } // FBB #endif bobcat-5.09.01/glob/accept.cc0000644000175000017500000000136014050437223014575 0ustar frankfrank#include "glob.ih" void Glob::accept() { auto begin = d_share->begin = new char *[d_share->globStruct.gl_pathc]; auto dest = begin; auto gsTypeEnd = d_share->gsType.end(); for ( auto src = d_share->globStruct.gl_pathv, end = src + d_share->globStruct.gl_pathc; src != end; ++src ) { if (d_share->gsType.find( static_cast(Stat(Stat::LStat, *src).type() & ANY)) != gsTypeEnd ) *dest++ = *src; // copy the pointer if type is OK } d_share->size = dest - begin; // compute the # of accepted entries d_share->end = dest; // end points beyond the last one } bobcat-5.09.01/glob/size.cc0000644000175000017500000000011514050437223014305 0ustar frankfrank#include "glob.ih" size_t Glob::size() const { return d_share->size; } bobcat-5.09.01/glob/isdot.cc0000644000175000017500000000025514050437223014462 0ustar frankfrank#include "glob.ih" namespace { string const dot("."); string const dot2(".."); } bool Glob::isDot(char const *cp) { return dot == cp || dot2 == cp; } bobcat-5.09.01/glob/operatorindex.cc0000644000175000017500000000017414050437223016223 0ustar frankfrank#include "glob.ih" char const *Glob::operator[](size_t idx) const { return idx < size() ? d_share->begin[idx] : ""; } bobcat-5.09.01/glob/operatorassign2.cc0000644000175000017500000000013314050437223016455 0ustar frankfrank#include "glob.ih" Glob &Glob::operator=(Glob &&tmp) { swap(tmp); return *this; } bobcat-5.09.01/glob/end.cc0000644000175000017500000000012714050437223014104 0ustar frankfrank#include "glob.ih" char const *const *Glob::end() const { return d_share->end; } bobcat-5.09.01/glob/glob2.cc0000644000175000017500000000021214050437223014336 0ustar frankfrank#include "glob.ih" Glob::Glob(Type type, string const &pattern, int flags, Dots dots) : Glob(fillSet(type), pattern, flags, dots) {} bobcat-5.09.01/glob/begin.cc0000644000175000017500000000013314050437223014417 0ustar frankfrank#include "glob.ih" char const *const *Glob::begin() const { return d_share->begin; } bobcat-5.09.01/glob/glob.ih0000644000175000017500000000062414050437223014276 0ustar frankfrank#include "glob" #include #include #include "../fswap/fswap" #include "../stat/stat" #include "../exception/exception" using namespace std; using namespace FBB; struct Glob::GlobShare { glob_t globStruct; size_t users; unordered_set gsType; char **begin; char **end; size_t size; }; #include "mbegin.f" #include "mend.f" bobcat-5.09.01/glob/destructor.cc0000644000175000017500000000036714050437223015542 0ustar frankfrank#include "glob.ih" Glob::~Glob() { if (!d_share) // for the move-operations return; if (!--d_share->users) { globfree(&d_share->globStruct); delete[] d_share->begin; delete d_share; } } bobcat-5.09.01/glob/operatorassign.cc0000644000175000017500000000016714050437223016402 0ustar frankfrank#include "glob.ih" Glob &Glob::operator=(Glob const &other) { Glob tmp(other); swap(tmp); return *this; } bobcat-5.09.01/glob/swap.cc0000644000175000017500000000011714050437223014307 0ustar frankfrank#include "glob.ih" void Glob::swap(Glob &other) { fswap(*this, other); } bobcat-5.09.01/glob/fillset.cc0000644000175000017500000000103514050437223014777 0ustar frankfrank#include "glob.ih" //static unordered_set Glob::fillSet(Type type) { unordered_set ret; for (auto value: initializer_list{ BLOCK_DEVICE, CHARACTER_DEVICE, DIRECTORY, FIFO, REGULAR_FILE, SOCKET, SYMBOLIC_LINK, } ) { if ((type & value) == value) ret.insert(value); } return ret; } bobcat-5.09.01/glob/glob4.cc0000644000175000017500000000015114050437223014342 0ustar frankfrank#include "glob.ih" Glob::Glob(Glob const &other) { d_share = other.d_share; ++d_share->users; } bobcat-5.09.01/glob/glob3.cc0000644000175000017500000000013714050437223014345 0ustar frankfrank#include "glob.ih" Glob::Glob(Glob &&tmp) : d_share(tmp.d_share) { tmp.d_share = 0; } bobcat-5.09.01/glob/driver/0000755000175000017500000000000014050437223014322 5ustar frankfrankbobcat-5.09.01/glob/driver/build0000755000175000017500000000056414050437223015354 0ustar frankfrank#!/bin/bash tput clear GPP="g++ `cat ../../c++std`" # CMD="$GPP -o driver -Wall -I../ driver.cc -L../tmp -lglob -lbobcat -s" # CMD="$GPP -o driver -Wall -I../../tmp driver.cc -L../../tmp/lib -lbobcat -s" # CMD="$GPP -o driver -Wall -I../ driver.cc -L../tmp -lglob -lbobcat -s" CMD="$GPP -o driver -Wall *.cc -lbobcat -s" echo $CMD $CMD || exit 1 echo Ready... driver bobcat-5.09.01/glob/driver/driver.cc0000644000175000017500000000265714050437223016136 0ustar frankfrank/* driver.cc */ #include #include #include #include using namespace std; using namespace FBB; Glob makeGlob(char const *pat) { cout << "Using pattern " << pat << '\n'; return Glob(pat, Glob::PERIOD, Glob::DEFAULT); } int main(int argc, char **argv) try { if (argc == 1) { cout << "Provide glob-expression as 1st arg\n"; return 1; } cout << "\nGeneral:\n"; Glob general; for (size_t idx = 0; idx < general.size(); idx++) cout << idx << ": " << general[idx] << '\n'; cout << "\nPattern: " << argv[1] << "\n"; Glob pattern(makeGlob(argv[1])); Glob copy(pattern); copy = general; for (size_t idx = 0; idx < pattern.size(); idx++) cout << idx << ": " << pattern[idx] << '\n'; pattern = Glob(Glob::DIRECTORY, argv[1], Glob::PERIOD, Glob::FIRST); cout << "Only directories:\n"; for (size_t idx = 0; idx < pattern.size(); idx++) cout << idx << ": " << pattern[idx] << '\n'; pattern = Glob(Glob::REGULAR_FILE, argv[1], Glob::PERIOD, Glob::FIRST); cout << "regular files:\n"; for (size_t idx = 0; idx < pattern.size(); idx++) cout << idx << ": " << pattern[idx] << '\n'; cout << "\nThe next glob fails, this is intentional\n"; Glob fails("*", 1023); } catch (exception const &err) { cout << err.what() << '\n'; return 1; } bobcat-5.09.01/glob/driver/main.ln0000777000175000017500000000000014050437223017031 2main.ccustar frankfrankbobcat-5.09.01/glob/driver/buildmain0000755000175000017500000000055414050437223016220 0ustar frankfrank#!/bin/bash tput clear GPP="g++ --std=c++2a" CMD="$GPP -o driver -Wall -I../ main.cc -L../tmp -lglob -lbobcat -s" # CMD="$GPP -o driver -Wall -I../../tmp main.cc -L../../tmp/lib -lbobcat -s" # CMD="$GPP -o driver -Wall -I../ main.cc -L../tmp -lglob -lbobcat -s" # CMD="$GPP -o driver -Wall *.cc -lbobcat -s" echo $CMD $CMD || exit 1 echo "'driver' ready..." bobcat-5.09.01/glob/driver/main.cc0000644000175000017500000000156614050437223015565 0ustar frankfrank#include "../../stat/stat.ih" void Stat::init() { d_errno = ::lstat(d_name.c_str(), &d_stat) ? errno : 0; } #include #include "../glob" using namespace std; using namespace FBB; void files(Glob::Type type, char const *label) { cout << label << ", type: " << type << ":\n"; // Glob glob{ type, "*" }; Glob glob{ unordered_set{ type }, "*" }; cout << "list:\n"; for (char const *cp: glob ) cout << cp << '\n'; cout << "list done\n\n"; } int main() { cout << hex; files(Glob::BLOCK_DEVICE, "BLOCK_DEVICE"); files(Glob::CHARACTER_DEVICE, "CHARACTER_DEVICE"); files(Glob::DIRECTORY, "DIRECTORY"); files(Glob::FIFO, "FIFO"); files(Glob::REGULAR_FILE, "REGULAR_FILE"); files(Glob::SOCKET, "SOCKET"); files(Glob::SYMBOLIC_LINK, "SYMBOLIC_LINK"); } bobcat-5.09.01/gs/0000755000175000017500000000000014050437223012515 5ustar frankfrankbobcat-5.09.01/gs/opbinor.f0000644000175000017500000000027114050437223014334 0ustar frankfrankinline GS__::Type operator|(GS__::Type lhs, GS__::Type rhs) { return static_cast( static_cast(lhs) | static_cast(rhs) ); } bobcat-5.09.01/gs/gs0000644000175000017500000000130414050437223013047 0ustar frankfrank#ifndef INCLUDED_GS_ #define INCLUDED_GS_ namespace FBB { struct GS__ { enum Type { BLOCK_DEVICE = 0060000, CHARACTER_DEVICE = 0020000, DIRECTORY = 0040000, FIFO = 0010000, REGULAR_FILE = 0100000, SOCKET = 0140000, SYMBOLIC_LINK = 0120000, ANY = BLOCK_DEVICE | CHARACTER_DEVICE | DIRECTORY | FIFO | REGULAR_FILE | SOCKET | SYMBOLIC_LINK }; }; #include "opbinor.f" // Type | Type } // namespace FBB #endif bobcat-5.09.01/hash/0000755000175000017500000000000014050437223013027 5ustar frankfrankbobcat-5.09.01/hash/hashcharptr4.f0000644000175000017500000000026114050437223015570 0ustar frankfranktemplate inline HashCharPtr &HashCharPtr::operator=(HashCharPtr &&tmp) { static_cast(*this) = std::move(tmp); return *this; } bobcat-5.09.01/hash/hashstring1.f0000644000175000017500000000016414050437223015432 0ustar frankfranktemplate inline HashString::HashString(HashString &&tmp) : BaseClass(std::move(tmp)) {} bobcat-5.09.01/hash/opfun4.f0000644000175000017500000000016014050437223014406 0ustar frankfrankinline bool CharPtrEqual::operator()(char const *s1, char const *s2) const { return strcmp(s1, s2) == 0; } bobcat-5.09.01/hash/hashcharcaseptr2.f0000644000175000017500000000026414050437223016425 0ustar frankfranktemplate inline HashCharCasePtr::HashCharCasePtr( std::initializer_list iniValues) : BaseClass(iniValues) {} bobcat-5.09.01/hash/opfun1.f0000644000175000017500000000020014050437223014376 0ustar frankfrankinline size_t CaseHash::operator()(std::string const &key) const { return std::hash()(FBB::String::lc(key)); } bobcat-5.09.01/hash/hashstringcase3.f0000644000175000017500000000034314050437223016267 0ustar frankfranktemplate template inline HashStringCase::HashStringCase(InputIterator first, InputIterator beyond) : BaseClass(first, beyond) {} bobcat-5.09.01/hash/hashstring2.f0000644000175000017500000000031214050437223015426 0ustar frankfranktemplate inline HashString::HashString(std::initializer_list iniValues) : BaseClass(iniValues) {} bobcat-5.09.01/hash/hashstring4.f0000644000175000017500000000025614050437223015437 0ustar frankfranktemplate inline HashString &HashString::operator=(HashString &&tmp) { static_cast(*this) = std::move(tmp); return *this; } bobcat-5.09.01/hash/hashcharptr2.f0000644000175000017500000000031414050437223015565 0ustar frankfranktemplate inline HashCharPtr::HashCharPtr(std::initializer_list iniValues) : BaseClass(iniValues) {} bobcat-5.09.01/hash/opfun2.f0000644000175000017500000000016114050437223014405 0ustar frankfrankinline bool CaseEqual::operator()(char const *s1, char const *s2) const { return strcasecmp(s1, s2) == 0; } bobcat-5.09.01/hash/hashcharcaseptr1.f0000644000175000017500000000020214050437223016414 0ustar frankfranktemplate inline HashCharCasePtr::HashCharCasePtr(HashCharCasePtr &&tmp) : BaseClass(std::move(tmp)) {} bobcat-5.09.01/hash/hash0000644000175000017500000001127314050437223013701 0ustar frankfrank#ifndef INCLUDED_BOBCAT_HASH_ #define INCLUDED_BOBCAT_HASH_ #include #include #include #include namespace FBB { // Support structs // =============== struct CaseHash { size_t operator()(std::string const &key) const; // opfun1.f }; struct CaseEqual { bool operator()(char const *s1, char const *s2) const; // opfun2.f bool operator()(std::string const &s1, // opfun3.f std::string const &s2) const; }; struct CharPtrEqual { bool operator()(char const *s1, char const *s2) const; // opfun4.f }; // HashCharPtr: case sensitive char const *keys // ============================================ template class HashCharPtr: public std::unordered_map< char const *, Value, std::hash, CharPtrEqual > { typedef std::unordered_map< char const *, Value, std::hash, CharPtrEqual > BaseClass; public: typedef typename BaseClass::value_type value_type; HashCharPtr() = default; HashCharPtr(HashCharPtr &&tmp); // 1.f HashCharPtr(std::initializer_list iniValues); // 2.f template HashCharPtr(InputIterator first, InputIterator beyond); // 3.f HashCharPtr &operator=(HashCharPtr &&tmp); // 4.f }; // HashCharCasePtr: case insensitive char const *keys // ================================================== template class HashCharCasePtr: public std::unordered_map< char const *, Value, CaseHash, CaseEqual > { typedef std::unordered_map BaseClass; public: typedef typename BaseClass::value_type value_type; HashCharCasePtr() = default; HashCharCasePtr(HashCharCasePtr &&tmp); // 1.f HashCharCasePtr(std::initializer_list iniValues); // 2.f template HashCharCasePtr(InputIterator first, InputIterator beyond); // 3.f HashCharCasePtr &operator=(HashCharCasePtr &&tmp); // 4.f }; // HashString: case sensitive std::string keys // =========================================== template class HashString: public std::unordered_map { typedef std::unordered_map BaseClass; public: typedef typename BaseClass::value_type value_type; HashString() = default; HashString(HashString &&tmp); // 1.f HashString(std::initializer_list iniValues); // 2.f template HashString(InputIterator first, InputIterator beyond); // 3.f HashString &operator=(HashString &&tmp); // 4.f }; // HashStringCase: case insensitive std::string keys // ================================================= template class HashStringCase: public std::unordered_map< std::string, Value, CaseHash, CaseEqual > { typedef std::unordered_map BaseClass; public: typedef typename BaseClass::value_type value_type; HashStringCase() = default; HashStringCase(HashStringCase &&tmp); // 1.f HashStringCase(std::initializer_list iniValues); // 2.f template HashStringCase(InputIterator first, InputIterator beyond); // 3.f HashStringCase &operator=(HashStringCase &&tmp); // 4.f }; #include "opfun1.f" #include "opfun2.f" #include "opfun3.f" #include "opfun4.f" #include "hashcharptr1.f" #include "hashcharptr2.f" #include "hashcharptr3.f" #include "hashcharptr4.f" #include "hashcharcaseptr1.f" #include "hashcharcaseptr2.f" #include "hashcharcaseptr3.f" #include "hashcharcaseptr4.f" #include "hashstring1.f" #include "hashstring2.f" #include "hashstring3.f" #include "hashstring4.f" #include "hashstringcase1.f" #include "hashstringcase2.f" #include "hashstringcase3.f" #include "hashstringcase4.f" } // FBB #endif bobcat-5.09.01/hash/hashstringcase2.f0000644000175000017500000000032214050437223016263 0ustar frankfranktemplate inline HashStringCase::HashStringCase(std::initializer_list iniValues) : BaseClass(iniValues) {} bobcat-5.09.01/hash/hashcharptr1.f0000644000175000017500000000016614050437223015571 0ustar frankfranktemplate inline HashCharPtr::HashCharPtr(HashCharPtr &&tmp) : BaseClass(std::move(tmp)) {} bobcat-5.09.01/hash/hashstring3.f0000644000175000017500000000032314050437223015431 0ustar frankfranktemplate template inline HashString::HashString(InputIterator first, InputIterator beyond) : BaseClass(first, beyond) {} bobcat-5.09.01/hash/hashstringcase4.f0000644000175000017500000000035314050437223016271 0ustar frankfranktemplate inline HashStringCase &HashStringCase::operator=( HashStringCase &&tmp) { static_cast(*this) = std::move(tmp); return *this; } bobcat-5.09.01/hash/opfun3.f0000644000175000017500000000026214050437223014410 0ustar frankfrankinline bool CaseEqual::operator()(std::string const &s1, std::string const &s2) const { return FBB::String::casecmp(s1, s2) == 0; } bobcat-5.09.01/hash/hashcharptr3.f0000644000175000017500000000033714050437223015573 0ustar frankfranktemplate template inline HashCharPtr::HashCharPtr(InputIterator first, InputIterator beyond) : BaseClass(first, beyond) {} bobcat-5.09.01/hash/hashstringcase1.f0000644000175000017500000000020014050437223016255 0ustar frankfranktemplate inline HashStringCase::HashStringCase(HashStringCase &&tmp) : BaseClass(std::move(tmp)) {} bobcat-5.09.01/hash/hashcharcaseptr4.f0000644000175000017500000000035614050437223016431 0ustar frankfranktemplate inline HashCharCasePtr &HashCharCasePtr::operator=( HashCharCasePtr &&tmp) { static_cast(*this) = std::move(tmp); return *this; } bobcat-5.09.01/hash/hashcharcaseptr3.f0000644000175000017500000000034714050437223016430 0ustar frankfranktemplate template inline HashCharCasePtr::HashCharCasePtr(InputIterator first, InputIterator beyond) : BaseClass(first, beyond) {} bobcat-5.09.01/hash/driver/0000755000175000017500000000000014050437223014322 5ustar frankfrankbobcat-5.09.01/hash/driver/driver.cc0000644000175000017500000000070114050437223016122 0ustar frankfrank#include "../hash" #include using namespace FBB; using namespace std; int main(int argc, char **argv) { HashStringCase hsc; hsc["AAP"] = "noot"; hsc["Aap"] = "mies"; cout << hsc["aap"] << endl; HashString hs; hs["AAP"] = "noot"; hs["Aap"] = "mies"; cout << hs["AAP"] << endl; HashCharPtr hcp; hcp["jan"] = 31; hcp["feb"] = 28; cout << hcp["jan"] << endl; } bobcat-5.09.01/hash/driver/driver2.cc0000644000175000017500000000147414050437223016214 0ustar frankfrank// With g++ 4.3 ext/hash_map is deprecated. The following example shows how to // use hashes with version >= 4.3: // FOR NOW, THE OPTION -std=c++0x IS REQUIRED #include #include #include using namespace std; class Hash { public: size_t operator()(char const *str) const { size_t ret = 0; for (size_t idx = 0; *str; ++idx, ++str) ret += idx + *str; return ret; } }; int main(int argc, char *const *const argv) { pair d[] = { pair("aap", 18), pair("noot", 20), pair("wim", 30) }; unordered_map> hcp(d, d + 3); cout << hcp["noot"] << endl; } bobcat-5.09.01/hmacbuf/0000755000175000017500000000000014050437223013511 5ustar frankfrankbobcat-5.09.01/hmacbuf/overflow.cc0000644000175000017500000000031414050437223015661 0ustar frankfrank#include "hmacbuf.ih" int HMacBuf::overflow(int ch) { HMAC_Update(d_ctx, ucharPtr(), bufSize()); setp(); if (ch != EOF) { *pptr() = ch; pbump(1); } return ch; } bobcat-5.09.01/hmacbuf/hmacbuf0000644000175000017500000000143014050437223015037 0ustar frankfrank#ifndef INCLUDED_HMACBUF_ #define INCLUDED_HMACBUF_ #include #include namespace FBB { class HMacBuf: public EoiBuf { friend std::ostream &operator<<(std::ostream &out, HMacBuf const &hmacbuf); HMAC_CTX *d_ctx = 0; EVP_MD const *d_md; std::string d_digest; std::string d_key; public: HMacBuf(std::string const &key, char const *type, size_t bufsize = 1024); void reset(); void eoi(); std::string const &hash() const; private: int overflow(int c) override; void eoi_() override; // .cc }; std::ostream &operator<<(std::ostream &out, HMacBuf const &hmacbuf); } // FBB #endif bobcat-5.09.01/hmacbuf/reset.cc0000644000175000017500000000033414050437223015142 0ustar frankfrank#include "hmacbuf.ih" void HMacBuf::reset() { if (d_ctx != 0) return; d_ctx = HMAC_CTX_new(); HMAC_CTX_reset(d_ctx); HMAC_Init_ex(d_ctx, d_key.c_str(), d_key.length(), d_md, 0); setp(); } bobcat-5.09.01/hmacbuf/hash.cc0000644000175000017500000000012414050437223014740 0ustar frankfrank#include "hmacbuf.ih" string const &HMacBuf::hash() const { return d_digest; } bobcat-5.09.01/hmacbuf/hmacbuf1.cc0000644000175000017500000000063014050437223015505 0ustar frankfrank#include "hmacbuf.ih" HMacBuf::HMacBuf(std::string const &key, char const *type, size_t bufsize) : EoiBuf(bufsize), d_key(key) { OpenSSL_add_all_digests(); d_md = EVP_get_digestbyname(type); if (!d_md) { if (type == 0) type = "** unspecified hmac-digest type **"; throw Exception{ 1 } << "HMacBuf `" << type << "' not available"; } reset(); } bobcat-5.09.01/hmacbuf/operatorinsert.cc0000644000175000017500000000042414050437223017100 0ustar frankfrank#include "hmacbuf.ih" namespace FBB { std::ostream &operator<<(std::ostream &out, HMacBuf const &digestbuf) { OHexBuf ohex(out); ostream outs(&ohex); outs.write(digestbuf.d_digest.data(), digestbuf.d_digest.length()); return out; } } // FBB bobcat-5.09.01/hmacbuf/eoi.cc0000644000175000017500000000055214050437223014576 0ustar frankfrank#include "hmacbuf.ih" // override void HMacBuf::eoi_() { d_digest.resize(EVP_MAX_MD_SIZE); if (pptr() > pbase()) HMAC_Update(d_ctx, ucharPtr(d_digest), pptr() - pbase()); unsigned digestbufLen; HMAC_Final(d_ctx, ucharPtr(d_digest), &digestbufLen); d_digest.resize(digestbufLen); HMAC_CTX_free(d_ctx); d_ctx = 0; } bobcat-5.09.01/hmacbuf/hmacbuf.ih0000644000175000017500000000100714050437223015436 0ustar frankfrank#include "hmacbuf" #include #include #include #define CERRX std::cerr << __FILE__": " #include "../exception/exception" #include "../ohexbuf/ohexbuf" #if OPENSSL_VERSION_NUMBER < 0x10100000L inline HMAC_CTX *HMAC_CTX_new() { return new HMAC_CTX; } inline int HMAC_CTX_reset(HMAC_CTX *ctx) { HMAC_CTX_init(ctx); return 1; } inline void HMAC_CTX_free(HMAC_CTX *ctx) { HMAC_CTX_cleanup(ctx); delete ctx; } #endif using namespace std; using namespace FBB; bobcat-5.09.01/hmacbuf/driver/0000755000175000017500000000000014050437223015004 5ustar frankfrankbobcat-5.09.01/hmacbuf/driver/build0000755000175000017500000000143314050437223016032 0ustar frankfrank#!/bin/sh ln -s .. bobcat # # g++ -I. --std=c++2a -O2 -Wall -o driver driver.cc -lssl -lbobcat \ # -L../../ohexbuf/tmp -L../tmp -lhmacbuf -lohexbuf # tput clear LIBS=" -lbobcat -lcrypto" GPP="g++ --std=c++2a" # Using the standard bobcat library # CMD="$GPP -o driver -Wall *.cc ${LIBS} -s" # Using the library in ../tmp/ and bobcat as /tmp/libbob.a CMD="$GPP -o driver -Wall *.cc -L../tmp -lhmacbuf -L /tmp -lbob -lcrypto -s" # Using the library in ../tmp/ # CMD="$GPP -o driver -Wall *.cc -L../tmp -lhmacbuf ${LIBS} -s" # Using tmp libraries and bobcat CMD="$GPP -o driver -Wall -I../tmp driver.cc \ -L../tmp -lhmacbuf \ -L../../ohexbuf/tmp -lohexbuf \ -L../../eoibuf/tmp -leoibuf \ -L../../eoi/tmp -leoi \ ${LIBS} -s" echo ${CMD} ${CMD} rm bobcat bobcat-5.09.01/hmacbuf/driver/driver.cc0000644000175000017500000000126514050437223016612 0ustar frankfrank#include #include #include #include #include #include "../hmacbuf" using namespace std; using namespace FBB; int main(int argc, char **argv) try { if (argc < 3) throw Exception{} << "Arg1: key, arg2: digest method required"; string key(argv[1]); HMacBuf hmacbuf{ key, argv[2] }; ostream out(&hmacbuf); string hw{ "hello world\n" }; out << hw << eoi; cout << ">" << hmacbuf << "<" << endl; // hmacbuf.reset(); // out.write(hw.c_str(), hw.length()) << eoi; // cout << ">" << hmacbuf << "<" << endl; } catch(exception const &err) { cout << err.what() << endl; return errno; } bobcat-5.09.01/hostent/0000755000175000017500000000000014050437223013570 5ustar frankfrankbobcat-5.09.01/hostent/dotteddecimaladdress.cc0000644000175000017500000000035214050437223020247 0ustar frankfrank#include "hostent.ih" string Hostent::dottedDecimalAddress(size_t nr) const { char buffer[100]; char const *ba = binaryAddress(nr); return (ba && inet_ntop(AF_INET, ba, buffer, 100)) ? buffer : ""; } bobcat-5.09.01/hostent/hostent.ih0000644000175000017500000000031114050437223015571 0ustar frankfrank#include "hostent" #include #include #include #include #include #include "../fswap/fswap" using namespace std; using namespace FBB; bobcat-5.09.01/hostent/addresslength.f0000644000175000017500000000010614050437223016563 0ustar frankfrankinline size_t Hostent::addressLength() const { return h_length; } bobcat-5.09.01/hostent/hostent0000644000175000017500000000426714050437223015210 0ustar frankfrank#ifndef INCLUDED_BOBCAT_HOSTENT_ #define INCLUDED_BOBCAT_HOSTENT_ #include #include namespace FBB { class Hostent: private hostent { union PTR { char const * const *p2; char const *p1; }; size_t d_nAliases; size_t d_nAddresses; public: Hostent(); Hostent(Hostent const &other); // hostent1.f Hostent(Hostent &&tmp); explicit Hostent(hostent const *other); ~Hostent(); // destructor.f Hostent &operator=(Hostent const &other); Hostent &operator=(Hostent &&tmp); // opis.f char const *alias(size_t nr) const; // .f char const *binaryAddress(size_t nr) const; // .f length bytes! char const * const *beginAlias() const; // .f std::string dottedDecimalAddress(size_t nr) const; char const * const *endAlias() const; // .f char const *hostname() const; // .f size_t nAliases() const; // .f size_t nAddresses() const; // .f size_t addressLength() const; // .f size_t addressType() const; // .f void swap(Hostent &other); private: static char *xstrdup(char const *src); void copy(hostent const *other, size_t n_aliases, size_t n_addresses); void destroy(); // the count functions also count // the final 0-values. size_t countAliases(char const * const *alias) const; size_t countAddresses(char const * const *addresses, size_t length) const; }; #include "addresslength.f" #include "addresstype.f" #include "alias.f" #include "beginalias.f" #include "binaryaddress.f" #include "destructor.f" #include "endalias.f" #include "hostent1.f" #include "hostname.f" #include "naddresses.f" #include "naliases.f" #include "opis.f" } // FBB #endif bobcat-5.09.01/hostent/countaliases.cc0000644000175000017500000000030014050437223016562 0ustar frankfrank#include "hostent.ih" size_t Hostent::countAliases(char const * const *alias) const { size_t idx = 1; // counts the final 0-ptr. while (*alias++) idx++; return idx; } bobcat-5.09.01/hostent/hostent1.f0000644000175000017500000000015214050437223015502 0ustar frankfrankinline Hostent::Hostent(Hostent const &other) { copy(&other, other.d_nAliases, other.d_nAddresses); } bobcat-5.09.01/hostent/naliases.f0000644000175000017500000000010714050437223015534 0ustar frankfrankinline size_t Hostent::nAliases() const { return d_nAliases - 1; } bobcat-5.09.01/hostent/beginalias.f0000644000175000017500000000012114050437223016027 0ustar frankfrankinline char const * const *Hostent::beginAlias() const { return h_aliases; } bobcat-5.09.01/hostent/hostname.f0000644000175000017500000000010414050437223015550 0ustar frankfrankinline char const *Hostent::hostname() const { return h_name; } bobcat-5.09.01/hostent/naddresses.f0000644000175000017500000000011314050437223016065 0ustar frankfrankinline size_t Hostent::nAddresses() const { return d_nAddresses - 1; } bobcat-5.09.01/hostent/xstrdup.cc0000644000175000017500000000025014050437223015605 0ustar frankfrank#include "hostent.ih" char *Hostent::xstrdup(char const *src) { return src ? strcpy(new char[1 + strlen(src)], src) : 0; } bobcat-5.09.01/hostent/binaryaddress.f0000644000175000017500000000016414050437223016572 0ustar frankfrankinline char const *Hostent::binaryAddress(size_t nr) const { return nr >= nAddresses() ? 0 : h_addr_list[nr]; } bobcat-5.09.01/hostent/endalias.f0000644000175000017500000000013414050437223015515 0ustar frankfrankinline char const * const *Hostent::endAlias() const { return h_aliases + nAliases(); } bobcat-5.09.01/hostent/hostent2.cc0000644000175000017500000000022614050437223015645 0ustar frankfrank#include "hostent.ih" Hostent::Hostent(Hostent &&tmp) { swap(tmp); tmp.h_name = 0; // prevent tmp's ~Hostent from deleting wild pointers } bobcat-5.09.01/hostent/destructor.f0000644000175000017500000000005714050437223016137 0ustar frankfrankinline Hostent::~Hostent() { destroy(); } bobcat-5.09.01/hostent/hostent3.cc0000644000175000017500000000027114050437223015646 0ustar frankfrank#include "hostent.ih" Hostent::Hostent(hostent const *other) { copy(other, countAliases(other->h_aliases), countAddresses(other->h_addr_list, other->h_length)); } bobcat-5.09.01/hostent/countaddresses.cc0000644000175000017500000000063714050437223017133 0ustar frankfrank#include "hostent.ih" size_t Hostent::countAddresses(char const * const *addresses, size_t length) const { PTR p = {addresses}; size_t n = 1; // counts the final 0-address while ( static_cast(count(p.p1, p.p1 + length, char())) != length ) { p.p1 += length; n++; } return n; } bobcat-5.09.01/hostent/operatorassign.cc0000644000175000017500000000020614050437223017135 0ustar frankfrank#include "hostent.ih" Hostent &Hostent::operator=(Hostent const &other) { Hostent tmp(other); swap(tmp); return *this; } bobcat-5.09.01/hostent/swap.cc0000644000175000017500000000013014050437223015043 0ustar frankfrank#include "hostent.ih" void Hostent::swap(Hostent &other) { fswap(*this, other); } bobcat-5.09.01/hostent/opis.f0000644000175000017500000000012714050437223014711 0ustar frankfrankinline Hostent &Hostent::operator=(Hostent &&tmp) { swap(tmp); return *this; } bobcat-5.09.01/hostent/destroy.cc0000644000175000017500000000053114050437223015567 0ustar frankfrank#include "hostent.ih" void Hostent::destroy() { if (h_name == 0) return; delete h_name; if (h_aliases) { for (char **ptr = h_aliases; *ptr; ++ptr) // delete aliases entries delete *ptr; delete [] h_aliases; // and the array itself. } delete h_addr_list; } bobcat-5.09.01/hostent/hostent1.cc0000644000175000017500000000026514050437223015647 0ustar frankfrank#include "hostent.ih" Hostent::Hostent() : d_nAliases(0), d_nAddresses(0) { h_name = 0; h_aliases = 0; h_addrtype = 0; h_length = 0; h_addr_list = 0; } bobcat-5.09.01/hostent/alias.f0000644000175000017500000000015014050437223015024 0ustar frankfrankinline char const *Hostent::alias(size_t nr) const { return nr >= d_nAliases ? 0 : h_aliases[nr]; } bobcat-5.09.01/hostent/addresstype.f0000644000175000017500000000010614050437223016263 0ustar frankfrankinline size_t Hostent::addressType() const { return h_addrtype; } bobcat-5.09.01/hostent/driver/0000755000175000017500000000000014050437223015063 5ustar frankfrankbobcat-5.09.01/hostent/driver/build0000755000175000017500000000045614050437223016115 0ustar frankfrank#!/bin/bash tput clear GPP="g++ `cat ../../c++std`" CMD="$GPP -o driver -Wall -I../ driver.cc -L../tmp -lhostent -lbobcat -s" # CMD="$GPP -o driver -Wall -I../../tmp driver.cc -L../../tmp/lib -lbobcat -s" # CMD="$GPP -o driver -Wall *.cc -lbobcat -s" echo $CMD $CMD || exit 1 echo Ready... driver bobcat-5.09.01/hostent/driver/driver.cc0000644000175000017500000000130514050437223016664 0ustar frankfrank/* driver.cc */ #include "../hostent" #include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) { Hostent he(gethostbyname("localhost")); { Hostent he2(he); cout << "The local hostname = " << he2.hostname() << endl; cout << "All aliases: " << endl; copy(he2.beginAlias(), he2.endAlias(), ostream_iterator(cout, "\n")); cout << "Addresses:\n"; for (size_t idx = 0; idx < he2.nAddresses(); idx++) cout << he2.dottedDecimalAddress(idx) << endl; cout << "he2 destroyed\n"; } } bobcat-5.09.01/hostent/copy.cc0000644000175000017500000000117414050437223015054 0ustar frankfrank#include "hostent.ih" void Hostent::copy(hostent const *other, size_t n_aliases, size_t n_addresses) { d_nAliases = n_aliases; d_nAddresses = n_addresses; h_addrtype = other->h_addrtype; h_length = other->h_length; h_name = xstrdup(other->h_name); h_aliases = new char *[d_nAliases]; for (size_t idx = 0; idx < n_aliases; idx++) h_aliases[idx] = xstrdup(other->h_aliases[idx]); h_addr_list = reinterpret_cast( memcpy(new char [n_addresses * h_length], other->h_addr_list, n_addresses * h_length)); } bobcat-5.09.01/hostname/0000755000175000017500000000000014050437223013722 5ustar frankfrankbobcat-5.09.01/hostname/build0000755000175000017500000004302514050437223014753 0ustar frankfrank#!/usr/bin/icmake -qt/tmp/hostname // script generated by the C++ icmake script version 2.02 /* Configurable defines for the build script: CLASSES: string of directory-names under which sources of classes are found. E.g., CLASSES = "class1 class2" All class-names must be stored in one string. If classes are removed from the CLASSES definition or if the names in the CLASSES definition are reordered, the compilation should start again from scratch. */ string CLASSES; void setClasses() { // ADD ADDITIONAL DIRECTORIES CONTAINING SOURCES OF CLASSES HERE // Use the construction `CLASSES += "classname1 classname2";' etc. CLASSES += " "; } /* Default values for the following variables are found in $IM/default/defines.fm BUILD_LIBRARY: define this if you want to create a library for the object modules. Undefined by default: so NO LIBRARY IS BUILT. This links ALL object files to a program, which is a faster process than linking to a library. But it can bloat the executable: all o-modules, rather than those that are really used, become part of the program's code. When defined as an EMPTY STRING, the static library libXXX.a is created: all programs linked to this library will themselves contain the code of the required object modules. This will result in code duplication over different programs linked to this library. When defined as a VERSION STRING, e.g., 1.0.4, a shared library libXXX.so.VERSION is constructed, as well as the links libXXX.so.MAINVERSION and libXXX.so (e.g. 1.0.0 creates libXXX.so.1.0.0, libXXX.so.1 and libXXX.so). Note that with a shared library, the library is always constructed fresh from the compiled object files. But programs linked to this library will SHARE the code stored in the shared library. These programs will therefore tend to be relatively small. Also note that `ldconfig -v' might be required after installing a shared library (libXXX.so) for the first time, so that the linker knows of its existence (in ld.so.cache) BUILD_PROGRAM: define if a program is to be built. If not defined, library maintenance is assumed (default: defined). COMPILER: The compiler to use. COPT: C-options used by COMPILER ECHO_REQUEST: ON (default) if command echoing is wanted, otherwise: set to OFF GDB: define if gdb-symbolic debug information is wanted (not defined by default) LIBS: Extra libraries used for linking LIBPATH: Extra library-searchpaths used for linking LOCAL_NAMESPACE:The namespace that you, the programmer, use yourself. USING: List of :-separated namespaces to be used in sources and .fh files, appearing in `using' directives. USING does NOT automatically include LOCAL_NAMESPACE: add your LOCAL_NAMESPACE name to this list if want a `using' directive for your own namespace as well. Note that namespaces are NOT part of the build-script: they are only listed below for convenience. When they must be altered, the defaults must be changed in $IM/default/defines.fm RELINK: Defined by default, causing a program to be relinked every time the script is called. Do not define it if relinking should only occur if a source is compiled. No effect for library maintenance. Current values: */ //#define BUILD_LIBRARY "" #define BUILD_PROGRAM #define COMPILER "g++-3.2" #define COPT "-Wall -fsize_t-char" #define ECHO_REQUEST 1 //#define GDB "-g" #define ICMAKE "/usr/bin/icmake" #define LIBS "" #define LIBPATH "" // local namespace is: FBB // using-declarations generated for: std:FBB // NO CONFIGURABLE PARTS BELOW THIS LINE /* V A R S . I M */ string // contain options for cwd, // current WD libs, // extra libs, e.g., "-lrss -licce" libpath, // extra lib-paths, eg, "-L../rss" copt, // Compiler options lopt, // Linker options libxxx, // full library-path libso, // symbolic link to so.major library path libsomajor, // lib.so.major path ofiles, // wildcards for o-files sources, // sources to be used current; // contains name of current dir. int nClasses, // number of classes/subdirectories program, // 1: program is built so_lib; // 1: so_lib is built list classes; // list of classes/directories /* parser.fm */ void parser() { #ifdef GRAMBUILD chdir("parser/gramspec"); system("grambuild"); chdir(".."); if ( exists("grammar") && "grammar" younger "parser.cc" ) // new parser needed { exec("bison++", "-d", "-o", "parser.cc", "grammar"); printf("Note: the compilation of parser.cc may produce " "several compiler warnings.\n"); } chdir(".."); #endif } /* S C A N N E R . I M */ void scanner() { string interactive; #ifdef INTERACTIVE interactive = "-I"; #endif #ifdef GRAMBUILD chdir("scanner"); if ( // new lexer needed exists("lexer") && ( "lexer" younger "yylex.cc" || "../parser/parser.h" younger "yylex.cc" ) ) { exec("flex++", interactive, "-oyylex.cc", "lexer"); printf("Note: the compilation of yylex.cc may produce " "several compiler warnings.\n"); } chdir(".."); #endif } /* I N I T I A L . I M */ void initialize() { echo(ECHO_REQUEST); sources = "*.cc"; ofiles = "o/*.o"; // std set of o-files copt = COPT; #ifdef GDB copt += " " + GDB; #endif #ifdef BUILD_PROGRAM program = 1; so_lib = 0; #else program = 0; #endif; #ifdef BUILD_LIBRARY if (strlen(BUILD_LIBRARY)) so_lib = !program; else so_lib = 0; #else if (!program) { printf("no program, no library ?\n"); exit(1); } #endif if (so_lib) copt += " -fPIC"; cwd = chdir("."); #ifdef GRAMBUILD CLASSES = "parser scanner "; if (exists("parser")) // subdir parser exists parser(); if (exists("scanner")) // subdir scannerexists scanner(); #endif setClasses(); // remaining classes classes = strtok(CLASSES, " "); // list of classes nClasses = sizeof(classes); } /* O B J F I L E S . I M */ list objfiles(list files) { string file, objfile; int i; for (i = 0; i < sizeof(files); i++) { file = element(i, files); // determine element of the list objfile = "./o/" + change_ext(file, "o"); // make obj-filename if (objfile younger file) // objfile is younger { files -= (list)file; // remove the file from the list i--; // reduce i to test the next } } return (files); } /* A L T E R E D . I M */ list altered(list files, string target) { int i; string file; for (i = 0; i < sizeof(files); i++) // try all elements of the list { file = element(i, files); // use element i of the list if (file older target) // a file is older than the target { files -= (list)file; // remove the file from the list i--; // reduce i to inspect the next } // file of the list } return (files); // return the new list } /* F I L E L I S T . I M */ list file_list(string type, string library) { list files; files = makelist(type); // make all files of certain type #ifdef BUILD_LIBRARY if (!so_lib) // keep all files with so libs files = altered(files, library);// keep all files newer than lib. #endif files = objfiles(files); // remove if younger .obj exist return (files); } /* L I N K . I M */ void link(string library, string exe) { printf("\n"); exec(COMPILER, "-o", exe, #ifdef BUILD_LIBRARY "-l" + library, #else ofiles, #endif libs, #ifdef GRAMBUILD "-lfl", #endif "-L.", libpath, lopt #ifndef GDB , "-s" #endif ); printf("ok: ", exe, "\n"); } /* P R E F I X C L . I M */ void prefix_class(string class_id) { list o_files; string o_file; int i; chdir("o"); o_files = makelist("*.o"); for (i = 0; o_file = element(i, o_files); i++) exec("mv", o_file, class_id + o_file); chdir(".."); } /* R M C L A S S P . I M */ #ifdef BUILD_LIBRARY string rm_class_id(string class_id, string ofile) { string ret; int index, n; n = strlen(ofile); for (index = strlen(class_id); index < n; index++) ret += element(index, ofile); return ret; } #endif void rm_class_prefix(string class_id) { #ifdef BUILD_LIBRARY list o_files; string o_file; int i; chdir("o"); o_files = makelist("*.o"); for (i = 0; o_file = element(i, o_files); i++) exec("mv", o_file, rm_class_id(class_id, o_file)); chdir(".."); #endif } /* L I N K S O . I M */ void link_solib(string library) { string gdb; #ifdef GDB gdb = GDB; #endif #ifdef BUILD_LIBRARY int index; list sofiles, version; version = strtok(BUILD_LIBRARY, "."); libso = "lib" + library + ".so"; libxxx = libso + "."; libsomajor = libxxx + element(0, version); libxxx += BUILD_LIBRARY; for (index = 0; index < nClasses; index++) { current = element(index, classes); // determine class name chdir(current); // chdir to a class directory. prefix_class((string)index); chdir(cwd); // go back to parent dir } if (!makelist("o/*.o")) ofiles = "*/o/*.o"; printf("\n"); exec(COMPILER, gdb, "-shared", "-Wl,-soname," + libsomajor, "-o", libxxx, ofiles, libs, "-L.", libpath, lopt ); printf("ok: ", libxxx, "\n"); for (index = 0; index < nClasses; index++) { current = element(index, classes); // determine class name chdir(current); // chdir to a class directory. rm_class_prefix((string)index); chdir(cwd); // go back to parent dir } exec("ln", "-sf", libxxx, libsomajor); printf("ok: ", libsomajor, "\n"); exec("ln", "-sf", libsomajor, libso); printf("ok: ", libso, "\n"); #endif } /* C C O M P I L E . I M */ void c_compile(list cfiles) { string nextfile; int i; if (!exists("o")) system("mkdir o"); if (sizeof(cfiles)) // files to compile ? { printf("\ncompiling: ", current, "\n\n"); // compile all files separately for (i = 0; nextfile = element(i, cfiles); i++) exec(COMPILER, "-c -o o/" + change_ext(nextfile, "o"), copt, nextfile); printf("\n"); } printf("ok: ", current, "\n"); } /* U P D A T E L I . I M */ void updatelib(string library) { #ifdef BUILD_LIBRARY list arlist, objlist; string to, from; objlist = makelist("o/*.o"); if (!sizeof(objlist)) return; printf("\n"); exec("ar", "rvs", library, "o/*.o"); exec("rm", "o/*.o"); printf("\n"); #endif } /* S T D C P P . I M */ void std_cpp(string library) { list cfiles; cfiles = file_list(sources, library); // make list of all cpp-files c_compile(cfiles); // compile cpp-files } /* C P P M A K E . C CPP files are processed by stdmake. Arguments of CPPMAKE: cpp_make( string mainfile, : name of the main .cpp file, or "" for library maintenance string library, : name of the local library to use/create (without lib prefix or .a/.so suffix (E.g., use `main' for `libmain.a') string exe, : (path) name of the exe file to create ) Both mainfile and library MUST be in the current directory */ void cpp_make(string mainfile, string library, string exe) { int index; if (nClasses) ofiles += " */o/*.o"; // set ofiles for no LIBRARY use // make library name #ifdef BUILD_LIBRARY if (!so_lib) libxxx = chdir(".") + "lib" + library + ".a"; #endif // first process all classes for (index = 0; index < nClasses; index++) { current = element(index, classes); // next class to process chdir(current); // change to directory current = "subdir " + current; std_cpp(libxxx); // compile all files chdir(cwd); // go back to parent dir } current = "auxiliary " + sources + " files"; std_cpp(libxxx); // compile all files in current dir #ifdef BUILD_LIBRARY if (!so_lib) { // prefix class-number for .o files for (index = 0; index < nClasses; index++) { current = element(index, classes); // determine class name chdir( current); // chdir to a class directory. prefix_class((string)index); updatelib(libxxx); chdir(cwd); // go back to parent dir } current = ""; // no class anymore updatelib(libxxx); // update lib in current dir } else { link_solib(library); // separate processing for so-lib return; } #endif if (mainfile != "") // mainfile -> do link { link(library, exe); printf ( "\nProgram construction completed.\n" "\n" ); } } /* S E T L I B S . I M */ void setlibs() { #ifdef LIBS int n, index; list cut; cut = strtok(LIBS, " "); // cut op libraries n = sizeof(cut); for (index = 0; index < n; index++) libs += " -l" + element(index, cut); #ifdef GRAMBUILD libs += " -lfl"; #endif cut = strtok(LIBPATH, " "); // cut up the paths n = sizeof(cut); for (index = 0; index < n; index++) libpath += " -L" + element(index, cut); #endif } void main() { initialize(); setlibs(); #ifdef BUILD_PROGRAM cpp_make ( "hostname.cc", // program source "hostname", // static program library "hostname" // binary program ); #else cpp_make ( "", "hostname", // static- or so-library "" ); #endif } bobcat-5.09.01/hostname/hostname0000644000175000017500000000072314050437223015465 0ustar frankfrank#ifndef INCLUDED_BOBCAT_HOSTNAME_ #define INCLUDED_BOBCAT_HOSTNAME_ #include namespace FBB { class InetAddress; class Hostname: public Hostent { public: Hostname() = default; // may be name or dotted decimal address explicit Hostname(std::string const &host); // 1 explicit Hostname(InetAddress const &address); // 2 private: void init(); }; } // FBB #endif bobcat-5.09.01/hostname/hostname1.cc0000644000175000017500000000023614050437223016131 0ustar frankfrank#include "hostname.ih" Hostname::Hostname(string const &host) : Hostent(GetHostent::gethostent("Hostname::Hostname(std::string)", host)) { init(); } bobcat-5.09.01/hostname/init.cc0000644000175000017500000000026514050437223015177 0ustar frankfrank#include "hostname.ih" void Hostname::init() { if (addressType() != AF_INET) throw Exception{} << "Hostname::init(): no AF_INET address type found"; } bobcat-5.09.01/hostname/hostname.ih0000644000175000017500000000030214050437223016055 0ustar frankfrank#include "hostname" #include "../inetaddress/inetaddress" #include "../gethostent/gethostent" #include #include "../exception/exception" using namespace std; using namespace FBB; bobcat-5.09.01/hostname/hostname2.cc0000644000175000017500000000137514050437223016137 0ustar frankfrank#include "hostname.ih" /* initialize the Hostent part by - obtaining a hostent struct from the GetHostent::gethostent() function, - providing it with the dotted-decimal address obtained from the GetHostent::addressToString() function, - which function is given the binary address obtained from the InetAddress parameter. */ namespace { static char const name[] = "Hostname::Hostname(InetAddress)"; } Hostname::Hostname(InetAddress const &address) : Hostent ( GetHostent::gethostent ( ::name, GetHostent::addressToString ( ::name, address.sockaddrPtr() ) ) ) { init(); } bobcat-5.09.01/hostname/driver/0000755000175000017500000000000014050437223015215 5ustar frankfrankbobcat-5.09.01/hostname/driver/build0000755000175000017500000000045714050437223016250 0ustar frankfrank#!/bin/bash tput clear GPP="g++ `cat ../../c++std`" # CMD="$GPP -o driver -Wall -I../ driver.cc -L../tmp -lhostname -lbobcat -s" # CMD="$GPP -o driver -Wall -I../../tmp driver.cc -L../../tmp/lib -lbobcat -s" CMD="$GPP -o driver -Wall *.cc -lbobcat -s" echo $CMD $CMD || exit 1 echo Ready... driver bobcat-5.09.01/hostname/driver/driver.cc0000644000175000017500000000166314050437223017025 0ustar frankfrank#include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) { while (true) { cout << "Enter name or address:\n"; string str; if (!getline(cin, str)) return 0; if (str == "") break; try { Hostname h(str); cout << "Official name:\n"; cout << h.hostname() << endl; cout << "Aliases:\n"; for (size_t idx = 0; idx < h.nAliases(); idx++) cout << h.alias(idx) << " "; cout << endl; cout << "Adresses:\n"; for (size_t idx = 0; idx < h.nAddresses(); idx++) cout << h.dottedDecimalAddress(idx) << " "; cout << endl; } catch (exception const &err) { cout << err.what() << endl; } } } bobcat-5.09.01/ibase64buf/0000755000175000017500000000000014050437223014036 5ustar frankfrankbobcat-5.09.01/ibase64buf/ibase64buf.ih0000644000175000017500000000012614050437223016311 0ustar frankfrank#include "ibase64buf" using namespace std; using namespace FBB; using namespace IUO; bobcat-5.09.01/ibase64buf/ibase64buf0000644000175000017500000000106614050437223015716 0ustar frankfrank#ifndef INCLUDED_BOBCAT_IBASE64BUF_ #define INCLUDED_BOBCAT_IBASE64BUF_ #include #include namespace FBB { template class IBase64Buf; template <> class IBase64Buf: public IUO::Base64BufBase { public: IBase64Buf(std::istream &in, size_t bufSize = 1000); // 1.f }; template <> class IBase64Buf: public IUO::Base64BufBase { public: IBase64Buf(std::istream &in, size_t bufSize = 1000); // 2.f }; #include "ibase64buf1.f" #include "ibase64buf2.f" } // FBB #endif bobcat-5.09.01/ibase64buf/ibase64buf1.f0000644000175000017500000000017714050437223016225 0ustar frankfrankinline IBase64Buf::IBase64Buf(std::istream &in, size_t bufSize) : Base64BufBase(in, bufSize) { doEncrypt(); } bobcat-5.09.01/ibase64buf/ibase64buf2.f0000644000175000017500000000017714050437223016226 0ustar frankfrankinline IBase64Buf::IBase64Buf(std::istream &in, size_t bufSize) : Base64BufBase(in, bufSize) { doDecrypt(); } bobcat-5.09.01/ibase64buf/driver/0000755000175000017500000000000014050437223015331 5ustar frankfrankbobcat-5.09.01/ibase64buf/driver/build0000644000175000017500000000022314050437223016350 0ustar frankfrank#!/bin/bash # For development purposes: g++ `cat ../../c++std` -O2 -Wall -o driver -isystem ../../tmp driver.cc \ -L ../../tmp/lib/ -lbobcat bobcat-5.09.01/ibase64buf/driver/driver.cc0000644000175000017500000000165214050437223017137 0ustar frankfrank#include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) { switch (argv[1][0]) { case 'e': { IBase64Buf encode(cin); istream ein(&encode); cout << ein.rdbuf(); } break; case 'd': { IBase64Buf decode(cin); istream din(&decode); cout << din.rdbuf(); } break; case 'b': { IBase64Buf encode(cin); istream ein(&encode); IBase64Buf decode(ein); istream din(&decode); cout << din.rdbuf(); } break; default: cout << "Usage: " << argv[0] << " [edb] < infile > outfile\n" "to base64 -e-ncode, -d-ecode or -b-oth\n"; break; } } bobcat-5.09.01/ibase64stream/0000755000175000017500000000000014050437223014555 5ustar frankfrankbobcat-5.09.01/ibase64stream/ibase64stream.ih0000644000175000017500000000010414050437223017543 0ustar frankfrank#include "ibase64stream" using namespace std; using namespace FBB; bobcat-5.09.01/ibase64stream/ibase64stream0000644000175000017500000000063214050437223017152 0ustar frankfrank#ifndef INCLUDED_BOBCAT_IBASE64STREAM_ #define INCLUDED_BOBCAT_IBASE64STREAM_ #include #include // #include "../ibase64buf/ibase64buf" namespace FBB { template struct IBase64Stream: private IBase64Buf, public std::istream { IBase64Stream(std::istream &in, size_t bufSize = 1000); // 1.f }; #include "ibase64stream1.f" } // FBB #endif bobcat-5.09.01/ibase64stream/ibase64stream1.f0000644000175000017500000000023614050437223017457 0ustar frankfranktemplate IBase64Stream::IBase64Stream(std::istream &in, size_t bufSize) : IBase64Buf(in, bufSize), std::istream(this) {} bobcat-5.09.01/ibase64stream/driver/0000755000175000017500000000000014050437223016050 5ustar frankfrankbobcat-5.09.01/ibase64stream/driver/driver.cc0000644000175000017500000000022014050437223017644 0ustar frankfrank#include "../ibase64stream" #include using namespace std; using namespace FBB; int main() { IBase64Stream in(cin); } bobcat-5.09.01/icmake/0000755000175000017500000000000014050437223013335 5ustar frankfrankbobcat-5.09.01/icmake/installer0000755000175000017500000000050714050437223015262 0ustar frankfrank#!/bin/bash if [ $# -eq 0 ] ; then echo destination path, ending in /, must be provided exit 0 fi for src in `find -mindepth 1 -type d` # create missing target dirs do [ ! -e $1$src ] && mkdir -p $1$src done for file in `find -type f -or -type l` do cp -d --preserve=timestamps $file $1$file done bobcat-5.09.01/icmake/libraries0000644000175000017500000001112614050437223015235 0ustar frankfrankvoid catFile(string destination, string source) { list record; string line; while (1) { record = fgets(source, record); // get a line from source if (!record) // all done: leave. break; line = record[0] + "\n"; // get the line's contents if ( strfind(line, "#include \"") == 0 && strfind(line, ".f\"") != -1 ) // saw #include catFile(destination, strtok(line, "\"")[1]); // then include .f else // or write the line fprintf(destination, line); // to the dest. } } void buildHeader(string destination, string class, list iFiles) { echo(OFF); run("rm -f " + g_cwd + g_tmphdr + class); echo(ON); printf("Header ", g_tmphdr, class, "\n"); // show the name of the header // to construct catFile(destination, class); } void _iFiles(string class) { int idx; string destination; list iFiles; int recreate = 0; destination = g_cwd + g_tmphdr + class; chdir(class); // the destination file name iFiles = makelist("*.f"); // create list of all f-files if (class newer destination) recreate = 1; else { for (idx = listlen(iFiles); idx--; ) { if (iFiles[idx] newer destination) { recreate = 1; break; } } } if (recreate) buildHeader(destination, class, iFiles); chdir(g_cwd); } void _cpHeaders() { int idx; for (idx = g_nClasses; idx--; ) _iFiles(g_classes[idx]); } int g_gch = 1; void _precompileHeaders() { int idx; string class; string classIH; string compiler; if (!g_gch) return; compiler = g_cxx + " " + g_copt + " -isystem " + g_cwd + "tmp"; for (idx = g_nClasses; idx--; ) { class = g_classes[idx]; classIH = class + ".ih"; chdir(class); if (classIH younger class + ".ih.gch") run(compiler + " -x c++-header " + classIH); chdir(g_cwd); } } void static_library(string library) { if (listlen(makelist("*/oa/*.o"))) { printf("\n" "Creating static library ", library, "\n"); run("ar cr " + library + " */oa/*.o"); run("ranlib " + library); // run("rm */oa/*.o"); } } void _shared_library(string libso, string libsoshared, int strip) { string libsomajor; string gxx; gxx = g_cxx + " " + g_copt; if (listlen(makelist("*/os/*.o"))) { printf("\n" "Creating shared library ", libso, "\n"); libsomajor = libso + "." + element(0, strtok(g_version, ".")); run(gxx + " " + setOpt(LDFLAGS, "LDFLAGS") + " -pthread -shared -Wl,--as-needed," "-z,defs,-soname," + libsomajor + " -o " + g_tmplibso + "/" + libsoshared + " */os/*.o " + g_sharedLibReq); chdir(g_tmplibso); if (strip) run("strip --strip-unneeded " + libsoshared); run("chmod -x " + libsoshared); run("ln -sf " + libsoshared + " " + libsomajor); chdir(g_cwd + g_tmpliba); run("ln -sf " + libsomajor + " " + libso); chdir(g_cwd); // run("rm -f */os/*"); } } void libraries(int keepPch, string libname, int all, int strip, int select, int headersOnly) { string libso; string libsoshared; string staticLib; staticLib = g_tmpliba + "/lib" LIBRARY ".a"; addClasses("CLASSES"); special(1, all, select); md(g_tmpliba + " " + g_tmphdr + " " + g_tmplibso); _cpHeaders(); if (headersOnly) return; _precompileHeaders(); g_copt += " -isystem tmp"; library("oa", staticLib); // compile for static lib. static_library(staticLib); // build static library #ifdef BUILD_SHARED libso = "lib" LIBRARY ".so"; libsoshared = libso + "." + g_version; g_copt += " -fPIC"; // adds option for shared lib library("os", g_tmplibso + "/" + libsoshared); // compile the shared lib _shared_library(libso, libsoshared, strip); #endif // if (!keepPch) // run("rm -rf */*.ih.gch"); exit(0); } bobcat-5.09.01/icmake/findall0000644000175000017500000000107414050437223014673 0ustar frankfrank// assuming we're in g_cwd, all entries of type 'type' matching source/pattern // are returned w/o final \n list findAll(string type, string source, string pattern) { string cmd; list entries; list ret; int idx; chdir(source); cmd = "find ./ -mindepth 1 -maxdepth 1 -type " + type; if (pattern != "") pattern = "-name '" + pattern + "'"; entries = backtick(cmd + " " + pattern + " -printf \"%f\\n\""); for (idx = listlen(entries); idx--; ) ret += (list)cutEoln(entries[idx]); chdir(g_cwd); return ret; } bobcat-5.09.01/icmake/log0000755000175000017500000000063214050437223014045 0ustar frankfrank#!/bin/bash find tmp/install -type f -exec md5sum "{}" \; | sed 's|tmp/install|'$1'|' > $2 find tmp/install -type l -exec printf "link %s\n" "{}" \; | sed 's|tmp/install|'$1'|' >> $2 find tmp/install -type d -exec printf "dir %s\n" "{}" \; | sed 's|tmp/install|'$1'|' >> $2 bobcat-5.09.01/icmake/man0000644000175000017500000000270214050437223014034 0ustar frankfrankvoid man() { list yo; string base; string yodl; int idx; special(0, 0, 0); md("tmp/man/man3 tmp/man/man7 tmp/manhtml"); chdir("documentation/man"); if (g_test) yo = (list)"align.yo"; else yo = makelist("*.yo") - (list)LIBRARY ".yo" - (list)"reverseiter.yo" - (list)"sharedreadme.yo"; printf(" Building the man3 man-pages"); for (idx = listlen(yo); idx--; ) { yodl = element(idx, yo); base = get_base(yodl); run("yodl2man --no-warnings -r 3 -o ../../tmp/man/man3/" + base + ".3" LIBRARY " " + yodl); run("yodl2html --no-warnings -r 3 -o ../../tmp/manhtml/" + base + ".3.html " + yodl); printf("."); } printf("\n" " Building the man7 man-pages\n"); run("yodl2man --no-warnings -r 3 -o ../../tmp/man/man7/" LIBRARY ".7 " LIBRARY ".yo"); run("yodl2html --no-warnings -r 3 " "-o ../../tmp/manhtml/" LIBRARY ".7.html " LIBRARY ".yo"); run("yodl2man --no-warnings -r 3 " "-o ../../tmp/man/man7/sharedreadme.7" LIBRARY " sharedreadme.yo"); run("yodl2html --no-warnings -r 3 " "-o ../../tmp/manhtml/sharedreadme.7.html " "sharedreadme.yo"); exit(0); } bobcat-5.09.01/icmake/library0000644000175000017500000000467214050437223014735 0ustar frankfrank list inspect(string dstDir, int prefix, list srcList, string library) { int idx; string ofile; string oprefix; oprefix = "./" + dstDir + "/" + (string)prefix; for (idx = listlen(srcList); idx--; ) { g_file = element(idx, srcList); ofile = oprefix + change_ext(g_file, "o"); // make o-filename // A file s must be recompiled if it's newer than its object // file o or (with static libraries) newer than its target library l, // or if neither o nor (with static libraries) l exist. // Since `a newer b' is true if a is newer than b, or if a exists and // b doesn't exist s must be compiled if s newer o and (with static // libraries) s newer l. // So, it doesn't have to be compiled if s older o or (with static // libraries) s older l. // redo if file has changed if ( g_file older ofile || dstDir == "oa" && g_file older library ) srcList -= (list)g_file; } return srcList; } // c_compile: compile all sources in `{srcDir}/{cfiles}', storing the object // files in {srcDir}/o/{prefix}filename.o // // uses: g_opt, md, run // void c_compile(string dstDir, int prefix, string srcDir, list cfiles) { int idx; string compdest; string pthread; printf("\n" "Compiling ", srcDir, "\n"); if (strfind(PTHREAD, srcDir) != -1) // requiring classes defined in pthread = " -pthread"; // INSTALL.im compdest = g_cxx + " " + g_copt + pthread + " -c -o " + srcDir + "/" + dstDir + "/" + (string)prefix; md(srcDir + "/" + dstDir); for (idx = listlen(cfiles); idx--; ) { g_file = element(idx, cfiles); run(compdest + change_ext(g_file, "o") + " " + srcDir + "/" + g_file); } } void std_cpp(string dstDir, int prefix, string srcDir, string library) { list files; chdir(srcDir); // make list of all files files = inspect(dstDir, prefix, makelist(g_sources), library); chdir(g_cwd); if (listlen(files)) c_compile(dstDir, prefix, srcDir, files); // compile files } void library(string dstDir, string libname) { int idx; g_sources = "*.cc"; for (idx = g_nClasses; idx--; ) std_cpp(dstDir, idx, element(idx, g_classes), "../" + libname); } bobcat-5.09.01/icmake/clean0000644000175000017500000000071414050437223014344 0ustar frankfrankstring remove1; string remove2; void setRemovals() { // always: remove1 = "debian/lib" LIBRARY "3 debian/lib" LIBRARY "3-dev " "build-stamp configure-stamp debian/*substvars"; // unless `minimal': remove2 = "*/driver/driver tmp release.yo */tmp */oa */os */o " "*/*.ih.gch"; } void clean() { setRemovals(); run("rm -rf " + remove1); run("rm -rf " + remove2); exit(0); } bobcat-5.09.01/icmake/uninstall0000644000175000017500000000045614050437223015276 0ustar frankfrankvoid uninstall(string logfile) { int idx; list entry; string dir; list line; if (!exists(logfile)) { printf("installation log file " + logfile + " not found\n"); exit(0); } run("icmake/remove " + logfile + " " + (string)g_echo); exit(0); } bobcat-5.09.01/icmake/cuteoln0000644000175000017500000000023314050437223014727 0ustar frankfrankstring cutEoln(string text) { int len; len = strlen(text) - 1; if (text[len] == "\n") text = substr(text, 0, len); return text; } bobcat-5.09.01/icmake/run0000644000175000017500000000015114050437223014061 0ustar frankfrankvoid run(string cmd) { if (g_echo == OFF) cmd += "> /dev/null 2>&1"; system(0, cmd); } bobcat-5.09.01/icmake/md0000644000175000017500000000074014050437223013661 0ustar frankfrank// md: target should be a series of blank-delimited directories to be created // If an element is a whildcard, the directory will always be created, // using mkdir -p. // // uses: run() void md(string target) { int idx; list paths; string dir; if (!exists(target)) run("mkdir -p " + target); else if (((int)stat(target)[0] & S_IFDIR) == 0) { printf(target + " exists, but is not a directory\n"); exit(1); } } bobcat-5.09.01/icmake/gitlab0000644000175000017500000000035414050437223014524 0ustar frankfrankvoid gitlab() { run("cp -r release.yo tmp/manhtml ../../wip"); run("cp changelog ../../wip/changelog.txt"); run("cp -r documentation/man/bobcat.jpg documentation/images " "../../wip/manhtml"); exit(0); } bobcat-5.09.01/icmake/remove0000755000175000017500000000117014050437223014557 0ustar frankfrank#!/bin/bash g_echo=$2 rm_f() { [ $g_echo -ne 0 ] && echo rm $1 rm -f $1 } rm_dir() { [ $g_echo -ne 0 ] && echo rmdir $1 rmdir --ignore-fail-on-non-empty -p $1 } IFS=" " for line in `cat $1` do field1=`echo $line | awk '{printf $1}'` field2=`echo $line | awk '{printf $2}'` if [ $field1 == "link" ] ; then rm_f $field2 elif [ $field1 == "dir" ] ; then rm_dir $field2 elif [ -e "$field2" ] ; then if [ "$field1" != "`md5sum $field2 | awk '{printf $1}'`" ] ; then echo $field2 changed, not removed else rm_f $field2 fi fi done rm_f $1 bobcat-5.09.01/icmake/backtick0000644000175000017500000000034014050437223015030 0ustar frankfranklist backtick(string arg) { list empty; list ret; echo(OFF); ret = `arg`; if (listlen(ret) == 1 && !ret[0]) // no output: clear the list ret = empty; echo(g_echo); return ret; } bobcat-5.09.01/icmake/man10000644000175000017500000000056614050437223014123 0ustar frankfrankvoid man1(string manpage) { string base; special(0, 0, 0); base = get_base(manpage); chdir("documentation/man"); printf(" Writing the ", manpage, " man page to `/tmp/", base + ".man'\n"); run("yodl2man --no-warnings -r 3 -o /tmp/" + base + ".man " + manpage); exit(0); } bobcat-5.09.01/icmake/getenv0000644000175000017500000000034014050437223014545 0ustar frankfrankstring setOpt(string install_im, string envvar) { list optvar; string ret; optvar = getenv(envvar); if (optvar[0] == "1") ret = optvar[1]; else ret = install_im; return ret; } bobcat-5.09.01/icmake/subset.sh0000755000175000017500000000046314050437223015204 0ustar frankfrank#!/bin/bash # This script is called by 'build' (or must be called from build's directory rm -f CLASSES.$$ for word in $* do required=`grep "^$word" dependencies/required.classes` for class in $required do echo $class >> CLASSES.$$ done done sort -u CLASSES.$$ rm -f CLASSES.$$ bobcat-5.09.01/icmake/addclasses0000644000175000017500000000050414050437223015365 0ustar frankfrankvoid addClasses(string filename) { list class; string elem; if (g_test) { g_classes += (list)"align"; return; } while (listlen(class = fgets(filename, class))) { elem = strtok(class[0], " \t\n")[0]; if (elem != "#") g_classes += (list)elem; } } bobcat-5.09.01/icmake/install0000644000175000017500000000522614050437223014733 0ustar frankfrank void install(string request, string dest) { string target; int components = 0; string base; base = "tmp/install/"; md(base); if (request == "x") components = 15; else { if (strfind(request, "d") != -1) components |= 1; if (strfind(request, "h") != -1) components |= 2; if (strfind(request, "l") != -1) components |= 4; if (strfind(request, "m") != -1) components |= 8; } if (components & 1) { printf("\n installing documentation\n"); logZip("", "READLINE " "README " "README.X11 " "README.class-setup " "README.immovable " "README.milter " "README.optimization " "README.process-pipe " "README.fnwrap " "process-pipe.odp " "process-pipe.pdf " "TODO", base + DOC "/"); logRecursive("documentation/examples", base + DOC "/examples"); logZip("scripts", "", base + DOC "/scripts"); logInstall("documentation/images", "*.jpg", base + DOC "/images"); target = base + DOC + "/man"; logInstall("tmp/manhtml", "", target); logInstall("documentation/man", LIBRARY ".jpg", target); chdir(g_cwd + target); run("ln -sf " LIBRARY ".7.html index.html"); run("ln -sf iterator.3.html reverseiterator.3.html"); chdir(g_cwd + target); logZip("", "README", base + DOC); } if (components & 2) { printf("\n installing the headers\n"); logInstall("tmp/" LIBRARY, "", base + HDR); } if (components & 4) { printf("\n installing the libraries\n"); logInstall(g_tmpliba, "", base + LIB); #ifdef BUILD_SHARED logInstall(g_tmplibso, "", base + LIB); #endif } if (components & 8) { printf("\n installing the manual pages\n"); logZip("tmp/man/man3", "", base + MAN "/man3"); run("ln -sf iterator.3bobcat.gz reverseiterator.3bobcat.gz"); logZip("tmp/man/man7", "", base + MAN "/man7"); } chdir(g_cwd); if (dest == "") dest = "/"; else md(dest); dest = cutEoln(backtick("readlink -f " + dest)[0]); if (g_logPath != "") backtick("icmake/log " + dest + " " + g_logPath); chdir(base); run("../../icmake/installer " + dest + "/"); printf("\n Installation completed\n"); exit(0); } bobcat-5.09.01/icmake/loginstall0000644000175000017500000000156514050437223015437 0ustar frankfrank// source and dest, absolute or reachable from g_cwd, should exist. // files and links in source matching dest (if empty: all) are copied to dest // and are logged in g_log // Before they are logged, dest is created void logInstall(string src, string pattern, string dest) { list entries; int idx; chdir(g_cwd); md(dest); src += "/"; dest += "/"; if (listlen(makelist(O_DIR, src)) == 0) { printf("Warning: ", src, " not found: can't install ", src, pattern, " at ", dest, "\n"); return; } entries = findAll("f", src, pattern); for (idx = listlen(entries); idx--; ) run("cp " + src + entries[idx] + " " + dest); chdir(g_cwd); entries = findAll("l", src, pattern); for (idx = listlen(entries); idx--; ) run("cp " CPOPTS " " + src + entries[idx] + " " + dest); } bobcat-5.09.01/icmake/logrecursive0000644000175000017500000000130014050437223015763 0ustar frankfrank// log recursively all files and directories in src as entries in dest // dest is created if necessary // e.g., src = logRecursive: documentation/examples // ... // documentation/examples/sockets/forkserver/handler/ void logRecursive(string src, string dest) { list dirs; string next; int idx; chdir(g_cwd); if (!exists(src)) { printf("skipping unavailable directory `", src, "'\n"); return; } dirs = findAll("d", src, ""); // find all subdirs for (idx = listlen(dirs); idx--; ) // visit all subdirs { next = "/" + dirs[idx]; logRecursive(src + next, dest + next); } logInstall(src, "", dest); } bobcat-5.09.01/icmake/special0000644000175000017500000001427014050437223014704 0ustar frankfrankvoid checkXpointer() { if (listfind(g_classes, "xpointer") != -1) g_sharedLibReq += " -lX11"; } void checkMilter() { if (listfind(g_classes, "milter") != -1) g_sharedLibReq += " -lmilter -L/usr/lib/libmilter"; } void checkReadLine() { list class; string elem; while (listlen(class = fgets("READLINE", class))) { elem = strtok(class[0], " \t\n")[0]; if (elem != "#" && listfind(g_classes, elem) != -1) { g_sharedLibReq += " -lreadline"; return; } } } void checkSSL() { list class; string elem; while (listlen(class = fgets("SSLCLASSES", class))) { elem = strtok(class[0], " \t\n")[0]; if (elem != "#" && listfind(g_classes, elem) != -1) { g_sharedLibReq += " -lssl -lcrypto"; return; } } } void askMilter(int all) { if (!all) printf( " The class FBB::Milter can only be compiled if you have installed\n" " the file libmilter/mfapi.h. To use the class Milter, programs using\n" " Milter objects must also be linked against the milter library:\n" " -lmilter -l" LIBRARY "\n" "\n" " The class FBB::Milter can safely be left out of the " LIBRARY " " "library if\n" " you're not planning to construct mail filters using FBB::Milter.\n" "\n" " Enter y if you WANT to compile the files of the class " "FBB::Milter.\n" " Press Enter or any other line if you DON'T WANT to include the " "class\n" " FBB::Milter in the " LIBRARY " library.\n" ); if (all || gets() == "y") { g_sharedLibReq += " -lmilter -L/usr/lib/libmilter"; g_classes += (list)"milter"; } } void askXpointer(int all) { if (!all) printf( " The class FBB::Xpointer can only be compiled if you have installed\n" " the file X11/Xlib.h. To use the class Xpointer, programs using " "Xpointer\n" " objects must also be linked against the X11 library: -lX11 -l" LIBRARY "\n" "\n" " The class FBB::Xpointer can safely be left out of the " LIBRARY " " "library if\n" " you're not planning to construct programs using Xpointer.\n" "\n" " Enter y if you WANT to compile the files of the class " "FBB::Xpointer.\n" " Press Enter or any other line if you DON'T WANT to include the " "class\n" " FBB::Xpointer in the " LIBRARY " library.\n" ); if (all || gets() == "y") { g_sharedLibReq += " -lX11"; g_classes += (list)"xpointer"; } } void askOpenSSL(int all) { if (!all) printf( " The SSL classes can only be compiled if you have installed\n" " the libssl-dev development library, containing files like\n" " /usr/include/openssl/bn.h. To use objects from openssl programs\n" " must also be linked against the openSSL library: -lssl -l" LIBRARY "\n" "\n" " The SSL classes can safely be left out of the " LIBRARY " library if\n" " you're not planning to construct programs using them.\n" "\n" " Enter y if you WANT to compile the files of the SSL classes\n" " Press Enter or any other line if you DON'T WANT to include the " "SSL classes\n" " in the " LIBRARY " library.\n" ); if (all || gets() == "y") { g_sharedLibReq += " -lssl -lcrypto"; addClasses("SSLCLASSES"); } } void askReadLine(int all) { if (!all) printf( " The classes using the readline library can only be compiled if you\n" " have installed the libreadline-dev development library, containing\n" " files like /usr/include/readline.h. To use objects of these\n" " classes in your programs, your programs must also be linked\n" " against the readline library: -lreadline -l" LIBRARY "\n" "\n" " The classes depending on the readline library can safely be left\n" " out of the " LIBRARY " library if you're not planning to construct\n" " programs using them.\n" "\n" " Enter y if you WANT to compile the classes using the\n" " readline library\n" " Press Enter or any other line if you DON'T WANT to include these\n" " classes in the " LIBRARY " library.\n" ); if (all || gets() == "y") { g_sharedLibReq += " -lreadline"; addClasses("READLINE"); } } void special(int query, int all, int select) { list cut; list line; int refresh; if (select) { checkXpointer(); checkMilter(); checkReadLine(); checkSSL(); } else if (g_all && query) { askXpointer(all); askOpenSSL(all); askReadLine(all); askMilter(all); } g_nClasses = listlen(g_classes); refresh = "VERSION" newer "release.yo"; if (refresh) run("rm -f release.yo"); while (listlen(line = fgets("VERSION", line))) { cut = strtok(element(0, line), "= \t\n"); if (element(0, cut) == "VERSION") { g_version = element(1, cut); if (refresh) fprintf("release.yo", "SUBST(_CurVers_)(", g_version, ")\n"); } else if (refresh && element(0, cut) == "YEARS") fprintf("release.yo", "SUBST(_CurYrs_)(", element(1, cut), ")\n"); } } bobcat-5.09.01/icmake/logzip0000644000175000017500000000165614050437223014574 0ustar frankfrank// names may be a series of files in src, not a wildcard. // if it's empty then all files in src are used. // the files are gzipped and logged in dest. // src and dest do not have to end in / void logZip(string src, string names, string dest) { list files; int idx; string file; chdir(g_cwd); md(dest); dest += "/"; if (src != "") { if (listlen(makelist(O_DIR, src)) == 0) { printf("Warning: ", src, " not found: can't install ", src, names, " at ", dest, "\n"); return; } chdir(src); } if (names == "") files = makelist("*"); else files = strtok(names, " "); for (idx = listlen(files); idx--; ) { file = files[idx]; run("gzip -n -9 < " + file + " > " + file + ".gz"); } run("tar cf - *.gz | (cd " + g_cwd + "; cd " + dest + "; tar xf -)"); run("rm *.gz"); } bobcat-5.09.01/icmconf.lib0000644000175000017500000000076214050437223014217 0ustar frankfrank// #define PRECOMP "-x c++-header" #define CLS #define SOURCES "*.cc" #define OBJ_EXT ".o" #define TMP_DIR "tmp" #define USE_ECHO ON #define IH ".ih" #define CXX "g++" #define CXXFLAGS " --std=c++2a -Wall -O2 -I../tmp" \ " -fdiagnostics-color=never $EXTRAFLAGS" #define ADD_LIBRARIES "bobcat" #define ADD_LIBRARY_PATHS "" #define DEFCOM "library" bobcat-5.09.01/ifdbuf/0000755000175000017500000000000014050437223013343 5ustar frankfrankbobcat-5.09.01/ifdbuf/ifdbuf4.cc0000644000175000017500000000017214050437223015175 0ustar frankfrank#include "ifdbuf.ih" IFdBuf::IFdBuf(int fd, Mode mode, size_t size) : d_mode(mode) { reset(fd, KEEP_FD, size); } bobcat-5.09.01/ifdbuf/ifdbuf2.cc0000644000175000017500000000010614050437223015170 0ustar frankfrank#include "ifdbuf.ih" IFdBuf::IFdBuf(Mode mode) : d_mode(mode) {} bobcat-5.09.01/ifdbuf/ifdbuf3.cc0000644000175000017500000000022514050437223015173 0ustar frankfrank#include "ifdbuf.ih" IFdBuf::IFdBuf(int fd, size_t size) : d_mode(KEEP_FD) // comply with old default { reset(fd, KEEP_FD, size); } bobcat-5.09.01/ifdbuf/reset.cc0000644000175000017500000000025614050437223014777 0ustar frankfrank#include "ifdbuf.ih" void IFdBuf::reset(int fd, Mode mode, size_t size) { cleanup(mode); d_fd = fd; resize(size == 0 ? 1 : size); setg(size, size); } bobcat-5.09.01/ifdbuf/ifdbuf.ih0000644000175000017500000000027214050437223015125 0ustar frankfrank#include "ifdbuf" //#include //#define CERRX std::cerr << __FILE__": " #include #include #include using namespace FBB; using namespace std; bobcat-5.09.01/ifdbuf/xsgetn.cc0000644000175000017500000000142514050437223015164 0ustar frankfrank#include "ifdbuf.ih" std::streamsize IFdBuf::xsgetn(char *dest, std::streamsize size) { if (size == 0) return 0; // this function is called from istream's read() member. // it copies what's available in the IFdBuf's own buffer and // will then try to read some more from the fd, adding it to the // destination buffer. Unless the requested amount of information is // available the stream's good() member will return false. Calling // programs may have to clear the stream's flags when, e.g., // at least one byte was read int avail = egptr() - gptr(); if (avail > size) avail = size; memcpy(dest, gptr(), avail); gbump(avail); return avail + read(d_fd, dest + avail, size - avail); } bobcat-5.09.01/ifdbuf/close.f0000644000175000017500000000006714050437223014622 0ustar frankfrankinline void IFdBuf::close() { cleanup(CLOSE_FD); } bobcat-5.09.01/ifdbuf/ifdbuf1.cc0000644000175000017500000000014514050437223015172 0ustar frankfrank#include "ifdbuf.ih" IFdBuf::IFdBuf() : d_mode(KEEP_FD) // comply with old default {} bobcat-5.09.01/ifdbuf/destructor.cc0000644000175000017500000000010214050437223016041 0ustar frankfrank#include "ifdbuf.ih" IFdBuf::~IFdBuf() { cleanup(d_mode); } bobcat-5.09.01/ifdbuf/fd.f0000644000175000017500000000006314050437223014102 0ustar frankfrankinline int IFdBuf::fd() const { return d_fd; } bobcat-5.09.01/ifdbuf/underflow.cc0000644000175000017500000000071214050437223015657 0ustar frankfrank#include "ifdbuf.ih" int IFdBuf::underflow() { // if (gptr() < egptr()) // return static_cast(*gptr()); int nread = read(d_fd, &buffer()[0], bufSize()); if (nread <= 0) return EOF; setg(0, nread); // the static_cast is required to prevent // promotions of 0xff characters to -1, thus returning EOF... return static_cast(*gptr()); } bobcat-5.09.01/ifdbuf/cleanup.cc0000644000175000017500000000030214050437223015274 0ustar frankfrank#include "ifdbuf.ih" void IFdBuf::cleanup(Mode mode) { // CERRX << buffer() << '\n'; if (d_fd == -1) return; if (mode == CLOSE_FD) ::close(d_fd); d_fd = -1; } bobcat-5.09.01/ifdbuf/reset.f0000644000175000017500000000012014050437223014625 0ustar frankfrankinline void IFdBuf::reset(int fd, size_t size) { reset(fd, d_mode, size); } bobcat-5.09.01/ifdbuf/ifdbuf0000644000175000017500000000324114050437223014525 0ustar frankfrank#ifndef INCLUDED_BOBCAT_IFDBUF_ #define INCLUDED_BOBCAT_IFDBUF_ #include namespace FBB { class IFdBuf: public EoiBuf { public: // Mode defines what to do with the file descriptor at // destruction-time or when the default open is // called. CLOSE_FD will close the fd, KEEP_FD will leave the // fd as-is. When open is called with a Mode argument, then // the provided argument is used for the actual fd. The Mode // specified at the constructor is therefore only used for the // mode-less open() call and for the destructor. enum Mode { CLOSE_FD, KEEP_FD, }; private: Mode d_mode; int d_fd = -1; public: IFdBuf(); // 1 IFdBuf(IFdBuf const &other) = delete; explicit IFdBuf(Mode mode); // 2 explicit IFdBuf(int fd, size_t size = 1); // 3 IFdBuf(int fd, Mode mode, size_t size = 1); // 4 ~IFdBuf() override; IFdBuf &operator=(IFdBuf const &other) = delete; void reset(int xfd, Mode mode, size_t size = 1); // .cc void reset(int xfd, size_t size = 1); // .f void close(); // .f int fd() const; // .f private: int underflow() override; std::streamsize xsgetn(char *dest, std::streamsize n) override; void cleanup(Mode mode); }; #include "reset.f" #include "close.f" #include "fd.f" } // FBB #endif bobcat-5.09.01/ifdbuf/driver/0000755000175000017500000000000014050437223014636 5ustar frankfrankbobcat-5.09.01/ifdbuf/driver/build0000755000175000017500000000060214050437223015661 0ustar frankfrank#!/bin/sh # # g++ -I. --std=c++2a -O2 -Wall -o driver driver.cc -lssl -lbobcat \ # -L../../ohexbuf/tmp -L../tmp -lhmacbuf -lohexbuf # tput clear GPP="g++ --std=c++2a" # Using tmp libraries and bobcat CMD="$GPP -o driver -Wall -I../tmp driver.cc \ -L../tmp -lifdbuf \ -L../../eoibuf/tmp -leoibuf \ -L../../eoi/tmp -leoi \ -lbobcat -s" echo ${CMD} ${CMD} bobcat-5.09.01/ifdbuf/driver/driver.cc0000644000175000017500000000054614050437223016445 0ustar frankfrank#include #include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) { // define a streambuf of 20 or argv[1] characters IFdBuf buf{ STDIN_FILENO, argc == 1 ? 20 : stoul(argv[1]) }; istream in{ &buf }; cout << in.rdbuf(); } bobcat-5.09.01/ifdstream/0000755000175000017500000000000014050437223014062 5ustar frankfrankbobcat-5.09.01/ifdstream/ifdstream0000644000175000017500000000047114050437223015765 0ustar frankfrank#ifndef INCLUDED_BOBCAT_IFDSTREAM_ #define INCLUDED_BOBCAT_IFDSTREAM_ #include #include namespace FBB { class IFdStream: private IFdBuf, public std::istream { public: explicit IFdStream(int fd, size_t n = 1); // 1.f }; #include "ifdstream1.f" } // FBB #endif bobcat-5.09.01/ifdstream/ifdstream1.f0000644000175000017500000000013514050437223016267 0ustar frankfrankinline IFdStream::IFdStream(int fd, size_t n) : IFdBuf(fd, n), std::istream(this) {} bobcat-5.09.01/ifilterbuf/0000755000175000017500000000000014050437223014237 5ustar frankfrankbobcat-5.09.01/ifilterbuf/showmanyc.cc0000644000175000017500000000017714050437223016563 0ustar frankfrank#include "ifilterbuf.ih" std::streamsize IFilterBuf::showmanyc() { return (d_srcEnd - d_srcBegin) + (egptr() - gptr()); } bobcat-5.09.01/ifilterbuf/ifilterbuf0000644000175000017500000000126114050437223016315 0ustar frankfrank#ifndef INCLUDED_BOBCAT_IFILTERBUF_ #define INCLUDED_BOBCAT_IFILTERBUF_ #include namespace FBB { class IFilterBuf: public EoiBuf { size_t d_maxSize; char const *d_srcBegin = 0; char const *d_srcEnd = 0; public: ~IFilterBuf() override; protected: IFilterBuf(size_t bufSize = 1000); void setBuffer(); // .f private: virtual bool filter(char const **srcBegin, char const **srcEnd) = 0; int underflow() override; std::streamsize showmanyc() override; int pbackfail(int ch) override; }; #include "setbuffer.f" } // FBB #endif bobcat-5.09.01/ifilterbuf/pbackfail.cc0000644000175000017500000000067014050437223016465 0ustar frankfrank#include "ifilterbuf.ih" int IFilterBuf::pbackfail(int ch) { if (bufSize() == d_maxSize) // the buffer is at its return EOF; // max. size: no extensions buffer().insert(0, 1, ch); // insert ch at the front setg(0, bufSize()); // start reading from the // beginning return ch; } bobcat-5.09.01/ifilterbuf/ifilterbuf1.cc0000644000175000017500000000041114050437223016756 0ustar frankfrank#include "ifilterbuf.ih" IFilterBuf::IFilterBuf(size_t bufSize) : d_maxSize(bufSize < 100 ? 100 : bufSize) { setg(0, 0); // underflow is called because // buffer next == buffer end. } bobcat-5.09.01/ifilterbuf/setbuffer.f0000644000175000017500000000007114050437223016371 0ustar frankfrankinline void IFilterBuf::setBuffer() { underflow(); } bobcat-5.09.01/ifilterbuf/destructor.cc0000644000175000017500000000006714050437223016747 0ustar frankfrank#include "ifilterbuf.ih" IFilterBuf::~IFilterBuf() {} bobcat-5.09.01/ifilterbuf/underflow.cc0000644000175000017500000000146414050437223016560 0ustar frankfrank#include "ifilterbuf.ih" int IFilterBuf::underflow() { if (d_srcBegin == d_srcEnd) // no (more) source bytes: { // get some. If none available if (not filter(&d_srcBegin, &d_srcEnd)) // return EOF return EOF; } size_t size = d_srcEnd - d_srcBegin; // #available source bytes if (size > d_maxSize) // store at most maxSize bytes size = d_maxSize; buffer().assign(d_srcBegin, size); // store the chars in the buf. setg(0, size); // set the buffer ptrs. d_srcBegin += size; // consumed `size' source // bytes return static_cast(*gptr()); } bobcat-5.09.01/ifilterbuf/ifilterbuf.ih0000644000175000017500000000015114050437223016711 0ustar frankfrank#include "ifilterbuf" #include #include using namespace std; using namespace FBB; bobcat-5.09.01/ifilterbuf/driver/0000755000175000017500000000000014050437223015532 5ustar frankfrankbobcat-5.09.01/ifilterbuf/driver/build0000755000175000017500000000061314050437223016557 0ustar frankfrank#!/bin/bash # # g++ -I. --std=c++2a -O2 -Wall -o driver driver.cc -lssl -lbobcat \ # -L../../ohexbuf/tmp -L../tmp -lhmacbuf -lohexbuf # tput clear GPP="g++ --std=c++2a" # Using tmp libraries and bobcat CMD="$GPP -o driver -Wall -I../../tmp driver.cc \ -L../tmp -lifilterbuf \ -L../../eoibuf/tmp -leoibuf \ -L../../eoi/tmp -leoi \ -lbobcat -s" echo ${CMD} ${CMD} bobcat-5.09.01/ifilterbuf/driver/driver.cc0000644000175000017500000000307014050437223017334 0ustar frankfrank#include #include #include #include class CharFilterStreambuf: public FBB::IFilterBuf { std::istream &d_in; // stream to read from std::string d_rmChars; // chars to rm std::string d_buffer; // locally buffered chars size_t const d_maxSize = 100; public: CharFilterStreambuf(std::istream &in, std::string const &rmChars); private: bool filter(char const **srcBegin, char const **srcEnd) override; }; CharFilterStreambuf::CharFilterStreambuf(std::istream &in, std::string const &rmChars) : d_in(in), d_rmChars(rmChars) { setBuffer(); // required if peek() must return the 1st } // available character right from the start bool CharFilterStreambuf::filter(char const **srcBegin, char const **srcEnd) { d_buffer.clear(); while (d_buffer.size() != d_maxSize) { char ch; if (not d_in.get(ch)) break; if (d_rmChars.find(ch) != std::string::npos) // found char to rm continue; d_buffer.push_back(ch); } if (d_buffer.empty()) return false; *srcBegin = d_buffer.data(); *srcEnd = d_buffer.data() + d_buffer.size(); return true; } int main() { CharFilterStreambuf buf1(std::cin, "1234567890"); std::istream in1(&buf1); CharFilterStreambuf buf2(in1, "AEIOUaeiou"); std::istream in2(&buf2); std::cout << in2.rdbuf(); } bobcat-5.09.01/indent/0000755000175000017500000000000014050437223013365 5ustar frankfrankbobcat-5.09.01/indent/dec.cc0000644000175000017500000000032514050437223014427 0ustar frankfrank#include "indent.ih" void FBB::Indent::dec() { Indent::s_width = Indent::s_width > Indent::s_inc ? Indent::s_width - Indent::s_inc : 0; } bobcat-5.09.01/indent/data.cc0000644000175000017500000000011514050437223014602 0ustar frankfrank#include "indent.ih" size_t Indent::s_width = 0; size_t Indent::s_inc = 4; bobcat-5.09.01/indent/clear.f0000644000175000017500000000006114050437223014617 0ustar frankfrankinline void Indent::clear() { s_width = 0; } bobcat-5.09.01/indent/setwidth.f0000644000175000017500000000010414050437223015362 0ustar frankfrankinline void Indent::setWidth(size_t width) { s_width = width; } bobcat-5.09.01/indent/indent.cc0000644000175000017500000000022514050437223015154 0ustar frankfrank#include "indent.ih" ostream &FBB::indent(ostream &out) { if (Indent::s_width) out << setw(Indent::s_width) << ' '; return out; } bobcat-5.09.01/indent/inc.f0000644000175000017500000000006414050437223014305 0ustar frankfrankinline void Indent::inc() { s_width += s_inc; } bobcat-5.09.01/indent/decindent.cc0000644000175000017500000000015514050437223015632 0ustar frankfrank#include "indent.ih" ostream &FBB::decindent(ostream &out) { Indent::dec(); return out << indent; } bobcat-5.09.01/indent/indentdec.cc0000644000175000017500000000017414050437223015633 0ustar frankfrank#include "indent.ih" ostream &FBB::indentdec(ostream &out) { out << indent; Indent::dec(); return out; } bobcat-5.09.01/indent/nlindent.f0000644000175000017500000000012714050437223015347 0ustar frankfrankinline std::ostream &nlindent(std::ostream &out) { return out << "\n" << indent; } bobcat-5.09.01/indent/setinc.f0000644000175000017500000000007414050437223015022 0ustar frankfrankinline void Indent::setInc(size_t inc) { s_inc = inc; } bobcat-5.09.01/indent/indentinc.cc0000644000175000017500000000016714050437223015653 0ustar frankfrank#include "indent.ih" ostream &FBB::indentinc(ostream &out) { out << indent; Indent::inc(); return out; } bobcat-5.09.01/indent/indent.ih0000644000175000017500000000012314050437223015164 0ustar frankfrank#include "indent" #include using namespace std; using namespace FBB; bobcat-5.09.01/indent/incindent.cc0000644000175000017500000000017014050437223015645 0ustar frankfrank#include "indent.ih" std::ostream &FBB::incindent(std::ostream &out) { Indent::inc(); return out << indent; } bobcat-5.09.01/indent/indent0000644000175000017500000000156614050437223014601 0ustar frankfrank#ifndef INCLUDED_BOBCAT_INDENT_ #define INCLUDED_BOBCAT_INDENT_ #include namespace FBB { class Indent { friend std::ostream &indent(std::ostream &out); static size_t s_width; static size_t s_inc; public: static void setWidth(size_t width); // .f static void setInc(size_t inc); // .f static void clear(); // .f static void inc(); // .f static void dec(); }; #include "clear.f" #include "inc.f" #include "setinc.f" #include "setwidth.f" // Free functions std::ostream &indent(std::ostream &out); #include "nlindent.f" std::ostream &incindent(std::ostream &out); std::ostream &indentinc(std::ostream &out); std::ostream &decindent(std::ostream &out); std::ostream &indentdec(std::ostream &out); } // namespace FBB #endif bobcat-5.09.01/inetaddress/0000755000175000017500000000000014050437223014411 5ustar frankfrankbobcat-5.09.01/inetaddress/inetaddress2.f0000644000175000017500000000013714050437223017150 0ustar frankfrankinline InetAddress::InetAddress(sockaddr_in const &address) : d_address(address) {} bobcat-5.09.01/inetaddress/dotteddecimaladdress.cc0000644000175000017500000000030114050437223021062 0ustar frankfrank#include "inetaddress.ih" std::string InetAddress::dottedDecimalAddress() const { return GetHostent::addressToString("InetAddress::getAddress()", &d_address.sin_addr); } bobcat-5.09.01/inetaddress/sockaddrptr2.f0000644000175000017500000000014614050437223017163 0ustar frankfrankinline sockaddr *InetAddress::sockaddrPtr() { return reinterpret_cast(&d_address); } bobcat-5.09.01/inetaddress/inetaddress0000644000175000017500000000275114050437223016646 0ustar frankfrank#ifndef INCLUDED_BOBCAT_INETADDRESS_ #define INCLUDED_BOBCAT_INETADDRESS_ #include #include /* int-info coming in or going out: host byte order */ namespace FBB { class InetAddress { sockaddr_in d_address; // address/port: network byte order // sa_family_t in_addr, uint16_t // sin_family, sin_addr, sin_port public: uint16_t port() const; // .f // replaces the formerly available getAddress() member. std::string dottedDecimalAddress() const; sockaddr const *sockaddrPtr() const; // 1.f sockaddr_in const *sockaddr_inPtr() const; // 1.f size_t size() const; // .f protected: InetAddress(std::string const &host, uint16_t port); explicit InetAddress(uint16_t port); // 1.f explicit InetAddress(sockaddr_in const &address); // 2.f sockaddr *sockaddrPtr(); // 2.f sockaddr_in *sockaddr_inPtr(); // 2.f private: void init(uint32_t addr, uint16_t port); // host byte order ! }; #include "inetaddress1.f" #include "inetaddress2.f" #include "port.f" #include "size.f" #include "sockaddrinptr1.f" #include "sockaddrinptr2.f" #include "sockaddrptr1.f" #include "sockaddrptr2.f" } // FBB #endif bobcat-5.09.01/inetaddress/sockaddrptr1.f0000644000175000017500000000016714050437223017165 0ustar frankfrankinline sockaddr const *InetAddress::sockaddrPtr() const { return reinterpret_cast(&d_address); } bobcat-5.09.01/inetaddress/init.cc0000644000175000017500000000033514050437223015664 0ustar frankfrank#include "inetaddress.ih" void InetAddress::init(uint32_t addr, uint16_t port) { d_address.sin_family = AF_INET; d_address.sin_addr.s_addr = htonl(addr); d_address.sin_port = htons(port); } bobcat-5.09.01/inetaddress/port.f0000644000175000017500000000012414050437223015541 0ustar frankfrankinline uint16_t InetAddress::port() const { return ntohs(d_address.sin_port); } bobcat-5.09.01/inetaddress/inetaddress.ih0000644000175000017500000000017214050437223017240 0ustar frankfrank#include "inetaddress" #include #include "../gethostent/gethostent" using namespace std; using namespace FBB; bobcat-5.09.01/inetaddress/inetaddress1.f0000644000175000017500000000011714050437223017145 0ustar frankfrankinline InetAddress::InetAddress(uint16_t port) { init(INADDR_ANY, port); } bobcat-5.09.01/inetaddress/sockaddrinptr1.f0000644000175000017500000000013114050437223017503 0ustar frankfrankinline sockaddr_in const *InetAddress::sockaddr_inPtr() const { return &d_address; } bobcat-5.09.01/inetaddress/size.f0000644000175000017500000000011214050437223015524 0ustar frankfrankinline size_t InetAddress::size() const { return sizeof(d_address); } bobcat-5.09.01/inetaddress/inetaddress1.cc0000644000175000017500000000041614050437223017307 0ustar frankfrank#include "inetaddress.ih" InetAddress::InetAddress(string const &host, uint16_t port) { hostent const *hp = GetHostent::gethostent("InetAddress::InetAddress(host, port)", host); init(ntohl(*reinterpret_cast (*(hp->h_addr_list))), port); } bobcat-5.09.01/inetaddress/sockaddrinptr2.f0000644000175000017500000000011514050437223017506 0ustar frankfrankinline sockaddr_in *InetAddress::sockaddr_inPtr() { return &d_address; } bobcat-5.09.01/inetaddress/driver/0000755000175000017500000000000014050437223015704 5ustar frankfrankbobcat-5.09.01/inetaddress/driver/build0000755000175000017500000000005414050437223016730 0ustar frankfrank#!/bin/sh g++ -o driver driver.cc -lbobcat bobcat-5.09.01/inetaddress/driver/driver.cc0000644000175000017500000000120314050437223017502 0ustar frankfrank#include #include #include using namespace std; using namespace FBB; InetAddress X() { class A: public InetAddress { public: A(uint16_t port) : InetAddress(port) {} }; return A(2000); } int main(int argc, char **argv) try { InetAddress const &ia = X(); cout << "A InetAddress was constructed for port " << ia.port() << endl; cout << "It has the generic `ANY' address: " << ia.dottedDecimalAddress() << endl; } catch (exception const &e) { cout << "Exception: " << e.what() << endl; } bobcat-5.09.01/INSTALL0000644000175000017500000001206214050437223013136 0ustar frankfrankTo Install the bobcat library by hand instead of using the binary distribution perform the following steps: 0. To install bobcat icmake should be used, for which a top-level script (build) and support scripts in the ./icmake/ directory are available. Icmake is available on many architectures. 1. Inspect the values of the variables in the file INSTALL.im, in particular the #defines below COMPONENTS TO INSTALL. Modify these #defines when necessary. 2. Inspect the path to icmake at the top of the `build' script. By default it is /usr/bin/icmake, but some installations use /usr/local/bin/icmake Adapt when necessary. 3. If you want to build the complete bobcat library, then execute ./build libraries to compile the bobcat libraries. Optionally add the argument 'strip' if you want the libraries to be stripped. Unless you need the symbolic information in the compiled object modules, it is probably a good idea to provide this argument. So in that case issue: ./build libraries strip Several Bobcat classes depend on additional, non standard, libraries. They are libmilter, libssl, libX11, and libreadline. By just starting ./build libraries [strip] you are asked whether you want those classes included in the Bobcat library. If you know beforehand that you don't need those additional classes, then run ./build light [strip] (see also README.class-setup). If you only need a particular subset of classes, then run ./build select [strip] class ... where 'class ...' is replaced by the name(s) of the class(es) you want to include in the bobcat library. The build script will automatically also add the classes on which the specified set of classes (recursively) depend. The file dependencies/using.classes contains an overview of all bobcat classes (non-indented single words on separate lines) followed by an indented list of classes that use the last-mentioned non-indented class name. Each line in the file dependencies/required.classes starts with the name of a bobcat class, followed by all bobcat classes on which that particular bobcat class depends. Do not modify the file dependencies/required.classes as 'build select' depends on its contents. 4. Run (probably as root) ./build install 'LOG:path' 'what' 'base' to install components of the bobbat library. Here, 'LOG:path' is an optional item specifying the absolute or relative path of a log file to contain a log of all installed files (see also the next item). Using LOG:~/.bobcat usually works well. Do not put any blanks between LOG: and the path specification, or protect the LOG: specification by quotes. 'what' specifies what you want to install. Specify: x, to install all components, or specify a combination of: d (documentation), h (header files), l (libraries), m (man-pages) E.g., use ./build install hl 'base' if you only want to install the header files and the library. When requesting non-existing elements (e.g., ./build install x was requested, but the man-pages weren't constructed) then these non-existing elements are silently ignored by the installation process. 'base' is optional and specifies the base directory below which the requested files are installed. This base directory is prepended to the paths #defined in the INSTALL.im file. If 'base' is not specified, then INSTALL.im's #defined paths are used as-is. 5. Uninstalling previously installed components of Bobcat is easy if a log path (LOG:...) was specified at the `./build install ...' command. In that case, run the command ./build uninstall logpath where 'logpath' specifies the location of the logfile that was written by ./build install. Modified files and non-empty directories are not removed, but the logfile itself is removed following the uninstallation. Make sure that the bobcat library is found by the loader. By default it is installed in /usr/lib, which is in the loader's standard search path By default the headers are stored under /usr/include. Since this is part of the compiler's the standard include path the header files are included as, e.g., #include . No `bobcat' headers have (.h) extensions. By default the manual pages are stored under /usr/share/man/man1, /usr/share/man/man3, and /usr/share/man/man7, which are normally in the `man' program's set of visited directories. bobcat-5.09.01/INSTALL.im0000644000175000017500000000605414050437223013546 0ustar frankfrank// About compiling the bobcat library on BSD/MacOSX: // // According to Karel Kubat (karel at e dash tunity dot com) the bobcat // library won't compile under BSD/MacOSX if the Linux options to create // the dynamic library are used. Instead of // -shared -Wl,-z,def,-soname, // Karel suggests to use: // -dynamiclib -Wl,-single_module // // Also, he suggests to use the name libbobcat.dylib instead of // libbobcat.so.1 // // In the directory ./contrib the script c-conf is found which is provided // by Karel and which might be useful to construct the libraries under // BSD/MacOSX systems. Don't contact me if you experience any problems // with Karel's script. Instead, contact Karel directly. //=========================================================================== // The name of the C++ compiler #define CXX "g++" // Specify compiler options that should be used. // This is overruled by the environment variable CXXFLAGS // The options "-isystem tmp" must always be used, are set in // icmake/library and should not be altered. #define CXXFLAGS "--std=c++2a -O2 -Wall -fdiagnostics-color=never" // Classes requiring the -pthread compiler option #define PTHREAD "sharedmutex sharedblock sharedmemory sharedsegment " \ "process processdata semaphore " // Specify linker options that should be used when creating the shared // library: #define LDFLAGS "" // The following /bin/cp options are used to keep, rather than follow // symbolic references. If your installation doesn't support these flags, // then change them into available ones. // -P, --no-dereference // never follow symbolic links in SOURCE // --preserve[=ATTR_LIST] // preserve the specified attributes (default: // mode,ownership,timestamps), if possible additional // attributes: context, links, all // -d same as --no-dereference --preserve=links #define CPOPTS "-d" // INTERNAL USE ONLY: #define BUILD_SHARED // COMPONENTS TO INSTALL // ===================== // For an operational non-Debian installation, you probably must be // `root'. // If necessary, adapt the #defines below to your situation. // The provided locations are used by Debian Linux. // With 'build install' you can dynamically specify a location to prepend // to the locations configured here, and select which components you want // to install // ONLY USE ABSOLUTE DIRECTORY NAMES: // DOC is the directory in which development- related documentation is // stored (various README files, examples, html-man-pages) #define DOC "/usr/share/doc/libbobcat5-dev" // HDR is the directory in which the header files are stored #define HDR "/usr/include/bobcat" // LIB is the directory in which the bobcat libraries will be stored #define LIB "/usr/lib" // MAN is the directory in which the manual pages are stored // They are stored below MAN in subdirectories man3 and man7 #define MAN "/usr/share/man" bobcat-5.09.01/iobuf/0000755000175000017500000000000014050437223013210 5ustar frankfrankbobcat-5.09.01/iobuf/pseekoff.cc0000644000175000017500000000070014050437223015316 0ustar frankfrank#include "iobuf.ih" std::ios::pos_type IOBuf::pSeekoff(off_type offset, std::ios::seekdir way, std::ios::openmode mode) { if (mode == std::ios::in) { if (d_in->seekg(offset, way)) { setg(&d_buf, &d_buf + 1, &d_buf + 1); return d_in->tellg(); } } else { if (d_out->seekp(offset, way)) return d_out->tellp(); } return -1; } bobcat-5.09.01/iobuf/xsputn.cc0000644000175000017500000000020514050437223015055 0ustar frankfrank#include "iobuf.ih" std::streamsize IOBuf::xsputn(char const *buffer, streamsize n) { return d_out->write(buffer, n) ? n : 0; } bobcat-5.09.01/iobuf/overflow.cc0000644000175000017500000000021414050437223015357 0ustar frankfrank#include "iobuf.ih" int IOBuf::overflow(int c) { if (c == EOF) d_out->flush(); else d_out->put(c); return c; } bobcat-5.09.01/iobuf/iobuf0000644000175000017500000000277514050437223014252 0ustar frankfrank#ifndef INCLUDED_BOBCAT_IOBUF_ #define INCLUDED_BOBCAT_IOBUF_ #include #include namespace FBB { class IOBuf: public Eoi { char d_buf; std::istream *d_in; std::ostream *d_out; public: IOBuf(); // 1.f IOBuf(std::istream &in, std::ostream &out); // 2.f ~IOBuf() override; void reset(std::istream &in, std::ostream &out); protected: pos_type pSeekoff(off_type offset, std::ios::seekdir way, std::ios::openmode mode = std::ios::in | std::ios::out); pos_type pSeekpos(pos_type offset, // .f std::ios::openmode mode = std::ios::in | std::ios::out); private: int underflow() override; pos_type seekoff(off_type offset, std::ios::seekdir way, std::ios::openmode mode = std::ios::in | std::ios::out) override; pos_type seekpos(pos_type offset, std::ios::openmode mode = std::ios::in | std::ios::out) override; int sync() override; int overflow(int c) override; std::streamsize xsputn(char const *buffer, std::streamsize n) override; }; #include "iobuf1.f" #include "iobuf2.f" #include "pseekpos.f" } // namespace FBB #endif bobcat-5.09.01/iobuf/iobuf.ih0000644000175000017500000000014014050437223014631 0ustar frankfrank#include "iobuf" #include "../exception/exception" using namespace std; using namespace FBB; bobcat-5.09.01/iobuf/reset.cc0000644000175000017500000000027414050437223014644 0ustar frankfrank#include "iobuf.ih" void IOBuf::reset(std::istream &in, std::ostream &out) { if (d_out) sync(); d_in = ∈ d_out = &out; setg(&d_buf, &d_buf + 1, &d_buf + 1); } bobcat-5.09.01/iobuf/iobuf2.f0000644000175000017500000000013114050437223014540 0ustar frankfrankinline IOBuf::IOBuf(std::istream &in, std::ostream &out) { reset(in, out); } bobcat-5.09.01/iobuf/pseekpos.f0000644000175000017500000000024014050437223015204 0ustar frankfrankinline IOBuf::pos_type IOBuf::pSeekpos(pos_type offset, std::ios::openmode mode) { return seekoff(offset, std::ios::beg, mode); } bobcat-5.09.01/iobuf/sync.cc0000644000175000017500000000014514050437223014473 0ustar frankfrank#include "iobuf.ih" int IOBuf::sync() { d_out->flush(); return not d_out->good(); } bobcat-5.09.01/iobuf/destructor.cc0000644000175000017500000000011014050437223015705 0ustar frankfrank#include "iobuf.ih" IOBuf::~IOBuf() { if (d_out) sync(); } bobcat-5.09.01/iobuf/seekoff.cc0000644000175000017500000000030014050437223015132 0ustar frankfrank#include "iobuf.ih" streambuf::pos_type IOBuf::seekoff(off_type offset, ios::seekdir way, ios::openmode mode) { return pSeekoff(offset, way, mode); } bobcat-5.09.01/iobuf/iobuf1.f0000644000175000017500000000007514050437223014546 0ustar frankfrankinline IOBuf::IOBuf() : d_in(0), d_out(0) {} bobcat-5.09.01/iobuf/underflow.cc0000644000175000017500000000036214050437223015525 0ustar frankfrank#include "iobuf.ih" int IOBuf::underflow() { int c; c = d_in->get(); if (c == EOF) setg(&d_buf, &d_buf + 1, &d_buf + 1); else { d_buf = c; setg(&d_buf, &d_buf, &d_buf + 1); } return c; } bobcat-5.09.01/iobuf/seekpos.cc0000644000175000017500000000025514050437223015172 0ustar frankfrank#include "iobuf.ih" IOBuf::pos_type IOBuf::seekpos(pos_type offset, ios::openmode mode) { return pSeekpos(offset, mode); } bobcat-5.09.01/iostream/0000755000175000017500000000000014050437223013727 5ustar frankfrankbobcat-5.09.01/iostream/iostream2.f0000644000175000017500000000020714050437223016002 0ustar frankfrankinline IOStream::IOStream(std::istream &in, std::ostream &out) : std::istream(this), std::ostream(this) { open(in, out); } bobcat-5.09.01/iostream/clear1.cc0000644000175000017500000000014114050437223015401 0ustar frankfrank#include "iostream.ih" void IOStream::clear() { istream::clear(); ostream::clear(); } bobcat-5.09.01/iostream/iostream.ih0000644000175000017500000000007714050437223016100 0ustar frankfrank#include "iostream" using namespace std; using namespace FBB; bobcat-5.09.01/iostream/iostream1.f0000644000175000017500000000012014050437223015773 0ustar frankfrankinline IOStream::IOStream() : std::istream(this), std::ostream(this) {} bobcat-5.09.01/iostream/open.f0000644000175000017500000000013714050437223015040 0ustar frankfrankinline void IOStream::open(std::istream &in, std::ostream &out) { IOBuf::reset(in, out); } bobcat-5.09.01/iostream/iostream0000644000175000017500000000100514050437223015471 0ustar frankfrank#ifndef INCLUDED_BOBCAT_IOSTREAM_ #define INCLUDED_BOBCAT_IOSTREAM_ #include namespace FBB { class IOStream: private IOBuf, public std::istream, public std::ostream { public: IOStream(); // 1.f IOStream(std::istream &in, std::ostream &out); // 2.f void clear(); void open(std::istream &in, std::ostream &out); // .f }; #include "iostream1.f" #include "iostream2.f" #include "open.f" } // namespace FBB #endif bobcat-5.09.01/iquotedprintablebuf/0000755000175000017500000000000014050437223016154 5ustar frankfrankbobcat-5.09.01/iquotedprintablebuf/iquotedprintablebuf0000644000175000017500000000171614050437223022154 0ustar frankfrank#ifndef INCLUDED_BOBCAT_IQUOTEDPRINTABLEBUF_ #define INCLUDED_BOBCAT_IQUOTEDPRINTABLEBUF_ #include #include namespace FBB { // generic class declaration template class IQuotedPrintableBuf; // specialization when encoding (using available symbolic name ENCRYPT // from bobcat/fbb) template <> class IQuotedPrintableBuf: public IUO::QPBufBase { public: // 1.f IQuotedPrintableBuf(std::istream &in, size_t bufSize = 1000); }; // specialization when decoding (using available symbolic name DECRYPT // from bobcat/fbb) template <> class IQuotedPrintableBuf: public IUO::QPBufBase { public: // 2.f IQuotedPrintableBuf(std::istream &in, size_t bufSize = 1000); }; #include "iquotedprintablebuf1.f" #include "iquotedprintablebuf2.f" } // FBB #endif bobcat-5.09.01/iquotedprintablebuf/iquotedprintablebuf1.f0000644000175000017500000000023114050437223022450 0ustar frankfrankinline IQuotedPrintableBuf::IQuotedPrintableBuf( std::istream &in, size_t bufSize) : QPBufBase(in, bufSize) { doEncode(); } bobcat-5.09.01/iquotedprintablebuf/iquotedprintablebuf2.f0000644000175000017500000000023114050437223022451 0ustar frankfrankinline IQuotedPrintableBuf::IQuotedPrintableBuf( std::istream &in, size_t bufSize) : QPBufBase(in, bufSize) { doDecode(); } bobcat-5.09.01/iquotedprintablebuf/iquotedprintablebuf.ih0000644000175000017500000000013714050437223022547 0ustar frankfrank#include "iquotedprintablebuf" using namespace std; using namespace FBB; using namespace IUO; bobcat-5.09.01/iquotedprintablebuf/driver/0000755000175000017500000000000014050437223017447 5ustar frankfrankbobcat-5.09.01/iquotedprintablebuf/driver/build0000755000175000017500000000107014050437223020472 0ustar frankfrank#!/bin/bash rm -f driver case $1 in (loc) echo "g++ -c driver.cc" g++ -I. -c driver.cc || exit 1 g++ -o driver driver.o -L../tmp -lqsbb -lbobcat ;; (lib) echo "g++ -c driver.cc" g++ -o driver.o -c driver.cc -lbobcat ;; (*) echo " Usage: build loc - build the driver using the shared library created in ../../tmp/lib build lib - build the driver using the shared bobcat library installed in the standard location for shared libs " exit 1 ;; esac bobcat-5.09.01/iquotedprintablebuf/driver/driver.cc0000644000175000017500000000175214050437223021256 0ustar frankfrank#include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) { if (argc == 1) { cout << "Usage: " << argv[0] << " [edb] < infile > outfile\n" "to quoted printable -e-ncode, -d-ecode or -b-oth\n"; return 0; } switch (argv[1][0]) { case 'e': { IQuotedPrintableBuf encode(cin); istream ein(&encode); cout << ein.rdbuf(); } break; case 'd': { IQuotedPrintableBuf decode(cin); istream din(&decode); cout << din.rdbuf(); } break; case 'b': { IQuotedPrintableBuf encode(cin); istream ein(&encode); IQuotedPrintableBuf decode(ein); istream din(&decode); cout << din.rdbuf(); } break; } } bobcat-5.09.01/iquotedprintablebuf/driver/bobcat/0000755000175000017500000000000014050437223020701 5ustar frankfrankbobcat-5.09.01/iquotedprintablebuf/driver/bobcat/qpstreambufbase0000777000175000017500000000000014050437223033141 2../../../qpstreambufbase/qpstreambufbaseustar frankfrankbobcat-5.09.01/iquotedprintablebuf/driver/bobcat/iquotedprintablestreambuf1.f0000777000175000017500000000000014050437223034554 2../../iquotedprintablestreambuf1.fustar frankfrankbobcat-5.09.01/iquotedprintablebuf/driver/bobcat/iquotedprintablestreambuf0000777000175000017500000000000014050437223033742 2../../iquotedprintablestreambufustar frankfrankbobcat-5.09.01/iquotedprintablebuf/driver/bobcat/iquotedprintablestreambuf2.f0000777000175000017500000000000014050437223034556 2../../iquotedprintablestreambuf2.fustar frankfrankbobcat-5.09.01/iquotedprintablestream/0000755000175000017500000000000014050437223016673 5ustar frankfrankbobcat-5.09.01/iquotedprintablestream/iquotedprintablestream1.f0000644000175000017500000000035714050437223023717 0ustar frankfranktemplate IQuotedPrintableStream::IQuotedPrintableStream(std::istream &in, size_t bufSize) : IQuotedPrintableBuf(in, bufSize), std::istream(this) {} bobcat-5.09.01/iquotedprintablestream/iquotedprintablestream0000644000175000017500000000072014050437223023404 0ustar frankfrank#ifndef INCLUDED_BOBCAT_IQUOTEDPRINTABLESTREAM_ #define INCLUDED_BOBCAT_IQUOTEDPRINTABLESTREAM_ #include #include namespace FBB { template struct IQuotedPrintableStream: private IQuotedPrintableBuf, public std::istream { IQuotedPrintableStream(std::istream &in, size_t bufSize = 1000); // 1.f }; #include "iquotedprintablestream1.f" } // FBB #endif bobcat-5.09.01/iquotedprintablestream/iquotedprintablestream.ih0000644000175000017500000000011514050437223024001 0ustar frankfrank#include "iquotedprintablestream" using namespace std; using namespace FBB; bobcat-5.09.01/iquotedprintablestream/driver/0000755000175000017500000000000014050437223020166 5ustar frankfrankbobcat-5.09.01/iquotedprintablestream/driver/driver.cc0000644000175000017500000000042414050437223021770 0ustar frankfrank#include #include using namespace std; using namespace FBB; int main() { IQuotedPrintableStream in(cin); cout << in.rdbuf(); // quoted printable encode the info on // cin. } bobcat-5.09.01/irandstream/0000755000175000017500000000000014050437223014415 5ustar frankfrankbobcat-5.09.01/irandstream/irandstream1.f0000644000175000017500000000013514050437223017155 0ustar frankfrankinline IRandStream::IRandStream(int max) : RandBuf(1, max, 1), std::istream(this) {} bobcat-5.09.01/irandstream/irandstream3.f0000644000175000017500000000017014050437223017156 0ustar frankfrankinline IRandStream::IRandStream(int min, int max, size_t seed) : RandBuf(min, max, seed), std::istream(this) {} bobcat-5.09.01/irandstream/irandstream2.f0000644000175000017500000000015014050437223017153 0ustar frankfrankinline IRandStream::IRandStream(int min, int max) : RandBuf(min, max, 1), std::istream(this) {} bobcat-5.09.01/irandstream/irandstream0000644000175000017500000000067714050437223016663 0ustar frankfrank#ifndef INCLUDED_BOBCAT_IRANDSTREAM_H_ #define INCLUDED_BOBCAT_IRANDSTREAM_H_ #include #include namespace FBB { class IRandStream: private RandBuf, public std::istream { public: explicit IRandStream(int max); IRandStream(int min, int max); IRandStream(int min, int max, size_t seed); }; #include "irandstream1.f" #include "irandstream2.f" #include "irandstream3.f" } // FBB #endif bobcat-5.09.01/irandstream/driver/0000755000175000017500000000000014050437223015710 5ustar frankfrankbobcat-5.09.01/irandstream/driver/build0000755000175000017500000000044314050437223016736 0ustar frankfrank#!/bin/bash GCC='g++ `cat ../../c++std` -o driver' # Using the standard bobcat library # ${GCC} driver.cc -lbobcat #Using the randbuf/tmp library, bobcat, and the local randbuf/irandstream #header files ${GCC} -I../../randbuf:.. driver.cc -L../../randbuf/tmp \ -lrandbuf -lbobcat -s bobcat-5.09.01/irandstream/driver/driver.cc0000644000175000017500000000041414050437223017511 0ustar frankfrank#include #include using namespace std; using namespace FBB; int main(int argc, char **argv) { IRandStream in(1000); for (; argc--; ) { size_t random; in >> random; cout << random << endl; } } bobcat-5.09.01/isharedstream/0000755000175000017500000000000014050437223014737 5ustar frankfrankbobcat-5.09.01/isharedstream/isharedstream0000644000175000017500000000212314050437223017513 0ustar frankfrank#ifndef INCLUDED_BOBCAT_ISHAREDSTREAM_ #define INCLUDED_BOBCAT_ISHAREDSTREAM_ #include #include namespace FBB { struct ISharedStream: private SharedBuf, public std::istream, public virtual SharedEnum__ { ISharedStream(); ISharedStream( size_t maxSize, SizeUnit sizeUnit, std::ios::openmode openMode = std::ios::in, size_t access = 0600); ISharedStream( size_t id, std::ios::openmode openMode = std::ios::in); using SharedBuf::attachSharedCondition; using std::istream::clear; using SharedBuf::id; using SharedBuf::kill; void memInfo(std::ostream &out, char const *end = "\n") const; void open( size_t maxSize, SizeUnit sizeUnit, std::ios::openmode openMode = std::ios::in, size_t access = 0600); void open( int id, std::ios::openmode openMode = std::ios::in); using SharedBuf::remove; bool truncate(std::streamsize offset); }; #include "truncate.f" } // FBB #endif bobcat-5.09.01/isharedstream/truncate.f0000644000175000017500000000015414050437223016733 0ustar frankfrankinline bool ISharedStream::truncate(std::streamsize offset) { return sharedMemory().truncate(offset); } bobcat-5.09.01/isharedstream/isharedstream.ih0000644000175000017500000000010414050437223020107 0ustar frankfrank#include "isharedstream" using namespace std; using namespace FBB; bobcat-5.09.01/isharedstream/open2.cc0000644000175000017500000000025014050437223016266 0ustar frankfrank#include "isharedstream.ih" void ISharedStream::open(int id, std::ios::openmode openMode) { setMemory(SharedMemory(id)); setOpenMode(openMode); clear(); } bobcat-5.09.01/isharedstream/isharedstream1.cc0000644000175000017500000000012514050437223020160 0ustar frankfrank#include "isharedstream.ih" ISharedStream::ISharedStream() : istream(this) {} bobcat-5.09.01/isharedstream/open1.cc0000644000175000017500000000041314050437223016266 0ustar frankfrank#include "isharedstream.ih" void ISharedStream::open( size_t maxSize, SizeUnit sizeUnit, std::ios::openmode openMode, size_t access) { setMemory(SharedMemory(maxSize, sizeUnit, access)); setOpenMode(openMode); clear(); } bobcat-5.09.01/isharedstream/isharedstream3.cc0000644000175000017500000000022714050437223020165 0ustar frankfrank#include "isharedstream.ih" ISharedStream::ISharedStream(size_t id, std::ios::openmode openMode) : SharedBuf(id, openMode), istream(this) {} bobcat-5.09.01/isharedstream/isharedstream2.cc0000644000175000017500000000040614050437223020163 0ustar frankfrank#include "isharedstream.ih" ISharedStream::ISharedStream( size_t maxSize, SharedMemory::SizeUnit sizeUnit, std::ios::openmode openMode, size_t access) : SharedBuf(maxSize, sizeUnit, openMode, access), istream(this) {} bobcat-5.09.01/isharedstream/meminfo.cc0000644000175000017500000000025714050437223016704 0ustar frankfrank#include "isharedstream.ih" void ISharedStream::memInfo(std::ostream &out, char const *end) const { static_cast(this)->memInfo(out); out << end; } bobcat-5.09.01/isymcryptstream/0000755000175000017500000000000014050437223015363 5ustar frankfrankbobcat-5.09.01/isymcryptstream/isymcryptstream1.f0000644000175000017500000000062714050437223021077 0ustar frankfranktemplate ISymCryptStream::ISymCryptStream( std::istream &in, char const *type, std::string const &key, std::string const &iv, size_t bufSize, size_t filterBufSize, ENGINE *engine) : ISymCryptStreambuf( in, type, key, iv, bufSize, filterBufSize, engine ), std::istream(this) {} bobcat-5.09.01/isymcryptstream/isymcryptstream0000644000175000017500000000116414050437223020567 0ustar frankfrank#ifndef INCLUDED_BOBCAT_ISYMCRYPTSTREAM_ #define INCLUDED_BOBCAT_ISYMCRYPTSTREAM_ #include #include namespace FBB { template struct ISymCryptStream: private ISymCryptStreambuf, public std::istream { ISymCryptStream( // 1.f std::istream &in, char const *type, std::string const &key, std::string const &iv, size_t bufSize = 100, size_t filterBufSize = 1000, ENGINE *engine = 0 ); }; #include "isymcryptstream1.f" } // FBB #endif bobcat-5.09.01/isymcryptstream/isymcryptstream.ih0000644000175000017500000000010614050437223021161 0ustar frankfrank#include "isymcryptstream" using namespace std; using namespace FBB; bobcat-5.09.01/isymcryptstream/driver/0000755000175000017500000000000014050437223016656 5ustar frankfrankbobcat-5.09.01/isymcryptstream/driver/build0000755000175000017500000000023414050437223017702 0ustar frankfrank#!/bin/bash # For development purposes: g++ `cat ../../c++std` -O2 -Wall -o driver -isystem ../../tmp driver.cc \ -L ../../tmp/lib/ -lbobcat -lcrypto bobcat-5.09.01/isymcryptstream/driver/driver.cc0000644000175000017500000000060314050437223020457 0ustar frankfrank#include "../isymcryptstream" #include using namespace std; using namespace FBB; int main() { ISymCryptStream encryptor(cin, "bf-cbc", "1234567890", "1234567890"); ISymCryptStream decryptor(encryptor, "bf-cbc", "1234567890", "1234567890"); cout << decryptor.rdbuf(); } bobcat-5.09.01/isymcryptstreambuf/0000755000175000017500000000000014050437223016060 5ustar frankfrankbobcat-5.09.01/isymcryptstreambuf/isymcryptstreambuf1.f0000644000175000017500000000076314050437223022272 0ustar frankfrankinline ISymCryptStreambuf::ISymCryptStreambuf( std::istream &in, char const *type, std::string const &key, std::string const &iv, size_t bufSize, size_t filterBufSize, ENGINE *engine ) : SymCryptStreambufBase( &EVP_EncryptInit_ex, &EVP_EncryptUpdate, &EVP_EncryptFinal_ex, in, type, key, iv, bufSize, filterBufSize, engine ) {} bobcat-5.09.01/isymcryptstreambuf/isymcryptstreambuf2.f0000644000175000017500000000067614050437223022276 0ustar frankfrankinline ISymCryptStreambuf::ISymCryptStreambuf( std::istream &in, char const *type, std::string const &key, std::string const &iv, size_t bufSize, size_t filterBufSize, ENGINE *engine) : SymCryptStreambufBase( &EVP_DecryptInit_ex, &EVP_DecryptUpdate, &EVP_DecryptFinal_ex, in, type, key, iv, bufSize, filterBufSize, engine ) {} bobcat-5.09.01/isymcryptstreambuf/isymcryptstreambuf0000644000175000017500000000221014050437223021752 0ustar frankfrank#ifndef INCLUDED_BOBCAT_ISYMCRYPTSTREAMBUF_ #define INCLUDED_BOBCAT_ISYMCRYPTSTREAMBUF_ #include #include namespace FBB { template class ISymCryptStreambuf; template <> class ISymCryptStreambuf: public IUO::SymCryptStreambufBase { public: ISymCryptStreambuf( // 1.ff std::istream &in, char const *type, std::string const &key, std::string const &iv, size_t bufSize = 100, size_t filterBufSize = 1000, ENGINE *engine = 0 ); }; template <> class ISymCryptStreambuf: public IUO::SymCryptStreambufBase { public: ISymCryptStreambuf( // 2.ff std::istream &in, char const *type, std::string const &key, std::string const &iv, size_t bufSize = 100, size_t filterBufSize = 1000, ENGINE *engine = 0 ); }; #include "isymcryptstreambuf1.f" #include "isymcryptstreambuf2.f" } // FBB #endif bobcat-5.09.01/isymcryptstreambuf/isymcryptstreambuf.ih0000644000175000017500000000013614050437223022356 0ustar frankfrank#include "isymcryptstreambuf" using namespace std; using namespace FBB; using namespace IUO; bobcat-5.09.01/isymcryptstreambuf/driver/0000755000175000017500000000000014050437223017353 5ustar frankfrankbobcat-5.09.01/isymcryptstreambuf/driver/build0000755000175000017500000000023414050437223020377 0ustar frankfrank#!/bin/bash # For development purposes: g++ `cat ../../c++std` -O2 -Wall -o driver -isystem ../../tmp driver.cc \ -L ../../tmp/lib/ -lbobcat -lcrypto bobcat-5.09.01/isymcryptstreambuf/driver/driver.cc0000644000175000017500000000065214050437223021160 0ustar frankfrank#include #include using namespace std; using namespace FBB; int main() { ISymCryptStreambuf ebuf(cin, "bf-cbc", "1234567890", "1234567890"); istream ein(&ebuf); ISymCryptStreambuf dbuf(ein, "bf-cbc", "1234567890", "1234567890"); istream din(&dbuf); cout << din.rdbuf(); } bobcat-5.09.01/iterator/0000755000175000017500000000000014050437223013735 5ustar frankfrankbobcat-5.09.01/iterator/operatorinc.f0000644000175000017500000000016214050437223016430 0ustar frankfranktemplate inline Iterator &Iterator::operator++() { ++d_value; return *this; } bobcat-5.09.01/iterator/max.f0000644000175000017500000000020614050437223014667 0ustar frankfranktemplate inline Iterator Iterator::max() { return Iterator(std::numeric_limits::max()); } bobcat-5.09.01/iterator/last.f0000644000175000017500000000017014050437223015045 0ustar frankfranktemplate inline Iterator Iterator::last(Type value) { return Iterator(++value); } bobcat-5.09.01/iterator/operatorequal.f0000644000175000017500000000022114050437223016762 0ustar frankfranktemplate inline bool operator==(Iterator const &lhs, Iterator const &rhs) { return lhs.d_value == rhs.d_value; } bobcat-5.09.01/iterator/min.f0000644000175000017500000000020614050437223014665 0ustar frankfranktemplate inline Iterator Iterator::min() { return Iterator(std::numeric_limits::min()); } bobcat-5.09.01/iterator/operatorpostdec.f0000644000175000017500000000020614050437223017317 0ustar frankfranktemplate inline Iterator Iterator::operator--(int) { Iterator tmp(d_value--); return tmp; } bobcat-5.09.01/iterator/iterator0000644000175000017500000000324514050437223015515 0ustar frankfrank#ifndef INCLUDED_BOBCAT_ITERATOR_ #define INCLUDED_BOBCAT_ITERATOR_ #include #include #include namespace FBB { template class Iterator; template struct ReverseIterator: public std::reverse_iterator> { explicit ReverseIterator(Type const &value); explicit ReverseIterator(Iterator const &iter); static ReverseIterator last(Type const &value); }; template bool operator==(Iterator const &lhs, Iterator const &rhs); template class Iterator: public std::iterator { friend bool operator==<>(Iterator const &lhs, Iterator const &rhs); Type d_value; std::shared_ptr d_type; public: Iterator() = default; explicit Iterator(Type const &value); Iterator &operator++(); Iterator operator++(int); Type const &operator*() const; static Iterator last(Type value); static Iterator min(); static Iterator max(); private: friend struct std::reverse_iterator>; Iterator &operator--(); Iterator operator--(int); }; #include "iterator1.f" #include "last.f" #include "max.f" #include "min.f" #include "operatordec.f" #include "operatorequal.f" #include "operatorinc.f" #include "operatorpostdec.f" #include "operatorpostinc.f" #include "operatorstarconst.f" #include "operatorunequal.f" #include "reverseiterator1.f" #include "reverseiterator2.f" #include "reverseiteratorlast.f" } // FBB #endif bobcat-5.09.01/iterator/iterator1.f0000644000175000017500000000017214050437223016016 0ustar frankfranktemplate inline Iterator::Iterator(Type const &value) : d_value(value), d_type(new Type) {} bobcat-5.09.01/iterator/operatordec.f0000644000175000017500000000016214050437223016412 0ustar frankfranktemplate inline Iterator &Iterator::operator--() { --d_value; return *this; } bobcat-5.09.01/iterator/reverseiterator2.f0000644000175000017500000000021514050437223017411 0ustar frankfranktemplate ReverseIterator::ReverseIterator(Iterator const &vi) : std::reverse_iterator>(vi) {} bobcat-5.09.01/iterator/operatorunequal.f0000644000175000017500000000020714050437223017331 0ustar frankfranktemplate inline bool operator!=(Iterator const &lhs, Iterator const &rhs) { return not (lhs == rhs); } bobcat-5.09.01/iterator/operatorpostinc.f0000644000175000017500000000020614050437223017335 0ustar frankfranktemplate inline Iterator Iterator::operator++(int) { Iterator tmp(d_value++); return tmp; } bobcat-5.09.01/iterator/reverseiterator1.f0000644000175000017500000000023114050437223017406 0ustar frankfranktemplate ReverseIterator::ReverseIterator(Type const &value) : std::reverse_iterator>(Iterator(value)) {} bobcat-5.09.01/iterator/reverseiteratorlast.f0000644000175000017500000000025014050437223020212 0ustar frankfranktemplate inline ReverseIterator ReverseIterator::last(Type const &value) { return ReverseIterator(Iterator::last(value)); } bobcat-5.09.01/iterator/operatorstarconst.f0000644000175000017500000000023014050437223017673 0ustar frankfranktemplate inline Type const &Iterator::operator*() const { return d_value; // // *d_type = d_value; // return *d_type; } bobcat-5.09.01/iterator/driver/0000755000175000017500000000000014050437223015230 5ustar frankfrankbobcat-5.09.01/iterator/driver/build0000755000175000017500000000010514050437223016251 0ustar frankfrank#!/bin/bash g++ `cat ../../c++std` -Wall -o driver -I. driver.cc -s bobcat-5.09.01/iterator/driver/driver.cc0000644000175000017500000000202414050437223017030 0ustar frankfrank#include #include #include #include #include using namespace std; using namespace FBB; int main() { copy(Iterator(10), Iterator(20), ostream_iterator(cout, ", ")); cout << '\n'; copy(Iterator(*Iterator::max() - 9), Iterator::last(*Iterator::max()), ostream_iterator(cout, ", ")); cout << '\n'; cout << *Iterator::max() << '\n'; copy(Iterator(*Iterator::max() - 9), Iterator::last(*Iterator::max()), ostream_iterator(cout, ", ")); cout << '\n'; copy(ReverseIterator(20), ReverseIterator(10), ostream_iterator(cout, ", ")); cout << '\n'; std::string letters(Iterator('a'), Iterator::last('z')); cout << letters << '\n'; std::string caps(ReverseIterator::last('Z'), ReverseIterator('A')); cout << caps << '\n'; } bobcat-5.09.01/iterator/driver/bobcat0000777000175000017500000000000014050437223016540 2..ustar frankfrankbobcat-5.09.01/iuo/0000755000175000017500000000000014050437223012700 5ustar frankfrankbobcat-5.09.01/iuo/iuo0000644000175000017500000000066614050437223013427 0ustar frankfrank#ifndef INCLUDED_BOBCAT_IUO_ #define INCLUDED_BOBCAT_IUO_ #include #include namespace FBB { void deprecated__(bool &called, char const *msg); class OptStructArray { typedef struct option OptStruct; size_t d_n; OptStruct *d_opt; public: OptStructArray(size_t n); ~OptStructArray(); OptStruct *get(); }; #include "destructor.f" #include "get.f" } // FBB #endif bobcat-5.09.01/iuo/opstructarray1.cc0000644000175000017500000000021514050437223016210 0ustar frankfrank#include "iuo.ih" OptStructArray::OptStructArray(size_t n) : d_n(n), d_opt(new OptStruct[n]) { d_opt[n - 1] = OptStruct{0, }; } bobcat-5.09.01/iuo/deprecated.cc0000644000175000017500000000047014050437223015310 0ustar frankfrank#include "iuo.ih" namespace FBB { void deprecated__(bool &called, char const *msg) { if (called) return; cerr << "\n[Warning] " << msg << " is deprecated.\n" "Avoid its use, see the man-page for alternatives.\n"; called = true; } } bobcat-5.09.01/iuo/get.f0000644000175000017500000000011614050437223013624 0ustar frankfrankinline OptStructArray::OptStruct *OptStructArray::get() { return d_opt; } bobcat-5.09.01/iuo/destructor.f0000644000175000017500000000010214050437223015236 0ustar frankfrankinline OptStructArray::~OptStructArray() { delete [] d_opt; } bobcat-5.09.01/iuo/iuo.ih0000644000175000017500000000011714050437223014015 0ustar frankfrank#include "iuo" #include using namespace std; using namespace FBB; bobcat-5.09.01/level/0000755000175000017500000000000014050437223013213 5ustar frankfrankbobcat-5.09.01/level/level.ih0000644000175000017500000000012314050437223014640 0ustar frankfrank#include "level" #include "../log/log" using namespace std; using namespace FBB; bobcat-5.09.01/level/level.f0000644000175000017500000000007014050437223014466 0ustar frankfrankinline level::level(size_t lvel) : d_level(lvel) {} bobcat-5.09.01/level/insertinto.cc0000644000175000017500000000022214050437223015714 0ustar frankfrank#include "level.ih" std::ostream &level::insertInto(Log &lp) const { return lp.level(d_level); // otherwise set the level. } bobcat-5.09.01/level/level0000644000175000017500000000057014050437223014247 0ustar frankfrank#ifndef INCLUDED_BOBCAT_LEVEL_ #define INCLUDED_BOBCAT_LEVEL_ #include namespace FBB { class level { friend std::ostream &operator<<(std::ostream &, level const &); size_t d_level; public: explicit level(size_t lvel); private: std::ostream &insertInto(Log &lp) const; }; #include "level.f" } // FBB #endif bobcat-5.09.01/level/operatorinsert.cc0000644000175000017500000000053414050437223016604 0ustar frankfrank#include "level.ih" namespace FBB { std::ostream &operator<<(std::ostream &str, level const &lv) { Log *lp = dynamic_cast(&str); // a Log object is required. return !lp ? // if not, ignore the manip. str : lv.insertInto(*lp); } } // FBB bobcat-5.09.01/level/driver/0000755000175000017500000000000014050437223014506 5ustar frankfrankbobcat-5.09.01/level/driver/build0000755000175000017500000000005614050437223015534 0ustar frankfrank#!/bin/bash g++ -o driver driver.cc -lbobcat bobcat-5.09.01/level/driver/driver.cc0000644000175000017500000000157314050437223016316 0ustar frankfrank/* driver.cc */ #include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) { try { Log::instance() << "hello world" << endl; } catch(exception const &e) { cout << e.what() << endl; } Log log; log << ": message to cout" << nl << "<-- No timestamp here " << '\n' << "<-- But timestamp here " << endl; Log::instance() << "\n"; log.setLevel(1); log.setTimestamp(NOTIMESTAMPS); log.level(0) << "Not shown" << "\n"; log.level(1) << "Shown" << "\n"; log << "This one too" << endl; log << level(0) << "Again not shown\n"; log << level(1) << "Shown again\n"; log.setLevel(5); log << level(1) << "Not shown\n"; log << level(5) << "Shown again\n"; } bobcat-5.09.01/LICENSE0000644000175000017500000010471614067263022013124 0ustar frankfrank GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . Specific permission is granted for the GPLed code in this distribution to be linked to OpenSSL without invoking GPL clause 2(b). bobcat-5.09.01/linearmap/0000755000175000017500000000000014050437223014054 5ustar frankfrankbobcat-5.09.01/linearmap/erase1.f0000644000175000017500000000035214050437223015403 0ustar frankfrank// bool erase(Key const &key) // template bool LinearMap::erase(Key const &key) { auto iter = find(key); if (iter == end()) return false; erase(iter); return true; } bobcat-5.09.01/linearmap/operatorindex.f0000644000175000017500000000046214050437223017110 0ustar frankfrank//Value &operator[])Key const &key) template Value &LinearMap::operator[](Key const &key) { auto iter = find(key); if (iter != end()) return iter->second; Base::push_back(value_type(key, Value())); return Base::back().second; } bobcat-5.09.01/linearmap/find2.f0000644000175000017500000000036414050437223015230 0ustar frankfrank// const_iterator find(Key const &key) const template inline typename LinearMap::const_iterator LinearMap::find(Key const &key) const { return const_iterator(findPtr(key)); } bobcat-5.09.01/linearmap/equalrange2.f0000644000175000017500000000050414050437223016430 0ustar frankfrank// std::pair equal_range(Key const &key) const template inline typename LinearMap::ConstIterPair LinearMap::equal_range(Key const &key) const { const_iterator iter = lower_bound(key); return ConstIterPair(iter, iter); } bobcat-5.09.01/linearmap/insert3.f0000644000175000017500000000041314050437223015610 0ustar frankfrank// iterator insert(iterator pos, value_type const &keyValue); template template inline void LinearMap::insert(Iterator begin, Iterator end) { for (; begin != end; ++begin) insert(*begin); } bobcat-5.09.01/linearmap/lowerbound1.f0000644000175000017500000000034514050437223016466 0ustar frankfrank// iterator lower_bound(Key const &key) template inline typename LinearMap::iterator LinearMap:: lower_bound(Key const &key) { return iterator(findPtr(key)); } bobcat-5.09.01/linearmap/insert2.f0000644000175000017500000000061714050437223015615 0ustar frankfrank// iterator insert(iterator pos, value_type const &keyValue); template typename LinearMap::iterator LinearMap::insert(iterator pos, value_type const &keyvalue) { auto iter = find(keyvalue.first); if (iter == end()) { push_back(keyvalue); iter = iterator(&Base::back()); } return iter; } bobcat-5.09.01/linearmap/upperbound2.f0000644000175000017500000000040214050437223016464 0ustar frankfrank// const_iterator upper_bound(Key const &key) const template inline typename LinearMap::const_iterator LinearMap::upper_bound(Key const &key) const { return const_iterator(findPtr(key)); } bobcat-5.09.01/linearmap/equalrange1.f0000644000175000017500000000043414050437223016431 0ustar frankfrank// std::pair equal_range(Key const &key) template inline typename LinearMap::IterPair LinearMap::equal_range(Key const &key) { iterator iter = lower_bound(key); return IterPair(iter, iter); } bobcat-5.09.01/linearmap/linearmap0000644000175000017500000000624114050437223015752 0ustar frankfrank#ifndef INCLUDED_BOBCAT_LINEARMAP_ #define INCLUDED_BOBCAT_LINEARMAP_ #include #include #include #include namespace FBB { template class LinearMap: private std::vector> { typedef std::vector> Base; typedef LinearMap LinMap; typedef std::pair< typename LinearMap::const_iterator, typename LinearMap::const_iterator > ConstIterPair; typedef std::pair< typename LinearMap::iterator, typename LinearMap::iterator > IterPair; public: typedef std::pair value_type; typedef typename Base::iterator iterator; typedef typename Base::const_iterator const_iterator; typedef typename Base::reverse_iterator reverse_iterator; typedef typename Base::const_reverse_iterator const_reverse_iterator; LinearMap() = default; template LinearMap(Iterator begin, Iterator end); LinearMap(std::initializer_list initial); Value &operator[](Key const &key); Value &at(Key const &key); using Base::begin; using Base::capacity; using Base::cbegin; using Base::cend; using Base::clear; size_t count(Key const &key) const; using Base::crbegin; using Base::crend; using Base::emplace; using Base::empty; using Base::end; IterPair equal_range(Key const &key); ConstIterPair equal_range(Key const &key) const; bool erase(Key const &key); void erase(iterator iter); void erase(iterator begin, iterator end); iterator find(Key const &key); const_iterator find(Key const &key) const; using Base::get_allocator; std::pair insert(value_type const &keyvalue); iterator insert(iterator pos, value_type const &keyValue); template void insert(Iterator begin, Iterator end); iterator lower_bound(Key const &key); const_iterator lower_bound(Key const &key) const; using Base::max_size; using Base::rbegin; using Base::rend; using Base::reserve; using Base::size; using Base::swap; iterator upper_bound(Key const &key); const_iterator upper_bound(Key const &key) const; private: value_type *findPtr(Key const &key) const; }; #include "count.f" #include "equalrange1.f" #include "erase1.f" #include "erase2.f" #include "erase3.f" #include "find1.f" #include "find2.f" #include "findptr.f" #include "insert1.f" #include "insert2.f" #include "insert3.f" #include "linearmap1.f" #include "linearmap2.f" #include "lowerbound1.f" #include "lowerbound2.f" #include "operatorindex.f" #include "upperbound1.f" #include "upperbound2.f" } // FBB #endif bobcat-5.09.01/linearmap/count.f0000644000175000017500000000026314050437223015354 0ustar frankfrank// size_t count(Key const &key) const template inline size_t LinearMap::count(Key const &key) const { return find(key) != end(); } bobcat-5.09.01/linearmap/insert1.f0000644000175000017500000000100414050437223015603 0ustar frankfrank// pair insert(value_type const keyvalue); template std::pair::iterator, bool> LinearMap::insert(value_type const &keyValue) { bool inserted; auto iter = find(keyValue.first); if (iter != end()) inserted = false; else { Base::push_back(keyValue); iter = iterator(&Base::back()); inserted = true; } return std::pair(iter, inserted); } bobcat-5.09.01/linearmap/at.f0000644000175000017500000000040214050437223014623 0ustar frankfrank// Value &at(Key const &key); template Value &LinearMap::at(Key const &key) { auto iter = find(key); if (iter == end()) throw std::out_of_range("LinearMap::at"); return iter->second; } bobcat-5.09.01/linearmap/erase2.f0000644000175000017500000000022514050437223015403 0ustar frankfrank// bool erase(Key const &key) // template void LinearMap::erase(iterator iter) { Base::erase(iter); } bobcat-5.09.01/linearmap/findptr.f0000644000175000017500000000063514050437223015675 0ustar frankfrank// value_type *findPtr(Key const &key) const template inline typename LinearMap::value_type * LinearMap:: findPtr(Key const &key) const { value_type *ptr = const_cast(&*begin()); return std::find_if(ptr, ptr + size(), [&](value_type const &value) { return key == value.first; } ); } bobcat-5.09.01/linearmap/linearmap1.f0000644000175000017500000000033014050437223016250 0ustar frankfrank// LinearMap(Iterator begin, Iterator end) template template inline LinearMap:: LinearMap(Iterator begin, Iterator end) { insert(begin, end); } bobcat-5.09.01/linearmap/erase3.f0000644000175000017500000000025214050437223015404 0ustar frankfrank// bool erase(Key const &key) // template void LinearMap::erase(iterator begin, iterator end) { Base::erase(begin, end); } bobcat-5.09.01/linearmap/upperbound1.f0000644000175000017500000000034514050437223016471 0ustar frankfrank// iterator upper_bound(Key const &key) template inline typename LinearMap::iterator LinearMap:: upper_bound(Key const &key) { return iterator(findPtr(key)); } bobcat-5.09.01/linearmap/linearmap2.f0000644000175000017500000000035614050437223016261 0ustar frankfrank// LinearMap(initializer_list initial) template inline LinearMap:: LinearMap(std::initializer_list initial) { for (auto &value: initial) insert(value); } bobcat-5.09.01/linearmap/lowerbound2.f0000644000175000017500000000040214050437223016461 0ustar frankfrank// const_iterator lower_bound(Key const &key) const template inline typename LinearMap::const_iterator LinearMap::lower_bound(Key const &key) const { return const_iterator(findPtr(key)); } bobcat-5.09.01/linearmap/find1.f0000644000175000017500000000032714050437223015226 0ustar frankfrank// iterator find(Key const &key) template inline typename LinearMap::iterator LinearMap:: find(Key const &key) { return iterator(findPtr(key)); } bobcat-5.09.01/linearmap/driver/0000755000175000017500000000000014050437223015347 5ustar frankfrankbobcat-5.09.01/linearmap/driver/build0000755000175000017500000000015414050437223016374 0ustar frankfrank#!/bin/bash g++-8 --std=c++17 -Wall -fdiagnostics-color=never -o driver -I. driver.cc \ -lbobcat -s bobcat-5.09.01/linearmap/driver/driver.cc0000644000175000017500000000172414050437223017155 0ustar frankfrank#include #include #include #include using namespace std; using namespace FBB; int main() { typedef LinearMap LM; // constructors: LM lm; LM lm2 = { {"one", "value 1"}, {"two", "value 2"} }; LM lm3(lm2); LM lm4(lm3.begin(), lm3.end()); // assignment: lm = lm2; // some members: lm["key"] = "value"; cout << lm["key"] << '\n'; cout << lm.find("key")->second << '\n'; for (auto value: lm) cout << "For loop: " << value.first << ", " << value.second << '\n'; cerr << "# times 'key' is stored: " << lm.count("key") << "\n" "# times 'value is stored: " << lm.count("value") << '\n'; lm4 = lm2; cout << "lm4's size after assignment: " << lm4.size() << '\n'; lm4.clear(); cout << "lm4's size after clear: " << lm4.size() << '\n'; }; bobcat-5.09.01/linearmap/driver/bobcat0000777000175000017500000000000014050437223016657 2..ustar frankfrankbobcat-5.09.01/localclientsocket/0000755000175000017500000000000014050437223015606 5ustar frankfrankbobcat-5.09.01/localclientsocket/localclientsocket0000644000175000017500000000142514050437223021235 0ustar frankfrank#ifndef INCLUDED_BOBCAT_LOCALCLIENTSOCKET_ #define INCLUDED_BOBCAT_LOCALCLIENTSOCKET_ #include #include #include #include namespace FBB { class LocalClientSocket: public LocalSocketBase { public: LocalClientSocket() = default; explicit LocalClientSocket(std::string const &name); void open(std::string const &name); int connect(); // returns fd (socket) to talk to the server private: LocalClientSocket(LocalClientSocket const &other) = delete; }; inline LocalClientSocket::LocalClientSocket(std::string const &name) : LocalSocketBase(name) {} inline void LocalClientSocket::open(std::string const &name) { LocalSocketBase::open(name); } } // FBB #endif bobcat-5.09.01/localclientsocket/localclientsocket.ih0000644000175000017500000000025214050437223021631 0ustar frankfrank#include "localclientsocket" #include #include #include #include "../exception/exception" using namespace std; using namespace FBB; bobcat-5.09.01/localclientsocket/connect.cc0000644000175000017500000000034714050437223017552 0ustar frankfrank#include "localclientsocket.ih" int LocalClientSocket::connect() { if (::connect(socket(), sockaddrPtr(), size()) < 0) throw Exception{} << "LocalClientSocket::connect(): " << errnodescr; return socket(); } bobcat-5.09.01/localclientsocket/driver/0000755000175000017500000000000014050437223017101 5ustar frankfrankbobcat-5.09.01/localclientsocket/driver/build0000755000175000017500000000025414050437223020127 0ustar frankfrank#!/bin/bash g++ -o client client.cc -lbobcat # g++ -o client client.cc -L../tmp -lclientsocket -lbobcat # g++ -I../../tmp -o client client.cc -L../../tmp/lib -lbobcat bobcat-5.09.01/localclientsocket/driver/client.cc0000644000175000017500000000237014050437223020670 0ustar frankfrank#include #include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) try { if (argc == 1) { cerr << "Provide filename representing the unix domain socket\n"; return 1; } LocalClientSocket client(argv[1]); int fd = client.connect(); string line; cout << "Connecting to socket " << fd << endl; IFdStream in(fd); // stream to read from OFdStream out(fd); // stream to write to while (true) { // Ask for a textline, stop if empty / none cout << "? "; if (!getline(cin, line) || line.length() == 0) return 0; cout << "Line read: " << line << endl; // Return the line to the server out << line.c_str() << endl; cout << "wrote line\n"; // Wait for a reply from the server getline(in, line); cout << "Answer: " << line << endl; } } catch (exception const &err) { cerr << err.what() << "\n" << "Can't connect to " << argv[1] << endl; return 1; } bobcat-5.09.01/localserversocket/0000755000175000017500000000000014050437223015636 5ustar frankfrankbobcat-5.09.01/localserversocket/localserversocket.ih0000644000175000017500000000030214050437223021705 0ustar frankfrank#include "localserversocket" #include #include #include #include #include "../exception/exception" using namespace std; using namespace FBB; bobcat-5.09.01/localserversocket/accept.cc0000644000175000017500000000066014050437223017406 0ustar frankfrank#include "localserversocket.ih" size_t LocalServerSocket::accept() { sockaddr_un address; socklen_t size = sizeof(address); int sock = ::accept ( socket(), reinterpret_cast(&address), &size ); if (sock < 0) throw Exception{} << "LocalServerSocket::accept(): " << errnodescr; return sock; } bobcat-5.09.01/localserversocket/localserversocket0000644000175000017500000000151414050437223021314 0ustar frankfrank#ifndef INCLUDED_BOBCAT_LOCALSERVERSOCKET_ #define INCLUDED_BOBCAT_LOCALSERVERSOCKET_ #include #include namespace FBB { class LocalServerSocket: public LocalSocketBase { bool d_unlink; std::string d_name; public: enum Socket { KEEP, UNLINK, }; LocalServerSocket() = default; explicit LocalServerSocket(std::string const &name, // 1.f Socket action = UNLINK); ~LocalServerSocket(); void open(std::string const &name, Socket action = UNLINK); void listen(size_t backlog = 5, bool blocking = true); size_t accept(); private: LocalServerSocket(LocalServerSocket const &other) = delete; }; #include "localserversocket1.f" } // FBB #endif bobcat-5.09.01/localserversocket/open.cc0000644000175000017500000000062714050437223017113 0ustar frankfrank#include "localserversocket.ih" void LocalServerSocket::open(string const &name, Socket action) { LocalSocketBase::open(name); d_unlink = action == UNLINK; d_name = name; if (bind(socket(), sockaddrPtr(), size()) < 0) throw Exception{} << "LocalServerSocket::open(" << name << "): " << errnodescr; } bobcat-5.09.01/localserversocket/localserversocket1.f0000644000175000017500000000023414050437223021617 0ustar frankfrankinline LocalServerSocket::LocalServerSocket(std::string const &name, Socket action) { open(name, action); } bobcat-5.09.01/localserversocket/destructor.cc0000644000175000017500000000022414050437223020341 0ustar frankfrank#include "localserversocket.ih" LocalServerSocket::~LocalServerSocket() { if (d_unlink) unlink(d_name.c_str()); } bobcat-5.09.01/localserversocket/listen.cc0000644000175000017500000000105314050437223017442 0ustar frankfrank#include "localserversocket.ih" void LocalServerSocket::listen(size_t backlog, bool blocking) { static char name[] = "LocalServerSocket::listen(): "; if (::listen(socket(), backlog) < 0) throw Exception{} << name << errnodescr; if (blocking) return; if // not tested ( fcntl ( socket(), F_SETFL, fcntl(socket(), F_GETFL, 0) | O_NONBLOCK ) == -1 ) throw Exception{} << name << errnodescr; } bobcat-5.09.01/localserversocket/driver/0000755000175000017500000000000014050437223017131 5ustar frankfrankbobcat-5.09.01/localserversocket/driver/build0000755000175000017500000000025414050437223020157 0ustar frankfrank#!/bin/bash g++ -o server server.cc -lbobcat # g++ -o server server.cc -L../tmp -lserversocket -lbobcat # g++ -I../../tmp -o server server.cc -L../../tmp/lib -lbobcat bobcat-5.09.01/localserversocket/driver/server.cc0000644000175000017500000000262114050437223020747 0ustar frankfrank#include #include #include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) try { if (argc == 1) { cerr << "Provide local filename, e.g., /tmp/uds\n"; return 1; } LocalServerSocket server(argv[1]); cerr << "server using `" << argv[1] << "'" << endl; cout << "The server terminates when it receives a single `q' on a line\n" "A connection is terminated when no input is received anymore.\n" "Then another connection is possible" << endl; server.listen(); // listen in blocking mode while (true) { int fd = server.accept(); cerr << "Client FD = " << fd << ", " << endl; IFdStream in(fd); // stream to read from client OFdStream out(fd); // stream to write to client string cmd; while (getline(in, cmd)) { cout << "Got: " << cmd << endl; out << "Got: " << cmd << "\r" << endl; if (cmd[0] == 'q') return 0; } cout << "Ready for another connection\n"; } } catch (exception const &err) { cerr << err.what() << endl << "Server socket on " << argv[1] << " can't be opened" << endl; return -1; } bobcat-5.09.01/localsocketbase/0000755000175000017500000000000014050437223015242 5ustar frankfrankbobcat-5.09.01/localsocketbase/sockaddrptr.f0000644000175000017500000000017314050437223017732 0ustar frankfrankinline sockaddr const *LocalSocketBase::sockaddrPtr() const { return reinterpret_cast(&d_address); } bobcat-5.09.01/localsocketbase/localsocketbase1.f0000644000175000017500000000012514050437223020626 0ustar frankfrankinline LocalSocketBase::LocalSocketBase(std::string const &name) { open(name); } bobcat-5.09.01/localsocketbase/socket.f0000644000175000017500000000010414050437223016674 0ustar frankfrankinline int LocalSocketBase::socket() const { return d_socket; } bobcat-5.09.01/localsocketbase/open.cc0000644000175000017500000000125414050437223016514 0ustar frankfrank#include "localsocketbase.ih" void LocalSocketBase::open(std::string const &name) { d_address.sun_family = AF_UNIX; if (name.length() >= sizeof(d_address.sun_path)) throw Exception{} << "LocalSocketBase::open(" << name << "): " << errnodescr; d_address.sun_path[name.copy(d_address.sun_path, string::npos)] = 0; d_length = sizeof(d_address.sun_family) + name.length(); d_socket = ::socket(AF_UNIX, SOCK_STREAM, 0); if (d_socket < 0) throw Exception{} << "LocalSocketBase::open(" << name << "): " << errnodescr; } bobcat-5.09.01/localsocketbase/size.f0000644000175000017500000000010514050437223016357 0ustar frankfrankinline size_t LocalSocketBase::size() const { return d_length; } bobcat-5.09.01/localsocketbase/localsocketbase.ih0000644000175000017500000000022514050437223020721 0ustar frankfrank#include "localsocketbase" #include #include #include "../exception/exception" using namespace std; using namespace FBB; bobcat-5.09.01/localsocketbase/localsocketbase1.cc0000644000175000017500000000024114050437223020765 0ustar frankfrank#include "localsocketbase.ih" LocalSocketBase::LocalSocketBase() : d_length(0), d_socket(-1) { memset(&d_address, 0, sizeof(struct sockaddr_un)); } bobcat-5.09.01/localsocketbase/localsocketbase0000644000175000017500000000146114050437223020325 0ustar frankfrank#ifndef INCLUDED_BOBCAT_LOCALSOCKETBASE_ #define INCLUDED_BOBCAT_LOCALSOCKETBASE_ #include #include #include namespace FBB { class LocalSocketBase { size_t d_length; int d_socket; struct sockaddr_un d_address; protected: LocalSocketBase(); // 1 explicit LocalSocketBase(std::string const &name); // 1.f void open(std::string const &name); int socket() const; // .f size_t size() const; // .f sockaddr const *sockaddrPtr() const; // .f }; #include "localsocketbase1.f" #include "size.f" #include "sockaddrptr.f" #include "socket.f" } // FBB #endif bobcat-5.09.01/log/0000755000175000017500000000000014050437223012665 5ustar frankfrankbobcat-5.09.01/log/instance.cc0000644000175000017500000000025214050437223014777 0ustar frankfrank#include "log.ih" Log &Log::instance() { if (!s_stream.get()) throw Exception{} << "Log::instance: FBB::Log not initialized"; return *s_stream.get(); } bobcat-5.09.01/log/data.cc0000644000175000017500000000006214050437223014103 0ustar frankfrank#include "log.ih" unique_ptr Log::s_stream; bobcat-5.09.01/log/off.f0000644000175000017500000000006014050437223013602 0ustar frankfrankinline void Log::off() { setActive(OFF); } bobcat-5.09.01/log/log0000644000175000017500000000343614050437223013377 0ustar frankfrank#ifndef INCLUDED_BOBCAT_LOG_ #define INCLUDED_BOBCAT_LOG_ #include #include #include namespace FBB { enum LogManipulator { FATAL, nl, // new line without new time stamp fnl, // forced new line, even at low level specs. }; class Log: private LogBuf, public std::ostream { private: static std::unique_ptr s_stream; std::ofstream d_stream; size_t d_level; // defined by setLevel: the level messages // must at least have to be inserted size_t d_msgLevel; // the level of inserted messages public: static Log &instance(); static Log &initialize(std::string const &filename, std::ios::openmode = std::ios::out | std::ios::app, char const *delim = " "); Log(); Log(std::ostream &out, char const *delim = " "); Log(std::string const &filename, std::ios::openmode = std::ios::out | std::ios::app, char const *delim = " "); void open(std::string const &filename, std::ios::openmode = std::ios::out | std::ios::app, char const *delim = " "); size_t level() const; // .f std::ostream &level(size_t useLevel); void setLevel(size_t newLevel); void setTimestamp(TimeStamps timeStamp, char const *delim = " "); void off(); // .f void on(size_t logLevel = 0); // .f private: void init(); }; #include "level.f" #include "off.f" std::ostream &operator<<(std::ostream &str, LogManipulator); } // FBB #endif bobcat-5.09.01/log/open.cc0000644000175000017500000000104514050437223014135 0ustar frankfrank#include "log.ih" void Log::open(string const &filename, ios::openmode mode, char const *delim) { if (!filename.length() || filename == "&1") setStream(cout); else if (filename == "&2") setStream(cerr); else { d_stream.open(filename.c_str(), mode); if (!d_stream) throw Exception{} << "Log::Log(string, ...): can't write `" << filename << '\''; setStream(d_stream); } settimestamp(TIMESTAMPS, delim); init(); } bobcat-5.09.01/log/setlevel.cc0000644000175000017500000000014314050437223015015 0ustar frankfrank#include "log.ih" void Log::setLevel(size_t logLevel) { d_level = logLevel; level(~0U); } bobcat-5.09.01/log/log.ih0000644000175000017500000000021214050437223013763 0ustar frankfrank#include "log" #include #include #include "../exception/exception" using namespace std; using namespace FBB; bobcat-5.09.01/log/log3.cc0000644000175000017500000000023414050437223014037 0ustar frankfrank#include "log.ih" Log::Log(string const &filename, ios::openmode mode, char const *delim) : ostream(this) { open(filename, mode, delim); } bobcat-5.09.01/log/level.f0000644000175000017500000000007114050437223014141 0ustar frankfrankinline size_t Log::level() const { return d_level; } bobcat-5.09.01/log/init.cc0000644000175000017500000000011714050437223014136 0ustar frankfrank#include "log.ih" void Log::init() { d_msgLevel = ~0U; setLevel(0); } bobcat-5.09.01/log/log2.cc0000644000175000017500000000021314050437223014033 0ustar frankfrank#include "log.ih" Log::Log(ostream &out, char const *delim) : LogBuf(out, TIMESTAMPS, true, delim), ostream(this) { init(); } bobcat-5.09.01/log/on.cc0000644000175000017500000000015214050437223013606 0ustar frankfrank#include "log.ih" void Log::on(size_t logLevel) { setActive(ACTIVE); setLevel(logLevel); } bobcat-5.09.01/log/operatorinsert.cc0000644000175000017500000000106614050437223016257 0ustar frankfrank#include "log.ih" namespace FBB { std::ostream &operator<<(std::ostream &str, LogManipulator manipulator) { switch (manipulator) { case FATAL: str.flush(); throw Exception(1); case nl: str << static_cast(0); // 0-char is interpreted by // LogBuf as '\n', without break; // timestamp writing request. case fnl: str << static_cast(1); break; } return str; } } // FBB bobcat-5.09.01/log/log1.cc0000644000175000017500000000014614050437223014037 0ustar frankfrank#include "log.ih" Log::Log() : LogBuf(TIMESTAMPS, false, " "), ostream(this) { init(); } bobcat-5.09.01/log/initialize.cc0000644000175000017500000000052214050437223015334 0ustar frankfrank#include "log.ih" Log &Log::initialize(std::string const &filename, std::ios::openmode mode, char const *delim) { if (s_stream.get()) throw Exception{} << "Log::initialize: FBB::Log already initialized"; s_stream.reset(new Log(filename, mode, delim)); return *s_stream.get(); } bobcat-5.09.01/log/settimestamp.cc0000644000175000017500000000016114050437223015711 0ustar frankfrank#include "log.ih" void Log::setTimestamp(TimeStamps type, char const *delim) { settimestamp(type, delim); } bobcat-5.09.01/log/level.cc0000644000175000017500000000022014050437223014275 0ustar frankfrank#include "log.ih" ostream &Log::level(size_t msgLevel) { d_msgLevel = msgLevel; setActive(d_level <= d_msgLevel); return *this; } bobcat-5.09.01/log/driver/0000755000175000017500000000000014050437223014160 5ustar frankfrankbobcat-5.09.01/log/driver/build0000755000175000017500000000027214050437223015206 0ustar frankfrank#!/bin/bash g++ --std=c++2a -o driver driver.cc -lbobcat #g++ --std=c++2a -o driver driver.cc -L../tmp -L../../logbuf/tmp \ # -llogbuf -llog -lbobcat bobcat-5.09.01/log/driver/driver.cc0000644000175000017500000000165714050437223015773 0ustar frankfrank#include #include #include #include using namespace std; using namespace FBB; int main() { // Log &log = Log::initialize("&1"); // uses the static Log object Log log; // explicitly defining a Log object log.open("/tmp/out"); // or at once: Log log{ "/tmp/out" } log << "This message is written to cout" << nl << setw(16) << ' ' << "occupying multiple lines\n"; log.off(); log << "This message is not shown\n"; log << "This message is not shown\n"; log << fnl; log << "This message is not shown\n"; log.on(2); log << "This message is shown\n"; log << level(0) << "not shown" << level(2) << "shown at level 2\n"; log << level(3) << "at level(3)" << level(1) << "not shown" << fnl; log << "separate new line\n"; log << level(2) << "in business again\n"; log << "final line\n"; } bobcat-5.09.01/logbuf/0000755000175000017500000000000014050437223013362 5ustar frankfrankbobcat-5.09.01/logbuf/logbuf0000644000175000017500000000406414050437223014567 0ustar frankfrank#ifndef INCLUDED_BOBCAT_LOGBUF_ #define INCLUDED_BOBCAT_LOGBUF_ #include #include #include namespace FBB { enum TimeStamps { NOTIMESTAMPS, TIMESTAMPS, UTCTIMESTAMPS }; class LogBuf: public std::streambuf { std::ostream *d_stream; // the stream to insert info to TimeStamps d_timestamps;// what timestamp to use? uint8_t d_active; // actually write information or not bool d_empty; // set to true at the beginning, after writing \n std::string d_delim; // delimiter following time stamps public: enum Active { OFF, NOT_ACTIVE, ACTIVE, }; LogBuf(LogBuf const &other) = delete; explicit LogBuf( // output to cerr TimeStamps timestamps = TIMESTAMPS, bool active = true, char const *delim = " "); explicit LogBuf(std::ostream &stream, TimeStamps timestamps = TIMESTAMPS, bool active = true, char const *delim = " "); void setStream(std::ostream &stream); // .f bool empty() const; // .f bool active() const; // .f void settimestamp(TimeStamps timestamps, char const *delim = " "); void setEmpty(bool empty); // .f void setActive(bool active); // 1.f void setActive(Active active); // 2.f private: int sync() override; int overflow(int c) override; std::streamsize xsputn(char const *buffer, std::streamsize n) override; size_t newLine(char const *buffer, size_t begin, size_t n) const; void checkTimestamp(); void insertTimestamp(); }; #include "empty.f" #include "setactive1.f" #include "setactive2.f" #include "active.f" #include "setempty.f" #include "setstream.f" } // FBB #endif bobcat-5.09.01/logbuf/setstream.f0000644000175000017500000000012014050437223015531 0ustar frankfrankinline void LogBuf::setStream(std::ostream &stream) { d_stream = &stream; } bobcat-5.09.01/logbuf/xsputn.cc0000644000175000017500000000145514050437223015237 0ustar frankfrank#include "logbuf.ih" streamsize LogBuf::xsputn(char const *buffer, streamsize n) { if (d_active != ACTIVE) return n; streamsize begin = 0; while (true) { // find the 1st newline pos. streamsize end = newLine(buffer, begin, n); if (begin < end) // only a timestamp if there's { // something to show. checkTimestamp(); d_stream->write(buffer + begin, end - begin); } if (end == n) // nothing more to do break; overflow(buffer[end]); // handle \n, nl, fnl begin = end + 1; // continue beyond end } return n; } bobcat-5.09.01/logbuf/overflow.cc0000644000175000017500000000207314050437223015536 0ustar frankfrank#include "logbuf.ih" int LogBuf::overflow(int ch) { if (d_active == OFF) // ignore the char if we're not active return ch; // if the ch. is not fnl (forced \n) if (ch != 1 and d_active == NOT_ACTIVE) { if (ch == '\n') d_empty = true; return ch; } switch (ch) { case 0: // write newline, without considering d_empty true d_empty = false; ch = '\n'; // also see logbuf/operatorinsert.cc break; case 1: // at fnl (forced new line) (re)activate and ch = '\n'; // fallthrough (continue) as \n [[fallthrough]]; case '\n': // at '\n', set d_empty to true. This generates // a timestamp at the next insertion d_empty = true; break; } return d_stream->write(reinterpret_cast(&ch), sizeof(char)) ? ch : EOF; } bobcat-5.09.01/logbuf/logbuf.ih0000644000175000017500000000030014050437223015153 0ustar frankfrank#include "logbuf" #include #include #include #include #include #include "../exception/exception" using namespace std; using namespace FBB; bobcat-5.09.01/logbuf/setactive1.f0000644000175000017500000000017114050437223015600 0ustar frankfrankinline void LogBuf::setActive(bool active) { if (d_active != OFF) d_active = active ? ACTIVE : NOT_ACTIVE; } bobcat-5.09.01/logbuf/checktimestamp.cc0000644000175000017500000000041714050437223016674 0ustar frankfrank#include "logbuf.ih" void LogBuf::checkTimestamp() { if (d_timestamps == NOTIMESTAMPS) // no timestamps requested return; if (d_empty) // write one if there's nothing on the line { insertTimestamp(); d_empty = false; } } bobcat-5.09.01/logbuf/logbuf1.cc0000644000175000017500000000100314050437223015222 0ustar frankfrank#include "logbuf.ih" LogBuf::LogBuf(TimeStamps timestamps, bool active, char const *delim) : d_stream(&cerr), d_active(active ? ACTIVE : NOT_ACTIVE), d_empty(true) { settimestamp(timestamps, delim); setp(0, 0); // we're not using buffering, so we see every single // character. overflow() may therefore act like a filter, // which decides what to do depending on the booleans. // see overflow() for details. } bobcat-5.09.01/logbuf/newline.cc0000644000175000017500000000044414050437223015334 0ustar frankfrank#include "logbuf.ih" size_t LogBuf::newLine(char const *buffer, size_t begin, size_t n) const { return find_if(buffer + begin, buffer + n, [](char c) { return c == '\n' || c == 0 || c == 1; } ) - buffer; } bobcat-5.09.01/logbuf/setempty.f0000644000175000017500000000010214050437223015374 0ustar frankfrankinline void LogBuf::setEmpty(bool empty) { d_empty = empty; } bobcat-5.09.01/logbuf/empty.f0000644000175000017500000000007214050437223014666 0ustar frankfrankinline bool LogBuf::empty() const { return d_empty; } bobcat-5.09.01/logbuf/inserttimestamp.cc0000644000175000017500000000053314050437223017122 0ustar frankfrank#include "logbuf.ih" void LogBuf::insertTimestamp() { time_t curtime = time(0); struct tm *timestruct = (d_timestamps == TIMESTAMPS ? localtime : gmtime)(&curtime); char buffer[256]; // see time functions example of `info libc' strftime(buffer, 256, "%b %e %T", timestruct); *d_stream << buffer << d_delim; } bobcat-5.09.01/logbuf/sync.cc0000644000175000017500000000012214050437223014640 0ustar frankfrank#include "logbuf.ih" int LogBuf::sync() { d_stream->flush(); return 0; } bobcat-5.09.01/logbuf/setactive2.f0000644000175000017500000000011014050437223015572 0ustar frankfrankinline void LogBuf::setActive(Active active) { d_active = active; } bobcat-5.09.01/logbuf/settimestamp.cc0000644000175000017500000000027314050437223016412 0ustar frankfrank#include "logbuf.ih" void LogBuf::settimestamp(TimeStamps timestamps, char const *delim) { if ( (d_timestamps = timestamps) != NOTIMESTAMPS) d_delim = !delim ? "" : delim; } bobcat-5.09.01/logbuf/active.f0000644000175000017500000000010614050437223015001 0ustar frankfrankinline bool LogBuf::active() const { return d_active == ACTIVE; } bobcat-5.09.01/logbuf/logbuf2.cc0000644000175000017500000000102614050437223015230 0ustar frankfrank#include "logbuf.ih" LogBuf::LogBuf(ostream &stream, TimeStamps timestamps, bool active, char const *delim) : d_stream(&stream), d_active(active ? ACTIVE : NOT_ACTIVE), d_empty(true) { settimestamp(timestamps, delim); setp(0, 0); // we're not using buffering, so we see every single // character. overflow() may therefore act like a filter, // which decides what to do depending on the booleans. // see overflow() for details. } bobcat-5.09.01/logbuf/driver/0000755000175000017500000000000014050437223014655 5ustar frankfrankbobcat-5.09.01/logbuf/driver/build0000755000175000017500000000017314050437223015703 0ustar frankfrank#!/bin/bash g++ --std=c++2a -o driver driver.cc -lbobcat # g++ --std=c++2a -o driver driver.cc -L../tmp -llogbuf -lbobcat bobcat-5.09.01/logbuf/driver/driver.cc0000644000175000017500000000104114050437223016453 0ustar frankfrank#include #include #include #include using namespace std; using namespace FBB; int main() { LogBuf buffer(cout, FBB::TIMESTAMPS); ostream log(&buffer); log << "This message is written to cout" << nl << setw(16) << ' ' << "occupying multiple lines\n"; buffer.setActive(false); log << "one line\n"; log << "more lines "; log << fnl; log << "another\n"; buffer.setActive(true); log << "and active again\n"; log << "another log msg\n"; } bobcat-5.09.01/mailheaders/0000755000175000017500000000000014050437223014362 5ustar frankfrankbobcat-5.09.01/mailheaders/initial.f0000644000175000017500000000027414050437223016165 0ustar frankfrankinline bool MailHeaders::const_hdr_iterator::initial( string const &hdr, string const &key) { return hdr.substr(0, hdr.find(':')).find(key) == 0; } bobcat-5.09.01/mailheaders/caseinitial.f0000644000175000017500000000031414050437223017014 0ustar frankfrankinline bool MailHeaders::const_hdr_iterator::caseInitial( string const &hdr, string const &key) { return String::lc(hdr.substr(0, hdr.find(':'))).find(key) == 0; } bobcat-5.09.01/mailheaders/data.cc0000644000175000017500000000034214050437223015601 0ustar frankfrank#include "mailheaders.ih" MailHeaders::const_hdr_iterator::Comparator MailHeaders::const_hdr_iterator::s_comparator[] = { fail, initial, partial, full, caseInitial, casePartial, caseFull }; bobcat-5.09.01/mailheaders/oppostinc.f0000644000175000017500000000021714050437223016547 0ustar frankfrankinline MailHeaders::const_hdr_iterator MailHeaders::const_hdr_iterator::operator++(int) { return const_hdr_iterator(d_mh, d_current++); } bobcat-5.09.01/mailheaders/opindex.f0000644000175000017500000000014114050437223016173 0ustar frankfrankinline std::string const &MailHeaders::operator[](size_t idx) const { return d_lines[idx]; } bobcat-5.09.01/mailheaders/lookup.cc0000644000175000017500000000066114050437223016205 0ustar frankfrank#include "mailheaders.ih" MailHeaders::const_iterator MailHeaders::const_hdr_iterator::lookup (const_iterator const &begin) const { const_iterator next = find_if(begin, d_mh->end(), [&](std::string const &header) { return (*d_comparator)(header, d_key); } ); return next; } bobcat-5.09.01/mailheaders/read.cc0000644000175000017500000000210714050437223015604 0ustar frankfrank#include "mailheaders.ih" void MailHeaders::read() { static char funName[] = "MailHeaders::read()"; if (size()) throw Exception{} << funName << "Mail headers already read"; while (true) { string line; if (!getline(d_in, line)) // no more header lines throw Exception{} << funName << // is an error condition "Headers incomplete after line " << d_lines.size(); if (line.find_first_not_of(" \t") == string::npos) // blank line { d_lines.resize(size() + 1); // last line will be used as // the search sentinel return; } if (line[0] != ' ' && line[0] != '\t') // add the new header line d_lines.push_back(line); else { if (not d_lines.size()) // no header yet: error throw Exception{} << funName << "Invalid begin of headers"; (d_lines.back() += "\n") += line; // add line continuation } } } bobcat-5.09.01/mailheaders/mailheaders1.cc0000644000175000017500000000023014050437223017223 0ustar frankfrank#include "mailheaders.ih" MailHeaders::MailHeaders(istream &in, Mode mode) : d_in(in), d_match(FAIL) { if (mode == READ) read(); } bobcat-5.09.01/mailheaders/begin.f0000644000175000017500000000013614050437223015615 0ustar frankfrankinline MailHeaders::const_iterator MailHeaders::begin() const { return d_lines.begin(); } bobcat-5.09.01/mailheaders/iteratorclass.demo0000644000175000017500000000265214050437223020114 0ustar frankfrank/* class const_iterator: public std::iterator { friend MailHeaders; MailHeaders const &d_mh; Hdr::const_iterator d_begin; Hdr::const_iterator d_end; public: const_iterator(MailHeaders const &mh, char const *hdr, Match match, Where where); const_iterator &operator++(); const_iterator const operator++(int); const *operator->() { return ; } const &operator*() { return *operator->(); } bool operator==(const_iterator const &rvalue) const { return &d_mh == &rvalue.d_mh && d_begin == rvalue.d_begin; } bool operator!=(const_iterator const &rvalue) const { return !operator==(rvalue); } private: const_iterator &operator--(); const_iterator const operator--(int); }; friend class MailHeaders::const_iterator; */ bobcat-5.09.01/mailheaders/opstar.f0000644000175000017500000000015014050437223016035 0ustar frankfrankinline std::string const &MailHeaders::const_hdr_iterator::operator*() const { return *d_current; } bobcat-5.09.01/mailheaders/opinc.f0000644000175000017500000000022214050437223015635 0ustar frankfrankinline MailHeaders::const_hdr_iterator &MailHeaders::const_hdr_iterator::operator++() { d_current = lookup(++d_current); return *this; } bobcat-5.09.01/mailheaders/mailheaders2.cc0000644000175000017500000000027114050437223017231 0ustar frankfrank#include "mailheaders.ih" MailHeaders::MailHeaders(MailHeaders &&tmp) : d_lines( move(tmp.d_lines) ), d_in(tmp.d_in), d_hdr( move(tmp.d_hdr) ), d_match(tmp.d_match) {} bobcat-5.09.01/mailheaders/lookdown.cc0000644000175000017500000000103314050437223016522 0ustar frankfrank#include "mailheaders.ih" MailHeaders::const_iterator MailHeaders::const_hdr_iterator::lookdown (const_iterator const &begin) const { return d_mh->begin() + ( &*find_if( const_reverse_iterator(begin), d_mh->rend(), [&](std::string const &header) { return (*d_comparator)(header, d_key); } ) - &*d_mh->begin() ); } bobcat-5.09.01/mailheaders/consthdropdec.cc0000644000175000017500000000035114050437223017527 0ustar frankfrank//#include "mailheaders.hh" // //MailHeaders::const_hdr_iterator //MailHeaders::const_hdr_iterator::operator--(int) //{ // const_hdr_iterator ret(d_mh, d_current); // d_current = lookdown(d_current); // // return ret; //} bobcat-5.09.01/mailheaders/consthdriterator1.cc0000644000175000017500000000065314050437223020354 0ustar frankfrank#include "mailheaders.ih" MailHeaders::const_hdr_iterator::const_hdr_iterator ( MailHeaders const *mh, MailHeaders::const_iterator begin ) : d_mh(mh), d_key ( static_cast(mh->d_match) < static_cast(MailHeaders::caseInsensitive) ? d_mh->d_hdr : String::lc(d_mh->d_hdr) ), d_comparator(s_comparator[mh->d_match]), d_current(lookup(begin)) {} bobcat-5.09.01/mailheaders/end.f0000644000175000017500000000013214050437223015273 0ustar frankfrankinline MailHeaders::const_iterator MailHeaders::end() const { return d_lines.end(); } bobcat-5.09.01/mailheaders/rbeginh.f0000644000175000017500000000017714050437223016154 0ustar frankfrankinline MailHeaders::const_reverse_hdr_iterator MailHeaders::rbeginh() const { return const_reverse_hdr_iterator(endh()); } bobcat-5.09.01/mailheaders/fail.f0000644000175000017500000000036114050437223015444 0ustar frankfrankinline bool MailHeaders::const_hdr_iterator::fail( string const &hdr, string const &key) { throw Exception(1) << "MailHeaders: setHeaderIterator() not called"; return false; // not reached } bobcat-5.09.01/mailheaders/casefull.f0000644000175000017500000000030114050437223016321 0ustar frankfrankinline bool MailHeaders::const_hdr_iterator::caseFull( string const &hdr, string const &key) { return String::lc(hdr.substr(0, hdr.find(':'))) == key; } bobcat-5.09.01/mailheaders/rend.f0000644000175000017500000000014414050437223015460 0ustar frankfrankinline MailHeaders::const_reverse_iterator MailHeaders::rend() const { return d_lines.rend(); } bobcat-5.09.01/mailheaders/size.f0000644000175000017500000000010714050437223015501 0ustar frankfrankinline size_t MailHeaders::size() const { return d_lines.size(); } bobcat-5.09.01/mailheaders/full.f0000644000175000017500000000026114050437223015472 0ustar frankfrankinline bool MailHeaders::const_hdr_iterator::full( string const &hdr, string const &key) { return hdr.substr(0, hdr.find(':')) == key; } bobcat-5.09.01/mailheaders/casepartial.f0000644000175000017500000000032714050437223017023 0ustar frankfrankinline bool MailHeaders::const_hdr_iterator::casePartial( string const &hdr, string const &key) { return String::lc(hdr.substr(0, hdr.find(':'))).find(key) != string::npos; } bobcat-5.09.01/mailheaders/operatorassign.cc0000644000175000017500000000020714050437223017730 0ustar frankfrank#include "mailheaders.ih" MailHeaders &MailHeaders::operator=(MailHeaders &&tmp) { fswap(*this, tmp, d_hdr); return *this; } bobcat-5.09.01/mailheaders/mailheaders0000644000175000017500000001176214050437223016572 0ustar frankfrank#ifndef INCLUDED_BOBCAT_MAILHEADERS_ #define INCLUDED_BOBCAT_MAILHEADERS_ #include #include #include #include namespace FBB { class MailHeaders { public: typedef std::vector::const_iterator const_iterator; typedef std::vector::const_reverse_iterator const_reverse_iterator; enum Mode { DONT_READ, READ }; enum Match { FAIL, INITIAL, PARTIAL, FULL, caseInsensitive, CASE_INITIAL = caseInsensitive, CASE_PARTIAL, CASE_FULL, lastMatch = CASE_FULL }; private: enum Size { SIZEOFMATCH = lastMatch + 1, }; std::vector d_lines; std::istream &d_in; std::string d_hdr; Match d_match; public: class const_hdr_iterator: public std::iterator { friend MailHeaders; typedef bool(*Comparator)(std::string const &header, std::string const &key); MailHeaders const *d_mh; std::string d_key; Comparator d_comparator; const_iterator d_current; static Comparator s_comparator[]; const_hdr_iterator(MailHeaders const *mailHeaders, const_iterator begin); const_iterator lookup(const_iterator const &old) const; const_iterator lookdown(const_iterator const &old) const; static bool fail(std::string const &hdr, // .f std::string const &key); static bool initial(std::string const &hdr, // .f std::string const &key); static bool partial(std::string const &hdr, // .f std::string const &key); static bool full(std::string const &hdr, // .f std::string const &key); static bool caseInitial(std::string const &hdr, // .f std::string const &key); static bool casePartial(std::string const &hdr, // .f std::string const &key); static bool caseFull(std::string const &hdr, // .f std::string const &key); public: const_hdr_iterator &operator++(); // opinc.f const_hdr_iterator &operator--(); // opdec.f const_hdr_iterator operator++(int); // oppostinc.f // not used, but potentially available in consthdropdec.cc // const_hdr_iterator operator--(int); bool operator==(const_hdr_iterator const &other) // opeq.f const; bool operator!=(const_hdr_iterator const &other) // opneq.f const; std::string const &operator*() const; // opstar.f std::string const *operator->() const; // oparrow.f }; typedef std::reverse_iterator const_reverse_hdr_iterator; explicit MailHeaders(std::istream &in, Mode mode = READ); MailHeaders(MailHeaders &&tmp); MailHeaders &operator=(MailHeaders &&tmp); void read(); void setHeaderIterator(char const *header, Match match = FULL); // .f const_hdr_iterator beginh() const; // .f const_hdr_iterator endh() const; // .f const_reverse_hdr_iterator rbeginh() const; // .f const_reverse_hdr_iterator rendh() const; // .f // available from vector: size_t size() const; // .f std::string const &operator[](size_t idx) const; // opindex.f const_iterator begin() const; // .f const_iterator end() const; // .f const_reverse_iterator rbegin() const; // .f const_reverse_iterator rend() const; // .f }; #include "begin.f" #include "beginh.f" #include "end.f" #include "endh.f" #include "opindex.f" #include "rbegin.f" #include "rbeginh.f" #include "rend.f" #include "rendh.f" #include "setheaderiterator.f" #include "size.f" #include "oparrow.f" #include "opdec.f" #include "opeq.f" #include "opinc.f" #include "opneq.f" #include "oppostinc.f" #include "opstar.f" } // FBB #endif bobcat-5.09.01/mailheaders/rbegin.f0000644000175000017500000000015014050437223015773 0ustar frankfrankinline MailHeaders::const_reverse_iterator MailHeaders::rbegin() const { return d_lines.rbegin(); } bobcat-5.09.01/mailheaders/oparrow.f0000644000175000017500000000015214050437223016220 0ustar frankfrankinline std::string const *MailHeaders::const_hdr_iterator::operator->() const { return &*d_current; } bobcat-5.09.01/mailheaders/beginh.f0000644000175000017500000000042114050437223015762 0ustar frankfrankinline MailHeaders::const_hdr_iterator MailHeaders::beginh() const { return const_hdr_iterator(this, begin()); // returns iterator over all headers // matching d_hdr by the d_match type } bobcat-5.09.01/mailheaders/opneq.f0000644000175000017500000000026114050437223015652 0ustar frankfrankinline bool MailHeaders::const_hdr_iterator::operator!=( const_hdr_iterator const &other) const { return d_current != other.d_current; } bobcat-5.09.01/mailheaders/rendh.f0000644000175000017500000000017714050437223015636 0ustar frankfrankinline MailHeaders::const_reverse_hdr_iterator MailHeaders::rendh() const { return const_reverse_hdr_iterator(beginh()); } bobcat-5.09.01/mailheaders/partial.f0000644000175000017500000000030714050437223016165 0ustar frankfrankinline bool MailHeaders::const_hdr_iterator::partial( string const &hdr, string const &key) { return hdr.substr(0, hdr.find(':')).find(key) != string::npos; } bobcat-5.09.01/mailheaders/opeq.f0000644000175000017500000000026114050437223015474 0ustar frankfrankinline bool MailHeaders::const_hdr_iterator::operator==( const_hdr_iterator const &other) const { return d_current == other.d_current; } bobcat-5.09.01/mailheaders/setheaderiterator.f0000644000175000017500000000017114050437223020246 0ustar frankfrankinline void MailHeaders::setHeaderIterator(char const *header, Match match) { d_hdr = header; d_match = match; } bobcat-5.09.01/mailheaders/endh.f0000644000175000017500000000027514050437223015453 0ustar frankfrankinline MailHeaders::const_hdr_iterator MailHeaders::endh() const { // returns address of the sentinel return const_hdr_iterator(this, end()); } bobcat-5.09.01/mailheaders/opdec.f0000644000175000017500000000022214050437223015617 0ustar frankfrankinline MailHeaders::const_hdr_iterator &MailHeaders::const_hdr_iterator::operator--() { d_current = lookdown(d_current); return *this; } bobcat-5.09.01/mailheaders/mailheaders.ih0000644000175000017500000000045414050437223017165 0ustar frankfrank#include "mailheaders" #include #include "../fswap/fswap" #include "../exception/exception" using namespace std; using namespace FBB; #include "casefull.f" #include "caseinitial.f" #include "casepartial.f" #include "fail.f" #include "full.f" #include "initial.f" #include "partial.f" bobcat-5.09.01/mailheaders/driver/0000755000175000017500000000000014050437223015655 5ustar frankfrankbobcat-5.09.01/mailheaders/driver/build0000755000175000017500000000005614050437223016703 0ustar frankfrank#!/bin/bash g++ -o driver driver.cc -lbobcat bobcat-5.09.01/mailheaders/driver/driver.cc0000644000175000017500000000230014050437223017452 0ustar frankfrank/* driver.cc */ #include "driver.h" #include "../mailheaders" #include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) { MailHeaders mh(cin, MailHeaders::DONT_READ); try { mh.read(); } catch (exception &err) { cout << err.what() << endl; } mh.setHeaderIterator("Received"); cout << "=================================== All mail headers:\n"; copy(mh.begin(), mh.end(), ostream_iterator(cout, "\n")); cout << "=============================== First and last but 1 hdr:\n"; cout << mh[0] << endl << mh[mh.size() - 2] << endl; cout << "====================== Received: headers:\n"; copy(mh.beginh(), mh.endh(), ostream_iterator(cout, "\n")); cout << "====================== Received: headers, reversed order:\n"; copy(mh.rbeginh(), mh.rendh(), ostream_iterator(cout, "\n")); cout << "====================== all From headers:\n"; mh.setHeaderIterator("From", MailHeaders::PARTIAL); copy(mh.beginh(), mh.endh(), ostream_iterator(cout, "\n")); } bobcat-5.09.01/mailheaders/driver/driver.h0000644000175000017500000000017014050437223017317 0ustar frankfrank#ifndef INCLUDED_DRIVER_H_ #define INCLUDED_DRIVER_H_ #include #include namespace FBB { } #endif bobcat-5.09.01/mailheaders/driver/spam10000644000175000017500000000646614050437223016635 0ustar frankfrankFrom hsookh1004@hanmail.net Sat Mar 22 17:54:59 2003 Received: from oosix.icce.rug.nl (oosix.icce.rug.nl [129.125.14.80]) by suffix.rc.rug.nl (8.12.3/8.12.3/Debian-5) with ESMTP id h2MGsxcA015750 (version=TLSv1/SSLv3 cipher=EDH-RSA-DES-CBC3-SHA bits=168 verify=FAIL) for ; Sat, 22 Mar 2003 17:54:59 +0100 Received: from relay.surfnet.nl (relay.surfnet.nl [192.87.5.144]) by oosix.icce.rug.nl (8.12.3/8.12.3/Debian-5) with ESMTP id h2MGswZ5005649 for ; Sat, 22 Mar 2003 17:54:59 +0100 Received: from icce.rug.nl (unknown [211.110.47.214]) by relay.surfnet.nl (Postfix) with SMTP id 9A76F43DB for ; Sat, 22 Mar 2003 17:54:57 +0100 (MET) From: Á¤¹Î°æ Subject: ±×³É »èÁ¦ÇϽÃÁö ¸¶½Ã°í Çѹø º¸¼¼¿ä..Èñ¸ÁÀÌ º¸ÀÔ´Ï´Ù........................................(±¤,.°í) Content-Type: text/html;charset=ks_c_5601-1987 Message-Id: <20030322165457.9A76F43DB@relay.surfnet.nl> Date: Sat, 22 Mar 2003 17:54:57 +0100 (MET) To: undisclosed-recipients:; Content-Length: 2322 Lines: 34
À§ ¹è³Ê´Â ¹ß¼ÛÀÚ ¹× ¸ÞÀϳ»¿ë°ú ¹«°üÇÕ´Ï´Ù.

¾È³çÇϼ¼¿ä...
±ÝÀ¶¿¡ °üÇÑ ¸ðµç ºñ¹ÐÀ» °ø°³ÇÕ´Ï´Ù. ´õÀÌ»ó ´ëÃâ¾÷Àڵ鿡°Ô ÀÚ½ÅÀÇ
Á¤º¸¸¦ ÁÖÁö ¸¶½Ã°í ¼ö¼ö·á ¾øÀÌ º»ÀÎÀÌ Á÷Á¢ ´ëÃâ¹Þ°Ô ÇØµå¸³´Ï´Ù.
¿©±â ÇöÁ÷ 16ÀÎÀÇ ±ÝÀ¶Àü¹®°¡°¡ ¿©·¯ºÐÀÇ °í¹ÎÀ» Çѹø¿¡ ÇØ°áÇØ
µå¸®°Ú½À´Ï´Ù..
                  
Áö±Ý Ŭ¸¯ Çϼ¼¿ä.

¿¹) Çö´ëÄ«µå ¾ß°£Áõ¾× 500¸¸¿øÀÌ»ó (ÁÖ°£¾ÈµÊ)
¿¹) Çö´ëÄ«µå ÁÖ°£¿¡ 1,000¸¸¿ø Áõ¾×°¡´É (¾ß°£¾ÈµÊ)
¿¹) LGÄ«µå Áï½Ã¹ß±Þ°ú µ¿½Ã¿¡ ¹°°Ç±¸ÀÔ Çϴ¹ý
¿¹) ½Å¿ëºÒ·®ÀÚ ´ëÃâ 400¸¸¿ø °¡´É (2±ºµ¥)
¿¹) Â÷ ¼³Á¤¾øÀÌ ÇÒºÎÇϰí Ÿ°í ´Ù´Ï´Â ¹æ¹ý
¿¹) ¹«Á÷ÀÚ ´ëÃâ¹æ¹ý °ø°³ (1,000¸¸¿ø ÀÌ»ó °¡´É)
¿¹) Çϳª(±¸ ¼­¿ï)ÀºÇà ÀüÈ­·Î ÇÑÅëÈ­·Î 500¸¸¿ø ´ëÃâ
¿¹) ¾ÆÆÄÆ® »ç½Ã´Â ¿©¼ººÐÀº 100 ~ 500¸¸¿ø ´ëÃâ
¿¹) ½Å¿ëºÒ·®ÀÚ ´çÀÏ´ëÃâ ¹æ¹ý
¿¹) ¿Üȯ, ±¹¹ÎÄ«µå 1Â÷, 2Â÷ Áõ¾×¹æ¹ý

                   Áö±Ý Click Çϼ¼¿ä.

´ëÃâ¿¡ °üÇÑ ³ëÇÏ¿ì 50¿©°³¿Í Ä«µåÀÇ °üÇÑ ³ëÇÏ¿ì 50¿©°³¸¦
16ÀÎÀÇ ÇöÁ÷±ÝÀ¶ÀÎÀÌ ¸ðµÎ °ø°³ÇÕ´Ï´Ù..
À̰Ŵ٠¶ó´Â ź¼º°ú ÇÔ²² ¿©·¯ºÐÀÇ °í¹ÎÀº »ç¶óÁú°ÍÀÔ´Ï´Ù.
ÀÌÁ¨ ´õÀÌ»ó ¾÷Àڵ鿡°Ô ÀÚ½ÅÀÇ Á¤º¸¸¦ ÁÖÁö ¸¶½Ã°í °í¾×ÀÇ ¼ö¼ö·á¾øÀÌ
º»ÀÎÀÌ Á÷Á¢ ´ëÃâÀ» ¹ÞÀ¸¼¼¿ä...

                   WWW.WAMONEY.CO.KR

* »ó±âÀÇ ¸ÞÀÏÀº ±¤°í ¸ñÀûÀ¸·Î ¹ß¼ÛµÇ¾ú½À´Ï´Ù.
* ¿øÇÏÁö ¾ÊÀ¸½Ã´Â °æ¿ì¿¡´Â ¼ö½Å°ÅºÎ ÇϽñ⠹ٶø´Ï´Ù.   ²Ù¹÷!²Ù¹÷!

bobcat-5.09.01/mailheaders/driver/spam20000644000175000017500000000431414050437223016624 0ustar frankfrankFrom zjevf@excite.com Sat Mar 22 21:33:08 2003 Received: from dep.rc.rug.nl (dep.rc.rug.nl [129.125.3.10]) by suffix.rc.rug.nl (8.12.3/8.12.3/Debian-5) with ESMTP id h2MKX8c9019670 for ; Sat, 22 Mar 2003 21:33:08 +0100 Received: from excite.com (238.Red-80-36-13.pooles.rima-tde.net [80.36.13.238]) by dep.rc.rug.nl (8.9.3/8.9.3) with SMTP id VAA08234 for ; Sat, 22 Mar 2003 21:32:49 +0100 (MET) From: zjevf@excite.com Message-ID: <000510c6ea03$cce35275$28363632@qfafjfk.obp> To: Subject: A n t i * A g i n g M_i_r_a_c_l_e W_o_r_k_e_r 4883bLIH1-029NQXx2510vRym-24 Date: Sun, 23 Mar 2003 03:16:39 -0800 MIME-Version: 1.0 Content-Type: text/html; charset="iso-8859-1" X-Priority: 3 X-Mailer: Microsoft Outlook Express 5.00.2615.200 Importance: Normal Content-Length: 1350 Lines: 27 Message

* Reduce the amount of sleep you need
* Cause wounds to heal faster
* Lose weight while your sleeping
* Become less winded when excersizing
* Put color back in grey hair
* Grow hair back where it had once fallen out
* Tighten skin
* Strengthen bones
* Body builders - use this to build your muscles quicker
.........The List truly goes on and on..........

As seen on NBC, CBS, CNN, and Oprah! The health discovery
that actually reverses aging symptoms without dieting or exercise!
This PROVEN FDA approved discovery has been reported on by the
New England Journal of Medicine - don't just take our word for it.

In fact we'd like you to receive a F.R.E.E thirty day supply; look and feel
younger, lose weight, reduce sleep, The list goes on, we
encourage you to at least take a look at the information as to
what else it can do.

CLICK HERE

If the above link doesn't work: CLICK HERE

4837qhzz8-768bqfj0549vZSa3-859Vvll2323eyOG2-477Yltl47 bobcat-5.09.01/mailheaders/driver/mail.hein0000644000175000017500000001320214050437223017442 0ustar frankfrankFrom frank@suffix.rc.rug.nl Sun Mar 2 21:11:01 2003 Return-Path: Received: from suffix.rc.rug.nl (suffix.rc.rug.nl [129.125.3.162]) by knarfix.oostum.north (8.12.3/8.12.3/Debian -4) with ESMTP id h22KAvQp011565 (version=TLSv1/SSLv3 cipher=EDH-RSA-DES-CBC3-SHA bits=168 verify=FAIL) for ; Sun, 2 Mar 2003 21:10:59 +0100 Received: from suffix.rc.rug.nl (localhost [127.0.0.1]) by suffix.rc.rug.nl (8.12.3/8.12.3/Debian -4) with ESMTP id h22KAqCb003128 (version=TLSv1/SSLv3 cipher=EDH-RSA-DES-CBC3-SHA bits=168 verify=FAIL) for ; Sun, 2 Mar 2003 21:10:52 +0100 Received: (from frank@localhost) by suffix.rc.rug.nl (8.12.3/8.12.3/Debian -4) id h22KAqvc003127 for frank@dial30.service.rug.nl; Sun, 2 Mar 2003 21:10:52 +0100 Resent-Message-Id: <200303022010.h22KAqvc003127@suffix.rc.rug.nl> Received: from dep.rc.rug.nl (dep.rc.rug.nl [129.125.3.10]) by suffix.rc.rug.nl (8.12.3/8.12.3/Debian -4) with ESMTP id h1EJJ9Sj011249 for ; Fri, 14 Feb 2003 20:19:09 +0100 Received: from mano.soest.hawaii.edu (mano.soest.hawaii.edu [128.171.151.45]) by dep.rc.rug.nl (8.9.3/8.9.3) with ESMTP id UAA18183 for ; Fri, 14 Feb 2003 20:18:43 +0100 (MET) Received: from equator.soest.hawaii.edu (IDENT:root@equator [128.171.151.54]) by mano.soest.hawaii.edu (8.12.1/8.12.1) with ESMTP id h1EJJ1Jv003882 for ; Fri, 14 Feb 2003 09:19:02 -1000 (HST) Received: (from hein@localhost) by equator.soest.hawaii.edu (8.11.6/8.11.6) id h1EJJ0R01740 for f.b.brokken@rc.rug.nl; Fri, 14 Feb 2003 09:19:00 -1000 Date: Fri, 14 Feb 2003 09:19:00 -1000 From: Hein Zelle To: "Frank B. Brokken" Subject: Re: iterators + annotations Message-ID: <20030214191900.GA1667@equator.soest.hawaii.edu> References: <20030207185644.GA1714@equator.soest.hawaii.edu> <20030213131606.GA7329@rc.rug.nl> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20030213131606.GA7329@rc.rug.nl> Resent-From: frank@rc.rug.nl Resent-Date: Sun, 2 Mar 2003 21:10:52 +0100 Resent-To: frank@dial30.service.rug.nl Status: RO Content-Length: 3503 Lines: 79 Hoi Frank, > moet-ie ook worden geinitialiseerd. Maar de volgende truuk leert je dat een > iterator normaliter op 0 is geinitialiseerd: > > int main(int argc, char *argv[]) > { > vector::iterator vi; > > cout << &*vi << endl; > } Ah, dat dacht ik al maar ik wist het niet zeker. Ik heb dit misschien nodig, tenzij ik jouw truuk van een lege static member vector gebruik. Probleem is namelijk dat de class met de iterator niet weet naar welke vector hij wijst, en dus ook niet kan vergelijken met vector.end(). (Of dat wenselijk is is vraag 2, maar goed) Ik denk dat de static member oplossing het mooist is. > end() kan volgens mij prima, want end() wijst dan toch al voorbij het laatste > element. begin() is dan direct al end(): de volgende code levert `gelijk' Dat is goed om te weten. Misschien is dat iets om expliciet in de annotations te vermelden: het werd mij niet helemaal duidelijk welke members van een lege vector je nou wel en niet mag aanroepen. > Wb een eerdere mail, over Java: ik ben niet zo blij met Java. Er zitten een > paar onlogische constructies in ... [knip knip] Bedankt voor je uitleg, dat was ook mijn eerste indruk. Bevestigt mijn idee dat ik het niet hoef te leren totdat ik echt behoefte krijg aan web-applicaties of iets dergelijks. (Alhoewel de basis niet zo moeilijk lijkt, gaat er waarschijnlijk een hoop tijd zitten in het leren van die 2000 classes ...) > De basis gedachte is: er gebeuren dingen die ik niet beheers, en > waar ik mogelijk niet om heb gevraagd. Daar heb ik een grote hekel > aan in programmeertalen. Idem. Dat vind ik een goed argument om het niet te gebruiken, mits je een alternatief hebt natuurlijk. Helemaal nu ik de STL van C++ begin te kennen en begrijpen, zie ik het nut van java niet zo in (voor mij). De STL vult het voornaamste gat in wat er nog was: een standaard oplossing voor de dingen die je anders bij ieder project weer opnieuw maakt. Met name vector en list vind ik een fantastische uitvinding. (en de algoritmes als sort()) > Verder heb ik wel eens gekeken naar 't verschil tussen een complex C++ > programma en hetzelfde Java programma: Java runt 10 x zo traag en gebruikt 10 > x zoveel geheugen. Ik kan aardig omgaan met Java, en leer KI-studenten hier > programmeren mbv Java, maar ik ben er bepaald niet juichend enthousiast > over. C/C++ vind ik nog steeds in hoge mate te prefereren boven Java. Over runtime performance van java: daar zijn ze bij sun nu blijkbaar ook achter gekomen. Als je tijd hebt vind je het volgende artikel misschien wel interessant: een intern memo van SUN over de redenen waarom java niet breed geaccepteerd wordt. (niet van de origine site, dit is een mirror, originele adres ben ik kwijt) http://www.misura.org/temp/JavaInternalMemo.html > Sorry voor de late reactie(s), maar soms heb ik 't hier even een beetje > druk. Wellicht heb je (nog) iets aan mijn verlate reacties. Ben je mal, natuurlijk snap ik dat je het druk hebt. Mijn mail over java was bepaald niet dringend, en het helpt zeker om er van jou wat over te horen, omdat jij er daadwerkelijk mee gewerkt hebt. Bedankt en groeten (uit een druilerig Hawaii) Hein >-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-< Unix is user friendly. It's just very particular about who it's friends are. Hein Zelle hein@icce.rug.nl http://www.icce.rug.nl/~hein >-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-< bobcat-5.09.01/mailheaders/driver/driver.ih0000644000175000017500000000014614050437223017473 0ustar frankfrank#include "driver.h" #include #include using namespace std; using namespace FBB; bobcat-5.09.01/mailheaders/driver/mail0000644000175000017500000001345014050437223016525 0ustar frankfrankFrom m.pattiapon@rc.rug.nl Mon Jul 15 13:56:57 2002 Received: from oosix.icce.rug.nl (oosix.icce.rug.nl [129.125.14.80]) by suffix.icce.rug.nl (8.12.3/8.12.3/Debian -4) with ESMTP id g6FButlO018423 (version=TLSv1/SSLv3 cipher=EDH-RSA-DES-CBC3-SHA bits=168 verify=FAIL) for ; Mon, 15 Jul 2002 13:56:57 +0200 Received: from rug.nl (imap.rc.rug.nl [129.125.50.21]) by oosix.icce.rug.nl (8.12.3/8.12.3/Debian -4) with ESMTP id g6FBut14018196 for ; Mon, 15 Jul 2002 13:56:55 +0200 Received: from by rug.nl (CommuniGate Pro RULES 3.5.9) with RULES id 175635; Mon, 15 Jul 2002 13:56:56 +0200 X-Autogenerated: Mirror X-Mirrored-by: (F.B.Brokken) Received: from dep.rc.rug.nl ([129.125.3.10] verified) by rug.nl (CommuniGate Pro SMTP 3.5.9) with ESMTP id 175634 for brokken@imap.rc.rug.nl; Mon, 15 Jul 2002 13:56:55 +0200 Received: from rc-285 (rc-285.rc.rug.nl [129.125.3.72]) by dep.rc.rug.nl (8.9.3/8.9.3) with ESMTP id NAA21616 for ; Mon, 15 Jul 2002 13:56:55 +0200 From: "Magda Pattiapon" Organization: Rekencentrum RUG To: F.B.Brokken@rc.rug.nl Date: Mon, 15 Jul 2002 13:56:54 +0200 MIME-Version: 1.0 Content-type: text/plain; charset=US-ASCII Content-transfer-encoding: 7BIT Subject: fakemails chello Reply-to: m.pattiapon@rc.rug.nl Message-ID: <3D32D4A5.1582.5D218B74@localhost> Priority: normal Status: RO Content-Length: 4411 Lines: 70 Jul 12 18:04:51 dep sendmail[16508]: SAA16508: from=, size=41126, class=0, pri=71126, nrcpts=1, msgid=<200207121604.SAA16508@dep.rc.rug.nl>, proto=SMTP, relay=a106005.upc-a.chello.nl [62.163.106.5] Jul 12 18:04:51 dep sendmail[16510]: SAA16508: to=brokken@imap.rc.rug.nl, delay=00:00:03, xdelay=00:00:00, mailer=esmtp, relay=imap.rc.rug.nl. [129.125.50.21], stat=Sent (173817 message accepted for delivery) Jul 12 18:04:51 dep sendmail[16510]: SAA16508: to=brokken@rc2000.rc.rug.nl, delay=00:00:03, xdelay=00:00:00, mailer=esmtp, relay=rc2000.rc.rug.nl. [129.125.3.3], stat=Sent (Data received OK.) Jul 12 18:12:42 dep sendmail[16585]: SAA16585: from=, size=41147, class=0, pri=71147, nrcpts=1, msgid=<200207121612.SAA16585@dep.rc.rug.nl>, proto=SMTP, relay=a106005.upc-a.chello.nl [62.163.106.5] Jul 12 18:12:42 dep sendmail[16588]: SAA16585: to=brokken@imap.rc.rug.nl, delay=00:00:03, xdelay=00:00:00, mailer=esmtp, relay=imap.rc.rug.nl. [129.125.50.21], stat=Sent (173824 message accepted for delivery) Jul 12 18:12:42 dep sendmail[16588]: SAA16585: to=brokken@rc2000.rc.rug.nl, delay=00:00:03, xdelay=00:00:00, mailer=esmtp, relay=rc2000.rc.rug.nl. [129.125.3.3], stat=Sent (Data received OK.) Jul 12 18:19:25 dep sendmail[16650]: SAA16650: from=, size=41127, class=0, pri=71127, nrcpts=1, msgid=<200207121619.SAA16650@dep.rc.rug.nl>, proto=SMTP, relay=a106005.upc-a.chello.nl [62.163.106.5] Jul 12 18:19:25 dep sendmail[16651]: SAA16650: to=brokken@imap.rc.rug.nl, delay=00:00:04, xdelay=00:00:00, mailer=esmtp, relay=imap.rc.rug.nl. [129.125.50.21], stat=Sent (173833 message accepted for delivery) Jul 12 18:19:25 dep sendmail[16651]: SAA16650: to=brokken@rc2000.rc.rug.nl, delay=00:00:04, xdelay=00:00:00, mailer=esmtp, relay=rc2000.rc.rug.nl. [129.125.3.3], stat=Sent (Data received OK.) Jul 12 18:25:14 dep sendmail[16691]: SAA16691: from=, size=42320, class=0, pri=72320, nrcpts=1, msgid=<200207121625.SAA16691@dep.rc.rug.nl>, proto=SMTP, relay=a106005.upc-a.chello.nl [62.163.106.5] Jul 12 18:25:14 dep sendmail[16693]: SAA16691: to=brokken@imap.rc.rug.nl, delay=00:00:04, xdelay=00:00:00, mailer=esmtp, relay=imap.rc.rug.nl. [129.125.50.21], stat=Sent (173839 message accepted for delivery) Jul 12 18:25:14 dep sendmail[16693]: SAA16691: to=brokken@rc2000.rc.rug.nl, delay=00:00:04, xdelay=00:00:00, mailer=esmtp, relay=rc2000.rc.rug.nl. [129.125.3.3], stat=Sent (Data received OK.) Jul 12 18:29:24 dep sendmail[16738]: SAA16738: from=, size=41140, class=0, pri=71140, nrcpts=1, msgid=<200207121629.SAA16738@dep.rc.rug.nl>, proto=SMTP, relay=a106005.upc-a.chello.nl [62.163.106.5] Jul 12 18:29:24 dep sendmail[16739]: SAA16738: to=brokken@imap.rc.rug.nl, delay=00:00:03, xdelay=00:00:00, mailer=esmtp, relay=imap.rc.rug.nl. [129.125.50.21], stat=Sent (173845 message accepted for delivery) Jul 12 18:29:24 dep sendmail[16739]: SAA16738: to=brokken@rc2000.rc.rug.nl, delay=00:00:03, xdelay=00:00:00, mailer=esmtp, relay=rc2000.rc.rug.nl. [129.125.3.3], stat=Sent (Data received OK.) Jul 12 18:35:52 dep sendmail[16800]: SAA16800: from=, size=42316, class=0, pri=72316, nrcpts=1, msgid=<200207121635.SAA16800@dep.rc.rug.nl>, proto=SMTP, relay=a106005.upc-a.chello.nl [62.163.106.5] Jul 12 18:35:52 dep sendmail[16801]: SAA16800: to=brokken@imap.rc.rug.nl, delay=00:00:03, xdelay=00:00:00, mailer=esmtp, relay=imap.rc.rug.nl. [129.125.50.21], stat=Sent (173851 message accepted for delivery) Jul 12 18:35:53 dep sendmail[16801]: SAA16800: to=brokken@rc2000.rc.rug.nl, delay=00:00:04, xdelay=00:00:01, mailer=esmtp, relay=rc2000.rc.rug.nl. [129.125.3.3], stat=Sent (Data received OK.) Jul 12 18:42:52 dep sendmail[16864]: SAA16864: from=, size=42312, class=0, pri=72312, nrcpts=1, msgid=<200207121642.SAA16864@dep.rc.rug.nl>, proto=SMTP, relay=a106005.upc-a.chello.nl [62.163.106.5] Jul 12 18:42:52 dep sendmail[16865]: SAA16864: to=brokken@imap.rc.rug.nl, delay=00:00:04, xdelay=00:00:00, mailer=esmtp, relay=imap.rc.rug.nl. [129.125.50.21], stat=Sent (173858 message accepted for delivery) Jul 12 18:42:53 dep sendmail[16865]: SAA16864: to=brokken@rc2000.rc.rug.nl, delay=00:00:05, xdelay=00:00:01, mailer=esmtp, relay=rc2000.rc.rug.nl. [129.125.3.3], stat=Sent (Data received OK.) bobcat-5.09.01/mbuf/0000755000175000017500000000000014050437223013035 5ustar frankfrankbobcat-5.09.01/mbuf/xsputn.cc0000644000175000017500000000030114050437223014677 0ustar frankfrank#include "mbuf.ih" std::streamsize Mbuf::xsputn(char const *buf, std::streamsize n) { atFirstChar(); d_ostr.write(buf, n); return n; // only if the write succeeded } bobcat-5.09.01/mbuf/showlinenr.cc0000644000175000017500000000016414050437223015535 0ustar frankfrank#include "mbuf.ih" inline void Mbuf::setLineNr(size_t lineNr) { d_showLineNr = true; d_lineNr = lineNr; } bobcat-5.09.01/mbuf/overflow.cc0000644000175000017500000000014714050437223015211 0ustar frankfrank#include "mbuf.ih" int Mbuf::overflow(int c) { atFirstChar(); d_ostr.put(c); return c; } bobcat-5.09.01/mbuf/setcount.f0000644000175000017500000000010214050437223015041 0ustar frankfrankinline void Mbuf::setCount(size_t count) { d_count = count; } bobcat-5.09.01/mbuf/reset1.cc0000644000175000017500000000070514050437223014551 0ustar frankfrank#include "mbuf.ih" void Mbuf::reset(Mbuf const &other) { sync(); d_ofstr = other.d_ofstr; d_ostr.rdbuf(other.d_ostr.rdbuf()); d_firstChar = true; d_throw = other.d_throw; d_tag = other.d_tag; d_count = other.d_count; d_maxCount = other.d_maxCount; d_lineExcess = other.d_lineExcess; d_showLineNr = other.d_showLineNr; d_lineNr = other.d_lineNr; d_lineTag = other.d_lineTag; } bobcat-5.09.01/mbuf/reset3.cc0000644000175000017500000000070514050437223014553 0ustar frankfrank#include "mbuf.ih" void Mbuf::reset(string const &name, size_t maxCount, string const &tag, bool throwing) { sync(); if (d_ofstr->rdbuf() == d_ostr.rdbuf()) d_ofstr.reset(); d_ofstr = make_shared(name); d_ostr.rdbuf(d_ofstr->rdbuf()), d_firstChar = true; d_throw = throwing; setTag(tag); d_maxCount = maxCount; d_lineExcess = d_count >= maxCount; inspectOfstr(name); } bobcat-5.09.01/mbuf/reset2.cc0000644000175000017500000000056014050437223014551 0ustar frankfrank#include "mbuf.ih" void Mbuf::reset(streambuf *buf, size_t maxCount, string const &tag, bool throwing) { sync(); if (d_ofstr->rdbuf() == d_ostr.rdbuf()) d_ofstr.reset(); d_ostr.rdbuf(buf); d_firstChar = true; d_throw = throwing; setTag(tag); d_maxCount = maxCount; d_lineExcess = d_count >= maxCount; } bobcat-5.09.01/mbuf/mbuf1.cc0000644000175000017500000000040614050437223014356 0ustar frankfrank#include "mbuf.ih" Mbuf::Mbuf() : d_ostr(cout.rdbuf()), d_firstChar(true), d_throw(false), d_count(0), d_maxCount(numeric_limits::max()), d_lineExcess(false), d_showLineNr(false), d_lineNr(0), d_lineTag("Line") {} bobcat-5.09.01/mbuf/inspectofstr.cc0000644000175000017500000000024714050437223016072 0ustar frankfrank#include "mbuf.ih" void Mbuf::inspectOfstr(string const &name) const { if (not d_ofstr->good()) throw Exception{1} << "Can't write `" << name << '\''; } bobcat-5.09.01/mbuf/atfirstchar.cc0000644000175000017500000000103214050437223015652 0ustar frankfrank#include "mbuf.ih" void Mbuf::atFirstChar() { if (not d_firstChar) return; d_firstChar = false; ++d_count; d_lineExcess = d_count + 1 > d_maxCount; // if d_maxCount == UINT_MAX // then this is never true if (d_lineExcess) { d_ostr.setstate(ios::badbit); return; } if (d_tag.length()) showTag(); if (d_showLineNr) { d_showLineNr = false; d_ostr << d_lineTag << ' ' << d_lineNr << ": "; } } bobcat-5.09.01/mbuf/throwing.f0000644000175000017500000000010214050437223015036 0ustar frankfrankinline void Mbuf::throwing(bool ifTrue) { d_throw = ifTrue; } bobcat-5.09.01/mbuf/maxcount.f0000644000175000017500000000010014050437223015031 0ustar frankfrankinline size_t Mbuf::maxCount() const { return d_maxCount; } bobcat-5.09.01/mbuf/lineexcess.f0000644000175000017500000000010214050437223015337 0ustar frankfrankinline bool Mbuf::lineExcess() const { return d_lineExcess; } bobcat-5.09.01/mbuf/mbuf.cc0000644000175000017500000000002514050437223014272 0ustar frankfrank#include "mbuf.ih" bobcat-5.09.01/mbuf/count.f0000644000175000017500000000007214050437223014333 0ustar frankfrankinline size_t Mbuf::count() const { return d_count; } bobcat-5.09.01/mbuf/linetag.f0000644000175000017500000000011214050437223014621 0ustar frankfrankinline std::string const &Mbuf::lineTag() const { return d_lineTag; } bobcat-5.09.01/mbuf/mbuf3.cc0000644000175000017500000000127514050437223014365 0ustar frankfrank#include "mbuf.ih" Mbuf::Mbuf(string const &name, size_t maxCount, string const &tag, bool throwing) : d_ofstr(new ofstream(name)), d_ostr(d_ofstr->rdbuf()), d_firstChar(true), d_throw(throwing), d_count(0), d_maxCount(maxCount), d_lineExcess(maxCount == 0), d_showLineNr(false), d_lineNr(0), d_lineTag("Line") { setTag(tag); inspectOfstr(name); } // If a MsgStream is created by name and a second MsgStream is intialized // using the initial stream's MsgBuf then the initial MsgStream should outlive // the second MsgStream. If not then the 2nd MsgStream's MsgBuf::d_ostr will // no longer refer to a valid streambuf. bobcat-5.09.01/mbuf/throws.f0000644000175000017500000000007114050437223014530 0ustar frankfrankinline bool Mbuf::throws() const { return d_throw; } bobcat-5.09.01/mbuf/showtag.cc0000644000175000017500000000037314050437223015023 0ustar frankfrank#include "mbuf.ih" void Mbuf::showTag() { if (d_tag.empty()) return; d_ostr << d_tag; // starts with [ if (d_maxCount != numeric_limits::max()) d_ostr << ' ' << d_count; d_ostr << "] "; } bobcat-5.09.01/mbuf/sync.cc0000644000175000017500000000014414050437223014317 0ustar frankfrank#include "mbuf.ih" int Mbuf::sync() { d_ostr.flush(); d_firstChar = true; return 0; } bobcat-5.09.01/mbuf/setlinenr.cc0000644000175000017500000000015514050437223015350 0ustar frankfrank#include "mbuf.ih" void Mbuf::setLineNr(size_t lineNr) { d_lineNr = lineNr; d_showLineNr = true; } bobcat-5.09.01/mbuf/settag.cc0000644000175000017500000000020414050437223014627 0ustar frankfrank#include "mbuf.ih" void Mbuf::setTag(string const &tag) { d_tag = not tag.empty() && (tag.front() != '[') ? '[' + tag : tag; } bobcat-5.09.01/mbuf/nolinenr.f0000644000175000017500000000007314050437223015030 0ustar frankfrankinline void Mbuf::noLineNr() { d_showLineNr = false; } bobcat-5.09.01/mbuf/setmaxcount.f0000644000175000017500000000011614050437223015554 0ustar frankfrankinline void Mbuf::setMaxCount(size_t maxCount) { d_maxCount = maxCount; } bobcat-5.09.01/mbuf/mbuf0000644000175000017500000000620114050437223013710 0ustar frankfrank#ifndef INCLUDED_BOBCAT_MBUF_ #define INCLUDED_BOBCAT_MBUF_ #include #include #include #include #include #include namespace FBB { class Mbuf: public std::streambuf { std::shared_ptr d_ofstr; std::ostream d_ostr; // this is the receiving ostream bool d_firstChar; bool d_throw; std::string d_tag; size_t d_count; // counts # messages size_t d_maxCount; bool d_lineExcess; bool d_showLineNr; size_t d_lineNr; std::string d_lineTag; public: Mbuf(); // 1 explicit Mbuf(std::streambuf *strbuf, // 2 size_t maxCount = std::numeric_limits::max(), std::string const &tag = "", bool throwing = false); // 3 explicit Mbuf(std::string const &name, size_t maxCount = std::numeric_limits::max(), std::string const &tag = "", bool throwing = false); void reset(Mbuf const &mbuf); // 1: initialize from // mbuf. Shares // d_ofstr and uses // d_ostr's rdbuf void reset(std::streambuf *strbuf, size_t maxCount, // 2 std::string const &tag, bool throwing); void reset(std::string const &name, size_t maxCount, // 3 std::string const &tag, bool throwing); bool throws() const; // .f void throwing(bool ifTrue); // .f size_t count() const; // .f size_t maxCount() const; // .f std::string const &tag() const; // .f std::string const &lineTag() const; // .f void noLineNr(); // .f void setLineNr(size_t lineNr); void setCount(size_t count); // .f void setMaxCount(size_t maxCount); // .f void setTag(std::string const &tag); void setLineTag(std::string const &lineTag); // .f bool lineExcess() const; // .f private: void atFirstChar(); bool firstChar() const; void showTag(); void inspectOfstr(std::string const &name) const; int overflow(int c) override; std::streamsize xsputn(char const *buf, std::streamsize n) override; int sync() override; }; #include "count.f" #include "lineexcess.f" #include "linetag.f" #include "maxcount.f" #include "nolinenr.f" #include "setcount.f" #include "setlinetag.f" #include "setmaxcount.f" #include "tag.f" #include "throwing.f" #include "throws.f" } // FBB #endif bobcat-5.09.01/mbuf/mbuf2.cc0000644000175000017500000000054314050437223014361 0ustar frankfrank#include "mbuf.ih" Mbuf::Mbuf(streambuf *buf, size_t maxCount, string const &tag, bool throwing) : d_ostr(buf), d_firstChar(true), d_throw(throwing), d_count(0), d_maxCount(maxCount), d_lineExcess(maxCount == 0), d_showLineNr(false), d_lineNr(0), d_lineTag("Line") { setTag(tag); } bobcat-5.09.01/mbuf/setlinetag.f0000644000175000017500000000012614050437223015342 0ustar frankfrankinline void Mbuf::setLineTag(std::string const &lineTag) { d_lineTag = lineTag; } bobcat-5.09.01/mbuf/tag.f0000644000175000017500000000010214050437223013750 0ustar frankfrankinline std::string const &Mbuf::tag() const { return d_tag; } bobcat-5.09.01/mbuf/mbuf.ih0000644000175000017500000000023014050437223014303 0ustar frankfrank#include "mbuf" #include #include #include #include "../exception/exception" using namespace std; using namespace FBB; bobcat-5.09.01/mbuf/driver/0000755000175000017500000000000014050437223014330 5ustar frankfrankbobcat-5.09.01/mbuf/driver/build0000755000175000017500000000050614050437223015356 0ustar frankfrank#!/bin/bash #CMD="g++ `cat ../../c++std` -o driver -Wall -I../../tmp driver.cc -L../../tmp/lib \ # -lbobcat -s" # CMD="g++ `cat ../../c++std` -o driver -Wall driver.cc ../*.o -lbobcat -s" CMD="g++ `cat ../../c++std` -o driver -Wall driver.cc -lbobcat -s" echo $CMD $CMD bobcat-5.09.01/mbuf/driver/driver.cc0000644000175000017500000000130514050437223016131 0ustar frankfrank #include #include #include #include using namespace std; using namespace FBB; int main() { Mbuf msb(cout.rdbuf()); Mstream ms(&msb); string s; ms << "hello world" << s << 12 << endl; // explicit flush ms.setstate(ios::badbit); ms << "this should fail" << endl; // explicit flush ms.clear(); ms << "this should be shown" << endl; // explicit flush ms.setMaxCount(0); try { ms << "Following this, we throw" << endl; } catch (exception const &err) { cerr << "Caught exception" << endl; } cout << "leaving " << ms.bad() << "\n"; } bobcat-5.09.01/milter/0000755000175000017500000000000014050437223013400 5ustar frankfrankbobcat-5.09.01/milter/body.cc0000644000175000017500000000015114050437223014641 0ustar frankfrank#include "milter.ih" sfsistat Milter::body(unsigned char *text, size_t length) { return CONTINUE; } bobcat-5.09.01/milter/data.cc0000644000175000017500000000022114050437223014613 0ustar frankfrank#include "milter.ih" string Milter::s_name; Milter *Milter::s_mp; bool Milter::s_callClose; unordered_map Milter::s_map; bobcat-5.09.01/milter/eom.cc0000644000175000017500000000010614050437223014464 0ustar frankfrank#include "milter.ih" sfsistat Milter::eom() { return CONTINUE; } bobcat-5.09.01/milter/mclose.cc0000644000175000017500000000062614050437223015175 0ustar frankfrank#include "milter.ih" sfsistat Milter::mClose(SMFICTX *ctx) { iterator it = s_map.find(ctx); sfsistat ret = SMFIS_CONTINUE; if (it != s_map.end()) // installed. { if (s_callClose) ret = it->second->close(); delete it->second; // delete this Milter s_map.erase(it); // and erase from the map } return ret; } bobcat-5.09.01/milter/sender.cc0000644000175000017500000000012414050437223015164 0ustar frankfrank#include "milter.ih" sfsistat Milter::sender(char **argv) { return CONTINUE; } bobcat-5.09.01/milter/recipient.cc0000644000175000017500000000012714050437223015671 0ustar frankfrank#include "milter.ih" sfsistat Milter::recipient(char **argv) { return CONTINUE; } bobcat-5.09.01/milter/eoh.cc0000644000175000017500000000010614050437223014457 0ustar frankfrank#include "milter.ih" sfsistat Milter::eoh() { return CONTINUE; } bobcat-5.09.01/milter/install.cc0000644000175000017500000000055414050437223015361 0ustar frankfrank#include "milter.ih" Milter *Milter::install(SMFICTX *ctx) { iterator it = s_map.find(ctx); if (it != s_map.end()) // already installed. return it->second; Milter *mp = s_mp->clone(); mp->d_ctx = ctx; // make ctx available to the Milter itself return s_map[ctx] = mp; // return the Milter's address } bobcat-5.09.01/milter/milter0000644000175000017500000002454414050437223014630 0ustar frankfrank#ifndef INCLUDED_BOBCAT_MILTER_ #define INCLUDED_BOBCAT_MILTER_ #include #include #include #include #include namespace FBB { class Milter { static std::string s_name; static Milter *s_mp; static bool s_callClose; typedef std::unordered_map::iterator iterator; static std::unordered_map s_map; SMFICTX *d_ctx; // for local use only public: virtual ~Milter(); // empty typedef size_t callback_set; enum CallBack { CONNECT = 1 << 0, HELO = 1 << 1, SENDER = 1 << 2, RECIPIENT = 1 << 3, HEADER = 1 << 4, EOH = 1 << 5, BODY = 1 << 6, EOM = 1 << 7, ABORT = 1 << 8, CLOSE = 1 << 9, UNKNOWN = 1 << 10, // version > 2 DATA = 1 << 11, // version > 3 ALL_CALLBACKS = (DATA << 1) - 1 }; typedef unsigned long flag_set; enum Flags { NO_FLAGS = 0L, ADD_HEADERS = SMFIF_ADDHDRS, // filter may add headers ADD_RECIPIENTS = SMFIF_ADDRCPT, // filter may add recipients CHANGE_BODY = SMFIF_CHGBODY, // filter may replace body CHANGE_HEADERS = SMFIF_CHGHDRS, // filter may change/delete // headers DELETE_RECIPIENTS = SMFIF_DELRCPT, // filter may delete recipients QUARANTINE = SMFIF_QUARANTINE, // filter may quarantine // envelope ALL_FLAGS = ADD_HEADERS | ADD_RECIPIENTS | CHANGE_BODY | CHANGE_HEADERS | DELETE_RECIPIENTS | QUARANTINE }; enum Status { ACCEPT = SMFIS_ACCEPT, CONTINUE = SMFIS_CONTINUE, DISCARD = SMFIS_DISCARD, REJECT = SMFIS_REJECT, TEMPFAIL = SMFIS_TEMPFAIL, }; enum Return { FAILURE = MI_FAILURE, SUCCESS = MI_SUCCESS, }; static void initialize(std::string const &name, Milter &milter, callback_set callbacks = CONNECT, flag_set flags = NO_FLAGS); static bool start() { return smfi_main() == MI_SUCCESS; } static void stop() { smfi_stop(); } static std::string const &name() { return s_name; } protected: Milter() = default; Milter(Milter const &other) = delete; virtual sfsistat abort(); bool addHeader(std::string const &hdrName, std::string const &hdrValue) { return smfi_addheader(d_ctx, const_cast(hdrName.c_str()), const_cast(hdrValue.c_str())) == SUCCESS; } // from eom() only // hdr-name: without : // hdr-value: \n and \t ok. bool addRecipient(std::string const &rcptName) { return smfi_addrcpt(d_ctx, const_cast(rcptName.c_str())) == SUCCESS; } virtual sfsistat body(unsigned char *text, size_t length); bool changeHeader(std::string const &hdrName, unsigned headerNr, std::string const &hdrValue) { return smfi_chgheader(d_ctx, const_cast(hdrName.c_str()), headerNr, hdrValue.length() ? const_cast(hdrValue.c_str()) : 0 ) == SUCCESS; } virtual Milter *clone() const = 0; // cloning required virtual sfsistat close(); virtual sfsistat connect(char *hostname, _SOCK_ADDR *hostaddr); #if SMFI_VERSION > 3 virtual sfsistat data(); #endif bool deleteRecipient(std::string const &rcptName) { return smfi_delrcpt(d_ctx, const_cast(rcptName.c_str())) == SUCCESS; } virtual sfsistat eoh(); virtual sfsistat eom(); virtual sfsistat header(char *headerf, char *headerv); virtual sfsistat helo(char *helohost); SMFICTX *id() const { return d_ctx; } bool insertHeader(size_t hdrIdx, std::string const &hdrName, std::string const &hdrValue) { return smfi_insheader(d_ctx, hdrIdx, const_cast(hdrName.c_str()), const_cast(hdrValue.c_str())); } static bool openSocket(bool removeIfTrue = true) { return smfi_opensocket(removeIfTrue) == SUCCESS; } bool quarantine(std::string const &reason) { return smfi_quarantine(d_ctx, const_cast(reason.c_str())) == SUCCESS; } virtual sfsistat recipient(char **argv); bool replaceBody(std::string const &body) { return smfi_replacebody(d_ctx, reinterpret_cast ( const_cast(body.c_str()) ), body.length()) == SUCCESS; } virtual sfsistat sender(char **argv); static bool setBacklog(size_t backlog = 5) { return smfi_setbacklog(backlog) == SUCCESS; } static void setConnection(std::string const &socketName) { smfi_setconn(const_cast(socketName.c_str())); } bool setReply(std::string const &rcode, std::string const &xcode = "", std::string const &msg = "") { return smfi_setreply(d_ctx, const_cast(rcode.c_str()), xcode.length() ? const_cast(xcode.c_str()) : 0, const_cast(msg.c_str())); // rcode: The three-digit (RFC 821/2821) SMTP reply code, as a // null-terminated string. rcode cannot be NULL, and must be a // valid 4XX or 5XX reply code. // xxcode The extended (RFC 1893/2034) reply code. If xcode is // NULL, no extended code is used. Otherwise, xcode must // conform to RFC 1893/2034. // * Values passed to smfi_setreply are not checked for // standards compliance. // * The message parameter should contain only printable // characters, other characters may lead to undefined // behavior. For example, CR or LF will cause the call to // fail, single '%' characters will cause the text to be // ignored (if there really should be a '%' in the string, use // '%%' just like for printf(3)). // * If the reply code (rcode) given is a '4XX' code but // SMFI_REJECT is used for the message, the custom reply is // not used. // * Similarly, if the reply code (rcode) given is a '5XX' // code but SMFI_TEMPFAIL is used for the message, the custom // reply is not used. // Note: in neither of the last two cases an error is returned // to the milter, libmilter silently ignores the reply code. // * If the milter returns SMFI_TEMPFAIL and sets the reply // code to '421', then the SMTP server will terminate the SMTP // session with a 421 error code. } // can't do smfi_setmlreply(ctx, ...) // since there is no smfi_Vsetmlreply(ctx, ...) static void setTimeout(size_t seconds = 7210) { smfi_settimeout(seconds); } char const *symval(std::string const &name) const { return smfi_getsymval(d_ctx, const_cast(name.c_str())); } #if SMFI_VERSION > 2 sfsistat unknown(char const *ptr); #endif bool wait() // from eom() only { return smfi_progress(d_ctx) == SUCCESS; } private: static Milter *install(SMFICTX *ctx); static sfsistat mConnect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr) { return install(ctx)->connect(hostname, hostaddr); } static sfsistat mAbort(SMFICTX *ctx) { return install(ctx)->abort(); } static sfsistat mBody(SMFICTX *ctx, unsigned char *body, size_t len) { return install(ctx)->body(body, len); } static sfsistat mSender(SMFICTX *ctx, char **argv) { return install(ctx)->sender(argv); } static sfsistat mRecipient(SMFICTX *ctx, char **argv) { return install(ctx)->recipient(argv); } static sfsistat mEoh(SMFICTX *ctx) { return install(ctx)->eoh(); } static sfsistat mEom(SMFICTX *ctx) { return install(ctx)->eom(); } static sfsistat mHeader(SMFICTX *ctx, char *headerf, char *headerv) { return install(ctx)->header(headerf, headerv); } static sfsistat mHelo(SMFICTX *ctx, char *helohost) { return install(ctx)->helo(helohost); } static sfsistat mClose(SMFICTX *ctx); #if SMFI_VERSION > 2 static sfsistat mUnknown(SMFICTX *ctx, char const *ptr) { return install(ctx)->unknown(ptr); } #endif /* SMFI_VERSION > 2 */ #if SMFI_VERSION > 3 static sfsistat mData(SMFICTX *ctx) { return install(ctx)->data(); } #endif /* SMFI_VERSION > 3 */ }; } #endif bobcat-5.09.01/milter/close.cc0000644000175000017500000000011014050437223015004 0ustar frankfrank#include "milter.ih" sfsistat Milter::close() { return CONTINUE; } bobcat-5.09.01/milter/helo.cc0000644000175000017500000000012514050437223014634 0ustar frankfrank#include "milter.ih" sfsistat Milter::helo(char *helohost) { return CONTINUE; } bobcat-5.09.01/milter/destructor.cc0000644000175000017500000000005314050437223016103 0ustar frankfrank#include "milter.ih" Milter::~Milter() {} bobcat-5.09.01/milter/abort.cc0000644000175000017500000000011014050437223015006 0ustar frankfrank#include "milter.ih" sfsistat Milter::abort() { return CONTINUE; } bobcat-5.09.01/milter/header.cc0000644000175000017500000000014514050437223015137 0ustar frankfrank#include "milter.ih" sfsistat Milter::header(char *headerf, char *headerv) { return CONTINUE; } bobcat-5.09.01/milter/unknown.cc0000644000175000017500000000016714050437223015412 0ustar frankfrank#include "milter.ih" #if SMFI_VERSION > 2 sfsistat Milter::unknown(char const *ptr) { return CONTINUE; } #endif bobcat-5.09.01/milter/initialize.cc0000644000175000017500000000506014050437223016051 0ustar frankfrank#include "milter.ih" void Milter::initialize(string const &name, Milter &milter, callback_set callbacks, flag_set flags) { if (s_mp) throw Exception{1} << "Milter::initialize(): can't define multiple Milters"; if (flags & ~ALL_FLAGS) throw Exception{1} << "Milter::initialize(): invalid flag(s): " << hex << (flags & ~ALL_FLAGS)<< dec; if (!callbacks) throw Exception{1} << "Milter::initialize(): no callbacks requested"; if (callbacks & ~ALL_CALLBACKS) throw Exception{1} << "Milter::initialize(): illegal callback(s) requested: " << hex << (callbacks & ~ALL_CALLBACKS) << dec; struct smfiDesc descr = {const_cast(name.c_str()), SMFI_VERSION, flags, 0}; s_name = name; s_mp = &milter; s_callClose = callbacks & CLOSE; // Milter has its own close // function callbacks |= CLOSE; // always call mClose() for (size_t callback = 1; callback & ALL_CALLBACKS; callback <<= 1) { switch (callback & callbacks) { case CONNECT: descr.xxfi_connect = &mConnect; break; case HELO: descr.xxfi_helo = &mHelo; break; case SENDER: descr.xxfi_envfrom = &mSender; break; case RECIPIENT: descr.xxfi_envrcpt = &mRecipient; break; case HEADER: descr.xxfi_header = &mHeader; break; case EOH: descr.xxfi_eoh = &mEoh; break; case BODY: descr.xxfi_body = &mBody; break; case EOM: descr.xxfi_eom = &mEom; break; case ABORT: descr.xxfi_abort = &mAbort; break; case CLOSE: descr.xxfi_close = &mClose; break; #if SMFI_VERSION > 2 case UNKNOWN: descr.xxfi_unknown = &mUnknown; break; #endif /* SMFI_VERSION > 2 */ #if SMFI_VERSION > 3 case DATA: descr.xxfi_data = &mData; break; #endif /* SMFI_VERSION > 3 */ } } if (smfi_register(descr) == MI_FAILURE) throw Exception{} << "Milter::initialize(): defining Milter " << s_name << " failed"; } bobcat-5.09.01/milter/milter.ih0000644000175000017500000000014114050437223015212 0ustar frankfrank#include "milter" #include "../exception/exception" using namespace std; using namespace FBB; bobcat-5.09.01/milter/connect.cc0000644000175000017500000000015614050437223015342 0ustar frankfrank#include "milter.ih" sfsistat Milter::connect(char *hostname, _SOCK_ADDR *hostaddr) { return CONTINUE; } bobcat-5.09.01/milter/datamember.cc0000644000175000017500000000014514050437223016010 0ustar frankfrank#include "milter.ih" #if SMFI_VERSION > 3 sfsistat Milter::data() { return CONTINUE; } #endif bobcat-5.09.01/mstream/0000755000175000017500000000000014050437223013554 5ustar frankfrankbobcat-5.09.01/mstream/noid.cc0000644000175000017500000000065614050437223015023 0ustar frankfrank#include "mstream.ih" namespace FBB { std::ostream &noid(std::ostream &os) { os.flush(); if (Mstream *mp = dynamic_cast(&os)) { if (mp->throws()) throw Exception(); if (mp->lineExcess()) throw Exception{} << "Exceeding max. # of " << mp->maxCount() << " messages"; } return os; } } // FBB bobcat-5.09.01/mstream/reset3.f0000644000175000017500000000014714050437223015132 0ustar frankfrankinline void Mstream::reset(std::streambuf *buf) { Mbuf::reset(buf, maxCount(), tag(), throws()); } bobcat-5.09.01/mstream/mstream3.f0000644000175000017500000000030714050437223015456 0ustar frankfrankinline Mstream::Mstream(std::streambuf *buf, size_t maxCount, std::string const &tag, bool throwing) : Mbuf(buf, maxCount, tag, throwing), std::ostream(this) {} bobcat-5.09.01/mstream/reset6.f0000644000175000017500000000026614050437223015137 0ustar frankfrankinline void Mstream::reset(std::streambuf *buf, size_t maxCount, std::string const &tag, bool throwing) { Mbuf::reset(buf, maxCount, tag, throwing); } bobcat-5.09.01/mstream/fmsg.cc0000644000175000017500000000017214050437223015017 0ustar frankfrank#include "mstream.ih" namespace FBB { Mstream fmsg(std::cout, numeric_limits::max(), "Fatal", true); } bobcat-5.09.01/mstream/off.f0000644000175000017500000000007714050437223014501 0ustar frankfrankinline void Mstream::off() { setstate(std::ios::badbit); } bobcat-5.09.01/mstream/reset4.f0000644000175000017500000000027614050437223015136 0ustar frankfrankinline void Mstream::reset(std::ostream &ostr, size_t maxCount, std::string const &tag, bool throwing) { Mbuf::reset(ostr.rdbuf(), maxCount, tag, throwing); } bobcat-5.09.01/mstream/reset.cc0000644000175000017500000000034014050437223015202 0ustar frankfrank#include "mstream.ih" void Mstream::reset(Mstream const &mstr) { if (Mbuf *mb = dynamic_cast(mstr.rdbuf())) Mbuf::reset(*mb); else throw Exception{1} << "Can't reset Mstream without Mbuf"; } bobcat-5.09.01/mstream/mstream4.f0000644000175000017500000000031414050437223015455 0ustar frankfrankinline Mstream::Mstream(std::string const &name, size_t maxCount, std::string const &tag, bool throwing) : Mbuf(name, maxCount, tag, throwing), std::ostream(this) {} bobcat-5.09.01/mstream/setactive.cc0000644000175000017500000000021714050437223016052 0ustar frankfrank#include "mstream.ih" bool Mstream::setActive(bool ifTrue) { if (ifTrue) on(); else off(); return ifTrue; } bobcat-5.09.01/mstream/isactive.f0000644000175000017500000000007514050437223015534 0ustar frankfrankinline bool Mstream::isActive() const { return good(); } bobcat-5.09.01/mstream/mstream0000644000175000017500000001134714050437223015155 0ustar frankfrank#ifndef INCLUDED_BOBCAT_MSTREAM_ #define INCLUDED_BOBCAT_MSTREAM_ #include #include #include #include #include namespace FBB { std::ostream &endl(std::ostream &os); std::ostream &flush(std::ostream &os); std::ostream &noid(std::ostream &os); std::ostream &noidl(std::ostream &os); // http://www.drdobbs.com/184401357: // A slightly more serious concern is that the virtual functions in a // class that's derived from streambuf might throw exceptions; // perhaps, for example, a user-defined class for network I/O might // throw an exception when the underlying connection has been // lost. High-level istream and ostream functions will catch those // exceptions and translate them into an error state within the // stream (that's one of the reasons that seemingly innocent // functions like istream::get are so complicated), but if you're // working with stream buffers directly there's nobody to catch // exceptions for you. If you work with stream buffers, you should // make sure that your code is exception safe. class Mstream: private Mbuf, public std::ostream { public: Mstream(); // 1.f initializes to cout explicit Mstream(std::ostream &ostr, // 2.f writes to ostr size_t maxCount = UINT_MAX, std::string const &tag = "", bool throwing = false); explicit Mstream(std::streambuf *buf, // 3.f writes to buf size_t maxCount = UINT_MAX, std::string const &tag = "", bool throwing = false); // uses a named ofstream, explicit Mstream(std::string const &name, // 4.f size_t maxCount = UINT_MAX, std::string const &tag = "", bool throwing = false); static void echo(bool trueIsOn, int fd = STDIN_FILENO); // rdbuf members are still available but will turn a Mstream into // the kind of stream the streambuf handles. Except for one if the // reset members below Mstream assumes an Mbuf long id() const; // .f void reset(std::ostream &ostr); // 1.f void reset(std::string const &name); // 2.f void reset(std::streambuf *mbuf); // 3.f void reset(Mstream const &mstream); void reset(std::ostream &ostr, size_t maxCount, // 4.f std::string const &tag, bool throwing); void reset(std::string const &name, size_t maxCount, // 5.f std::string const &tag, bool throwing); // opens the ofstream // and uses that stream for // Mstream's output void reset(std::streambuf *mbuf, size_t maxCount, // 6.f std::string const &tag, bool throwing); void on(); // .f void off(); // .f bool isActive() const; // .f bool setActive(bool ifTrue); using Mbuf::count; // size_t count() const; using Mbuf::lineExcess; // bool lineExcess() const; using Mbuf::lineTag; // string const &lineTag() const; using Mbuf::maxCount; // size_t maxCount() const; using Mbuf::setCount; // void setCount(size_t count); using Mbuf::setLineNr; // void setLineNr(size_t lineNr); using Mbuf::setLineTag; // void setLineTag(string const &lineTag); using Mbuf::setMaxCount; // void setMaxCount(size_t maxCount); using Mbuf::setTag; // void setTag(string const &tag); using Mbuf::tag; // string const &tag() const; using Mbuf::noLineNr; // void noLineNr(); using Mbuf::throws; // bool throws() const; using Mbuf::throwing; // bool throwing(bool ifTrue); }; #include "mstream1.f" #include "mstream2.f" #include "mstream3.f" #include "mstream4.f" #include "id.f" #include "isactive.f" #include "off.f" #include "on.f" #include "reset1.f" #include "reset2.f" #include "reset3.f" #include "reset4.f" #include "reset5.f" #include "reset6.f" extern Mstream emsg; extern Mstream fmsg; extern Mstream imsg; extern Mstream wmsg; } // FBB #endif bobcat-5.09.01/mstream/mstream2.f0000644000175000017500000000031714050437223015456 0ustar frankfrankinline Mstream::Mstream(std::ostream &ostr, size_t maxCount, std::string const &tag, bool throwing) : Mbuf(ostr.rdbuf(), maxCount, tag, throwing), std::ostream(this) {} bobcat-5.09.01/mstream/noidl.cc0000644000175000017500000000020014050437223015160 0ustar frankfrank#include "mstream.ih" namespace FBB { std::ostream &noidl(std::ostream &os) { return FBB::noid(os.put('\n')); } } // FBB bobcat-5.09.01/mstream/flush.cc0000644000175000017500000000074014050437223015205 0ustar frankfrank#include "mstream.ih" namespace FBB { std::ostream &flush(std::ostream &os) { os.flush(); if (Mstream *mp = dynamic_cast(&os)) { if (mp->throws()) throw Exception{} << ' ' << mp->id() << ' '; if (mp->lineExcess()) throw Exception{} << ' ' << mp->id() << " Exceeding max. # of " << mp->maxCount() << " messages"; } return os; } } // FBB bobcat-5.09.01/mstream/on.f0000644000175000017500000000005314050437223014335 0ustar frankfrankinline void Mstream::on() { clear(); } bobcat-5.09.01/mstream/mstream.ih0000644000175000017500000000021014050437223015537 0ustar frankfrank#include "mstream" #include #include #include "../exception/exception" using namespace std; using namespace FBB; bobcat-5.09.01/mstream/imsg.cc0000644000175000017500000000014514050437223015022 0ustar frankfrank#include "mstream.ih" namespace FBB { Mstream imsg(std::cout, numeric_limits::max()); } bobcat-5.09.01/mstream/mstream1.f0000644000175000017500000000006614050437223015456 0ustar frankfrankinline Mstream::Mstream() : std::ostream(this) {} bobcat-5.09.01/mstream/wmsg.cc0000644000175000017500000000016614050437223015043 0ustar frankfrank#include "mstream.ih" namespace FBB { Mstream wmsg(std::cout, numeric_limits::max(), "Warning"); } bobcat-5.09.01/mstream/endl.cc0000644000175000017500000000020014050437223014775 0ustar frankfrank#include "mstream.ih" namespace FBB { std::ostream &endl(std::ostream &os) { return FBB::flush(os.put('\n')); } } // FBB bobcat-5.09.01/mstream/emsg.cc0000644000175000017500000000016414050437223015017 0ustar frankfrank#include "mstream.ih" namespace FBB { Mstream emsg(std::cout, numeric_limits::max() - 1, "Error"); } bobcat-5.09.01/mstream/reset5.f0000644000175000017500000000027314050437223015134 0ustar frankfrankinline void Mstream::reset(std::string const &name, size_t maxCount, std::string const &tag, bool throwing) { Mbuf::reset(name, maxCount, tag, throwing); } bobcat-5.09.01/mstream/reset1.f0000644000175000017500000000015714050437223015131 0ustar frankfrankinline void Mstream::reset(std::ostream &ostr) { Mbuf::reset(ostr.rdbuf(), maxCount(), tag(), throws()); } bobcat-5.09.01/mstream/id.f0000644000175000017500000000011514050437223014314 0ustar frankfrankinline long Mstream::id() const { return reinterpret_cast(this); } bobcat-5.09.01/mstream/driver/0000755000175000017500000000000014050437223015047 5ustar frankfrankbobcat-5.09.01/mstream/driver/build0000755000175000017500000000026114050437223016073 0ustar frankfrank#!/bin/bash CMD="g++ `cat ../../c++std` -o driver -Wall -I../../tmp driver.cc -L../../tmp/lib \ -lbobcat -s" echo $CMD $CMD bobcat-5.09.01/mstream/driver/driver.cc0000644000175000017500000000357614050437223016664 0ustar frankfrank#include #include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) try { cout << sizeof(Mstream) << ' ' << sizeof(Mbuf) << '\n'; imsg << "Informational: " << endl; imsg.off(); cout << "The i-msg stream is now off. This message should appear once" << endl; imsg << "The i-msg stream is now off. This message should appear once" << endl; imsg << "The i-msg stream is now off. This message should appear once" << endl; cout << "But this message is shown" << endl; wmsg << "Warning message" << endl; emsg << "Oops, this this is an error (not really)" << endl; emsg << "Oops, this goes wrong, too" << noid; imsg.on(); imsg << "And another informational msg: " << emsg.count() << " error messages\n" << flush; emsg << "Third error" << endl; emsg.setMaxCount(3); imsg << "Msg in between" << endl; imsg.setTag("tag"); imsg << "tagged message" << endl; imsg.setTag("label"); imsg << "labeled message" << endl; cerr << "(cerr) LineExcess: " << emsg.lineExcess() << ", count = " << emsg.count() << endl; emsg << "Fourth error\n" << noid; // no id is shown emsg << "Fourth error\n" << flush; // shows id (remove the previous // statement) cerr << "(cerr) LineExcess: " << emsg.lineExcess() << ", count = " << emsg.count() << endl; cerr << "Beyond\n"; } catch(exception const &e) { std::cerr << "Got a std::exception: " << e.what() << '\n'; } catch(...) { std::cerr << "Got an exception\n"; } bobcat-5.09.01/mstream/reset2.f0000644000175000017500000000015414050437223015127 0ustar frankfrankinline void Mstream::reset(std::string const &name) { Mbuf::reset(name, maxCount(), tag(), throws()); } bobcat-5.09.01/multibuf/0000755000175000017500000000000014050437223013733 5ustar frankfrankbobcat-5.09.01/multibuf/stream1.f0000644000175000017500000000014214050437223015453 0ustar frankfrankinline MultiBuf::stream::stream(std::ostream &os, Mode mode) : d_os(&os), d_mode(mode) {} bobcat-5.09.01/multibuf/xsputn.cc0000644000175000017500000000022214050437223015577 0ustar frankfrank#include "multibuf.ih" std::streamsize MultiBuf::xsputn(char const *buffer, std::streamsize n) { d_buffer.append(buffer, n); return n; } bobcat-5.09.01/multibuf/multibuf1.f0000644000175000017500000000012114050437223016004 0ustar frankfrankinline MultiBuf::MultiBuf(std::ostream &os, Mode mode) { insert(os, mode); } bobcat-5.09.01/multibuf/overflow.cc0000644000175000017500000000021514050437223016103 0ustar frankfrank#include "multibuf.ih" int MultiBuf::overflow(int c) { if (c == EOF) sync(); else d_buffer += c; return c; } bobcat-5.09.01/multibuf/multibuf2.f0000644000175000017500000000013114050437223016006 0ustar frankfrankinline MultiBuf::MultiBuf(std::vector const &osvector) { insert(osvector); } bobcat-5.09.01/multibuf/mode.f0000644000175000017500000000011414050437223015022 0ustar frankfrankinline MultiBuf::Mode MultiBuf::stream::mode() const { return d_mode; } bobcat-5.09.01/multibuf/insert2.f0000644000175000017500000000016314050437223015470 0ustar frankfrankinline void MultiBuf::insert(std::vector const &os) { d_os.insert(d_os.end(), os.begin(), os.end()); } bobcat-5.09.01/multibuf/begin1.f0000644000175000017500000000011114050437223015240 0ustar frankfrankinline MultiBuf::iterator MultiBuf::begin() { return d_os.begin(); } bobcat-5.09.01/multibuf/end1.f0000644000175000017500000000010514050437223014725 0ustar frankfrankinline MultiBuf::iterator MultiBuf::end() { return d_os.end(); } bobcat-5.09.01/multibuf/multibuf.ih0000644000175000017500000000027414050437223016107 0ustar frankfrank#include "multibuf" #include #include "../exception/exception" using namespace std; using namespace FBB; struct MultiBuf::Insert { std::string &buffer; bool ok; }; bobcat-5.09.01/multibuf/setonce.f0000644000175000017500000000015414050437223015542 0ustar frankfrankinline void MultiBuf::stream::setOnce(stream &os) { if (os.d_mode == RESET) os.d_mode = ONCE; } bobcat-5.09.01/multibuf/size.f0000644000175000017500000000010114050437223015044 0ustar frankfrankinline size_t MultiBuf::size() const { return d_os.size(); } bobcat-5.09.01/multibuf/insert1.f0000644000175000017500000000014414050437223015466 0ustar frankfrankinline void MultiBuf::insert(std::ostream &os, Mode mode) { d_os.push_back(stream(os, mode)); } bobcat-5.09.01/multibuf/sync.cc0000644000175000017500000000037314050437223015221 0ustar frankfrank#include "multibuf.ih" int MultiBuf::sync() { if (!d_buffer.length()) return 0; Insert istruct = {d_buffer, true}; for (auto &os: d_os) insertStruct(os, istruct); d_buffer.erase(); return istruct.ok ? 0 : 1; } bobcat-5.09.01/multibuf/insertstruct.cc0000644000175000017500000000066314050437223017020 0ustar frankfrank#include "multibuf.ih" void MultiBuf::insertStruct(stream &os, Insert &insert) { switch (os.d_mode) { case ONCE: os.d_mode = RESET; [[fallthrough]]; case ON: os.d_os->write(insert.buffer.data(), insert.buffer.size()).flush(); insert.ok = insert.ok && os.d_os; break; default: break; } } bobcat-5.09.01/multibuf/setmode.f0000644000175000017500000000011014050437223015532 0ustar frankfrankinline void MultiBuf::stream::setMode(Mode mode) { d_mode = mode; } bobcat-5.09.01/multibuf/multibuf0000644000175000017500000000543014050437223015507 0ustar frankfrank#ifndef INCLUDED_BOBCAT_MULTIBUF_ #define INCLUDED_BOBCAT_MULTIBUF_ #include #include #include #include #include namespace FBB { struct MultiBuf: public std::streambuf { enum Mode { OFF, // stream not used ON, // stream always used ONCE, // stream used until flushed RESET, // stream once used. Set to ONCE to re-use ALL, // with remove: remove all ostreams matching os }; class stream // holds a pointer to a stream and a indicator { // telling us whether or not to use the stream friend MultiBuf; std::ostream *d_os; Mode d_mode; public: stream(std::ostream &os, Mode mode = ON); // 1.f void setMode(Mode mode); // .f Mode mode() const; // .f std::ostream &ostream(); // .f private: static void setOnce(stream &os); // .f }; typedef std::vector::iterator iterator; typedef std::vector::const_iterator const_iterator; private: std::string d_buffer; std::vector d_os; public: MultiBuf() = default; explicit MultiBuf(std::ostream &os, Mode mode = ON); // 1.f explicit MultiBuf(std::vector const &osvector); // 2.f void insert(std::ostream &os, Mode mode = ON); // 1.f void insert(std::vector const &os); // 2.f bool remove(std::ostream &os, Mode mode = ONCE); iterator begin(); // 1.f iterator end(); // 1.f const_iterator begin() const; // 2.f const_iterator end() const; // 2.f size_t size() const; // .f void setOnce(); // reset all `RESET' modes to `ONCE' private: int overflow(int c) override; std::streamsize xsputn(char const *buffer, std::streamsize n) override; int sync() override; struct Insert; static void insertStruct(stream &os, Insert &insert); }; #include "mode.f" #include "ostream.f" #include "setmode.f" #include "setonce.f" #include "stream1.f" #include "multibuf1.f" #include "multibuf2.f" #include "begin1.f" #include "begin2.f" #include "end1.f" #include "end2.f" #include "insert1.f" #include "insert2.f" } // namespace FBB #endif bobcat-5.09.01/multibuf/ostream.f0000644000175000017500000000010714050437223015552 0ustar frankfrankinline std::ostream &MultiBuf::stream::ostream() { return *d_os; } bobcat-5.09.01/multibuf/setonce.cc0000644000175000017500000000015414050437223015702 0ustar frankfrank#include "multibuf.ih" void MultiBuf::setOnce() { for (auto &os: d_os) stream::setOnce(os); } bobcat-5.09.01/multibuf/remove.cc0000644000175000017500000000117714050437223015545 0ustar frankfrank#include "multibuf.ih" bool MultiBuf::remove(ostream &os, Mode mode) { bool ret = false; while (true) { auto iter = find_if(d_os.begin(), d_os.end(), [&](stream &entry) { return &entry.ostream() == &os; } ); if (iter == d_os.end()) return ret; switch (mode) { case ALL: case ONCE: ret = true; d_os.erase(iter); if (mode == ONCE) return ret; break; default: return false; } } } bobcat-5.09.01/multibuf/end2.f0000644000175000017500000000012114050437223014724 0ustar frankfrankinline MultiBuf::const_iterator MultiBuf::end() const { return d_os.end(); } bobcat-5.09.01/multibuf/begin2.f0000644000175000017500000000012514050437223015246 0ustar frankfrankinline MultiBuf::const_iterator MultiBuf::begin() const { return d_os.begin(); } bobcat-5.09.01/multibuf/driver/0000755000175000017500000000000014050437223015226 5ustar frankfrankbobcat-5.09.01/multibuf/driver/build0000755000175000017500000000026114050437223016252 0ustar frankfrank#!/bin/bash CMD="g++ `cat ../../c++std` -o driver -Wall -I../../tmp driver.cc -L../../tmp/lib \ -lbobcat -s" echo $CMD $CMD bobcat-5.09.01/multibuf/driver/driver.cc0000644000175000017500000000100214050437223017021 0ustar frankfrank/* driver.cc */ #include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) { MultiBuf msb(cout); ostream os(&msb); ofstream out("out"); msb.insert(out, MultiBuf::ONCE); os << "This is on cout and out" << endl; os << "This is on cout only" << endl; msb.setOnce(); os << "This is on cout and out" << endl; os << "This is on cout only" << endl; } bobcat-5.09.01/ofdbuf/0000755000175000017500000000000014050437223013351 5ustar frankfrankbobcat-5.09.01/ofdbuf/xsputn.cc0000644000175000017500000000101214050437223015213 0ustar frankfrank#include "ofdbuf.ih" // override streamsize OFdBuf::xsputn(char const *buffer, streamsize nChars) { streamsize pending = nChars; while (pending > 0) { streamsize available = epptr() - pptr(); if (available == 0) { sync(); continue; } streamsize write = available < pending ? available : pending; memcpy(pptr(), buffer, write); pbump(write); pending -= write; buffer += write; } return nChars; } bobcat-5.09.01/ofdbuf/overflow.cc0000644000175000017500000000030314050437223015517 0ustar frankfrank#include "ofdbuf.ih" int OFdBuf::overflow(int ch) { sync(); if (ch != EOF) { *pptr() = ch; pbump(1); } return ch; } bobcat-5.09.01/ofdbuf/reset.cc0000644000175000017500000000023714050437223015004 0ustar frankfrank#include "ofdbuf.ih" void OFdBuf::reset(int fd, Mode mode, size_t size) { cleanup(mode); d_fd = fd; resize(size == 0 ? 1 : size); setp(); } bobcat-5.09.01/ofdbuf/ofdbuf3.cc0000644000175000017500000000022014050437223015202 0ustar frankfrank#include "ofdbuf.ih" #include OFdBuf::OFdBuf(int fd, size_t bufSize) : d_mode(CLOSE_FD) { reset(fd, CLOSE_FD, bufSize); } bobcat-5.09.01/ofdbuf/ofdbuf2.cc0000644000175000017500000000010714050437223015205 0ustar frankfrank#include "ofdbuf.ih" OFdBuf::OFdBuf(Mode mode) : d_mode(mode) {} bobcat-5.09.01/ofdbuf/ofdbuf.ih0000644000175000017500000000023614050437223015141 0ustar frankfrank#include "ofdbuf" #include #include #include #include "../exception/exception" using namespace FBB; using namespace std; bobcat-5.09.01/ofdbuf/eoi.f0000644000175000017500000000005214050437223014271 0ustar frankfrankinline void OFdBuf::eoi() { eoi_(); } bobcat-5.09.01/ofdbuf/ofdbuf0000644000175000017500000000354214050437223014545 0ustar frankfrank#ifndef INCLUDED_BOBCAT_OFDBUF_ #define INCLUDED_BOBCAT_OFDBUF_ #include namespace FBB { class OFdBuf: public EoiBuf { public: // Mode defines what to do with the file descriptor at // destruction-time or when the default open is // called. CLOSE_FD will close the fd, KEEP_FD will leave the // fd as-is. When open is called with a Mode argument, then // the provided argument is used for the actual fd. The Mode // specified at the constructor is therefore only used for the // mode-less open() call and for the destructor. enum Mode { CLOSE_FD, KEEP_FD, }; private: Mode d_mode; int d_fd = -1; public: OFdBuf(); // 1.cc OFdBuf(OFdBuf const &other) = delete; explicit OFdBuf(Mode mode); // 2.cc explicit OFdBuf(int fd, size_t bufSize = 1); // 3.cc OFdBuf(int fd, Mode mode, size_t bufSize = 1); // 4.cc ~OFdBuf() override; OFdBuf &operator=(OFdBuf const &other) = delete; void reset(int fd, Mode mode, size_t bufSize = 1); // .cc void reset(int fd, size_t bufSize = 1); // .f int fd() const; // .f void eoi(); // .f private: int sync() override; int overflow(int c) override; void eoi_() override; // .cc std::streamsize xsputn(char const *buffer, std::streamsize n) override; void cleanup(Mode mode); }; #include "eoi.f" #include "fd.f" #include "reset.f" } // FBB #endif bobcat-5.09.01/ofdbuf/sync.cc0000644000175000017500000000077514050437223014645 0ustar frankfrank#include "ofdbuf.ih" int OFdBuf::sync() { if (pptr() > pbase()) // if there are chars in the buffer { // then write them to the device if (write(d_fd, ucharPtr(), pptr() - pbase()) < 0) std::cerr << "[Warning] OFdBuf::sync could not " "write to FD " << d_fd << '\n'; setp(); // and reset the stream pointers } return 0; // return OK. } bobcat-5.09.01/ofdbuf/destructor.cc0000644000175000017500000000010214050437223016047 0ustar frankfrank#include "ofdbuf.ih" OFdBuf::~OFdBuf() { cleanup(d_mode); } bobcat-5.09.01/ofdbuf/ofdbuf4.cc0000644000175000017500000000017414050437223015213 0ustar frankfrank#include "ofdbuf.ih" OFdBuf::OFdBuf(int fd, Mode mode, size_t size) : d_mode(mode) { reset(fd, CLOSE_FD, size); } bobcat-5.09.01/ofdbuf/eoi.cc0000644000175000017500000000010514050437223014430 0ustar frankfrank#include "ofdbuf.ih" void OFdBuf::eoi_() { cleanup(CLOSE_FD); } bobcat-5.09.01/ofdbuf/fd.f0000644000175000017500000000006314050437223014110 0ustar frankfrankinline int OFdBuf::fd() const { return d_fd; } bobcat-5.09.01/ofdbuf/cleanup.cc0000644000175000017500000000026214050437223015307 0ustar frankfrank#include "ofdbuf.ih" void OFdBuf::cleanup(Mode mode) { if (d_fd == -1) return; sync(); if (d_mode == CLOSE_FD) close(d_fd); d_fd = -1; } bobcat-5.09.01/ofdbuf/ofdbuf1.cc0000644000175000017500000000014714050437223015210 0ustar frankfrank#include "ofdbuf.ih" OFdBuf::OFdBuf() : d_mode(CLOSE_FD) // comply with old default {} bobcat-5.09.01/ofdbuf/reset.f0000644000175000017500000000012614050437223014641 0ustar frankfrankinline void OFdBuf::reset(int fd, size_t bufSize) { reset(fd, d_mode, bufSize); } bobcat-5.09.01/ofdbuf/driver/0000755000175000017500000000000014050437223014644 5ustar frankfrankbobcat-5.09.01/ofdbuf/driver/build0000755000175000017500000000067114050437223015675 0ustar frankfrank#!/bin/sh # ln -s .. bobcat # # g++ -I. --std=c++2a -O2 -Wall -o driver driver.cc -lssl -lbobcat \ # -L../../ohexbuf/tmp -L../tmp -lhmacbuf -lohexbuf # tput clear LIBS=" -lbobcat -lcrypto" GPP="g++ --std=c++2a" # Using tmp libraries and bobcat CMD="$GPP -o driver -Wall -I../tmp driver.cc \ -L../tmp -lofdbuf \ -L../../eoibuf/tmp -leoibuf \ -L../../eoi/tmp -leoi \ ${LIBS} -s" echo ${CMD} ${CMD} # rm bobcat bobcat-5.09.01/ofdbuf/driver/driver.cc0000644000175000017500000000105014050437223016442 0ustar frankfrank#include #include #include #include "../ofdbuf" using namespace std; using namespace FBB; int main(int argc, char **argv) { // define a streambuf of 20 or argv[1] characters OFdBuf buf{ STDOUT_FILENO, argc == 1 ? 20 : stoul(argv[1]) }; ostream out{ &buf }; out << "First line, just to start the insertions\n" << argv[0] << endl << // using an explicit flush argc << "\n" "a long line to end this multiple-insertions statement\n"; } bobcat-5.09.01/ofdstream/0000755000175000017500000000000014050437223014070 5ustar frankfrankbobcat-5.09.01/ofdstream/ofdstream0000644000175000017500000000045414050437223016002 0ustar frankfrank#ifndef INCLUDED_BOBCAT_OFDSTREAM_ #define INCLUDED_BOBCAT_OFDSTREAM_ #include #include namespace FBB { class OFdStream: private OFdBuf, public std::ostream { public: explicit OFdStream(int fd, size_t n = 1); }; #include "ofdstream1.f" } // FBB #endif bobcat-5.09.01/ofdstream/ofdstream1.f0000644000175000017500000000013514050437223016303 0ustar frankfrankinline OFdStream::OFdStream(int fd, size_t n) : OFdBuf(fd, n), std::ostream(this) {} bobcat-5.09.01/ofilterbuf/0000755000175000017500000000000014050437223014245 5ustar frankfrankbobcat-5.09.01/ofilterbuf/reset1.cc0000644000175000017500000000027214050437223015760 0ustar frankfrank#include "ofilterbuf.ih" void OFilterBuf::reset(std::string const &fname, openmode mode) { d_out->flush(); d_dest.close(); d_dest.open(fname, mode); d_out = &d_dest; } bobcat-5.09.01/ofilterbuf/ofilterbuf3.f0000644000175000017500000000010614050437223016635 0ustar frankfrankinline OFilterBuf::OFilterBuf(std::ostream &out) : d_out(&out) {} bobcat-5.09.01/ofilterbuf/ofilterbuf0000644000175000017500000000152514050437223016334 0ustar frankfrank#ifndef _INCLUDED_OFILTERBUF_ #define _INCLUDED_OFILTERBUF_ #include #include namespace FBB { class OFilterBuf: public Eoi { typedef std::ios::openmode openmode; std::ofstream d_dest; std::ostream *d_out; protected: OFilterBuf(); // 1.f OFilterBuf(std::string const &fname, // 2.cc openmode mode = std::ios::out); OFilterBuf(std::ostream &out); // 3.f void reset(std::string const &fname, // 1.cc openmode mode = std::ios::out); void reset(std::ostream &out); // 2.cc std::ostream &out() const; // .f }; #include "ofilterbuf1.f" #include "ofilterbuf3.f" #include "out.f" } // FBB #endif bobcat-5.09.01/ofilterbuf/reset2.cc0000644000175000017500000000020214050437223015752 0ustar frankfrank#include "ofilterbuf.ih" void OFilterBuf::reset(std::ostream &out) { d_out->flush(); d_dest.close(); d_out = &out; } bobcat-5.09.01/ofilterbuf/ofilterbuf2.cc0000644000175000017500000000021314050437223016773 0ustar frankfrank#include "ofilterbuf.ih" OFilterBuf::OFilterBuf(std::string const &fname, openmode mode) : d_dest(fname, mode), d_out(&d_dest) {} bobcat-5.09.01/ofilterbuf/out.f0000644000175000017500000000010414050437223015216 0ustar frankfrankinline std::ostream &OFilterBuf::out() const { return *d_out; } bobcat-5.09.01/ofilterbuf/ofilterbuf1.f0000644000175000017500000000007014050437223016633 0ustar frankfrankinline OFilterBuf::OFilterBuf() : d_out(&d_dest) {} bobcat-5.09.01/ofilterbuf/ofilterbuf.ih0000644000175000017500000000010114050437223016720 0ustar frankfrank#include "ofilterbuf" using namespace std; using namespace FBB; bobcat-5.09.01/ofoldbuf/0000755000175000017500000000000014050437223013704 5ustar frankfrankbobcat-5.09.01/ofoldbuf/iniblankstabs.cc0000644000175000017500000000022214050437223017033 0ustar frankfrank#include "ofoldbuf.ih" void OFoldBuf::iniBlankTabs(TabsOrBlanks tob) { if (tob == BLANKS) useBlanks(); else useTabs(); } bobcat-5.09.01/ofoldbuf/modify1.f0000644000175000017500000000022414050437223015421 0ustar frankfrankinline std::ostream &lm::modify(std::ostream &out) const { dynamic_cast(*out.rdbuf()).setIndent(d_value); return out; } bobcat-5.09.01/ofoldbuf/overflow.cc0000644000175000017500000000052314050437223016056 0ustar frankfrank#include "ofoldbuf.ih" int OFoldBuf::overflow(int ch) { //cerr << c << ' ' << static_cast(ch) << endl; switch (d_mode) { case INDENT: indent(ch); break; case WS: ws(ch); break; case NON_WS: nonWs(ch); break; } return ch; } bobcat-5.09.01/ofoldbuf/ofoldbuf3.cc0000644000175000017500000000070714050437223016102 0ustar frankfrank#include "ofoldbuf.ih" OFoldBuf::OFoldBuf(ostream &stream, size_t indent, size_t rightMargin, TabsOrBlanks tob, TrailingBlanks tb) : OFilterBuf(stream), d_rightMargin(rightMargin), d_indent(indent), d_reqIndent(false), d_wsLength(0), d_next(0), d_mode(INDENT), d_handleTrailingBlanks(tb == HANDLE_TRAILING_BLANKS) { s2_buffers.push_back(this); iniBlankTabs(tob); } bobcat-5.09.01/ofoldbuf/data.cc0000644000175000017500000000010714050437223015122 0ustar frankfrank#include "ofoldbuf.ih" vector OFoldBuf::s2_buffers; bobcat-5.09.01/ofoldbuf/lm1.f0000644000175000017500000000010114050437223014534 0ustar frankfrankinline lm::lm(int value) : d_value(value < 0 ? 0 : value) {} bobcat-5.09.01/ofoldbuf/addnonws.f0000644000175000017500000000007414050437223015671 0ustar frankfrankinline void OFoldBuf::addNonWs(int c) { d_nonWs += c; } bobcat-5.09.01/ofoldbuf/ofoldbuf2.cc0000644000175000017500000000071014050437223016073 0ustar frankfrank#include "ofoldbuf.ih" OFoldBuf::OFoldBuf(string const &fname, size_t indent, size_t rightMargin, TabsOrBlanks tob, TrailingBlanks tb) : OFilterBuf(fname), d_rightMargin(rightMargin), d_indent(indent), d_reqIndent(false), d_wsLength(0), d_next(0), d_mode(INDENT), d_handleTrailingBlanks(tb == HANDLE_TRAILING_BLANKS) { s2_buffers.push_back(this); iniBlankTabs(tob); } bobcat-5.09.01/ofoldbuf/put.f0000644000175000017500000000007714050437223014667 0ustar frankfrankinline void OFoldBuf::put(int ch) const { out().put(ch); } bobcat-5.09.01/ofoldbuf/findofoldstreambuf.cc0000644000175000017500000000053514050437223020073 0ustar frankfrank#include "ofoldbuf.ih" OFoldBuf::BufIt OFoldBuf::findOFoldBuf(streambuf const *buf) { BufIt it = find(s2_buffers.begin(), s2_buffers.end(), dynamic_cast(buf)); if (it == s2_buffers.end()) throw Exception{1} << "Illegal cast from std::streambuf to FBB::OFoldBuf"; return it; } bobcat-5.09.01/ofoldbuf/ofoldbuf.ih0000644000175000017500000000034014050437223016023 0ustar frankfrank#include "ofoldbuf" #include #include #include "../exception/exception" using namespace std; using namespace FBB; #include "addnonws.f" #include "writews.f" #include "writenonws.f" #include "put.f" bobcat-5.09.01/ofoldbuf/indent.cc0000644000175000017500000000056514050437223015502 0ustar frankfrank#include "ofoldbuf.ih" void OFoldBuf::indent(int c) { if (c == '\n') newline(); else if (isspace(c)) { d_ws.assign(d_indent, d_indentChar); d_wsLength += d_indent * d_indentWidth; addWs(c); d_mode = WS; } else if (c != EOF) { d_reqIndent = true; addNonWs(c); d_mode = NON_WS; } } bobcat-5.09.01/ofoldbuf/writenonws.f0000644000175000017500000000014014050437223016265 0ustar frankfrankinline void OFoldBuf::writeNonWs() const { out().write(d_nonWs.data(), d_nonWs.length()); } bobcat-5.09.01/ofoldbuf/ws.cc0000644000175000017500000000041714050437223014646 0ustar frankfrank#include "ofoldbuf.ih" void OFoldBuf::ws(int c) { if (c == '\n') { newline(); clearWs(); d_mode = INDENT; } else if (isspace(c)) addWs(c); else if (c != EOF) { addNonWs(c); d_mode = NON_WS; } } bobcat-5.09.01/ofoldbuf/mlm1.f0000644000175000017500000000006314050437223014720 0ustar frankfrankinline mlm::mlm(int value) : d_value(value) {} bobcat-5.09.01/ofoldbuf/writews.f0000644000175000017500000000012714050437223015557 0ustar frankfrankinline void OFoldBuf::writeWs() const { out().write(d_ws.data(), d_ws.length()); } bobcat-5.09.01/ofoldbuf/settrailingblanks.f0000644000175000017500000000017414050437223017575 0ustar frankfrankinline void OFoldBuf::setTrailingBlanks(TrailingBlanks tb) { d_handleTrailingBlanks = tb == HANDLE_TRAILING_BLANKS; } bobcat-5.09.01/ofoldbuf/opinsert2.f0000644000175000017500000000014314050437223015776 0ustar frankfrankinline std::ostream &operator<<(std::ostream &out, mlm const &idt) { return idt.modify(out); } bobcat-5.09.01/ofoldbuf/ofoldbuf1.cc0000644000175000017500000000063414050437223016077 0ustar frankfrank#include "ofoldbuf.ih" OFoldBuf::OFoldBuf( size_t indent, size_t rightMargin, TabsOrBlanks tob, TrailingBlanks tb) : d_rightMargin(rightMargin), d_indent(indent), d_reqIndent(false), d_wsLength(0), d_next(0), d_mode(INDENT), d_handleTrailingBlanks(tb == HANDLE_TRAILING_BLANKS) { s2_buffers.push_back(this); iniBlankTabs(tob); } bobcat-5.09.01/ofoldbuf/newline.cc0000644000175000017500000000016014050437223015651 0ustar frankfrank#include "ofoldbuf.ih" void OFoldBuf::newline() { //cerr << "NEWLINE\n"; put('\n'); d_next = 0; } bobcat-5.09.01/ofoldbuf/setmargins.cc0000644000175000017500000000023114050437223016363 0ustar frankfrank#include "ofoldbuf.ih" void OFoldBuf::setMargins(size_t leftMargin, size_t rightMargin) { d_rightMargin = rightMargin; d_indent = leftMargin; } bobcat-5.09.01/ofoldbuf/nonws.cc0000644000175000017500000000043514050437223015361 0ustar frankfrank#include "ofoldbuf.ih" void OFoldBuf::nonWs(int c) { if (c == '\n') { flush(); newline(); d_mode = INDENT; } else if (isspace(c)) { flush(); addWs(c); d_mode = WS; } else if (c != EOF) addNonWs(c); } bobcat-5.09.01/ofoldbuf/ofoldbuf0000644000175000017500000000744214050437223015436 0ustar frankfrank#ifndef INCLUDED_BOBCAT_OFOLDBUF_ #define INCLUDED_BOBCAT_OFOLDBUF_ #include #include #include #include namespace FBB { class lm { size_t d_value; public: lm(int value); // 1.f std::ostream &modify(std::ostream &out) const; // 1.f }; class mlm { int d_value; public: mlm(int value); // 1.f std::ostream &modify(std::ostream &out) const; // 2.f }; struct OFoldBufEnums { enum TrailingBlanks { IGNORE_TRAILING_BLANKS, HANDLE_TRAILING_BLANKS }; enum TabsOrBlanks { BLANKS, TABS }; }; // 'virtual public OFoldBufBlanks is used to avoid 'base class not // accessible' warnings when classes inherit from OFoldBuf like // OFoldStream. class OFoldBuf: virtual public OFoldBufEnums, public OFilterBuf { friend std::ostream &lm::modify(std::ostream &) const; friend std::ostream &mlm::modify(std::ostream &) const; enum Mode { INDENT, WS, NON_WS }; std::string d_nonWs; std::string d_ws; size_t d_rightMargin; size_t d_indent; bool d_reqIndent; size_t d_wsLength; size_t d_next; Mode d_mode; char d_indentChar; size_t d_indentWidth; bool d_handleTrailingBlanks; typedef std::vector::iterator BufIt; static std::vector s2_buffers; public: explicit OFoldBuf( // 1 size_t leftIndent = 0, size_t rightMargin = 80, TabsOrBlanks tob = BLANKS, TrailingBlanks tb = IGNORE_TRAILING_BLANKS); explicit OFoldBuf(std::string const &fname, // 2 size_t leftIndent = 0, size_t rightMargin = 80, TabsOrBlanks tob = BLANKS, TrailingBlanks tb = IGNORE_TRAILING_BLANKS); explicit OFoldBuf(std::ostream &stream, // 3 size_t leftIndent = 0, size_t rightMargin = 80, TabsOrBlanks tob = BLANKS, TrailingBlanks tb = IGNORE_TRAILING_BLANKS); ~OFoldBuf() override; void setMargins(size_t leftMargin, size_t rightMargin); void setTrailingBlanks(TrailingBlanks tb); // .f void useBlanks(); // .f void useTabs(size_t tabWidth = 8); // .f static size_t leftMargin(std::streambuf const *buffer); static size_t rightMargin(std::streambuf const *buffer); private: int sync() override; int overflow(int c) override; void indent(int c); void ws(int c); void nonWs(int c); size_t length() const; void iniBlankTabs(TabsOrBlanks tob); void newline(); void addNonWs(int c); // .f void addWs(int c); void indent(); void flush(); void clearWs(); void modifyIndent(int delta); void setIndent(int value); // .f void writeWs() const; // .f void writeNonWs() const; // .f void put(int ch) const; // .f static BufIt findOFoldBuf(std::streambuf const *buffer); }; #include "lm1.f" #include "modify1.f" #include "mlm1.f" #include "modify2.f" #include "leftmargin.f" #include "rightmargin.f" #include "setindent.f" #include "settrailingblanks.f" #include "useblanks.f" #include "usetabs.f" // Free functions #include "opinsert1.f" // ostream << lm #include "opinsert2.f" // ostream << mlm } // FBB #endif bobcat-5.09.01/ofoldbuf/flush.cc0000644000175000017500000000121514050437223015333 0ustar frankfrank#include "ofoldbuf.ih" void OFoldBuf::flush() { if (d_reqIndent) { d_reqIndent = false; indent(); writeNonWs(); d_next = d_indent + d_nonWs.length(); } else if (length() <= d_rightMargin) { writeWs(); writeNonWs(); d_next += d_wsLength + d_nonWs.length(); } else { newline(); indent(); writeNonWs(); d_next = d_indent + d_nonWs.length(); } // cerr << "FLUSHNONWS " << d_next << ' ' << d_wsLength << ' ' << // d_nonWs.length() << ": " << length() << endl; d_nonWs.erase(); clearWs(); } bobcat-5.09.01/ofoldbuf/clearws.cc0000644000175000017500000000013314050437223015650 0ustar frankfrank#include "ofoldbuf.ih" void OFoldBuf::clearWs() { d_ws.clear(); d_wsLength = 0; } bobcat-5.09.01/ofoldbuf/rightmargin.f0000644000175000017500000000017114050437223016365 0ustar frankfrankinline size_t OFoldBuf::rightMargin(std::streambuf const *buffer) { return (*findOFoldBuf(buffer))->d_rightMargin; } bobcat-5.09.01/ofoldbuf/length.cc0000644000175000017500000000015714050437223015477 0ustar frankfrank#include "ofoldbuf.ih" size_t OFoldBuf::length() const { return d_next + d_wsLength + d_nonWs.length(); } bobcat-5.09.01/ofoldbuf/sync.cc0000644000175000017500000000021114050437223015161 0ustar frankfrank#include "ofoldbuf.ih" int OFoldBuf::sync() { if (d_mode == NON_WS) flush(); out().rdbuf()->pubsync(); return 0; } bobcat-5.09.01/ofoldbuf/destructor.cc0000644000175000017500000000056714050437223016421 0ustar frankfrank#include "ofoldbuf.ih" OFoldBuf::~OFoldBuf() { s2_buffers.erase(findOFoldBuf(this)); if (d_mode == NON_WS) flush(); else if (d_mode == WS) { if (d_handleTrailingBlanks) { if (length() <= d_rightMargin) writeWs(); else put('\n'); } } out().rdbuf()->pubsync(); } bobcat-5.09.01/ofoldbuf/indent2.cc0000644000175000017500000000017414050437223015560 0ustar frankfrank#include "ofoldbuf.ih" void OFoldBuf::indent() { for (size_t nr = 0; nr < d_indent; ++nr) put(d_indentChar); } bobcat-5.09.01/ofoldbuf/opinsert1.f0000644000175000017500000000014214050437223015774 0ustar frankfrankinline std::ostream &operator<<(std::ostream &out, lm const &idt) { return idt.modify(out); } bobcat-5.09.01/ofoldbuf/modifyindent.cc0000644000175000017500000000023114050437223016700 0ustar frankfrank#include "ofoldbuf.ih" void OFoldBuf::modifyIndent(int delta) { d_indent += delta; if (static_cast(d_indent) < 0) d_indent = 0; } bobcat-5.09.01/ofoldbuf/setindent.f0000644000175000017500000000010514050437223016044 0ustar frankfrankinline void OFoldBuf::setIndent(int value) { d_indent = value; } bobcat-5.09.01/ofoldbuf/modify2.f0000644000175000017500000000023014050437223015417 0ustar frankfrankinline std::ostream &mlm::modify(std::ostream &out) const { dynamic_cast(*out.rdbuf()).modifyIndent(d_value); return out; } bobcat-5.09.01/ofoldbuf/useblanks.f0000644000175000017500000000012514050437223016040 0ustar frankfrankinline void OFoldBuf::useBlanks() { d_indentChar = ' '; d_indentWidth = 1; } bobcat-5.09.01/ofoldbuf/leftmargin.f0000644000175000017500000000016314050437223016203 0ustar frankfrankinline size_t OFoldBuf::leftMargin(std::streambuf const *buffer) { return (*findOFoldBuf(buffer))->d_indent; } bobcat-5.09.01/ofoldbuf/addws.cc0000644000175000017500000000034214050437223015314 0ustar frankfrank#include "ofoldbuf.ih" void OFoldBuf::addWs(int c) { if (c != '\t') ++d_wsLength; else { size_t wsLen = d_next + d_wsLength; d_wsLength = ((wsLen + 8) & ~7) - wsLen; } d_ws += c; } bobcat-5.09.01/ofoldbuf/driver/0000755000175000017500000000000014050437223015177 5ustar frankfrankbobcat-5.09.01/ofoldbuf/driver/build0000755000175000017500000000106014050437223016221 0ustar frankfrank#!/bin/bash # (cd ..; icmbuild) || exit 1 # CMD="g++ -o driver -Wall -I../ driver.cc -L../tmp -lofoldbuf \ # -L../../tmp/lib -lbobcat -s" # CMD="g++ -o driver -Wall -I../../tmp driver.cc -L../../tmp/lib -lbobcat -s" # CMD="g++ -o driver -Wall *.cc -lbobcat -s" tput clear GPP="g++ --std=c++2a" # Using tmp libraries and bobcat CMD="$GPP -o driver -Wall -I../../tmp driver.cc \ -L../../ofoldstream/tmp -lofoldstream \ -L../tmp -lofoldbuf \ -L../../ofilterbuf/tmp -lofilterbuf \ -L../../eoi/tmp -leoi \ -lbobcat -s" echo $CMD $CMD bobcat-5.09.01/ofoldbuf/driver/driver.cc0000644000175000017500000000126014050437223017000 0ustar frankfrank#include //#include "../ofoldbuf" // #include "../../ofoldstream/ofoldstream" #include using namespace std; using namespace FBB; int main() { OFoldBuf fb(cout, 4, 40); // OFoldBuf fb("fsb.out", 4, 40); ostream out(&fb); // OFoldStream out("foldstream.nam2", 4, 40, OFoldStream::TABS); // int c; // int linenr = 0; // while ((c = cin.get()) != EOF) // { // if (c == '\n') // { // if (++linenr == 5) // out << indent(+4); // } // out << static_cast(c); // } // out << mlm(-3); string line; while (getline(cin, line)) out << line << '\n'; } bobcat-5.09.01/ofoldbuf/usetabs.f0000644000175000017500000000015214050437223015517 0ustar frankfrankinline void OFoldBuf::useTabs(size_t tabWidth) { d_indentChar = '\t'; d_indentWidth = tabWidth; } bobcat-5.09.01/ofoldstream/0000755000175000017500000000000014050437223014423 5ustar frankfrankbobcat-5.09.01/ofoldstream/reset1.cc0000644000175000017500000000043314050437223016135 0ustar frankfrank#include "ofoldstream.ih" void OFoldStream::reset(string const &fname, size_t leftIndent, size_t rightMargin, TrailingBlanks tb) { OFoldBuf::reset(fname); // = OFilterBuf:: setMargins(leftIndent, rightMargin); setTrailingBlanks(tb); } bobcat-5.09.01/ofoldstream/reset2.cc0000644000175000017500000000041614050437223016137 0ustar frankfrank#include "ofoldstream.ih" void OFoldStream::reset(ostream &out, size_t leftIndent, size_t rightMargin, TrailingBlanks tb) { OFoldBuf::reset(out); // = OFilterBuf setMargins(leftIndent, rightMargin); setTrailingBlanks(tb); } bobcat-5.09.01/ofoldstream/ofoldstream1.f0000644000175000017500000000040314050437223017167 0ustar frankfrankinline OFoldStream::OFoldStream(std::string const &fname, size_t leftIndent, size_t rightMargin, TabsOrBlanks tob, TrailingBlanks tb) : OFoldBuf(fname, leftIndent, rightMargin, tob, tb), std::ostream(this) {} bobcat-5.09.01/ofoldstream/ofoldstream2.f0000644000175000017500000000037214050437223017175 0ustar frankfrankinline OFoldStream::OFoldStream(std::ostream &out, size_t leftIndent, size_t rightMargin, TabsOrBlanks tob, TrailingBlanks tb) : OFoldBuf(out, leftIndent, rightMargin, tob, tb), std::ostream(this) {} bobcat-5.09.01/ofoldstream/settrailingblanks.f0000644000175000017500000000014714050437223020314 0ustar frankfrankinline void OFoldStream::setTrailingBlanks(TrailingBlanks tb) { OFoldBuf::setTrailingBlanks(tb); } bobcat-5.09.01/ofoldstream/setmargins.f0000644000175000017500000000014014050437223016741 0ustar frankfrankinline void OFoldStream::setMargins(size_t lm, size_t rm) { OFoldBuf::setMargins(lm, rm); } bobcat-5.09.01/ofoldstream/ofoldstream0000644000175000017500000000410014050437223016660 0ustar frankfrank#ifndef INCLUDED_BOBCAT_OFOLDSTREAM_ #define INCLUDED_BOBCAT_OFOLDSTREAM_ #include #include #include #include namespace FBB { // 'virtual public OFoldBufBlanks is used to avoid 'base class not // accessible' warnings since OFoldBuf also inherits from // OFoldBufBlanks and only one struct definition is needed in the // final OFoldStream class. class OFoldStream: virtual public OFoldBufEnums, private OFoldBuf, public std::ostream { public: OFoldStream() = default; explicit OFoldStream(std::string const &fname, // 1.f size_t leftIndent = 0, size_t rightMargin = 80, TabsOrBlanks tob = BLANKS, TrailingBlanks tb = IGNORE_TRAILING_BLANKS); explicit OFoldStream(std::ostream &dest, // 2.f size_t leftIndent = 0, size_t rightMargin = 80, TabsOrBlanks tob = BLANKS, TrailingBlanks tb = IGNORE_TRAILING_BLANKS); void reset(std::string const &fname, size_t leftIndent = 0, size_t rightMargin = 80, TrailingBlanks tb = IGNORE_TRAILING_BLANKS); void reset(std::ostream &out, size_t leftIndent = 0, size_t rightMargin = 80, TrailingBlanks tb = IGNORE_TRAILING_BLANKS); void setMargins(size_t leftMargin, size_t rightMargin); // .f void setTrailingBlanks(TrailingBlanks tb); // .f void useBlanks(); // .f void useTabs(size_t tabWidth = 8); // .f static size_t leftMargin(std::ostream const &os); // .f static size_t rightMargin(std::ostream const &os); // .f }; #include "ofoldstream1.f" #include "ofoldstream2.f" #include "leftmargin.f" #include "rightmargin.f" #include "setmargins.f" #include "settrailingblanks.f" #include "useblanks.f" #include "usetabs.f" } // FBB #endif bobcat-5.09.01/ofoldstream/ofoldstream.ih0000644000175000017500000000010314050437223017256 0ustar frankfrank#include "ofoldstream" using namespace std; using namespace FBB; bobcat-5.09.01/ofoldstream/rightmargin.f0000644000175000017500000000016114050437223017103 0ustar frankfrankinline size_t OFoldStream::rightMargin(std::ostream const &os) { return OFoldBuf::rightMargin(os.rdbuf()); } bobcat-5.09.01/ofoldstream/useblanks.f0000644000175000017500000000010414050437223016554 0ustar frankfrankinline void OFoldStream::useBlanks() { OFoldBuf::useBlanks(); } bobcat-5.09.01/ofoldstream/leftmargin.f0000644000175000017500000000015714050437223016725 0ustar frankfrankinline size_t OFoldStream::leftMargin(std::ostream const &os) { return OFoldBuf::leftMargin(os.rdbuf()); } bobcat-5.09.01/ofoldstream/driver/0000755000175000017500000000000014050437223015716 5ustar frankfrankbobcat-5.09.01/ofoldstream/driver/build0000755000175000017500000000007614050437223016746 0ustar frankfrank#!/bin/sh g++ -I../../tmp driver.cc -L../../tmp/lib -lbobcat bobcat-5.09.01/ofoldstream/driver/driver.cc0000644000175000017500000000063514050437223017524 0ustar frankfrank#include #include #include using namespace std; using namespace FBB; void margins(ostream &out) { cout << OFoldStream::leftMargin(out) << ", " << OFoldStream::rightMargin(out) << endl; } int main() { OFoldStream out(cout, 4, 40); out << lm(4); string line; while (getline(cin, line)) out << line << '\n'; margins(out); } bobcat-5.09.01/ofoldstream/usetabs.f0000644000175000017500000000012714050437223016240 0ustar frankfrankinline void OFoldStream::useTabs(size_t tabWidth) { OFoldBuf::useTabs(tabWidth); } bobcat-5.09.01/ohexbuf/0000755000175000017500000000000014050437223013544 5ustar frankfrankbobcat-5.09.01/ohexbuf/separator1.cc0000644000175000017500000000016414050437223016135 0ustar frankfrank#include "ohexbuf.ih" void OHexBuf::separator(bool reset) { d_separated = &OHexBuf::plain; clear(reset); } bobcat-5.09.01/ohexbuf/overflow.cc0000644000175000017500000000022414050437223015714 0ustar frankfrank#include "ohexbuf.ih" // overrides int OHexBuf::overflow(int ch) { (this->*d_separated)(ch); (this->*d_widthHandler)(); return ch; } bobcat-5.09.01/ohexbuf/setwidth.cc0000644000175000017500000000035614050437223015712 0ustar frankfrank#include "ohexbuf.ih" void OHexBuf::setWidth(size_t width) { d_width = width; d_widthHandler = d_width == 0 ? &OHexBuf::noWidth : &OHexBuf::widthHandler; } bobcat-5.09.01/ohexbuf/widthhandler.cc0000644000175000017500000000026614050437223016534 0ustar frankfrank#include "ohexbuf.ih" void OHexBuf::widthHandler() { d_count += 2 + d_separator.length(); if (d_count >= d_width) { d_count = 0; out() << '\n'; } } bobcat-5.09.01/ohexbuf/ohexbuf.ih0000644000175000017500000000016614050437223015531 0ustar frankfrank#include "ohexbuf" #include #include "../exception/exception" using namespace std; using namespace FBB; bobcat-5.09.01/ohexbuf/separated.cc0000644000175000017500000000014614050437223016024 0ustar frankfrank#include "ohexbuf.ih" void OHexBuf::separated(int ch) { out() << setw(2) << ch << d_separator; } bobcat-5.09.01/ohexbuf/nowidth.cc0000644000175000017500000000006214050437223015525 0ustar frankfrank#include "ohexbuf.ih" void OHexBuf::noWidth() {} bobcat-5.09.01/ohexbuf/separator2.cc0000644000175000017500000000024214050437223016133 0ustar frankfrank#include "ohexbuf.ih" void OHexBuf::separator(string const &sep, bool reset) { d_separator = sep; d_separated = &OHexBuf::separated; clear(reset); } bobcat-5.09.01/ohexbuf/ohexbuf0000644000175000017500000000267214050437223015136 0ustar frankfrank#ifndef INCLUDED_BOBCAT_OHEXBUF_ #define INCLUDED_BOBCAT_OHEXBUF_ #include #include #include namespace FBB { class OHexBuf: public OFilterBuf { std::ios::fmtflags d_current; char d_padding; size_t d_width; size_t d_count; std::string d_separator; void (OHexBuf::*d_separated)(int ch); void (OHexBuf::*d_widthHandler)(); public: OHexBuf(std::ostream &out, size_t width = 0, std::string const &separator = ""); ~OHexBuf() override; size_t size() const; // .f void setWidth(size_t width); void separator(bool reset = true); // 1 void separator(std::string const &sep, bool reset = true); // 2 void eoi(); // .f static std::string text2bin(std::string const &in); // length and // contents not // checked private: int overflow(int ch) override; int sync() override; void eoi_() override; void separated(int ch); void plain(int ch); void widthHandler(); void noWidth(); void clear(bool reset); }; #include "size.f" } // FBB #endif bobcat-5.09.01/ohexbuf/text2bin.cc0000644000175000017500000000033214050437223015610 0ustar frankfrank#include "ohexbuf.ih" string OHexBuf::text2bin(string const &in) { string ret; for (size_t idx = 0, end = in.length(); idx != end; idx += 2) ret += stoul(in.substr(idx, 2), 0, 16); return ret; } bobcat-5.09.01/ohexbuf/plain.cc0000644000175000017500000000012314050437223015152 0ustar frankfrank#include "ohexbuf.ih" void OHexBuf::plain(int ch) { out() << setw(2) << ch; } bobcat-5.09.01/ohexbuf/clear.cc0000644000175000017500000000021514050437223015137 0ustar frankfrank#include "ohexbuf.ih" void FBB::OHexBuf::clear(bool reset) { if (reset) { d_separator.clear(); d_count = 0; } } bobcat-5.09.01/ohexbuf/size.f0000644000175000017500000000007414050437223014666 0ustar frankfrankinline size_t OHexBuf::size() const { return d_count; } bobcat-5.09.01/ohexbuf/eoi.f0000644000175000017500000000004614050437223014467 0ustar frankfrankinline OHexBuf::eoi() { eoi_(); } bobcat-5.09.01/ohexbuf/sync.cc0000644000175000017500000000012214050437223015022 0ustar frankfrank#include "ohexbuf.ih" int OHexBuf::sync() { out() << flush; return 0; } bobcat-5.09.01/ohexbuf/destructor.cc0000644000175000017500000000016214050437223016250 0ustar frankfrank#include "ohexbuf.ih" OHexBuf::~OHexBuf() { eoi_(); out().fill(d_padding); out().flags(d_current); } bobcat-5.09.01/ohexbuf/eoi.cc0000644000175000017500000000016314050437223014627 0ustar frankfrank#include "ohexbuf.ih" #include void OHexBuf::eoi_() { sync(); separator(); setWidth(0); } bobcat-5.09.01/ohexbuf/ohexbuf1.cc0000644000175000017500000000066314050437223015601 0ustar frankfrank#include "ohexbuf.ih" OHexBuf::OHexBuf(ostream &out, size_t width, string const &separator) : OFilterBuf(out), d_current(out.flags()), d_padding(out.fill('0')), d_count(0), d_separator(separator), d_separated(separator.empty() ? &OHexBuf::plain : &OHexBuf::separated) { setWidth(width); out << hex; } bobcat-5.09.01/ohexbuf/driver/0000755000175000017500000000000014050437223015037 5ustar frankfrankbobcat-5.09.01/ohexbuf/driver/build0000755000175000017500000000066214050437223016070 0ustar frankfrank#!/bin/bash tput clear LIBS=" -lbobcat" GPP="g++ --std=c++2a" # Using the wip ohexbuf library and bobcat # CMD="$GPP -o driver -Wall *.cc -L../tmp -lohexbuf -lbobcat -s" # Using the wip ohexbuf and ofilterbuf libraries and bobcat CMD="$GPP -o driver -I../../tmp -Wall *.cc -L../tmp -lohexbuf \ -L../../ofilterbuf/tmp -lofilterbuf \ -L../../eoi/tmp -leoi \ -lbobcat -s" echo ${CMD} ${CMD} bobcat-5.09.01/ohexbuf/driver/driver.cc0000644000175000017500000000061214050437223016640 0ustar frankfrank#include #include #include "../ohexbuf" using namespace std; using namespace FBB; int main(int argc, char **argv) try { OHexBuf ohexbuf(cout, 20, " "); ostream out(&ohexbuf); string hw("hello world\n"); out << hw << eoi; cout << '\n'; out << hw; cout << '\n'; } catch(exception const &err) { cout << err.what() << endl; return 1; } bobcat-5.09.01/omutexstream/0000755000175000017500000000000014050437223014641 5ustar frankfrankbobcat-5.09.01/omutexstream/data.cc0000644000175000017500000000011114050437223016052 0ustar frankfrank#include "omutexstream.ih" recursive_mutex OMutexStream::Out::s_mutex; bobcat-5.09.01/omutexstream/out1.cc0000644000175000017500000000021414050437223016035 0ustar frankfrank#include "omutexstream.ih" OMutexStream::Out::Out(OMutexStream const &mstr) : std::ostream(mstr.d_out.rdbuf()) { s_mutex.lock(); } bobcat-5.09.01/omutexstream/omutexstream.ih0000644000175000017500000000020514050437223017715 0ustar frankfrank#include "omutexstream" //#include //#define XERR std::cerr << __FILE__": " using namespace std; using namespace FBB; bobcat-5.09.01/omutexstream/operatorinsert1.f0000644000175000017500000000025714050437223020155 0ustar frankfranktemplate OMutexStream::Out operator<<(OMutexStream const &mstr, Tp &&tp) { OMutexStream::Out out{ mstr }; out << std::forward(tp); return out; } bobcat-5.09.01/omutexstream/omutexstream1.f0000644000175000017500000000011114050437223017617 0ustar frankfrankinline OMutexStream::OMutexStream(std::ostream &out) : d_out(out) {} bobcat-5.09.01/omutexstream/out2.f0000644000175000017500000000011414050437223015675 0ustar frankfrankinline OMutexStream::Out::Out(Out &&tmp) : std::ostream(tmp.rdbuf()) {} bobcat-5.09.01/omutexstream/operatorinsert2.f0000644000175000017500000000026014050437223020150 0ustar frankfranktemplate OMutexStream::Out operator<<(OMutexStream const &mstr, Ret &(*manip)(Ret &os)) { OMutexStream::Out out{ mstr }; out << manip; return out; } bobcat-5.09.01/omutexstream/destructor.cc0000644000175000017500000000012014050437223017337 0ustar frankfrank#include "omutexstream.ih" OMutexStream::Out::~Out() { s_mutex.unlock(); } bobcat-5.09.01/omutexstream/omutexstream0000644000175000017500000000175414050437223017330 0ustar frankfrank#ifndef INCLUDED_BOBCAT_OMUTEXSTREAM_ #define INCLUDED_BOBCAT_OMUTEXSTREAM_ #include #include namespace FBB { class OMutexStream { std::ostream &d_out; public: class Out; explicit OMutexStream(std::ostream &out); Out ostream() const; }; class OMutexStream::Out: public std::ostream { friend Out OMutexStream::ostream() const; template friend Out operator<<(OMutexStream const &mstr, Tp &&tp); // 1.f template friend Out operator<<(OMutexStream const &mstr, // 2.f Ret &(*manip)(Ret &os)); static std::recursive_mutex s_mutex; public: ~Out(); private: Out(OMutexStream const &mstr); // 1.cc Out(Out &&tmp); // 2.f }; #include "omutexstream1.f" #include "ostream.f" #include "out2.f" #include "operatorinsert1.f" #include "operatorinsert2.f" } // FBB #endif bobcat-5.09.01/omutexstream/ostream.f0000644000175000017500000000014214050437223016457 0ustar frankfrankinline OMutexStream::Out OMutexStream::ostream() const { return OMutexStream::Out{ *this }; } bobcat-5.09.01/omutexstream/driver/0000755000175000017500000000000014050437223016134 5ustar frankfrankbobcat-5.09.01/omutexstream/driver/build0000755000175000017500000000035614050437223017165 0ustar frankfrank#!/bin/bash if [ $# -eq 1 ] ; then sed 's??"../omutexstream"?' driver.cc > main.cc else cp driver.cc main.cc fi g++ -pthread --std=c++2a -o driver -Wall -I../ main.cc -L../tmp -lomutexstream -s rm main.cc bobcat-5.09.01/omutexstream/driver/driver.cc0000644000175000017500000000166414050437223017745 0ustar frankfrank#include #include #include #include #include #include #include using namespace std; using namespace FBB; OMutexStream mout(cout); void run(int nr) { for (size_t idx = 0; idx != 3; ++idx) { mout << "hello world 1 from thread " << nr << ": " << log(rand()) << endl; this_thread::sleep_for( chrono::milliseconds(200 + rand() % 800)); mout << "hello world 2 from thread " << nr << ": " << log(rand()) << '\n'; this_thread::sleep_for( chrono::milliseconds(200 + rand() % 800)); } auto out{ mout.ostream() }; cout << nr << ": " << out.tellp() << '\n'; } int main() { srand(time(0)); thread t1(run, 1); thread t2(run, 2); thread t3(run, 3); thread t4(run, 4); t1.join(); t2.join(); t3.join(); t4.join(); } bobcat-5.09.01/onekey/0000755000175000017500000000000014050437223013376 5ustar frankfrankbobcat-5.09.01/onekey/get.cc0000644000175000017500000000031214050437223014460 0ustar frankfrank#include "onekey.ih" int OneKey::get() const { int c = cin.get(); // read the char if (d_useEcho) cout << static_cast(c) << flush; return c; } bobcat-5.09.01/onekey/setecho.f0000644000175000017500000000011314050437223015172 0ustar frankfrankinline void OneKey::setEcho(Mode state) { d_useEcho = (state == ON); } bobcat-5.09.01/onekey/onekey0000644000175000017500000000123014050437223014607 0ustar frankfrank#ifndef INCLUDED_BOBCAT_ONEKEY_ #define INCLUDED_BOBCAT_ONEKEY_ #include namespace FBB { class OneKey { termios d_saved; bool d_useEcho; // default false public: enum Mode { OFF, ON }; explicit OneKey(Mode state = OFF); ~OneKey(); int get() const; // get the next char void setEcho(Mode state); // .f private: OneKey(OneKey const &other) = delete; OneKey const &operator=(OneKey const &other) = delete; }; #include "setecho.f" } // FBB #endif bobcat-5.09.01/onekey/onekey.cc0000644000175000017500000000136014050437223015177 0ustar frankfrank#include "onekey.ih" OneKey::OneKey(Mode state) { setEcho(state); if (!isatty(STDIN_FILENO)) throw Exception(2) << "OneKey::OneKey(): STDIN is not a tty"; if (tcgetattr(STDIN_FILENO, &d_saved)) throw Exception(2) << "OneKey::OneKey(): can't save the current stdin state"; termios tattr; tcgetattr(STDIN_FILENO, &tattr); // can't assign saved to tattr tattr.c_lflag &= ~(ICANON | ECHO); tattr.c_cc[VMIN] = 1; tattr.c_cc[VTIME] = 0; if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &tattr)) { tcsetattr(STDIN_FILENO, TCSANOW, &d_saved); throw Exception{1} << "OneKey::OneKey(): can't change the stdin state to direct input"; } } bobcat-5.09.01/onekey/onekey.ih0000644000175000017500000000021214050437223015205 0ustar frankfrank#include "onekey" #include #include #include "../exception/exception" using namespace std; using namespace FBB; bobcat-5.09.01/onekey/destructor.cc0000644000175000017500000000013414050437223016101 0ustar frankfrank#include "onekey.ih" OneKey::~OneKey() { tcsetattr(STDIN_FILENO, TCSANOW, &d_saved); } bobcat-5.09.01/onekey/driver/0000755000175000017500000000000014050437223014671 5ustar frankfrankbobcat-5.09.01/onekey/driver/build0000755000175000017500000000023314050437223015714 0ustar frankfrank#!/bin/bash # CMD="g++ -o driver -Wall -I../../tmp driver.cc -L../../tmp/lib -lbobcat -s" CMD="g++ -o driver -Wall driver.cc -lbobcat -s" echo $CMD $CMD bobcat-5.09.01/onekey/driver/driver.cc0000644000175000017500000000154414050437223016477 0ustar frankfrank/* driver.cc */ #include #include #include using namespace std; using namespace FBB; int main() { try { OneKey onekey; cout << "Usage: 1: next chars are echoed, 0: no echo, q: quits\n"; while (true) { char c; cout << "ready...\n"; cout << "Got character '" << (c = onekey.get()) << "'\n"; switch (c) { case '1': onekey.setEcho(OneKey::ON); break; case '0': onekey.setEcho(OneKey::OFF); break; case 'q': return 0; } } } catch (exception const &e) { cout << e.what() << endl; return 1; } } bobcat-5.09.01/osharedstream/0000755000175000017500000000000014050437223014745 5ustar frankfrankbobcat-5.09.01/osharedstream/osharedstream3.cc0000644000175000017500000000023414050437223020177 0ustar frankfrank#include "osharedstream.ih" OSharedStream::OSharedStream(size_t id, std::ios::openmode openMode) : SharedBuf(id, openMode), std::ostream(this) {} bobcat-5.09.01/osharedstream/osharedstream0000644000175000017500000000225314050437223017533 0ustar frankfrank#ifndef INCLUDED_BOBCAT_OSHAREDSTREAM_ #define INCLUDED_BOBCAT_OSHAREDSTREAM_ #include #include namespace FBB { struct OSharedStream: private SharedBuf, public std::ostream, public virtual SharedEnum__ { OSharedStream(); OSharedStream( size_t maxSize, SizeUnit sizeUnit, std::ios::openmode openMode = std::ios::out, size_t access = 0600); OSharedStream( size_t id, std::ios::openmode openMode = std::ios::out | std::ios::in); using SharedBuf::attachSharedCondition; using std::ostream::clear; using SharedBuf::createSharedCondition; using SharedBuf::id; using SharedBuf::kill; void memInfo(std::ostream &out, char const *end = "\n") const; void open( size_t maxSize, SizeUnit sizeUnit, std::ios::openmode openMode = std::ios::out, size_t access = 0600); void open( int id, std::ios::openmode openMode = std::ios::in | std::ios::out); using SharedBuf::remove; bool truncate(std::streamsize offset); }; #include "truncate.f" } // FBB #endif bobcat-5.09.01/osharedstream/truncate.f0000644000175000017500000000015414050437223016741 0ustar frankfrankinline bool OSharedStream::truncate(std::streamsize offset) { return sharedMemory().truncate(offset); } bobcat-5.09.01/osharedstream/osharedstream1.cc0000644000175000017500000000012514050437223020174 0ustar frankfrank#include "osharedstream.ih" OSharedStream::OSharedStream() : ostream(this) {} bobcat-5.09.01/osharedstream/osharedstream.ih0000644000175000017500000000010414050437223020123 0ustar frankfrank#include "osharedstream" using namespace std; using namespace FBB; bobcat-5.09.01/osharedstream/open2.cc0000644000175000017500000000025014050437223016274 0ustar frankfrank#include "osharedstream.ih" void OSharedStream::open(int id, std::ios::openmode openMode) { setMemory(SharedMemory(id)); setOpenMode(openMode); clear(); } bobcat-5.09.01/osharedstream/open1.cc0000644000175000017500000000041314050437223016274 0ustar frankfrank#include "osharedstream.ih" void OSharedStream::open( size_t maxSize, SizeUnit sizeUnit, std::ios::openmode openMode, size_t access) { setMemory(SharedMemory(maxSize, sizeUnit, access)); setOpenMode(openMode); clear(); } bobcat-5.09.01/osharedstream/meminfo.cc0000644000175000017500000000025714050437223016712 0ustar frankfrank#include "osharedstream.ih" void OSharedStream::memInfo(std::ostream &out, char const *end) const { static_cast(this)->memInfo(out); out << end; } bobcat-5.09.01/osharedstream/osharedstream2.cc0000644000175000017500000000041314050437223020175 0ustar frankfrank#include "osharedstream.ih" OSharedStream::OSharedStream( size_t maxSize, SharedMemory::SizeUnit sizeUnit, std::ios::openmode openMode, size_t access) : SharedBuf(maxSize, sizeUnit, openMode, access), std::ostream(this) {} bobcat-5.09.01/pattern/0000755000175000017500000000000014050437223013561 5ustar frankfrankbobcat-5.09.01/pattern/pattern0000644000175000017500000001356614050437223015174 0ustar frankfrank#ifndef INCLUDED_BOBCAT_PATTERN_ #define INCLUDED_BOBCAT_PATTERN_ #include #include // for pair<> #include #include // match() throws an Errno when either the construction (i.e., // compilation of the pattern) or the match failed. // // The 0-index for position() or operator[] indicates the matched text, // other indices indicate subsequent subexpressions // // Patterns may use: // \b - indicating a word-boundary // \d - indicating a digit // \D - indicating no digit // \s - indicating a white-space ([:space:]) char // \S - indicating no white-space ([:space:]) char // // Pattern strings: // // ------------------------------------------------------------ // Required pattern Provide Pattern() Use as argument: // internally with: // ------------------------------------------------------------ // \\ \\\\ \\\\\\\\ | // \d \d \\d | // ------------------------------------------------------------ namespace FBB { class Pattern { typedef std::pair conversion; static conversion s_patmod[]; static size_t s_sizeofPatmod; struct Regex { size_t d_referenceCount; regex_t d_regex; static std::string s_converted; Regex(std::string pattern, int options); ~Regex(); // destructor.f private: Regex(Regex const &other) = delete; Regex &operator=(Regex const &other) = delete; }; Regex *d_regex = 0; regmatch_t *d_subExpression = 0; size_t d_nSub; size_t d_beyondLast; std::string d_text; int d_matchOptions; public: typedef std::pair Position; // define a pattern using a case-flag and number of // ()-subexpressions. Compilation flags: // // REG_EXTENDED // Use POSIX Extended Regular Expression syntax when // interpreting regex. If not set, POSIX Basic Regu- // lar Expression syntax is used. // // REG_NOSUB // Support for substring addressing of matches is not // required. The nmatch and pmatch parameters to // regexec are ignored if the pattern buffer supplied // was compiled with this flag set. // // REG_NEWLINE // Match-any-character operators don't match a newline. // // A non-matching list ([^...]) not containing a newline // does not match a newline. // // Match-beginning-of-line operator (^) matches the // empty string immediately after a newline, regardless // of whether eflags, the execution flags of // regexec, contains REG_NOTBOL. // // Match-end-of-line operator ($) matches the empty // string immediately before a newline, regardless of // whether eflags contains REG_NOTEOL. Pattern(); // 1 Pattern(Pattern const &other); // 2.f explicit Pattern(std::string const &pattern, // 3.cc bool caseSensitive = true, size_t nSub = 10, int options = REG_EXTENDED | REG_NEWLINE); Pattern(Pattern &&tmp); // 4 ~Pattern(); Pattern &operator=(Pattern const &other); Pattern &operator=(Pattern &&tmp); Pattern &operator<<(int matchOption); bool operator<<(std::string const &text); void setPattern(std::string const &pattern, bool caseSensitive = true, size_t nSub = 10, int options = REG_EXTENDED | REG_NEWLINE); // match a string with a pattern. true: string matched // options could be: // // REG_NOTBOL // The match-beginning-of-line operator always fails // to match (but see the compilation flag REG_NEWLINE // above) This flag may be used when different portions // of a string are passed to regexec and the // beginning of the string should not be interpreted // as the beginning of the line. // // REG_NOTEOL // The match-end-of-line operator always fails to // match (but see the compilation flag REG_NEWLINE) void match(std::string const &text, int options = 0); std::string before() const; // text before the matched text std::string matched() const; // the matched text .f std::string beyond() const; // text beyond the matched text // (0) is complete matching part. Remaining are subexpressions. // (npos, npos) is returned if index exceeds available indices // (which may be 0) // position of subexpression Position position(size_t index) const; // subexpression itself std::string operator[](size_t index) const; size_t end() const; // index beyond the last available .f std::string const &pattern() const; // compiled pattern void swap(Pattern &other); private: void newRegex(std::string const &pattern, int options); // .f void destroy(); void copy(Pattern const &other); }; #include "pattern2.f" #include "matched.f" #include "pattern.f" #include "end.f" } // FBB #endif bobcat-5.09.01/pattern/pattern.ih0000644000175000017500000000544214050437223015565 0ustar frankfrank#include "pattern" /* The PerlSetFSA is a Finite State Automaton converting the special character set characters as used by Perl to their corresponding set-notations. The special perl-set characters may be used inside and outside of character classes. When used in a class, it adds the set to the current set. If the class starts with a caret, then the meaning of the set is reversed: \s <-> \S \d <-> \D (etc). The character sets s, d, and w are currently supported. \b and \B are already part of the standard regex implementation. */ #include #include #include #include "../fswap/fswap" #include "../ranger/ranger" #include "../exception/exception" using namespace std; namespace FBB { class PerlSetFSA { friend class Validator; enum State { Start, Bs, Set, // NegatedSet, SetBs, // NestedSet, InsideASet, // NegatedSetBs, // NegatedNestedSet, // InsideANegatedSet, nStates_ }; struct TransitionMatrix { State d_state; int d_input; State d_next; void (PerlSetFSA::*d_action)(); }; static TransitionMatrix s_stateTransitions[]; static TransitionMatrix *s_stateTransitions_end; class Validator { vector d_used; int d_last; State d_state; bool d_valid; size_t d_element; public: Validator() : d_used(nStates_), d_last(0), d_state(nStates_), d_valid(true) {} void operator()(TransitionMatrix const &state); operator bool() const { return d_valid; } }; // s_transition holds as many elements as there are states, // first: points to first element of corresponding state // in s_transition // second: points just beyond the last element of corresponding // state in s_transition typedef pair statePair; static vector s_transition; string d_target; string::iterator d_next; public: //static void setup(); PerlSetFSA(); void convert(string &pattern); private: static void initialize(TransitionMatrix &stateDescription); void nop() {}; void copy(); void copybs(); void w_Set(); void W_Set(); void d_Set(); void D_Set(); void s_Set(); void S_Set(); void w_Nest(); void d_Nest(); void s_Nest(); }; #include "destructor.f" #include "newregex.f" } // FBB using namespace FBB; bobcat-5.09.01/pattern/position.cc0000644000175000017500000000053614050437223015740 0ustar frankfrank#include "pattern.ih" Pattern::Position Pattern::position(size_t index) const { regoff_t begin; return ( index >= d_beyondLast || (begin = d_subExpression[index].rm_so) == -1 ) ? Position(string::npos, string::npos) : Position(begin, d_subExpression[index].rm_eo); } bobcat-5.09.01/pattern/before.cc0000644000175000017500000000016114050437223015330 0ustar frankfrank#include "pattern.ih" string Pattern::before() const { return d_text.substr(0, d_subExpression[0].rm_so); } bobcat-5.09.01/pattern/validatorobject.cc0000644000175000017500000000142614050437223017247 0ustar frankfrank#include "pattern.ih" void PerlSetFSA::Validator::operator()(TransitionMatrix const &state) { static char name[] = "Pattern::PerlSetFSA::Validator()"; d_element++; if (state.d_state != d_state) // new state ? { if (d_last != 0) d_valid = false, cerr << name << ", element #" << d_element << ": last transition of state " << d_state << " not 0\n"; d_state = state.d_state; // set new state; d_last = state.d_input; // set new transition character if (d_used[d_state]) d_valid = false, cerr << name << ", element #" << d_element << ": Non-contiguous use of state " << d_state << endl; d_used[d_state] = true; } } bobcat-5.09.01/pattern/convert.cc0000644000175000017500000000271014050437223015550 0ustar frankfrank#include #include "pattern.ih" //namespace { // char const *s_state[] = // { // "Start", // "Bs", // "Set", // "NegatedSet", // "SetBs", // "NestedSet", // "InsideASet", // "NegatedSetBs", // "NegatedNestedSet", // "InsideANegatedSet", // }; //} void PerlSetFSA::convert(string &pattern) { d_next = pattern.begin(); //cerr << "Pattern: " << pattern << '\n'; d_target.clear(); State state = Start; for ( ; d_next != pattern.end(); d_next++) { int current = *d_next; //cerr << "state: " << s_state[state] << ", input: " << current << // " (" << static_cast(current) << ") " << // " from: " << (s_transition[state].first - s_stateTransitions) << // ", to: " << (s_transition[state].second - s_stateTransitions) // << '\n'; // set the current char in the transition // matrix s_transition[state].second->d_input = current; TransitionMatrix *mp = s_transition[state].first; while (mp->d_input != current) mp++; // find the appropriate state transition element //cerr << "next state: " << s_state[mp->d_next] << '\n'; (this->*mp->d_action)(); // do the appropriate action state = mp->d_next; //cerr << "target = " << d_target << "\n\n"; } pattern = d_target; } bobcat-5.09.01/pattern/data.cc0000644000175000017500000000443414050437223015006 0ustar frankfrank#include "pattern.ih" // Note: all state transitions MUST be clustered per state // the last element of a state cluster is the default transition. // its 0-value will be overwritten by the conversion. // // PerlSetFSA::convert (convert.cc) converts the received regular expression // to a regcomp-compilable regex. PerlSetFSA::TransitionMatrix PerlSetFSA::s_stateTransitions[] = { // d_state d_input d_next d_action {Start, '\\', Bs, &PerlSetFSA::nop }, {Start, '[', Set, &PerlSetFSA::copy }, {Start, 0, Start, &PerlSetFSA::copy }, {Bs, 'd', Start, &PerlSetFSA::d_Set }, {Bs, 's', Start, &PerlSetFSA::s_Set }, {Bs, 'w', Start, &PerlSetFSA::w_Set }, {Bs, 'D', Start, &PerlSetFSA::D_Set }, {Bs, 'S', Start, &PerlSetFSA::S_Set }, {Bs, 'W', Start, &PerlSetFSA::W_Set }, {Bs, 0, Start, &PerlSetFSA::copybs }, {Set, '\\', SetBs, &PerlSetFSA::nop }, {Set, 0, InsideASet, &PerlSetFSA::copy }, {SetBs, 'd', InsideASet, &PerlSetFSA::d_Nest }, {SetBs, 's', InsideASet, &PerlSetFSA::s_Nest }, {SetBs, 'w', InsideASet, &PerlSetFSA::w_Nest }, {SetBs, '\\', InsideASet, &PerlSetFSA::copy }, {SetBs, 0, InsideASet, &PerlSetFSA::copybs }, {InsideASet, ']', Start, &PerlSetFSA::copy }, {InsideASet, '\\', SetBs, &PerlSetFSA::nop }, {InsideASet, 0, InsideASet, &PerlSetFSA::copy }, }; PerlSetFSA::TransitionMatrix *PerlSetFSA::s_stateTransitions_end = PerlSetFSA::s_stateTransitions + sizeof(PerlSetFSA::s_stateTransitions) / sizeof(PerlSetFSA::TransitionMatrix); vector PerlSetFSA::s_transition; string Pattern::Regex::s_converted; bobcat-5.09.01/pattern/regex.cc0000644000175000017500000000120414050437223015177 0ustar frankfrank#include "pattern.ih" Pattern::Regex::Regex(string pattern, int options) : d_referenceCount(1) { PerlSetFSA{}.convert(pattern); int errcode = regcomp(&d_regex, pattern.c_str(), options); if (errcode) { unique_ptr buffer(new char[100]); regerror(errcode, &d_regex, buffer.get(), 100); throw Exception(errcode) << "Pattern::Pattern(" << pattern << "): " << buffer.get(); } s_converted = pattern; // make the converted pattern available // to who's interested in it. } bobcat-5.09.01/pattern/beyond.cc0000644000175000017500000000025014050437223015345 0ustar frankfrank#include "pattern.ih" string Pattern::beyond() const { size_t begin = d_subExpression[0].rm_eo; return begin < d_text.length() ? d_text.substr(begin) : ""; } bobcat-5.09.01/pattern/operatorindex.cc0000644000175000017500000000050114050437223016747 0ustar frankfrank#include "pattern.ih" string Pattern::operator[](size_t index) const { regoff_t begin; return ( index >= d_beyondLast || (begin = d_subExpression[index].rm_so) == -1 ) ? "" : d_text.substr(begin, d_subExpression[index].rm_eo - begin); } bobcat-5.09.01/pattern/operatorassign2.cc0000644000175000017500000000015314050437223017211 0ustar frankfrank#include "pattern.ih" Pattern &Pattern::operator=(Pattern &&tmp) { swap(tmp); return *this; } bobcat-5.09.01/pattern/operatorlshift2.cc0000644000175000017500000000032514050437223017217 0ustar frankfrank#include "pattern.ih" bool Pattern::operator<<(std::string const &text) try { match(text, d_matchOptions); d_matchOptions = 0; return true; } catch (...) { d_matchOptions = 0; return false; } bobcat-5.09.01/pattern/actions.cc0000644000175000017500000000125714050437223015535 0ustar frankfrank#include "pattern.ih" void PerlSetFSA::copy() { d_target += *d_next; } void PerlSetFSA::copybs() { (d_target += "\\") += *d_next; } void PerlSetFSA::d_Set() { d_target += "[[:digit:]]"; } void PerlSetFSA::s_Set() { d_target += "[[:space:]]"; } void PerlSetFSA::w_Set() { d_target += "[[:alnum:]]"; } void PerlSetFSA::D_Set() { d_target += "[^[:digit:]]"; } void PerlSetFSA::S_Set() { d_target += "[^[:space:]]"; } void PerlSetFSA::W_Set() { d_target += "[^[:alnum:]]"; } void PerlSetFSA::d_Nest() { d_target += "[:digit:]"; } void PerlSetFSA::s_Nest() { d_target += "[:space:]"; } void PerlSetFSA::w_Nest() { d_target += "[:alnum:]"; } bobcat-5.09.01/pattern/fsadriver/0000755000175000017500000000000014050437223015546 5ustar frankfrankbobcat-5.09.01/pattern/fsadriver/build0000755000175000017500000004072414050437223016602 0ustar frankfrank#!/usr/bin/icmake -qt/tmp/fsadriver // script generated by the C++ icmake script version 2.12 /* Configurable defines for the build script: CLASSES: string of directory-names under which sources of classes are found. E.g., CLASSES = "class1 class2" All class-names must be stored in one string. If classes are removed from the CLASSES definition or if the names in the CLASSES definition are reordered, the compilation should start again from scratch. */ string CLASSES; void setClasses() { // ADD ADDITIONAL DIRECTORIES CONTAINING SOURCES OF CLASSES HERE // Use the construction `CLASSES += "classname1 classname2";' etc. CLASSES += " "; } /* Default values for the following variables are found in $IM/default/defines.im BUILD_LIBRARY: define this if you want to create a library for the object modules. Undefined by default: so NO LIBRARY IS BUILT. This links ALL object files to a program, which is a faster process than linking to a library. But it can bloat the executable: all o-modules, rather than those that are really used, become part of the program's code. When defined as an EMPTY STRING, the static library libXXX.a is created: all programs linked to this library will themselves contain the code of the required object modules. This will result in code duplication over different programs linked to this library. When defined as a VERSION STRING, e.g., 1.0.4, a shared library libXXX.so.VERSION is constructed, as well as the links libXXX.so.MAINVERSION and libXXX.so (e.g. 1.0.0 creates libXXX.so.1.0.0, libXXX.so.1 and libXXX.so). Note that with a shared library, the library is always constructed fresh from the compiled object files. But programs linked to this library will SHARE the code stored in the shared library. These programs will therefore tend to be relatively small. Also note that `ldconfig -v' might be required after installing a shared library (libXXX.so) for the first time, so that the linker knows of its existence (in ld.so.cache) BUILD_PROGRAM: define if a program is to be built. If not defined, library maintenance is assumed (default: defined). COMPILER: The compiler to use. COPT: C-options used by COMPILER ECHO_REQUEST: ON (default) if command echoing is wanted, otherwise: set to OFF GDB: define if gdb-symbolic debug information is wanted (not defined by default) LIBS: Extra libraries used for linking LIBPATH: Extra library-searchpaths used for linking LOCAL_NAMESPACE:The namespace that you, the programmer, use yourself. QT: Define this (default: to "qt") if the unthreaded QT library is used. Define as "qt-mt" if the threaded QT library is used. If set, header files are grepped for the occurrence of the string '^[[:space:]]*Q_OBJECT[[:space:]]*$'. If found, moc -o moc.cc .h is called if the moc-file doesn't exist or is older than the .h file. Also, if defined the proper QT library is linked, assuming that the library is found in the ld-search path (E.g., see the environment variable $LIBRARY_PATH). USING: List of :-separated namespaces to be used in sources and .ih files, appearing in `using' directives. USING does NOT automatically include LOCAL_NAMESPACE: add your LOCAL_NAMESPACE name to this list if want a `using' directive for your own namespace as well. Note that namespaces are NOT part of the build-script: they are only listed below for convenience. When they must be altered, the defaults must be changed in $IM/default/defines.im RELINK: Defined by default, causing a program to be relinked every time the script is called. Do not define it if relinking should only occur if a source is compiled. No effect for library maintenance. Current values: */ //#define BUILD_LIBRARY "" #define BUILD_PROGRAM #define COMPILER "g++" #define COPT "-Wall" #define ECHO_REQUEST 1 //#define GDB "-g" #define LIBS "bobcat" #define LIBPATH "../.." // local namespace is: FBB // using-declarations generated for: std:FBB // qt-mt can be used to select the threaded QT library //#define QT "qt" // NO CONFIGURABLE PARTS BELOW THIS LINE /* V A R S . I M */ string // contain options for cwd, // current WD libs, // extra libs, e.g., "-lrss -licce" libpath, // extra lib-paths, eg, "-L../rss" copt, // Compiler options lopt, // Linker options libxxx, // full library-path ofiles, // wildcards for o-files sources, // sources to be used current; // contains name of current dir. int nClasses, // number of classes/subdirectories program; // 1: program is built list classes; // list of classes/directories /* parser.im */ void parser() { #ifdef GRAMBUILD chdir("parser/gramspec"); system("grambuild"); chdir(".."); if ( exists("grammar") && "grammar" younger "parser.cc" ) // new parser needed { exec("bison++", "-d", "-o", "parser.cc", "grammar"); printf("Note: the compilation of parser.cc may produce " "several compiler warnings.\n"); } chdir(".."); #endif } /* S C A N N E R . I M */ void scanner() { string interactive; #ifdef INTERACTIVE interactive = "-I"; #endif #ifdef GRAMBUILD chdir("scanner"); if ( // new lexer needed exists("lexer") && ( "lexer" younger "yylex.cc" || "../parser/parser.h" younger "yylex.cc" ) ) { exec("flex++", interactive, "-oyylex.cc", "lexer"); printf("Note: the compilation of yylex.cc may produce " "several compiler warnings.\n"); } chdir(".."); #endif } /* I N I T I A L . I M */ void initialize() { echo(ECHO_REQUEST); sources = "*.cc"; ofiles = "o/*.o"; // std set of o-files copt = COPT; #ifdef GDB copt += " " + GDB; #endif #ifdef BUILD_PROGRAM program = 1; #else program = 0; #endif; cwd = chdir("."); #ifdef GRAMBUILD CLASSES = "parser scanner "; if (exists("parser")) // subdir parser exists parser(); if (exists("scanner")) // subdir scannerexists scanner(); #endif setClasses(); // remaining classes classes = strtok(CLASSES, " "); // list of classes nClasses = sizeof(classes); } /* M O C . I M */ void moc(string class) { string hfile; string mocfile; int ret; hfile = class + ".h"; mocfile = "moc" + class + ".cc"; if ( hfile younger mocfile // no mocfile or younger h file && // and Q_OBJECT found in .h file !system(P_NOCHECK, "grep '^[[:space:]]*Q_OBJECT[;[:space:]]*$' " + hfile) ) // then call moc. system("moc -o " + mocfile + " " + hfile); } /* O B J F I L E S . I M */ list objfiles(list files) { string file, objfile; int i; for (i = 0; i < sizeof(files); i++) { file = element(i, files); // determine element of the list objfile = "./o/" + change_ext(file, "o"); // make obj-filename if (objfile younger file) // objfile is younger { files -= (list)file; // remove the file from the list i--; // reduce i to test the next } } return (files); } /* A L T E R E D . I M */ list altered(list files, string target) { int i; string file; for (i = 0; i < sizeof(files); i++) // try all elements of the list { file = element(i, files); // use element i of the list if (file older target) // a file is older than the target { files -= (list)file; // remove the file from the list i--; // reduce i to inspect the next } // file of the list } return (files); // return the new list } /* F I L E L I S T . I M */ list file_list(string type, string library) { list files; files = makelist(type); // make all files of certain type #ifdef BUILD_LIBRARY files = altered(files, library); // keep all files newer than lib. #endif files = objfiles(files); // remove if younger .obj exist return (files); } /* L I N K . I M */ void link(string library, string exe) { printf("\n"); exec(COMPILER, "-o", exe, #ifdef BUILD_LIBRARY "-l" + library, #else ofiles, #endif libs, #ifdef GRAMBUILD "-lfl", #endif #ifdef QT "-l" + QT, #endif "-L.", libpath, lopt #ifndef GDB , "-s" #endif ); printf("ok: ", exe, "\n"); } /* P R E F I X C L . I M */ void prefix_class(string class_id) { list o_files; string o_file; int i; chdir("o"); o_files = makelist("*.o"); for (i = 0; o_file = element(i, o_files); i++) exec("mv", o_file, class_id + o_file); chdir(".."); } /* R M C L A S S P . I M */ #ifdef BUILD_LIBRARY string rm_class_id(string class_id, string ofile) { string ret; int index, n; n = strlen(ofile); for (index = strlen(class_id); index < n; index++) ret += element(index, ofile); return ret; } #endif void rm_class_prefix(string class_id) { #ifdef BUILD_LIBRARY list o_files; string o_file; int i; chdir("o"); o_files = makelist("*.o"); for (i = 0; o_file = element(i, o_files); i++) exec("mv", o_file, rm_class_id(class_id, o_file)); chdir(".."); #endif } /* C C O M P I L E . I M */ void c_compile(list cfiles) { string nextfile; int i; if (!exists("o")) system("mkdir o"); if (sizeof(cfiles)) // files to compile ? { printf("\ncompiling: ", current, "\n\n"); // compile all files separately for (i = 0; nextfile = element(i, cfiles); i++) exec(COMPILER, "-c -o o/" + change_ext(nextfile, "o"), copt, nextfile); printf("\n"); } printf("ok: ", current, "\n"); } /* U P D A T E L I . I M */ void updatelib(string library) { #ifdef BUILD_LIBRARY list arlist, objlist; string to, from; objlist = makelist("o/*.o"); if (!sizeof(objlist)) return; printf("\n"); exec("ar", "rvs", library, "o/*.o"); exec("rm", "o/*.o"); printf("\n"); #endif } /* S T D C P P . I M */ void std_cpp(string library) { list cfiles; cfiles = file_list(sources, library); // make list of all cpp-files c_compile(cfiles); // compile cpp-files } /* C P P M A K E . C CPP files are processed by stdmake. Arguments of CPPMAKE: cpp_make( string mainfile, : name of the main .cpp file, or "" for library maintenance string library, : name of the local library to use/create (without lib prefix or .a/.so suffix (E.g., use `main' for `libmain.a') string exe, : (path) name of the exe file to create ) Both mainfile and library MUST be in the current directory */ void cpp_make(string mainfile, string library, string exe) { int index; string class; if (nClasses) ofiles += " */o/*.o"; // set ofiles for no LIBRARY use // make library name #ifdef BUILD_LIBRARY libxxx = chdir(".") + "lib" + library + ".a"; #endif // first process all classes for (index = 0; index < nClasses; index++) { class = element(index, classes); // next class to process chdir(class); // change to directory current = "subdir " + class; #ifdef QT moc(class); // see if we should call moc #endif std_cpp(libxxx); // compile all files chdir(cwd); // go back to parent dir } current = "auxiliary " + sources + " files"; std_cpp(libxxx); // compile all files in current dir #ifdef BUILD_LIBRARY for (index = 0; index < nClasses; index++) { current = element(index, classes); // determine class name chdir( current); // chdir to a class directory. prefix_class((string)index); updatelib(libxxx); chdir(cwd); // go back to parent dir } current = ""; // no class anymore updatelib(libxxx); // update lib in current dir #endif if (mainfile != "") // mainfile -> do link { link(library, exe); printf ( "\nProgram construction completed.\n" "\n" ); } } /* S E T L I B S . I M */ void setlibs() { #ifdef LIBS int n, index; list cut; cut = strtok(LIBS, " "); // cut op libraries n = sizeof(cut); for (index = 0; index < n; index++) libs += " -l" + element(index, cut); #ifdef GRAMBUILD libs += " -lfl"; #endif cut = strtok(LIBPATH, " "); // cut up the paths n = sizeof(cut); for (index = 0; index < n; index++) libpath += " -L" + element(index, cut); #endif } void main() { initialize(); setlibs(); #ifdef BUILD_PROGRAM cpp_make ( "fsadriver.cc", // program source "fsadriver", // static program library "fsadriver" // binary program ); #else cpp_make ( "", "fsadriver", // static- or so-library "" ); #endif } bobcat-5.09.01/pattern/fsadriver/fsadriver.h0000644000175000017500000000017614050437223017710 0ustar frankfrank#ifndef INCLUDED_FSADRIVER_H_ #define INCLUDED_FSADRIVER_H_ #include #include namespace FBB { } #endif bobcat-5.09.01/pattern/fsadriver/fsadriver.cc0000644000175000017500000000107714050437223020047 0ustar frankfrank/* fsadriver.cc $Id$ $Log$ Revision 1.1 2005/08/19 15:12:52 frank Initial revision Revision 1.1.1.1 2003/04/19 14:24:00 frank Installation of Pattern */ #include "fsadriver.h" #ifndef INCLUDED_PATTERN_H_ #include "../pattern.hh" #endif using namespace std; using namespace FBB; int main(int argc, char **argv) { string line; PerlSetFSA fsa; while (true) { cout << "line to convert: "; if (!getline(cin, line) || line.empty()) break; fsa.convert(line); } } bobcat-5.09.01/pattern/pattern3.cc0000644000175000017500000000045714050437223015636 0ustar frankfrank#include "pattern.ih" Pattern::Pattern(string const &pattern, bool caseSensitive, size_t nSub, int options) : d_subExpression(new regmatch_t[nSub]), d_nSub(nSub), d_beyondLast(0), d_matchOptions(0) { newRegex(pattern, options | (caseSensitive ? 0 : REG_ICASE)); } bobcat-5.09.01/pattern/pattern4.cc0000644000175000017500000000042114050437223015626 0ustar frankfrank#include "pattern.ih" Pattern::Pattern(Pattern &&tmp) : d_regex(tmp.d_regex), d_subExpression(tmp.d_subExpression), d_nSub(tmp.d_nSub), d_beyondLast(tmp.d_beyondLast), d_text(tmp.d_text), d_matchOptions(tmp.d_matchOptions) { tmp.d_regex = 0; } bobcat-5.09.01/pattern/pattern2.f0000644000175000017500000000010314050437223015461 0ustar frankfrankinline Pattern::Pattern(Pattern const &other) { copy(other); } bobcat-5.09.01/pattern/end.f0000644000175000017500000000010014050437223014465 0ustar frankfrankinline size_t Pattern::end() const { return d_beyondLast; } bobcat-5.09.01/pattern/matched.f0000644000175000017500000000011014050437223015325 0ustar frankfrankinline std::string Pattern::matched() const { return (*this)[0]; } bobcat-5.09.01/pattern/operatorlshift1.cc0000644000175000017500000000017714050437223017223 0ustar frankfrank#include "pattern.ih" Pattern &Pattern::operator<<(int matchOptions) { d_matchOptions = matchOptions; return *this; } bobcat-5.09.01/pattern/destructor.f0000644000175000017500000000007314050437223016126 0ustar frankfrankinline Pattern::Regex::~Regex() { regfree(&d_regex); } bobcat-5.09.01/pattern/destructor.cc0000644000175000017500000000012714050437223016266 0ustar frankfrank#include "pattern.ih" Pattern::~Pattern() { if (d_regex) destroy(); } bobcat-5.09.01/pattern/operatorassign.cc0000644000175000017500000000021214050437223017123 0ustar frankfrank#include "pattern.ih" Pattern &Pattern::operator=(Pattern const &other) { Pattern tmp(other); swap(tmp); return *this; } bobcat-5.09.01/pattern/swap.cc0000644000175000017500000000014014050437223015035 0ustar frankfrank#include "pattern.ih" void Pattern::swap(Pattern &other) { fswap(*this, other, d_text); } bobcat-5.09.01/pattern/match.cc0000644000175000017500000000076314050437223015172 0ustar frankfrank#include "pattern.ih" void Pattern::match(string const &text, int options) { int errcode = regexec(&d_regex->d_regex, text.c_str(), d_nSub, d_subExpression, options); if (errcode) throw Exception{} << "Pattern::match(): no match"; d_text = text; for (d_beyondLast = d_nSub; d_beyondLast--; ) { if (d_subExpression[d_beyondLast].rm_so != -1) { ++d_beyondLast; return; } } } bobcat-5.09.01/pattern/newregex.f0000644000175000017500000000016114050437223015552 0ustar frankfrankinline void Pattern::newRegex(string const &pattern, int options) { d_regex = new Regex(pattern, options); } bobcat-5.09.01/pattern/pattern.f0000644000175000017500000000012714050437223015405 0ustar frankfrankinline std::string const &Pattern::pattern() const { return Regex::s_converted; } bobcat-5.09.01/pattern/destroy.cc0000644000175000017500000000027414050437223015564 0ustar frankfrank#include "pattern.ih" void Pattern::destroy() { if (d_regex == 0) return; if (--d_regex->d_referenceCount == 0) delete d_regex; delete [] d_subExpression; } bobcat-5.09.01/pattern/perlsetfsa.cc0000644000175000017500000000311314050437223016236 0ustar frankfrank#include "pattern.ih" // all subsequent elements of s_stateTransion[] are referrred to by // stateDescription void PerlSetFSA::initialize(TransitionMatrix &stateDescription) { // statePtr points to the element matching // stateTransitions[]' element statePair *statePtr = &s_transition[stateDescription.d_state]; // not yet initialized: both point to the if (!statePtr->first) // first element in stateTransitions[] *statePtr = statePair(&stateDescription, &stateDescription); else statePtr->second++; // otherwise: there's another element: count } // the #elements of a state // following th constructor's call s_transition holds #states elements, // each entry's first element points to the first line of that state in // s_stateTransitions[], the 2nd element points to the last line of // that state. E.g., for s_transition[1] first = &s_stateTransitions[3], // and first = &s_stateTransitions[9] PerlSetFSA::PerlSetFSA() { if (!s_transition.size()) // s_transition: vector of (#states) pairs { // of (initially 0-)pointers to // s_stateTransition elements s_transition.resize(nStates_); // initialize all elements to zeroes for ( auto &transit: // visit each s_stateTransitions element ranger(s_stateTransitions, s_stateTransitions_end) ) initialize(transit); } } bobcat-5.09.01/pattern/pattern1.cc0000644000175000017500000000035614050437223015632 0ustar frankfrank#include "pattern.ih" Pattern::Pattern() : d_subExpression(0), d_nSub(0), d_beyondLast(0) { newRegex("\\b", 0); // for the benefit of MACs: \\b prevents } // the `empty subexpression' error. bobcat-5.09.01/pattern/driver/0000755000175000017500000000000014050437223015054 5ustar frankfrankbobcat-5.09.01/pattern/driver/build0000755000175000017500000000065714050437223016111 0ustar frankfrank#!/bin/bash tput clear GPP="g++ --std=c++2a" # CMD="$GPP -o driver -Wall -I../ driver.cc ../../errno/*.cc -L../tmp -lpattern -s" CMD="$GPP -o driver -Wall *.cc -L../tmp -lpattern -lbobcat -s" #CMD="$GPP -o driver -Wall *.cc -L../tmp -lpattern -L../../tmp/liba -lbobcat -s" #CMD="$GPP -o driver -Wall *.cc -L../../tmp/liba -lbobcat -s" #CMD="$GPP -o driver -Wall *.cc -lbobcat -s" echo $CMD $CMD || exit 1 echo Ready... driver bobcat-5.09.01/pattern/driver/driver.cc0000644000175000017500000000371014050437223016657 0ustar frankfrank#include "driver.h" #include using namespace std; using namespace FBB; #include #include void showSubstr(string const &str) { static int count = 0; cout << "String " << ++count << " is '" << str << "'\n"; } void match(Pattern const &patt, string const &text) try { Pattern pattern{ patt }; pattern.match(text); Pattern p3(pattern); cout << "before: " << p3.before() << "\n" "matched: " << p3.matched() << "\n" "beyond: " << pattern.beyond() << "\n" "end() = " << pattern.end() << '\n'; for (size_t idx = 0; idx != pattern.end(); ++idx) { string str = pattern[idx]; if (str.empty()) cout << "part " << idx << " not present\n"; else { Pattern::Position pos = pattern.position(idx); cout << "part " << idx << ": '" << str << "' (" << pos.first << "-" << pos.second << ")\n"; } } } catch (exception const &exc) { cout << exc.what() << '\n'; } int main(int argc, char **argv) { string patStr = R"(\d+)"; do { cout << "Pattern: '" << patStr << "'\n"; try { // by default: case sensitive // use any args. for case insensitive Pattern patt(patStr, argc == 1); cout << "Compiled pattern: " << patt.pattern() << '\n'; while (true) { cout << "string to match : "; string text; getline(cin, text); if (text.empty()) break; cout << "String: '" << text << "'\n"; match(patt, text); } } catch (exception const &exc) { cout << exc.what() << ": compilation failed\n"; } cout << "New pattern: "; } while (getline(cin, patStr) and not patStr.empty()); } bobcat-5.09.01/pattern/driver/driver.h0000644000175000017500000000017014050437223016516 0ustar frankfrank#ifndef INCLUDED_DRIVER_H_ #define INCLUDED_DRIVER_H_ #include #include namespace FBB { } #endif bobcat-5.09.01/pattern/driver/main.notused0000644000175000017500000000100214050437223017374 0ustar frankfrank { Pattern one("one"); Pattern two(one); Pattern three("a"); Pattern four; three = three; } try { Pattern pattern("aap|noot|mies"); { Pattern extra(Pattern(pattern)); } if (pattern << "noot") cout << "noot matches\n"; else cout << ": noot doesn't match\n"; } catch (exception const &e) { cout << e.what() << ": compilation failed" << endl; } bobcat-5.09.01/pattern/copy.cc0000644000175000017500000000056614050437223015051 0ustar frankfrank#include "pattern.ih" void Pattern::copy(Pattern const &other) { d_regex = other.d_regex; d_regex->d_referenceCount++; d_nSub = other.d_nSub, d_beyondLast =other.d_beyondLast; d_text = other.d_text; d_subExpression = new regmatch_t[d_nSub]; std::copy(other.d_subExpression, other.d_subExpression + d_nSub, d_subExpression); } bobcat-5.09.01/pattern/setpattern.cc0000644000175000017500000000064614050437223016267 0ustar frankfrank#include "pattern.ih" void Pattern::setPattern(string const &pattern, bool caseSensitive, size_t nSub, int options) { delete [] d_subExpression; d_subExpression = new regmatch_t[nSub]; d_nSub = nSub; d_beyondLast = 0; if (--d_regex->d_referenceCount == 0) delete d_regex; newRegex(pattern, options | (caseSensitive ? 0 : REG_ICASE)); d_matchOptions = 0; } bobcat-5.09.01/pf_iterator/0000755000175000017500000000000014050437223014422 5ustar frankfrankbobcat-5.09.01/pf_iterator/iterator1.cc0000644000175000017500000000014614050437223016644 0ustar frankfrank#include "../primefactors/primefactors.ih" PrimeFactors::iterator::iterator() : d_sentinel(1) {} bobcat-5.09.01/pf_iterator/checkinitialprimes.cc0000644000175000017500000000046614050437223020606 0ustar frankfrank#include "../primefactors/primefactors.ih" void PrimeFactors::iterator::checkInitialPrimes( BigIntVector const &primes) const { if (primes.size() < 2 || primes[0] != 2 || primes[1] != 3) throw Exception{} << "PrimeFactors: first primes must be 2 and 3"; } bobcat-5.09.01/pf_iterator/next.cc0000644000175000017500000000037214050437223015711 0ustar frankfrank#include "../primefactors/primefactors.ih" void PrimeFactors::iterator::next() { do { d_iterator = d_primes->begin(); d_lastPrime += 2; } while (isComposite(d_lastPrime)); d_primes->push_back(d_lastPrime); } bobcat-5.09.01/pf_iterator/operatorpreinc.cc0000644000175000017500000000063714050437223017773 0ustar frankfrank#include "../primefactors/primefactors.ih" PrimeFactors::iterator &PrimeFactors::iterator::operatorPreInc() { ++d_iterator; switch (d_mode) { case PRIMES: if (d_iterator != d_primes->cend()) break; d_mode = SENTINEL; d_iterator = d_sentinel.begin(); [[fallthrough]]; case SENTINEL: break; } return *this; } bobcat-5.09.01/pf_iterator/destructor.cc0000644000175000017500000000012314050437223017123 0ustar frankfrank#include "../primefactors/primefactors.ih" PrimeFactors::iterator::~iterator() {} bobcat-5.09.01/pf_iterator/iscomposite.cc0000644000175000017500000000052014050437223017264 0ustar frankfrank#include "../primefactors/primefactors.ih" bool PrimeFactors::iterator::isComposite(BigInt const &candidate) { BigInt last(candidate.isqrtc()); d_sentinel[0] = last + 1; while (*d_iterator <= last) { if ((candidate % *d_iterator).isZero()) return true; ++*this; } return false; } bobcat-5.09.01/pf_iterator/iterator2.cc0000644000175000017500000000044614050437223016650 0ustar frankfrank#include "../primefactors/primefactors.ih" PrimeFactors::iterator::iterator(BigIntVector &primes) : d_mode(PRIMES), d_primes(&primes), d_sentinel(1) { if (primes.empty()) primes = BigIntVector{2, 3}; d_lastPrime = primes.back(); d_iterator = primes.begin(); } bobcat-5.09.01/pf_iteratorstream/0000755000175000017500000000000014050437223015636 5ustar frankfrankbobcat-5.09.01/pf_iteratorstream/writenewprimes.cc0000644000175000017500000000045714050437223021237 0ustar frankfrank#include "../primefactors/primefactors.ih" void PrimeFactors::iteratorStream::writeNewPrimes() { d_stream.clear(); d_stream.seekp(0, ios::end); copy(d_newPrimes.begin(), d_newPrimes.end(), ostream_iterator(d_stream, "\n")); d_newPrimes.clear(); } bobcat-5.09.01/pf_iteratorstream/openstream.cc0000644000175000017500000000056714050437223020332 0ustar frankfrank#include "../primefactors/primefactors.ih" void PrimeFactors::iteratorStream::openStream() { User user; if (d_name.find("~/") == 0) d_name.replace(0, 2, user.homedir()); d_stream.open(d_name, ios::in | ios::out); if (not d_stream) { d_stream.clear(); Exception::open(d_stream, d_name, ios::out | ios::trunc | ios::in); } } bobcat-5.09.01/pf_iteratorstream/next.cc0000644000175000017500000000054414050437223017126 0ustar frankfrank#include "../primefactors/primefactors.ih" void PrimeFactors::iteratorStream::next() { BigInt candidate = d_lastPrime; do { resetPrimes(); candidate += 2; } while (isComposite(candidate)); if (d_newPrimes.size() == d_blockSize) writeNewPrimes(); d_newPrimes.push_back(d_lastPrime = candidate); } bobcat-5.09.01/pf_iteratorstream/operatorpreinc.cc0000644000175000017500000000136014050437223021201 0ustar frankfrank#include "../primefactors/primefactors.ih" PrimeFactors::iterator &PrimeFactors::iteratorStream::operatorPreInc() { ++d_iterator; switch (d_mode) { case STREAM_PRIMES: if (d_iterator != d_streamPrimes.cend()) break; readPrimes(); if (d_iterator != d_streamPrimes.cend()) break; d_mode = NEW_PRIMES; d_iterator = d_newPrimes.begin(); [[fallthrough]]; case NEW_PRIMES: if (d_iterator != d_newPrimes.cend()) break; d_mode = SENTINEL; d_iterator = d_sentinel.begin(); [[fallthrough]]; case SENTINEL: break; } return *this; } bobcat-5.09.01/pf_iteratorstream/newprimes.OBS0000644000175000017500000000045714050437223020222 0ustar frankfrank#include "../primefactors/primefactors.ih" bool PrimeFactors::iteratorStream::newPrimes() { if (d_newPrimes.empty()) return false; d_primes = d_newPrimes; if (d_newPrimes.size() == d_blockSize) writeNewPrimes(); d_iterator = d_primes.begin(); return true; } bobcat-5.09.01/pf_iteratorstream/destructor.cc0000644000175000017500000000016614050437223020346 0ustar frankfrank#include "../primefactors/primefactors.ih" PrimeFactors::iteratorStream::~iteratorStream() { writeNewPrimes(); } bobcat-5.09.01/pf_iteratorstream/readprimes.cc0000644000175000017500000000065614050437223020307 0ustar frankfrank#include "../primefactors/primefactors.ih" bool PrimeFactors::iteratorStream::readPrimes() { d_streamPrimes.clear(); BigInt tmp; size_t idx; for (idx = 0; idx != d_blockSize; ++idx) { if (not (d_stream >> tmp)) break; d_streamPrimes.push_back(tmp); } if (idx != 0) d_lastPrime = d_streamPrimes.back(); d_iterator = d_streamPrimes.begin(); return idx; } bobcat-5.09.01/pf_iteratorstream/resetprimes.cc0000644000175000017500000000066214050437223020513 0ustar frankfrank#include "../primefactors/primefactors.ih" void PrimeFactors::iteratorStream::resetPrimes() { d_stream.clear(); d_stream.seekg(0); d_mode = STREAM_PRIMES; readPrimes(); if (not d_streamPrimes.empty()) checkInitialPrimes(d_streamPrimes); else { d_mode = NEW_PRIMES; d_newPrimes = BigIntVector {2, 3}; d_iterator = d_newPrimes.begin(); d_lastPrime = 3; } } bobcat-5.09.01/pf_iteratorstream/iteratorstream1.cc0000644000175000017500000000051114050437223021270 0ustar frankfrank#include "../primefactors/primefactors.ih" PrimeFactors::iteratorStream::iteratorStream(std::string const &name, size_t blockSize) : d_name(name), d_blockSize(blockSize) { openStream(); d_stream << hex; d_streamPrimes.reserve(blockSize); resetPrimes(); } bobcat-5.09.01/pipe/0000755000175000017500000000000014050437223013041 5ustar frankfrankbobcat-5.09.01/pipe/closereadfd.f0000644000175000017500000000006614050437223015465 0ustar frankfrankinline void Pipe::closeReadFd() { close(READ); } bobcat-5.09.01/pipe/writefd.f0000644000175000017500000000007514050437223014656 0ustar frankfrankinline int Pipe::writeFd() const { return d_fd[WRITE]; } bobcat-5.09.01/pipe/pipe1.cc0000644000175000017500000000017114050437223014365 0ustar frankfrank#include "pipe.ih" Pipe::Pipe() { if (pipe(d_fd)) throw Exception{} << "Pipe::Pipe(): " << errnodescr; } bobcat-5.09.01/pipe/pipe3.cc0000644000175000017500000000013114050437223014363 0ustar frankfrank#include "pipe.ih" Pipe::Pipe(int const *fd) { memcpy(d_fd, fd, 2 * sizeof(int)); } bobcat-5.09.01/pipe/swap.f0000644000175000017500000000010614050437223014157 0ustar frankfrankinline void Pipe::swap(Pipe &other) { FBB::fswap(*this, other); } bobcat-5.09.01/pipe/pipe2.cc0000644000175000017500000000013714050437223014370 0ustar frankfrank#include "pipe.ih" Pipe::Pipe(Pipe &&tmp) : d_fd{ -1, -1} { FBB::fswap(*this, tmp); } bobcat-5.09.01/pipe/closewritefd.f0000644000175000017500000000006714050437223015705 0ustar frankfrankinline void Pipe::closeWriteFd() { close(WRITE); } bobcat-5.09.01/pipe/pipe0000644000175000017500000000301014050437223013713 0ustar frankfrank#ifndef INCLUDED_BOBCAT_PIPE_ #define INCLUDED_BOBCAT_PIPE_ #include #include namespace FBB { class Pipe { int d_fd[2]; protected: enum RW { READ, WRITE }; public: Pipe(); Pipe(Pipe &&tmp); explicit Pipe(int const *fd); explicit Pipe(bool initialize); // ~Pipe(); removed from the interface as it's implementation was // empty and this class is not a Base class having virtual // members Pipe &operator=(Pipe &&tmp); void swap(Pipe &other); int readFd() const; // .f int writeFd() const; // .f void close(); // close the fds 1.cc void closeReadFd(); // .f void closeWriteFd(); // .f void readFrom(int filedescriptor); void readFrom(int const *filedescriptor, size_t n); void writtenBy(int filedescriptor); void writtenBy(int const *filedescriptor, size_t n = 2); int readOnly(); // closes the write FD int writeOnly(); // closes the read FD protected: void close(RW rw); // 2.cc }; #include "readfd.f" #include "writefd.f" #include "closereadfd.f" #include "closewritefd.f" #include "swap.f" } // FBB #endif bobcat-5.09.01/pipe/pipe.ih0000644000175000017500000000020214050437223014312 0ustar frankfrank#include "pipe" #include #include "../redirector/redirector" #include "../exception/exception" using namespace FBB; bobcat-5.09.01/pipe/close1.cc0000644000175000017500000000011614050437223014534 0ustar frankfrank#include "pipe.ih" void Pipe::close() { close(READ); close(WRITE); } bobcat-5.09.01/pipe/readfrom.cc0000644000175000017500000000064014050437223015147 0ustar frankfrank#include "pipe.ih" void Pipe::readFrom(int fd) // read from file descriptor fd { // instead of the pipe's fd close(WRITE); // we're reading, not writing Redirector redirect{ d_fd[READ] }; // perform the redirection: redirect.swallow(fd); // read from fd. close(READ); // don't need this anymore, as fd is used } bobcat-5.09.01/pipe/readonly.cc0000644000175000017500000000012614050437223015164 0ustar frankfrank#include "pipe.ih" int Pipe::readOnly() { close(WRITE); return d_fd[READ]; } bobcat-5.09.01/pipe/writeonly.cc0000644000175000017500000000012714050437223015404 0ustar frankfrank#include "pipe.ih" int Pipe::writeOnly() { close(READ); return d_fd[WRITE]; } bobcat-5.09.01/pipe/pipe4.cc0000644000175000017500000000025114050437223014367 0ustar frankfrank#include "pipe.ih" Pipe::Pipe(bool initialize) { if (initialize) *this = Pipe{}; else { d_fd[READ] = -1; d_fd[WRITE] = -1; } } bobcat-5.09.01/pipe/readfrom2.cc0000644000175000017500000000036214050437223015232 0ustar frankfrank#include "pipe.ih" void Pipe::readFrom(int const *fd, size_t n) { close(WRITE); for (size_t idx = 0; idx != n; ++idx) { Redirector redirector{ d_fd[READ] }; redirector.swallow(fd[idx]); } close(READ); } bobcat-5.09.01/pipe/operatorassign.cc0000644000175000017500000000016714050437223016414 0ustar frankfrank#include "pipe.ih" Pipe &Pipe::operator=(Pipe &&tmp) { close(); FBB::fswap(*this, tmp); return *this; } bobcat-5.09.01/pipe/writtenby2.cc0000644000175000017500000000036414050437223015464 0ustar frankfrank#include "pipe.ih" void Pipe::writtenBy(int const *fd, size_t n) { close(READ); for (size_t idx = 0; idx != n; ++idx) { Redirector redirector{ d_fd[WRITE] }; redirector.swallow(fd[idx]); } close(WRITE); } bobcat-5.09.01/pipe/writtenby.cc0000644000175000017500000000064114050437223015400 0ustar frankfrank#include "pipe.ih" void Pipe::writtenBy(int fd) // fd rather than the pipe's write fd { // is used to write to the pipe close(READ); // we're writing, not reading Redirector redirector{ d_fd[WRITE] }; // perform the redirection: redirector.swallow(fd); // fd writes close(WRITE); // we don't need this anymore. } bobcat-5.09.01/pipe/close2.cc0000644000175000017500000000020314050437223014532 0ustar frankfrank#include "pipe.ih" void Pipe::close(RW rw) { if (d_fd[rw] == -1) return; ::close(d_fd[rw]); d_fd[rw] = -1; } bobcat-5.09.01/pipe/readfd.f0000644000175000017500000000007314050437223014435 0ustar frankfrankinline int Pipe::readFd() const { return d_fd[READ]; } bobcat-5.09.01/pipe/driver/0000755000175000017500000000000014050437223014334 5ustar frankfrankbobcat-5.09.01/pipe/driver/build0000755000175000017500000000023314050437223015357 0ustar frankfrank#!/bin/bash #CMD="g++ -o driver -Wall -I../../tmp driver.cc -L../../tmp/lib -lbobcat -s" CMD="g++ -o driver -Wall driver.cc -lbobcat -s" echo $CMD $CMD bobcat-5.09.01/pipe/driver/driver.cc0000644000175000017500000000202414050437223016134 0ustar frankfrank#include #include #include #include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) try { Pipe p; // construct a pipe cout << "Read file descriptor: " << p.readFd() << endl; cout << "Write file descriptor: " << p.writeFd() << endl; int pid = fork(); if (pid == -1) return 1; if (!pid) //child { p.readFrom(STDIN_FILENO); // read what goes into the pipe from cin string s; getline(cin, s); cout << "CHILD: Got `" << s << "'" << endl; getline(cin, s); cout << "CHILD: Got `" << s << "'" << endl; return 0; } p.writtenBy(STDOUT_FILENO); // write to the pipe via cout cout << "first line" << endl; cout << "second line" << endl; waitpid(pid, 0, 0); } catch (exception const &err) { cout << err.what() << endl; return 1; } bobcat-5.09.01/primefactors/0000755000175000017500000000000014050437223014602 5ustar frankfrankbobcat-5.09.01/primefactors/primefactors.ih0000644000175000017500000000156214050437223017626 0ustar frankfrank#include "primefactors" #include #include "../exception/exception" #include "../user/user" using namespace std; using namespace FBB; class PrimeFactors::iteratorStream: public iterator { enum InputMode { STREAM_PRIMES, NEW_PRIMES, SENTINEL }; std::string d_name; std::fstream d_stream; size_t d_blockSize; BigIntVector d_streamPrimes; BigIntVector d_newPrimes; public: iteratorStream(std::string const &name, size_t blockSize); ~iteratorStream(); private: iterator &operatorPreInc() override; void next() override; void openStream(); void resetPrimes(); bool readPrimes(); void writeNewPrimes(); }; #include "opinc.f" #include "opstar.f" #include "lastprime.f" #include "nextprime.f" #include "atsentinel.f" #include "setsentinel.f" bobcat-5.09.01/primefactors/addprimes.cc0000644000175000017500000000057114050437223017064 0ustar frankfrank#include "primefactors.ih" void PrimeFactors::addPrimes() { BigInt const &prime = d_iterator->lastPrime(); while (not d_value.isOne()) { d_iterator->nextPrime(); if (prime > d_last) // beyond the last possible factor { d_factors.push_back({d_value, 1}); break; } reduce(prime); } } bobcat-5.09.01/primefactors/reduce.cc0000644000175000017500000000055314050437223016363 0ustar frankfrank#include "primefactors.ih" void PrimeFactors::reduce(BigInt const &prime) { BigInt remainder; size_t count = 0; while (true) { BigInt div(d_value.divc(&remainder, prime)); if (not remainder.isZero()) break; d_value = div; ++count; } if (count) d_factors.push_back({prime, count}); } bobcat-5.09.01/primefactors/setsentinel.f0000644000175000017500000000014414050437223017305 0ustar frankfrankinline void PrimeFactors::iterator::setSentinel(BigInt const &value) { d_sentinel[0] = value; } bobcat-5.09.01/primefactors/atsentinel.f0000644000175000017500000000015014050437223017113 0ustar frankfrankinline bool PrimeFactors::iterator::atSentinel() const { return d_iterator == d_sentinel.begin(); } bobcat-5.09.01/primefactors/primefactors1.cc0000644000175000017500000000017114050437223017667 0ustar frankfrank#include "primefactors.ih" PrimeFactors::PrimeFactors(BigIntVector &primes) : d_iterator(new iterator(primes)) {} bobcat-5.09.01/primefactors/opstar.f0000644000175000017500000000013314050437223016256 0ustar frankfrankinline BigInt const &PrimeFactors::iterator::operator*() const { return *d_iterator; } bobcat-5.09.01/primefactors/opinc.f0000644000175000017500000000014514050437223016061 0ustar frankfrankinline PrimeFactors::iterator &PrimeFactors::iterator::operator++() { return operatorPreInc(); } bobcat-5.09.01/primefactors/factorize.cc0000644000175000017500000000050114050437223017073 0ustar frankfrank#include "primefactors.ih" PrimeFactors::Factors const &PrimeFactors::factorize(BigInt const &value) { d_factors.clear(); d_value = value; d_last = d_value.isqrtc(); d_iterator->setSentinel(d_last + 1); availablePrimes(); if (not d_value.isOne()) addPrimes(); return d_factors; } bobcat-5.09.01/primefactors/lastprime.f0000644000175000017500000000013314050437223016746 0ustar frankfrankinline BigInt const &PrimeFactors::iterator::lastPrime() const { return d_lastPrime; } bobcat-5.09.01/primefactors/availableprimes.cc0000644000175000017500000000105314050437223020250 0ustar frankfrank#include "primefactors.ih" void PrimeFactors::availablePrimes() { while (not d_value.isOne()) { BigInt const &prime = **d_iterator; // get the next prime if (prime > d_last) // checked the last available { if (not d_iterator->atSentinel()) { d_factors.push_back({d_value, 1}); d_value = 1; } return; } reduce(prime); // try to reduce d_value by prime ++*d_iterator; } } bobcat-5.09.01/primefactors/primefactors2.cc0000644000175000017500000000022714050437223017672 0ustar frankfrank#include "primefactors.ih" PrimeFactors::PrimeFactors(string const &name, size_t blockSize) : d_iterator(new iteratorStream(name, blockSize)) {} bobcat-5.09.01/primefactors/primefactors0000644000175000017500000000441214050437223017224 0ustar frankfrank#ifndef INCLUDED_BOBCAT_PRIMEFACTORS_ #define INCLUDED_BOBCAT_PRIMEFACTORS_ #include #include #include #include #include namespace FBB { struct PrimeFactors { struct PrimePower { BigInt prime; size_t power; }; typedef std::vector Factors; private: typedef std::vector BigIntVector; typedef BigIntVector::const_iterator ConstIterator; class iterator { protected: enum InputMode { PRIMES, SENTINEL }; int d_mode; BigIntVector *d_primes; ConstIterator d_iterator; BigInt d_lastPrime; BigIntVector d_sentinel; public: virtual ~iterator(); iterator(); iterator(BigIntVector &primes); // 2 iterator &operator++(); // opinc.f void setSentinel(BigInt const &sentinel); // .f BigInt const &operator*() const; // opstar.f void nextPrime(); // .f BigInt const &lastPrime() const; // .f bool atSentinel() const; // .f protected: void checkInitialPrimes(BigIntVector const &primes) const; bool isComposite(BigInt const &candidate); private: virtual iterator &operatorPreInc(); virtual void next(); }; class iteratorStream; BigInt d_value; BigInt d_last; std::shared_ptr d_iterator; Factors d_factors; public: PrimeFactors(BigIntVector &primes); PrimeFactors(std::string const &name = "", size_t blockSize = 1000); PrimeFactors(PrimeFactors const &other) = delete; Factors const &factorize(BigInt const &value); private: void reduce(BigInt const &prime); void availablePrimes(); void addPrimes(); }; } // FBB #endif bobcat-5.09.01/primefactors/driver/0000755000175000017500000000000014050437223016075 5ustar frankfrankbobcat-5.09.01/primefactors/driver/build0000755000175000017500000000103114050437223017115 0ustar frankfrank#!/bin/bash tput clear LIBS=" -lbobcat" GPP="g++ `cat ../../c++std`" # WHEN LINKING TO A STATIC LIBRARY DON'T FORGET TO LINK AGAINST # ssl (-lssl) # CMD="$GPP -o driver -Wall -I../ driver.cc -L../tmp ${LIBS} -lbigint -s" # CMD="$GPP -o driver -Wall -I../../tmp driver.cc -L../../tmp/lib ${LIBS} -s" # CMD="$GPP -o driver -Wall -I../ driver.cc -L../tmp ${LIBS} -s" # CMD="$GPP -o driver -Wall driver.cc ../*.o ../../pf_*/*.o ${LIBS} -s" CMD="$GPP -o driver -Wall *.cc ${LIBS} -s" echo $CMD $CMD || exit 1 echo Ready... driver 4 bobcat-5.09.01/primefactors/driver/driver.cc0000644000175000017500000000137714050437223017707 0ustar frankfrank#include #include using namespace std; using namespace FBB; int main(int argc, char **argv) { PrimeFactors pf1("/tmp/primes"); PrimeFactors::Factors const *factors = &pf1.factorize(stoull(argv[1])); cout << "Using /tmp/primes:\n"; for (auto &factor: *factors) cout << factor.prime << "**" << factor.power << ' '; vector primes; PrimeFactors pf2(primes); factors = &pf2.factorize(stoull(argv[1])); cout << "\n" "Using BigIntVector:\n"; for (auto &factor: *factors) cout << factor.prime << "**" << factor.power << ' '; cout << "\n" "Collected primes: "; for (auto &prime: primes) cout << prime << ' '; cout << '\n'; } bobcat-5.09.01/primefactors/nextprime.f0000644000175000017500000000010014050437223016753 0ustar frankfrankinline void PrimeFactors::iterator::nextPrime() { next(); } bobcat-5.09.01/process/0000755000175000017500000000000014050437223013562 5ustar frankfrankbobcat-5.09.01/process/process1.cc0000644000175000017500000000016414050437223015631 0ustar frankfrank#include "process.ih" Process::Process(std::string const &command) : Process(ALL, NO_PATH, 0, 200, command) {} bobcat-5.09.01/process/childerrstream.cc0000644000175000017500000000015214050437223017077 0ustar frankfrank#include "process.ih" std::istream &Process::childErrStream() { active(); return d_iChildErr; } bobcat-5.09.01/process/exitstatus.f0000644000175000017500000000010414050437223016141 0ustar frankfrankinline int Process::exitStatus() const { return d_exitStatus; } bobcat-5.09.01/process/newpipe.cc0000644000175000017500000000014214050437223015535 0ustar frankfrank#include "process.ih" void Process::newPipe(Pipe &pipe) { pipe.close(); pipe = Pipe{}; } bobcat-5.09.01/process/forking.cc0000644000175000017500000000022614050437223015530 0ustar frankfrank#include "process.ih" void Process::forking() { newPipes(); if (d_mode == IOMode::DIRECT) childProcess(); fork(); } bobcat-5.09.01/process/parentprocess.cc0000644000175000017500000000014214050437223016756 0ustar frankfrank#include "process.ih" void Process::parentProcess() // overrides { d_child.pid = pid(); } bobcat-5.09.01/process/dquotedstring.x0000644000175000017500000000245714050437223016657 0ustar frankfrank#include "process.ih" // On entry, `begin' points at the beginning of the double quoted string, // on exit, the unescaped double quoted string (without the surrounding double // quotes) is returned, and 'begin' points to the location immediately // following the last double quote. string Process::dquotedString(ConstIter &begin, ConstIter const &end) { string dquoted; while (true) { if (++begin == end) throw Exception() << "Process " << d_command << ": unmatched \""; switch (*begin) { default: // regular characters are added to dquoted dquoted += *begin; break; case '\\': // backslash: accept it and accept the next char dquoted += '\\'; if (begin + 1 == end) // the \ was the last character break; // causing an error at the loop's top dquoted += *++begin; // add the char beyond the \-char break; case '"': // closing double quote observed ++begin; // skip it // return the unescaped double quoted string's return dquoted = String::unescape(dquoted); // contents } } } bobcat-5.09.01/process/operatorfun1.cc0000644000175000017500000000024214050437223016514 0ustar frankfrank#include "process.ih" Process &Process::operator()(IOMode mode, ProcessType type, size_t timeLimit) { return operator()(mode, type, timeLimit, bufSize()); } bobcat-5.09.01/process/whichstream.cc0000644000175000017500000000121314050437223016404 0ustar frankfrank#include "process.ih" Process::ChildOutput Process::whichStream() { d_selector.wait(); switch (size_t count = d_selector.nReady()) { case 0: return NOTHING_AVAILABLE; case 1: return d_selector.readFd() == d_iChildOutPipe.readFd() ? CHILD_COUT : CHILD_CERR; case 2: return CHILD_COUT | CHILD_CERR; default: throw Exception{} << "Process::whichStream(): internal error. " "d_selector.nReady() returns " << count << " (should be <= 2)"; } } bobcat-5.09.01/process/stop.cc0000644000175000017500000000047314050437223015062 0ustar frankfrank#include "process.ih" int Process::stop() { if (!d_active) return -1; d_oChildIn.flush(); d_oChildInbuf.reset(-1); d_iChildOutbuf.reset(-1); d_iChildErrbuf.reset(-1); closePipes(); discontinue(d_child); d_limit.join(); d_active = false; return d_child.ret; } bobcat-5.09.01/process/operatorpipe.cc0000644000175000017500000000373014050437223016605 0ustar frankfrank#include "process.ih" // See ../README.process-pipe for an explanation of the inner workings of // operator| namespace FBB { Process &operator|(Process &lhs, Process &rhs) { // make sure output is available if (not (lhs.d_mode & Process::MERGE_COUT_CERR)) { lhs.d_mode |= Process::COUT; lhs.d_setMode |= Process::COUT; } // all but the first process has IN_PIPE set if ( (lhs.d_setMode & Process::CIN) && not (lhs.d_setMode & Process::IN_PIPE) ) lhs.d_setMode |= Process::CLOSE_ON_EXEC; // This is the output end of the pipe lhs.d_setMode |= Process::PIPES_OK | Process::OUT_PIPE; rhs.d_setMode |= Process::PIPES_OK; lhs.start(); // forking() does the real work #ifdef BOBCAT_DIY_CLOEXEC_ rhs.d_closedByChild = lhs.d_closedByChild; // children close the initial // writing ends of the pipes // to the 1st process #endif rhs.d_oChildInPipe.swap(lhs.d_iChildOutPipe); // copy the input fm the lhs's child to the rhs's // output. lhs.iChildOutPipe only has an open // read-pipe and will be available to the rhs's // child process to read via its stdin, thus // connecting lhs's output to the rhs's input if (lhs.d_oChildIn.rdbuf() != 0) { lhs.d_oChildIn.rdbuf(0); rhs.d_oChildInbuf.reset(lhs.d_oChildInbuf.fd(), 200); rhs.d_oChildIn.rdbuf(&rhs.d_oChildInbuf); } // this is the input end of the pipe rhs.d_setMode |= Process::CIN | Process::IN_PIPE; rhs.d_mode |= Process::CIN; return rhs; // to start do, e.g., (p1|p2).start() } } bobcat-5.09.01/process/closepipes.cc0000644000175000017500000000021414050437223016234 0ustar frankfrank#include "process.ih" void Process::closePipes() { d_oChildInPipe.close(); d_iChildOutPipe.close(); d_iChildErrPipe.close(); } bobcat-5.09.01/process/opinsert.f0000644000175000017500000000025014050437223015571 0ustar frankfranktemplate Process &Process::operator<<(Type const &value) { if (active()) dynamic_cast(*this) << value; return *this; } bobcat-5.09.01/process/opfun1.f0000644000175000017500000000016414050437223015142 0ustar frankfrankinline Process &Process::operator()(IOMode mode) { return operator()(mode, d_setProcessType, d_setTimeLimit); } bobcat-5.09.01/process/iomode.f0000644000175000017500000000015614050437223015207 0ustar frankfrankinline Process::IOMode Process::ioMode() const { return d_mode & ~(IN_PIPE | OUT_PIPE | CLOSE_ON_EXEC); } bobcat-5.09.01/process/eoi2.cc0000644000175000017500000000020714050437223014726 0ustar frankfrank#include "process.ih" void Process::eoi_() { if (active()) { close(); d_exitStatus = waitForChild(); } } bobcat-5.09.01/process/showmode.cc0000644000175000017500000000212414050437223015715 0ustar frankfrank#include "process.ih" void Process::showMode(char const *lab) const { std::cerr << lab << ' ' << getpid() << ' ' << d_child.pid << " IOMode: "; if (d_mode == NONE) std::cerr << "NONE "; if (d_mode & CIN) std::cerr << "CIN "; if (d_mode & COUT) std::cerr << "COUT "; if (d_mode & CERR) std::cerr << "CERR "; if (d_mode & IGNORE_COUT) std::cerr << "IGNORE_COUT "; if (d_mode & IGNORE_CERR) std::cerr << "IGNORE_CERR "; if (d_mode & MERGE_COUT_CERR) std::cerr << "MERGE_COUT_CERR "; if (d_mode & DIRECT) std::cerr << "DIRECT "; if (d_setMode & IN_PIPE) std::cerr << "IN_PIPE "; if (d_setMode & OUT_PIPE) std::cerr << "OUT_PIPE "; if (d_setMode & CLOSE_ON_EXEC) std::cerr << "CLOSE_ON_EXEC "; std::cerr << d_oChildInPipe.readFd() << ' ' << d_oChildInPipe.writeFd() << ' ' << d_iChildOutPipe.readFd() << ' ' << d_iChildOutPipe.writeFd() << ' ' << d_iChildErrPipe.readFd() << ' ' << d_iChildErrPipe.writeFd(); std::cerr << '\n'; } bobcat-5.09.01/process/process3.cc0000644000175000017500000000022114050437223015625 0ustar frankfrank#include "process.ih" Process::Process(IOMode mode, ProcessType type, std::string const &command) : Process(mode, type, 0, 200, command) {} bobcat-5.09.01/process/retpid1.f0000644000175000017500000000007514050437223015303 0ustar frankfrankinline Process::RetPid::RetPid() : ret(0), pid(0) {} bobcat-5.09.01/process/childprocess.cc0000644000175000017500000000154614050437223016561 0ustar frankfrank#include "process.ih" void Process::childProcess() { ExecContext ec; if (d_processType != USE_SHELL) ec = analyzeCommand(); // No system, so run execl() or execle() else { ec.argv = new char const *[4]; ec.argv[0] = "/bin/sh"; ec.argv[1] = "-c"; ec.argv[2] = d_command.c_str(); ec.argv[3] = 0; } #ifdef BOBCAT_DIY_CLOEXEC_ if (d_closedByChild != 0) close(d_closedByChild); #endif (*(d_processType == USE_PATH ? execvp : execv)) (ec.argv[0], const_cast(ec.argv)); throw Exception{} << "Process: cannot execv[p] " << d_command; } // std::cerr << "ChildOutput starts as:\n"; // for (char const **cp = ec.argv; *cp; ++cp) // std::cerr << " " << *cp << endl; // std::cerr << "======================\n"; bobcat-5.09.01/process/system4.f0000644000175000017500000000017714050437223015346 0ustar frankfrankinline void Process::system(IOMode mode, size_t timeLimit, size_t bufSize) { start(mode, USE_SHELL, timeLimit, bufSize); } bobcat-5.09.01/process/process4.cc0000644000175000017500000000030614050437223015632 0ustar frankfrank#include "process.ih" Process::Process(IOMode mode, ProcessType processType, size_t timeLimit, string const &command) : Process(mode, processType, timeLimit, 200, command) {} bobcat-5.09.01/process/newpipes.cc0000644000175000017500000000043014050437223015720 0ustar frankfrank#include "process.ih" void Process::newPipes() { if ((d_setMode & CIN) && not (d_setMode & IN_PIPE)) newPipe(d_oChildInPipe); if ((d_mode & (COUT | MERGE_COUT_CERR))) newPipe(d_iChildOutPipe); if (d_mode & CERR) newPipe(d_iChildErrPipe); } bobcat-5.09.01/process/start1.f0000644000175000017500000000013114050437223015142 0ustar frankfrankinline void Process::start() { start(d_setMode, d_setProcessType, d_setTimeLimit); } bobcat-5.09.01/process/discontinue.cc0000644000175000017500000000047614050437223016424 0ustar frankfrank#include "process.ih" pid_t Process::discontinue(RetPid &proc) { if (proc.pid > 0) { kill(proc.pid, SIGHUP) && kill(proc.pid, SIGHUP) && kill(proc.pid, SIGTERM); proc.pid = waitpid(proc.pid, &proc.ret, 0); } return proc.pid = 0; } bobcat-5.09.01/process/setiomode.f0000644000175000017500000000012614050437223015720 0ustar frankfrankinline void Process::setIOMode(IOMode mode) { d_setMode = sanitizeIOMode(mode); } bobcat-5.09.01/process/timelimit.f0000644000175000017500000000011014050437223015716 0ustar frankfrankinline size_t Process::timeLimit() const { return d_setTimeLimit; } bobcat-5.09.01/process/setcommand.f0000644000175000017500000000013114050437223016056 0ustar frankfrankinline void Process::setCommand(std::string const &command) { d_command = command; } bobcat-5.09.01/process/opfun2.f0000644000175000017500000000032714050437223015144 0ustar frankfrankinline Process &Process::operator()(IOMode mode, ProcessType type) { return operator()(mode & ~(IN_PIPE | OUT_PIPE | CLOSE_ON_EXEC), type, d_setTimeLimit); } bobcat-5.09.01/process/childoutstream.f0000644000175000017500000000014214050437223016755 0ustar frankfrankinline std::istream &Process::childOutStream() { return static_cast(*this); } bobcat-5.09.01/process/limiter.cc0000644000175000017500000000222114050437223015533 0ustar frankfrank#include "process.ih" void Process::limiter(Process *process) { size_t &timeLimit = process->d_timeLimit; if (timeLimit == 0) // no timelimit: thread immediately return; // ends unique_lock lock(process->d_mutex); // get the lock volatile ChildAction &action = process->d_action; action = TIME_LIMIT; // when the child process ends, signalHandler is called, which // sets d_action to CHILD_ENDED, and notifies this function: // the loop ends with CHILD_ENDED. Otherwise, the time limit is // reached and the wait_for ends with d_action == TIME_LIMIT while (action != CHILD_ENDED) { // When the time limit is reached // the loop breaks, and d_action is // TIME_LIMIT. if (process->d_condition.wait_for( lock, chrono::seconds(timeLimit)) == cv_status::timeout) break; } if (action == TIME_LIMIT) process->discontinue(process->d_child); } bobcat-5.09.01/process/escapedstring.x0000644000175000017500000000206314050437223016607 0ustar frankfrank#include "process.ih" // On entry, `begin' points at the beginning of the stand-alone escape // character. // On exit, the character is unescaped and returned, and `begin' points // immediately beyond the characters defining the escape-sequence. int Process::escapedString(ConstIter &begin, ConstIter const &end) { if (begin + 1 == end) // at least one char. should follow throw Exception() << "Process " << d_command << ": trailing \\"; string escaped(begin, end); // local copy of the escaped text // cut the copy at the next backslash escaped = escaped.substr(0, escaped.find('\\', 1)); size_t preLength = escaped.length(); // unescape the escape-sequence escaped = String::unescape(escaped); // reposition begin beyond the chars of // the escape sequence begin += 1 + preLength - escaped.length(); return escaped[0]; // return the escaped character } bobcat-5.09.01/process/start1.cc0000644000175000017500000000022514050437223015306 0ustar frankfrank#include "process.ih" void Process::start(size_t mode, ProcessType type, size_t timeLimit) { start(iomode(mode), type, timeLimit, bufSize()); } bobcat-5.09.01/process/process.ih0000644000175000017500000000101614050437223015560 0ustar frankfrank#include "process" #include #include #include #include #include #include #include #include "../redirector/redirector" #include "../exception/exception" using namespace std; using namespace FBB; struct Process::ExecContext { size_t argc; // must eventually be at least 1 char const **argv; // 0-terminated array of pointers to the // arguments }; #include "retpid1.f" bobcat-5.09.01/process/system1.f0000644000175000017500000000013014050437223015330 0ustar frankfrankinline void Process::system() { start(d_mode, USE_SHELL, d_timeLimit, bufSize()); } bobcat-5.09.01/process/available.cc0000644000175000017500000000015514050437223016012 0ustar frankfrank#include "process.ih" size_t Process::available() { d_selector.setAlarm(0); return whichStream(); } bobcat-5.09.01/process/str.f0000644000175000017500000000011114050437223014532 0ustar frankfrankinline std::string const &Process::str() const { return d_command; } bobcat-5.09.01/process/bufsize.f0000644000175000017500000000010114050437223015370 0ustar frankfrankinline size_t Process::bufSize() const { return d_bufSize; } bobcat-5.09.01/process/setbufsize.f0000644000175000017500000000014214050437223016111 0ustar frankfrankinline void Process::setBufSize(size_t bufSize) { d_bufSize = bufSize == 0 ? 1 : bufSize; } bobcat-5.09.01/process/close.cc0000644000175000017500000000034114050437223015174 0ustar frankfrank#include "process.ih" void Process::close() { d_oChildIn.flush(); d_oChildInPipe.close(); if (d_oChildIn.rdbuf() != 0) close(d_oChildInbuf.fd()); d_oChildIn.rdbuf(0); } bobcat-5.09.01/process/operatorfun2.cc0000644000175000017500000000042414050437223016517 0ustar frankfrank#include "process.ih" Process &Process::operator()(IOMode mode, ProcessType type, size_t timeLimit, size_t bufSize) { d_bufSize = bufSize; d_timeLimit = timeLimit; d_processType = type; sanitizeIOMode(mode); return *this; } bobcat-5.09.01/process/opextract.f0000644000175000017500000000030014050437223015733 0ustar frankfranktemplate Process &Process::operator>>(Type &value) { if ((available() & CHILD_COUT) || active()) dynamic_cast(*this) >> value; return *this; } bobcat-5.09.01/process/start3.f0000644000175000017500000000021514050437223015147 0ustar frankfrankinline void Process::start(IOMode mode, ProcessType type) { start(mode & ~(IN_PIPE | OUT_PIPE | CLOSE_ON_EXEC), type, d_setTimeLimit); } bobcat-5.09.01/process/waitforchild.cc0000644000175000017500000000017514050437223016553 0ustar frankfrank#include "process.ih" int Process::waitForChild() { int ret = Fork::waitForChild(); closePipes(); return ret; } bobcat-5.09.01/process/system2.f0000644000175000017500000000014114050437223015333 0ustar frankfrankinline void Process::system(IOMode mode) { start(mode, USE_SHELL, d_timeLimit, bufSize()); } bobcat-5.09.01/process/childredirections.cc0000644000175000017500000000241414050437223017570 0ustar frankfrank#include "process.ih" void Process::childRedirections() { if (d_mode & CIN) // CHILD PROCESS: d_oChildInPipe.readFrom(STDIN_FILENO); // reads from the pipe if (d_mode & MERGE_COUT_CERR) // cout/cerr to 1 pipe { int fd[] = { STDOUT_FILENO, STDERR_FILENO }; d_iChildOutPipe.writtenBy(fd, 2); } else { if (d_mode & COUT) // cout to a pipe d_iChildOutPipe.writtenBy(STDOUT_FILENO); if (d_mode & CERR) // cerr to another pipe d_iChildErrPipe.writtenBy(STDERR_FILENO); if (d_mode & (IGNORE_COUT | IGNORE_CERR)) // ignores cout/cerr { int fd = ::open("/dev/null", O_WRONLY); if (fd == -1) throw Exception{} << "Process " << d_command << ": can't open /dev/null"; Redirector redirector{ fd }; if (d_mode & IGNORE_COUT) // ignores COUT redirector.swallow(Redirector::STDOUT); if (d_mode & IGNORE_CERR) // ignores CERR redirector.swallow(Redirector::STDERR); } } } bobcat-5.09.01/process/parentredirections.cc0000644000175000017500000000173514050437223020003 0ustar frankfrank#include "process.ih" void Process::parentRedirections() { d_selector = Selector{}; if (d_setMode & CLOSE_ON_EXEC) closeChildInputOnExec(); if (d_mode & CIN) { int fd = d_oChildInPipe.writeOnly(); if (not (d_setMode & IN_PIPE)) { d_oChildInbuf.reset(fd, 200); d_oChildIn.rdbuf(&d_oChildInbuf); } } if (d_mode & (COUT | MERGE_COUT_CERR)) { int fd = d_iChildOutPipe.readOnly(); if (not (d_setMode & OUT_PIPE)) { d_iChildOutbuf.reset(fd, 200); d_iChildOut.rdbuf(&d_iChildOutbuf); d_selector.addReadFd(fd); } } else d_iChildOutPipe.closeWriteFd(); if (d_mode & CERR) { int fd = d_iChildErrPipe.readOnly(); d_iChildErrbuf.reset(fd, 200); d_iChildErr.rdbuf(&d_iChildErrbuf); d_selector.addReadFd(fd); } clear(); // clears IOStream's streams } bobcat-5.09.01/process/operatorinsert.cc0000644000175000017500000000026514050437223017154 0ustar frankfrank#include "process.ih" Process &Process::operator<<(std::ostream &(*pf)(std::ostream &)) { if (active()) static_cast(*this) << pf; return *this; } bobcat-5.09.01/process/settimelimit.f0000644000175000017500000000014614050437223016443 0ustar frankfrankinline void Process::setTimeLimit(size_t timeLimit) { d_setTimeLimit = d_timeLimit = timeLimit; } bobcat-5.09.01/process/destructor.cc0000644000175000017500000000015614050437223016271 0ustar frankfrank#include "process.ih" Process::~Process() { stop(); Signal::instance().remove(SIGCHLD, *this); } bobcat-5.09.01/process/operatorassign.cc0000644000175000017500000000031114050437223017124 0ustar frankfrank#include "process.ih" int Process::operator=(std::string const &command) { int ret = stop(); setCommand(command); start(d_mode, d_processType, d_timeLimit, bufSize()); return ret; } bobcat-5.09.01/process/quotedstring.x0000644000175000017500000000146314050437223016507 0ustar frankfrank#include "process.ih" // On entry, `begin' points at the beginning of the quoted string, on exit, // the quoted string (without the surrounding quotes) is returned, and 'begin' // points to the location immediately following the last quote. // // A single quoted string does not do \-escapes. string Process::quotedString(ConstIter &begin, ConstIter const &end) { string quoted; while (true) { if (++begin == end) throw Exception() << "Process " << d_command << ": unmatched '"; if (*begin == '\'') // stop at the next single quote { ++begin; // skip it return quoted; // and return the string's contents } quoted += *begin; // otherwise add the next char } } bobcat-5.09.01/process/signalhandler.cc0000644000175000017500000000026414050437223016706 0ustar frankfrank#include "process.ih" void Process::signalHandler(size_t signal) { if (d_action == TIME_LIMIT) { d_action = CHILD_ENDED; d_condition.notify_one(); } } bobcat-5.09.01/process/sanitizeiomode.cc0000644000175000017500000000167314050437223017123 0ustar frankfrank#include "process.ih" Process::IOMode Process::sanitizeIOMode(IOMode mode) { if (mode & ~ALL_IOMODES) throw invalid_argument("Undefined IOMode"); if ((mode & DIRECT) && (mode & ~DIRECT)) throw invalid_argument("IOModes cannot be combined with DIRECT"); if ((mode & IGNORE_CERR) && (mode & (CERR | MERGE_COUT_CERR))) throw invalid_argument( "IOMode IGNORE_CERR cannot be combined with modes " "CERR or MERGE_COUT_CERR"); if ((mode & IGNORE_COUT) && (mode & (COUT | MERGE_COUT_CERR))) throw invalid_argument( "IOMode IGNORE_COUT cannot be combined with modes " "COUT or MERGE_COUT_CERR"); if ((mode & MERGE_COUT_CERR) && (mode & (CERR | COUT))) throw invalid_argument( "IOMode MERGE_COUT_CERR cannot be combined with modes " "COUT or CERR"); return d_mode = mode; } bobcat-5.09.01/process/setprocesstype.f0000644000175000017500000000014714050437223017027 0ustar frankfrankinline void Process::setProcessType(ProcessType type) { d_setProcessType = d_processType = type; } bobcat-5.09.01/process/opaddis.f0000644000175000017500000000016014050437223015351 0ustar frankfrankinline Process &Process::operator+=(std::string const &command) { d_command += command; return *this; } bobcat-5.09.01/process/start2.f0000644000175000017500000000026014050437223015146 0ustar frankfrankinline void Process::start(IOMode mode) { start(mode & ~(IN_PIPE | OUT_PIPE | CLOSE_ON_EXEC), d_setProcessType, d_setTimeLimit); } bobcat-5.09.01/process/process0000644000175000017500000002113114050437223015161 0ustar frankfrank#ifndef INCLUDED_BOBCAT_PROCESS_ #define INCLUDED_BOBCAT_PROCESS_ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(__FreeBSD_kernel__) || defined(__FreeBSD__) #ifndef BOBCAT_DIY_CLOEXEC_ #define BOBCAT_DIY_CLOEXEC_ #endif #endif namespace FBB { struct Process: private Fork, private SignalHandler, public IOStream, public ProcessEnums { friend Process &operator|(Process &lhs, Process &rhs); enum ProcessType { NO_PATH, USE_PATH, USE_SHELL }; private: bool d_active; IOMode d_mode; size_t d_timeLimit; // seconds allowed to child-process ProcessType d_processType; size_t d_setMode; // these values are set by the size_t d_setTimeLimit; // set members and used as ProcessType d_setProcessType; // defaults unless overridden by // actual values // Constructors set these values // too. std::string d_command; Pipe d_oChildInPipe; // cin read by the CHILD Pipe d_iChildOutPipe; // cout written by the CHILD Pipe d_iChildErrPipe; // cerr written by the CHILD OFdBuf d_oChildInbuf; // Child extracts, IFdBuf d_iChildOutbuf; // Child inserts, IFdBuf d_iChildErrbuf; // Child inserts std::ostream d_oChildIn; // Parent inserts to child's cin std::istream d_iChildOut; // Parent extracts child's cout std::istream d_iChildErr; // Parent extracts child's cerr Selector d_selector; // senses activities on Child's // out/err streams struct RetPid { int ret; pid_t pid; RetPid(); // 1.f }; RetPid d_child; std::thread d_limit; volatile ChildAction d_action = CHILD_ENDED; std::mutex d_mutex; std::condition_variable d_condition; size_t d_bufSize; int d_exitStatus; #ifdef BOBCAT_DIY_CLOEXEC_ int d_closedByChild = 0; // DIY CLOSE_ON_EXEC #endif public: explicit Process(std::string const &command = ""); // 1 explicit Process(IOMode iomode, std::string const &command = ""); // 2 Process(IOMode mode, ProcessType type, // 3 std::string const &command = ""); Process(IOMode mode, ProcessType type, size_t timeLimit, // 4 std::string const &command = ""); Process(IOMode mode, ProcessType type, size_t timeLimit, // 5 size_t bufSize, std::string const &command = ""); Process(Process const &other) = delete; ~Process() override; // stop()s any ongoing process Process &operator=(Process const &other) = delete; size_t bufSize() const; // returns current buffer size .f IOMode ioMode() const; // returns default IOMode .f ProcessType processType() const; // returns default ProcessType .f size_t timeLimit() const; // returns default time limit .f void setBufSize(size_t bufSize); // .f void setIOMode(IOMode mode); // change IOMode .f void setProcessType(ProcessType type); // .f void setTimeLimit(size_t timeLimit); // .f // for the next cmd to start // 0 means: no time monitor void setCommand(std::string const &command); // sets cmd, .f Process &operator+=(std::string const &text); // opaddis.f // adds to the command void start(); // 1.f void start(IOMode mode); // 2.f void start(IOMode mode, ProcessType type); // 3.f void start(size_t mode, ProcessType type, size_t timeLimit); // 1 void start(IOMode mode, ProcessType type, // 2 size_t timeLimit, size_t bufSize); void system(); // calls /bin/sh -c cmd; 1.f // shell redirs OK void system(IOMode mode); // 2.f void system(IOMode mode, size_t timeLimit); // 3.f void system(IOMode mode, size_t timeLimit, size_t bufSize); // 4.f int operator=(std::string const &cmd); // sets and starts a command std::string const &str() const; // current command .f template Process &operator<<(Type const &value); // opinsert.f template Process &operator>>(Type &value); // opextract.f Process &operator<<(std::ostream &(*pf)(std::ostream &)); int stop(); // terminate a running childprocess void close(); // closes input to the child int eoi(); // closes input and waits for // the child to end using Fork::waitForChild; int exitStatus() const; // .f bool active(); Process &operator()(IOMode mode); // opfun1.f Process &operator()(IOMode mode, ProcessType type); // opfun2.f // operatorfun1.cc Process &operator()(IOMode mode, ProcessType type, size_t timeLimit); Process &operator()(IOMode mode, ProcessType type, // operatorfun2.cc size_t timeLimit, size_t bufSize); std::istream &childErrStream(); // READ cerr from the child std::istream &childOutStream(); // .f // READ cout from the child // (also: direct through // extraction) size_t available(); // returns ChildOutput bit_or // (cf. manpage) int waitForChild(); void showMode(char const *lab) const; private: void childRedirections() override; void childProcess() override; void parentRedirections() override; void parentProcess() override; void signalHandler(size_t signum) override; void eoi_() override; void newPipe(Pipe &pipe); // close and reopen pipe. void newPipes(); // close and reopen all necessary // pipes pid_t discontinue(RetPid &proc); ChildOutput whichStream(); void close(int fd); void closePipes(); void rmBackticks(); void forking(); IOMode sanitizeIOMode(IOMode mode); void closeChildInputOnExec(); typedef std::string::const_iterator ConstIter; struct ExecContext; ExecContext analyzeCommand(); static void limiter(Process *process); }; #include "bufsize.f" #include "childoutstream.f" #include "exitstatus.f" #include "iomode.f" #include "opaddis.f" #include "opextract.f" #include "opfun1.f" #include "opfun2.f" #include "opinsert.f" #include "processtype.f" #include "setbufsize.f" #include "setcommand.f" #include "setiomode.f" #include "setprocesstype.f" #include "settimelimit.f" #include "start1.f" #include "start2.f" #include "start3.f" #include "str.f" #include "system1.f" #include "system2.f" #include "system3.f" #include "system4.f" #include "timelimit.f" } // FBB #endif bobcat-5.09.01/process/eoi1.cc0000644000175000017500000000017614050437223014732 0ustar frankfrank#include "process.ih" int Process::eoi() { eoi_(); // *this << FBB::eoi; return exitStatus(); } bobcat-5.09.01/process/active.cc0000644000175000017500000000044314050437223015345 0ustar frankfrank#include "process.ih" bool Process::active() { if (d_child.pid != 0) { int retChild = waitpid(d_child.pid, &d_child.ret, WNOHANG); if (retChild == d_child.pid) d_child.pid = 0; // process has ended } return d_child.pid; } bobcat-5.09.01/process/process5.cc0000644000175000017500000000151714050437223015640 0ustar frankfrank#include "process.ih" Process::Process(IOMode mode, ProcessType processType, size_t timeLimit, size_t bufSize, string const &command) : d_active(false), d_timeLimit(timeLimit), d_processType(processType), d_setTimeLimit(timeLimit), d_setProcessType(processType), d_command(command), d_oChildInPipe(false), // cin read by the CHILD d_iChildOutPipe(false), // cout written by the CHILD d_iChildErrPipe(false), // cerr written by the CHILD d_oChildIn(0), // initialize the streams with 0-buffers d_iChildOut(0), d_iChildErr(0), d_bufSize(bufSize == 0 ? 1 : bufSize) { Signal::instance().add(SIGCHLD, *this); d_setMode = sanitizeIOMode(mode); // connect the input and output streams to Process open(d_iChildOut, d_oChildIn); } bobcat-5.09.01/process/split.x0000644000175000017500000000241314050437223015106 0ustar frankfrank#include "process.ih" vector Process::split(ConstIter begin, ConstIter const &end) { vector ret; string next; for (; begin != end; ) { switch (*begin) { case '"': // dquoted string: accept all until the // next, and then do unescape. next += dquotedString(begin, end); break; case '\'': // quoted string: accept all until // the next ', without unescaping next += quotedString(begin, end); break; case '\\': // unescape a lone escape sequence next += escapedString(begin, end); break; case ' ': // mere blanks end the current element. case '\t': if (next.length()) { ret.push_back(next); next.clear(); } ++begin; break; default: // add remaining chars to the next element next += *begin++; break; } } if (next.length()) // add any remaining element ret.push_back(next); return ret; } bobcat-5.09.01/process/processtype.f0000644000175000017500000000013214050437223016305 0ustar frankfrankinline Process::ProcessType Process::processType() const { return d_setProcessType; } bobcat-5.09.01/process/close2.cc0000644000175000017500000000013614050437223015260 0ustar frankfrank#include "process.ih" void Process::close(int fd) { if (fd != -1) ::close(fd); } bobcat-5.09.01/process/rmbackticks.cc0000644000175000017500000000044314050437223016367 0ustar frankfrank#include "process.ih" void Process::rmBackticks() { if (d_command.front() == '`' && d_command.back() == '`') // rm backticks { d_command.resize(d_command.length() - 1); // rm last backtick d_command.erase(0, 1); // rm front backtick } } bobcat-5.09.01/process/start2.cc0000644000175000017500000000163414050437223015314 0ustar frankfrank#include "process.ih" void Process::start(IOMode mode, ProcessType type, size_t timeLimit, size_t bufferSize) { if (d_active) stop(); size_t savedBufSize = bufSize(); setBufSize(bufferSize); d_active = true; d_timeLimit = timeLimit; d_processType = type; rmBackticks(); // rm backticks from d_command sanitizeIOMode(mode); // not yet using the time limit // thread d_limit = thread(limiter, this); forking(); // execute the requested command setBufSize(savedBufSize); d_mode = static_cast(d_setMode); // revert to the default // process d_processType = d_setProcessType; // parameters for a next run d_timeLimit = d_setTimeLimit; } bobcat-5.09.01/process/system3.f0000644000175000017500000000016114050437223015336 0ustar frankfrankinline void Process::system(IOMode mode, size_t timeLimit) { start(mode, USE_SHELL, timeLimit, bufSize()); } bobcat-5.09.01/process/process2.cc0000644000175000017500000000020214050437223015623 0ustar frankfrank#include "process.ih" Process::Process(IOMode mode, std::string const &command) : Process(mode, NO_PATH, 0, 200, command) {} bobcat-5.09.01/process/analyzecommand.cc0000644000175000017500000000142114050437223017071 0ustar frankfrank#include "process.ih" Process::ExecContext Process::analyzeCommand() { // split the elements in d_command String::Type type; vector elements(String::split(&type, d_command)); if (type != String::NORMAL) throw Exception{} << "Process: " << d_command << ": ill-formed"; ExecContext ec = {0, new char const *[elements.size() + 1]}; for (auto str: elements) // copy the elements to ec.args ec.argv[ec.argc++] = (new string(str))->c_str(); // the allocated memory is never returned, but that's OK as the // program's execution ends and the args are passed over to the child // process. ec.argv[ec.argc] = 0; // terminate in a null ptr return ec; } bobcat-5.09.01/process/driver/0000755000175000017500000000000014050437223015055 5ustar frankfrankbobcat-5.09.01/process/driver/build0000755000175000017500000000327314050437223016107 0ustar frankfrank#!/bin/sh precompile() { cd .. cd ../signal icmbuild cd ../processdata icmbuild cd ../process icmbuild cd driver } compile() { precompile echo compiling $1.cc $2 g++ `cat ../../c++std` -o $1 $2 $1.cc \ -L../tmp -lprocess \ -L../../processdata/tmp -lprocessdata \ -L../../signal/tmp -lsignal \ -lbobcat -s } case $1 in (pipe|gpg|sha1sum|limit|ls) compile $1 ;; (sort|thread) compile $1 -pthread ;; (all) compile cincoutcerr compile $1 -pthread ;; (clean) rm -f pipe gpg sort sha1sum thread limit ls all cincoutcerr rm -rf ../tmp ../../*/tmp ;; (*) echo " Provide the name of the test as first argument. The executable receives the name of the test. The test-name plus .cc extension is the name of the test program source file. Available tests are: all - stdin is split over stdout and stderr using multi-threading gpg - stdin is a PGP encrypted file, stdout is the decrypted file, stderr shows the result of the signature verification limit - limits process time to 5 seconds, while copying stdin to stdout using /bin/cat ls - show directory contents: no input, only std output pipe - stdin is passed through 3 /bin/cat programs, and is then written to stdout sha1sum - compute the input's sha1sum not using multi-threading sort - multi threading is used when sorting stdin to stdout, where sort's output is extracted from the Process object thread - compute the input's sha1sum using multi-threading clean - not a test, but removes the test binaries " ;; esac bobcat-5.09.01/process/driver/driver.cc0000644000175000017500000000641414050437223016664 0ustar frankfrank//#ifdef BOBCAT #include //#else // #include "process" //#endif #include #include #include using namespace std; using namespace FBB; void prompt(char const *task) { cout << "Press Enter to start " << task << endl; cin.ignore(INT_MAX, '\n'); } int main(int argc, char **argv) try { cout << "Size of Process: " << sizeof(Process) << endl; string line; // Nota bene: without IOMode you get CIN, COUT and CERR Process p1(Process::CIN, "/bin/cat"); Process p2(Process::NONE, "/bin/cat"); Process p3(Process::NONE, "/bin/cat"); prompt("sending lines (until empty) to cat | cat | cat"); (p1 | p2 | p3).start(); while (getline(cin, line) && not line.empty()) { cout << "Entering " << line << endl; p3 << line << endl; } p3.close(); p3.waitForChild(); // // Process process(Process::CIN | Process::COUT, // "/usr/bin/sha1sum"); // // prompt("sha1sum"); // process.start(); // process << "Hello world\n"; // input to sha1sum // process.close(); // process >> line; // retrieve the value // cout << line << endl; // process.stop(); // // prompt("cat, ignoring its output"); // process.setCommand("/bin/cat"); // process.setIOMode(Process::CIN | Process::IGNORE_COUT); // // process.start(); // process << "Hello world\n"; // input to sha1sum // process.close(); // // line.clear(); // if (process >> line) // retrieve the value // cout << ">>>" << line << "<<<" << endl; // process.stop(); // // //// if (argc > 1) // sending an e-mail //// { //// cout << "Sending mail to " << argv[1] << endl; //// prompt("/usr/bin/mail"); //// process.setCommand("/usr/bin/mail -s 'from Process' "); //// process += argv[1]; //// process.start(Process::CIN); //// process << "This mail was sent by the process drive\n"; //// process << "It consists of multiple lines of text\n"; //// process.close(); //// process.waitForChild(); //// } // // prompt("5 seconds IO to /bin/cat"); // process.setIOMode(Process::CIN | Process::COUT); // process.setTimeLimit(5); // change time limit // // process = "/bin/cat"; // while (process.active()) // { // cout << "? "; // getline(cin, line); // process << line << endl; // to /bin/cat // line.clear(); // if (!getline(process, line)) // from /bin/cat // break; // cout << "Received: " << line << endl; // } // cout << "/bin/cat forcefully terminated\n"; // // process.setTimeLimit(0); // // cout << "3 times running /bin/ls\n"; // // for (size_t trial = 0; trial < 3; ++trial) // { // prompt("ls"); // // process(Process::COUT) = "/bin/ls"; // // cerr << process.str() << endl; // size_t count = 0; // while (getline(process, line)) // cout << ++count << ": " << line << endl; // } // } catch (exception const &err) { cerr << "CAUGHT EXCEPTION: " << err.what() << endl; return 1; } catch (bool) { return 0; } catch (...) { cerr << "Unrecognized exception in main()\n"; return 0; } bobcat-5.09.01/process/driver/gpg.cc0000644000175000017500000000063614050437223016146 0ustar frankfrank#include "../../processenums/processenums" #include "../../processdata/processdata.decl" #include "../process" #include using namespace std; using namespace FBB; int main() try { Process gpg(Process::CIN, "/usr/bin/gpg --quiet --batch --decrypt"); gpg.start(); gpg << cin.rdbuf() << eoi; } catch (exception const &err) { cerr << err.what() << endl; } catch (int x) { return 0; } bobcat-5.09.01/process/driver/spawn/0000755000175000017500000000000014050437223016205 5ustar frankfrankbobcat-5.09.01/process/driver/spawn/parentprocess.cc0000644000175000017500000000012514050437223021402 0ustar frankfrank#include "spawn.ih" void Spawn::parentProcess() { d_insertPipe.writeOnly(); } bobcat-5.09.01/process/driver/spawn/childprocess.cc0000644000175000017500000000054014050437223021175 0ustar frankfrank#include "spawn.ih" void Spawn::childProcess() { vector cmd(String::split(static_cast(0), d_command)); char const **args = String::argv(cmd); execv(args[0], const_cast(args)); throw 0; // this should not be reached, but if so main properly ends. } bobcat-5.09.01/process/driver/spawn/end.cc0000644000175000017500000000016314050437223017262 0ustar frankfrank#include "spawn.ih" void Spawn::end() { flush(); ::close(d_insertPipe.writeFd()); waitForChild(); } bobcat-5.09.01/process/driver/spawn/spawn.ih0000644000175000017500000000030114050437223017651 0ustar frankfrank#include "spawn.h" #include #include #include #include #include #include using namespace std; using namespace FBB; bobcat-5.09.01/process/driver/spawn/spawn1.cc0000644000175000017500000000057014050437223017727 0ustar frankfrank#include "spawn.ih" // 1: program[0] // 2: command // 3: cin-name // 4: cout-name // 5: cerr-name Spawn::Spawn(std::string const &command) : d_command(command), d_insertBuffer(d_insertPipe.writeFd(), 10000) // d_extractBuffer(d_extractPipe.readOnly()), // d_errStream(d_errPipe.readOnly()) { rdbuf(&d_insertBuffer); // rdbuf(&d_extractBuffer); } bobcat-5.09.01/process/driver/spawn/main.cc0000644000175000017500000000035214050437223017440 0ustar frankfrank#include "spawn.h" using namespace std; int main(int argc, char **argv) try { Spawn spawn(argv[1]); ifstream in(argv[2]); spawn.fork(); spawn << in.rdbuf(); spawn.end(); } catch (int x) { return 0; } bobcat-5.09.01/process/driver/spawn/spawn.h0000644000175000017500000000137614050437223017515 0ustar frankfrank#ifndef INCLUDED_SPAWN_ #define INCLUDED_SPAWN_ #include #include #include #include #include #include #include #include class Spawn: public FBB::Fork, public std::ostream// , public std::istream { FBB::Pipe d_insertPipe; // FBB::Pipe d_extractPipe; // FBB::Pipe d_errPipe; FBB::OFdBuf d_insertBuffer; // FBB::IFdBuf d_extractBuffer; // FBB::IFdStream d_errStream; std::string d_command; public: Spawn(std::string const &command); void end(); private: void childProcess() override; void parentProcess() override; void childRedirections() override; }; #endif bobcat-5.09.01/process/driver/spawn/childredirections.cc0000644000175000017500000000027314050437223022214 0ustar frankfrank#include "spawn.ih" void Spawn::childRedirections() { d_insertPipe.readFrom(STDIN_FILENO); // d_extractPipe.writtenBy(STDOUT_FILENO); // d_errPipe.writtenBy(STDERR_FILENO); } bobcat-5.09.01/process/driver/sha1sum.cc0000644000175000017500000000103014050437223016737 0ustar frankfrank#include #include #include "../../processenums/processenums" #include "../../processdata/processdata.decl" #include "../process" using namespace std; using namespace FBB; int main() try { Process sha1sum(Process::CIN | Process::COUT, "/usr/bin/sha1sum"); sha1sum.start(); sha1sum << cin.rdbuf() << eoi; string line; while (getline(sha1sum, line)) cout << line << '\n'; } catch (exception const &err) { cerr << err.what() << endl; return 1; } catch (int x) { return 1; } bobcat-5.09.01/process/driver/sort.cc0000644000175000017500000000101014050437223016343 0ustar frankfrank#include #include #include "../../processenums/processenums" #include "../process" using namespace std; using namespace FBB; void collect(streambuf *buf) { cout << buf; } int main() try { Process sort(Process::CIN | Process::COUT, "/usr/bin/sort"); sort.start(); thread out(collect, sort.childOutStream().rdbuf()); sort << cin.rdbuf() << eoi; out.join(); } catch (exception const &err) { cerr << err.what() << endl; return 1; } catch (int x) { return 1; } bobcat-5.09.01/process/driver/ls.cc0000644000175000017500000000050314050437223016000 0ustar frankfrank#include #include "../../processenums/processenums" #include "../../processdata/processdata.decl" #include "../process" using namespace std; using namespace FBB; //CODE int main() { Process process(Process::COUT, "/bin/ls -Fla"); process.start(); cout << process.childOutStream().rdbuf(); } //= bobcat-5.09.01/process/driver/thread.cc0000644000175000017500000000101014050437223016623 0ustar frankfrank//#include #include "../process" #include #include using namespace std; using namespace FBB; void collect(streambuf *buf) { cout << buf; } int main() try { Process sha1sum(Process::CIN | Process::COUT, "/usr/bin/sha1sum"); sha1sum.start(); thread out(collect, sha1sum.childOutStream().rdbuf()); sha1sum << cin.rdbuf() << eoi; out.join(); } catch (exception const &err) { cerr << err.what() << endl; return 1; } catch (int x) { return 1; } bobcat-5.09.01/process/driver/all.cc0000644000175000017500000000122114050437223016130 0ustar frankfrank#include #include #include #include "../../processenums/processenums" #include "../../processdata/processdata.decl" #include "../process" using namespace FBB; using namespace std; //CODE void collect(ostream *outStream, streambuf *rdbuf) { *outStream << rdbuf << flush; } int main() { string cmd(getcwd(0, 0)); cmd += "/cincoutcerr"; Process all(Process::ALL, cmd); all.start(); thread outThread(collect, &cout, all.childOutStream().rdbuf()); thread errThread(collect, &cerr, all.childErrStream().rdbuf()); all << cin.rdbuf() << eoi; outThread.join(); errThread.join(); } //= bobcat-5.09.01/process/driver/pipe.cc0000644000175000017500000000060714050437223016324 0ustar frankfrank#include #include "../../processenums/processenums" #include "../process" using namespace std; using namespace FBB; int main() { // Nota bene: by default IOMode equals Process::ALL Process p1(Process::CIN, "/bin/cat"); Process p2(Process::NONE, "/bin/cat"); Process p3(Process::NONE, "/bin/cat"); (p1 | p2 | p3).start(); p3 << cin.rdbuf() << eoi; } bobcat-5.09.01/process/driver/cincoutcerr.cc0000644000175000017500000000060314050437223017703 0ustar frankfrank#include using namespace std; // Generates output to cout and cerr, and reads cin int main() { string line; size_t count = 0; while (getline(cin, line)) { ++count; if (count % 5 == 0) cerr << "Cerr line " << count << ": " << line << endl; else cout << "Cout line " << count << ": " << line << endl; } } bobcat-5.09.01/process/driver/discontinue/0000755000175000017500000000000014050437223017401 5ustar frankfrankbobcat-5.09.01/process/driver/discontinue/build0000755000175000017500000000005214050437223020423 0ustar frankfrank#!/bin/sh g++ -o driver *.cc -lbobcat -s bobcat-5.09.01/process/driver/discontinue/demo.cc0000644000175000017500000000464714050437223020647 0ustar frankfrank#include #include #include #include #include pid_t discontinue(pid_t procId); extern char **environ; using namespace std; using namespace FBB; int main(int argc, char **argv) { if (argc == 1) { cout << "a.out sleep-1 sleep-2\n" "\n"; return 1; } pid_t p1 = fork(); if (p1 < 0) { cout << "Fork 1 failed\n"; return 1; } if (p1 == 0) // child runs the process { // char *name[] = {argv[1], 0}; // cout << "Child 1 starts " << argv[1] << endl; // execve(name[0], name, environ); // cout << "Child 1 failed\n"; // return 1; size_t sleepTime = stoul(argv[1]); cout << "Child 1 sleeps for " << sleepTime << "secs\n"; sleep(sleepTime); cout << "Child 1 wakes up\n"; return 0; // stop after waking up } cout << "Started process 1: " << p1 << endl; // parent process continues pid_t p2 = fork(); // child waits at most arg2 seconds if (p2 < 0) { cout << "Fork 2 failed\n"; p1 = discontinue(p1); return 1; } if (p2 == 0) // child runs the process { size_t sleepTime = stoul(argv[2]); cout << "Child 2 sleeps for " << sleepTime << "secs\n"; sleep(sleepTime); cout << "Child 2 wakes up\n"; return 0; // stop after waking up } cout << "Started sleeper process 2: " << p2 << endl; string cmd; while (p1 || p2) { cout << "Enter a command\n"; getline(cin, cmd); cout << "Command entered: " << cmd << endl; if (p1) { if (waitpid(p1, 0, WNOHANG) > 0) // p1 has changed { cout << "Process 1 (" << p1 << ") has stopped\n"; p1 = 0; p2 = discontinue(p2); } } if (p2) { if (waitpid(p2, 0, WNOHANG) > 0) // p1 has changed { cout << "Process 2 (" << p2 << ") has stopped\n" "Forcefully end process 1 (" << p1 << ")\n"; p2 = 0; p1 = discontinue(p1); } } } cout << "Ending. All child processes should have disappeared\n" "(Press enter to end this program) "; getline(cin, cmd); } bobcat-5.09.01/process/driver/discontinue/discontinue.cc0000644000175000017500000000077314050437223022243 0ustar frankfrank#include #include #include #include using namespace std; pid_t discontinue(pid_t procId) { if (procId == 0) return 0; int ret; if ((ret = kill(procId, SIGHUP)) && (ret = kill(procId, SIGHUP))) ret = kill(procId, SIGKILL); cout << "Process " << procId << " killed with return value " << ret << endl; if (!ret) wait(0); return 0; } bobcat-5.09.01/process/driver/manual/0000755000175000017500000000000014050437223016332 5ustar frankfrankbobcat-5.09.01/process/driver/manual/data.cc0000644000175000017500000000066714050437223017563 0ustar frankfrank#include "main.ih" auto_ptr d_child_inp; // cin read by the CHILD auto_ptr d_child_outp; // cout written by the CHILD OFdBuf d_childCinbuf; IFdBuf d_childCoutbuf; ostream d_childCin(0); // Parent inserts child cin istream d_childCout(0); // Parent extr. child cout IOStream io(d_childCout, d_childCin); pid_t pid; string line; int p1; int p2; int oldIn; int oldOut; bobcat-5.09.01/process/driver/manual/childls.cc0000644000175000017500000000024114050437223020260 0ustar frankfrank#include "main.ih" void childLs() { char *args[] = {const_cast("/bin/ls"), 0}; execv(args[0], args); std::cerr << "CHILD FORK FAILED\n"; } bobcat-5.09.01/process/driver/manual/parentcat.cc0000644000175000017500000000073014050437223020622 0ustar frankfrank#include "main.ih" void parentCat() { while (true) { cout << "Empty line stops, q breaks echoing: "; if (!getline(cin, line)) { cout << "End of input: exiting\n"; throw 0; } if (line == "") return; if (line == "q") throw false; io << line << endl; line.erase(); getline(io, line); cout << "received line: " << line << endl; } } bobcat-5.09.01/process/driver/manual/newpipes.cc0000644000175000017500000000035414050437223020475 0ustar frankfrank#include "main.ih" void newPipes() { oldIn = d_child_inp.get() ? d_child_inp->writeFd() : -1; oldOut = d_child_outp.get() ? d_child_outp->readFd() : -1; d_child_inp.reset(newPipe()); d_child_outp.reset(newPipe()); } bobcat-5.09.01/process/driver/manual/childsha1.cc0000644000175000017500000000025514050437223020503 0ustar frankfrank#include "main.ih" void childSha1() { char *args[] = {const_cast("/usr//bin/sha1sum"), 0}; execv(args[0], args); std::cerr << "CHILD FORK FAILED\n"; } bobcat-5.09.01/process/driver/manual/parentredirs.cc0000644000175000017500000000054114050437223021343 0ustar frankfrank#include "main.ih" void parentRedirections() { d_childCinbuf.open(p1 = d_child_inp->writeOnly()); d_childCin.rdbuf(&d_childCinbuf); d_childCoutbuf.open(p2 = d_child_outp->readOnly()); d_childCout.rdbuf(&d_childCoutbuf); if (oldIn != -1) ::close(oldIn); if (oldOut != -1) ::close(oldOut); io.clear(); } bobcat-5.09.01/process/driver/manual/mewpipe.cc0000644000175000017500000000015014050437223020303 0ustar frankfrank#include "main.ih" Pipe *newPipe() { Pipe *ret = new Pipe; ret->verify(); return ret; } bobcat-5.09.01/process/driver/manual/close.cc0000644000175000017500000000021314050437223017742 0ustar frankfrank#include "main.ih" void close() { ::close(d_child_inp->writeFd()); d_child_inp.reset(newPipe()); d_child_inp->writeOnly(); } bobcat-5.09.01/process/driver/manual/redirchild.cc0000644000175000017500000000022714050437223020753 0ustar frankfrank#include "main.ih" void redirectChild() { d_child_inp->readFrom(STDIN_FILENO); // set up the pipes d_child_outp->writtenBy(STDOUT_FILENO); } bobcat-5.09.01/process/driver/manual/main.cc0000644000175000017500000000303114050437223017562 0ustar frankfrank#include "main.ih" int main(int argc, char **argv) try { cout << "Enter for sha1sum\n"; if (getline(cin, line)) { // start.cc newPipes(); // forking.cc if ((pid = fork()) < 0) return 1; if (pid == 0) // child { redirectChild(); childSha1(); } parentRedirections(); parentCloseIn(); finalization(); } cout << "Enter for manual cat\n"; if (getline(cin, line)) { try { while (true) { newPipes(); if ((pid = fork()) < 0) return 1; if (pid == 0) // child { redirectChild(); childEchoes(); return 0; } parentRedirections(); parentCat(); finalization(); } } catch (bool) {} } cout << "Enter for ls-list\n"; if (getline(cin, line)) { newPipes(); if ((pid = fork()) < 0) return 1; if (pid == 0) // child { redirectChild(); childLs(); } parentRedirections(); parentOut(); finalization(); } } catch (...) { return 1; } bobcat-5.09.01/process/driver/manual/parentout.cc0000644000175000017500000000021614050437223020661 0ustar frankfrank#include "main.ih" void parentOut() { size_t count = 0; while (getline(io, line)) cout << ++count<< ": " << line << endl; } bobcat-5.09.01/process/driver/manual/main.ih0000644000175000017500000000211614050437223017600 0ustar frankfrank#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; using namespace FBB; extern std::auto_ptr d_child_inp; // cin read by the CHILD extern std::auto_ptr d_child_outp; // cout written by the CHILD extern OFdBuf d_childCinbuf; extern IFdBuf d_childCoutbuf; extern ostream d_childCin; // Parent inserts child cin extern istream d_childCout; // Parent extr. child cout extern IOStream io; extern int p1; extern int p2; extern int oldIn; extern int oldOut; extern pid_t pid; extern string line; void close(); Pipe *newPipe(); void newPipes(); void redirectChild(); void childEchoes(); void childLs(); void childSha1(); void parentRedirections(); void parentCat(); void parentOut(); void parentCloseIn(); void finalization(); bobcat-5.09.01/process/driver/manual/childechoes.cc0000644000175000017500000000027114050437223021113 0ustar frankfrank#include "main.ih" void childEchoes() { while (getline(cin, line)) { cerr << "Child receives: " << line << endl; cout << "Child saw: " << line << endl; } } bobcat-5.09.01/process/driver/manual/parentclosein.cc0000644000175000017500000000023214050437223021504 0ustar frankfrank#include "main.ih" void parentCloseIn() { io << "Hello world" << endl; close(); while (getline(io, line)) cout << line << endl; } bobcat-5.09.01/process/driver/manual/finalization.cc0000644000175000017500000000030714050437223021330 0ustar frankfrank#include "main.ih" void finalization() { cout << "USed pipes " << p1 << ", " << p2 << endl; kill(pid, SIGTERM); cout << "Wait returns " << wait(0) << ", child pid = " << pid << endl; } bobcat-5.09.01/process/driver/pipes/0000755000175000017500000000000014050437223016175 5ustar frankfrankbobcat-5.09.01/process/driver/pipes/demo.cc0000644000175000017500000000166414050437223017437 0ustar frankfrank#include #include #include #include #include #include #include using namespace FBB; using namespace std; int main () { pid_t pid; Pipe pin; Pipe pout; pin.verify(); pout.verify(); pid = vfork(); if (pid == (pid_t) 0) { pin.readFrom(STDIN_FILENO); pout.writtenBy(STDOUT_FILENO); execl("/usr/bin/sha1sum", "sha1sum", 0); perror("exec prog1"); return 1; } else { close(pout.writeFd()); close(pin.readFd()); OFdStream out(pin.writeFd()); out << "These are the data" << endl; close(pin.writeFd()); IFdStream in(pout.readFd()); string line; while (getline(in, line)) cerr << line << endl; waitpid(pid, NULL, 0); close(pout.readFd()); return 0; } } bobcat-5.09.01/process/driver/limit.cc0000644000175000017500000000126714050437223016510 0ustar frankfrank#include #include "../../processenums/processenums" #include "../process" using namespace std; using namespace FBB; //CODE int main() { Process process(Process::CIN | Process::COUT, "/bin/cat"); process.setTimeLimit(5); process.start(); while (true) { cout << "? "; string line; if (not getline(cin, line)) return 0; process << line << endl; // to /bin/cat line.clear(); if (not getline(process, line)) // from /bin/cat break; cout << "Received: " << line << endl; } cout << "/bin/cat time limit of 5 seconds reached: child process ended\n"; } //= bobcat-5.09.01/process/closechildinputonexec.cc0000644000175000017500000000104314050437223020462 0ustar frankfrank#include "process.ih" void Process::closeChildInputOnExec() { #ifdef BOBCAT_DIY_CLOEXEC_ int writeDup[] = { d_oChildInPipe.readFd(), fcntl(d_oChildInPipe.writeOnly(), F_DUPFD, 4) }; d_closedByChild = writeDup[1]; #else int writeDup[] = { d_oChildInPipe.readFd(), fcntl(d_oChildInPipe.writeOnly(), F_DUPFD_CLOEXEC, 4) }; #endif // OFdBuf set at parentRedirections d_oChildInPipe = Pipe{ writeDup }; } bobcat-5.09.01/processenums/0000755000175000017500000000000014050437223014632 5ustar frankfrankbobcat-5.09.01/processenums/processenums0000644000175000017500000000713114050437223017305 0ustar frankfrank#ifndef INCLUDED_BOBCAT_PROCESSENUMS_ #define INCLUDED_BOBCAT_PROCESSENUMS_ namespace FBB { struct ProcessEnums { enum ChildOutput { NOTHING_AVAILABLE = 0, CHILD_COUT = 1 << 0, CHILD_CERR = 1 << 1, }; enum IOMode: size_t { NONE = 0, // no piping/redirection STD = NONE, // for backward compatibility reasons CIN = 1 << 0, COUT = 1 << 1, CERR = 1 << 2, ALL = CIN | COUT | CERR, IGNORE_COUT = 1 << 3, IGNORE_CERR = 1 << 4, IGNORE_COUT_CERR = IGNORE_COUT | IGNORE_CERR, MERGE_COUT_CERR = 1 << 5, DIRECT = 1 << 8, }; protected: static IOMode iomode(size_t mode); enum IOModeExt { ALL_IOMODES = (1 << 9) - 1, IN_PIPE = 1 << 10, // used by operator| OUT_PIPE = 1 << 11, CLOSE_ON_EXEC = 1 << 12, PIPES_OK = 1 << 13 }; friend IOMode operator|(IOMode lhs, IOModeExt rhs); friend IOMode operator|(IOModeExt lhs, IOModeExt rhs); friend IOMode &operator|=(IOMode &lhs, IOModeExt rhs); enum ChildAction { TIME_LIMIT, CHILD_ENDED }; }; inline ProcessEnums::ChildOutput operator|(ProcessEnums::ChildOutput lhs, ProcessEnums::ChildOutput rhs) { return static_cast( static_cast(lhs) | static_cast(rhs)); } inline bool operator&(ProcessEnums::ChildOutput lhs, ProcessEnums::ChildOutput rhs) { return static_cast(lhs) & static_cast(rhs); } inline ProcessEnums::IOMode ProcessEnums::iomode(size_t mode) { return static_cast(mode & ALL_IOMODES); } inline ProcessEnums::IOMode operator|(ProcessEnums::IOMode lhs, ProcessEnums::IOMode rhs) { return static_cast( static_cast(lhs) | static_cast(rhs)); } inline ProcessEnums::IOMode operator|(ProcessEnums::IOMode lhs, ProcessEnums::IOModeExt rhs) { return static_cast( static_cast(lhs) | static_cast(rhs)); } inline ProcessEnums::IOMode operator|(ProcessEnums::IOModeExt lhs, ProcessEnums::IOModeExt rhs) { return static_cast( static_cast(lhs) | static_cast(rhs)); } inline ProcessEnums::IOMode operator&(ProcessEnums::IOMode lhs, ProcessEnums::IOMode rhs) { return static_cast( static_cast(lhs) & static_cast(rhs)); } inline ProcessEnums::IOMode operator~(ProcessEnums::IOMode mode) { return static_cast(~static_cast(mode)); } inline ProcessEnums::IOMode &operator|=(ProcessEnums::IOMode &lhs, ProcessEnums::IOMode rhs) { reinterpret_cast(lhs) |= static_cast(rhs); return lhs; } inline ProcessEnums::IOMode &operator|=(ProcessEnums::IOMode &lhs, ProcessEnums::IOModeExt rhs) { reinterpret_cast(lhs) |= static_cast(rhs); return lhs; } } // FBB #endif bobcat-5.09.01/process-pipe.odp0000644000175000017500000004230114050437223015221 0ustar frankfrankPKîe>>3&¬¨//mimetypeapplication/vnd.oasis.opendocument.presentationPKîe>>Configurations2/statusbar/PKîe>>'Configurations2/accelerator/current.xmlPKPKîe>>Configurations2/floater/PKîe>>Configurations2/popupmenu/PKîe>>Configurations2/progressbar/PKîe>>Configurations2/menubar/PKîe>>Configurations2/toolbar/PKîe>>Configurations2/images/Bitmaps/PKîe>> content.xmlí]ë’ã¸uþŸ§`ÉIjÆQÄ…Ù™ž)g½©JÕl<•WmòÇÅ–¨nz)R!©én—ßÁ?ý~y’ð&€¤HI-©%5ÖÞm‰< €ƒsùøñóÓ"4¾ûIÄÑí™ÖÈð£i< ¢ûÛÑ¿ýûØ}þôãù<˜ú7³xºZøQ6žÆQ h¥7ÅÝÛÑ*‰nb/ Ò›È[øéM6½‰—~Tµº‘©oòß*®¤Ùs¸uóœXnùOÙ¶­ÒÖ»Ûþ—sb¹õ,ñ·m,hA¨róy¼mã§4ÏcúbéeAƒ‹§0ˆ~½=dÙòf2y||4‰'÷äºî$¿[3<­é–«$Ì©fÓ‰úâÇÒ 2Ѥ¢]ø™·-‚Vf)Z-îüdkÑx™×Õeâ§@Ýs»Ém”ùõý~ëÙõý~ƒ˜§^²õ<ˉթBfÛO2“Û.¼ìaÃø:“ŸàfþŸŸ¾¬çU²Øö·­"ªi,·îfA-·ã¸fU4({Î.¶,:)¾KÔ½äIù‰D>í%Ÿzá´–x¼èС PŒýïbÊ׋H"ÝÐOŠÛ5q:Ûøè_~úòóôÁ_xkâ`˜xDiæEkɤ‹ Üz€väõ¢`ë© h[K'“a£ÄíIâ/ã$«h¾ý&¿‚k=d‹p³ w+Òûd6ë$vÈÔ(“ñ÷ÀüÍHÙú'¦Û˜˜¹ªj’Õ‹.ðÃj…×´¥ü§¥Ÿ¢÷^(&ñx‘€ÃÄŽ—7RkuoHOÛ=NLæx6o>±±°§iJ².¹}û¯‰¸7[#(ÿò—$“F)úM–xQ*ž[*åòY0²©™øX°š?´x ì'°tÒ0›8™ÍMø2úTY…öH'õo•ÅâáÓq¾¤Ÿ>ÛBþ_£ø,Dp;š-Ѩ¼0÷`ú?Ã¥bƒ/½{Tµ”/Ž— ?É?5”âΛþzŸÄ«h' r‹ KV0´›Èâ»?ûÓ,í%Ÿé2ôžaߎ3±ν0ÝD“³Wmš=Ï‚Éí³@H xÈn"ɨO`øp«Øyð½ÙÇUï{H”Î÷IIê}þ¸­;Ÿ´fË}â-‚iuyé%¬ͿŒ‹FBϼdV‹¦l"KEH+·)¡¹7~ˆ“à/±X•c/ îa…üy•fÁüyÔ ü.šO×d‹–—_R‰E0†yöâ ú>i õ{»ð’_ýd ývô»Ø5¯ƒ™0X,“LÍ®·e4õ£|‹ßJD;Qi–Ä¿Bƒ(Ž`ØÀf,¯À.Æ0‹cåÿ”šaXÑÖjÒyþϰœBžmœ"ÅòjÜ,Ç¡¸7oAT7°ÄДתñ‚K;È—jùöÉ×t0}±ŒíM2î`)ýôîIƒ¿ì´lØq†µc Kü¯¥>Î\­ð#NûÖD>¿­Å9»­e¡kR¸GŸi³.õæ3Ÿm£Þ^i¾ ëÛÄÌKFò¥±¸r;úc.Ë<ˆü?aëO¿‡KþlIó*’[¶MVÙ&î‘Þïý¹· ³q@ºÕìêÞ*7m‚aÓæd—mík»g^âå ÖìÖWd†á—…ô‹yûßm™ÅíßÍŸ¯þä<†]ôv„é2«ŸQ]ƒçëE›nаLè?•··çµe½îÀ«¸{; ` ¯—ÙúNÅïÆû5Ë%ÅÖLk ¬`ñìdû­5†Ø”­N±>º8oH?a’p‡ÉC³©±Úáž‘+°½HZÓí"9É`¶ÜíæÜ±×Hžh ƒ´l ðüd‚Ðÿî‡åsïVaègFqS\;*¾·Æ"³p;ú¿¿ÿ­î£ôuO'C¨Äõ3ìf??/îâz¾­Rì¬hš?§,‡ºÖþÒ8SûŸò®÷uf‡®â½ºZ´I—ÞêÏãÄ"b~GìV¡wmjë‘ûÕåIˆLBÈÄW)!z@ 9W)!û`Â&½J ±ƒIˆ\¥|øáäs¥zÚ9˜„è•êi÷€ºN=-B'‘}YŠZº]šÓ“âòÆ]<{®¿È‘’Oóh†H2q2¾ßQ3z®£'yb¹Œ:¦™Ÿ”ÙI9²2*9]¥ÀÌ8}ð–~ûAyαŽ)š¯ÕÐ{9Oø¯²"ÏQމmº–-†L\«B-ÔDNuíIŒ›‹«¯Ï¹*¥b»)gØrR²éGX2ßûñÂÏ’ç¼@Hü[,žbXFÌ*ÿ[ñü¼FšyÑ}ÕªµÌI?¢ñ—²¹òcý×2þÇøÏ|Ð[R+9 ƒ¨S€x>!Ø¿MDjé=#!9êðZtô³iÙkáᜂ:ªô&5sÇâ“›C2Ÿ¶‰d.péÊ\Â}âžšKà+\2s-;Á&7]âÈl27:½09å2›„Ed>aQQ[æ(8àsžÀ¯w1J16™ƒ›‹™‘W11‘ÄT½ÈË_Ï¥p?U~Šxgÿ•*rY1¼¦›¬¹êÝ¢.c=àTé–õ3±ãöô =øÃ*Û¥ g jmGê£k×Öº¶ÔµœÈËY&&nCÙ*ZLP¼‚ªuÝ›ŽªÆ@Ϲ¼Á§ãž\©JåÌ› —3…S !ä4®c78uÖWJ•ë§nŒxe+q%–³KðÅ)]E#\-ЬvÇ¡=eð`÷€Sdw ±Ô?–žÓó”n>»7o.µ›¯Ý|íæk7_»ùÚÍ×nþù(ÝKuó™IÖúa“›ÏM1©–ÉqÏ®ÒöÌ¿ÖXºÍ¾ÿÔ aÖÝàðšiæ%Ù»÷7âË?{Ë8ý×Ô˜>á Ü“xê§¢~(Ríä_˜“²M›(£C»*bo÷ÃÒ¦ oM’ì”:kxkˆž|c6(G*£ÜU< è c®Ê©CNnì6HÃeÈ4djÓ†Ó†øÐÆ|øÁÇ&±¹Ê©ƒYC¦¶m«œ:ÌàôØ&ãǶU}ËÉeÙÐÅ ÆZŸt¢¯·ô*‚éa«Š•cuß³qŸ­ì{åßwùFÿ~—~-ãðù ëvm¹nköq—oås«ã6@éÇ™—ùÆ»±eZT¸M-Û±mÇåø½‘Ó…ù}ðläRŠ9L$Ü1´Â6£È†íKüäûQ{³AÌu‰-«ØsDY 7?0JÜÁäuˆ+(-ë…‡>0-e.¤¼½Z+[¢ÜÄmû›(×!›%J`µ¸Ø¡ÆÃ¥ª8± Nå6²‹åñ|à Ël—D&Â6ï”'‡'ŠÝ–5ä‰)ˆl ®´Í K|°- ‚äðѵ1|Èà‹ÃX<¥ fƒr=¶åf›ÔQM›±žøÃ'Ò°;Óv¦¥Á}åWTÜóÒÙÌýñ×?üøË?¼¡$ÖI¦}“LÕ<ÕI¦óô[t’é\’LTf²#Çd+ÁÙWÊ15¢È­S+ˆ¬sL‡pUÀÃr¸“™sdº0]{0íÐÎ1µôƒN2 T'™t’éz“L¶¬L7%™8{²#a£Ñãºî—d'$¸Ê4S•YA¹¤Ø4Y_óëõ,ÐY&eÒY&eÒY&eÒY&eÒY&eÒY&eÚÓþäƒ<˜ÝŽ‚Ùðt‡ •¶;mª ™ÓˆÙ¡ƒX£ÂÜ„.$~6}Èg÷X¨iX(› žU‚\âÀVXŸçÄø<§ð¯ ÿ2ÕâÍ_ìд{ñ,˜~Éš«–5üy Íøþý»#.4¸MƒÛŽÎ¥·1G¢Ám—š…Êñ[DÁ¦Ñʶc)¦1-EyCCp%;)H¬W8—–;´Á)Wò¨UvOf”»'?šVõ¢2Êé~uçÀÅéÓýàñŸl¿ˆ9 F‡³ýÇ׺sÔõìÐKS»HUIà€ÒCŸ\s¬#,Ôd|t›82Q`Û¾bã]ø¾ÏÏRüJŒw‰ø²ËIŠä')¾¶C¡X€¥X€uVûÜ›`}E¥ñW¥ñWˆ¿ÚFijü•hhÁAD¹Üˆ'œ n€‚Q?x¨æ‘pâ?äX!]u¯«îwÌ[êªûƒ$ztÕý[®º?p¡øP¥õŽ…â/÷´4‚[;WÚ¹ÒÎÕ8WÇ?5CÚ Š\?³úå;›ñ"þ1çÃüc,ëj2ç—sW~¦ý¼/ú¹-~>OÇW£Ÿ÷A?k¼î°ƒ¦ñºo[=h¼®Æëj¼îÉÕî¥âu™ÉÜŽˆYóÅæÜ s{‚~{ᙆڞëþ¤¡¶j«¡¶µEi¨­†Úž ÔVCBû¸?$Tƒ}N{¾÷q3ç•qMË9XÖù²ÞvÉ;vwHpý !‘Q`UíXPh(ztê‚€tôéû3´ÏZ!dòÞ÷œ'´Æ"¶2ØéƒZs‚—€ %ìd:ò\¹¡6bŠò/ÉRBÏ©&*0˜œ<9|`Š^©I°#tGÒÙ¸ °_;AN£ª’ ¬/¿s†ŠN8Óê""ýÕÿçêŠ2‹«CpŸ{æçîcy±V½f°*Ö{ø¢ùJ£Üe.A˜Šh™!RT˜rL°KÜ<3ÝåŒbÇr F‰ÕòE‚ö¶1|´à9éÄ1£àRøD8}ÍbOÔ“ÐrÜ,ÇÁbO¢{ŠH¬¢ªÚ“m*ö±;¸!Ţؓ`JQìI°í¢Ø“P&ê>±Má®[<¾X[ƒr=FĘª…3°ÒT¸·ØVšÒô1ãF|ŒcÊšAãF€SØØÖÉ£ÆÈ-Ld^]“[Í-)›5XÕl_¸ÿ‹ÆŸ4k(R&t†‘f±øÓÆ÷‹ï¨H쪀§{‹øŠÊ—­rÛ>Tü‚™‘my/´d·˜Ú1Qó¢þ¾e–`3ʃÅQúÇ­Æ Úß¶×°y ›o´Ó°y ›ßäïšßƯá]¦­¸5Ži+¶µìÖò½¡y0ÃßMÃ8õÓ£a9õ‚Áç¤e«+»E±1 „‘ v°Ã*Nô9~5räÄ1]Ôþ{SÕ ¶®fØ·š¡ÚËt5Õu5ÃQ“bºšáüsJºšaó²ÓÐ{ ½ß9o~1Ð{dËçûlÂJ9òá‘9Vªyºö^”}•èû2i€œ‚\Pâ¨ìd}=ίד@£óÏNßjt¾FçktþEíbv€Îßc¢ht~÷¯ÑùgeÐèüž ƒFç7Ê Ñù¯Ñù¯Ñùç§è4:ÿ,Q\挕^30Üû_!4ŒÎ‡;®C¸íä  TªÅ˜mY„*Ü‚Np>¸‘#VóB”~@àÉbÛ…ÈÅ9­Àä;iŽ8u;^C ±ùžÆækl~Å«Æækl¾Ææ«ƒ¥±ù›¯±ù›¯±ù]Z°[Ëklþ„|^×fê{’ÄQÀMô\ë„]dü„]`·nlq“Ó¡ÀÔ¡^y:\+°åky¸hɬmÄh#F1Çéétã6Qçm^Í•Z$¸O±ÖŒZ3jͨ5ã©5ãÉ^ÝLÇZêë/€«ÙØÊ`¬8SÞM•Ë÷A—R˜­Éíâ¹ÅK¢™e ??&Ü@6ÇxQôË+‰wAô¾©Bb¦ ‰÷-$森áÖ…ÄÞ™;t!ñ>…ÄÇm9.HƒOõ­å"µþúÕŒºàùüazo àù€Xd]ð|T(².x>黯øpõ ‚þRË`ÕÔÎî½ìmc‰~ÛØ«S]Ϭë™Nu=³®gÖõÌr§u=s¿Ðt=s›ûó©gv /±äãÖ3¿“ šß¿Ô|¼öÊæãÇD¯¥²Y—áê2Ü®>\|.3¯,¾wÈ2\D:T†ë”±´×.ÃuM{  (ί —=vñe¸ŽÉ®  —A³‹.ÃmaÙˆIŠPø¾”XïÔµ™í"AQUá"î:¢Ä–‚wµ¡ —ZÈ „9-ª*ÂEvU„ ¤üŒkP¸Fm6\-z,ÂÞñž±¾Qˆ5¸äÊ §4Ÿo,[¼b ¸bÂé A Pì†Ë \D8Î+p‘¸AƒryÞN|¶pRæjnÁ±ª¹eõIü§j6kna\knA}Öܳ$q+4?ðMpÃÊ¡ÈáþVŽÆ¬jÌj£Æ¬jÌêÉü”ö "Q>pA]¥ýÚg(è†3„ÉpvgˆSŒ®çqzÔUŸB¡¥!Ð{¾Þóõžÿv!Ô`·žƒçˆ*ˆ =ˆàµzÏÆä„´@îëüAQ±ð•+}/rn)Ø+  '/ ¾ø)b•cT¶Ó<Ìq÷Q½%Ö¨ÄÕÇ­•«æ9€Æym,s޹VOý²ûûç™æp”µ“€¹'3(ÆÔShp/„æYŽ+UewƒÝJtXÕ€ÏmÇèEˆÞr-æ ÇO¶ÎÉdu@•cð×E–‰Ä7¡þo.’ÝçdÂmÃeM˜æÌÍÄdn¤§Ôf1zXÏÔ@Q[\v *žQ-¶Ui«šþ/ÙíK콩ÚV®k[j[Õ~ûYD÷©ú£‹x•úãïAÜ…ÂòÂ4—Þ$žÏƒ©#¯¯Þųçõ·Y<]-€h<£ þ~úPKo~eM!vMPKîe>> styles.xmlí]Kã6¾ï¯0$7½ýRgz‚ì ,0=2“½´DÛš‘DA’ÛÝ9í?ØÃöÿí/ÙâC2e=,¹Õ¶Ç­ ´É¢Tõ©X,V•¨w?=þèljGÂû±¡êãâzáú~üûç¿+‹ñOïÿòެVžƒï\âl¦J’>û8Áà0¹ã÷ãmÞ”xÉ]ˆœÜ¥Î‰p˜ º“©ïØ­x »XÛáŒXâ§´í`J[‹–íï̈åÑnŒvmSZÀT¾"m?%¾²"ŠC‚¥ÞO¾~½oÒ4ºÓ´Ýn§î,•ÄkͰm[c½9ÃNNmcŸQ¹Ž†}Lo–h†jhm€SÔ–?J+³nƒ%Ž[CƒRTzªQŒ q©^¶»<¦ _ëÖÚõ¸®ÙÙ ¸µž1⢪Xn{U±\yl€ÒMÍó]hÐÉþ÷ða¯WqÐö^”¶•{Qk19µ<ž’³JðÉÎØ5u}¢ñßõ®‘|{)Ž%r§‘ÜA¾“#N‚*ЀÎЀBÁTås¹Ïo-5ÐÖ( ½ÖÐSÚ’ªÆüZ §ZŒ#§9 «öFîbæ&c“~½É ½é:vÝJR`ÇÒÀ|ÀäU=¼ûn\X šÁ>PfZ aDùtL+­âëóoíS¨©c&Vi…˜PwiŒÂ„Nadĵ¹Deˆ*” vQ~°¦¶8Õˆ»2cw¥ÂñûlqäkâûwÔÔä¿âxÄþ¦æ~üs“ÝxæŽâõWòt?ÖGúÈÔG–ÎÛÁD´)mÛ˜úŸcM\/Icò+.J6òE÷AŠ•â?Lý_ »cÞïzIä£gå€nT +oŒ4FÒĘ䟊Ã5µAºªO 'úÌ"©YGê%) ©µƒ\Üæ»x…¶¾ð(F¼m…`Š=ß×1Š6ž3Îh##Ö¦D1<›8õÀá]ôq+h›’$Bô>ž‹ 'E~´AcAmC'ݲ®ì û~œxADÕŠ÷Ãj‰•eŒ¬¨¹Gqá=ÔÁ®Ä…Ëû±’.³®È ]LçõŽØU(#Ì‹Z!?Á¹  Å +‰@@«+'§r•¤Ý&XwÂ%;…ÝÜ!>õ6· ÉŠpŽ2@I~üèËm2ú(}$öèo/Á‡(kbƒR("/uàñ>¢ØãÓ1»[âý ¸˜“(em> ×[´†&²‡lÃ4v~ÿTuK˜o(ÌxýAÿÜŽ>Áü<Êd62yNR”yÍú÷K”錀³.Ô@pŸõý¹Éz„YÇß>V±F?$N>¶V œ¢^¤œ¤R¨¼w㊕wýããx¯ …9ši¦2ÅoY­%×!¾çr‹(ÌÞÎs™Q¡EjjÿÎþ [Ã-/ð .X>Pµr[Tèw`ºRO•ÏÑÌå†á´·jðÊóý\‚¼%çÔ¶gµb"B.Ýe)` è sJï!u,IšR'¦ªÏÇ«”ö”:bo½‘z8®ä2GËs]:¥FÖ®§ÊSQÈbçseg&ÒB§ÿÁÃe›+,½Ò 2™>˜Ï‰•åÖ÷q:â´-,ì'ïR¨O}?þßÿë‘t‘½*iu–óÐ,~øô,‰?îbU¹›L¿gó£I˜¢š'‰ÊǰOYbðdØú:£Šõ^¨øh cr=žÉKï·„ÕBàÄÝ$B“ZÜ$BÓÞ2ÕÉM"4ë !ë&ñ™÷‡ÏÚéEoMnÔNÛ="t›vÚÐ{ƒhúmj©[ìµ´º-ScLî û”5˜oÄ.A4f›„b+߈Ûò=ˆhf‘ æã ]ÿžµ2ä<ûव˜¶ÀMH¶)½a¾Ã’º#é&&ÛõFa¬„ÇÂtþ:‘c!"¼-ã(¿Ç(Û‰qN%q¶^ÌÃFU²ìâÙõÄ,À)ì?ØŽ†,Ð$ãw]±ŽÜÉÔ^ô¥’n ¸ºHKˆy½5$L/pmW0YgØðû^U(y¬Ò¥*1ñö“P ú öåì¤;/ãÌÛ•1Ÿ,îŠâÝCF' ÉMÄkÂ)lУ—xL¥_%t‚ä`íi¬ìEçÁ96ZóG'Ì”›ÏÑq¹$îó%9mö¢Ä*9+ÙYª/ÛT×–Ï']·ÅÓO¾·†ÕŠrë­ž»‹É=¨ë²ƒKYô3?»%^*­´WªÈ“I'E¦"—©6¡s;ÝqM0›Ö„RgyMh?‹ø*Ûöq˜Ý‡ù:£Ê=Ñ÷¹˜Â3X­Ƕ¯ë´™äü.‡;GÕ¨Ù;æÏ·Ûö±øÐ­N‹É#—:½—·,G hNÌ:8M£=FÝ&F†ÑELÕå@*îݳÍö’ønwè^ɬ\-t“а‡—Â$w^Šh€Q²Ï1_åE²ë&Ñ<Ü$Â&°r\ash„ÂM6`µ·¡—ŠfÛav™è¿ˆŠŽ%r¾®c² K¾µ\LûZ.o­ c½@¾£L^&Ð9J&΂KHRüB,úÜ5ð´W»}ƒr$@Ï[o1˜lêC0¹¾PO¿ù`rˆ7LÎŒ•˜£%÷³G{Åh¥°ËÅ.Of‹øRð’Ä\L6±~¥¿¡ùH™[IŽW/w«®k¬¾°¯,éy*9CÞ$BÕUrÿúÏ)Nµ‹³!4¿Ö*¹[­O©®’;E‡®¦ø¢gê¯Jnv£U`ýÕÉÍo´Æ©¿:9û&ñé¯JÎÐoÔP÷X&g×bª/U'×XüƼÅ7†°Ì! Q†ààÜt¢FÄ·†(¥r aˆúüCE 4éô+Õ"Êá³ÊÎ}èiqJAˆjõƒ˜ÙbVÇ4i-b•ÅwlOElÒbV?ˆ™+…(C´åðæ©ˆMûAlÒb]Rñ—BlÖbÓ·ƒØ¼Äfo±E?ˆÍßbv?ˆ-ÞbÉvYYÚ{Zˆ ˆ#呎tŸU«žëú¸eö'gw8ì`8ì`8ì`8ìàzÒ8ÃaÃaçOâ ‡¼ÕdòpØÁpØÁuvÀÉ;(-Ðéž!Ý3¤{®;Ýó-ņÀÂX C`a,\/BC`a, …!°0¾ùÀBE´à &U/ùN0)U‡Ý\` FÄ È;}%¢ÈðÑ3LÏÂþûçúg“Öó>2ù`&7Ä:ø÷ã K°¥à=®ïhýƒªOçÙY…Ït“0ŸXÙoaP ]Nó ³÷S]5-QÑø2 0ç†ya&OnÏÓ¥€¸‡@O ãÒ@œÆ„Ö<Ÿ€ààKYâ'}›~„ËQ²ŽlQ®ž‹¿>è㠚ʞŠÍmÒì~ÓP§¶ÜžbÎU›yL Ø {ûÒ¯¸ÅÈ“k¡ HÀ¸•Ò¢û |‰ƒ"Ü,{9úàF¥ƒÄg5™šåÈ¥PíþœáÜ,IìÒ$ÐÉgo_¥7:ñU˜£ÙwÛèyRûSf+IV„¤GHØ­²Ïq O³’ÐE)øœ;¯Ó93ëør§…Už©Gÿ;æª7èv~’¹jÙó‚;.õåú:&um¦OûWÇ&*kDÇÚÖòaN×¢'“‰Ý‹—¾Et½Xt׋—¾tn,.=“~-O¤,P1>p‘Ïç«ÙºVwî´ïôbÓïeM/1Û&΂C·Ûéƒç‘®¬»'I×í\Û3 ø¹¤k”µ‹©YS2üáÃNVº¦ˆæRàC üjRàC |H)ðË"4¤À‡xûx³?mþôàOþôàOþôU"4øÓƒ?=øÓƒ?=øÓ×âOkµÅ+¢#@IÊ>Ä[Y¦ÈGÏ´‰^qÿ›'‘¸'Îk (CÕýÒ÷zZÐdI²ZRpˆ‰ß@!>ÂD+ê•v(\T)\èb‰A]=R¨¬Ë“‡ý´Ú'Ëå=çAVt!˜^ÅÐTAÂ*ò<^!¡È2k{Qª@“kŸlÕšÙ‡¥O47ËŸD…Œ( bPp|”$ü3a8Î8g|-É“˜ƒ‘˜)ŒŠ^˜@aÁgã°*‘ß#Wj:.û;ÊžàþÎÚ×àiöާaª¦ÙÓ¼v¥ ¬fgXóÛ¼²æ¥4Õœ©S^ýY-/1z]uå÷83¨¯¯®ÍÀJ…Y½k-¾¿ÁûüôGþçëôÇ [‰àTèÙ5Ò \$Džß QSTHJˆÎT{.*ƒ©N¬ýGT UmF¾xCW' Qôzæ;/Ô©eœíÎM+Ãeî~fØK·—°×ªÜžÌžå®êþ&WǨvuŒ¢«S0(2éÁ‰í1§ªa—Lœ¥Nõ‚‰S'ºº°æuöMpPW—.|ñ˧՛÷£"ï?öR© K]ÔK=QmcR'µ`âró*Ë^|X¨L«„‚:™,jQ0lÕ`s¡?‡¬»ãЛCv"ÈVêb^z{âd[Îg­aîîœYrÎN¸““ÖJ‹M]ÕçÓÖó^ZA(ö)ØÆ}võºÚÿr&Öž-J Ö÷¹lyÁ@Ãlt¨sÇ åš!¾Ûï¹jÎß&L[SÖ2Õ˜Ú²’YÙ°*ÎgY2.¶Í¼€È‰¸‘^¶†ÉEÀ%/\‚µòœï¥â>£p8Èš]âlƒüŘäýÿPK5ÝŒ»­PKîe>>“ÇAìiimeta.xml 2011-01-30T12:28:36PT00H25M45S32011-01-30T13:47:29OpenOffice.org/3.2$Linux OpenOffice.org_project/320m19$Build-9505PKîe>>Thumbnails/thumbnail.pngÅWgPÓß¶ý%D‘&E:‚‚H‹Ò”¤ƒH ]©&R‚ Í@°Ð4 ^¤'H¤*Ò"Ò‚H/þ ‘*ýæÎ¼¹ï~¸ÿ7ó>½/gö™sö>kÖÌÞk8ó[l̰̂êZˆ­gÀôÕ=Qì‚FºÚÖ!9k¯˜Ì¹m;c@\ê#?ePqÚI½lÙe,qŸ!¬ö(∓,)¶ªÕ0©.Vͱiâv5ÆÖZÞÙÂXåTÜäk¼}±Ãç$ž4Û!1ŽGsxŒ™9o|]μw:C¤äàà$>‹mþµÛ2ºµ`ëââÂA#*œÀþÜÀŽ /®làM€Sâ*Oƒ‘u®ÖÎÎÒ–罕ýC9O ^Ú}KrÄ‘ç—Üæ»ÌûØÍ>,ëñêh¾ÇbYò§¡tgÆ_¹;y Ѩu\Ö‰º$&–ƒTȪÅüпFˆˆ¸sçŽÃ»û™Ê>Y+h_Ôv1ÛýQÒ«•Í•¨™õèFŠ4B[»m{eò½Ÿ–'%£Ð 1W+²Å­3ª»¡â73^ã5Y{¯æÁRÿááa_¶JLt4év~Ðý²¶–Àe.ä”ssÒÆfdx8hm"hº!èªô¥K:%ÖÆ™jJ(˜_3ÍŠžÛ7§È‘Zø–“ãƒN6õƒÕšdI3^0+¿<®gÀûáÎDÛÅ˶¾„€¶éÆàÞ 2ö`Ç4[ùÙÓ§]ÛÉ&ÖDùp£ƒÏ¥¨:Θò[ìȲMÊ‚´÷/Ä]/e§±ÿ³@ ô(@ Zw¿1¿„%x)P›žxAK„›ÛÚÒò†R;ªÎ‰4}um8¢¿¶¶¶ÿÕu+üë°ÌÜ܈¿ŒŒÅAÖ5ÍûÔò»ïºº ¯ETUUùL¾ãIŽþÜ£'_û‰‚¢"Rž’nÌuîœNrŽÚPc°ŸqÑ÷¡R³çJe(rͪ÷‚……q*Õèøò­„Në‚Â`f–ÃN‘ð6Rú………„C†©Ñ›“ë³ÚY1ÄëLùSέi«l S­.Z[ؼP,¬õ½ït> ]é–Ì T•¬ÓøCpW?^]S¾³úg}.x&´´©iê³Q1%)á½£YÌYá2¯VöÛu(Õꦥ/õ@ÜúäŠV—á§²>ÏX‘a Z‚äÜ„…¡ñ"£äŸot2U½úsâããßÏ„™” ¬§H[•í E˜“B?>eú&-V7ÿãÒ£–(£î7£…R¤[ó9ÚaMëùíZ}àç8 ÷€¹°Zý ¯öPRRº€ÝJjW[3›X…ÒzÓ*)·d ÐBš*¢ó¯2c^Q4¸ú“ûcª,²Â+€á*öÁÕ×—„Ú<'ä_﹦à}sxFHpå7ÿ"w~¨¹WàêXÕ.mº0öïÜÜÜÝóð€¿ ‘É«FÎ{ #=“8€Œ@nÒÛ'lIìƒ ó*j£—;Àƒß‚é]Zÿ¦åË0µÎ{m…DàCæ/ZЧuK£™À‡Ožâ8f5½ÿŒƒA¬Vl˜€»±„§€>áè1[gsC™t¢‚çÑ)D黫ùàV%›vö-(8Ci¶`‡!Î68ª_DúÚN¢0yMØÞ¯oÚW xrøB/Eeï¹iãå˾ƌÊW†ùîäψzåžv–medI>y÷C·”¤áûÈÉùd“E= ¿'x¼)©Y3^ÝÀ#,76Uó w¡¥1©É;Í×ãRlo+›è¤íì§&8ÑÈf%—}ÈÝ(­A•kž[[¡ÜŒbŒ‘.NòõùÕ*rrLÁrl!ª‹·r—Ûsj Wh#ÑšŽÜ­_ÙnÞ>`rùžwÖe¯[G›Ý -Óµíœ6Á¸/Dñ–é#Ü_Ëx´=>ÅÂG<—JÉÓú¾Í]¢p>К‘×òýz…2õóµÛ²Y‚ò¢©«¯"xîÚÆFçõµÅŒ+¢Ñ¾ïïívhVã/AEˆårZÜÜWôùL_œ ŸÏœ]zbpYƖ窽S¶ûµ„éâ]Zé¤íˆµYy¶ÇØo$š|ù¼4Åáv€â%z‡ðص<5!UüçÉ*O‡í½|ÿ#õýŠ+Z¦Dî%Yôô­èA8àï#O¶7ý†6pè½ —ÃgëÏž,0U9Fáêf”Œ"'µ{[B<Éù«Î=3ÜIò uÓГ‰á~™wëö¯Ùg ø·azAÍÐaÿF•OÈÖ:Õ¸;™‚ðÙ†¤¡M¦½é—­·œ>•y[1xò.ÈYÐÊ?D®æÕíæÜ?+ÑÜbsËò!,ÕÀf‡ %1&™ÅŠ=a)ö神µ§ˆ<˜îèëyžºdv¼ô}Ô;ä#Ôï¹ò39C&;Õùõ Ÿ™ðònx'¬óô>ó@ ¢ñí¢Ðekv{ËøÆ`TÆâá¼l¼g±ûñ­±Vp#Ð/×.DZ"¼&@é©QHˆãóq7RãúïªÏ¦Yu^ÛЫWEÝêªM«¤²xP˜‰‡lá´³mr›©.œ±¢¬Þ³ßßMÇ’)i…Ä!ÅñG9jMo S–ž—F¥[c£àJòâ]ø¢Ÿ \Š6²;¼!>&Z»®ñ­0ÑÀØÝð…(îH‰åàôëÇWýýNª—Ž+`ú;.ÀÀ^;×FMRvÙ{‡&Ï…°"ÕRÁÝí §#ßëìjÎÊÇ$˜ÄñŸ‡Iw¹lnýÉì÷¶Xh7òý`–0ê Š›|e .s~/š“¢bq°¿·ä)ÑrÜ$‘ˆ]F Øý/°$ñ·xª’œFçü¡§*2þÍ[_B}Ø å ÊøÎòËúíäË÷–½Ùeì´Û’^;¿«â©èòF•ûލm•tûò±°üF€ûÁ½å}ðãTév†ëAUìõiÑB¼æ>dO®Ö'Nã|*º0l:º)Õ~FwZù¢|èà;r…Ç7ÄÞFÉ©¡WÈñÁ´ïG"}C×ﺖ§M÷ý”:¦Î¾jT¢×ÜÌ»`·ÿÛÙZLp×CÄ|‡\¦VRO±¬™o×qâ¨ABý¹Hež;Šsqr/kphÌ–z‘Âì×_Â|·Ñ¬Olø·5¿oAc°í‰èîs`U–z^= >ÞÈŸß_¶äù Ä^Ht€]Nj¨Sp, Ü•µ:ß‚C‡ùÝ‘aæÍ¿HF˜ba/ç Þ<¬qD*Ô¥háMZo¯Üà퀲~›c–-?Éwè»ïNFœr ÂUíÅ}Xç_à3”×QZŸ7“kõŽ> —¿uJ-›´Ôé9¯CXX &_¿¡£ã£Ñ}Ö)FF[këOŸ©uît ³¼¼ zÓa¥©ª”Øó•ö´ID)‚ÁuG-(°%9VIMDX §Z°uªÃnp¤œ­­9˜6ÅY¨àô!7??¿±Kî0ftj!cµ÷¬ìíí}|dñrÎNH7‰u `)¯õ6ÆÖÉw>½]]±/^¨ÓKŒT8XÄù(ÝÝ™šØ}ºC˜Áî:-0§®h>ª§ ù0еþI¿sC áf:gë8ëïß䩞’7)œ p8ü_@'û´#r@ÿÑïþSeA¬˜'€Üüã´Cˆ÷çÍúÜOîfW€/Oä8þuÝô¢iܱ´˜ uä¹N½ðøFAKóN]_Ú°†êªÛb.–ñp}ÿ—Þdì až¤÷ŸÇzüðÒû`¢o–g€¹à¸;Œœ~Üîø…0øË’ ™9'6qRÞ¡e¥lú¼·¿×«’ž§Î½åï¾ÇSË·'îéÓçs¢¼F›ïè)Ýżÿ.=º|äÏ6·–|éz܆Ï")ïô¿Ê4ð3˜ð—Š‚L¯Y²LGhï*KþÇ×> settings.xmlÝZ[sê6~ï¯ÈxúÐ>BÈ &pHh˜ÃIh §=}öjd­G’C误d å€u:ÍCBléûV»ë½áëO¯!;z!)ò†W9>ñŽ€ûP>mxO£néÊûÔüá'êC=@?«’¥ôy¤·sY_Þnx±àu$’Ê:'!Ⱥòë_m«o®®'dË+¯Œòç†7S*ª—Ëóùüx^=F1-WjµZ9¹»Z ЍDàý7÷lÒúÈ'tº/Êrõæ~D\ m6,–~zrrV^þ¿Z-CÊöå2kK>†‘–y̾Óá4ÜƬÝ9õRª·e¯­eOµá"§^så+7h^§ÊYþ)Q¡ñ‘£ô²‘±áiÊú …ùÚ{¼¬}ßïùJ¥Q@Kaä­nªE¤oR®¼f©Z½¼.ïâ|»• ~~~uRý7¨Y|µvV;/ t:Ëÿ´rY;Ý¿’¨Dy¯lsÁ<ÛXÉíob±Ä0ï[bJ%´'xMã;Mü"hГ©>¶àLj ÷šÂ$Áï äÛ:>zO9‰FhXÂȾ1¥\æ±($1¿û”C.Åò0þ|Õú¢s–ê§ÈÍa,–w„ d‹ÍÉ¡ÿßÕn™õ³Æœ˜ç–Ñr¢`€l‘è­¯/¨–áËŠL•ó˸ړ»\.N”¤O:õmã gm-„XxÍòÞ?W ;Y:H*ò_‘¦þ3ï‹R~ê[Jg€± ÞcîŠX<Þ=Æ „Ë”c¢õgŠ·“å …~v,œ!0Ó 0àÙÀ– ¸'_ø‚›ðÕ¦Ó4TºH]7k#võŸGðªn𛿋Ð$áSxÄe+â@YCF8϶ñ™e|×j1*m "¶=3‰é–~¹‚¾GµcáCàßÁ8³>¶tøÿSrá¸)©Ú—â$BB®ô•ÓKKÝüž/{1ô®®s¿¨Zv‚+ä|© A›‚8ú÷û8A ‡7À1)î²Y ´ˆkŽoÿÂ9¾¹9GO&µ¡¹å¦tÑ2tuûˆáÏ(>öH¯7'y·ÓaFö jÿ±ÕòB,’¼ý‘ùU+ŠØâI‚¸!о®hS¥:2®ðôØÏ™­üøS¬ø9%(Ë4…KÛ±ê2F]JІf¶j&ƒ#MyÐr5)Þ­OæÛ‘Þ9³æ ,9aBb¦4íPeWÉ:ùS¼.Š1 àkóŸéõu=gô©®€ÛÚ>6ü9¨OCËê„Jv†x)êÍj¦”›ù–5Â-ÞÜ_4νŸ£H@5˜µ‹Oí4Ÿ–àòý ¹"ìð¡ðŽ(ßþÙÙ&äÏ xKj¿ÄÜW±«Æ®'“Pñ™›9ô&A›øÏ.ºàMŽ7'ê…It¾u3X¢ 27åJú.UoUJÅÝ’ I5æN¦6 GÖÄà€GxˆÛÖ$0Ú¹wõEFÂ0¢ Ü:Òˆ:‘ߤI-­ã¹--’àH€œmW‡šëêîs Bc!ÉlÖ-t]ÓM‰fÃ8 ]e¡Äâ¿Æ„Qµ­ž"“ºDO—1æ] ôÉb7:­¬Îp^Ò]²Ø³eÆÓ·5—b AÅÛeûG¿’øº|ÅâwJÏÔz8œüÓvÍrô÷:ã꜎ ŒØÙ÷cm~Ò¦—wÞ7)网ÔüPKu߈RÓ$PKîe>>META-INF/manifest.xmlµ•KjÃ0@÷9…ÑÞR›U1q-ôéyìôC3 Éí+’¸m(M±V–Äø½ñX#­6GkªDÔÞµì™?± œòvCË>¶ïõ Û¬++ ªüžÃë´e)ºÆKÔØ8iRà:¯’GÍ×øf4­Õ ÜkuŒ§ê&ƒNËšNZ&C0ZIÊyŠƒëøÙŧ "`~žcØ2ùºåd¹OÆÔAÒ¾e‚‰‡r¹Oyó®×CŠg?.æLîd,ƒ—J<õQ¨ãX\äâ®"‚ÞxIP|H!ïTýw^¹?=¦^ NÞ›bpmå(^5Y°¨ãAö÷ã“»‡'ÍÕTð·”IŒ½zžýô¿fþ‹t2€³c-œíàÙî“Ý9© º ypÃÜðy Dù¾¼–v%~\—ëOPK’È DHiPKîe>>3&¬¨//mimetypePKîe>>UConfigurations2/statusbar/PKîe>>'Configurations2/accelerator/current.xmlPKîe>>äConfigurations2/floater/PKîe>>Configurations2/popupmenu/PKîe>>RConfigurations2/progressbar/PKîe>>ŒConfigurations2/menubar/PKîe>>ÂConfigurations2/toolbar/PKîe>>øConfigurations2/images/Bitmaps/PKîe>>o~eM!vM 5content.xmlPKîe>>5ÝŒ»­ styles.xmlPKîe>>“ÇAìiiÍ&meta.xmlPKîe>>eP¨8S\+Thumbnails/thumbnail.pngPKîe>>u߈RÓ$ Ú9settings.xmlPKîe>>’È DHi2?META-INF/manifest.xmlPKî½@bobcat-5.09.01/process-pipe.pdf0000644000175000017500000100750714050437223015222 0ustar frankfrank%PDF-1.4 %äüöß 2 0 obj <> stream xœµUMO1½ï¯ð‰Ô¿¤hH%n”H=T½µ´BP©\øû}o¼i6»”ö0c?¿ùð<Ço‚{~9ï.ý&ºÒ⦺Ôì§oîÓ…û9ÇÏÓ÷ÁsÃ=³\·qVàø“Ñw wFÎކ؀·?‡¯îÝÔêw[ñãá~¸: 7+|Ú¤×øMjøq©[¢Á7˜±D$ó8HFÝypæh  {pÉ뛀gS!=­,Ãgü^#Üý›D»EY^sš vÀ*ìjgo‡?©8Âf ÄEà!:¼Œ=żrYˆ ˆ&äã*pÚpö,T( lD)É59=NÑÈçÈe¨P> stream xœµWËn[G Ý߯¸ëRg8ä<A€kزK- ‹¢»6-»@³Éï÷Îut’•cDjø’û8~þø û4––öu´f8ýküíÃøïGþ|ý{¼_2??ý Y·~ûÏðùƒ+ç4ü|R¿œþz„jOŸާ/ÃÃiø´á·½½-öÖðo pÝ¡á˜J‚3/ƒdÄØ‰çÑ mêžÇçuEMŒ S Ý­_q¿áÿG˜ûò.ÖžVÕFÍ7Ð+ÎÕeŸ†ï©áEs&£‰" `TÆâ;P3Î×€öbËãú7B˜U }b…¤6hsãWĘù)ÖäbJÔÜRpÎ’;0ç¼íN,‘k =ÇQ)#²{Ã!sÆäb Ds“¤Ò¨!C³óÊ·~l‰Œ;5ñgˆ¥zýFbö‰5¿(yäëÖÒß”à.ûëÎ9/BÄùÔ ½ä Pò¿ò£¦\ùï³â—¶ãNùáøÇéã%ì´J'ˆ•šv´ÃL“>+zV²ÅSäQ^³_öN o$’Ô©¦•‘-¨‰q¡ãžÞÁZǸƒNhjÔl‹'$/:ž2MœO™oâ„§3ç¦f„E.xþŽž„35-+¦°¤xѱB_¤Š— )DÓ‚çœsmªãH”™é †µ®£b#Â×|‰IÏid#MžŠ9ç6*‚qw$ð7»Ê Œø»xë zÑ ŒORšp漌„Bn‡Þ (â\ N¤´A PTS Ç9 –º˜†82Þ^Õ‰vu)Çã.BÛÑ?ŒP‹tK¹àC‹núM%gIG=ȃ[ME!.‡"Ç]Jp@*¿—–î$t••×鮕„o’“݂ߪ[(aÒCdHÙ\ŒB°·£ê¥!|{%ÖT}‚pެ2wïy»!I¬ØBFs…ÔÕÙmT£P•îÔóØ) Á˜C‰%5q.´¼ÝmÞÇÞSíÚ8³ŠñUØ^†œ|*•âjßfYÅÇ;-C@ÄЂMŽeR˜Ø8çœëøsŸ5ïÖ|C±êeb«l$¸p&TM]5)Ö„¸ê3ßÚŒÕ>¤ûf÷pnûUcÊXì¼gaSñì “ÃQͦy溽)äÄF¦^xt«âÍn®.†ÖTœU]°¯Ù_¥/ÄŠáÑ<æ3çŶe‘W\¼lÓ·Øeû{ÖŸë=˰ ˜-ÚÖÔýº–i[jîuÑý² :”gˆ¼(e²r½ ¦{gÍmrDÚl‹XÃï+ªÏ‹¬·èŒa›§˜rµâIξzöšŒC’ËòÍ–|¡¬.¼*“—ÿ™k[þ^±S]ìÙ+óìºxß ³ïO9MsQ^ºa>Zcñ%«¯‡â5œ¼@ ”‚Qp7æœË&fpÿ#`ñBšÔ®¼ð¯ƒdº™^!ÈÍ]Ÿ9¼?&†œ²Z¬ö£ÎÚø§ñYà endstream endobj 6 0 obj 1138 endobj 8 0 obj <> stream xœµXKoG ¾ï¯Øs«3|ÌH¸@niôPä¤6-¹@sÉß/³O­¤^lÃÒp‡äœu8ÄþG÷oú§pÀ>W<”ž+ËúûŸýoïúºØëï÷¿º ýk§LÙÖ—Þ×" B„yá»w_ß™rý ?Ÿ:¬Âo§?úŸ^D5õ§¯GÃé[÷áÔ}ºâçß®òÓ1Ý ¡Ê3Š1¯$ñщKoÕ(ê.}ãiC5Æ•Žæˆ›õë/fáùû(Ç}{“Ó>‹[Q¨ÚSʲ#zc‘u1ÙÏÝ!€""ºQ‰õˆ BÉéB%Ù#y&Ô‚stèÀ!ÖÔo¿ÅEc‰ƒÈ¾v±ˆ$UÑf‡ßÓÈç¨bŠ&Fj± ”Çh,9›£ÜbB ã¨ø¤%º °+š HÉÄ5>' I ÑøÌœÛ P£±‚]E,(ëhn,®"fÝF»_ebzÉ~ÛÅQœì~—œ»Ib|Ä,\zúßé…0•!Ós"ù¢:<Ñ1}¾œ>îeO³›·j*áÀÇTF5/ª&³,3ͺ®+êÆkÈ'$|J ”nRwWTc\éxXopÚgwë>Î0PË9 ³îΔµN8CIê:á Cly8sîã 4Ôp%xgºΠ€ÁÖq5¤—œÛ£<ÿ€4î©Le[]´€Éã–v(Š€Á¯ jB Î’óÚ« &BõìÉú­Õh›?I Ø5ZÉQõ@-Ô?@¯KÎýüÉÊméz?+à?ÊŸªF îäÏ* ÷óg­+Ö"ÊØÂ×Ô¹º8À1KõOuˆÇ”…“äÃH[åá)JÏKÏú¤ûû:È™(P]¨â–øÖv]Ò˜IHzÛDA&b J䩬ÁdG}ªÌvn+ª·c…ź¢{­g‹UÆ»’šë:uÌŠHÝìóìe¹DK:"Mr§.½S‚%] YŽXSs¥å~Az›ó”$.Ò&³V×.¡‚‡r6µw R"°Q@OAI>îIÎÔ®”´A™/´.9·þ'>®V#¸Ú4ÃŪÉ"q¹hñ cÒ¤$&S­”bLõÌ·=†‹\Š>ňy²®‡M1J2ŠóŒEkE48ÚÔµPÎ\§Š„Z¼È€§¦û89\lŽ>q›;™Ï6œH ©æó̹[ª8ê–iWMúE+ j­Ò’E÷r¥Å°šo·z×òJ±Yé°®|–Ê‹ŒÜ•bؘex’£QëeIµu1h¬à4ÎZà¨xËAáHÖrÐg r²1ÕµŒ¥¤Vá›mø,&€†J4øÏ\×ð7Ä6\f™“!s6Sôé1iqÇ„­Â8úuËv5qÇ1 Ãh! ¢`f,9wa“]¸½0¬nˆøÆý€¾I ÓUW4„HlÞ{/qòy@j-\|I¸so›Á-[E°±!JhJ£¢´°€¦i­‰rn‹FJ¯Èå1kaq;>w:`£4슧£U\Ÿ|ÍvŽS~êe¢ŠÍ*ïvºf_ŸWþŒ{ã±û2y©ÉkÕ|n”Ÿz™(¶éMåÝN×ìëóÊŸ[M+Ó~ÏhrIMïÓ61oÔñrC}£ A{bœÞ-ₚ9÷ÿס@f.ímàã€Ñ°çáI¿åÌiõ©ÿ×f‘„ endstream endobj 9 0 obj 1358 endobj 11 0 obj <> stream xœµXIo[G ¾ëW¼s»3r@ÐqÜÒè¡èÉmZræ’¿_~ä¼UOVuŒÈC Éá¾8ÜÇáÛáß! wá> ¥¥û:H=ýsøõÝðÏ!øùú×!àbx9©Øù<øYiI0üöïÃçwÆ?Êá§§CjŠoO ?<*kž>)œž¾Þ?>^à˽¼Nî[ˆ-ão6†¦š¤’T —eÕÓó`·¨,ÏCTxuÄ®Œ‹öËÏ&å7ýÿAŸûò&¯}RÕ¢Bmà\ôFùƪçj´Ÿ“•ˆª’࢒à‰B éë e½cýN¡æ¨Ð½tã­«ŠD¤Ï²¥}9Δܔ›=~… –/dŠšŒŒ!‹ H…“d,1o‹l!·qDŒrŒjÝ™ 5!©ÙÈa؉CVA`Ÿsëp"™+bMzަÆÂ±à:™$öZÜÛÕ#9›—˜»‰bx,¢Xø¤ 4ð;æGN¹žò1?dÖ_ÜNw|ÌïO¿?}ØË F&·lÙ4N'9æ:²y›"z,<óR;6ý§ö¬cbµQÝÕ˜°IqØ9VØ`Ã5Ôñ ·דêÿ}É ~ö RN9ßË6¥µ¸(††œŒ%˜¯±Þ‘§÷ó2d‚>¹z&äwäb™° šÜ ­X`kž={¤OK/ ÌícQ³ZTåÚc<ã¼OOiT³i CTm̦–W1°™q‰w¡U„-˜cíj³ôYé”Uiý^ºæ4Tq•64vÿÌHû)´¨Å"_¤vÎn¯„?ò¨!b¶ñ¯ÑùiÀüXdøk.±UUZÞè|ˆO ':æ¨Ek·rÈEýªœî¢¶) Ê>‘„ס:5íbÈ]P;ë‡éti‚©êt§»t­Š›` CÙ»àÂ…=ÁÐ¥œHÅP!g¦…ÊòìtYñ¢X£µfÄCçÁ! Áâ=[.®¡Ž¹âòzŸ}›÷>y»Öx¤j“²89äCr™’øzÛÉLÖˆ‹%J&„9ë›H@Ú„ŠçÞs«NŠ'ž¯Òl–jíi‘mRQÇôÂ0 °xŠBÿ'c=ãmŸm̪eôBÅÓóERç„rˆf\iÞŒÃí!Cªuñ೉´±µ²él£–²f:Ϙ»UF"®0"]´È±ÌŒ%â•2#ZrÅ-×m/4»v͎Ť.¬š,ÙiYHñʨÜi„6P=Ýéà ŲæÖÅ ¶Èíõ3’ÖŠ$"ÚJ€(ÙZO 08K1g=¬–áb ‰pEðfI6øU#H“É‚ƺ ~‹×•E§´lq9‹rôÉ-£>§œzK¦qì:,»Ÿu®q„#‹àdá™"X…Þ gÌÝ AûK൵5\X®ø‡0Å'ዉÎâCmó£WzN‰ûPƈ©~ÔÛK¿m§bõ„È 5Mí2ƒæéŒ4yîP²qž ¸ÈéSAYqÎ~~V "&‚Ù QŠVoA?žÅÞqÈ_=Oäqz—Ó9ûùy¥ÏX¯7».“Æ3´ße2Y_VдyYÃ1:DmÜ6¦9Ç/z„jƒ£4®w¨Á34cîoƨZêÞ¹ õFm)¯íøŽl¤Ðy¢±^Ü#Ž4îOEes@Ý QÄ– ÔWí b Ü—eØ3×å[ "PÛ´ &}Û´ &íP<-ˆŽ¹¿ ê˜Ö×eüz±XøÚ‡‹4-ˆT½ú‚H-XÑYb^Ìú¶8—>ÆCâMùõÍD¿îûrB.JßZl‡!N=sg̽FE¤æk¯í0ø3ÂvñµÍ„¨§‹5$qé; Ê@ßh˜ûS¶•ÞËÅwµ±ÞZ|„Hi§¯öçïéÇ©šßãåŒð`¼Ê÷Tex`,0CíïAÉþp3žc¯Ê€¨&_:lã4OØXêœýülqÈrß¶¡Çq§ÏàüÜ!õÿ »FÈ endstream endobj 12 0 obj 1606 endobj 14 0 obj <> stream xœµXËŽ[7 Ýû+î:À¸)êÒÁLìÒ ÐEU-‚™Í&¿_R×¾/$iбhQ)’Gû8|Ýý7„á&ìy(÷u&:þòqøëÅðï.ø÷åï]ÀÄð´ƒR±ñãàc]K*„óÀgÿÙ}zaÆñO-üþ°ã¦úöçáÃðÛ½šNÃç…ãÃçÝÝÃîõJ_öòü‚°o!¶<ŒŸæl M#áÂêÐÓŽ²ÆéÂã`BjQM>QH ©+Îlô`ܵ?ÿ0/¿êÿ¯t»Ï¿d·7ZT© )Q»±ê¸ÚÚ7»Ó)U]‚‰fJ‚- ©¤»«”u.éw*M4Ç€öÒoþ©!‘n›$èÚ§]¬º25µf›_X†“/ËT•mY‚IÌHꜰ90ÕÜKËpWDµìòI èå¿=äûĹó!ßæ¤©oÒ!ßß=¼ÚBQÃi(”–fZâ£rÍÜÃL–t¶¥Á5ýOƒ¬#¸Š¥ÞG8‚±±0Ʊú)E½f^H]obàq÷<°~îN*À/f Ãñ¢–rÞËV@.&Š©—±C¤¤säŸh.ó„(è61UGCÆc*††Éf17S+–@Š5˜Ož tkéI3Ñ\nÙ¢!{²ô‚c}`l³3aˆiDùŠ!Ù1NõVQEDЂ`,8»ŠÈ1e Z¿—9 Uü†JZòû9+m§Ô¢&L^¥{΂Ԟ?ò¨1Kü+úa#ß" Rº/2þÜ UTaIõl‡’Ûá¤ncÿÓðçßýCÁ¿­:.Lw…u$,V:ÞP;ø7T©Mo£²‹AŸk´r—îÌ¥ÇÁ% Áð• ûs©kά<_ÛÍ~o¼®\ª½Rµ0®žv™ÿTNIs¹öæDVü‹3`•tO€RÑ9ÇúTsfÕÏiÖ¿¤Zž [*ê†N˜šR‡4$ô2Óg½å6¢Í@£ŒÞ·Ô=¯’(3ò&Q0äJ";]Âá¤(–8g­ëm-3(K ÑW¬5¤®76Ñ:TL5ÙB'&ÙnÅ)SÒÒÑ,æ³æfVKÄÚòª%i=¦ä3i-ZâÄ6-—ìÍÆ67—ļ.I#™š;Hàxžõ5B ¨otcFqª¹u7f¹}îÎq:}±Ò/h+®HLVêKÀ')vÄÙh‰Ãj KHÀàÍÂF6ª-`Ã$øÏZ›÷ƒÎ&–+óÀôf’\8 IcI+²bW¡n¼TΪ·àâí‘Sç ×"Õ‡:{ázÓù3dzõµëA‘-·ZIõS¿ ñ |À²Ý•//hœ9,ã-”ká ÕÞdBÔsØnÒ…ÎP˜½j9'™K]qfãÍþù»])ÄN)È8èH*HòÈÁ/W §Pmfo;Ñ êœü¬·M3ˆ«3pëÄe,Us¢ >1 böà•jPò®3Õ»L6X+cúQ²-×Eé{Ø£°rŒûeiÑýáFágº8ëìÜU÷ì·æi["ëÒ¨1s©kά\ã¿b?@S¬{SàÞÑEç(¤%YÏŒ.KÖ  †&OÁŸŠôF‚¿Í§šßÒ, CÍÆËÅ^±Êu&"ŠÂdª±wY\`4 E{®À…©æv³ÔŒÕhì™øcÏ@ ÍÜhë¶Û–¾©a¦fµaE«×Ý\Èy•#T3™Ò=Ùì™~-Êw¬0”îã,Ï»$¥s£+–Œ¼ÄK05Xfí*Vl‰¡%Äꬷ¦‰(Š@R5'²Õ¯ÑÝÀ+ N±=øñ«xb»ùÏÓ—YÌ0¨åÎj-Á”ÿdEÍæÄ"™j^±ænÉC%dž–â«Tšr²–ˆe ”Š@*ÖJϨQs}FÜ/ œÈ&¥°d¹N1‘OÔðÈ'j‰ ‰'jéš+BÍÀWÖʊׅåó×Y7“ß¼´¦n¼ 19ö'šßpÈ–ÆÈC`Ü5ZÉÕF)„·|Ü F­TTÒsf¢µY%ÙiaɾÀŽ^6{x%ýŽN–*ª3ò6)ÝFfÎûB"´nî¿~tM³Gȯ­Í¿ï5O–QbËw¬§Zm\Oã÷»-Wª¯ÉŠ+ÚûZ™¶}·G›Xå¾¹5¿ŸÅ0v¥E”=–åDÚÖ7_Ì¿§Éxª;)Ùl$´»ž•Ê[»ÏÂY oVÊÙÎÃÛA¹MbÞþx§ztGüàb}<=â)7pf?Ýl)3“\k\9þж@²>e^«ùëêõð?¡”Í~ endstream endobj 15 0 obj 1721 endobj 17 0 obj <> stream xœµYM#7½ûWÔ9ÀôJ¤>Ã@ÒÈ,[vØC““ì"è°¹äï/ߣʮ*—Û$3i‹E‘?žÔá)Nþ7…éCxÒ©v}jSîÙÆ¿ÿ<ýû«é·CœðóûÓÛL•ã×ÉǶVŒ×Ïþ÷ðËWŽ“ðÍËA»ñó×ËOÓ?>šè4½ür”pzùõðíËáûþü”ß_žzˆ½Ló'•¡›%ZÕz;H1;xH¤MäëÍ€´¡ãJÆ0ÆUû×?©åöÿ;Ûî×/²Û'3-Õ§TªÍ˜ÜØlܸöÓáâ%‘fK0ÑÉ”±E£lw£ŠÍ%ûΨçlÐSÎ[š‰"bÛ¦líÛ!6[™ºIãæw–Áó5b™±*—%(2eÊe¥KÎÝ`éêæl\<|1vø?ËǤ¥Ê±<—d©Ÿ>¤cùöôãËw{QÔá ¥­˜žô”¥Íb>BLÍ6¬é*ËŒëöÏŒlspU3Ê´p8ŒáØŒqlî¥hǬjð-¼Þ¬¿w'•¶ )±ió@VA…ÃGLrç¦ÕwŽHò7[òmsDbµÓîÁ-j±]b|µQ,Å´µï3™ºÉnÙí¨}êÉ­¸2í Ø¢…U¹ ë5VR'Hm~ÝF‰Åd”gKJk^†ÇZФhrª× •ärâIŽÕÜÆc©F™2rt’#|g• ±Ì½ÚéC´%_÷“…¥ŽWkÚeõ3~%#¡¶I`•`Ÿ '@l.oÔb- ·"a,X;m·ÜfÆ£¶È”BÄ©×É©K@a@®©Á¹’ò~Áý2û}òd¿Ws³jÅ0~;Ô¦Z)öÝ‚X’°"WæADq²=ã ªÍyj-9·ö5¾ìé˜;›Jn,œ‹dÊ–:dB§HÙ3Pô•o»M¶ mVFo&¦žor¶(Ò4I R3 ½+pNŠ™yzåzÜkŠG¤éÜÌzBxÜmr.ô&•Z(<Ç1É*U§ÍWÎÝ"’#¦Ð+oúÄ\Eæ ðNÉVQ37­÷»Í¨#»Ýf-.ej]“Y²wÌAãÌ4ÖdÙ( VNlcE-l¥5¤/rûRºÅÇÀ q™#¢­¨’c"L©O¹ÒÅ…XÁÃj.LH„+‚·d%h\ ŒIeð_¹vÏ'z–i劤)ßq…  kN7‚Gaj|íÐÉ瓦Ž%7ÚìãQD˜Í_Cf{«îóé>í ™¿˜‹|¶«Þ^ѧKØÚ[¥´ª ü» Odä0OÒ‰T½j9PXSƒq%ãöýûw{PˆÁáŒa$—߯ŽVÀÚªso¿ É2€ò•oÕˆ6‡Åì¢u.Uk\ƒ ½Quã Ù8N˜¡óÝÇ6j•1ýUlƒ-o‹ÒŸ7ŠÂª1>mK‹í5ª¾ƒš³ žÃÞŠž­p®SÖ³I‰µ%a—FYSƒs%åFøû!43»·=Ûœ„Ä®·j“è²ÂV64y ~e'ü¼äüœfPZám3öÇ–#‘lQ˜ÈG—ÅFª*ò–œûÍÒ2Ö¬áÝí¯ÝÍrèT£ß¶Ý¾‘ôY 3uÖ†¡» µÜ䈴‚A¦ Mv{¦1nDos5ÈÏ]RÒµÑU&£nã%Ío{ź —0ZÒ ¬®|·0E‘Ô¨Da æ…1y­RÞÂcj”)’¹›¿E,/‚±@ •;ÖZ(GÀ¢Î¹LK–œƒØr§ä¦ 2ÏJñC(­ˆraKÄ2)E@U6…:2jæ¼õ‘ލ°))lQ®FL” ´Dx” ´ÄÄ ´tÎ@­ÀDJ¬l•· ÛÛ¶£n?ù\ÑT†ðŠÄÔ86^p~†“™ÆÄMPœ5ZÉÃF™w ñ8CMze¨e3TfÁµ[%’ð…+lÑБÝ@q%$ý,5TgeäíBºÌ\÷…$hÝš;óP‘òÕÄÄc¶ùó ¤{²Ì`Ÿ¯—Ö8n—ñùP"s¥ùšbàc‹ö±ÖG俨w{õ1µÀ*×Í¥ùø¼²aîJ+‡-ÃʵÏO]¨ßÛb¼ä]”leH ZÏ@W¥ò™çYµäª»•rµóôÃdØ&©îüh|?ÙŽxßa£W\å&-êÞ-L™å\óÊùõë]X‰rKf¶HD-DãÏa%b`F€’Ök`š2TdTÌ+ç °<‡¢ NËóåá,)‘lÊšî¯Æ L|ïË Î¾¤¢ÈÇR±ŽTduÊÕËÅîÛ2[œð}œ_Rwä×ÈþSu {Åѵæ1æ> stream xœµYM7 ½ûW̹ÀnE‰Ô`HIÜÒ,ÐCÓ¦iìh.ùûå#5žíÝ6É"¶8CQ”ôÈGÉá–†o»†0Ü„Û4”–në M´ýõá÷Ÿ†¿w4àï럻€ÃÓJÅÚƒ·µoT!L û×îóOfjá—û]jªo÷Ÿ†Ÿß¨iî?ïc8ÜÙ½¾ß½;Ñ—[¹Ü!ܶ@-ã·9K¡éLRIêÐÓ.f§ ƒ ÜHM>¤à•Ô6údܵß~5/¿éÿ·:Ü—2Ú{©ÔÎEߨ]ªÚ®Ö÷ýî¸J1Ví‚Í”C”¨’Ž®RÖw¬ÏTšiŽº•¾xËobŒQ‡e Ú÷iGU{rSk6ø™nXùB親ɺ1`1 ©s’̹æz}c„NjÑfN5i›¬×læTð:ÙrBI€­Z|q«'ÛrÎ57qiz,¢Z†³¨göù §\yŸï2ë·Ã ïóëÃÇû·[€mÑü–µ™Æé û\G3o`¦ˆ6 O¶t›þÓõ¬#Ž‹®Ÿ.ao±&ÖÖ½D›ªoéÄÒJêz3»Ëþ¾#½÷éœC) Eû8°£öÔö¸ÁçÑå D¬˜›¢än’6Ïæz'Ø¢¢(lA5%«±·ÄVÎ:5}.¦ÔÔvŸtiCcŸò¤´*¨‘Â=Ÿ  ˜€Åí¢Í†MXCJùÈb~SdŽ¥U"A}ÎÂ#»”épCêÇÁ>– û\ôCs-°ÕÛ¸/)¾.IÇAÄÃMl{kls4odfñÈ®d銻æÒãà’„`Ù" –R×\X¹œ›ÌxWÐ-U›!ëi—SDn)ÅÌ^DwæhÉ»4s°XÇì }çhŸk®çŸ“ê‰Gˆ4ã©–cgøEsà S©°8¨!3¢™žôÖÈ&s%9ï¨{Ú> £œ9ƒ© Z8ÚêF,“XèLZ×i)'”ÈW,ßr׉Ij´ŽÎgÒF~`›3JÖäÑlΓæf\ áhõ$Ï=å…ÀM{bƒ–ólÑC{“-–æXÌëÂ:“¹¹½„DgÊ«ÞGâÊX7:pBzª¹u7±½dêcùQK! ­¸"ÄFÁ%`ÁYŠ-q¶²Âa5‡‹$à ðfIV,Të “ÉÀ?imîe[Y«¥KÁ‰åÌRDYIø¤°­P7^ytñ8c[¤zSßžKÀ@˜¾Ÿ Óóo´®¶Iȵåî˜r%èP)N)Ø_©jB£Å×ö4xÿ¼„¼ò¨€sX/2½½R_#óÄüz½’§;¯–RW\ظV_ÿÑÞŸ-ò_ÒÄÂÿ—­#ÓFL¿ˆ®‘—Ñí:2u|¸QÒ…¢Q"Ò¡V@"Ë-V\ öt™-@—’+ÎM\£×ï=6FŒô:‡åˆÂ>‡5³€˜ ½P-fÏ4”ÕÅjý™Ús¸%+ÙyB¬Èå0RÚfÑòö‚Œ¤FvölÑè׉uRÛfE(Y{‚B$ŸòF͸2ô,baÔ!Dlw Æ­®¶"k‚ÉÄDwe“\T ¼LÎ%ÄÞè"Gî|€ãå(­02ª)HÜ“¬Ê۵דÞi5ª¿f£èÊ6“°‰…ašáŒq˜meípÜŠŽ³o‹ŽJ(vÔºŽP Œ¾º $Ï(,”ÈnÐ1Ú†¶^XÂ'"?ÅÍ5O—¥W+r^yµ|ZXÂ\ËÇ«Å^V‚©WjG­+Ù¥"”)VÈ]’‚–l Æ6Vñ¡Kv·òØ;ÞyoÛG7kÍ›U0ý¬ÆM@•‘¼«7ÍäC|´Ç£?¼³ûçV½ý°˜Çœ|f3ísg:IÛúݻܑ}Ž4¡À¢"^í‹qÖ=Ù-<Ô*RÈÎúÁ¢B vŽJ´ýšôžRËt䇋d})õËy4â˜B’æ…ÉOÏžµ•ÉÝšimæQŽØ(Êé„ÈQd½jvеúö¼ÎÕø«ÊI*ëõáFöZî«ß<Äl‡ÝI—Ót‰ôÜUmT½£Ô/̺Ä(aú$Y Å좥X&P Úˆë`-M½µÌÖƒ·[¯­ã8:ú¸OnÉÛ ß·ñè¾g7“Îà×¼Jýì8¶· 3IÄGJ ¹³},)KI›,²yø0h…Ç)m}T½O:"¢ÏBGÞ|ĉðX@æL³*Ô¥®vì<]ƒmÞƒèqµ\Êl•ªI¸•°*6g§Š€$°”ºæÌƵ"í{…iå*N±§ãp¨¬SL9R°ª8eÅÐOÝök@¬ýÔ]ÎP°ßAD‹½'+Òœéôð˜ŽL#N±ÏëѪÿJø™æsªB侨oᥩ՜¯_U"çWS-ý"FÈÎÿb÷±8ÿÏ5ÏÜ7 õ¥6®§_r߀‹Hô¿ÝM¯oìàeÕìº(4cŠBïJuuQ1V…ÈÆ¯p£–5CyEf5Xö-v \Äv'%à·°­*~ûÈ`óFËTŠ’b'K0ŸQN–8´þ3Τ¶ý»V¶ ¡¼*Ý—w/L˜' endstream endobj 21 0 obj 1958 endobj 23 0 obj <> stream xœœ¹cte]·5ÛvvR±m;UìT´cÛ¶mÛ¶m›Ul§Â[Ï{ÎyÏ=÷;ߟÛvk{­9ú}ŽÑg_ëÏ"'ù¡L/llk”°µq¢gf`âÈ›[:;*ÙZËÛrËÒ+Mãpää*æNVÀÿ-Ž\ èàhnkÃó_©¢@§¿1§¿*fÎagS€ÀÌÊÃÌÆÃÆ `abâü¯D[€‰ƒ­!¹¨­»ƒ¹©™àß·*U%ujZZºÿŽ0sss Ýÿ ˆÍMmÿƒàoÔhekg ´qâˆþ [Y™L­ÜíÌÆÆ@ã8Ô ¬€– s+s;;[•(õÿdùÛ(3ýß?v8r€$Ðèðw¤þ#™„­ƒ)ð_³0q²°¨ÌœœìxMþB&ÿ@ Ž& 6@'Æ¿œäâ6Æ¢¶Öÿtã÷O±˜¹ÐèïðîŒÿ‹æ–6¶®6žÿbbncüÏcg;FUs{g ´Øæÿ ÁýwÌè`gbaâfeí@7#3Æ6Vq·þ üWØÀÆØÛÓÎÖ`b`åô67þ½Ày:¸NÎ@oÏÿ7ð?WpÌÌcs#'€!ÐÔÜî¿Ùÿ†&ÿ±–3pr0wh31üUÀôÏïßwºߨ֯Êý¿Óå ¬€ÿmîgˆˆØº<é™9¸ô,\Ìf¦¿óq³°¼ÿ'Û¿uø/ þýa`þŸ=2ý7¥´‰-€û?Fù«áŽ`tù_¨þñ55àðÿmÒÖÉÜø×2ÿ6¦;Ó_Oþ½0ÿ¯†ýø¿mûÿÏ©ÿp‰þÃôßý?:”p¶²ú— Tÿ!(௢6€¿¢dÿ¨jeàðX›[¹ÿßÊþtuà<¥ÿ7:i'ƒ¿ÓÛ˜Zý—äFsG s7 ñs'#³ÿðݪ6Æ@+sà[GóÞ zf&¦ÿ/¨bfndittü{´ÿ€6Æÿs[Fq#[csS€²Ó_ƒ8ÿ;ðläìàðWì÷ßÚÿZ›˜ÿítÁ9 ¡ßY•iå~¾ýhê¤d¢ÑTÝú¶{Ïí2ö^Œ{hGר‚}Wªi=,, 4Úp² AÈ/’аì¥Àú/€XMŸ„}¤ØO¯^¢+…|—1êKñn@eÌ޽ÍmÏEª·¾Ÿó“µÙÈIJ bûäJt?ð¦c¨jÑÎÁxcãEËCC¬¦Úôù‚A¾«ñûâ£Lo Æ‚Aƒa»ùèòÛ‡S¯µßz3åû´Tí½hïá‡ÉeƒàßeÍääßÔU:É-SüÈ~*íç$µbEÅÌ0X¼Ï}Y<3gW›«tÞ?/} ñ›··šÓÌœpû•^à¶ÎE ¯¸½6:°¿G¿R¾j’J>sI¬s7>˜~m0¥}¤R¤†'HwÖœ¬…Év)<ËñÁ+'Û±éý–[Àe–&‚8#sYÉÉhýbÑ7öû‡ÓAž<äë}ƒÉwhÐ$æ‚=ÈW4ø²Á³c¶ÞU\-ÿv/ˆe.eŸ ‹á{µæ®´ô?ën_ª‹Ö…އrÒÎü—×'à GmJòxüü”IÄ7‘¿Î4·ZóÒ•¥0ìrC¥Ú•}Ì¡}ŸëE‰öÈbÀnzRT¿iû¼3îü›–)‘ìMÎå:Èõ/9Ÿåª‰_TÃݲ™bºD d¼‘iº°‚#?¸A4‰tP°ï±UÂÙ¯%•˜]7_ÚÃIn’Ð-rb¼…)~¨îšÉ²E—ä”Yb`*KÆÕo¶[J¯ÌÙ0AøŠÇmoÑ"”-«LùG´*øuU>Ž-C†ú6ŒÞ£SŽKj0Ö¡üsv‚i ™‡÷—î.ÔlœIù A¶žS€ â½ l¡tÄÌÆ¼QˆÂ#'PSfQ9!•Ö!¦_ «ÚRþML#Þ­æMNzÅ"¬Ój 4)€ŒÀˆ~þïE5”¿Ö½ÉŸ>ŠŸ$Q/<¨Ò«Òº£ÃÜKÚH4ä‡, £}Kq'ïž%™FûÞ›_œÅ5Ñ·a#•öÊ8¿¿+£rK þëÙîÈ3¨ø¦[>±A á]P!ªtŽQ>¥´Q‡G¨rÇ´qXÿú1EÚy¯[A»ÎùÐT,Ýi£R%^Õ̱†óP‰erÎûÄ¿‹š]÷ÈIˆwhní®ó†¤³Øw*ê§cÈ›G'TŽÍƒºórEÓ³ 5ÈÚ-ø¹œvµ3í9SÃgêב{êâ¿ú0,€Ò4¿^CË`^/¯²h5+ÓB ^~],@8Æ=HØço¤X®_m.G×p¤’D™íͬöi~ «åÇŒe}ê!¦1v.Åþ ŽêôFkŠëd£ª— Øv¸×ÜÜ׺(ˆ² ©×W­ì˜D/\ÝöæÝ˜œŠäüõ†Î$¾ã:’ØǹÀ÷TÚa:vYš‹u‚k46 mÞéôý,oUvÑÇ0éÏOØâ+ŒêhÒÇ™<+¾ÒËÉÀ¨Kß×ýÁß%Â¥Y›Ûz½Ð´ÒÔÒë.}=û;ûq¡~ů“¼–0”ž:ÖGì3ાéSÅ\qÝOxk ¿¤;'nº°&ÈdÚW<~gƒ•Ž¡Ð]:æ…$¹Ô8Ⱥßb±_ÌÓ í¿S‚8Õê` ¶˜Ãè\¾¥öá=¥‡ON»ë‹ùÜ€íaD~,$AkäLüiÈ£^ü,nQcÛN¹Áâ]Vª;æI‹]ÕWm¥ŒÚ¼ëÏhßo‘UÔJ %šHÖ¯f”R&•h Šõ¹¤+A-CE-Ñzx§P¯ÞþÍAÕé„0EÔð[ÌDàÍñlÿŒ¤<-¿ÝÜ“ûœï‚®¹4ÑÄ9©«Èü Ñ‘ŸŽ"¢òÄfkoTo“9ä—ûã», ¿0áì×g{Üc”VLY·‚ TzÎÂiRÊŸ‹ìZ\óöç)Ïׂ¥ê=þøl /½UÌ9!¦Ê‡½Ô¶ ‹ÓôçÜs!í°ÔÉÌ;?¿Qdƃ#H}MÎtÖ×"N@t“äõ釩'‘hõA‹OPSè°y­¨´óŸAºg¢ÍÉõ*Ý[Û’3í"DHáCëmЫÆèYv$f_ÏŽ¶Õæ+(Íg†pÖÎßk´•¸Ü[»ÊÂ\­[W¹ËÐ>æñç(Ï·uª6ÑÕ8_.”‚cQ]µiaªo‚ÁíhnÞý¯–"_Aíw¦8!Ìyçžbj@&Š Må¹Lw™ðµÃF>HòÂXh×e4­6æÄòú"iXdÙµ´ ÙO¡þµ\?Ì%ì0ÈÁºMl\Û“!1žZºU‰mZW Y年!4ã±1Ъ¡/BÿXoƒÏs&‘Ú-Šlt}­ö(‡W8c“hÚÚ;à Ô~ £ õm1„0áPUyûÜ (ú×E²›+Å`îŸ;ñ5 ñ.™ë+iÃU{J„Î8½¿¦‚ bOœKÌ#²™ó…ÆA¥_lpßk&÷ˆßs!†¿ÅÞ"¸3pœ$†ðÕÀši|âH\¯B'ù¦èÇOø7•+gá/.[|G9ñÝ»ðä †€@PêG×ÓÇ?Ï5–³ %ó~âšI,¤7\)òÕÜ"ÞˆB_CVÖÕ,°´";ïRhjvž… Œg]á÷¹H} o‘MGûÂi²TšÎ8²­$~ãbP–7†<}>S§f,!Mö(Ö9ƒI§˜^«š4ÚLŠ»‘ä"­#hþØ+]辯-S^4#C¬ÎËTÕa1+I’W©ï©[haÕÕV$¨ŒQçjYsqê?âü ¬›0¿0‰¾3,Oiÿ4ETê´À&7Ì$[¾ä€F ¸Ðm»¨³w=žÐ(½ï¼êLÈœ>ùy1¿þt¨˜®£ƒm4ùã)LJœXrý»ïñ½@Ó]HKÎÛÙ^Í\Bù§­È9…Øçùh®èGµ˜€Ü£ŽjhdpjVØ›¡Ó–w ð`G>¾­ŠXEÕõu4›["‘ƒ¢°ÞÊäY#CEþñ»$šVà2Þ$!÷°?áÝ5ÝN¦•kì…°ÐT¼wP§ÿ i¡þÃö šb:]ĵچ… }*MÙ½]Žà!(¯†›7'HH«I¥\#"ˆûÌ5á©¥ØÔ’,›xöŠ¿èÜúË¥•ïºÖ•qªO,äÁ2øö·uË>øAZRïvÅFÕiÅfqõÔ%±k8Qò¶£CóÞ®ÖGÃ\ƒ¿€ÎÁ—I”2Aò÷ú¶s”D:¿îWÌùÝÄxTÇ!‘ƒÐSI-éÆXš|o=?ŠS,èëû¢Tê#ìÎÚ„ŸëÚõO ‚’È·E2ñ ØËжݴ˜·_ß9æó¢ÛÐò¶ÙY@*xnksªèõ™) jŸ±÷­t6Õö}Ÿï³´Còg•ŽDª9%ϪŸ²^J*îsr/¥a_–ÀŠº–DZ£3iÚ Ö²’ÒW™µý”¢{X“²Ý³VÑÌLžýNg”gE9ñÇ2 &JS õíónÈ› àÑ¿ˆvâÙ[0Þ©<—Ì)N«²|Â.æ lK{mšúè7F"ó ¯(‰¥_I묜YWÒ> ~ÝÎÀA®E-ɶ«çkÒ§e‡é&£zŽ>}N)„lÏ£~ŽØÑmòÚÿélÇ( ¶ó½i½i+µ°´8\ÓrÙB3õ _,¸ªÿðJ(s©®;KòÏ9<25/”ö¯qÙ 9Œ¹åg=ò³Ä/ãÞvMûŽŽó4ZçÑHf²LØŠ:ø›ŠœÌÃl ¹öìs$‰Î›Ö›©pXÆG~±w~/d¬×,S}d+uj¹ƒŽÓúœÎ £é2±\p']¦Ÿl07ÍAÙmqYÒÁ²‚‹ÑsŽÕ0ÜqDÅ~»®*ë¤Mjt·ÏKŽ'ÅÉ&àáŠSà~š#'  ‘Vc º(ú¥ ªaÉSÄ!xŸ$"} ­Î DvQ—Ž&n 1ƒ •櫹 ¿À½:!èң˂è'ûqÞµ›zã¡8ý¤ †ÄUôç*ñ6fd2~T‘§)îsŽy~)3ÙHŸÅ…Åì\Ñ_@ëÉA—)^Q Ñý¾Ö,ÞÄOgËeó R­œ™(;;AK²f£“ÜÁL®æÆà»+ÑÏ"¾G÷œ°_BøoR/½3nyX‡v8!Æ!”W:ÎË£Ï~Jæ*®â1x”Æ ‡ œv:>]Ž“¡&æÉ¬ïîãPæß´ šW[¬7ÚÎç`åï#Ùáã\”ò2«Sx ÷7k‘áe‰©6†„¿ÐáŸwúåqî³Ä/ ÁaÖ¾î#ƒÓc¨ ñpnµÈל”æðÁu[Þ£˜~\ÏŽÔKñ¯\ûÄ-E”—HÔõŸØcÆFJ®¶“ñï_Ƚn»0 ¾>9‘‚Ýf_¼ÿ„L·5Uã•;dìØH3ë¾€ï× ŽTqüͺô’«ülѸ¶Ö² †<ëâÒÛÝjçd=5RBPÅâUH¯=B€W4–aF”yæî¯¢cè`!‹¬s³´.`vÍP:Ä(J|]ü{¶W¸¼Ýi”HJç{Võ£½d ”bÆ•˜|Ðkha¼Ñz,?5«‚ÍèŒpkS6i-5ARľ&¶bì]i1ãÝý`£Yèpâå1 ðÛ×Qàv¤mY†›¦(J4é{À „ÁŸý†÷ ø`>q68òR!W^vž Ç[U^þÕÝGü{ ,8P]\âA^JbŸaš°CØîy{›Ko¿t×i4ˆýMNˆ¶T!v_{­ÀLï1 ´*âiǼŽR€-µâyŠQ,È0Ù²žêI}¾—U uð^u‡ZÕaûùõ¼b‰}MîâóF/¬W)ð„§ÈÍl˜…aûQ!&]1ñEABšÎ醯KOè3R-e°Àȳ`g"ãd+·ð‚踔žÓûQÕhd™Þ»;ü¢¢bøò=Ã!®› &èsØ­C˜#b½¾A|¢µþC{fÓ»¨õ½ÃÁ·mª˜·+8¿Ü‰ÆS â„ ã,(oÜ]ïb«„DÜÛ€´NˆêvÚÈRjâVÈáËÚo³`5reÞ¯·Ï'ù)mú¡öé Àfp„©$ß%ã ¡Ü-¹ù Œ0ê±C飹ÞX+´a’3=Å9„ýÖÞ|G]CÑO’Ìø1ó1|C•ÔEíâ#Ù­‚y t0{hRƒQE»››üÇ'6ázûœ3†Ê‰Í¡ÈátÑ-\îåò¨6Ð Xc 'Œ^ü†(Ò«¤`†ý83`ÍØÃ”ùR’äçVÞz_b:ê¤ÙqVÄI÷¹Ñågü“CëRÅRàt{̬4 -)ä -<3-–ÈÎ&]:à™>k7®E ¤Íß™zznûW"ñ¦é×^|˜ÔK"‹T*¯ÿÜk¥$%qå)Ò%R§Æ¥M‘ˆÉÀuµ ôòó0ô–eÓbȺj¡*ºV,è'ùiW7°+܂ވëÈ®Võ…-Ý— ~AÚÉq^誴Η¸Þ÷ó,0½‚᜹Ûé.AÖqÈ4Ö…‚BVÏàJY},Rqë$ÿÖ0ÐÅC‰-¦…õgÀd2&p¨‡ÄGÅvhž´ÌÎ*oe&‘Æ6žÔ(ÌåÙ† èK)©e/üV .ñv|›½ñe²X饫Â>„ñ⩳ÖÅ=Ã*ê§Ž-/ŽÜMc èV°àþàÃpV ‡+Û=ÑåÀ²áÛÛ-„Æh/çæråÇÜÃ)NôÉs„Ö~7W0ïŠÿ¹Ô'Uå&åQJ›°7陸Cåðùü¹„”£ßÑNªVk(NȬ¶ÞwTÕb¹x+¡qÈ!%`óRÐAVáWµåù~lÖ¯V–^“JXxå{§®å×è E0ú[L(ûoÚ̽"FYfsôþ\ˆï>†ÎRî9ß{¹9¬~k¶ü9mdÃ÷M‘oaí.þ®Ú)‰.Æm]Ó¨ÏЪ-VV{sÈ`[¹/M-˜=ô-5N×ÝÿBö4üVÍÊ)O mÃ=žlE]MȽt¬Øa(ÊM2ae|·$åé9¶ŠvÖôÓëB³ò#Š:wà€4Ó¤-«>V€-(ëeB&eyC­Ï¼øUåÉÄ»ª¶û£.»ÔZZ—æÞsE,Æã5”½î2 ûÂâE‹`±©ª”=ÖúÛRq£è±!ÅHqhÛڸ÷/Œ]”]yk;ÕfÌrg8%úÒoG¼‚ ŠÓµŸ¦ªd èÆo£hÅ¿²ù9Rù*ýkYutª†V‡´uŒ&qšg7õdRÁúçlëé\µ± àvñ¿;ò ÓÚÞkv|Ë 73–ŠzZ哱>= Fö}^Òúƒ’ð.…L’Dǘ_bÍ瓞/ÏÛà é|ä) 9­ûé¿Oóe׸:ôŒ!¼OÅd혅‹*:å\û†™¦ˆÎgØ.Úp7‡´y**,¿?#zK‡Úæ× â’ƒj çâYf8\^ïÿ‰â;ÕõcÑpÃt¬”H<~aç]ýCm¿Ls&Ü?æ {µ9ø.Ž"­:„ÊÈ2ae¤Ã®ß”&Žº³>§¥A¾Ö#ã?lâçµ!™=…¥Bðgճг€¥©xÖö›ÜÔ‘ ¦&›Œ”Q¼0;F™ß쀭 ž÷¬Î­nðj2¦m°‡ã¨»ÿú&_½ÞÂ@eŽ¥ú¹oK²H÷€œL–hâ»ÊAý^4Õ´3F`lvƒÝ4£tçáÂÓUÛdí\©Œ#GRˆ7xyL«×"_š~ð'ŠgÞ‡xž=·¡4\GGÄSð@‹¨Á‰`Ò¼þD²üd#­÷ÓæYz¼DJ¹£q3 ×Õå;.2»x#?É {øYÜ”áÌTÑUÈøÈÁ¥K²•Ç­¸ã†*Ò‘OÂÜ`åRÀôÞ€t]AK%4z§¥önæä“Òtï1câ@ÎÒi‹kO¤»¤Ÿ×±î"ò†¢IùWÄÌÆÇ‰õŽÅãk;àŒ•ÝQ¸a´ë#[Ç¢¶»7ËØTõw#A§´½^¶]Ý£¥¥/g—Í©®]øÈŽýjpX7¡œvœþ/¹eÑèmžô. <¡[ÎeÔ:×õD¨ òÞšˆ h0 „ˆb5oí·nÕeM²Ì¦5jÃ=ã E$]Ræûðâ!™5]}gúGhZÃÝ®ÙB©N NÝ÷úïG “phü Hjço4y¾Ï‹Ü|båÛ¼3bu;•éùâq7=™Çwh»‘5]„ë‹ð€KYmÙ>KÑŽäPóeŠkN¿Ã1©Õ.FçÇÔwâ×Û܉‰~á"ì ñ³‚ ÜaZÕov½ýÞ*u ¬ÁF³-·]UFø*ŒhÕõ ÀõæŽS‡åS˜:ô–c¦çE ­}ªî¶=nÔ±Nc®|ÕmÒ¦l!ñNÆŠÚ7ójoൠ Ž>€G*.C]5‹Q\åë^î“ÂóÁÇ S31ù¶LÛFÏ_ÐH“ Ì¢\‰ Ö˜K ,«FœÌÉç0É6"ÖWËoÜSg ÙD^§à\‡õÎn‚ÐR[ÚIt)—Žã¿Q¼°ýîzÕ«· LþÃ2Ê-2k3àÕíô*y[²J_ýÆ[L^æøÓiu-3Iòz.CK¬B|uÏÀ°qhÒáK #÷çº}€VÐ{ FLUlM%ƒU¢ƒŽøOBúW>KûŒKE£Þ%“¡w˜'àV€>½Þבæ|±ÇÝ—‡®†¸ô©õTŠ9²“/Ä«TUûy¼Xø§Mî×bBû†-Ú\qä¿BÁ¼ëävŠM’ÏsƒB çZÁN’¨áK£Õ5”çèÍ1Ì kÈá³F¨¯¹°ƒ1_o • ª½Ã*ZÄßPÐ\íÿ¼n€‘>°xéu0%Žƒ¨'ÕɰãÊ®á!Ê•t˜?ZdšQ ó‹÷‚¥v®»/ŽÏ©„ gÙ©/C¨˜zf¦{,îyšûÜS">ò­"Æ¢¨é–!ýõüä)/ošJTÁ=à^˜Užp«°ßªž4!0ßÛ¸[ѯ»BEô‡ŒË™{úȪàî¶’hªÀ‹ **£S&ŸŒGU‚ ¹‘ˆžª~S¨äCÞÓ›.¥¦AfìünÐ…×£ñ ‘}ΉÔ_É w½Íc-xèÿ±F×Û~§ù±CO;yë »ùƒ r‚'Y83É ìqàÁf¨‰œx!ìÝžkQîTÀe)ÔJ~‰Ž¾»À%©%ì Gušâ,âùô ™Óµ…Æ:æ0nÇ-HbÏgÿãÕuI[ݯ»=¢žÌ꽘;Ã䵚 ‘­¿òý$j©B(èà NyçK™ÏDzï1„y횦.GðeUŒÔþç!ÅÍ Ÿ)Ü/Ö¢²üi…µ¿?æª ßË·b+¤™·Gñ}ø¹%³Š\ ô„â¦gkÉÏ¿1fSjÕÑôëuˆòrúÊ”Ä,NÚ9¹Z ZŠ~Ü`’‡ìÄ0 ²£ì¡Z,,'Ø9ÜŒ$z_#i*¤ãxL!›Á™”ïtCm:´&áBž€È…Ñ>ú è”¶#Í6Љ´Õ5ŠºQHëruÑÔ3DPñÑð‚ô¤>°Ý#ð"…ËöÆ?#<˜‚®¹JüA(ÉÏQ³Hß s·F*«ЦecQ×k¸- Œ`ýZ©!‘ Hæ³~±ýhst¸¸•@s¶ÛAPªC%c_á볊›ì ’L¢õÔy^'E±¯Œf¥îÔJç ~¯^EhãCø&¥¸ÌêãzªÕÐÊ%>áí7œM~7ì¹ ™Åê³1³žkÞè–ÿy©Kaž3JuPu£—hv·Å}¾n*¶f[œÛ]A0•MW ­l̈²ÃþŽŸJì},AôÞwÙÐvÔÒ(ÞÆoÍÜgY$Þx’WÒ!죭ÄñÙ—Ø}uÄnèT·böxèuÇ6ÊåQØCö1'I¯hÇ:[¬™½aÖÙ“üpRÜÙN¸Eöò1)j‘b,áÿ(y¡% _†»€¬ªè( -ýìöíLÈþ@X®p# Š-Z©ïaÛ‘ÃˉA\}†å¢0#M±$¥ìEÛü(&›Ñ›ÝêCÂæ%¡³ËÙ€?B¹¥- Vï_¡‚ J‡¦pªBÅá*ô!ÎYE§œ«þcYx†:~5ñö¹êÉ¿Y}máÙ2À–pâš¿ ­q¡øÈ‰†OÊc"7×äWšc&xÜi-¢À¹×–-Å­SýÀMmè¾_²(‡%´ˆgWlÀÚy‰e‘ŠwOŠÁв¥r1?~¶0Øjf õ$Üš õá ŒX5ZýK}ì¯kˆŸŠGÖÈ.­Ëú­1·ciÄñ &‘̻ʟ„bÍÕB³{nWÍlåˆÒDBÞÔ:™Ò²â¦þ²3ñ]SÚ/¥°(|N+дJG†`~4Cå %,š0Æ~5Aó×\mt¤õé>Y3²Y»º-ò»iûàÓÚuN!TˆRaØ3ššÐ¦²@Ì‘xtÂ’zÙPÉX²o/¦ HPm+Ç" M¿1à.u¤"×w,‡ª_Ðé“C¥Á2Б¤!€îüNiômÆçÖKrfáiÛI—ZºSQú зé“[ØŠo[É2œ'Jdäv[âRtŒ¥wFòý¹g•˜;ÇÄiMðh`§ö4VüÔ‚p‰byA[¥_ØEô /% éØ_qÑ©K‚žEB>ªûñ+"àsÆÅô„$aGªÛõ-ËhÏ ÝÜìNéw‡ÌÌ}¢×¨0“OR+m6ÔW ¹Rs{¹6´Þo#òœš9#ô¿O”Œ‚¯¡á™Yº¥È‡Ê…ûÔnú¸Z\Ý4°G²È¾‚ÖÁSòx-ÇXƒvÒG­“³[§wÊsÔã,HßP¯ oé^ªˆo› ÅÛ+Iw5­ËÇ)ø8Ñ‚´Ž3â ì5 ¢Ÿµ›nƒ‡pmnSg-2žÃ›iú¦×ç¿VÒW¯Cü²lNe'·¬;ðlÀÁúSŒqМGŠo¯;ö:\C‰Ì\³*+gØ“­8.Ï9—è1ׂÙú3†ŽÏ2`ELÝ)q·+|~‚´E(Ê·Îú­2y4Çq×;Ñv0`ã¼½ÔK©l‹bm¡žÅ)0Ó QJÒ2¯~ù'Öñò7ýè|ŽrëÈxò"ӡ˹êbªCžø8å8›D ÿOk]Îë%4Ï#S¸ku‰#x‚T?AÓ% ¬’¿HýÚgÅ‹m\°`f¼ÀÎG£k=Žž$4â+µËyñPÚµÖ®èh!™†_#"¾¥õ$uªõ*½bv[ô¿[w9‚@ÔS;Õ|Ï5ç?IbYWr\Ë'kå'­[?±]Üb—çMê‰S 'å ÐeÌ€ýre´Ü“ÿ‰õn ؘǶù#Ý\cH(ÕʶX«…ó"¶J¿±}Mî^p"ê‡Ð¥¶xlesht–[´}¶¯íι7qÞ©„’µÝ"'c™„{K³´@y>d](¿||#RÑÃzæ›Æˆ ð7óG•ŒCá„¶‹Ùèþ†g{³cÖ_ƒéìóg´<Ìi@ÉãÃðö¥¼v僨N?ËÒ˜[²-h‹µÀ0†Ö-BÝ;üYÒ¸) hc™çÃfO!²6’"Uí¯ü¬¶ÀõöÐ7ô1Ò×Gé îÔuñÖlÑϺOΙ? :/-U˨î™mo“‹TÒÈ¿Ô` àCáÛ%À%C ÊQ•nï~YG(`d^0wœ½Èºêó-IEjºB¡‰aXÁA—ݤ±T)ÖÉ.OžLò‘¡7;.Y¢Ø g‘Ëu¶ŽúC½T/Zv{) îËQžIò)²Ÿ/Ôt™sŦ å«»›Óä‚T© ´Äm´¹5êx6ÿ3VÙáEPá:äÏdñ¨R¥ Â-5cUÔmÎ7eeɳ:£u—¤ y«swO”«‚ÛtìpÓ‡8§µx =1;×KVy¶Úp; Ì%E%«–'DK)à A|.C×µ~ßDãðÓTô¼¦àèa:­ˆñý´‹7Ì&  jù]†èÁ~ïÜKT¸êD ¤ <_Å,4ì÷‡ º®¯)0%È?¿o¼‰Ñ¶L éÙvhf>FOþ >jCmoð@õ×äVJ/ö®£ã¡8Xiwª" ‚!åcZË£b·úŽRŠ Ï–»]ta`fø·ØjîôgÔ¬ð:xÐçNb4T\XyV2¢„cmî°i—س1¼`¯1ã€Í Ð—:ë~ŸèÓ3+´­¢´“èF{¼Fb|£†õži8ÁB´ô[5¢‚äÍØ¤{ 1|h˜Ñ1ñC3KM§¦(0nïN2<ˆY…óq*ÆÓöÁ=dÅ%À DQ03ü<b¢ÿ‹FÆYSÙàItɣޤå05÷¡, ˆzb¶ú¾BîEA³q|é­ŽãÛ {&!Ch¶{··ó•±çeÿ m¨-мrÀ†BlÞÀd©Ó.5Bô eÏb`ŠÃ¾}«/òm¥12¸ÙrüæÎz'Y´) ©Ñ9A1_@Íeºäè½²Pí1ªzÁŠ`-W°,æÌíûºLÔ1Ì"•;[«1­˜s„š«$ÎËÏA¼ÎÙ•~öð|ÁY†yQê6«·±t"¦Ÿg¹L•ä÷TÍ–yt-R›-~‚Œî3Uð„sjç ¸Æ9&W~e<¤ùªF_ GÚÊíˆQ­v^Õl®áûÉÀa07½zæ]zF iRúv.£ß1ÔS>o“+ù ï܆Ü)wµéËLhp^ÛŠ˜éaÒ&|}í÷vúÙú±}`ü͹2@òDPÇ„­£W¯dkyÖ,›e€ž>\ëH€Í‚É@ÞNâneì/”…¼n=òú"Þ÷¦àö;%tP™Øæ€zKöÔ“ÕfJÓÒŽ˜ JÁG¤‘ªôc¥c:MÈOŸßÍDzkzoñ¡½Ù4OJ—ŽØ\¸/Ýþ Á_„”Lìì, èßܶÑÖ“¹¹ }ej Àn™FøÄyR}ã¢8`ðynLcêú%œºÝ§^ýcN~;2Õt£6 … ]}á ×Ö7h–Ög÷¥µ5ö•R‰U͉Á8h>SΧ×EÆ™šã”Eƒ–*½½ €dWE㢰QØ"qÆêÉa$©Ð^]QZlD$¡ÇûÇ™ô°v#}ă¿íd±$4…%š,_‹A¥%Z<ñ,é‡=ÆcÑ…ѵ¦“Ƭ¤Üw^Ð[Pý0Æo"ˆáTîb•uåŒH9´¿%6Äó­øÔ7u®TuTOKwï Á=j†›hº³ñÀ]VBº€^¹ABò!u°iUú.Ü’€{¢bqÏÀÑ|?ÐbÁNädØ•mŽ`㙊¡ L3}G*ØOºë\E.ÞÛ4«8]°ü’}«1÷[ýÉÕ8–üs¿ý‡¼ü“sTb!Ùr/`i”K ²\s0÷%wPD$¹Æ<$7Èšž™¡˜ˆÒUv]e“p¥6-e厃À§˜‹—¢+‹™ æRjìOÜçâd‰ñ¡²Ù–šh0‡½îÔ+ëöRŸ»P´5´õeKA–[WC9&ÒQH¯8h´ÒË-:»2UD¬I9ãsÛ­ºæL1ÞRsÎ/#VM.³¥ˆã3ü^ºX鯲ÝüÌs‡®iGÒÓ: Råq6HC©[EMÇ3ý°@Ý®ª ½õá½ÚßFäƒw¿Pªºô+뽩R¯/×o½FQnãYD´Y6ÁtFLD­Æ¹—Ae¸ÅhÖÝÍG°1ŒXӞ䟰¢L}š”.3èÖQ5 :p¦*}¤e_ðe(§F±X»8D.²<»¿F P8oŸ0×ï­‰šÏcªÎ~-¶ÓèL²Uv¸4OEDß>N0 ªW.ØìâJÚlœÙ7¶ÕRÒ›àøÊˆÓca ž,K¯ÿüÜKDæpÆþ™¯¿d­-H½¹Іöb¤3¶=©V.ÿ.åon|Ó¤&³:ôS¼ÎéSGýâê¹ÌBÑÍ»'Jæåé¹ Õ§óçÓ1¹sõÁ6iú‘çŸk«¤'ç¶ü?ózŒëkíÁiöðU Ö ^9ÎE>€Ê/²û²\ ¢}qÔïÝ¿ˆ+àìÝÆWÛÔÀÇòî}}÷LÐ\þHòõ[K¨¨ŸmÎxîNŵñÒ!£•‡ïV,”6Íô°[‹ð“sCÿ‰vf‡ ÅøI0 yÁg„°ÿ,“Ŧn¢!'ºA±¨åaNeÿ ,¤jx–ÊmLDÙRÀ./‰4‡éí‰k>Þµf,<¨×ꨑ ®¸Lÿ›ƒ`sgYotéÐ꘳ެÞe BÈû­îøÅZTÌ&€ ÿ­\ku"3JÏ­sœ¦ m÷1<‹ ÒÆ÷Eæ5iÖu"•C¡ø’­Üu¦t±^æÁUQêœÈR ¦2yª¯ÿ2þÁÚ#$S nåúM')Kyî8¼LcûæÏšB÷ö®Áª† #b|'¥´¤ð“ÄiÞ'më`•‘4p„6¨ž“z·g¾p®ú]Ëk¢¥ãWg,¬]OÝwò'X†y¨­‚͈¼ AG/Ë@5 ( °ñ5w®V½Ûr®f 8–ç§q©È„ìJõï ®$¬êÙ''0c©P&ø¬U Lþ:M<©?¿p2$ΘR'ÇfV©Ï͵ãD•r"ë“ 0*xQ$噌Am‚UÚ[úç ÑЃ¸Yä}×ñɱÓ]i–Ej£æP- ùÙžõ¸yÐöMT¤S“%%»ÒwK½råeÀŠ~|×KÙ½ƒ{øà-ï'’x¨).sê!n’íêœëgÏ\ö_·lÐÊ4±Ö×Zv{ãå’rEí¢nÏ2®'Êw#¸I·õÅcíHÙ¸OŽw³#£îc0÷Ì"ø1‚›ä7|†ó WD Sƒ¨Í¡úHùÃêyn´ZþµàòùWKÀøuã2o Ü+†û'üì°Î1&8æ·ï8i{ÔÑf>ˆ¯)×ù™í¹4ǽ)y%G½V…Ž7ËDT­†Nòª þ)úsÒƒñ!=ÑÓÅ3u‡ûÍ›…)Ä|ýÌ:–Æx¬¿;ÒÕN'éÚߌ’F å«ý»G R·<°f™7ÀþœLÌ™ÈC›žn®ïžÓö$Ö€/«„bƒÿÀ•­,¢Ai™ƒO=Z•\0õX5ŠÙ.í§‚ƒ¬?êmKUºY:„þ&„5áõ­+1a`åTéNjU˜·Múœ +£áGÍVÙS -v)•ù¡µ<‚Î[lR’¦þè-”´Ó«îYî·9¾d ÏɆÿýn>Q¿fˆÿ½ŸÝÂ[œ&sçM€í$*IôÌe˜?óTYÈ:˜MûU ñ”¥Z±Ä.êD—I‚%,o»†Ðµ'ù…Ú4L™Fªž`wÈ `ß÷&˜O@'I¢”ªo:8˜·â¤In]k'ìÑJ¬ Á§]Õµº@ŠóÔšûü{,–-8Èë´Õ“W9°!o3-¾-&Á¢ï¨¸mñû]ÞAŠ4–nÚtÉ?„Þ¾U¢…•t·¼ ³t£Û[¯±·#XŸ|ºg}áÌpå”y›˜iêwƆ&—²fªFMË:õÇ 5ƒ™|¡ÖO“Ó…ñ¦è™í.ÕPpÁÈóFâ¼)þš=Øf¥Ì,[d(߸º µð.è=v³köÞÏÑ1W;ºò=ÍN³&Ñ€±%yþ¼½{c;©–*øÝ¡ݺ®Õ“œ“m´ôœ_~zèR(KæçÈúV蔞ÌcŽ\)~¶>uFòêmµò1}£šû6(@µ“¦¼\^ÿØ“Šû½¤…ˆÊ¸?4/:ݨ³?L¢ òþ¦Q¿…^“zÚá8Œo#™´Y±„&#êžXžâ$³Àaü5[ßü[éj ßà!û¾“Ãéæ>t:8ï1§9©Þ†7ûwÓºÙ0Jî ÇËãuMjøóT†S‰O°RÂMÞW'Q=iDŽ‚«–N²„êeÏîÄÖ)ªXãpg÷»M¿ÿâ„ãôVl(ÑžS@þ”ÏüÅæ¢:=tÜ´˜ ÝL¬èÐõþ"©ž´\r¾ôÏ•B¸tI}‘Û´?dŸPW·EY$×YFâÞ©²Á2\õMˆÊïº8kú8™Ì9Í6ˆ½EzÍ~ää¨âˆÓJ)=ž¼e°<þnY³ü7–º')ì9µQ5¯È;î¶T°òøß³Ã‚§¿m ë¡ðŠ+K”T±Ç^!ŒU𠘞<ÎV;jûÀ'#öyÇÑ'¤ô‰õ°'æýêî¡Ázp=,*Déñ¶_ãÊ-ˆµÎ4cº“óâ7’!˜m$,/i÷=@««¯ŠçðáÔ {DM8üÚÌRÅEöÀé¼¼wb|ËGÿSBõ¥ðœÇù{X m°'’ÏÏ•ƒ¨Išˆ¨ƒH˜–›Ð@zázcTEéŠ9ÓBUXàhc‹]`ƒ8™<ΤÿÜQž¬Ø;s¯ý9q|ü£"6ØD×,`$rð=#ýK2›öY+°QœæÒ@`mÕÄ ÝZ’”œ ø¾\ì©a© Ÿ-m/f˜·™Nh›$ÒžæõMŒ[°êXz®ò´ ³¦‹ÛÂme·â³~óÞ›ßP½öÃÕ>ÉS.ÌãÕâ›i:‹pdÌ<› -þOh{VÚô£ÇFQ?@…h!&Ï=ªØ”)n"zb 1aí`åÓ0ã´:Éd%ȤG%cU!SŽ— {˶”Ì=1åÉäí;:,érˆ4+©¿S³Í0hú”ë!yÀO9ÑÎÓ~Zà v‚D*gSc \ÎÖú$"«»BBa%ÜFà3¤SÕ>„®zÒ¹ÚO¥vëÁðÊûh0;:xz Fà÷ÌÃiü4Ýhþ15¹f^á*–ôÅK¥Ig;£ý/M}ßhIq£¶¨yÌ æ—tBÃ;ˆû¸òã®xkŠ&àÈ›4Þ4|ÿöE½"OõœÅ³LAäÙ¯L7ø¸wª>P™£³÷Ûšö·o40 ƒŽ¡G7¢çŽGyŠÄ„ö%…B¯©á·ã µJ…_ Ÿ¼vAÖ0·Sfù­°Â0ܺži¯%M¾–¥L(@Ǽ@ewR²Ù7›©¼lõ…!  s+~›Îÿ˜ïhM¹çèú‚O××amñx N|Jº–ðøÐtŒb:IBÑŽ ´Ó$§3÷B½0`ÄCŸX› w8,ÕÐx •àpâ*Z~÷&$;gîäË9¼é°tQ0f*o÷¬ý£BCCŸa^,‚>ÛÝjœ2ò5ëÅ4H1\c¢6º·þÃñ>e«ÚЕôQP‚Qr¦o*ǰÁóRÛÅÚ ¢¦*†¶´P+’2çñòŠmóð›ÈáÐë£mg$Ê=9¸š“ù´Zö¡¯v³ö¢±X~†žºþ9°;–;éß I€ê  ð-ãZ™œ G£ÃYDÁW‚HœÈÂ^Û· ¬‘H.K(­ÑAˆÊ"ò¬¥NLæñ瞘ٶàÍ„#Ø·Àt;°nLv{š°ôˆ«ÄW‘j¥{¶=g E£ÁH!ƒY†Ü.ã?“zÅ£-ømš zm¾Ä)Ñà8ôk ¾ÊÇ’Pÿ1Å0Cù0ZEµ0uÙ{áµsì19‰<ðþ¡\,VÓÞße"ŹæÈåké‚Viq êåá ”8qi¹„Ï¢CmÞD.÷éäš×4=¶ö™íî ¹I›ía%HòC‰o'¾îãê-6eÌ¢øW[ðbê˜P4ç©þ;6VÀ‰ESQ(o‹éIZ}m0æÔYG•¹ÔÊ— ûQÀ8:ª˜Ã0ú‰ÈoÏ‘z=þ[R])WH€ªÿA²–Þâ íi#a$ý@£è/ÅÎÒñ³¢!îïh«|>̧îŸXÔœø1VríÈŒöÄtj±èió¿„s¯É g F¯(b+0Š'0ÔÒÝF¢×À‡'Xµ¢­_ŠÆ7Ko¹½‡«“ô²{t¾÷ìÕ @‰´JûBééüb½²!ÑsmûÝ/€‘Ê?/“Ÿh”Þ‰5˜õ’úÌ~3, ycõ»N5¢ù}oo2_å„›áçe¦—±Päç7`ËØÚzµZØD-bí†à8ëÈ êUB‹§©”w2j¾Uìk•FÇŽúy°R3ÐÃ\‹ìȨº¥uº±SÐ…«­ÇÝiêTÂ_“›°<¬’)ý“$B•^uÖœ>éli!«c¶™Ö.q5øA€¼–§‹÷ãúê, &÷zb8u´ šÝç°¹õ6ia‰î3l¦•°ÙN¬=çAbdr³H 2ùv-£[7»û’|ÔEu{uøì3£‘–F&ïŸ[âNØo»É0çuV£c‡Ï|šßŒèì©pCµèáÏõÍØb©ßHÈq,Ú„YÙäd“È??î¯øe¥Qöª«ˆvóˆö%0ü"öìôâ¼ “6NtÑdAÓbf0Š·!úQ½’»¬ÛBÂ;;ûgyòFð‡µ+ÏähšË·éœd/W3‰Npƒ°Á”§ÿü‘ô`†½Œ!Æ¡Íéi)­9“ÅýpЬtpí¯!´Û–©=çWÈÊà\ÔÚ;½ŽX[miåNÓ¸§]2êá® ç…ÅÈôx q™g “B{ÿ«ŠÔ3äUG(%DÛ,‚†sdúwªŽ| ç²9‡—ÐÄ/#AÕC—©‰+-â_ë Æj!€VyMpnVÈ»,м¢öÙ(„ŸÂ–„zSÆi*±ƒA×Ç@µ±á{è%Rú:fhÙt¿êÖ¯¼šÞh¿ÄðãdüŒ^‡ƒ‹hý€¢éÇe•úI`UqssÅÞšêà¬ÑÄ‹ïÌCøj-] œúrh¼.¤ÝO."¨2˜‡¾@òz¦èÅxôü†Í¼~–~¢{ÂóÚP`ëM†ºêË÷n 0Y•Ä›§œ.Δ|bÃF…¥”vì5h®LÊó³£ì~"RÒ× qk~c¼›¡¹ò¢Wa]ákä|ãr °=úœ>Æz}_íþA­CYЫÙ_ Øp ¡ Yª"nõ „d¹U ÒhZ®i"™sÏZ´2#ÃðTëKPt§ÄãIY˜0.À2ïÊ Ã5…†`vÍeDJŸ¿RgÕû `BEw€¼¨c[¿ ¤â7äŸ8³&´õ5ÕUŽÎ$ÀÏç³Ì0ƒQRû§TÏUú gÐû;_¶‰Óß]ü¼æ*Í\…_é5ª|l_õÈ£¢¨;BS~Ù~TJÉVŒTLåîI¤+pŒÎ@‰× )­9íþ¢Ž”¹UÍÆ4³{±n‚g•æ@!ŒÖ ñ9y’ ¯|KLô…?iÂõ…åj­Å'‹4äI÷b7o¦º"¡:è¨2mËcc§³R,Í“ãÈŽ'bl¦ÏL‘ÙNË×XZ7zÓoêiÿ._š&Ò§K$1Öøáöô|HÝw7Úq2JÖÏSÄ2¬EÒ®Åè Sñ‡w–óËÞÙ”ø‹ACº’®ÏìE3Ùä‰Py5ľõxÐXä›ÏþÁxÄNE UâáÄ÷‚¼c‘Bæ&_‰u׳{áχÙÔÝ=mM*;=ùs”£Ÿ¿Ó÷j™”ª¾=4‹0…¶¥L¢/1/`-ܯ!žÑ³`Á+¢à æÏ1]Cïeb^Ù¯bˆúQá^Ö=Âðàš}uwZwвFr‡œÙĈ"‡Í²qvàÈ:PåZ- =Èæ‘Õ0¢·«Á]˜…N¦_cðs˜0³’å:ÀõúðŒÅTZnûœGW…ie7³½i93F9­z؈¹l9ØåOâ}6ôÆö$2õ_¶xÇ–"3hMÀ´ÏíÖ×-uêªwë=9‡Ú$T}‘ X… «;Å&W®R.þœøÛÅ8…èÓd’PéܨÈÿΔ“&’¡ ³n“_!ímFÛ¼GšYŸy@Œ!¾-ÏÞd þô0ô‘r¿CRÌfâ÷ž^÷ØÀ‚T¹çˆ1âðÙ%ð ˜ûYÙÆl üç€À~ñZd÷£eDRÕÌûé>• 6b’ô*ÏŒíjo&g®æa$]«$éŒ}±3 2UcoŒäòcB£³ÕU7&.êñ4‰:ôà–¬H®¯<ƒÅ®ùvcK•p¨-6‡Ú¹¹Ý2lázÂS4=u&‡)rk²5ÄÐny«Ô©M˜Ž‘±œåÁ q„`l´Ç5(Mtïz[FMÿùWóná É[ý«¼ÓUý”‹·ï R 6tþ ß ])é“‚$hB/‹UâUËÔÿ&@Ù¿wqr"‡Ü¹á•/Ù·¹òç#JSy-EÃUïGÁ– ";”ó{ÞYذþ½ &ffFA+ã§Éá‘Ã[F*¶¼/Ÿµ8ÓÜ1ñù†ÀŽƒbjã.·uuLFý£Qô%HˆU…'…’ íY褛RuÊäö ¶´®ù¦ñ)AþQÚÿšèîv‰»|“\Dp'tždì) À±šP]Š5©©¤Ú_ Ú®0œW8=%ûÆD‰0OiL,kÌ–§Úª>)éšwXDÜ&š$6÷‹OLòm×¼OM½¼ãÌÕH¹ÓŒPv†+ÿ(ñKÓ Kþ=ÒüŠՕ€’ bÒ»=ÃS2ßþ„…¯6ø5õÛùÖ™ÄsbPùžq1Ú&húíÜÃðô @¯ògüên´Ì5b{ðÙÄåP`´˜£Wƒìõop)/ò”JY ÓšÂ4g=;Sù±Èþ•×OÿO=‘ÇBÌ‚Ûz A o!D9¼`<ØÙ¦½fR)ðr¤ôeÊàŽØíK?ÆïÊ6\¶/×3÷”^ ðÊ)zB¶*ß5íè=Wܻ޿že?w䯻fCAš»ör¯P*U-ðÉ¢¾=×!SA¾€@A&ùÛãpEgú`Ó÷ äYþK(5ŽzšuÙxoµ)L‚”­Z[=CxŸ0–šæ•ò<\Ž?jæ¡+õè?íC±"áÓÙhá6/»À^Y[í×´™¤’²R•géáÓz÷ìß¾¯á„ŽÞ[*hç_ˆºÅùÀ°9€¶Þ]ÂŒ?hc§@víåÅ7 ë5T¥¬L¯õÏT‰Žˆ>0³ÓœEro>¥$0êZ~Æ÷Êirî²eÛ•YàvšN­ 0Ø;_ þÉøÊvøhIû t:P) ã¼Ee:ä_oGÒŸÊBÖþÆj’´à©’âQQ´‹ ÌB˜ÖŸÚ@›£±xæöþnõóZjzcv¯Mdh4Êj|ç¯M¼éÏw ‰¾ç;ñ¯Uc2fÀ‰ÉñÌ–æ\Dw¯gX hØš÷4ÒΓž©M:É·å!syÛANó9D¤ ÎÈróÝ7îÂÍ[«¶†ÙhðݱXnržÂ N–ÝöÓ¶Q“¡m¯t¯ÓzD-ŽGsÞ\ŠÍAÖ®é{£äÅh4GvÖ–oñÕô¦9âž²ݘ֔‰Êí0ŒDAsÙl”“ aÐå_H²Åq*FWÓÐv@÷_e;Ÿ5*ð/õLeÏ®[òr>g”ãc:[.ÂC¸ÍŰE˜ˆŒ[íA‡Çù)üŒG•â#©,y²Œ†¥±ýwÌä-•Y.#%ÁR¦þ[}¤¢c;W"tÔŽµHgÖt†,fKÞÅПA­Š­ã|Ã<ÿ€1üáøðåÈ—²?ýº‘AiDûz)cX`-ÄÖÂ<{’ÚçÁ/+ζþ\¹Í®ù×P}q3M¦åDç°W¤zÈå·¹q.$ݲŸ%€fUÙ>½¯@üfm‚[4½Õ¬#øóþ³#“Ò)¶óåÓdr*¹'óÓ+yv©ÕÁª2óú ¿äâÏt½–¢ýYsÍŒõY¹†he˜sê_Ò0ø¾É¹€É€ÝμA\¯Ü¶ˆùê®2A°‘+~ŸaüQB'zNïªË–5›fc™1ÃyAÝ÷Þ r­­÷§U/Dók&ý§¿ê0»\É›ƒ>í¨¥ËÛù 7ø#P0‘¯H%]CÙu'kÖ‹SK+6ù’BRR}:¦w)Æö7Þœ ¿’(ÁÓ¯½ v[0}Ü>¤‘‡þrù’vd›Eõ£Ä  H \±`£É°9W_<1ÐKc¥o@µ¹î=lµÁC‚ùpSèKß°iSAĆv4,n¢Øüy‰îoÍþ÷%L™XMI¡ñjh$CI³Ã/9˲µ;ß{ÈY„å˜ÉÃNPÇÒS³”U/ë{= r9TKdw  ®;Ì¢-³ ßŸ­ ß£àö˜=Sœ|Û{´”¯è::Nn‘Ïî>*¢S .¼ÛÛ½ü¶åZ°•½½M'OÔ)y âAAgU /—ËŠAsñÐÚÕMÃR„6èF(šFÍ8=øôF³ÍœBkzB÷ï²b6˜aßáh>,»øÜUãæÌÀ_¬]7ÇŸÚÓ…g#gÔþõ–Kž"óPmf+zä|yÖk d:Õ{ <²«›€ß?‹DÊ|5ªÒ=Nd«ËËE,OjvÒc¹‚Úþ<¯e€Ðµ#‹ŒËR!—1²¢÷3Ñ>+¬ÙA‘–ãd:«I×àõ£ž&¦'Φ„™óë´PÄXŸ{c€YÔ ºiÌûL\ä’{½ñ.|•pVÞßóŸ8Ká AD¶9rôgU—w½&µÀæðI™èW{ÓI\%ôIÅs(‚§ƒ9½é& V°}ßiÏA.Zû¢Nï45X˜Œ¬áð Ú£°’Z¬ ÷×@W}`–ãÐA»ÔÉBà«ÝSä‰@ )9‡± >KÕäÄ›ÒùA¦ap “|SsõÂqyœ‰‰2®>¡dìÎî}¤p¥À<ÿj‹#9qÓòªXÚ7íé ø{u|QnÎ4”aº==¯g2h] {D0p=¨Zì¼}”ÀÈåT•ûŒd< 9¬V|œÔâEØ“¤åašÚõ—' ìÝ|i/t8Qšªî÷?ß;_Îbç ¾½ˆ:2GÀ‹9¥>±P~^¡ÀºâÔ³ë(RVK<¢‡Õnb·ÐH¯çTÿ‚G§w¹¶ü`ÀÊÇÆuªuEʹcU‚©*Ïû74Á[C\ŸhìÊ1"sR)¡=þh@HÉÏ‹œ¶êÀ ZWѯ”kÁÂÃ^$‡ã ~ëëö—}ú4LÎÔÖ§¡ƒ;‰D$éczã4ÕÂà U'íñ ±$6“>ôÇPCz–`Œ»ØéÞR›)Á"r¤x¿]¦K¹¼Ëm¶6j †Å¢¡M\/b}ô<Ñ;¹´Òf—ýn·Oüi?ó:B¦S‰ÛßÅp®&Ų’/¼—7IVÕº@çÈ(S9qèâ=.¿5þ®ãFF;Ü&Y–JOKøWnV¥bh4œÅ¢|3EWÊNq-˜¾Þy³\vÿÐÀ/ó¨uðŠÁ™ú|7  ¯ìñ¡þõ¡ P­¾2ä&ÕED6XÉ9º—аB¤cìN„¹Î °;¤á G¬¯»’¤9œ'1Ð p÷tĉ>¡ßòevƒ/¼¤"œ9AJ#ã/Æ&F@! NÙ¤Ò éãœs<ûG¼õYt+õ7_qçäNÄ 7!9˜Ë)ŒU"ÚÏ&ÚÅ£$Z]¢2Zöq)åéÆqròŸÃþœAµÞ¬m eEÄ7>ÖÂ/€`÷ŒE04*ŒväRö> î„IÉ5é´Ðu…²Ž³Í²ã!õ}ŒÍ¸W\eÞ˪В IÛ½ ÷þ@ ê¼ASÌ^§ÅSŸ>1J$Û¿2™É\-PŠÞ¤×/¢¯Ž‰W„•J.ÑQ5H‰À Ï\ Ð83”óÆ>\ÊQ²d¢à-ÞöÅÇz€íu :"¹mñM 0ÉÚÿ%m¾x:.úÈÄe•Cý5ÌgÔu.=»G¿ví)i­QéóÊÀ«‰;š‡£Œ´A óJ“Å$ ¶žUÅæ(üÒSê8 —ϼÕq¡h Éá3µß‰J˜;4>RS€í6ݬïBR(coÔ¥-”Úå¤ÚF [Ÿ5 ï%‹RG‚éãÀ õÛÊ~ozr¢™EŽìEòœ*ñ•ÛÉ#uñHºÚt¿­šï%{ƒ6´Âƒ… 4ÇãHL\WHªÒ”•ü³`šÍéÚ·ÀzŸSæÿŒqÚ|~:NñÐ$ m€"ä£=^`„Ôaéh_ä耫ù-}J¸…‹tˆ«QÊú²‹Dû|/¬Éž9¸€ x2°ÎÕæçÒkG Ô£¾æB‰¹+ *eøÊø¸ä™^ëà1RýeýªD–GßKmyp<¢ê›«~d4]¨´XK ù&âV@⯞#ŽËû,PNñm+þÅò(@±¿jMŠˆÃ1x øQÖ•Ä+E21ðM•» |…Ðá\€¾ØçføñÈàVÀÂÞZ%`/>à²tÏó;V¼·#,WE|kÃ˰D zâŒÆŒ|IºÈ}¸O²ÉIÿ×Sì-'p©è=û|!üéÊCª©§uÔÉÈöGr2­‹ûÚ¯/_­^òQ\ ©6,­"n‚†› kwµ™ØÆFBÓ%¨&ä¡Ót[Œ­c(ŽWgÖgÆÄd铸åo&ߦŠløÛB‰X¬ ë @±€UÑYE²àØ-4[:Ž}ŒËA*%ž—°ëþÌÁBÒ˜öî2,!*8® ~RÅ9QN›õHO©¥§¼#asPßÇ_DªÌŠïï_ô*0ŠÔíò÷€g>È­ÏbéÓÜo:¡ž„Æì‚Ñû/. #ˆ:©®‘L¢äeÒTp{û†r‰và&•9IŠkxã± ,"éAÍ€B³v+OÊYZtqX·Ê5&M‰¿][ì!_Ö˜¶($fM¡uŠ|{ÕtœÛë¨û>TÛ.µ)µqQ#ëù Ãw+EŽáK M{&>N²\™’ž0…d[€¢2}ü¢½àV”¡ÇÓË?â”L:Ðæf­€4¢ÖÇ<¸ OÈL …=jé†&¯ÛVƒ³©ŠaÈr€Xð8=XH* ÉŒ”-˜†¾«¾4T9%§–ÕŒâÌÔ(^Q2àž‚ÊÁ‰Ž—CX,—pÙFôK—ŽPË‹ðÆ)̳üaE¿µÌèíŸmÏ.¥Ãð~“‘)¦€.èì´Õ?£cœ|ÖŠËÕ¶àZÅ€S»d*îÑ©-»exó)ls?ÇHš ‡ß”C¦Ÿ‚±Á9¥hUhí…'CP–06§ úËcˆC£¢Šš¶ê¨€A>®áyypýNrήpËëĶދêßpßÐê]Ó,æ:IzÚÞKýœ,ñÖs¨×+¾iD‘·7'´ž+ âÃqWBز.r¤}1eGAða¼ˆ Eƒ'd²ø^¼ áT{”s“²—½'t2ŠÚkDR)³_@ÎE›W,—éoùË^©ÕKô–œ~¨ýÅÙae…l™¢¦€ü‰¸a ò·J´¢-^ûø%äâ³\XÅ×3϶š\Þ2?¹ ™ ([»* wVÇÖÆ@g(¡ÊÒUÓ.ÂmâPÁ8²ÉMò–Ñÿå;’e´äC’F:¸ãaJúòNü¼b¸Ýð–d²•ù`‰ÛåÚ"Ò6=êÆ'¯Ð¸ásÅÚ¶J=ºk §Û0­åõS+.úYb¯·|}m\®&bìCi}Ö­Râã)˜•[Û Óýìõýil›—2±ö®v*È~bÖ™iÓ^\°,\,ÃTïNFsy¤Ñn€|ød‹cã´ÛxL#¢™œ]Š/ñ‹‘ ˜„Ä{¯9S­ðN¤L%F6&dÑñ’÷£°Àlä6Ë>›¹ã‹Ÿ*N !Íe%ñýñDcÃ,Ç¿º§X’Æ…ØÖbtŠfr[°¤IÓ0a0÷÷K”w/õ,׫êËÁ¢•½»}Ú§£«¤hú9°“à•PÃr……îïwZn0>i_"®@lV¾=4fP8…aIÍa;¾—ô4ó : ÐäFþ+™ 8î6Æ[þ ¨6½&“e5è„Ñ´}àÁ<§cÍñr¸6FŽU4Èy BÓ«£k÷ÆMxÚ³ÔfwÞå¯ÄæNE0—‰¼ëÚ„Ô®ê% çåûN‰R¡„®É:­)*x4á}é`8)ï7anѼ_•õ.#C¸aEÃ.ý ¡ÖüæŒÛøù“)—ðù4¨"ãy%®ÆÌCòlmý!ê×{=/¡ÈÏ7I@ö ê|胆šDxþÈ›9bLþvüG(˜óD;dþY.®•zMÙqegœÑvºÆ®{8éø`f“²``Æé<®Ié±§•óŸ=„žþ*¯k§^‹òo(Îm!¨9X?ŸÍõÌ3`ÒØLåûºF7|%¦"LÛ¯ƒHyCpQ~9mÛÓ[QáÅJ7§[¹Þ¨`~Œì$Šmõ î¨¸e¤æÎŒÁ­Q¬ÝÎmÓ&Vn˜ü^‘;›£ k,òí-Ò0 «ÄýbÔ1§R}>ô­,•1Å“ƒµØòõ2~Àæ½D^ö”d¼…Óí!جnsMèɳŽõuÂkf™Œ VÛ8/³GÊgÓÕ«ËpbH‡cý°y9Äln=ûQW(/ç's&_½X5."|CÝBNV§ ä^ÝÓ¿_T-¼&LaŒˆ×R¦D? ùÿ[\>C¬aq)esðŠÝ‰~íGønU[Hªl„Þ 4º3ÿ/GÜE˜:Jm€h¦Ã^.Ò£gp}îé-øLõ–|qlMâ ÙIÄnCäù{¿.@#PØLN Ïâ;’ ¦YäGõ:¥´[U@GQ=ãFSió/sÝÜ¡Th¶½ºcœ:`@E (·ZÕ~`bqìhìßU¿(·F¨ú¬¬P´ÎŒÙÚâÖÇáòFÌßIÞBŠXø×£3…`QVXv®/Xä«áDg¯ñCU„^0,ÌeÃÞ_®3ÑÎÇ’Tòá‹Áª=‚Eêtòá'ׯûzÆó|åsm‡nƒju$ <úþÊÁeªKV_tÁp7_3hQ‡‘—Õì „À¾q€·ËðšAâ9”ëOŸæ$¿jpïÀûòŒØý:®QôØGÎTöùÜÏ^Ñþ_®"£åwVˆ,‘å3®¨;hiû>˜ |–¢¤sœN;”Cù3«sY‰ÙÀ\øì¢²†t ³¬“ ŒÉì/ÃR™ÃD×1x$’ïP¨3OæMUhG¼Œ8¾%§V9d–§Ô,ÑJ IˆÚ#ì FÄ[xã²4ºÃ7Ž4ó Fœ¦*¸0˜•ª?l›ñoíЙ šæ¤„”О(s'iVßkŒz¥Å*ãkµu$öØàÄbÓß½DåÓ6³QÂh[¬ eêÒ®«×ñýS“ãìJ+¿…Yæ 0 ¢ÞöFÞìM]>ª¨<Õ™Šœ‹= hù³”üÞF¼¿Ùê¡«Y ~FïUeQ÷>Ò‡2ËÝ›.v0 lÉpŽìïj{d‡r½ä©…`p¹Ru).$kÃØŸŒeÏ­•¢IUîÎ6o47l7œ:j›L=0Š.,Ô]ß.¶ð¬"¤B[œ|wÛ60–…kähnÇÏb&£v!T÷àyTueÆÎS_0“ûÖŽG¶ E®µIÂãACc²9`r‡%ŒÔO /õ‘šÈ6“@­A™M‡fˆZÛ`_ÿOö+Ú²=}7¤.q2®¢檑*ÃlÑ_ËÉ\waW²dI™\ 7ò _‡ûÑ'^ðQÔeÈ×G±‘úaUŽÃY€¿ÔIŠp±œ™ôÎoùÙ%gS¡1Ñ0ð?ˆÖÝ}.®ÜU—oÝ_HJB¢)íIÙå¼M¸QgN…·XPïjÞÔócµ²öœÓV¼(SG{£R«è·lüÜÐÌÙÉÖÛ’ò2nkõK…¸¯m¶v¤wÛûÞÆ¦½nFt¯FÕÒ„áÑÁ 6W $]©ÇKÀ§4$G¹Ÿˆ#Š+EѦT×wçØ±ë¯°ì›úb•pùbAï C÷FÞ›'}3$”6~q”­®øØÃÅø^ñgSsø8Ñifõ™ÌCíŒ3:Ç0› ìû4õ ]û¯ýeü{“q@•ߢG°¿X§íËZðnàÍ—¼·Ä§#È×úÒ‹ð´#D£ìŒ8¢þÛe•.ZOÈxç¤ØÒ·,LæŒ"QžÝÓ »¯õ“ÓÃRD„×e`§è3s÷Œe¥…¥ˆ’>œÈKxêËf Kí`Îz†ÏÚJ¯–0+ÎÜ÷¬MÊ=xÕªÑ_«ŸÊ^_IP¢7E ð°Á… uWíÃþè%±–r^â·Ùæ X$¡ûswá£è)„ ÅóRßû“@#ó'K¢°“l?þ¬­ºpc†¯´.¡¼ê÷o@ÓŒHð+9ôä³ÙB7$? ßš‡ˆ}\ö€.Û5ž:“7ïÏÊÁãF~âWb¤ç}ì1¦Âõ}w3*–ªQ`tê¾'¹ymXeæ†\‰G•ÉŸQÚÔ+d¡‹ø»ÂÇ^Û­Q?‰¢wbº¢wÞ¯|QËfŸ xæÈÏã²nªih–¤Ãî%¥Ó;Çô˜vïX]e™O×ò›Ó#†ühâÉ—Œ$ ?• T—9¦±rB”Ýå­‘áwšYÁ†j¢¡Ë«;¼[[ëRù–VòQ‹¨¾w{Áˆå»zž½AV‡Id·«sc±<É!Å”µ§ºcÔ #Å1èmnÂh[Ž¿¥•)6PKVùyQ ©{GÞ•cï‹ìéµFÕªÉ>°°ZŸ¤ƒ¬#Ì3Q QŽÃìÂ]û’£Ôá 3Ætüy°ãµ/|Ž’˜–PÞÒ}+uÙDÐí°9åpjò¾öÏ5|º¦¸”Ú®¤‘íªœb¢¼ EE³ÜП˜³ÞÕà¯.^@÷pÏ R6èþâ@\{µ rcú¸l˜ª±ØÜ²_ØLvÑÒe3÷’¯œß´H$x/÷“e©– ²uI…ÑIšø»YcNúÜ«¾{0ÎO˜rôûì&»ÑÉ%ñF 7G¸¼g@Ý¡û[åŸ/š@Ö{qÊ|×›bÅjUàåâ|·‚x¹©Þ®{W»¶M‚ÅsNt³½ÑõýæK“ÄžëMNÖ‘¡úJüSõWnÚëT¼ä¯õN ˆe/G%¶Œãx&8vò|ÉńάâÂvMª‹¡á‰>M ‘Ï}Á·±yÆë© ã9§˜Z9#"®`âÇ‚jÀw&F¨»v¸Ã3¶Í2'GLf=Ežpx‡A^c­=íÔ’©y›#µFÏ`Oã‹dÔDP‰®˜¤ÈJ{YrH˜âuëÙìd¡Ø>¤°¯,j¡*2F¹µên?ú|ÔJÜd·¾%½KÎõMŽœô?#üLò©YFé²µ8yÿõ±óâãÌá]×Ó°Ät_×M—÷ë¡s=-"2£d‹®± ÍPΨ€¿4Ñ $û[CÖsE0‚z‘ GõyÅZZÔ¨OMŽEùÿá zyßë§F6û N!| oÂà(ÝÙ¤øyú RˆÜNMg(MÐööQì_Ý µ¯³<ä †Þöç:½AÆ)U±ß<º¹cÔ»i¯‹N…{ªj}¤Ì+[=CBïÅtçó.֙ܵI§~dS^òP+Âú0Š€,¦ƒ±# Pˆ¶%Š'çl˜ÜìŸì´§¼ßLjټ³è†¬î±ÎòÝÀÞJ‘j¤ ÏY+¿÷LÎ^t¬2Ùbe Ðù |ã†&ð©X±K³×‚8X%Vp§”òÇD^äòÛ ˜\a¶i™ÄÓ§°¼ÒJ)p/ ¢²ñýrT.ãJ9UÄytÃó¥RjìÑ %N[{¶7cÂæÝÁ°Ôæ\·ý‘UŒç~ÑŠqŸt„2EA¥8Œlh&=3H(ŒwIÔÊ{ñÐB"dQU÷i)þ‚¥~GᲬò9q­yókx”ú©p.[äéT‰ØashFNð«lV%ÏÒxÕ3 ¦Å³.\ò²4-‹u[$A¦H£E6~ÎiîÞ% ÅŒ›1}Ž\J¡T-.ß“#zr½ÃÞ_a wFàæØí¶¾ÒLêTò¯Íi°Õp”í,CV›UµÓì´ðÒ¦_æ   –RiA%kÈŸosÖÛç8(\Ä®ÃtPÉÉò{–€þ IÂZQšó( !Ëç‡,E>¨\{éUI‡¤Ô»Ü+öÁk–^ªwLçr#eV¾î¾½Òp‹%ð?̽úNI^ }cRkŠ'.ïáê;æð¾$‚ìÙ5ÛžtÂéN‹YÔ}Tç.Eö“ŠþõÐÐ'ZÇAĽ¾Pý9 $ªÒ <½iWìeƒK§„ë²R‰Ø«&®åÞd wÍòwíÜDå›êÛÚU.üí=5æOÔÊBžFb@YùùM†ÇþÎñ¤¨9{¾¾q:ûŸø"qW}p% Þ’ýΛ¿Ç9ÀµyÁÅ—ËÃ÷ÛŽZ5[Û¥Ý`ävÄ»òkmp°I”þ2äà2GÚC‰9¯yw8ŠcãÀÆ2yÅ3Vœ*[âaD^üY¾÷NQçð¯r™ý„~£ØÜ*öö¬ê 'kÙÄø‰Ž‡ÖŒ ŒœóÕG‰Ø×¥E¤­tÅj 8qnŽ +Y5ƒè'›†­¨3+b.³[flµ7¯œÉQRÔoa”¢wßÿ•{#þ§%ÝÄS¡ÀNši 5nRÕj߸ßÌ`œ=bÞDtŽÑ¢àèä`§q¹ƒrDŸÜ c…³À*¤T“¨CcïpxãotÐ0(w&S…›gÄGAÐsQŒÛhæ3¯/'o x‹—É=µvg?)óÕ¨Cˆ u˜_O°Ïq/Ž‚Ò:¾Ú:7O:ÁZšÑŸ9Ïh§ïœ*ÌÄçÛü¬òÐÃtN“xšüO‹‰#žb÷<Œfñùˆ[Duë\0JÉÎÑÍ^8³{$ˆ9ÜúÕ9Ë¡«©=ªª’¾· 󒺦«èwÄUöfCÁ|໵D}ÀÜ`sˆ®1—˜Y¬¼%1$ó2aȺÊ×+çÇÆµº°/x˦ j^¹/X;'Wi p±%=EÁMþàУöíÌu¯iNvV’±‚ß¼:=ƒ<ú!˜PiNâÍÌl `6±Rnz™‰)aaÓàóüG¥ß°Éü8Ô6ÒZ6x£«dƒÚ¦90wˉ÷ùk“èÅ-G¾d’4ðçÍ=BQ X< £¬!|­vî.ëNÆm1JšJÿHGJzuÏ¢;JÄœvIBS U)Jáÿÿñax¯›ˆ—'r®mè½—6u(NEÅJhT$.(˜Ý(hzå<ËHC1¢Ì-Ÿ¥Q@(»UݹL,žÍ}5 Õì¹…‡‡GC$¾0ZØfC综ï0›ä·TÇì ¯ðF‡B~ ]ÖžòR oœµy/îZ‰@‹ÑáLé:mé;DžJʉã][ô¨6³ ìì ƒ¦*Q—ët+ptqH{3ó<£Ÿ uÈÑ%wYƒt•Ù†"Úu÷±ÐP“0i¼µÏ› A°‰g:\ Ò’Þœœh'VL¢„Ð>t¡<8#[#AïÙÇdɉÌ/dM3ÃOR€ÈúÍ9å £ï"šû.»À*bæ*Å£o¨Ùœª½¥lÒ¼J]Ý&,.±†¬K»]ÁEs„.m¨Pñû HÔºÙ?{~‡sÌ3Í<étAW#Z‘=¡µ#/ …¡' :Z{ÆíõŸW>~æiqÅ8ùÖ„ÙÏ‘°Ú?{( p+ôÙqã‡wV[ÕáÂáëG”¬Ø#ÊŠÈ$¬¹Û.w2²›¶ñžUý·8©H!ÂMƒ‚$ç EД_ÀäüW3ñO´œÞ|íåÅS–e¬»#%LÃ%ôIx+Û΃٫¼57ιôŠS(Ò ióUEE,¢ÄJÿ›m½y…ÖNó`Èð‘ úˆ(ï ÷K¨u»º#Ô‰ËrÇ*dÖ¶½ˆíí‹Û ø‡Ð°¬ðɦ'i½+bu =ÌÊIpOø[OèÜÜÄç%}j­;<ãà€â‚FkdŽšF‰ÁÞ….kП3è´r‹çt´¸sœò¡´ƒ¼™´Æ´9½ÒžÎuç˜kü‰ÅÕ.Há€- êß±^0N½Ä@[¨º…žƒ'¦Ž¢¯'±Â"ž­tiÇ!ÆÑ(ùÈx„áöÿ&Ù¥ÑÓÆ)NÖr°À=ø’»ZöjBKŠ9±°¡o6yïzO®–#ÙôzËÿä q¨Q³ ‚–‹gîªOˆ&dµb®Ý—ØÜÚn‹ªñšü\kгÂuø‹´QHé?0‹Ñ†Vt¸sìvØ4”k ©E\h¼ Ù¥Ü6:Å_yK•b,ù³·LèÆÝÆŠ&‹–?í˜ÑŒëêý\4ãh° £ÈgU1®ˆ„ ªtÖ5_:÷ê,Îìq›ÿv)¢/'FuÔû$âå­(®‚¬k _zt²dv>²7²s{~b²ýr"Í”lª–n¾6R ŸÎ¬C Tª±Ã&hU/1Ù±ƒåÖ«¢_¶ Ë 479Ø8§è¯‹xîê5:°‚/N·Rœ‘/Üx_Î ¥ R^ÍlºC}Òª:>kÍc½ÝrR~–ùL»UWµÇË›^z@re™† ¬·y1›lú<ïÀM$Ýb ,]œ]¡6¼ƨ©¨öá¨ö„s×›®’…†Íl‡3—b†ÔÚþ˜x¢—Ìî&ª½&ë-ÛIÛ5 ϱæ~YêWT=·|(Ö—7V4ñ­}„ÐõÓp\Sò½e%U,Jð?J¦ëµ$ñÓ]Ó³ –˜Yùñnhº~ùNþwÁÛ:kíW¾,˜kkWY#{›»:Y÷Ñ~ÀLkáVº³^¤Î¯Œúoˆý.å½uÌI¡|«pêómé<<3ìèð²5ù›oõ¸þHóàx;Þ#¦«nñiÔ$ðaAhCžü.é\=FÌÑ»È@" —¡þ…+”[Ò^¬99¢¦j1ôì?†îKÀE ªE4p†ãE¤Í£lÈ2y?,ðh ÇuË_ŠZ¥ßÑõFÓŽ‹¼sÖoU¥§ú´#Nø0¦ƒúA;Ù£€-ÖÅe»í¿‡hð]Ÿ`©#dÄ#¡dÍuo²k«{Ç÷¿{tCEm¹9ꉺ¾Õoص9+ÔdI(ñ4tàO®fŽE‰– ‚9¬–{í…S£R+–/vÕä&û"9ñä"±Á¿ÉÚSx¬v™½qTDDµTøNÀ ïHçål¡÷,ŸlÔ)L±4Ç& ¥¦¾áÿi'>–©£uÇQïˆì»á#ª z±={¤ù^TtaQr;¶ðªyµ&:&ŸZø¤YïÕèKàaÏälç1ÁC‚¨|/±ÿ‚Ç3ãO~Ã2,38R‚iutLÖ5P‡ÙSÒƒUŸâä™{Î)"uEs·Te…¦ÇP?Ù°CÙC½ 2öç¨wÔ‘Ô"T™gÉvÓÐÈK©PèºùC^»š¬ã ¶~ nYt&å|«Þ³`òó5â«W8py†FaI“„Åj¢¤£Tzbã -N€ÿ®ØB—–•ó*„,úÞÎþdi– Vim>øÓLëÕëVati¼5 ã±~×OE7ænÞ]èØ@o4× õÃ$ÞµeFW¸åYû”)Ç$}tnÙ-èlØ<‚‘þ_€q%®Íü+ aI?Rž( ±U=z×,6ß…+pW<çÔd÷Ñ ! ~AÂ]¬ú‹O J†³.ÁѪsÑw õq²üçŽIìL'9ä#)øxÎ[×þùX,ãÙ£äÕߤÖme(Òð*-<‰Þ’Ùø´ÎÀÞ힎RbËê(fY,° Ce:å5h—ÐÿÄ'×Ör\ˆ{”æ`¡«Ë¹ƒe÷Œk‘…™ã>çÿomjLályó¹î{t(®´á¬Îj÷Ì—h÷&FèôV(ow0—Ó¦]5 a'jI½ìK[™^Ž!‚Ue&ËVé´§)/Ô‘ O]Ý!WpGª‚«K~Œhæº9Òd«ëÈÔ Î%CöC¶¸3¤â|¬ÐëE‹q—Zßz‹5fš¨6„JÌðú_èxñŸÒáÆXô©YE˜Ù‚<ÿ¯“V@.3ZÓ½ × )ÒP³¤²ÔÕûúë³r7Ì|(AG¤¯‚û úþÑo£à2g—e B€æ¶JI®Ec°³óµú¤þÉ>„±½aÅ&G\2Öˆ7“l¼Dœ\<\“GáÆõ­²H„ž‘r¨ÀîåÉ}wîƒN‘d0öiwÙ±­ôÒ뜮„Ÿb9&êöŠw¸ßßB"LË«ê<Ùútà ücôL$÷dG¢3²H’cRµ@[‘½n”g[Úþ r7휴µ-åJkpÄ— ÷ ˜¶è¤Ä‚j{ Uj±sÄ-Ó†·Ldž—'B#RòµT‹žbÌTPœÿÊ«xQ¤8“¯ÝÏ-Â| YL“zÕ[íÜˆŽŽ™Â9HSÉ*”²±š.PÙ,ÿZѡҗ´gc>ˆXÃ@\’§(é}½^œ‘ʼF%™e!MŸÚ?Ä‘T¾…ÝGIöØ;‚ìc[aùÈ9ôÔõ~‹ 9#k¤&CO’ýu`&؉ta ¼Eû”ì<Óü‹|³˜Iú;À«7Íž½Sk¦@aÊ^"ûí9©¼Q¹&0 Û¿…Å-±u)rCA¬nkÿê4yçà …<¡¿d€6ÜJ¯Ð—Zgy÷¨ùÿ†?q,ãã°ë±ë,†=7^)Œ¸9ߤզꅭ…æ*Âöwì×ËÆo3gh3 ’¢}0ØàWµ£v zàKDºz"R=ØY9JwòÕ{I„MÅ&ËÒ¼ºá’ÃbmPåë‡Iü„…'¦Øåå€ÍøZ,»Ìõ özFЈu”jL V¥0ÒqôìL‡ÝyÆÏÓâ‡É”qôMãÎ«ë´Ø–Êj¹‚ñ-ïšA¯§ý"ÈùS}à0ÑÆ æ6Íb\¤L,YëÞíýu€åòZ/™ÊµkvY¨ZãÈß°üýÁ=õ§¼in~Y[¨/œ.:‰Œ%ÃMÙ1ñ±Oõw‚.úf@/ï'l£ùï“ü¶Iž¸±’±ÑmýŠmõpváê®Ñ(GpÝn¡Dî¦sóê èx²*çq€H¯LË0e4k™«†_šàõ"p.¨f‹=æL-Ú€7,8z5U}ΰðqÃ4\¡5ºü×)œ£¸³<ð«‰Ð9~5wïvßj ÆeB].iH†=Z½ª×ýW(ˆ¢Ãœ§®0É ›]/éífLù/t?e ½ªáÊSà(õÝ2ü9UU¨…`L^Ϋ[n"£SÓ²ìc6n!щ¯ÿÐï„ V7 Lnšî.þŒH†æêomï=uiJ„y[½T~'ؘ ß©=¤_ ! ”ÜçÖ5šX|îÕßU¿`KºECJ’ý®£CýÂjd©8Dé2RµNª–ñ‰fEy!O ÿ¦‘T‘ûNJúkìF‘á©JýÓaô:Ã.˜ÌÞ¿Eo¿Ãš¶ð1æ’Ü[-E1UïšèÜâÏe—Üq“V-⺺ÐK™08´2×êxÀ€^)|˜Ö:¾Ã+úÂ%ö&2ë0½ã«¬^N˜ÀZ7nU=ƒ8$eKYŠç´þëkê8¶ ]2°-¸•’£”ÿ‘Ÿ uêÝ Ëá…Ä…Ú|³EùîµämƸYd%ßO,¦„öC'vU?¡>²$«Ä|·Ÿ« ~Wº4¢jÇ:w hžR”-¾›ð+GßÙ‹b2ûG¿<8zèrÿ%1‘yyåhÛC`à sÑ ¤J|ÒÚÿâÑ•íØ —^AxѪR“P… ‹5(_=UÍs%*÷0}ŽïzM-.Mú G_¢°ìêtÒ³’Ü·G僻£œc9ƒ¼›á©œš“í.b‰$}¥]¸À÷^SDnÚ²F¯/è4Ê#€ÑxÜÑ[Ñn(”,<ŽUgòÒdâ¯|ˆ$Ó(r/Èåøó¬Gàú%ÀˆÖÂ*ÛøÆå]ì™¶ïOqûEÁÍHìÆˆÿâJ€=¿E€]‚H:DÄ¿ü‘Dý I‚¦oiÕOÄ?£k&tå¢9+1²Q¡ˆÒžu8 ³â4FÒ¤H¨²’?ÂÁFóð'Q°Út¿­1‚³Ðüì &ü:¯È²‹ÐüÓ§"ØÚ"”êÊ{¿(íØ»ù:rþ‡'~ ¬ÐLU½¨{§%=£€–ÂIùœ—á#¿…@ ¨ón(š9XµWì;ÁLîŽÞ4qmպĆ]~kRÏ@”@s‡ëNFºÆ¬ÕÍÇŽ¿4O¨·M@ˆ*<ž6C®‡ÃKð…ûõf™4!,u?9 fòfJ¬ÉT Ÿl><ÈÐZqÅUŸ¥kc¸Äà4>¦¢l« á£úL­µ úèõ÷Mã ÉŽ—3™©Åâ4±C²JF ÂÍ<\Š¡=íà8c]|1–©ÄPXã›´ó<¥ñqüßËóï+•cÚÒŽ7;ƒ‚;X Ýxª ;Æ®¼},ôù"ó°Qçô:'q„gâ݊ăY‰7'÷÷ã–"ŠË¤o0E­«Þ`üS\î<×"G›)éNÒ°ZM2q¢ëûÈ+Ü}ÿÍ »%á`æ]}Íïˆ×LÖO¬’™CðÏ:'‚;ñ‰0û•ˆ2cØd£ú©vv Þ°[1ËÉ8ç^æ’õ]Á~Ò¼Ý\jðßþĶ´‹°ï¾Lï%‚ƒ·¾0ÇîwêÉV„ŠëRü¾"”ÿ‘9yj×o!Ÿ+=¯¤»à¾ÁLR,-cU¡…ëó˜UŠ =l¬Ã‡¦â2þ})V+; HÅãžúQiïÒ2ÉUÞ)¹#ºÅç?á%6þO0Ü’w £G…ÎÔàsZƒ Cjiê|ÇÓ:I-»Ô{à«ÇUæôdâ8”b$ÚÒêtw *…ÉŒãS§ù•`=5¨|åë½ý.h´ìµ$Ò·ˆ°iŽÔ}¿¢½çœ`t·T€iŸ~æ+Ò"úƒÁSÝj\¼ýL3;€PÜuÆøÅSÌýðØ%Û_z‡íõ…=™?†–ÌÙ*kj¤»›'$ª Z(’>¥÷8ÈØý†ê‚d ±}$Iõó_(ùç@rZ:aÓ Œbðñ–âVú;Ó_C¼.¡ò€k³¨WÒ'õ$“4Û€±ÞBË=VÝÐ0¼Ç@üGµû$i¤šú TM*žlC¿ [XØš´ÃIa Ôí¿¢W?®¾¾µË¤š¶»h 7Š‚Û.)ѽ߫wU]ïà¶ReEv†‡‰8 Á'Á¢ò'“O¥/&P\¬PqŸ·‹¹ò­ÇÑ$Æçq,bäR´š®û/…êÙZÙ—´>̽î%ÐÃGà;$ }O-#gå*Ý.ãµ&C Þ>b<±”ö±™Ž^§›lmŽ ºKLËþfGõ–÷X¨;èæ³í>Ï€Ñ×´ˆ-6ÓÁþfmü¼Qù¬áÈqñ½3Mk4YiÐt/±×ÆÉÌ}†~¿ãpìVtð×BY4EÐ djÒc•ù¥ðØ]PpO.¾¬^+}ÈÉ£žvŽUvç–´Ûñ/O3Øm¶†Êýë’ |ˆø ;ªY¤hŸ´”nœ*›bè¨Ë)öÔZ¥¨spN¶¬`` g“^ƒ§ÏP?¦ -9J&µ‹åtÜž ã£ÝPû`m™q–)…N_è]©¹é]¤¶ˆ.ت¦yrôÚì{åqÀ4ñ¤Ž„W€õL%½(MHsúªlë@Ž2& YìQ'ã©;—blp±j4•òη™º’ãº\?ïš©2_ª‡Ï†øûÆò¯ÇôÿðŒç?Ý<Šó6义Ӡ,`Êéñ͘•\ÒŠÃÉÝ´–ú뀣ª(í¤îZ†¯¸\¶K3GY ?ËWÿ,S[ 9wœ-¤ÛÕA+ÐÆ¯lµõ-‹PVlú@Ûý!éGXd«n£ƒútÑ&cæÞ Ìbu]ÿcBsjs°Yi¸ íø?8îGÌѾæº_…ô€gÉ ½’Æú¬ùk ‚=è7×µ*!o´ÐDéeð&íT@çZá¸Du"…XJu?²¢Àl¥O ùÈ.ÃŒÐÏ!'-¥²¿æÛÈ$Æ(ÐÞß/ö4. 柗á[³ºp¨‡µ]Öi¶“B¯Ù¹k;ÓªV齺…„LA-ŠÍkrgûLï^óèÊmé¶Ê0¬ô' £g̵XNﴥ͸`0Ðǯª**âùù|½Ë?@ïtœ¹-\\ëðc/ÅreCz˳˜šëƒúç(ß²ò…;*,ÿX 9λo¶eæþÔc‘ÛŸ[ÕÄ®o2²Ü¾ü‚áîWQ«I]¹½ømhw9öËçã‰ï„k\kó×<~˜€¾ZðkÖˆ$gaÍ‹PÔ3½$LâØpàyæ!¿ASmsq͆–‰¤H™³2ºDÅ G~+k‡\$xðŠS{ÛbŽkz¤¬¸xR*Oæ#Ø×¹ïo¯ïvÊôÔúسTØíBÊ€å§è5·©3X”¥mÖ]Qþ§•,Ok·$PVÜ×?Ésš·ÎpÇ 2¶­AÕÿVkÌ’ÒÓQ³³ŸóÂ~H´ÍÕò‰ æeÆK<ï³­œY^”öÆn·#¤J®kÂÔN;¦H/Ž®r¶•m /T–'˜|'f8! '%]íËUÌÒ OÊò|8¦H#„A;Þ(Í3‘KiüTõ“ê#Q†&ë@B`jë[è(}W«û:LŸF#;1DìK9(×LŠ˜}§ÒÆY*§fËÚ8¾±¸š¢}ÑvÉ1EàxKƒ,Á5.` P´T€g¾±L³ª4 í²«ÏÀmšBå×®ÐTîè~ÒÌpƒzVÀO¬·ÛYí1Š|±b†}—š ¬.‰F«Ë 0s…B(Ÿ›´Ò£³×àÉ‘·‚žˆ÷7¼…sïüR‡Z2> úË¡k¤þ\}Kkœc?Râì8ƒ0I8<i8Ïé¼þ3€*MP[™ ø†©L… ÃFC7ÛÈË}E£Ý] ^~® (ÉÜÕº¨ßX{‹ x§S¡#6ÞáÞ^ˆË^¦ô÷Ê«–U¥¶gDwH7xdQKé΀&od •_œÃŒ03ÜDåú@õiš¼+DØ™UÈé8q”²ÃﯵgÚ¹S”ÚÇÜV5fºõ0»5hÓ='´–¾yt±¾zÿ³PêêŸÄˆV™ä»vg•®$ÔÆYw.¿¼€± ÖbXLñkÏÅM3Y–Gjç3Ã=Ûöe§dásà²äuõ›Ëš>tÜiXzÃÀ›cÐw“ßez`ÜO›5pü¸ã¡óÙ:¢·ã´¥áå°ƒÙ¹6MzÅ0 ÝÅ';/†(«ö4cÒ_bßÀÞ8‰?»,ßã6ëºvú7l¼W<<µ²bj=×Md$_ÐÒ–5ñ-—W@ï¿.ËD× ö^¨ŸæÓ_E>˜±ºq,—“G4°'^=fXVRn‡pùfýuîn©ÓõvZ£t êP+•oPRËÜj|$mGÓ{B‹=ñêi›À`ýþ©¿z.Ó¡ß,+z=F»#ÞÚ7U3Ì,ŸÙJëh,-Dc݇þ…“ñ}O1úf«“¤Ò Që}D@xëíDÒ°C¡.¶j˜æg˜-ÒŽmDñÌÎ…Ô‰ì$ª0!‹»ì1r¼&`y?¯R™=ü•Qca£[rzŽê£$Àmð¨]tØtíïè|Úë|…{  ½ŠÕ$\\ (ŒZw@©næ—:aç䌥ó`.X oµpQþ`úЇ¢ñ#òðÁ±uëwb¹ô^$3›ÁA&u®niç®7aOoGÇiîm ¶É°ÐbŠQúO9Ç:À¬û^éê¸:÷ §Š'.ÍìWNæsÝ¥X»éÅÃFO¼xšÖˆ5Ìëg„QH‰ Æ{ Q¤’ ¸—  U§(ŠE_ñï‘&jh«ZÇ£ùü«/ßBᄼÂN@õ~úÍ8Í(tÝòÚ‡HÙ’,¿¶Þýâ~JsëðÍ|Q†sµØ]uÇÖ²ÿOEY–@Øš„é&qΨ¢A,õ®¿“p.J.õ_zÖ¢ÿ¥þ7?Ñ÷Q¹…r5ƒÂò80ðG2–ÅÓwÊt×> aVuÊF4žÓM{ÅH¿ (0F:[ò\hñyË:mó¬:‡ Ú#‚WŒ©9‘ÒD%ô  Óš5ʳ#u´¦Uɵ¶½ç®Ó=u¿ù— ?÷âÑÄÅšXéSމCñ½LaŽ˜„¬‚jùþak´Ÿ)i€µ»‹@¯MeMkïoy%üQc7üëN!®Ê£"{Jè…:ãþïZ<šd4ޥЎ]±Å}^Զ׈Ùõ6·¨s–T„"ÎóÚíw,kÄfU0‚@`„ˆ%Ç/ïR÷‰Xy°À…·oñÎýÀÚ„èÏÝX‡kçk“æAàpáx‰2w¼¼°Œ=Be¢,×¾>œ1T0W×°æGÄ_ª¦4!ÙŽ 8œuH¬ÿcÔ5w[>*y3Íu'¶Ý ÝÊæOÆéuߘèऱ½ú·êUz•]C£ÈÇG[ò3„Öa£v°¡ÓÍ”°4GÁö‘†ÎGlÊXáÉ¢EB2å\°…=|úÁúÒa‰´ ¯«ZT]ª›Çdüj¨³]š?›’¼Ìe  –íBG3uQ’²3¸FÉm0£·$ˆn¡j6F¾8i]i¹Aú?Dv´Îßùg›.•)¯¹ûÈFd•üº{³  :å êEÙäËȬ¼•›­u ØÌ@sþÎ×ö¿£:9(–¥åŸˆâÖe™Së¢ÜuP}ƒ&«uìgǯ¦?È£†í¤ôÅšE£íwëéGÇ2Fï€2ÎB»¯Ìf¶°>g—“H½¦zÚÖhôޤbéÈ­äTŽ˜ªeF®Õ ¿--cåŸÄ%Ûç\\!ô"©ˆ§YX ›Ê bÎÓ<à®—a•ÝZ› F8XÔVPg¦BñÈ0{—Œ˜ÊKИÒ}F_}÷u›6éÞʲ—/y_â{@:“þþrõøÆ¯S'~«×M6¬³¯úI ž¡’©™¶THr3ä~ðvj1åg‘›ú°Ò`è} @ñ¤š­Áué·¨Vt±e€¿s­ '¯PבÿIµQY=›Žp »w öFK×À4I?ÜôNÚä5·|´nÏ5 #Üs‡Do­eHÐòô{y5·ËÂtá,ЂääO6ÀzÒ\»!ã£@lîzó݉nOW{:Ä3ð°Å¨¶ƒ•Hè›onXåÕ‡y±Šë³²þ¿J‹³o_u _2r÷‹‹›8¤ gÙuÄýÃ;}¡U}½d2šÞ~»Vbngw͆‡pì¨wà|3y´¢M‡yÐ]ÛÒÊxxú’IV†ãˆ<™B”óî©r„ÌUóo†Õ­œÄ„°wÔx4RÙi¾ëå a¸FÛ;¬ÓäeД¶Luý[ kM:± ÈÉáóAÃàF¥ðàžÏ¶Bõzê†á™©hÃãÅè™ÆºŠð 5Ää¦åDN^—ÿñãí%ÖÔg…á2=V=÷ÅPdžS¯_áÇ¡òÊH,PõÄ_zVt㙂nÌk›Zþg¢Üʙۡý+P²"»€³mçój¬ý¾&ˆ.Î! ÉŠ„ü:Í)V¿†$™Pÿ<,=ÙÇM)Û%ô%Ý šýŽÈœX3ÒsTaÐN ÛúïPf_Æ-~¦‹¢£ˆãÄC{6W·÷ûƒ30*½û(´@ÔÏTë„U]­ï0}-ô£±ˆ¸4ÈG/\¢ÙP¥EH ÌDKZ)d¹YyÛè.a^ñ‹öplÊä1扮YIÙÊ8üó÷\?‘Úì[?]ȶ6iŠxi÷A[m*¿–!­õj¹3Ž¥ýñ8²DdDÜÕ=·×>®7<]»ç¥»_¦ÄûC©Öx¯‰,h¶$‰pÄ·«á°x£LHÈþí¼w¡Øé6ËÈ£S.Ò‘.³ï=pžÚé5»››mŽ™¨ÞX×Í*ý¼ÛÍGŸ‰acÐëT2Iã¼¼x‹¸¯ÄæTê¯ò\0joâ–»ÑT÷u/¾ YåU– ûrWh©wÇfaÒ[ ˆ 8€€Èi0ßõ Ï­…Üüv>vÛ&@ÉKŽ”&x÷›oTˆ}”Ã3Þ;{¯HàÌ2µcœ©ù RϤ=ÔòëîVg»53e6ƒN$ÇS¹9©Óû©¬<={Å9 v>d$ûk ,³DBb¤9£ê9w¯@ê_®éÖ:‰‹²¥R7w›Yai%¬µÜsÄèŽ÷ÍDù$Û_F·Åv)½Ã5á±>AtòZÁ·C”ºõ«Žc^WT¯¦‹æÞŠiëu@ׯÈÅÿwdRKR‘D³”¤T|O'efR7C'ëjÉÿð >ç àÕ^xì÷逌Õtƒ)ìâĈˆ3PëM0Šò†Ë"$CÝ2Û Â€ÎÜs çB‚@Ý>$âÙ×nt¯4L”òJ!×5Äáøv_Ñ;•¦œR’9šÀ×¹AÁŸþ1×ÀŸ›wbè¨PBøL( ž?h®Ð»jÔN4☆FuŒnšO Bê‚<ºOr€@Ò ˜¬—Mf¹Ý'gT÷óŒß·^‰û·g²yH–Þ;qמÃMYÀúST^ŠÏ6Ä-›)xŽ8ÛSÝ|L¼½Õ™ñXà>ÔÃMš+¼’ÝæÏ2^\ È^Søì,´h|vg—Ý™»[Q¾ø„Fò1¹¥Íd• ÈõŸƒ ‡ R°À5ºÑÙ†­FœØådPMAw; (m ³®b͖θPAõÞc¸ÒDA6û¯ÙTܾ‚SIå–7øÄ*'cÐÉ’&@åúëIb¾]Ò­Ç[ÛZõè"õm´†PGSŠƒšIîEÈèÁ¿ëk\ȹCt¾'Ÿç;†‚ò™Ô€Õ õ”%——ª'¦±òRwÿ„'R5eï@šyΔœí¶[‹ÿ~I¯‚©½ÔzÏwe]Øjõ^Îqz»%]ùDCQ‹$ÿ 4ý—Z}l—Rç„ÊPýÊ!Ô±¤l×½”ÔméÐ#PÆAQ+§ÉPå“M+ÇNS¡½ý$t4+ pœå‚ä­ÈÞ]ù4ߺŽ:‘ÐsB!»èݦJO{±-nÁŠœRÆhØáú%&˜·½â®è»Ý«… 3Nì#o\ÿ,ó·"ö±sj!˜ †ÿ”Z58~2Ï${H=ÍÏß–´Šáº.K*a’•3ž,šï5¿ßäHÏr2_à8 ‚ìÿï93‘™4±ôŠ>#üKM{ÂNå˜çLÄ8\Ç9¤Þf k¿fž§pßSݱKDÛ1!_¾Á¸ß 4Ë›Æa_e•+}¤úÜ~Ø”Ñ Ê6éÇõæ«Û&ûu†üš“ wº¨:ð¶á³ )ÙC­ õ±d‡Šˆ¤Áá"†8ß*ºáän±ƒ­¥® ÷ÝDÔŽ4YÅó¤oCaNºò½×6þ’€˜¾‚žA»©&Ìr?Ê\~ÊËgŠ®¤z,P±,ÑKo¯t£(Óîñ¹¸?<ÖNqIŒ/ƒ”Æòzºó<¶ fט¬:ËBr†|l4ã¿w—¤ìôýÇîEºîr ¹U‹©þr¤éðæ=j#†nwX…%*$ú³I©…gƒJTù`#€ø9ÅŠiÉÑd`§¡ßßÀS¨5&pKŒ2ƒ´ß꣺µÉVCÂU°1¯íËzÅ¡ ‹Áù+¥SbB‡ª_b>›òÎ$N?0,n€¾ !ø’—}pdÜ-­„_EÚ>ü¸j¹ŽlîÕÍ/Ó€‘ÔþL+%*&¯0[ß–·eMc…½ZÐÛó*ù1íŽdÈ¥˜Õj›ŒèûcÀ»”ÙIÓú¾ÓãV§š8D|ÌIÖ™øbOŽ9jÏZ}àw|¤¸y=´ÜƒÚ¢yŠ3ÊŽêÑ:¯°ŽÄd¿TýU|˜Ñ1£%4Y ñ»YQÕãghx™4ÙÙB‹ÿ§)¨œÂr±œÁýƒ¦Öt·¢Ò«5À½¯# vCØIù8¯všêÖ™ÄVª¢È±Uéw–)” ÁŽÕÊ:åkOïIfN€{Ë8עРn#¥4Uõ8¬2ýZ ƒÖ%•o ÓзåèépÞ:2óRžÉü”0–n6Ÿ“çƒ| ‰žèîr²®ú‘-”“m㥣ž ÞÞìjŒÞ±µCXž@Yù‚ýK…9ìØAO°¬Š$»á¬î$@$#Öº'.iý^ì Æ ³ŠOÚŸªÁS‡vÚÄô*\“ÛãÜx¥1aË{̓´Q!¨ hÉ3y|e~Õ¦_ xÂ_º-µ¯пîèl5·-–• ûDRÔiÀ¸j6ôf>%Dó eMÅÀ|NâþeI÷ó…— (HÉ)Ø7b‡ê"mô£ßËñªÕjR¥ßkÄÏ4c |Ç[cÍN·äXAz°§Ÿˆã–“[D¡CÛΟ æóÞÆÉÞWÊ2[ЍXúhl<ÿÑ.ƒ&]è줆¤ Ìtõ¢Ej‡‰™ýÉ!7!y¦Y<­÷0ùÚo·Áª‹¸‰ ô~£ûèB5è&Ÿ·QýmïyÉ}Z}O†Í`…¦vøné^ºÛ ™›óǯô©Ž$¥7<0µæYè‰ðý€×àtÂQ"ûõÿ•GJÙÉ…ÕÝ™ŠüåX}b iFHn„‚Öj€Ñ ;µÈªó3;ë…»˜Æq?!¶‡– –O’Û7=’Ù|+æÓ:?ìÄôeõíÓ¼ÃçîRì•·é×îS⬠k¸:w!}'œ¯l·°b±Ó²…×îH*f‘WÎo¯]‚0Äå4ŠJŸ]\òg$Ä ¶tèRz2îðÊ»†)¯É‘ß:Ä;ñy`œÿ¹F­›¿™¬¸(+ØmÐÀ1 ¿·8ìÊ»9ö!¯ïQЮÖV3»ÎB-x~ýYA¥—šÖã)ªµ{5 hÌ‚ ª‚ Æ)áEnŒ[aƒŸÀy+²®{zÑÏ'?aøŸŒõáÆ(ïx,åõ\Oh0$ØÚ $‡íc0ÍÅOŸ°j]¦.ã¦? ÷¼ÁÆ¿ç=cwŸ”x zä)˜0DÒñv,ö­¼¯³ÊHN/Wɪy8Œ¿j˜ 54^¥pÁ>„¥ŽÏcÿ)ðð"‚CÐo8…Ÿ›·ñŒsfú­ò²Ÿå¶"]”¬èxãn×­œ ûÅj}ÀŽA<Ÿ—fé.“~tG2ãü*ØmD‹þk¡[Ô Oû’Š‹°µùËÖ)ªýQF%é?y’‹¢9õñ‰ÓÈž ®ç‘ÊDšmüüÏ÷ºö뎗HÑ©Bð½ïó °ñ¤ac“ E”׈«iºvƒõ7Õ¡ ª‰~’ïÏ_eY]qPó¹ç·¸ v½ñ.,Jóûøp$*T¸!·~³€§1©1̧§çãE<Ìô#â¼åÀš Ä ÚèøÞð2û× 2­ F¸Ù·å½ø²|*ªøÇ&Y[¨œTY–·2fõò‹¸2¡C–VVvj· ]ΨñèÔß<8m‰îãPd=ƒ’2ÿÞú¦›.1[GS±y5X’ñ=ú41›†7ÀÇfZÅ÷1×–C˳põ¹œ§8Úù¢èn»8‚Ésò?…J|èÖGû“eÈÈ;¹ä)mVËm¬ÓT—õ}0<–¡Óê$,,Æ¿Í6Rfq9œŠ¹ãC÷<-ñ À՜˿@S*fmP¬Ë=‹ CÁì-P1›ûfgf¶ZûO—á)—m¼ãc¨|n:)ݶb_xÆ—¥^x*ªb‹% &]ÎB¡8à ^ã°¸%M6IŸ²ÁváöÚÒG›üذc.jÊôy­cM7 Bw*ó%Óß5<Ê %û¡ ™íÞžÎU€; Ò y«n0¹[ÇÞ)ài}zŽßÕ{»{VegI±r‹øio%"0M–e tÓý+ ŒoKëÍ®\Š»zúÓh]2%#¸ûºï"Þ`ÝÓ‹\Á|*(«Àgˆ[\ìc#'¦ò´l0£®j¢3°E¡Cöä+â݇‰¶ðÛœ&”^ƒ~ip©,V ë4¨µQÃÈ&¹Œ=è&š[YÙyé[]]Ra}B”™LC«(áÎÍ\Ÿ''8üèk ~‘¶?&·¤‡¤Hg‡xš¶7=®Aä„öDï<^žZ5ÕC©v8›šŽ2QGl%ìKoçSY<Öb¼¢h‡K¯eÀÔpç´ïÁ†‚£S*t³ ýíQœ1€Ïj7ó”DÌð*? V/3Ö®Ëð2SN’C@,Ò:S'‹‚y¥&ìÓ– ÀŠ-ŠÎ7–<Û &ê=Û’vô…Çñ4 Ó‚})É/µÂn„H-"¥e‹ÛºHl‚*˜ õZû探¹±§³ˆ®Üa¾šzŠÅ¨-TùD#,ÍªÒø‰¯ut[x|®©Î©qN>ÃIqv@–ÂX‰± X4&‰V .^¯›çlâø,‘g‹iºG ¹ƒBø0Â^ѬæéêĺȊF£7êSà‡#0ïw¢i¤éEy“c\^_Åt§ªåœ„-SŠ™ï²á÷²S?'õŸï1~t+A}ç‡cÂþñîL’*Ó–K?M¦$P f®hVu(bôU)]Â=q„LêíªR£uʘ6ò­'îà žf¯5 RC=cm CXé9æp{–ÅŶ¥8“3©žÂñc1Vƒá,6εOR÷,3‰þ:ŽR„{4ãÁe "ò†©çäZb`ãKãÿpI ˆŒëòÐ÷û¬Ú|Ó r¥‚Y‰AúR õ÷ð ý°ô¢ÈŽ‘YèTmÂò¬^G:¯ÔÙð!Ó6ÞV3|<\:^) .~ÙþÛdt=~z‡ü =ÙíÂøÚs%ÿRþy‚XuwÓj îi¶ÌE*ÿ<Ȇâÿl½—ö==”g ,¬˜Ý .¦´(³j“´v§r‘Þ‘†è3¼Z ÄР¸ï_±ÜéÖç¸ÔšR8u‹ žW µ ºßqzÓÒ²aw»øtmÈðïÇW+xw~v „ çB¶}†hqÚ• ý&”RËµŽ®!¼ÁȤÎH+‡ªÙ{M@͹š­~G(Žä—^¨ˆ`|ú ˆùø×8Uãú’ ö  CØÝqá  ) x±ã•ÛW &1÷['hó êØÃV¨ÈÚÒõbÁ%­h7#"Ÿ4~‡Ľž@Zÿã:¦ä.¦£aÿ™´Ñ‡’Ëb¹®Äy’¢5†ŽÀœdòàΠÀ@¿#÷J%X÷÷?>Èv,*Éò¾]c>IæÑ pÛ¾¯<ÊkÁºîپе.·b”XR(ºYò —Î'¿ ÜUgº8oëô渘‚–î{­èq$d΋t™X;G,ï£cp¨¼ïó̵? ÂîØðÄÚKKÿ‡»·G+QÂþ¤eo€ˆÐs³Øx"›ãGg€¥¬æ´É4 1R-ÑéÙ—o¶‚tÀgTŽ·‚¶>ï^Ýß:«kl\Šˆç!@‚QÝ =¶WŒ_&`UœXÐŽm–LÌ·q˪.vxzg7ø^§ÎYÓYgl\°óiÒTïŽRÍF×§¡3ãhûö/Ô¦õHp h~L­á’ª^yªyêÂÅW(”?ïý¡ÄM"Íè |c¤T-5ÀÒOWÒÈUìP[ å°‰I†šòpû±/ÐF‹Usžñ=÷Åï²…CøY䄯âL`Ç]À(ƒ·ß¾Pì•SëÞ!à’—cöa"çÍ’«Â1<©ßƒ‹.û%¬º §d<ïx¶7áͰÐ?_Áý ‘°"müþ¼w•¤¡¼¦w8\4 Ñ]ãL™4ÜqÔ2i é»\ÂógßœSg¥C´v¾RŒ™Ûþ˜nªþ²*8«ð oAš®pÛjg‡Áj‚ÃHÅÁçŠÊ™,€ùàëä²…rŸôo1¿%djüxFì dáâŠõ( WÈ]át^=Œ±•ame¹£|õÝ´¯C±<¶s$é½ÿ$Ô@"Y7ÿPp5Öк^ƒ »CÎ Ùú«7XýÓQg·Ž?•£«KÁn=¢ÿå×ã bÓ¥åõ¡EÝ(FnüÌi©ü“ŸœAPæ$Q`ؘ0Ln®öz¾Lí¦±í¸CÒxRÊe©­ád°&ë~…Cç@ fPò3øÂrRãxõ,ƒk˜\Ç€tû*Z Œb)”Ø1ÿ²Ìà<ßló]™wÃ.‘Åï>IFH¿]98|âoôÊKâz=ÕI¸jHÚ ‡ â;º7… *ä Ò%EcÁ-Õø­>‡Õ‘—^–ûdˆÍù]ÈB¤ñ³uÞÀà 1¯iC„Ifgc™M‚ºá6½0™þšYÀ†—ÄOþæ‘òèD—ØG}®m˜NrO±ŒwH®Uºº³Eô_Î$&Üês=ä]Sªÿ?nßìf"á¼—zœQ%F\W žPÑÇ; òÇ…¨o”=”°N…øÛôƒØš#îÍ#àÊJgmýiÛYef‘ŸdQN/Ú.GªÜ³-Tµi£&Yôñ‚Cj²ÿ§Eë…o¨ÿozÓèŸ"á5]Ì«zñ„j­Ì›óæÁáÇÜŒ#—‚§>c¾šºßPóB {£‰Éô:£ n¼JPy<ÄC) Z”oò…àCì9Æ.(Š%1~´ZP¼©65O†(Ù¶ ôXÁ'ª™Åk¾¾Sì×þ÷­ð;eàž_µv·ÁÙ õíç`»ê!wÎ+ ¬¥„æÐOl:xO±Cíè]j÷«ß›Y(à õIÑëËî‰`é€U^Ð7G™ÛyÆ{.Î)3Bouî «Âá/ß2*HáÜX"ÐÂô¿Ø%ÖmQ#±R¼n§ñÀPˆÖeeò~8Þ“ö)ÜæÞT:dºƒ^بxs[p~ŽE¯²Á¶êÑï:€ ;‡&?K¼‚¡s°CñhÀ½6øI›ö-”8™ŸÅàÓüÂú…0˱]ŸXÆ>IŽfM¨VOzµ!_”‡RVéqüþí¸fº«;¹‹`Š›INº|@B€“}ÜšÙG˜ÿ|ændVp,–ØÏÉNõ ö¶1ô-ž<Ù¢j<ò*(ïÞ$ÕÞ’„ =ò„†c}£%;ç?î†ã‘è!veÔ%kû{<(O$3% ¹iâJ§?,i75³?{/~æ&üÁ›³?“&¦9é²ì€·~ýGKïR¬Ã¯øûi #û!Ä·/å›/´©Q½9®5<¿ÂªL›';И% ªÈQÀ¥Q¯<‚ì O½«Êç\S»í¿nÁÐ8g}sÛ®-¨¦Jÿ~b/‘ N ôi·cÊÀO5º±Žä>BÃ\C­ƒ†‹…•²ìšÐãæš)‚{$ô’àÔOªÜÆ8×èåäx üÆœ;ÜÈŽG¥¯ 7å ,™ö̾r„s Œ‡=ü ‚_Jƒ|.ÅÇ Ô&˜Õ ´ÆÏð¿{ LâÅmž#ù/ZiRµ€ÎT†Äí¶•« ®@$›’°ò †ïó„±cÊš¦üSNiMëhÅ >ÝÎI}[ô_0LVLeLÿ>¯N\4.µi€ÁözTÔ%l[‚²ómÕØ¼ g—ÝﯹÀ"›V+Èe6«‘T p"š9Ucl´ïÈeë,ÿÓ:öŒ›­øAÏÞº?!r˜Z+/xt²@ÇrªÇQœwÎw ø[Øï=‹ù_½¨þ…v•ÿôtу¬‹|–j–¡/.¡yÀ,¤f´óñ„.ÛFõ­álîì¯×EŠáŽÌÂÕàYél]__f¦Kóh a§¸óenÝ6€|çh‰å;Îg¤ª #sù—¬“ö¬­kœeè09v Ëm_ãúº@¤ÛÐ2`Á/ 仵UI 6ïZæ/9³\T¿–ØïZÍUÖ}é„ik _û¼‡Î¼Tx˜¿é ç,ñÐ%sßàE­¿9„–¼Â,#éò4¯<qa›J‡ØÔ+Qš¢L½;:)ÔžÊ2µ6N¬ k나ro´c4é†=/å#¥p„ƒRÍ‘j«0ØÑÉ‘$Âd*L‰gÄ| ›4-[ÈÝ>™C_õu†Õ 1Æ­š îXX”TmGQ3è†G:¤ø¬ØÍuEHûDœ°ÚeLPàìc¤=ý­¯dô#5˜oåK9ÑdD6 ïcDOÃןK:+ËhÊ ROvlœ“»ŒUÙZ¥[þ+3Ô`{Ôv¤r¿,c+Q“ߙΚ² ,»)ÀOE«®„[$30n÷¦Vw.¦À†‰‹²Z".êùz+Ä¿ÿU:SDºiœvBÉ)½ÈV(/"J§aQTSKÅׯ%"Zuw8öu—uò=ߨi([€ò—u$ اé@7¼ó- ¯{‰ÁÀa^€0òçúQ1à?OòU8qçýÞYØ(DOÖÙä'å¨BPK•]„Wc³’hìÇÄàÉä#?vnøEŒÔП¦’ú¾ä4e÷˜ï"Ý:®1îØ‡Pûº8Î5 ÑoQ§½³ƒ¢¾} ƒv»çW£‚ÎÅ÷ÑèffýŽ ÜÐæ¨Õ”`‰‹ ã ÁŠbÚ'AßVµ»VìæRIÊN¬ÙFCÐj\ËX$!¶lƒ¦©=¡67YxØ«‹T®èikzáÏÜÄ¿BBsœGIÝÈÔÀ:ÍËõ„äó4‰_àå*èâ ߸½SÁÓBÔÄ !ì$4Þñæ£gX§â2pÜ`äJ¡àr‡u¬)…«¤ïNÙZ1,½iS{ä±*ÞOêk%iIC2ÛLš×Ô@…–ÌŸ™Ùõy(“ín‹ÁV,çÒhmü"kôBÉÌ[°^™)²GýjíIóÛó}=bW± äÛ}-?üÂßÌŠ~©Gùï®c€<átI¹Ë ¸±…\¥ÑM^OLÀòTM~}㵎Í´\;Õ¬cɉ¡¯G‘³HÆÉÂsD·«ÖO 6†ØåNÅìâqþ¤9¨ Šr=ˆ$ÓõaC  ú=ÎU䙤¢XþDóÇ*²yÅuXß“!-XüTBëÑ›(Äþ¹$€ž©$ ‚šZÉnPJÇ$h%JNõˆœ„Ï*ÿ߇d ÷(kº­cn‡«K°è÷gk^žÅ©]†æk½¬h§­L¬¾Å¹ƒ¤H:F›Eàò¢Omè÷%HPÁŠi=»W2;“Ó1(†ïH BÀð(*JYå}¤&Ëp]§Ää¼÷«¸ˆâq#ÐmÌè Þl•¸_ó¤8e ©šÃ°“øðmüøôq%ÌÇÊ{õêH⇟<„_X•y|i‹ìiÌê¹8Ü»˜èeï,{ZÁ}Ó}-ëJNÉ´¦ÓÞŠñä½öé¶ðGçvC}'í™GÉv¢)K†7f¢A@¦cR?"1ud+4[0¹©ß+ˆ«}å çn¸/¿ cå~`á‹‚38{h/'ý4ݵ ŠÙÜ¢™µÉÔ×ò‰mfQ0ÝÀÖ¿†v½60Ñ¢'v_ºå…s;éÕ§ ¬ü°œ›/ǹ>ÛÜ/iº1Ïw˜üÛ éµ—Ç)ñ‡çŠ:ïV+R „†Š2V—òe‰Â³ß  Fƒw(!ƒüUEn °?2~máOß«¼}ö–ÙŠÑòÑÐjô*ÕI¨óR|?Û³yÓ­9µ¦tC¨‰F=Œ>PQ:uTU}É”ŒU9hY’ÂÖö/_Ê‚µGêÑ@q‡åy»y£"½Ë÷ˆÔÓE,T {޽øn™,™/ :‹,sŸœ¨ãä™–¦Kÿ‡‰=.³¿Î±Ee^ô[‡(·ü]À‘a@½ûD×Í£‚°B[PŠÜE?çG^Ê6À¿»³c×¥¯öümUx1@3 Œ&Â-erv嫎t?õËo΃_ô ;˜1ÙU‡2wéÝqHÒõ 8+…·ÕB÷>›Ó ®ü#{r s…#-]¾ÛúÒq ‰Î~éW0ipÃW|2˜G3WK¿F«' ͉¬˜^4ZuTlfíšËø ¹qeeú=ôÛ‚÷nX/SüÂ´ì€ ïŽíìag[]?84VѲáÙ{ã½JçÞšj  ‰Þ­+ºëy¾æUW íÕû9 ú´;x Þ¹‚z²aÛ¡­M<…X¨§áÕŸbµÓ…J >ˆ¶²ÓܸVO k·Å¹t/³ÕÿåËvŠÑúޤ-Y¯©O²ø`AÜH¬Þ)±Ú¿|œp¬5–Hè,×8*áL%$$i[òR.¾#Ï:V.ó»`Z³†Vó˜ Š÷ºÊ:/©%¶l€©k}öR{B¹§;”(O¥ŠŒn ¡÷MœYŽ|à¹DÄÍ–q¦$ÿ ­lÆÜH¿šßä$!êÉý_qŒXJ•¨Wñ ç¨Eí»¿ 6C9u’¿É ï-ó=GÁÕr_ -ì?’EÀŒ'  0.l™z=f}²[]þ˜LËEwnv‰"Úø’û2zê)WM¤P¤ÍòlνÉmh+â·KÌèÝϨ¥ÄPÒ*Óg,jïB°èóÈ_öÀ¬MÛZ·O˳Œ;PØÑe¸Ìöl‹@Iã@H@•¥«þ§È=7Öž&¼Ñ/¡ˆIæïkº÷‰ñ,_Š7IÙÚp9#†sÖÑŽöù·Ë@WýiÁaн1ÈšøÁÜ]?ŠÀs˜­ºèØü騾˜“ è·F§z1ùLÉ_¬>?C¯¸?í\sFG·ë_¡TΪî-อ!_Â8U=¾Ó)–¾å$/°ä=­©¡á‘Ìa‘@ýy|XiaB/¡Ôõ\ÂR^º)ª‡È¢„~i‚þ½'‡­GMrLšâ¶¶áS „ë?-Ò|+ÝúÅIŽï*/l[`×°wîð¶Ê²ceàW™gÄ”¥+èêÐõÈ4à¨JÓÛ¢NSÊ«Êí¹W牲•HÞ«tˆœÇÆqq«¥¯ôø…|M¥CŸ¯Ëõö.–Pž0šM?‘å¶?Ý#ÖøâzE&¹¹ßÏ2–äÊO µõtñB¿L©[¼ƒ@¼—DÅEy!v5M`ð ly¤5EÆ€”ä*[¢¶ƒQ$~°”î†.C$:àåÏy8¶ÈM5eјҒHÞw Å'|…Ó¨ìâ·‹9+­–ÙH¨¸sÆqðŠÚÍnº e&|k–½ñÓÀºëØ6·U^ܾ»ŒsSj|ãkU ®êpN îîOI8ôÇp/-­áЮ`]/ÿF„Mï–2¤SU£[£ª¨äXíÏ#µ)c}2@Ñíb•)p ú}—œÌ„œÜ›4CWÄñ*cS¡)³7ËÐêu$»¸æ‰¤Ë|õShÙNQ,ìZɰþ?þû‹ÆlkNQ©‹yŠñð7)Êçš W$ÏEÎj [º=èqOpÏsu(`³åWUŒ¸†’Š‘בã%éL6.¬n”)0c’Aå²]ÝÒ¦‹+ûg[auØ0‰—:GÁYm¿Åêü<0SÓqÚì%£÷92î}HÈbÈù“¿åA˜òG+µ7 ®š\«àm¥Ô;H7ð¡òáÍÿ¿ÿ3ÛŽk¸Ùj#FÀð†¸½ù#ôuÍIFprÐVûeZª° dú&^ ­ñ‘Ímãð¹›87 uÿ°_òH¡·,o48Ÿ"üãdWÇÑéÏóßW¦?Ñ|‡¤o/Љ[ ßÊžP“5i?^ªÚz`M 9ÕK¼ZDgðV.pÓ’BàíH:,¢ƒ¿vvX«n>/ŠqY}nqö»GëÍÅb@Ê…/:´‚+ô"Îþ³XÖ¿r¡”úÈkïR¾ ŒÛœÖWÿ¿ì–yº{mc‘¨sjûvw ö­|àþQÅRWtKyÚõ3†ßç'Æs)Ýfx¥@z,l¯B÷õUù/A›ÿƒ’[o ¤„ÞÒT %Y«cOéØcêóÑ(À¿ؘ}茉¹›FW2µ +Önd4Ù®Rƒ¶'dÔ@†[W Ñ×ÃM5˜¸ïIŠb¤vT{ O^}Q¿THõ¯ËØ×”˜â&±öü g½Yv@‰ Þ¾ÕHÊHéhL¶¥¿0`ºþ5RÕFнççp1çvÄŸÑ[^•o„ü\øæ—çè_\6bŸ¹µ}ŠD—[zƒGï»è'lýîLo5^ïðÏ2ìù½ ˜TÓ'ÇkNS™Þ"öKlhÎqûÞ˜01ªS"p¿ß…”Æò<±(Å£ïÄZ“Ë–UF½ÎC?nFç!Íùœ,‰0 ùNÁ! SJÃ:…rÍ-×ýˆË%‹Æ£Dûê§âÊ\hµ®ýB =)$:ïY\35_YŸíQùsc¾C½ï…T]íB4 bq‘4›oY³p|ì¢×3>í-lš°Þ\,±4žµhR$‚ë°ðEoþ¼¹1M|ÂÛñöæ•öã;8»pe´Òõd‹ïý–ÇåQ.:‹[ÿ0d¦$ujp9w¾‡×{¨pÞSD¸ üµ Ûw7|wx&Ü5—XadB­JRk™ ó3Tô„¶­þÁqJÌüPsðÊaO§ÅïÊå/S] \Ôæî+Q ‘v¬á[dAÆÜ®¼P]€“Û¦ÜZÇŒxZ+ŸªœðïÇüœC¶ø ™”ÅúYß2|) JˆÞ–TœÞ~\Ú:¤ïøJ‰á›Ïh\ÑÕ·š û²9‹K¾2 ?nâêOÍQ—DKÿœšÐõJÖüuX5,ý›úˆÊÇÔæ|á­9ÃWœZ Çã!pæŠð $Ô”ÒîÇëMÃHΠFæGééy˜žÚà9Ÿ¬î€tï5)+à œU‚|•¨ËÅsd}ÄóÚ<͆aAàâÀ\Tœ i] ×ë‚~…t,Ù$N†L}&ÈçGyZ1¸3W¶8¶µWúù¢@@m' èoÄCq¹Æžª¬è Íî"8Œ¯0„xŒß»íP—(›â R‘Ÿq|#Æ8Š©ü8›ø·g-g§Öo]êè÷ê8ò'©«‡¼A뷤ϣ„"¦D^ïvx:rÀŠSÔnPßÐäLHœÞ¯Vô‹¤ d›Ñ ÆÓ«&ÂÅÖÒß|Õ†ËCLMÖ•ðøå—Õã%= êêÊLûU†áe5œjèË.ußV“q®›s*r3]c~k¬êiV†¨Çh™|„'!F8;ÅSÈôLJ›X§QÄTIß œ‡D\ ôx« +·É6§^ùð­žÉòè¼âŒÓµÿÁ«~FÕ{m£jÊOöýy9”-³"f=Õ5N•̰TÎ)éðû~+Ђ¨‘¡,U J¿²Íû„ýôhé5šj<žÝǯ›é- .‘eì_¾˜\<„AŠÁà$/—¡gž¦ŒŒÄ-¸×ÓèöÀÒR,Ñ™b&ÿŒ•m? 7õh¦sŠB#²¦Ø|Z[¾uî 纵µi—üG÷žLê;G“Àp:õ>Ð*œÌÚèè`Ç¢ÛH]Oh¢‘K®||aKPÔåW¯ ’ y0•Êsšò/ýüU ‰öªŠF¬W4‘<”¼ä|Õ U¦ñfi¶À0åçRD[œÑèö>µýyÒ'ŸéFšEöW`(n–‡>"Ó‹¯Ø)——HóÉﺋ+­Ú tôÔëöÊÌ‹Ô!îš"û)bMºC%$ñTt‡ÌznUŸâ¤C”é,¿GDëŒ`ïin‘=/×Óe€°ÁÀÁ¶yU4Jd«*ܪ|‘#þ¶\+¸§JXYx"@B‘…Ë£–]é|Ì#x·Ý½7Ó–#æ uÊ(ÄÕ ¢?[Øô =À×ûÆ‘xõÍÀMGåv­~OG‘JÑ!†"CVÔ´Ie3NWAs= EÖA·(§Æ]_s?Q'ž¨ºö£ “œ$E×Ô_G3åù`  VY•Ú§ŒuW’~AB¡Ó_ì•§‡?gŠDþ“{l'¨|è—=ÜÁû¸‚H…ÕF=p¢©ÿ‰ô3l.vùÙ?å¾M·bI$Bä9bÃß*À‹ÊJ¥î:ú’˜Ô™Å½´Ï£__HhÍ·G²?Ü~–ök¯¯YmM»l`Áõìj£}÷[êiÚngX€|?ºçûÿÚ|¦ 6#?£èºN÷/ +ãîQk|ÌO SB®€m¶(´J<ˆ»GP‚WF_Ú' ›×oÖW.¨"äÞëp*¡£î q,×5y¨‘†xÈž(òºLÉUísH «¦_”ÿ’ƒù$:µ'xeg¹Ü°3s§®¹>'v„ôÊ6ð®úÝ«„biW–EófðÒ‰-ªÀ'w­(ók«ŽŒÍÃìNV`•ÇÌe#v‰f9+°cí ‰¢&‚¥Zvä'þ %1ò8z—²ö=ܽ&é¸ÒI××!3ˆSY#ÛÉhhµúh~±`$êžmÜ€±Sy€hŽTå¶[Î8>¶Q\\2gªñ¥èvâî`è—ä¿ço·¾/ožOPu5lDÙ ‚D Fý±ÿØŸŽ(iø5™Bf"É—©ƒõ5("A¦±롈hCƒWìMFZÜ"9EB~Û‹¿Ïº‘ÞW:î¤{7/Zó–ƒg¼Ï}«ËL”Õð³zYÌ”_˜€¶‘È{ª–âXÄ·ö¦¤jYM'›á_É&Cm+&}ÝpÓ™øÎnXGñpÛõ–EäÆÎÑAô*Ä90 lQYz!¥`âÙ¢ì‡æ%<‹SµÂ%D Œ”:Ù‘Ž™4ÆP·eQ·IÊ•ò ñP¢# ÅiegcBTÑÛšcúuÁ¯ÅRåqgüôNìðñ$©Ïã>2ÂkX–„$@lÐv£®Î›E˜YâP›ãØ3 t I0ïõ8\ì{­1‘™TL1û;Ý ²œS©ÐåÜÜ¿é’Õ&Ó \­?¿Höï ïcŒ_Ø9\¦53⬛T³v­úÏ}ÙÙÙs“‡†¨Õà{eð¬Dø® ÃT¦¼¤)E.Âgø¼;k]Áq„Y¢ýÅš;µ­Ød?§Ò·UýNöC»€~¾'Dÿè$Ýñ‘r &VÛ† øIë4E;'B:À Ê‹¼¾ø¾Ém‚âH|E.¬ÖTŠ9÷$=r¾%+ÅÍ¿¿;ÈaØy¶Õé©cÃÿúBÖ \öøªgQýÌßÍñŸ¡˜´e»š=šàcpZe“önGB„aºš«ÑE[V§ V Î}OåQ”±¿Q;‰„n¼yarƒX˜6r æÖ@Û1G;=Úîæ"Ú²²²hëVqÙiM…¯ P/€c¢Ú)J^½@X\6%s1¿=$^i†ýäÐîè!±-<Û_?œÖf¬cbù‚4ØìûœÊ-îÉ¿À¯¢H›áoÆzüã.ì}÷}”™H`µ—ÅÀ;èe¡–ÏÖ\K‹ã¦áê–‹ýÄÞ;“‚ú.U¸×Iƺֺ—I¼œgàš¯²žÓWüq>|ßx»­ãΪÞÚܤÏíùXY+:âÅxYôeÁé ¤Ã¥œ ~ùìõ@4з|^–%ÇnAD•¸Ùrý‚óÔ©Š½­²|ÀaÉðî˜'ç0…kkmù`8£z 0¸@Fš"»?4£Vy?`uÔ·ß ßæÑë¦5ƒ4}”Á@è7äÆðkò4X"îÜÍËü\‘®c¶¬jǦºÁÅUíÞ=§-æ­K"æÎãÔqÓ!AIåãÄìªÜU­1{idSeÐC í÷ Èj>ÚÜÕYL$%‰`L>®º ”í«Uö)š¬X-ïî@\@ÙSNÄ ×ìJôÈÌÂÒÞkøŠ|[gl »ä˜7è´Ž’lÖS¢j‘vR\âUÕË5è÷÷°ÅE \‚~Ëç¢$âë×Ëz2ÆØì3m¹{£“rf‘©Xš3ÒÀø„þmå•FîY¡?dVgñÁK…ý/~tó;6TgÕꬸʼXKÛ~¾oÉVgá# Ñ6†rºäZAnƒp½ÝJ»DÎ¬Ý üôÔüM[LÌfs9 ŒìÈ2´@ú<°)Ö‚Mó,ÏÕ¿UkÁ¤HÌ.›ûeúÕ2˜IgX Œi)û™¼a¿+`IÐS |çì[^½ù«*«×zÆu&âÿÈãFº*Èõ¿/D9Ì-\ZEßò è‘è~âtïÎ%ÐA^j ÎÁßëôTÑílÞrµµÅ6ö_)ÚÔ,U) cÀ£­¨‰TXi gû‚ ;\h»¨ˆü ø1´©û(OO¦o’%b•,jt¥£ €œk|²1á\Z¸6X<Úõ7–mœ;|t ÇH#üÛ€’íóÇJ ™N}Ô£œcTÇA—à§M¥å‡Ž‹ˆ¤‘à+êÎZ·V¬y¥pgÃã$[ÖíÝæŽLYªÇ <ñhûМ†PJäþ¡'¾ª“Çu¹ EÝ>¹ðÑQ꟟ë*µÅ:[4îRLŽŒP;æJ$Ä5àF¶eÖÆ–ž8šž¾*ý˜æ6eD°…C¿»rHMI»¤{ %óÌøK ʾÛ/KÎ_þèÖD–`le}å…ô‚5Þ_¿è*}8…GÓ¨ZsôòðƒÀpÅÑиá þ.¯‹\/,Ž¡Yÿù[»F ³ú“þ¦ÿ¾p®†YZÁyÉ\'úïU¾¿rpx.É@ÅÈ6´Ò‹%œ^.iü"$öÚûÌ'Y3škÿCÛäÈ{5;a¦E¦>åiSmKjÜÍ¿–9GáŽÀåüÒÊ\Û-á?oœ~ï­Ìöu`-¹¿éÜ+jx¼Pˆ‘Ün Û”Ò~0Ïïó`ª—$³#®ÿ ôôš˜Âèž@)8½¦dú´Û¿*‡\D¯Îð!º5JôÛƒsüe¸™÷™Á4[üœXsüšzqà T.Ÿ‰˜ZKœcÝ’AáA­g™^Aðºêõ^Ê:ŠZ~ PÃ’” °n3JrûŒ<‘ý 2·„½.ôïN+{ }¤¡]EÆÛ.R*9©®­˜bÿÉÔ/ÖÊW´ë]—Þ1lÓØ,¯¯}!Ë#ae¿Žõ¬>ak«i/S\OáähöT_±¡Žu[ðÚPi]9Eì(îÅü´,`‚Y¾S!_´4HCõ[«"C V#læê‹ç§Ðw¹¸CtÙÅË:pBd„ ìâG9á~ˆÊÒW×7à ûžKg6…(ý÷]HQð¦ Jû3ÿ‰1¨þÙ3„i èÝĪáïáqü*¶Àz' ðÀÌ6Œ‹]ÃÍ Ó`Vxºt®×Öÿ|í[ëJ £+qлvÚìò£ò™Óºt‹gZ¸ã.ÍÛ?7B. Ÿ&&Õ~ÆW䰼܉(†r¬Â­m°HÐU”n˰àÐSÍïHê ]Õ–¸šŽ¦T“‰ÕÈ ZáýšŒüâ~«N~´%õÂ)ÜÏEö„NŒÒ±w9="ëCÜäN\ÙµÃ/¸i¡'é`6mŒ£’äû#e!Ý òMûò“ZÍ ¿î“Z)¿1{&Ì}uÅ;á ¸ ¡Pj&Æ-ãT\ÕYb"Ó˜¼†¶†¹ÞR³8ÈÎÒçµ÷f-²9šãÌtzlàªæžvÊ=[)~b#U dÓûÓ¦‰4.ÀÎÇ:²D3zËØÓùTï x¸¤i}¾ª¶œæ…`àÐ;à|,6`ÊìQBäûÝ+\í¬)¹* —"¥X¤œ`G^Ô‚^ÖîãæUG¦7QèT†ôH|£4§¦Ù‚¨!ÔÜê1fÿ@©(»9oúpVMÇ‹tr=} ‘Cä)б@r‘A_ùAáXH,þáêéÚeíaÕý˜mðÓK.a¨¦|^€ŒtäѺ¦ìpKk©Ni¬+”úQOç•/š|åÆ2n^3â?Vï’²] #Kp¯\x„;+›B±Û™84›íÙˆÊ&(_Ø/XQ•§î¼²é| ÷)ÖWƒz*›G[Ù¼á +P£žB‰ohìÆa#_h¹Œù}ªn¶ª£RÔ…ô cýÐÙ… ë·Sã±Âî ôêÄþûu}`mFH³xsŽ”kÞä@||+‘(B€@˜ ѧk‚-îJK %¾j³8í·¯ÞÂ%ª^¦Mž$Ö.Iúõ”ÞÔÏò[N`‡}ýÌVœo•µ§œL$œê“ÚöÊœŽã 8Mòn)?¸í/©Ä´·Î{ÄG­]+‹öãY šÝ¶ ÏØ¦b#U¦©éoɲúuEȶ‰ÀËvlWbÉ•@E ¸†ùκ}ëB0ÜÛñ2¶zz¼ˆµ…sœFMÜF ãÀBÁ’Å®„'ì̱ªè¨qŠ¥ˆ‡¬˜Èü·¾èÊ©s8‹ßë·ü‡ýRçÍÓÕ>àŸW”"–f‰Ü—¯ <éJï„e@rC/g=£ºõ¹?–¯_@+pÅÑ0(ÔmvN’B2Û°GŸÝ.uú$ë2²‘óå´6Óù44õ›ÉØý÷æ©áà«\’ã›3ÞGóAú®ü“WÅÈÆöx’êz#&ˆ©x3D/j×+ 5°>àå¹{Ì„n=Tò0õ þ¾mëT¸©àKwuùoÈDŽGɾÏBœlœêIˆCÄÉо“ù+é7~yÆx"ª™¿ÏJù7‡$/vÑ'áöÃ’×ù3ÿdö…Zá˜Ø$ì®—Ž#dèìkÃ9‹‹âÁe® e s'±^÷a+çÛÙyåK2ĸå\7o:÷ïG&m»b…? ‚Eæ¿…Ó*Ш@›ÉrBæýe”v½|OœKfko|iÜÒ`HîOm7®IrnuþB…$²¼| ÷˜Õp·øèé3*[_jØh¯¦.’ŸR‡Ù.†Ð²%8³áÛtP{¶ÌgVKèÐøƒpÀ›Úwû%btLË ”ó¶Ž«jdó¼P ­:mgTÆ<œFÿ†Q¦IL@±ÛL^‡djw³d‹—¢°’$Ùm_umý(\Ù·½YÉÅš·c„G„;2¸µlç'£ªæ ¹ÌÐâ.ì ù€–®,DÁcÓÞe韚„0°‹}|­fTôûG¯=qø¿¼:ˆP¨‰ít5í´Ð÷ #2aóóüŸÐ°' °4 ^ÇÚw¾µ ï[‡j¢'+EŸo`¥N¦&Þ©>¼ Ó¿mØíû¨ ËxêU9ýQƒ¼TÔ(?n?δæÒÒÁÄ“®`™‚cäEô6µœ…ɉ$á\mPŸÝkª¨àºØÜßµwÀb43÷ΘéŸÞh‰¥èqÐŽT¶äŒsZ0.¥_m.Î)¬ÁD[%=wŒ1!(sÙ=Ž€gR[Éw ݗߺ8¼lž{ˆ½I4f;°Ò_)–Xæxc"O0‡˜,k=ôîäç½YŽYôåg°¿µ$ â¢T¬·œ^”Þg'<¢×¬ãw8YžÑ¶V÷Óï1ë᥈ÙuÔüiøfOÏ!ð–öR”ót]¿GåŽù™Èý`44(GrêZÁû`Z[*߯œJ³pÀ:)·M³Nã!aâbLÉc¤oˆN€Cª–›t0 \†û´„ô|E ›š#«‘˜Ð™N¥ðÕ2øk¹½¾ã€hֆȹOb² êIOb[\b0\“އrk\AuN?n$u¹z|t?Ý÷Vé¯÷~‚íåéÄé§4èT‡ÑßA1\, m¤ƒÌÓ™ÉÓl@Nž‹ëÓrÛ ¦ñ6ØÀªÒ 3»;Ï ˜¨¦f oß’ñy¹ £R2—JéÙ˺ÁñPߪ'$pn 9N@“ä¢ëóí³&þ,(<”Fèø}µ"ŒÒ›>žžRPÝÍôºÿ¢Æ¤éoßåzÍðÚ.>_ìnPĦq»7¶(|Iƒqºüü¬eÈ”ElÝ„'³¨Ùù-^â|Û]MKj6 }ØMRö?ΙâÏ€#ñDó8ÓS3²!¥CgBî $06çÉG@…6˨ÖQèMyŠ ™XŒã‘( ¬ç›>ªM=níÇb=ièäk1–sèÖë^ï×â{«ÄO=•¯Ušü+p ùÄ=ã>¿,õ¹fûÆê ‰–t\ËÀ³_D ™|çìøSçfñdÛÀîm¤›£qrG:µ›m¦~ߦC4ãéhë" ë„÷ÛåÜ\¢g~ÂŽP +"ì‰Huºp×Ãðÿâù‚ÜìuT þ„PQÏÛÆ-ý¨'›kYûxÚR¾¯×aÃK’¬AÃ:c½ñXÂùž¢þ÷ÐX«ÂØ]_1ÁzN:txT a&¶M}ÿ‡m™’&A‹(K—3«GÔ¿×ó®ê¥§ßdòÉ-×òÔ5þ¨¾°@rôª!J-eÕP¥m"õ!^´Ÿ÷é´ç|XXŠÙ¢Ó`MìšÛâúä>ÞíŸÌv]|ÒÌ I-Ãl²«—ZÍÛ^dÑ(#äÊïÿG¸Ž8õŠ u÷8œ-íò:¿ZN´f‡$̨QbL‚‚R»\’¨ÖÔÞ£¾)c_u2¬=D›¯lBW¼‰”Ê‹8HN¯Þ-¿9*¶SL¡Ç؃ZöœN«$„P‹}6î›U†^Z<°A…ÒJycØ€î12äÌú¥ƒj30“¨W ŠÔRfS\ ]鑳ïg®ŒÝj:Ð¥ÞVÍNš ºÂ1eVÑÎPZ52iœº²Qñ¢DØ(“Þ=—EÍŠö‰Áa–%2/Nÿ²r¢ jûF|¬ ^ßÍ’[˜Ì+pü×n€80³¢دñ‡Œk¾Ùú¿úýÓÿ¦t•¢…˜RnëW†;ÚEÌk&i‚ùKÕ¯ÚöuÜàNOž^‡O;ê•2êdPöͶ^.é0%<Æq’‘ý«tSy)û¬í—xîÅð5²®U'ÿÄ 7PmA[%ë%uSI$DݡȚBJ¿^èÚ·!Ö§j¸+‚êóVAàvÛköC,i]`·).±1tݪJsÆI•eã߯àÍçþç³óó8pd™‡ÁdÚ"ý½Fæ õÑ:ÞÒPü¸j<6Á&³Õ9SÕÑPˆÈ â§ÛÔ° ¬÷P²|“àðFÒŒHb¾[ÛI^w_Ôör¦²» …ÿÍD²U˜@«6.±L†æöðr¡šõêå’Ê)éeŠˆNŒôŸÍ“A?â½Ò™·AÔ/˜Ëz¢Q_*ÄÎÞœ¬Ó0å?]]3ó%CÄ䟖w¬ÙìüÙŒ õòÚ-’·:èÄ{!•vµE]Þý9 ÝøåF®ø·- 0=uZdËŠ¡E™|^°CLëø2éš<’Í@¬?|)q“§³Jø¤V_ýàΜ* ëÄ®~0Žàp1 #Àw­|"‘)û¤eZB-k[¨Dñ_†:  z–p°Hn÷Ñ~ÜaÝ4åºJ)©4Pjš[›`çO!†ô<‰è¸½˜™Øæ, ÎÎ¥LE…ôÿ—å7éÐߢl†ŽsÛ"¶xÝ·¸PÐ!Áܯ0°2 v;Ð#Þi:(OùÌpA¾à¨<•º>ª¢“ô´êqdï¬ÊТŒõßÿ©ò‡¤PØfc˜mUæ4áÛÂê² !†ŒTÎê*H´D§U2ù Rº¬™§‘Ó†î1ìü9`ùô}×ðBé} DßÉõý¤ç&R‰á3 QF6h¶¥±_=ë’øRîiDç4èó!©Iô^ïqæÛîVí»©¥‚õ{ùT¾|ˆ $)ö ÝÔ4%]B ÌÑ8:ØßpˆK:s²câeÌÒÒ*K%„D#…Á«\?{GFØ-û7É€–:¬y6EJÛ6]ÛŠUs*ྔ©˜nÌùêbé¸a:~㕇“pg~:€ÿóe.—G÷íš©f¥Ÿr¦\g”{7 4± tˆs•ËÐÃà3WSÿÒVGÂÌ«ÎDm3…²jŽkŒÖ6ef¦ÕÚ¹­á¼8–¥´Ëf®%O¥Œêl|®²˜. .y™˜¾!„ïr|òÑ@{÷¤ %º ±8Ú–øÚ••٢ǞÿÒ«x(ßo+;>h.᜸,m£dïCtN‹v­³Gœža¸e}Z2³k ѹòç3/´²ÔêÔ! ÐzLÈÿp}ÑDÆ]ûȇj­Yînˆõ—>ÁSÙÈ×ç9ê`vFn|Ó¢æøŸî¦r$½„âtÂAsùedF¾>õžSä€D«Sa·î¨1RxÓtt8ш(ö¶8Ú°éÑíê#Œn&Ì ÌªÏƒº€e¹B‰‹°éÊ^_Á“ó,>DSHq܇ ‰ ±Ø!9eµdJi'=0 o%Þ(ríìØû¦ÝÌ^¦ÿÙ½f1]')~΋ÈìåéŠ7b.72ŸkÅÝÐyn¿4ƒR˜‡`yY¸1¦¿nøI <æ]Y†5Ø©;ÝtCÐÏPú-ÚDä§°Ú˜™•ÂOÒåvmÿ¼°1¿7?[!G¸—ö›ñ,k&ퟠ6ßo›Ü^ýNxbA„ô÷6i{ƸqÖ~Ñ>ssÃ¥²÷¥T hûŸ©{ì8Æ“Îç!(D7 iV`iKL =öãJyË73²Sô}¦Nü0«Á_K“zø-‡uÇ1cϵ˅ÅkxÛ;BQFÅ:`ý¡y‚æÞÛÄ^CÕü¸‚(«˜wøŠ˜•ˆé –{´5ºíÀŠš÷ÏËê‡]¸|‰ ‹I—%K´[™~¿:uç‘£Ýd•$FÁ{A ypw·ÑH‡ê ï=F¾;=EÉ?~ ò­‰½²æM¯Âöûûé?ÅAžˆÀÅIœ‡ß£Ç¿Ú¦_#‡-B”ƒŠÄÆg'×X~9ïjhãí³|]äñ ÈJ.ºK´'Bãòj=iv×®!Ï¡¬ -Gâ€âP;Á‡úN'€C¢±>ª|ÁRt6Suò´¹€ÿí Æë,=È¥„+J¸FŒ%ÉPÞ*Ír'·ÈzÃP'ãë<ü€©~`#XH‚/G‚œpþªÞ†¢‰À%ÑC$ªkÖnª9§ýhs¦º·f,…w,ß=$ZßnF¿=Ö麙 ©@êô±ˆî”µö©mL,»sDcÀÿa“a³~$ü>ßIAˆ"›º{xŸ_´òÇ}Cƒ¥ä¶¥‡Œ,È<š*V«dL У×ÔÔ,Óµe.H½wv=®^th†p=}gZØì'$‹l:0×Þ2¤OÀ,XQQŠ O'ÎuŽþ…‘þè ­w1¥ ªHÄÒE˜u±²ŸmZ|æ—å‡D‡Jh{  Aï\$‡~ÞDЬŠ¿3Š‚²P›«I' °dîX†óÓOZiæÀd#厉ƒñ¯2˜Ý~ &Ç÷BVÆm¢ÂÆþh‡íã“‚:×sWÍš qÝ.¤k|ŽeÒƒ[Þ )ÃÚâ€V0NÁwe$ݳcm5÷T¶–]·ûݰr£:à8tDÊ õ,®&£ô'pï‡l2YÛ-g+ ]HÃ[/3…&`ÔˆîªR¶„8'¦ðçà&¢É8V=gkûc&|÷Ó2šÉJ–íì?œF,ÞÇ6­Ó¬µ¯e‹ØKâºô¶!¹ñOá Z7½ÞE•¶~ bÃ1þÈ¡èâBü_Ýa73éòVÊýk")£Uÿ³ªøaXL^“\‹ NÌ£Lûèéâ87ÚåËùD¨.7üÑ‚(ŠslÌûL\éLPµüМ˜Ö øÓ%Œì¾8ûÈ}ÍÅÉö–xBØÇüžo–4þx$zaø8Ã¥1”|OUD¦XˆÁ&›!†ÃzmO,r ÛÛê†u3Bäÿ—ãj®XY<¸”ɼ2uƒa»KízÚËTüÌ‹­ãX:ˆqúkp/õF©rã³]Ø(j Ï—ó\ChÙÇtJñßtËM¥>_9†©Úy]ì2>Æe Wg§@!•šP “Ø÷Ðц¸a0Ú`U¼a Î×$A‹yÉþ]1ë 8¥ 6µÓ0¬=¥1UÏ0º¯´I¡é±•$«¿qlYÖ«¤­K²¬Õ mÉÕdƒ@2m:jZÇZÐûÆ`KL?ýë­Îy³Vv·C¦*ée7i~Kí'>n$—|š² óS®ÄÈïñÃû‹ÎvŒŠÝšzzø¢ðæA õ7i©CÛÁq–çgaýÖULíQys˜ö¯C7­ÒzŠß¸[PÓeT3YÈ^ÁÐ1(j®ü’ÅX³ï†Ö¸Û¬³¦l\ð†Ï"“:¥t`‰Ü²ŒÚínKÑš$cuT0B?­ZÄ¿3¦¹j-e¿ºáVáýM–åÛ@e|Ü…M>o;òÁ÷œ¦8³Ë™sâ$êo*÷@Î*£•Xâ*ÂðXÜBΫ7îð®&תÿegª•›ŸPÍÎÜÑ´~æ™|–XÿÝL¿¡Êr81ĉøÐ²á»¶GÒ,ÐF8‚o1ñ3,¼3læ3â=G|æö*@éâüÝÖˆUN‡‘*R€äÔ ž!j³*2y?Í€CøH ‡xÌôsckm—ç%G¼­°¶vGš?虌åºÑ3€s *ˆ«#P3âB(å˜;ëáüv¹1m¡³"‘oŸ7"§,ÐM]ìþhÊMä# Âë ð0Pé|—CSV˜á>T6SXUXñì ¢aqkæâÐ>´ ‹¼e4õù8Ö³I}±TK2îvÓа” Ô3H¢5-îCŽWªÔz•ïéî9Æè›ÙºñJ÷Ú)öÂìO$;¨[²,…¤š¥d¿è{xU$ÁeÓJ¤P[Ýa’ U7° n¨éá=Ceb˜~‘¢~ûZŠE…[ëÖ‰1©¦ ”ÝY!.wƒ<\ÆÔh"Km¥‰Š —+c0,Z Ë>Æ©ÝæeæƯJ€ÅóHMá뵈h=Ôûå©GCžeŒ4xØì7î®áªúâñuÚYŒt㯃’éÎBËþ=;)9Pç6({pÕÏ=ñޝ[¼òäï)ÃúÑé †žŽ¨>8“!çÁ”ä‚c·˜èÿ iÆ=X¢+3q<¥ í£fº¶vä¨ü,÷{‡™+ê7úغå~?¬“Å#fOÉZÉ£O‹5ñs­¿Mägh“û3~bzŒfø®RÂ( ÔÜÐ$Æͤ  ”Ü=¼O¬ãìÝ>‘üD¨,£ü™»ÃOÒJÅÓÚÅ{žéèQÈVùËX_Ú8ñ má(î `— Ì ä!cn¥_6BÞßâÔØ¾L&4øÁç&œ%ºûÈÆ°»¡UPøiŒäõà¨ûkOË>gäR¥cÝ ÉÛª°9¤4éB‚%À„?> ý Y¨Ä;_,}¹Œgãÿë8ëåm0Žï LÊÈ·›1üHœT.ŠÚŒÂñs‹wqBSÚý ‚þ ïÌõ(—øCõ_%`Ê&Ù™£*dB™´Åèl°c9#µûV°ö‰ñ¶o1I½8ìß­Œ>`u1Ðt²$™¨yèmD‰ZÕªKÎ_¥Ø‚ Æ ÉLgãWÿo›>M7µ¾û ›öhéÁëåß~ˆF“‹E"y,ÄSçYÃŒ[µ è®óé¬kÔ©A×gµ}õ·š=e¨Î áöü¸ºÙJí•éRTÉB­®ÇLëܽ}JÖjyr~ÅÝë¶hãî 7÷êcýùþѶ÷³4é$Ú½®§ˆ¿›—TVnJNñ“ú­ ›ïÖ^?ÍNb›¯NÀ"ª>£ê7Ï;¶¸Y·ƒüÜnRû"6dØÝ»²„-Ž s¼;Òþ´áZ-·ðéͬ¸Ûûžú€:îq½Î=±†Ë_ô\µž8ù¹”­ÞZF9q_—žš&ózÁ®‘úV6cäɶóÌï±Y»SËå%×3ÑÓe"$ö[ÎêþI[qšƒ#Ÿ 4Yõ¢‰Å÷šyÚd˜f¡z„lçNB8'k³_¤s5].Ir]ïòDv@D7Ú4tÆ/Ãf{:åè ®Z¥À•<ÒÈ®&h½›œ å*Ì؈%éq­ÚѰZˆFf¡ÛŒ3^9‹×›AŽ‹fOYÛ¶ÈâaÅQo&Ì,?°r݈4ˆÓSQ7äæDiƒÁœVÖ™Ï2ÄŸÜL&ˆvaJ-ˆi·¼¬˜ 2(¦¾0Pë¡®JD焬Üi†ÊïdÂò5¹#îÞ‹°;¸Âޱ$€4~pk(íCÖ¬)ˆXð|^ó6Óªà­Ê޲P»G©fFƒ–]=hð¿ìÓ­¥\mÀY;D®ž7õ‘ÀÉ<¶x©_o°Â)­ŸGªå_¤5Q¶» ,7üfE.ßäàˆX·Šú3½jJ¢h`ãd)Û¦a/19† ô÷ºw¸®Þ>v>«Ñ¥œ½õ3°„ï•­xÙ×ÛþÒô±’ÏA†¥Ÿ=ùa⸠ ¾¥?ÿß_uŒ>»ö¼ iô£Ã(R(ƒ%7ÆŒªdA9½„¸3÷ÀmÇÏ&‚&i¹Ü•‚:Æ'»n-ïÛ ¦ É—ÒL¸àLº7º1<>UÉ â 8’Íî°îsÚQo¬Ôi}õkj×GçB¦0{ìúÍ5¢àñ‚GŸ+neÅë(ðqP&Kò¯&Âò¿ã¯–ÿZs3/ÊÀ]…ñðÓzxæ—(W¡ñìzkDðæ˜•>¸äèºøeáµø¬ I‹p°ýoñH®dEMh ð>îÑp4Yiays鑲dž˜*µ²L8}3Ó¬àŽŠ¦)@‘GLéȳAJ•„Š<´°9Vù˜BJ…íhÒàå†V³ÜæÁ·ŽñO»â¶pt ÑëÐuB(_[ý¾-Ý>¢tzIÉFÌ\ªB†ä}Œºù÷4ó&7æ¥Ýê9XAÚíÑ”ñ"AstÙçØÑüã:5(„k³¾ 3ÉJª§ýƒnér¦’ü àïÖÇÔ¨mû»²ÚÑôÃK +ò=&Ñf· pb©9A¢ ^ÑÈ¥sPvw³ÎŒàf×6Ô"]BEWHƒ@›jATMHa‘åRt]`¯bÔqï"p —õ2òAÇñ¡‚‘µ'ÕʵV WÜ€Ä@ù*tSÌÍtýÁåQr¸†zÐx¬ÍwÖŒ’&‰µ[ܻӶ[ÒÙàe-èš=wWúÕ’Û¯«yºñ oé`‰Æ Õk²Í¶\Ðu辶ì#AÛÔ½n€ôÚì×µ®–"niœ*Å n'ic/ã~ÉáÖª S±‹Ð1)Ø&HœŒÖ½a ÷WеÚ4Ñ/£Ž£è웣ÁÀOHúœw£ío‡j-®|è„þZQçõ¢|A’­6‹èh<7‘9Mí¨½’](ÀŽd¸XR ™K„Jˆ=…²8ͺy{̾À.í*A_c*ÙuôFã«j‡Tå{®GÜomãHá¯N[³øý½-n$ÅÅ\D@RhOšx›ŽúõÇGÆ c/àøô£éMaxmýÁ¢—GH’Z{‘¡%²Q‘°K¸Óz§iN "±À—åyI|^I@ÊÅÜ€I¦V`¯Tqõ·™¤: ð\êe…£tÅ60_Ÿ ;¡kgÚ‡çbÛB‡54B:­Ô⓪€(¼ïyYt¸et dwŸ®ŽØm]*VWù6‚J”´~Q.ÁI”—ËJôu3Ú•hzÊ5ÎÂjë­&ë‘+3ÓjàãaÖZ†Û0óâx»"_5b%/¬Þãƒ4ó‡´„d€IÓe­F¢‡ÀÕSðPþFU(:È.½zø8¢†…ì¤ò©tÀÑv¯ü¹µ-sòËÁ'$ ~·LÚÐåNûi7JO7ž1ñ“oÝjîq¡hÓt÷¢c~êGu¨ƒ´¦°¢;‚`†ÖOT¸¬aUÊ?I Ë+ôÀ˜cVÌ 'ê`‘5?‘Ú¬) )ÄÈl–ä¡ÑZ8 -ý™y©aqªUƒØ®[ȤsŽ"û%Gz7Yª›uE*w~¡Sˆ dà¬!xŦÂÞNx°Â4}<$•m9D} 2íQ úÒ¨oû%Öñ-Ó°K/n£.M˜ Ð…€‡G_³”ħ§œØ_I” Î»"v9v©'\Öðè+àû”©‡¢àÁMÊäÖSm*TI y©Ê²¢üAtQN îCîÖÔ›fíTÉŽÓÉ·5q«–œY%vÃì‰ fœõ„òî„!·t6Ärloé²C~`f×ùþœIjá8ó¦Õ¤v|‹„½0V«ƨùó?Hgä10Œr¿iÐè£åÅ¢%²w¾²Ðº5N„ÏO C• ŸNu¯7Ãum†}k7³ ßR›°uŸë•p6‘Xñåï»ÞK ½Ýé ¸ì‹†“GKsYh6J½ÑŠÅƒ²ò´A3ý=a5ë5X{–h†È]é— ŠsÊ *_)±v4% ¦k÷«íoYû0ͼ… +*‘ìI¡·SàÈÖ(Ø—Ü žAû…Äc‹dà?1È •†BxI» Ì·ùµö4‡zDœ·óƒGv½øé-Š÷ε|CYHgºì WÝ@œë-_÷Àõ Àï‚ô"óBzi¦Œþ>™š~avjç÷+RÑ¢YY …õÙµ4<òIvKhÁ[ù´øyh*IíI m˜JL¸V,ʃLJAUïv ‡ËÿŒß,3Fç,«Õ”³#ž 8ªzíN>ÛXŽ÷.:íÛ8Yåºÿÿ7òÿˆO2v¸#3>|€H)}ldÂxêA¢¬ÍœõG4'竆q|!> "öO2Cî`¶z¹ßÆ Bul·ëâ)”ýcÌCǸ\ 3`¸²Uè4zî¦?- tOÙ#¯ «yDGÓ¡ÎV7»²gHÂ+ý¦ÿÁ¶ÐL #‚åžÙAØÅ©ÃZLK—Wã¤g‰`1¤›”9@¥dBozX`xƒý¤•s¨œèØÈP [ËìœÄ„â8Y;ã›íC±¢LRrVè]üžGèdp¬ ¡á¼r¥þXô—NŒ–d'%ùzx…”µ#X¸¦µ`¥ð²ÕüKù¥h³™Š=»U$Ü€¥A(  "x bµ~v×ÿù#Úª¦_˜ËݲJ :äÛ;º¶G¾÷ˆqë¨~È(ýo$~qèE)Îõ¶Ó›Ü‰ÛÒ—Ô”ÓG^Fµ…»žŽô”yKñ3ÖãªXÒŽÁvóPŸê‡6•@i¾p~¬êÖÙG;Ã˲*¦ÃA°Aèqš§œ3ª~Òâº](V†güÆ)+ô9™ß;ÎKEö›ççÄ]Ý_ô¢Ypl€gããˆé¿e|ž†»½è«ºc=\& •Ðoop/æJOn‡IüQÊ-Òü–¢¬d×òú¶B‹‘É"¢œCžÁÅšòE+—˜_ßՈ뷖ªˆ¶ãÚp˜¢>äÇ=7fÄŽLØp~ó·m¼Ãƒœp¹\Ì[5ç ¶³¨ÁÇT'V úÁƒGÕ>sèeŽZá6ÈØ ¨©¹AM£`˜—0Zí"„Z!ÅIxÞý ¦>…÷^]àÉÉ«šn”QÜ[à@½(iÒ&d®ê¢ç õ6wß´ZÑöê§Pøh|^à¬L/­vB lŽ*‹©ñ¢$ÛPx ?N{ÉÃmå¿~4rEün- éqiã)qtmùJ3và¹õ¿^àG¸¾™Ù&‡¸þ#-^ÙÒñpž£&ÂvüÆLa£<’zÝyž­2%¥_ì3wÕ-!J1}–”AÍ¿ ÎgF$µ=ÑJÄ8—æOXÕºìVÂ6ZÍ{*pC1`ì7"¢­,9ïï‘pÏÿE[£kU °ÎXM ÓCtt ØŠ@E¡êiRLÆ…1Ó¤¸OŸÞk;DS{çÔi\`zò»]ãÖ¦/y: y@?Âéôq‰‹·ùNJ-õˆº‘7YÅs@ë»ÌŸσ:’)qp«ÁÓ/þL`,'øñÅÄ4Ù‹°˜ñpQÏÃó‰“ù>~ƒ(¯VÄíý‹õ.ñ‘ÇïvB ,³…œû¢lôûhaØom…#ÁÆÍTŸÌ~$…¸65“ïiaÒË/Êq „$Ùû.LJÀ);Ô,Â`úHºôjå¦ÃA‚ïJT„Däò4p'ŒÉö‚î]õ¦éÅ2QÚXAŸî.RZÅÖÐßdw’“BÄßÑ• ¾å 'A4‘ÃG‡y+•9Â’Ó.¥Œ¡( ßçÐkïfRº g"§…¡jÎ©Š )ûrÔ-®§ëø]BÕ÷_±èi†U—?`Ú÷–):ߡ鈣bçk«–ŒÛ®KÄ ú=zÒöá…–4ßO_Þ¯Vhó{ì¶ÅZÔ÷B«ã+šoÓU“6#µÂ¦úY þ¸:E6Ï{ªÃgOe¦±w€Í¸uÝ®÷º,K«8àî!Ÿ+ý+ô.ñ’·/™Óuš¼ÁÕ?ÿ]®)§×àü4”Í?Æ Î™>Þ¯@«q)Ú,‚㺂;K™ô¦,Q§&Eº¾xö„€ÐÐeúzí aããSdrÔqÄ€÷ʨ/·Å bÆÒžõ‰_µ-–Ã&ø× ­æBêv9G%ŸétmJ¬ºÊ×ù«›U¯FYD”_™Z7¿ªí׌Ù{7·ìºG^ ¤ñ‚ K0†(:ÿ}èF!R’’œé—p ï£+Ï—ÛìNi¨(wFØ׳5嵸 g\ü¾Hªÿâb ?ÃÞ»0ÖBL°3º…ƒØGLìÂþ«¿A>XiËÜÓô’Iâ9€N¸:wX©1ß×@–7y\lš…3kxxdïـ܌ 9§BGdÙdtñ|ç:Äi(¹“#‘ÄTë¹¢ªB ØJWÁö JrÌÉѺû{Œ öÇ1ð±ÕÁÒ)§u]:z¹²€5s‚c–¯×un l¯ßœéç"/ðí°ºIÉ|ÜÏè ›ç²BãeKÇ[Œ*Ú5³Ñdš’@§}Üjæ*}2ŸðwW]¥ÝÝähj7•b‰5«M€ÛÜ “J‚ÇUJÿzb{ ¼·!ÝmÚî”ÞàqÔWîÝäçe Ž¢Oü·iö!NkäöK¾"i ½rÔ²uÉ${¥c¼H3'|_AkÛ¼':@ò gòT¯œ9ÖLNhåú¦ÑÌX-<¨ÊàQâʇ²®#ÉMÓj»Ÿ-ijù44‹U$«òlÂGåzæf6› Øã•ÑôPÎùÑìü³Éëî™NL- !6t`UM˜Ê© œïKÚŸÐÌ{à_‚w¼vÞeméÃc5' ¹±åì MK{… GôÂzll —V_ 喎Ĺ ‹¥6&( tµªâY ËödQø7;+·÷+ÙÍU™ä6‹‡±ÓZ"`ž€“ô%ûäœD„*°`Ýjƒ9i3sÞÿ å6©HЇçŒð›ÓMD”Ux^Ñ £[`«0ƒ¯‘iÃäó2ü9ÏàÜ5T‚AýIÔ›Ï@’†cï½!ã¹MYœAª­ Ëö°§ºs ljȷ:¼‘úþÇ:‡"¿©qèz’!X Ìà|ÀšJx×¼-FÝë @¦¦´À>EŸEtfÁ¡Öï8ž¢²T$89ÃA©¬îA‹õü ~ù• £g¶ß¾ž}½íB•àkPïElÿIKð[ÖÊÁÅSÊ?+{ȇ­Æ»Ö ¤JÆÆôšòövÅ4v"öºRõ9&±|úN³}†¼kû'°ÿ8È) 5­±§ž4Fñ¸ŽºB—Y“æ»ðüýRI Òãç°¾·œ©íï¸ô£šÌ·O¥PM{þ|óZ߯PŽÕd +S‡ J“¦t>ý(#µ®¯‰ÒG\Ü*ß×ugÅ}ØI0x^Ô¨õ„¤ó6"2¾‰ù¶_â#K$ ±„àêÕq²‹ÁFºXý‰SpOtÄ‹…Cè¥ð¢åýŒNZKù@÷¿j@16ßÄ´^„6]>“'ñ€¯ç‡CÉ}óãp‡†•†¾|ÅÛ™£À°òQkxHàùÊ Ž¸ªõðóXùŠ dO‘ù[¦*|iÒ B9Œç¾L‚ôbØd¦ê4mRýUoD}‚6ô[šFÍõjçC8Fã\œÐ øƒÓq¯JN‰:<ÑôB—¶Ã1烙R4îGSáh¾=d~|zö®µ¿H >ÜÛzÿ†ûaøÃDr^3Ÿ Cað¡BŽY‰X/2äÉþ)ÖmÓ òÎW7ì3½èY3Ç6 5„û€™HÙK»^Ä«·“=ÃÃûÆ×±¥´dt&Þýèм4ødZrìþà™7Vtw(ñ®*ÈàØæ4ÈZk ó½xïÔtáçy¹J$ÅhÞåÒ<`)ä5ÇpÀÔ‰ý¯¹Æ5ÿEÂI~ÔžHÞà*žˆØRvËÜÞH"û=›ÊD.%àš÷€¶;û“FýÅt?¾ƒ¬ÅTì?Ó(ô0@H¦MAî³û—PÆŸ xe`u¬íä °ûìe݃ÛS ü„U%~©4ß{ku[Ùaë3úþ¦¬á4u5ð>¨ÈÈí |Cƒší÷>î ñ“8ï.Qäe¥.GÒéšFr_?ïÞv\Gt< ÏDs}1­NëEñÅ™JjÆÜø°Eä§·’`1Î$ê~Û¿w4½ÕÙ.‡½™¾ÇÍ€Œ«÷ÍÉ•Üàѱß‘ •öÒ¾æÔšúsî°Þ×®áetÕ²|tNðØ?UÒÃ*:Ê/Û8ø¾!2-G×&:›žŠp(g7‹ø9Ä3R?výäÔ¸YÑz ÑRçµlˆ©ôÎûôoLìN‘7h,Y~~ê Î.¹üMÐŒ‚U@¯#ú와s͆‹…ÆõdAØt¶BtV–WÌ;¦Æ©·Ã;=c‚zS7•(‰–¡«Ùv–TNMEÿÂK%3Æ/£eõ (‰pÒû¯ê¾™oŒšæÚV²ÀñNYÁLËÔUJG§µ¤‹ö{çÎ!Ëa+ ¤çÈ=¸B§gƒG®íÒÇwó/Øó+ ^˜zb5¹jj›âî?:ÉR«¡çKšØº×»‘Fɦ›]¶Ê!ÜÂа6õÙ±>ˆ[êѱƠkòµº/N®³À© ¡;“øõ-Á#­"JÆ ­Yk»H’&cʆ8Ty &Dh¤­â×¼!#HVðý‡ß¡‘lr赉 3ºÏ4Áɳ¨Q!Jm©ÜÛÄ3+(™¾Lõj~çéFK~3æ­,)›Ç»Ê8LœÓp¼ùá—[‡±ºšƒ0/°ðz†OÈÄRš·#?„(wraˆØxšWÒÒz2šª’÷0Sm­ª )YQà]æw‰[ÆŽ]Ü`‰²·OáS1±÷Ì3Qéq½ÍUw¸òï˜pKÿ”÷ÕIs—\ªŒ¼u;J¹äTXà™{ÑLƒ}z áó@òÆŸ±"Cïñ€ZPjo›Ç=Åø ¦9"´á¡±iLuÊð$â’—ãx$"X8cœp²Gk˜“9ªþEœi!7Ü×ûÓ€ ÝùáŠBÅ$ã{®åæËz¬õMèëé$Ãш¥ØÌè‰rd3r‡{ãû0{,›Î_•…‡:yKââ]:Rž•ýƒPø‰D3SÜá½ñ÷hº€Y@úÚêÓÊI~MHdê®xeM|q|Œç‡ó’óÛ펶â Á<°7’Èv'íqɬ÷çéR2sžNÊ\ŽpÞŸ×"ƒz4|•j‰½Ë^‚Y$Ù°ÿÑ£>%åQôWŸå¼Ù*’[¡Û›õ¬“dR}Î@@æiOŸvl°ÎÒe{4ü­­?£X ðãêZt·¯Þt+¦ƒ¹¬z†zåÙï_@G^`9‹v’ 'õsÔA6i]3®òÎÌý$A5vÜèåuø]¢J½«ðŸßaCêuž?{v´÷·–ÇÁ‰Rõm°ˆºÍrqŽ,ÿ²‹¦B6Q\ý²ÛO©SgP<ä×p]Lð(¥¬PöÌ$2I¦^7K„±…Bè¨j¥©3Ž´7#¦Ö”?UdÛZÞ'yËv€p’!HMúÐD +笘ܼB0ÙÿWK£P[Dö­t`jî•îC ·™8ûÚ?އzèÅi§2ô¢êŸ·sfJf+Þ`"=•¼”v韽°º¶ZÞ Å¨ÚÉ6(˜¡¢YÆKq£Vpãi]…¡o}gåûýŠûóñý7Rg¬"6ƒ (™5û¨Fµóú6ÞÎ~ùŒóðÝ å'¬ºÔ±6f†[C€šq¢>’l™Ü2|52Üh»ÿHÖ‡Bef¯ÿÓNí&ÍL"_fÂ=8¾ð-OJÌZÏ«$î çÚ¶Äû’Bý ;€ýÐÓÈkí‰?½Þäòxfu §?}3•+÷Ê>íWfŽiר°gYÀ4ù[BŸF&ï¢à1±÷4hÈxåLooI—ík·°’/(^|Q†$x`~^ ÁŸ x0v¡œ2ñ•W)1Nµˆ w+gKÙ£U :Ì9¤FEñmmÙ€ôƒõyrZ©,¯o·ØtþFxìa[d›#>ÈnDAi`‚%dÂðç7‘‹úíÊÔWiž‰ÚøR³÷ÎÖµŒBTd]ÜJ/¨6ƒóžý ÊØNýž³ïS‚WÉNî#î<¬˜ÑÕãtÞ+ò×¼Ó Ff¥Í™¯0J‹™ß“~jÐÕÓ,RŠbm]¼[`0Ϥ^¬Ù òšbsbê3£Pbß$xÍC è.%Л¢1qU~—¬«íNÐTÃ޵ײZ0vûÔÿ‡àF¿vk¦TªA[:]ÆO› ƒ~*t«…Á/zÑ %^;‹>ì-®<—!zùùÊò§£TÃëC"1½ÛkÙÿ|xÈôñ†zV/”E%§ðµÑ:§& ãAzÌvCp8wrÏ–yó•Ãü¾Ä™ /¾RêQ¿£ Ô#„y‚¦ÒÑ:56&pI \²Àe6?ì’¾ÉRÖÌxÐã\Yõ#ép-,ÀnÂö}é?Ô_©×j2nn³hŸyÁáM£$Œð¨ãU?v]€58º­ kB? Ìf€b®ô×Í•õ†gd†dRà°á¹œjêfùcâFÞ¨0ŽYÔDÐÉð7kVIC¼NJQpöÒ©ÑÌ-­ÆXù€74Z$¨±Õ™Ôäpÿ)ëÌ\»ãrÜõÄ›ŸŸÇkÊ™½»Üã·þ™µ'NŸ$ã€Eª¢]ì5ÄanSÑ/~EI¤[?ͪ_a¹’ïZ ƒÛb]*Ø Ëm»év)>o¸†²qwð D¨>xÃȦòŽM·–mh£áköøÅÓ¦œŸçMе脌±í±tÞ]ËÆÑ̽f÷Å4͘[ÝÌÅþh\Ú9Iëy_©^Ç {ÀÀÕÈzÁM*Öd%Ðë6à :U õ»¸„…¢ TŠôϾòoÒX‘?%ç(œdäå?Äɯâ—Íík/µÄ³^2Í Æû­IäɱùCYØ´h *•Büé4ñÛ ÓPÐoQø,æ,¯è“^§Jß$ÅèÝ»¨’ì õ)75À†éÙ„Bí.KFK‘‹µÈ~¥Êë ~(ŠÀ;™ ?Qàƒ—_¢+ˆi¹jG´yh¸®ÖÚV[›ós·p!ö²FP ÷þ”)Q× †$™>é‰Íµ’W^ŸYët‰.¹C6曹qÕVé ahÓ ¸0N£ßâ“õªs`¨ŽñôcD÷ìWd±} ("RÇØäÆvÿ@âÍàš]Kžªtä1dY]õ¯–qÏn º.Š0<Ü Á·oFbë* Á\¡Y »F£ZtZYE½AâávÁm—vΤ¥”È Ç‡õ[³ö Ô Îp`ºù(p.QîÂÍÃþ˜¨ŠÍ+->¼©Ï/ÃK”gî<°M³*o\<ÊŽ¹†ËXóVËÞu´xÄáßnÃ70T7´¶ÉÞ&ÑÈQ& ¹7Û r½ýuýmòx©^‹ýŠÃ€¤·Xtïô›0ŒË63*HPÊÝÑ¥ûymvŒ°ð{PGñ‚NƒSyÚ?ä&K»‡•Ð0´>!8xò-—¨*È2„Þ󵄼b¼b†]†;Šuè; (F»µÇ!Ü<¼(7áŒLi4ÑûH±…ʯ±!Âi Jó3ðÚ‰µëí5?œŒŽµe »A=űë:ŽûÒB2šx©õu^DtiÉYÞ‚çt2òü‡%a•F‘ùˆn>¯ÜŠÏ³¥¢’%DÎ|ÙehÜÏh)ºt©Ø)d%ÀÀÈ¿#¾Æ„¡”å˵r&ØqÙõ‚Ž$`kß.Çá#¥ûQDÈ ÜÄ;øˆA#%kmÝí~`׶б*§ªˆøaK‡¸¥5¬$ ê`ô—Lp·Ô¼_ˆNÎ^grB5rk¾%û‘öD—· †Q+¢âpâ¯ë‰&ËîÑ‚(Ðî:@(õ¦ _½>zʈ%§âèüÙ"Õí°ÈÖàÔ¨mBÿ¥7°}+ôø6ÌÀÛ«þ ÷WªË$aÐÀ  w+ gÄÝ)ºœE«±àY Päöm'Šk0w:û‹×P<ãÇ!F©z0Ý Ëû¶“FK~gh1ç¼pð×UNÌk××%ÏZcßöîúw`ÓߦÝ× "ÒÒ'õ/ä¨` & ã ;A `[ì ‡f½}ì`5ãBYÊ^ËÈ×wqhÏŸðd‘D_ì™ø«lºó`§Qgiç—œoó¯ Ü÷à¾rWUÑCÑ"‹œˆ‚ Æ@IÚTÃ|£²Ò&Ίdúõ¬ý@ÓçCe%ý»$ŠqNÅA¸ªóèÕƒPßt¯tÕèÆð—ƒyÓžnjê9K–ÙkßÏû@ö8Þ0=Ö1,Dzy™-Ê¡!q²±3Ö‰\ewuC$±ɃÍ(>°°Ò TF”"¨ÿOpÙ„¼pÂ]­§ V\?@ÌÌÔÔ\óì>Û?VH{XùO¡/ÍJü~¿uÎïyŽ sxΤv4Í¥¨½ë‚aói3ŸÜ芬…5D§Áòž7V–\ëpQ9 çÙÂ[[õ3÷ÀßÏq5Ê‚.Á<éù_¾«¼ì …rƒcÌ6Tlo5ÀXX 7Yû[àÖî_½§’Qg¸„hæÓÉi˜A(øl\ITÊHFQO\VœäùYÊ)¿.”áÈÊìÚËw;3€&¸owðØØê% þr¹{Àê‰õÂÛRµÇÕ½+€°HSÁŠ˜Nè‰×ʽå3õê» \N9ðå²&”ö—³ž¾•¹½¢µ I1ËïC5 '+½ÁŸŠà™¼Uò,п•cÇ YÿÞ :Sèyè¢@s9“‚Ê´ÜIÈ|©©µ\’I|–P«oŸã¹ÇC¡y!idãÅúO36E9À.RËjo;Ú^"/ò '7ÝÎyxmž=Äw€Ù†6- äîO ãon e™Þ ëè]¢ÄG›ßVl¤OO€ ‚g³÷ÎÁÅÚákŠŒ¡giæíÚ´úïИ7–ôyy m[,þ ̹àÐéÑý3åÙ7äV³ É‘_Ç,¹>Åð9u—NI¬4¨êÁþü“—¬‰°‘f¿«¼"!x)ªž;왘Ülü<ëi6ŸGÉC˜#6ƒFñÀê»Ó!  é©žü&Ç v¢feuuânðS }ïòÚåV8FŽ´ìëf;“U~»£™qí|Œˆ£ÖiòÈ9è?1(ìûs¤ÄÏM¼\`F-æ¾|9µ]P¨oaPùëõsËê±B =˜lî‹Ó±FGöŒäh+<¤ðé˜÷¨;_x6ƒA«>‹éÓ-§êvr#QÍ꣑]˜SF‹uîã<Ô7éËéQv›Ú®8–ŸÅ‚4 R̆„7”IÃý™%È{¦jàÆ­¸²•¶U[ý¥ÆþèǽæÀž»ôÓuY= uS™©ùž¶¥tO\kÍ­ƒ„ŸÂHÛćÀ­¸r´ú¤¯Í3hHþŸyÞ4õIÛýË$ÿi¨ËÔc7‚AÞ¦ÐË-™\)Ë*/ªœ¶þ¼‚a¢› cA <Ý=°£ÿ©©ï‰Á"±|gVB(ÆžŸÝE’Øä-Uâ ¹¤…]ÏÇ ݹqMU\¬Þæ‘Z¾o(Ý…â†Q>°ø°±¼$ªûÝD ÃG˜¼öНx×ÃQÈ6¼>y4ú‰y3Ÿ)o[z•,W¢^Â+Š÷-AñU¹~þ00Ö'ìùž¨g–2,_Âý܇–(ãy+¼[sžÅŽwͤ "‚Ùû^t{™³)s¼µÖ·NR‘Åeû5K]ú»7³—¹ TtÒPƒ›o;*^)¿ÓeÀ ¹` åàQ ™/8.>öÒ{HÂò»ÞKÆ#D\ñ‡MAø"Mu‹®U½”š‘cçFV©gOŸQTjHÎ3PàÍèó@ꎈ —Œã©Áòœmª;Üýü2Èf–ÕÕ‹LÊzOaY¿(š9wÜ„¨ÅÏàé{€Ðàç<¬íéxwZ6/‘c<¦ÇŽOZ¨ç½"]òh²cOt W5Õ™q;à‘‘þm9• TéùTaŸ RFZ²ÊPØ 87yp7„`q¨«¯’àlùøZ9+há#ºEéñ(» ‘¯¼h˜®èœu´Fâô¢Ò£Ê¢*Ì$“¹'w@(ÒÇ©ô<Á£·E^,¦„Ü‹£¿ÍÇåÂ+-Ÿ&#æHºEþÏîA]PZer%1Ìn¬%õ7冠bºp ““}µ¯ùAþ¦Çò¸5W;ƒåGAd;'.Øoö[øÞ,®Ñ°:yçÞÝV Õ\šm¿N)â'ŽYÇ}pÐ$<ØÜ…!ä?sÆ™Å_‰­¤xÍ9Jø¥]ÔÞ¼-øÐS:õÕ“w»ŠàŸ6PñŽýZRù(¹¤ÎÜÆY@ЧÀÅî Cz(øVfHïé]~¢+úñ粎3úOñfR2rv›6ºi¤[ov0\róyMpòø®6¸y¯¨…}³ÍÀÝRO•µÖõÈvL¼†&°€›ÊŸ*:’&¹Beg2fýótQærv£¿äêcY£†ð‰›bËiõxa¨—ï’¾¹•+=óÉ…‡•à3Sv —*°ˆßM%ð“¥Ô€›¸T¼ì•=¶p,-;_fåå¡cè‚låªK:7êÂ_ôÅB@”6š^Õ>—2·ær.ŸK|~pKÖîGàBòœ×KQHÞ¬líC/‚ì.wÜCSűG@RFf»}Q?Y ¦ ÀeÜešbg®®RÅ'U…w‡¾7Uœ…G4“âçq  pºá&:ô|ͬNÀ_IÈ nîF^3Ï^¾:C ô2Û&º(ù.á.!G8PiʹÒlUúßUL:Ո蓰81K7ˆ,­않?ۙʷ¦ñ‡o6í^ ¢Àºg«3ñ‘öFƒ6€¶EŸ ¤±·åô¸e¸8íÇJÖY^0‡) "HÀÞèuåëóÿ™Ì°Z¹²§¼ý£Úùýß…:Ÿá Åçfwž!JZëêoShëŸý‘mOïÄwdrnà–-züÀÛr¬Ø?ôFÉú rç‹{ñ§z7¬ ¯¤=ïgNZtÔ°_,þ"å#í5µÛÞ Ã|¥å‘ŽþŸÞ‹éütÐÎ ®¸22@˜"ðt<Ò…Ê6ü5pôEOîi± ö SŠÙ+[ô›:Õ’êvul/Ùgk½Xâ>ÞM¥šÅálçeˆ“0j”¸MÕgp“pð…Ñ¥ç]1Ìw#±ýhæ¥P¸·¸(ͯÃÏTèx«¦:¢4²gDíTñóª, åÑùtë Tÿš¶ÿL€uD„o°PÄÙå"©¨cÿ}B/›O·]‰^ÒŒ †WÖØƒD~Žßý‹Êd¤õr à'âF‘³ª÷ݹÀ :lÿÝÀî<â§nJ\±f¯òyŸü¬>kß ±½îìd'3ðTô¼wwV§!n³(ëØšgƉGæX] qf ›õ1ÿ½øt—Ýû4%'¨2Epœg¬~ߣx!1þ(oÁÅüL7Ù‚Dš74 î¨NpØ|—Ó ç5*ÃP«E„ K¨ƒÿãytÝ+JêyåNð>^½chІú÷®’=ÐÛˆÖ¼&©2þF§’SËÁ¶•Èn€TýÀñeâzsÉ BÞ9ƒò“œsctáÁæqM™ê0_›É;Šš½'ÄÌÝmßБ”õ5ë”\Rxüwm[3¬Œ?« ²QÉ ‚ç ܬ¹ú¤S-Õ_„É4È%°ù7逆 åÿÐV¥xA ü·æàÿ&o‘d^ÇÌT[O¢³‘Y+=~Ìå°†0ŒAv[¦ÚÛÂ%Þð bŽPá.õžÊ÷Bµ§YTÆJÄL2£=¿8@ík+ÎJ(ŸÒŒÀ,ˆºa µÀˆ>¥JùÉÙQ-v~E ö î-‘hºíl nÙÝËU“ˆM¶y,òÊàì ±\ð£Q6só[ˆQ‹V›a/½««„{þ<èZ„};g,4Z´Ö†÷8ŠÀçŠkÚ“ˆtBU“ã}Ûi%úØT•sår¶#é2HCÄ!{Ž|Ü´¥NxµAÐDs8j-§5Ñâ6zÚ÷ÛøEõ«[bõÏæƒ’xgÌ$mf±j=T>µ"!^Ãt˜k»déôÜ£Ëa¿ôú&f~ØÃo)*À¬þr°0‰›•Io _ç<¹ @õßagKã;TG×dGµÊ&DÈ›ÒQ€ÂŒFr;{ÂõÅš]¡xLÂÔÕ/_RQü« ØÀÑÎ]Æ›„–PÊêcª;”Ú’«ôª±ªq²Ú5?¼„– êw«,ªGŸ£¼ùŸ¦NMhŽû/VG?kœ‡Y½Ðõ,ðˆÔtRWåÓU>§°MrÓ[äàK”݉`Ž•Z°½Ü]3žÛŸ$4j Ž\Køµ‘rg!Ä®\êM¼«˜P‹âNâÔ[@àa/åêTÙ>¦{y›ñØghip³£“4+ºÊ´á†CPmR÷ ‚õ‡¶•²_3„Qgl”ûÆÎÌFAU]Ê%Á ÄÐuK"X·MtÉ¥i˲ØÜ’Sc£G„#Ï<5* á÷KÉD‡Q`&&ÌC©ÅÁG9:ß86ö“¤@.‘IØOÁæ\jë›DãwšX®Ò Ž]Þ0ê¶1Ñ÷˜‰t&ϸujþ÷˜ã@§àöÝ`È´ìiôšÃÍ .+QØ“@Ñ™#ü‘Pj'ÇãFnܽlËÏ—ýª>zdÔâ3EÔ[#Íp4@%yèΨԥ“Ì6nXÀh,Ólڈƨ`£Fã}f¢bŒ”âZÂ[ÔÙ /,„f …Gô ?$tøí¬Û ëç¦Ðfíṫ‘¯ÿ¨wÛ‡KÀ’Õs€?Z’©aÈ{4°)ßBUˆþþpÓË2déaÖ ùqò¢ »@ þåö4\;œÅ^I-{Ø b€C–¿yoUñƒÀb±¡HFbkS$#"2Ùi¡•RuJX=y _H€0ÎN4 –tE¤ƒÝ£€Ž$ãÕƒ†J¸ó¦†^9`ªÔþ­À$I ]lý/$ÜÈ¢C àð!ÕϬlIÖ`‹:Á+ Mÿº;• tþûŽ_X¬ Ý ©bË ¶ó«é7/OWÓYWw’²Ä€¡ƒ¡‡dën¶Îw}nShö~åiWGöÒ±|•ÏÉ®Kq¢ˆØ}¯»}â€j Åï™$&^AsË»6s‹¹ CCu’yÎ9Ú,²àÄ 0åTœõ5û)iƒÜízó©œØ7[X2önû³¸=Ö¢&Þï’1KÊ4®­ Áñ†³k.B_âP;¡:§¤¸.”ú_°J¿Ãç"Û4Ÿü-ƒzå|…vØG*Ô:Ì©Ïx4¦Zc§L¼žV~¿ÒnþÄAÝS{é-¥ÚÝDA´Â(®UYùVÊõ{eŸ9¡ ® Gù2ÏYÑî2[v¸Û1ˆ|æ¨X8á¥Å0Obdç4H¯žÝÊÅ>›”Sse:úQìÞ?+ŽZSDèŒÇâ. lûVYlÎ3åuÕ@ÃüäÉx¿Lqô¯Ì}ã˜$9ýK𯾎®-ÓÓ‚Dx&C§óž†É?® Ýý"Ôà€WEo {ŠÇv*Qöym£…€ÚÉNßÃÆQïù‘=Î= ÒŒòP D¥“韼.ŸËDT–XÐxÅs^¬SRëE>ÍÒ£36ø2%„EÅDòÒ:g  %h‚ÏøÙæ—é?M(À¥â]e+‰|ÙÞÿi™l©#nËL¥õl§ºå´¿òã0ÜåŸ;tÃ^¶­z—Vq@ ù‘ºÒ &®vÂÞt2ÃkŒ‰íó[<ÇåîÈ×½d<k׆¥ó–†ºZíŸ Î$âZ¬ÿžRõTЄf¯C5l+ŒÑÑ}_ýg‚H llB×ݺ/â-öÙ1ª Â¢ÉϯC:h ŠœÊØG ƒâœšŒ-öË]‰5øÞ€ëw;¾ƒ•¤‡„ޝE£ØˆN޳6ïÅS침{\p©íz:ï’×Õ’¯í¶• yîIåU&cñž2ù+¾1_Ë rÜaó¥™&S{89µ¯/:j¢g˜€$Sº\5eå\h' ÓC2±þ’ý´6–h«O¥Oo˜ ‰u Èz²i³ô•Í—alÔÀï 4ñ÷ä—/ð¹;‹I;@À±õÇ[ŒFªê DtŽq¼á fOÿkÊ ª1´?Æõß,TõÖ‹BwÞŽ÷‘Ð[gÿ¨Ý ²ãÈÀQ<8b!¹¸- hsc¼IÚ{xÎú4ž¼eÈ‹%OÊŽJDÚÞàs¼é6¯voø”?³£RÓ€Š[µ˜Â§&Ù½¼mì„4^^¶[úéä¨00‚ ¾Ñ¬»j•=šÔDrÖîŽ Ò E+vT¼ÄÖ]¨5Ýxv<ÆÀ-_1?_³Ú{}£æ]ÑÎþH^‡ÊY1¿EU×Jy ÓEÀ'#P]ÀŸ‚û$°"g”ß²9ì*¼ädÒÄUŸ¹tãÐÌ݆RÃòMû·ìúœØ± –fÌÅiJjëØŠË=§·…¨.‰ÿcä o’vómããîö|®-â43ÌŒ$£¹ä!ŒÐmÜ^R"h‹äMBþb|w–$¶byçîE EÅs89Ù¼eKñV(t}¤{··$‰ðÕÔ=ša_Î>hÍŸçw uVw—¬í½ 2Q¦<+ÓsaÑ-è`•Îvs=Rýp.¡>®ê ÙÎŽZ”¾—¸¼$Izm¿%4³÷õôP%ÚÈžÃ%3ÕÛЗFP䨖•œA¶€4%ÎìTg6š­Î‘ãõ(W{Їi$åÜ“Zªšæ¿ v¥gšSv$ g346+ÐêbAwàrÿµªRÅ?ÃXÇrÝâi V™q4ÕÔZ|í~­Æ@éE7½VCŸįÜ÷0?u ~ªhÿâFÚcíÁTo»ìøÜ\:¤&„¤H“Î÷TÌwG œ‚QþKßÐÃà£| Ù$¡Ø;{Ťޗ¹è3p¥4?¨òVà çw'å›éŠü­¨…¿ÒÏ®p "EÓ »q„—4{9æ¼-vmú[:n'˜*A=ÂŽä;Ü<Ð{#Q[¥^wI›4š¶”ñ¸õÅ!Çló¬ƒÐþUŠ>à´Vó){µ]Ü ÍŠÜ’€!h£”7)x×б«3ÂXî¼c2ñ4+·Á#Äà ;¾>Â{bšNˆ‹Põ´­hG;ÊMMÒÓ};3íº'xô W¹«Æ.Ì„Ac”´ð§ié4B†µzGÂÙ\ Ó9äÙyð˜1’'º1;Åû¡âÄÕȈقdgÈ¥àP51ØOM$¹ÌóNI,ö®5hMsÙÂ6¯ÚB‡•`‘Â{¸¾Ê¶ãWQ€ï•½ÃÿèÛêKáÐa;9úøÙ@lÚFabï BÙ=2î>þ ê–•ÀÚíÊ­ŽÚªÛv|ôÂßÌ®ñ‹Ê-bû…‹. Q#sç'¼Àc?SÍüå<³€HÙÕ•·HXŰüQ;)6¬þi޹cé’aPW•¶£@émˆèDm‡¹"ð®r äVçñŸ]v)”4{£Ø8ÞÌJ¢Ië“¢ø‡=v3orjôÖ¨ñKØ0«Œy7'ŒØÝEhŸíä5¨iU~]άdTí—@ÑŽG[¾nùj†4îW*r«Yá#:ÈÏ×~ Q¼#$öÛÊH”“ 17‘å×ÒÍ&iôž‰ìüõ:ÜgÆÛàO*(­ ¬‡üN뜅Nõ®½X¸*u=5_uOÈØ¼ì|»#H‘Œm_q»ÀõØOMåëx[sZÐÑö Ù  #ޤ?Æ3©©ïJ4hE°xßU¨Èö¶SDˆŠ?ÏõûO!›jyõ¯ ä£ëxBô«ÀU\ZÙ÷iv¾q…¦5Ã’t}‘TG8'„;ÿ¡‹™TÎ;®ÕƒRe§¦qY«k½Àަiøj‹”p”Yè¯x!&‹ÞúŽ©YÒ8•Zç˜f…`Íà ­cŒ±W—@j²žŽ4¼©¡;.Šü„ Ò:Y¡L'ÛöÖŽá\^ÈD èóc}q9âË·y®Õ»®»‚´ _1±gç%A„/mytZA®I¶BŸvVÝ3WtúD©BlHD•®ÄwjÑreNX¸Ô®mÝ_ ý£õ°â§Ñ/ŒFC¤“˜V ´Ÿ x ÕÔ¤k~j€ÞR¸It*©þêôà€…E¼±¿°ùðË´ý/£çA&©åõZmIf³Ì´áøGd”/ ë&içâ{\âO%k?Ì:È*ŽÄø½Íøºàãð<‹„¤ˆ²N–~'ÉA"߬aÕ­¦n‹T²jZ— HnçÂ…7ò‹Øg²3½Øt¶ÓŽÚ3wPÜ ”œ[¿éžPW1›®ÿHáøy »Ië%c§Qk˺–Úµw¶“ÎŹÑû6\Þs´rÊ€öpï‚Ò‡ò.ô„ª9z{¼Ë×óu~êÐÌA kD¦v©Öc”¦{iST³“ ’pß듇v¬=;2½ydFyN/Á/‹½îŠÝwF†î%Ú´E ¿]ë?ª*"õŠéEŸÜÁÙQH‘¬à*©ÅXȲaÉ‹6T®–øyœÍŽ?y€Þ‚VA‰¨kE¥8ïöü]Ù²e?‰érÛ$îl'¼“H+¶Ò¬ …À:Y\,#¢]“×÷O´ f%T"ˆ’¥:ÿ´ cܹܔ9»ÔË6ï°xˆ+én»3SÓo”håÏjÍ o˜U·Õaõ¥ß”b¦Úc•‡·²¨ Ÿ2Ckö²Z™ÔÜqõª–*Ò„” ÊZôñÑrQ)kñÝ‚WëY, è<ˇKïHÛŽÄJ•Ñ´x2gìP¼ xØ&DœÖÒÎoû7ïÓ9Îu¾˜-'åX²(Õ9 -Jð$P`%â‹!Týa¨‰ a î¸7qäöÞ6©è¶•ûƒƒ·Ðº"«Ú¤»sd™àðÁZu+úq°ÌqÛ4¢›%M…é¡ò›Q[dð€w -¢|£4pÈ$Ù;,htpXº9`µ«¤mû:“=ì³ÖK‘3BîNöp•¡õú6ÉœÃÛ2%TÃ*7Ò|œµÁþæ!¾ïÃ"L‚ÚzþÄCAÖÇ­[4„²f®1'4 dŸþ+ý"EöÝʱ•]ˆ&ûK€e`¯Z['õ%¥–»¼"` ÍO &oâäÔzóM?´‡dJ&Ñ·žó;ž?ŽÀƒí/n[TȸP,Eèõb¨õƒU”P¾Îmj±îz{ò£l5?nÄ)Õ_:.äßP`}„pÀ’æÏÀs>Ö$-ÚÁÏkµ„ÄîV˵ûý GE+=r^JÕll‘Ýx1}côŒóÂâ æ[Eÿªß€|øÛÅúWIç&—2­†¯Èïµr86¤˜™v òR`xþ²l©¼uØ”×Ø|ÎüX yF›ÖLüua²É̘Ê*OÔ@_Åc(sæ½:ÍÂñÔ¥þ¬‡ú™~T†Ñ7é×<^ UÄt4=ÀÏYIQ4D1T‚Î¥¿}PwÒWåVT•2Ж"΀œD@­ý0p¢Åå )‡ù, ØP~µ5œ%lfj®ß†›œ ´¸+/ñÌ•IÒA¡Ã¢òÿEäâ²SÕG£2bâ†vûMî†!ù=û­ÀS; 5Ö‹eaÞË—Èe-ïŸ@ê¿Ët‘øç3 ù<-Æ4ñü3š² Šù˜IJ˜ Û¡£4tþR}—´úá'†í±³y‰OMêÒÀ\¹sƒ­,ÐÊñUƒ(DÜ‹ÿ;ûèfãhLúÞ½õÝ‹¥O²ÞpîÛ»÷ÆïY±Yœ…ZaS×”s0mâúC–YM¥ëã¢7üëE7ßjŽéÌ$¹Kù!#O›Ókˆñ*<…îŒBà X ËìšËÕIr”CMú¶Ï‰,Eÿ–wY„Ï?t"AWXlÝoµ=¾¼#÷Ìi` 7ù‰ \ÄÛPϜܭ·X*ˆn*–m÷Äì™a#Ò!‘ö^e‚Åjs#í«ù'ß0‘®FÜóÖ@ eî%D#ÉMŸ Äa«êª²[Y¡àE±¼$€vQ»:Dxe« ¤¸v¶ ~׎ÐâÏSG¯ùvÎTÞõ(¢Œ %·=%ãm°ÎV$×#¼ˆ‚|÷™}V;ež«ÃÍzl2ÑæA&GšéhE=î ¼>ý­ñæ"»°iVï=Ÿ;e—Á'[„¥÷32Ë÷×›ÃÂl+‰ìæC‚kðhËà¢ÅuþEᎅeRg#ê>M`.á±zmص¤¹Jö"§Ìb}?_§¦Äü0©XžØØ{(œ´î.&Û¿;6íGZ&$>Ý·_í…Qt÷ÛÔ°wùBU¿Òõ}¿g¼ mÃvêÿä‡ì(† ɶlzå"”ü¦9&Îxhý»‡còp?ùùnp$ÄÍ7Øó*,±)]?™ß"4JÈ}»tžÝdÂߦ»Ì¼7ÅÑI† ^ÉG?;ÖÆQñÐ ~+‰Ó qºÖôEvÑb–§ë5bœ¢¸$"3uK~ï8xÿJ¾](_ÐÊ\˜(|OL4JŸ$ÌFX¡ÒÈ¢~Þãu)˜8ëkîjÞ°`#·Â ”'v—D¯ÿ2دí^)(ò°~Y81$eeà€v«ëc¹œÚ2ïÅ<‹ì¼nC‡{Õ{·¨a,F[œ)ŸÑ÷dúQöõ¨‘o÷ÝQ4¾éÊO÷{®ŠþÙ°X§<ß«l-þ!ÄYíI:Öô®íé¡Wíà; %ö„Þ¼#‡Žº ´¿€N-רL«äkí£7j‹®ÇlΪpWþ&U>éy>Ïç4%Š­J§­Ñ “öœªÄ™íi“²yNj‹Cò0ج6zXã¡»km(Šä{D5ŽO(¶QŒœ×ŽÔ(u ~BHD«V»Zš û@úµ6•,b8¤¨õš%ù&ý”RþH^KŠä?7¾ôâ“„ Œü|er{êá·¸ž7€Ú^…Em)?ÿ‚ Ésüî›°'·ÐŸ¾,‘‡a²*ò} Â@ È]§›H ß>Ò¤<9—2"mqÑilsàÅ=6u¥ŸÃ~_ž 4ñ¨Ûßyh*Yíé’€ˆ äTÊû¾¡Ô"XO&à9:ê\×áÜïÓ³3DxܼéÊ<¸SôùkKÎzéeçXc!õŽ- WÏ·ìß™iƒÇruq²VâoÈ¥ly×çÒ‘¡Äöâ­[šI¨7BˆÇ[9—Å·4˜öᙈFØ9Ná6D Bt”[›_רÞL8kQÑp´FÑ2’înò_Ê…ð¾3:iSR>Ri”&;{¥”Òÿ‚q5K{Ž&–|j2ÆhqöÑŸh‹ìwŽyªÔÞ!ƒSa5=C†G?Fë(ö­ë=ä·½¿–É’ƒpò±ÊâÍ•q³ODà˜dœ‰.Æ5˜’¾Ÿ@G(zÄ-õëC¯‹3?Œ”Igš¶{\ÜûcpsR¯«Ä–ðh‚cæ{Âh<„ÎÍ0}˜W s¤¸!}®¾M¬´Èp—\™§”Ýøßã?,ê ¨5­¨«¡’L`{Ø‹?FÞ&ƒPL $hÁ—o’·"ÜÒr”“K°l©ËËÞî°}iΊÎî+å (—ßE¡0~=ÜÏi©÷©‚Wó;7²ðþ6/*èml \#?ïq¶¡%|¢ÌbA$¦0­õ=èØãÚÛOS8Ø/á}¢Ž9N.õæÓ‘s®AR»Ñ¨º¾Çs5·%H]áV©Ko±f{n¼Þ¹^æëš”?m^§†T:üÞn­ZqèÎt*¶`…Ï žiq¢.¯Jšh7¶Ì¼vušø/r‰vH„“uùyëeìqÇ/+Soå“X\ò^w‹â“·b$¦»Z7ßÁ]}*ÒˆÍZ}µ²yóÌ/ÄÈLs””ÁÖk)Þ7a’GÅ`Š´Çbc‡hþ(Ç”T_å‘“o.í¦zdƼø¹x¯Êª‚48u_;Bõ6X]ñ±¬¯ÖD\°ËÖ/ÝÞY¬%ÑütiéÀP8t]Àެi(qÉ6;¼ÿûéù‚¨æj…‡ZŸQ:æ»jý¼ü%[4WöÉ•„X&sì4kÒ²êè‰ä åš·p¥\Ô¡¨¯;»Šqáó.zWŠ«i"†2··íì‘¢÷JÇÔ0.ö/KË(Çùô­=a:‡§l¥ŸÔ«jxÐ:2¿êÇrÖBˆ Qk#HCW=ÌÕ`òü»h¿³Aleëx{õ®¦Æèõelßfr ¼¾…±6Ö.ç1]ÁôÝíÁ%ìfü qg7xÙ°¯vTºLö&–UŸÝ‰\ŒÒk.ÀÙu\hXZã¢Ût\öPö®—Ì“}E¹YçŽK°­ãûx¬ˆã6'kH”Úûwì[§›’)?÷–ÆBZjm”èîY¶û·Èïl|¥®ê½ÿ•nùá›ÏÝC[ÓF0ORAÖJ i‹ ÅP#„ÀÆuçSlb®Ì¾‡rˆ¾Æ4…”u«C{>äþwÀ[ª]ž,fêrrå„í.‚³ûpŸx?Hê™AˆõWÍzcŸ¹·™ O+—‹–¸» ®<ûu ^ñŽbåvHA·Tý/8› ¨b3›P-Î2Ô~¥‰EH>ÅÍ1Ì,½2GBkàËME’v1¦1¹~Â5Ü„õcr–°­c¥IªY5GyÔúšéhè’×v,†2íë“×±œ¶–Aÿlõ¦=²! Uñ‚ý6Õ|¬‰‹ë”¿1U–ü"s£ (À PSsÛ£åäÏÝ{: P=`ŒéRt ¦]=À2rÙ§wâN1 ¨"íW‚OdïîËþ{´p„ƒTã¦y¥/ñ-ˇhJ¼™M “TBPÒþmtÈQ‡¾«¥é O™WE®G¡ìý¶fƒµ»GRiÜO.«`¸œä¹Ë‰ `÷ ô¦-¥³œ}=SäÕÌ„Køõ¨âJµF‰ÄA«L}wÿ¬^Õ‰ƒð-ÊÁÇŠ¡Ëñ‘£†Ð—‡‚zÓË©š5V²zéÀ²ê`…±êûî.ò ¦%eÈvÚ«£­†‰œ1°¹óå @aüzã±ÁFš¥@XGÀC‰¶2®”Åàaž“9ˆñ'EÃ=׿ôaç—M'ˆ]šD¾3üKºŽÇSGéªÌ•àà"q•RXý–ÚÀh—¿ýº å5çcpzÜspC”ÈaRÞ.4ý} CÖåŠß~î¶½m¡rU¥S¢ £LÚ;Ž½ÎƒHT¦–ò9˜Ï'Ζ“•3ü«–bUÙèú½4ˆÅs‡ˆåG?)êó?hÁÝ]~ñÕÍfy‘ÃðŠß&ÅP¿T¯Ëp¹>:iÅu¼¤ÍóxVskŽó5Á} ×J ¢u 2öd4þtÖ­ÊRÒ°Cµû3¢ê,t½’õ*Vå¢ëú`SýîçÜHï'E,âK.eTwZÖNûT ÄðζETEvóFVVD\'ak†åfÀ#ÉêL#Q7Õ‡~tk°ÖåZ[}ƒóõ°,¬¡Ä?0ì$èW´Ø->SÜéh—]rEäõcb[q¨^Œ„ÏÃùšŠþä< wcÝçyYûㆠc€,é€\ë‚ô üh­7yu¬‘]¥Õö^A^¶4éùÖ€½!¾ÕÌÑöÍ@*u? d¥íªÕ†%ÀA…+гvÅžÃÁåÆ=xôÇÕŽ§ù&Q%˜[á¯0ÚhFª3UFÓ‡+Wá”›ÕÁCKöƒÒÁÑJñr^.Mƒ£…âê^ƒd•Õ}¬Ñ‹N´—•6&Ðʇãî,Då#rM]]æV/ž,Á¬âRåÁÆ‘©{âØ?Î *GéñÛ/Rê?:û…ž'ÃþÌý"“`ÿª–QŠ“Û'”߉ ¨ªyòÏg­ö¦.ÿhs ®¡.ÍøàÞ²âècR8 ú}¬†àŠ­ûĺ}IÊqnJè!H·ÒÆÐ”ƒ€x6JE%˜ºØe8«¸„k޽¼—'4º×ZH/7hrÒïøáñµÊÛgážýFAña1ªµ¬‚Õ.ˆýå­¹#¤­2ùPüsçÁãdE ®¢¥5Ó‡`Ý=õ¥B«¡3‰!gâûšTÙ´\\iZÞSm\O\H¨uw]kû4¤ÕÀÌw ¼â¶^ ‚cB«P<¶ &L¾Ú¥ã½›)õD)ØP¥ÔQ¨ÒÍמ•-ò2J§sVmHbL@ ÂD‚$¦Q_˜CàÊŽK(# œ7,ô‹MU[ð5¦åþw¨KÁ¯‹øEÛ¹U¶$-&™xíŽ{›4kÔã¯+ ˆªÊ\œ¥eqˆ-PÜ*NÂÃ:2Æ;T‹œb½4ŒµÍDíK:žóÍf[Κzùòâ æÞžõþi®¤t‰;x¾©KnÃ%;úªñ»¸Ì ênMMƒq£Ýü©®¨¶»iÉ´L¹DG)y¤:žbôþ}-…‘#ߌ³ÙÝ‹IMøä¸¶8T (¾ßiÍéÕúd aq€1ƒJ <ª¦îI†= Íö!q·n}ÍÄó÷ €Ê|›®Vʬ{§­Rà-Ìv'QÈ6“BG#« 1rùeh[—e•àL­¿:Š‹”5YdTR- úeHû" ¼Z曦Ý1ùÓ<õºB]¸[âí¯nÙ¿7¸V÷ë‘wèN&ì'ÑŸÖ™WÆk¯ÁYáúÎþæ`ÃÑ!þº«qM夻ÆÁ[PšÊ¤ÞìYžj@‘O'q~T̨v¤¸ŠÙ¦†àºJ{/Óî?WÛÔÌÄV"ç/Þ ¹hiv&ƒàjæmœ}Õþ7Pž {g¥ƒFªëüàWZç±è¦*èð5­þºáµ¯K:´nÔð¦òä0› ÔÿlÕƒ@ˆ†öøSãØLd„@7kµÆ¾pÞZ‡”Rt(´<é³ZœJ°ÖÑp+úêr{HP0:ì)hÚ¾§÷“e,8®ìyK¡Oig™»ðFÝ®ý·,kÕ‚6gŽçÇàƒ!ü{•“NÖÂVª´ ;!âϨ²†ª.gj¢Ñ|—ð Þ!Ú~'€a ”2¹P&ÇÕª².Ú*s´tp©=L{B‚J8×»ø3ùÿ Å’AÒVgðâ7x£{i®¬Íµ‹ø¿•TãS$­ñf0 äLi’!4ç†ÄŒ¨q$µŽÍwE=©±ÑÂ[ oNtšßÛg²UGïoÍVöEË>‚áçÖa­ä¹Xïo|C—áÖ÷I'Y “>yað™®ÕžÙ‘dúªWõ¸1…°bEA+”aÔQÑ0nH¨o=‚æîzTô4(_À%°×¡Òìoueydo#Ç5U:”ô+£{±/•»ô”t« ªqG'Ö«µÀEOìeìÝΘ³àI7[À°Ô×P@P⯦õÇÀ欯<ÓæÛfÉêåæD¶ÆkâÚcq}Í„¸ê2ºswwqÝb1@/ª¹†al‚¿ä’N¬ i7ØG"6’; ÆOHâõ±O%tÅÒÃŽ˜?-ÐĖ٠ѽŠf3 ™åÒH¢B)5Ù+ÜÉܵÁ†JêcÊÆýP» ʼn=ÛÝ5y‰w’˜kÈîR«KÇõoFÉ¢§Q¡(Ÿg»ÂÌ`W¡–i'KBÛvÿ¶ø£U.6Zɹ-Kå„EØÁtKí· 2´êé@£»³=¶‘™ú¶‚ÈQ&¾Ú>§Ù¬ÝGA–O³Ì^ŠäýìNٲܢHgn­ \¯‹^*c…ãIc—äNb¡Md\±­ZŸÇ³ªÉHˆÛí4l®’”‰à=>{XtYK4Gń̵21šŽsí¿pÛ¹š(Ôs¦vå»|FÚ!D‹'\Ú¢jã'îø:NrôÚe,³æ6f÷°³·Þæ‡\úRœª†M6ë^K­íÌË0:…ä%<ƒæTðÚòãÕ Rò£@•q¸aœz^~Ep‹G|uäɈ*m“L´ïÞA išã†ÚˆŠ<£:2‡Ün‡®BÜœ˜§µÊºº»›M§ðÛØÙ‹jK Ûméò`BRJ”Úî/ImåùB<û¦B÷Ì¢T øÜ’è§–?–ùxþecŸãU4õ†ô­€>¡UòDX{^Ö 6«N¬ÍSØ3˜{¾0Xùbg²³;0I{Ÿ¤›?å‡Ç^£²À*Ò¿ê §ÿÊv+µ¼–ʨ[ßT—ó}KÞ²øwM2–Ôp¬*dœ~CŸÑ_Zìd#š¿#erûÿ8‚ V é Uì g¶”SïRõÁ! ×0| @ô“œÕlr±•'Œ%ž‡‡,ãPµ1wó/œ â?!ÚÆxxö¤kxþï2³KV¾ã0TálC½ñ¶'š]ÎñK&E\ä´Em<ßFŸÉ uÞÈ!9—Y¢ìé²ÁòÌí’oS$‹­þ¬Ïw4dX_Ïo× [L]¹&UøÊ m{"â¡»ÜÂÈQb, 21kEš|ioÿ¹¯°Fž°ä‰È㳺³“¯ͳͮåÚòwjsÁ˜þ™)þGÆÛwoì#³´b·Qh'è9Mχò¦á¨mã¥KRùpÉ5—¾Ȥ 7²ÎÃd¯‡Â6FØEq€k\F7Õd|¿™¬` {¸¹.ªïBä¦úGº"…ò=¼øº´SEVâ®âL(\¹|OÍÑÉ7/C€ëšŸuG ÒWƵê5‡ÿäÞ+ãX³ 3íÄô¤ù8ïÔ?Ìi…mÝ|Û1Õµ*p‘Üzñ½ÜÎ ¸GðXú©eµ‚Ýf¶’–,p„ OÂÀ CÝÆíÊ<Ì”?Ûœñ”þä ~^æT«€ñ¸¸Å=²ÈÙO×G¨<Nßÿ_Üf 2›Î£ÎK}_·ïFÒÙ@BòrµE÷pÙ¥¢ïÆ,€ÐÙýtŸÈý¨8ò—gîŠbÌà3ÅèËD ^_âˆSÔ%›Îš/ÏòášN9“{ÃJ6æóx À^úü &`ôƒvØ\š oç± Wxš>j½˜tD‘ù7Æ~ æ‰~eO*ÐÃyCd$À¹Ù ‚ÍIg­Fm+zµO¯cóDJÆ>a(F1#ðºˆfÍñ«mÚ’2~5%ÈøÊ­6öŽJ†?ÊP¿˜;qŽD({è°uZñÖüø“ÑÙÆ%Æ Ü¿Z9xQ¿œ²™<e邏4‰ªp4 úâ2‡ÂOøA® ²»Ó›Þé®-—ߪ͟¦H=\ŠîÕvÊÝUE$4ËE9ðúAXÇàx– ¡ ”5q±‰³£;.\Sʼn^gFýxmÕÆxI\Ɇ§3ú¬Ž~IÔgÉ_ñ ­r¸ª§>‚Ù±~|t辶Ð$Oê'ÒWlè)>e¶}Ìb+ÇöuãÈ<ï¾k7(úαäÖ}Çß—Ÿ²0TŠmÒ,æg½ âÌŒp+ó’nˆ—%O²ÌxŒDó£ì=å´cTÞIáê-‡ÂøÕfc 8µúàe€ˆÄµä£gzKš5¬"SÐ_(®VA¡%¢y~òàའ7õîk„2.è=3¸`ñÎfªg­»q²G"NÔZŒæ@Ò~qŠp”yåõ¾T†Ðñ°ssôOa4£­-1häIçŒ^YVÕX3b…«Á‰ô;äU Z}¥Jý?‚ÕÀ£UÓ¼–Þ¿@eï­Ê›`1mž¶ù…°S²Ð$!yY„®œõd@L˜Âè'"o'ò±h9YiɉðzP­]0´ªÇjóÒóœ”)œ„ØjªÆ„•mLl’ ja5’l§óV,ŸÑb;;¾ÖT±ßÐ(n'JâKƒ_òóôþ’ иQ:ûÂÐÌ4zаjæQ¨_ðoµ5Ú%êk­¹À9$½Æ˜ Â8Ú8WÕÜÁñOOȱ£ùã˜ù‚ÅD@¼A¢¿ ¿Ìóì‹2™rÍLßúÝI`¹„?ÂúxÕÀù÷‚³&»Ëé°‹Ts0}-hÕÁà4¼‡ÅÑÑØ©áïÞ,Ëýß ÙLŽ4š™4jÆÄúœIȵ¯vÍÒòŸÑâ úA"hD2rñµ˜ŸjGh%ådçM°¹¾JäñW]ÑÊ'ûO!R>¬hocFuáYªx@S-)ñÌî3„Ì&ÈÅKb†Ë‘ýûÅn °9~EîÒ ½Üÿu5 ÷“q·‰mµyq ,á¤óe‹•"OÞ,yÁjäËvx.áñ[-¾6W\w„Jê!A,Gms`XÃÉ+¾„ÿ\Y³sK UOún/DEî7‘/A¿FDíZ³ðÊo×8G¸4ëkÚWZ—å©Gâ¦ÓØ µtJLnìœ[Û_Çzî/s­dTÓ…ì†[ó`øÃÞ¯ÿÌ6”'ÚG|€oy~‰ÁÆ <VÃQ©_Â1=‹œ²ñûðUÿ³¦d²´^c«Užà7ÇV7rÄiŒÿv\8Ü0ˆx53 .¸D;úš—öñC‚ßI¼)ºxT—ÊlyêõGï(¸"Ö@—¢õJOÖ÷ú31ê° ¹Ìi©¢€_…&_üÍ#ó~"–P;b8ñ¡&ЛśˆÔÐ_Ë5lü±ØÌ9¡B”÷TâòžÍõB™ø ÌUó‡½àÇê4 Nÿ]}ðE° ùßHÞˆ×6#sgù¡îýgˆÓ.…]ï C»±|hRÔ/’ªŸ3™BÿÊg´Yáå5.“þµ[}m?GìÑ/`¡̨?ºJ€ù·1¬…/H&~§>èÁ»c8ßRœ»i£|Žâ÷L¶•âóJX”ïDzi›%O6ÎP0o¯0­#«º®!½06{4¤¯ù4מ¼…È£˜¤3Ee½yß%)Ë_¾È˜‡€.€ÌÌŠhʵ"u÷(„<¾ê{ñ!ƒ¦Õå\+ÿ0CiR–ÎØ·0¸Jst¥ŸS0âŒY­Ÿ@ˆõÉŸ>z‹­U$´¶¶~ÏuWÞ–{ö‚©@r/ÐÊ9ç ã®vS|cZAÈ%tAzPmCé=)­—7Ãgÿ¡Ž×§ïÃ8@,…;š©s±€€¦c5ByÖ)Ýr¢¦P.Ë/é©™…o¶Z[A×-Ê—:2eúUÛM]k&çñ’Ü¿‘ß¡tëûkœ8%®#£æ²(¤µZ,%ô $ z0Ðjð³ìl.-DÓ§÷!a?mï%˜(®]×|ae¶Æ0&¶Õº² £Q×Ñ/šôå+û¬áEâ¨aºY[.™\Š/?>&ç XÜ¥]m£Ë¤ãMq‡T&tr‡`Ž!“)EÈ pçѼü ·¸JIã3y‡5à'å t]È7D‡J òœ˜eƒÊh$€¿„ÁU\0O8À±(2"©{J3":òt]ÆÂµ¡Œ´ oǽs9¡.ªeŒ®çcrŸ6¯ò}YØ „Ñ@éè}ö˜ÀÜò‘‰2y+¦M‰âÅ«W…q/8§pÿîMZŽÍPkh{aÙ1y&tüžÙòÕMoó¬²<ñ/ÇÖa?ˆüʯu݇Ójû–,¨Üå@/GwŸMa-èGkD}¤ð©ƒƒŸfZbYÑ‹l‰t/ ±Øj¦èôRŸ”hCå1âÆñ±S@ÖòÁ~e} kÎ º]Ýd^T‹’´WÀç®<ƒ²±›ÐK¥ÑÀiT̘‡ˆw!u@Âp2„÷AÒf޵ò„ÜtFIZ^iÿ—à£ùÖ5ÐsDiërÿ$›Ø0b6Ëü~xŽÏ·._Ï–Òõ…Ür²`wYù;›ç¤²å»äˆ‡E3óùž²ëšvÇ»Ó'Ÿãµ~?— •Fh{‰tëß– Úö >NÀ^²‹Jà-Û[æb3ÂàÉ'é[fÚcBl¹†H(y’;=9ÿ—¥¸Iód¯ökˆ‰'R6"œdÞqît¿œý,‘Žß¢]MöV>»Ñ@Þw†M0®èçã^F`çFÕ²æL((¬±’S¢ÅïÂy§púÓ­Ë’5›íy1‘pÆ{”uxëÈOþ…Ž'¾7+Öº!íƒ c´Žè ~E€×þO¢‹aöb]Á3LQ`ÉB徿Ýh ¸xdce 7¼#ª,C!A¢¿F&Uì ÍÎ à=¡¤Òôõ"+Øèµ7¼¹zÕ½¤ ¹}D²6 ù?×bÍáCfúþVžä¬oJË™ÿ€ø›-ŸEÚÃ4Æulò¿ËûYO˜R•´²vTNè~õúÁÎóg/âïžÇ¿¢-;g”Õ,W¤MܶÞ|JÍ€çØ¼ÔKýF¾)—$N\&§^» ¥C1sà ÓTÆÄåò¿2,õºU'ë\Ï鬘ÒíÄ;?áó^²ÒÙ-|¼ˆÉ$˜L\|¡Ý¿õzŒ”%aí=xÏ9Ú®‚Z†7¼ã(Ìå±"ªÅ/t^ aå³KÁ;ï"7Åßn.E%gì¢i@ß@¹Ÿ†˜¿´:¿)[ÒÐ…¥ Ê.Ç3âu?C¸¹‚ä)tOsÒóŒÊJºþy>±Vq/Ǔۅ9‚[Š$q·QI‚f¯<£>@²2Ô>[ì ïe©,ÝŠßiÝÅh'Ü|Iª$’¡Ù+šûcIäE”tÒiÒt6›ä¸ßE3;Ý´6Õ¯qIk›®Í#®Z<ª:ÄÞé× Jâ`d¬*»ö¬(a+‘Zê mºf'hß®gú[ŠœÓÖ—kÑÅÞxñ`1ã×–7÷`´å£ò<Ë ôcƒ´$(Œ­‹c.æ”=…AfÐX£ª—.~qîôÛ³‡A8zi5ëµkµ‰RvŽÜ%Þ¯ ¼×s—4_ ˆ;<µ$â!wÉužÇÆ&ʼfDÚõŒü²”ªÚfK>¶°ÐPVoN’"Öõá‘§•6{ ,"›W&ð°Æ§´û&RTaÈc\} Åta°Àj)›HèÔyÓW,ªZ{E¯žOµpk.]3?5Ík]¬‚‡Aål³¤!Bd+Š‚y–׬NÃD4¶2мyÒå㙘ÓóXŸLI9Åã0ƈˆÂŒCè–¤;ÇÖvœù½?vîûÆ[_àçºÞ"¬<¸ù‚Ç86<ä\µfòjq;íâé ‚ÂPåC}BùâêUÀÒµN£5«Èm]¯ëô«–’´òÚPËuÁ|Ý‚Õh® ¬Pt„xq_ÈEìNºUK‹¡ïä FåTùk“.¾± ¾KiÙ T‹OÝî-ØEÄâzÂ@§$€¹c€ïÊxЫ/î§6‰Ìp@ÿÆVbc¡ô‚RMgµeaFb½Ç1­V&CÍ¡ˆ_©Š>¼/Âå†y1ó•›ßcºØ„=Kûÿªß2Å=±R"oŒ‡!3'öƒCxHœÈe ¬ñfÞ÷ÕÍÀ(î¥u<¯ZóƒZ\ë…Sb Mêi «úå•è(7g-üs%å³lßÐ1:O,'ˆ¡cT™Z®²Gö™&>ã0ãC4”ayösS°x–ÍýUâ )š š$Ö<Ò:¤¿ ·FDQ+ÓB$sh×äî úÈãó,ºG5Ô Ê¿†`Íþ}”út³ÃWc^NÜÅáá0 î*ßk)}“#­¸ämnKJ´ÝÄNEƒ¨ó vS5ú äÇ/²±^b7i’›tº(>ŸHM‡ ßìæüä‘Åû$ƒW[¦s#8#!Àç8zË2“Õ©úâLÖkÚ¸@ÒK,E Mƒò’\’ýŸn.ÀÀµµ€žÇ/’eîI­ aá³âNÃÛ|¼ç…ö]%ʧ/Y2™·÷›Œ¤(j°ß¨º>*ÊÀ=â;uÌçÒ~y»mAu¯zØÂ[£–#™ÇŸ¹úlŽ@ÛÞÃõìéxâcÝ–<¼t"©âO¶ö¦IJ&%d]*h%U†U¾â¯Üª&îB SÔgÈC\S·âFÿƒ‚T£kZ[8<,”8þÓª ƒ`ž¾¶‰¦R;Ÿö˜b½d>•Ð-l†›¯ô.âá,Ä[k¡–C žnk¾pî5RÝ=\>åÞå^ƒbHê4ýÍ秉3'®¼K2AÀä:6Q?Ý}SÏ„ú1r>kf«d'}Ä#˜]žÇÅ>âàÆŠ~·üòÏe¥nxªfZÑÂoX§OÌsmrT¾SVš=ï{A·£7*ÖsÂpqA•íiÜÒÑŒG¶4n$uÿÇRNåv šºÿ®Ä*ªh]^ü¢¦t*OT²R6¶žÓ@9L‚¿ñ’—>aÒëù6j–f£ƒ·ª;˜ƒ%ù«¡‡¸ á)‚ÇÌ McÓÝø¦nÞPþCÚÃÃWzÔïQ“i$¯Ü¼A¡ סÉÅ<5æi²$ë0>Ô; ]/G#ò+V²RPk•©IY¸Hªp³U¶qîþv»9¿ª×š¸³n¹OV«Q­ã‘%ËM¨…µsßUUKm–ŠLäÅü‘q£—Ò¬+ U_zÅ,ælöõkI’aM¢>ÃÓ9DH’+_qMˆý :åÃ+;þ £iB‰ÛƒŠ¬¯ý¯¢b_eʲä—ÔGT™uþÃ:þiNVÓp´¦[¯±MëëÏÉúÕnÃ(óBm8¼³aIê±EHÑÒ òÖ‘º^}ÈIlGÄ›rõDϼZÄtŒýR×G)•¸±‰9¦hÝýF2uËçîê½: êxÁ'2jU“ÕXíÄÑLÏ}øÏmMŒ°rþÑdÖ.‚Ù°Ï[dÜ€†q$û…­.M,þü0Ê(ÃС=ÏM¸}(C÷œÈµ¡S‚Ùþ |bD¡K¿6AåDŒ{u—&pøñXg¾ð¡Ñi}Û!q[œ…IÝFåb¦èOÊþ9͸Àpæ÷Z¶º¦Î¬„Ãþ~Þ¦?a•¢'žœ![aö¡³jÜPfqíö­±pê%Âúwôô¶œÅ rUÍÆì,5¢S{ׯÌ/Tª’Õ |BCÕÉŒÕ^(úM;ÿÀCÜÎk¿êseD  drâ^Ú(FsêVí3ŸÖ(N‚¤pôlELáªPE/*!pÅëÍ"F<¤€Éˆ“üY#ˆÙß§:w—¼ªÖn’DQ-¶¡Uvæëö w§s ®ˆc!º‰_³üð)Ï"[ìZw:ápWV_À® ;tOTqº5¾îWÐ_%ï+;n6»Y虼:D‹±'Ú FPÂÛ>ÀBù_?<®J:Õ•Id;0‚¬!–ì¤ãàÒr-cÞ{d ò<òÊ Aò{ ›0c\%§¥p9鯪ŸÅ8 û;®(`ádAN†yæ¯ð*‡0!»ƒZàâãíue¼è~xÑr„ô(؉Œ*õ¦äËy“€8MˆÑ$ætÇÓ¢ô#šÂ¬ðe »øÎâ%Õ {‚§ÝïFùXœ€ãÙ¸ð›Óò¯QF‹r‘V¾{yËó‰ZMúg &ôóî.ÕÞÎMM¨×¾ Ëz+¹=×;–L]-Ùó¤Òyìî²<gFľ7t+½iiÙ€gnÿTäWòb•ü<ÆÏ¶»F«£j SYžÅƒÀ 8±c©Hî™ 90ª×ä4°œ²R°˜é]_­‡äqEp¨œU&ÉØò<¡/=~øXâtšÙVû¦×Óó_dŠ6Ô÷nHD6t"ßkX(Ö¡ß{žÓ¸Œ2™©UªÇd_ø¡ï@u) xW0AŸR~Kô×HS5RêùãIõ&!²ã‡µò8½ì'VJÖ$Ô7Qʃ™‹3™¢•ÐòOÃj³Üô:M5¢{- æú°Q¤ äÃ{4¬ Þý0ÙxE™ZB°ŠT²±sÜÂr~¹ß, ëÃBìÒÿOdîíÕšZX(p)в(*"™ùùp­,B•²ÃÏ#+º¨°,» [Ò#¥*„»?ÇqתÞ÷Øå…7ó¶P¥w°£&„›ÂB ¨—ÙNU.$ïT¨¶«#¬0~V;Íâîc²QíGx“²' NAÜãÍÉdÄ\ v_ŒÆCÂ*ô®pþà4Î ª ß™`Çͤñ紪ݤ؜óó†ËÀu#¶N€€Ü:D¬c£ÆÊLääF3 …“|a¡H|S,³[w€Žo&ŸSL#ì%üVþw•]ú5…p*3[Ò„ùÕ˜#qŸ*ߊºîéQ7zp w-J¯§óS±–üÉ«_¢¸Äš’8+›"] e¶˜G‚噘1/Nã`#ì= ÊGö)D¥ Å h·ÒÂ,ÑÅÛÁLÎ0­ŒÕy­t†#¯ÚZ…|团ôÛ~«Æ fM²JŸKŸÁNÿ6 ì©ìÞ¾bT KÈŸ]¹ÞÜ„Y)ÚwÒ?[4ò©Ió¦>G)žJ&d}ýíÜŒÅÓò~Ø0 $´N냿´Èc®pVqí+ëCppG¾ùˆóßeõœõœ6GÌ,öfú8z”Ô7»S[¢S50c­›Ôq/”_9¹jó¿·Ü%×­tQS…“ßîLðbkÂÒxâe¤í3SðXG¸T¤J@ð«H´+†ÆW™íç´upèó`•I]± >W*ìÕ´$FZlEfg sôë¥*|zº7>ù!žI©Åÿ«; ¸ao Á¥e5MB+ Mø¡FËB6ð|fíbî š}ÍÌ­š^§A¾’•Ëâ¦}VnŽØ†ô.¹¼j*À¥-;Ù&ú)Ñó‰A¡Z7*8é±51Ÿ{‡Ïo:g7Ï.Lå7û.éñ²¯ƒE‘c‰Ð‹}tIÙØ*I ø¤¾ ñOWËíÅ'as\Ølð\ÍL¡6þÒF)pm­Ø,€•º·¢ÀPæá¸EW0d¤q]&ÿdV6ß.cùÂ~L´óðCß(¨îMëb#òEnÑ»PÅV½!Àȑѵ Ç jFÇé¨J$ǵÀcu?„4·[ö&å‡:1“&OÓö(øyD~EÜžù·ÐSF¢–ç=RËÉd£YÐûfG¸¤Í§³‹À;\ŸÝuJï,J„?‡NÞ"¥‹ñ±{ÀôÎ%µ øvN1ëÈôDü•÷Lݶ§ÖwŸ£º7ý:Íî•+†•ô$)Dx U¯"q ï×û4úS+a:ÇÞK ÿ÷QöŒ*y ç–5!ýÃ< ïþ¨è|ƒý‹6\ U+ᬮ[®eVéüvíÜ{ÈL+]¬)–ùxþecŸä溰ÿoö“?,‡Ä›X‘:¯Oò9T:1G4qÞ.ÌtÉÑ‚‚ëEæ‡áHԟ׋¬¡ª nÍPÑU7/˜ÄñcªXâ§nc]¾¨XŒPœ‹ayÚGºxª.wÈç¤}¬ÓÏÇž\r—f`¤„ñ@zJnî´a'¾¨s‡Š­NŸÔAëG½PLˆ6ºIQkí úº+äÿ¥ ÒKëÈíTžDø.yžÕ¿}‡ÀÄœiÃõ„äóä1íJ$ŽðdÍ=² óv–¡t5!(«:Ö+Ovl<¦ih^ý þj,QüYº‘îîÞâÄ?a塺Á7ÝëÜÇbÖ¼GÈ P˜MåoÑéïToãw¿dyçëÀã·œó6ês\Ô…‹R;ÕXÚ»ûÿõåöÁ¡\Ðs·~=ðÈTDŽÝCCijÚ`¹ÎŸÔ¬\·‹ðñ™_“ÿü§™¯$Âõ9j®Û¢_]L“ù’¦8áÌæh²»BJÖÛn¼ûXÏjY—”8Ò6騋í©YóZtÛt´Ìn„íUè¨PGØÊzAý+ÚT¦M1¥e¬åx£4AŠ\ˆÚ‡2;¡W³Rø}×!ÔÉ0àehyXÍbKÏÔlwæ l_%L;8ê8jßQüg-í× X¬ŒA•JòdÔ×Ã~Pl¥+4øð7ç©0òhذáÐQ@s<ëÍÚ¶}Z‹P€åñ µ˜‚Èc×?ׇÎXªN{Ò¾oçÀù;ËÙÍ@ê[våÊ)÷3šuEzØì>BÔ?t_Ñ ¼9™G´H|®Ö²ñjóèOHgäì,Û[$¤BCæ °õJ³öëOP_GçUV'žuƒÇÙ/{#KÑé¹™˜qÈ~|Hë8àäpz2Þ8«H8*M‰œû’wÇÞºå Eª”pÇ !}¡1{¹Œ_ZšlÈë¡ÁŠ;u§·+ú,fo ä-AÏ[HM¥×ÌÝåìtò*9¼Â^’щ§a–‹Û`B>/Cö0Þ÷ðišNË­þÊ âÄCHŽ´–/9fV.ŠÎÉó”6!œvóÑ@ƒ ðÉ!w±y;¯m$i¾äµH+·]YA|åÀD!j{‘øEÙ×ZQ5»¶'vgêæ¿ux”y–#Ú^Ž´¹Q« 1ªAä˜ØÿPâ'4R‰ÅU]¥‡xý'¬¡Â>¹æ’îtê€3Yêy.·¬4ÖçæÍÕO“߀®†×ñh’¶˜ap(AXž|§©Î±¿[‚ÎP§k vá}¬WŒ(átù?þB¾æ ÓÜõ'åqMä±ýE½ŽQéæ.Eö“g¤«¾V _‹ ”hÅ:DB¼ªO^ÛðÍÌkUü°õÒ| ¬u ýÅxTõtWw!BQE–NZ˜ª9Pvíîs³¹AÅ$vÉ®?·-~¡ò:ŠL34ú±ì0=§§ PøCV9´IØ{ã=Ž·ÓB´K yѲTp»~Ëp çévÛD5í¬ð2Ia‹¡EÛfåÀŽ„îŽ9’-v‹òIÇëmÄ»R vDo’ÌÎÏ÷ëí8t7}²³U@èpܸEHÕŽý[ï´’´ÈÎx·¬®#7 >æ &2Þ÷VõŸœ6ÊnæÀ­NÖÚþÿñú°‚Û…6[þŒõTo¾¤tœ®ã¥VøŽ![ ²]w¼­ ?r$T]µÖn°ïìÄ9?Æ´OõQÚOçU­§Y34WóíoxÊ2î½JÂ@Þ ·–݇_ýÚÎOeüõKŠÂåýÒÕ¶~~Y‡ö’*Ó}+«r†l¥‚z«° :¬Î­>2yá®GmÀúÀ„ ¿”À)Ûäý±,ƒ¬RŽ~––• ¿9e(Œ tÍà3ÎWZŸ«IDÊ$hDpãëYGÃÑÂÆ*ëq¾þîæÔn7T¾ÅQAT—FZ³+žÔu\7`äpß$ûòðSdSÅKôB™Ke$<Ìßšfœ¼”“p‚騸ag#au.ÁÄè6Ý ˆ?áÌcQùí!;äùãÀdõôèiÔõà !S½øIAúiù7ÞÃ]×K¸¾1|bi”e¦9»:…2)\)1§ã¨š†46?g¨Zgš›r¨'â 6'BT̰?©Õ_ÉD[2-8?± %_í/ê¾1%Þ2÷ÃÉ;ÌÆä`¢Q ÇI ý´‰#Ç€µFB P ˆÒõUwŽYdù>-µeˆ‘ÌÄ@Îå³uãšß€ý^T®®ÿÅN ôÅ&Å\lð6Ý\PPÔâfÎåzg˜Ú>B¯Áà!‹/P>8Ýí#PëV¡׫»‚K˜éù×DÜÛ›ñ#¶Š_ÊBQÂîZlJh ª„—mOþ'Ò5ↇ{°1”W(ø® —= æ¤&ïZ³NtÉÁ÷œ±á#Š»2©Da=B(œõxing‘:öÄžö5¡Ãջͯª—=¦èa:ô+j9…Q=\]<·ÂÑÞX, ÌÊU àbïIE8Ò¾ž*}»Rr–º.uR“H#ì&ƒR= —Cð¡z¡µ[“u°êßÄùŽßë"¹Ü,—YN~_U'o[g¦´ÏKÕWSÎ’5³ðL51œ¥ýÂ7Ùðy¶wúCÛúKŽ:XãC —$z…¾ýØàÒ²Rªí{Ì=.Õ줪Kš"²ñÞ^Ð <å½G í¯è”;0yøq Æ—¶ ¸Ðb9ð}ªÌc…ë rŸGµÔfôCçU棖0e²ø1MÛŸƒáï ³¿igÂêFõ/™¤‹yˆËåÝ~¶‰]\š<š^”‚ëÁ¬‚úC¯ŠI¿(T¼U<´ÆÐy¡•ãjÖ>V»HYeÛ+3¯‚áLã^Š_‹]c–vR –‰ãÒ‘ ÔòlÞÿ{!‘}²æ¯5âeœ8rÿNç&°³:|®Ûr·”½¹>U»Ýáaªp/÷SÔ$ µ´o>rP$Çî²UoicÕÃÏßëYéŒò“e»ê‡}ޱÈi1ñ24¦O­.Å>“ú¦µ9é%I9ÄùZX<‚QË  €on- šE3–?­-ƒbmïO!͘ØP;o3:]©u’¶eõ:#ß\ßh±_`ÊDLYF»"úQýHÍWÙ¯° H3'–¬í@·Ø£ƒ9©W²\hAºª{FñÁQ¹›57ò)°k½« ú^Ÿõ#°§Ç‰Õ:èM¥|åH0)ÜÍd8& 7tɘÕFÛ@ä¸QÆÜuX¦q>ÏÏ…ì«Yš}W ZÇ ™(9ö£¨ü|Z*íØÃôzK£âißh°oÛ²¾åH¨ÉH6í-/>N©Ç=û¸`0-hxõ“²–-#¹ßBWN¾ÁðÚ‘Þ±ŠŠ/úĉz¨~IÓ{‰nÅ]ê4õuµSظ~xª´£ÿÑ¡‰Ú5–:‡I âšÑRSÎ CKÐÙÖXâ ¨¤çi!c‹z2v#É+×XÌá°§×þlÿˆÁ+’b*¡ç#½@8(E$IÍÀ8 8ï=­ _|( 6,vzTïÊé›2yabÎ3Þ¯<å»XˉÅh¥â­ž¸gÔØÝœD'Cí Ž2å¿Üv3 ¿Úé÷71á¶9*Ìã<Ú£Òÿ|Ì`9¢A„;’£4ô­™irÄ|œa¹[^1–pÔ¥ž :¸[쇋q€šu ÉšâÄÆQ—4“aUžðáß¡O5WlInò]ãj|XÏ]ƒ/77Š%‘¶‘gç׊pJ¿”€î‘º§:AÜ«6!4ÿ¥ t#9ªÍÃßlç/mÛ ‚m§¥'Ìú­ÅŠU«(9Ý̯‰;­ ›AI¦€V†m¡Rµ[æÃVG Š#Ëè¾ÂŠÛWoa±ÜW)šõ¿uÎûñó`á…}íÕç_Àq4;•Àrc˜ë£b‘‰âÈ4­#S1ÃÃÐpb¹w(88Ëò²®8 6]H§]‘_êPèµ¼=Úñæa7Â$[±bøå‘Vÿ¶¼½D¾³• f©Ø&æÇœ+Ëx¾««±b ”:h„«”¡ ¦/†Xžæ…¸Êó%p W—ÔñÄi¶ ¯ç6Ð|œ¬4J•æ<Øk: a-Ä*TBÖ‘Óœ‡Èà›K½ûuÍ(¢vÓ} ‡(Åñw'Ö2¡ ßËuy“²"vý\rIi°•sà6Z>ˆÿäY©•»ÌÞÆ¶Â†ôYÃ*œ1¾@¥m¬Êüݧ(m©¼§N£#·(?Ö‚9Åö¦CmÍ‘¨ÔFÈŸBÆ~ÿ£]ÞNšmÊ_é‹Rå¸CÁO\Íúü¸?óFIMYY>Klð¾rø3NiéÙ ;¾Å™œúÕ@7™T•ÂN ‹qØL 0?ðè)L ¦1†¦µ½n0V¯Ò¬®ykKH“fö›ŽŸ‹{“UËŒÌNf`Þw –ÄÝ \>ÀvºƒF3@J«ÌíÝ}Ǩ?ŸG¬§Ïä$¬g#Àû„èþ_À}}Qm\«ÞävK©37 ‚Û Š\ñΰ™ˆ«< _GˆÓy,gËÖùá§îª/šÏtBÛu6T¶¦kq¯“;•ÇÑ5Õž?gEpÙ­Z^vf—Ü( ý'’åáÐ3×Jª½k‡É–óbïXšú›#Gºî’— 8?‹l8K?Çêë½Ç¦ó¹…=wƒ4rTÜùÌèͦBØæÖ¬’$ë†,É®÷X†±°íy|)3¿%žª¬g[׳h NÖ ûkGd«Á¯6:íO€—¦ì@Ƈ§y//–ç+*뤕×Eë)†_ö™OT?WKY/õ”@öö¸áÖ@e––wÎûså"Öm׉Ǹʲ:$·¥Vðr¥ ;{»ÿöTS($O w¾å¿“û¾ÞnwF¡‚¥Yíªƒ±›œ¹Ï[âïS‡rŒÔäKuò·½nˆð]gÂ'Lû\ûäíˆÊâNØDì65÷›SÎiž¥ÂJ¶+¼—˜[¸f4À:, 'í»ï{õ‚hóÉ|NíÕg Y„gŽVB+’°ÏÅFRTxàlòçHâ–q²¶ G»Ðé÷r)?UAÍ.FºR‹iSmÓ˜ó'‡%¦`]Ÿ4k§@DWtßõ7…ªHÉ+©åÊÖö¬F “Ÿ…÷òqüÊŠñ{~•¯,M$|F>õÇ™´©ÝÉw»Âœ ŽDÅÇZ©nÍ#¼¹0—o£0 ”³º¿ Ä3¼ß~Ð 8íÚó,¬†~IŽg×ÛˆBû²Ï:Ì“E$gåbý/r ”)Ûþ½%ý7ÑÚJ-ðê£Ìm… c/¾Fž½[CÑÒ‚ýtjµúÔdü!mqóö,”_Ñ¢c2œ¡?Œöjj¶Eû§¿€¾½­j×2¦ãHúpo9·£|}gÌÚñW1ªçà jQá>Õ}Yýƒd:ñ_öà¸@Œ‰ F)Ä ¸øbPJX0ð_ãûê endstream endobj 24 0 obj 100460 endobj 25 0 obj <
> endobj 26 0 obj <> stream xœ]ÖÍnÛ8ཟBËvQXïO HY²˜é iÀ±™Ô@#гÈÛW‡GÎt‘øˆ’®>R4éuw¿¿Ï·õ?ÓåøoÕÓy¼¿ÞòËýøtÙnWë/ó¹×Ûô^}ˆ§Ëcþ¸ZžNy:ÏÕ‡oÝÃ|üðv½þÈ/y¼Uõj·«Nùi®ó×áú÷á%¯Ë]ŸîOóéóíýÓ|Ëï ¾¾_sՖ㆔ãå”_¯‡cžãs^mëzWm‡a·ÊãésM]óžÇ§ã÷ôڶ¸¶®c½›sSòü1ç–¹EÌY˜Y™Ù˜ ÙçÜÖÍùŽíwÈæÒ™#rbNÈs‡¼§mܳ½G˜çnýþ@€?Ðàôøýþ@€?ÐàÎìÈôøýþ@€?Ðàôøýþ@€?Ðàú~¡_àú~¡_àú~¡_àú~¡_àú~¡_àú~¡_àú~¡_àú~¡_àWú~¥_áWú~¥_áWú~¥_áWú~¥_áWú~¥_áWú~¥_áWú~¥_áWú~¥_á·šsõ~ƒßè7ø~ƒßè7ø~ƒßè7ø~ƒßè·RŸ~ƒßè7ø~ƒßè7ø~ƒßè7ø~ƒß9þŽñwú~§ßáwú~§ßáwú~§ßáwú~§ßáwú~§ßáwú~§ßáwú~§ßátF8#ÎHg„3ÂÙ¶ l‘Îù+Ú²rÉæÿ Y,h6¥;ÑÈDt8. Pi|ñ€Fv ¢±+íåK÷ÌèdD†TôÀŒg¥†u€NmÉ-^F ̸>-AÍÄNèÄ…²,²éŽuð¬´aÆ`¥Å‰ALt&8eÁM‹³<—“#artË„F{ÇN‡® tÛáÞ®Lˆvqè”ípvÆv¼øÎ™Kû2ž¥=²æn±•ö=Ûaîzf˜»õ1þûå‹OOgñôË$@;<«) bÏwW<}ynS—~y.®X§G¡ô¥)›Á°ÔÁõë ¨3,uðîÖÙÿdØ@±ÃÿÚ˜«ãÛ4Í›rùPvcìÃç1ÿûKáz¹â®ò÷pר endstream endobj 27 0 obj <
> endobj 28 0 obj <> stream xœœ¸steo—5ÛvNlÛ¶mçĶÍJŬضíŠm£’ŠmT’[¿·ûí¾ýõwÿ¹ãŒqö~æ\ÏÜkÍ=÷c e5sGS ¤£ƒ #3/@ÑÚÞÔÝUÍÄAžAhéø rÂQP¨[»Ùÿ G¡ tqµvtàýw˜ ÐÄí/ nâö·\ÝÊ ân °XØyÙ8x9¸¬ÌÌ\ÿ.ttáX¸8šÂQˆ9:y»X[Z¹ñþë@­¡ªECGGÿß ÀÔûß @èjmé üQ £“=ÐÁ ö¶³³6XÚy;Y¹LÌÍæÿhhšØm’ÖvÖNNŽj1šÿ©ò·Q†¿_p) ÐåïHÿÚøY’Ž.–ÀÍÂÌÅÊ ¶rssâeb²øKYüC1ºZ0:ݘþjRH8˜‹9ÚÿÓ+Ü?›Å­]€f‡÷fú?ݶupôtðý_°…µƒù?Òsw'& kgw Œøÿ…àþ³º8˜Y™y˜Y@gÐËÌŠéŸKª{;ÿE²ü›8˜ûû:9:,Lì\þÖÀ¿8_W ÀÍÅèïûÿ&þç Ž…`nmæ0ZZ;Àý·ú_hñk7k/€3ã_Ìÿ|þëÌàï7wt°óþïrE{ à ý_´¨¨£À—…‹ÀÀÊÍ`afeðp°üÿ§Ô™ðoþ…*›XÿgƒÌÿ-)ã`áàù9þøŸ³˜<þ#ÎêâLøú;tt³6þMÊåQŸ™ƒùoÿXþ¯9ýü¥õÿ_@ÿÑûGé¿“ù¿:”t·³û—›Ôÿá&௮yÀ?†Ú™¸üïz{k;ïÿËŽÿU©üGòÿKIÆÍäï "–vÿ6Àdí*ií4W¶v3³ú¨ý'¡á`t±³v*;ºZÿós``á`ù?Iu+k3[ «ëßú/è`þ?/Ë$á`æhní` Psû›ióÿþ¡ÍÜ]\þZü¯»üwï¿×Ö{½€fpnBaè÷fvåºyŸïÊÍ]TÌ´:[d{÷<® cJpÛ%Ð7µbß•©ÅØËfË‚M\lŠ‹C$ta&¬ûi°Á vÓ'QiÎÓ«—課rfýiþ¨LãááÀ±÷¹í¹­¶?çäírñì‚„Øy’=|?°M4téæ`ü±ñb¡!VÓúA ²áDø(Ó[Bñ`Ð`Ø^ÎÑ4+G·þÌ­Õû/zûøEáQ 9 ø÷_Ù3¹7õUn Ë”ÊyÓO‘\$=§ )„q'!WÃ÷S‰Ö–Ãfz'þÝ©ƒGÔ „HØìpdî"2’ª’¨ŒtW£ÌƒÂ_CžŽuöxHßþÌ)>€6Á üž¬±!¡'d@üÜšûY6GŸ(TëhùX}gcÄä÷qÒ¢Ï}1X[ŽcÌ÷5c=í{rÖ_dMȈŸK‹«{7t5ï¡(L(Õœ ïW3Öìo7³X¦l蜵<àc¸Kª‘?€ÔÏŒù‰DOÎŒú#n)gg+P7±Çd¨ÒšÛÅ/•gÎQwô4ÊI›çZŠZ~]ƒÁ¸Øzu º´é×ÈÎÒ/Ç×`h³VÔõY÷"-®y¤ ^ˆn² ¯º°{ã?\}PúJßH „mg ȹhZТFH³!qMÐ=‡)ÅèÌ]Òo\rŒ_tòäË÷*"P—êÓ Ï’Á¿±±˜3A:Ði01{!‹FuÒIta}þŠ5¥‘DÏ]wyžËÿfº8r¥ˆíŒrH´e”U;ÔO¦K7TÖZØí;X–œT5)3ÿ¦¡Ç\&Hìv…ˆ´ý†eüÁÁQ¨8²€ %nÏÈ ãG¹°cgU¦ů)5ïcïÜôÈÉÂ~+_™‰+§I{O긦’ÃÌ*Ÿ:¹Ï¿oJæOúö Ÿ z¾㈶û沸Dê;º '1†´/Œ-j*ÑêãXÁJëF9Mžça>ÑlS1ÂÜ„.êfƒúÉZÙtÈÊ­Ì ôþè}®Æ.ðKŠg­ib4—^fj9f÷êTY“gŒ!|v;îˆï"úDT’ÖÏo<á&J/T¦?&iÉ5èD)U «tM¨NÃ~uÌš¡—AÝ.ÕÈMY0m{™”Lqþ‘ÙQîû³w@ÑhQ*MÃC\€:×ÏÅ?Øìã$“¯ÆUÀñ™6‹ V«zêSM³Æ KÉjå÷ ¹ÍʰB2EDn‚zãØË ×гšy*ž—Stnc°ùZÐÀ%‡ÿ5¶ÏŽL÷GM gÞfÁ™˜ùåò Èbó1>c$W©ÎÙ³  éù©¥8ëÄϧë´l·6c;h2kƒ![-ÏôcÒ”™òžß´zç=}Tëù‹‹yí—k©aËk}»'õí”^êïJN÷ #†N‰vò&œ||·ó¡9]«ß„MõA1LЉç¤ØÑùsϤºD„ÎB!3’EoÃ8×ôh¥€†X| ?R$ºµ¦qi?¾ò¡æ>Q¤.(2|}5uÌÛ*Рád_†z¶û}rw%ãÏÅ}¨2ø4‰2‹RhxìÒ‚Jü×o„Ë"ƒîcºCò­ž»n[óXu¨C{„¡«íKÜv;ÏzÁ~™¤ºÝڸõšº³ w\”7;ÙûÚ†Kmwð¬M‘¼Wpžg¤š0·'_­ùK+sm~ŠAI[Ì™Jû캡žØ¥´^UO=ýc>µ5g·Îp‰nA™™Ž2¢9Fà%`Šîr* –™é6®ò±½à=¼:ÆÌÔc Ó¤.šè6¿Ö{{+MtñÍ`wâù@=~`¯ÿP~· ‹ÈÃã2Ÿ«Q?™ ~ˆxZÕà’JŽög-èt?È5û[ËrRââô.ö½ŠÅïÔ.CíFqx×еg—¯VÒ« >ºzƒu}£ÀõÎo3{ «0vùiÐ…—Æ2&1·u^OFˆ,)²‹þÊàEIbÞ~ÓW³ U9PO+ÙžëR&’;®ð«£$ð`²dX)~ÛA)E”{ÃÚkÞwpö$¢UÒ½ó¤ï7Ñ…m$½[^Sʤq£Á‡nu¯9E’`edRô1Ô?YÖŒNÞßœUØ\mi‹±ŽÌ\‹S,iø³hçÓÑíî—Õ8H¢Ì %¼¡2ø ©ãµ}½ZB ¶«´edí{¢·I;ÐHæ_Å;^ê ScǶiú4)&Þ%4¥·QWDë4/¨…[Ý|9§é¥-š‹U’Â'‡Š”nò?•¬÷‰ýüï"T4ÍåqÚf–iûíÙš,9-cáœaÜð0A»ã3t¾G4`bÎsûmŽn¦w×yÚ'Ì‚C0¼Aò•ϳÕö1w”-+êÈT8ìasÑ ê QjŒÚ°Vôžð„9ëviÕ:ç?QÅId¼JÅÇ/y½šÖñƒs0Unkg3뙈²d§Gèù\mVÛ£˜àÉä ÷pGQ YX?dz— Èo¥qÝnkŒÏÃT°&l:+‹ÍÊÒD¨{)¼ÒùʵØÀê….úºr-F'É CrÅà/£û•Îg9È>më¡Ù”<²f,JHk9…ŽK$ïɱ†v•jÊd\0ø‚qjÊÃöº¿%Uº(æhWwžG¢ƒ…wiä蛀ÜífÆ‘%lB';S)©ò÷§&Å«+‰à¢¥gž’C˜!îö„Û‰â-·FI<“̼×ÈLüÄRQ“;Ö€,Óœ‹*>/Ås{» æVmCÂ`±çÆCjÎÚ¡É-®ýd^hÙUSÕø05T•fNƒ÷ÚS”þ6<Ï•Õ%ÌÅYgˆ5 «oÞp[]m–¡ë,”(Íl $­¾¼É>¯ ®¯ã×àŠÂlZÿÕ±ü{¿omýÑ=ƒ™­Ù¨¼•e”(¬Ml/û{„C 3-0µŒó±ácé3ó&oçY}•·XáÚ1†)ÔŠï'åŽÂë5VÏÔ|ªþaEœÒIÜ·û?§ØMϠϣ)O½¦SH¿GM°Ö>…v`j×+ÈD–Ê7Æ`iWÑ’FÞ¸UW\{í°˜Ý.“¢åŽ4.¡}|¢‰¦Nèa¾B'µ!¿+£_'“ xТ ÆÒ®áÃ#é>#;ˆdÆÎ " åDù[…u 0o¿&•®Â=CÓHOeüü' Ñy« OL›¸{eÊcXJZ-{÷hH&]ô®qˆRcÙöJ¾½¸ŠcÅÞÑô>ºZÙr¢ËYIÑûÁz ’˜üÚ]¢b^þ4ÏbÚ&¡€ü qgÚ6ð«¼)í3'­ÆÏh ®ªq¿kôu-$r 휩ÎÜRI{S¹_W­©<$ÌŠ«&õ¢ 51²vÅÔ} y‹K$:6ëGCÙ>ж×kã܇‘p Î{¹ÊHÿýè>Ê&Ç™1Ç!ŠnÖÉçtžð*á¶.¬U¦ïÌÇ¿@ÉŸ<á¤J£¸­úV>ûž|DÉZeúl y,Fþz“0ÎÅ4,«Çti*©×È2×\Ý¡ 7Gÿº“¡7­ÑˆÆäËBMèk_iüÒOL3–yÒ8“ M}lT±:p kDT§ÿ 8¨}S¼÷§¯«íïÔ9IÎ8gg±Ä†gÞω ™•NI?jÆñ›Â•a£Õj$’MhÃ:òÍèƒxT'*å',cQ퀘¤7åz­¿p¬S^ï0_Ú¼­&û„zÑcvjúÍuÊiãIb½G,ñ¨õ+žÂ‘.7íÕÞךøwƒ«ëŽâó~<ÛAÙÏ<;µ<•Ò¦ñê’Kñ'‡ú<â8d¢ nƃ ߳ǷØí§Š>‹;9ܳ; ™_£¸åæ7É0¥aL±–¹¥ølwSºM¹û.™ƒë Ù±§QT¢Ê§¼ÌæåY!ßNå4©ć ˜&‰. /E?ËgnbÙSÂÙïrmu}Œƒ,°Jš}Š .á!J¤I•Ôjb°7K$°Ü&÷’÷žÀ²ƒË³ÆFìóHÐïÑM¼©ˆÕ¸ÌjŒ ¥Z"ÉAÕ<ñ»³i|qÐúÔ0;™ºì†¸Ì—ã"ÐÙùЖ,ÖŒ¶Ú>³dFl«VV@hŠwüØ_A¾êß&„ÏÙã¯ëoÓÖÊ ^¥$žiPt[î%Å”úéH«Eáb 2ÃÔÎ4eôEï’ÃѺi$Oã^ç*O;':°Æß»ã}œWLò›¨d9[MÙ-Î$)n-DD5ge¤ÐÚœè6´º`3ÖröÓ¹È_H‹[ã^QFÚ’­b©Í2D*ÖÉëy|Ýu¼²ìe¶èW6™.›’CaÎWýªe,‘ ¡ž{›2øËA5‡‰¤B‹%.Él¨‡ 3ÚIŽì…}$•RÍú ÔÖªƒ4!1Ì5¸£Ñèâš?óµ´ébBýÕ>v¥Ì6‹C_Ê_ŸNûÌcÀkh%æR1Ä´"âM*s‰·Ú‡ùò;ïg¥«={mkÑT&Ñþ3±N >B»CP2êGvL"Ì sØ:©RØn•_eÀá6‚áˆH§ £I›,g4R×ÃA瑺?„ßPz¥†ºíKóŒ'ÿ´Ž# 6^;ö]à—ÇuÄ$\‹L#ˆ0Ö×ç/~xKmøÚ{¤¥N—5 âò7{’„l˜ ͯgˆ ß)tºŽ9 ü¼¢]Õ¡/‚HèñÃÜSp˜º˜»ÿÙÖ‘xíEQ+N¿B’Áåª ÝX&‡M}A4ék_‚óý'<ôÃ6Ž[-ÑbÚñx88«#;™çÁº*û¾Àþã. .!:ÈÌŽìWÜו©4ìï¸sWGÑZ[K FâÚ Ðy¼HŒ¡I±Ì}Ÿ G ß°M¿33(²¹±Î yï’ˆò½²÷wDº¾£Çº‹Fú³dÓÈúYlÈ}3qÌÓÐ/ú’Ž·)gXÔÏ=·Òèá¢Ý¶¼x TAÍ Ä&ñWÕq‹¤3«€u˜èbû®4+å%ñÝc82ÒÖÙ-'0Oáû¸Ç`M´ ¬Ón7,ôØë‰¾Óþ‚o­w 3ßo22ÿ£²í‹Tñ#廊ƒ,e;yêÅèÚ[…={E;ÃÃP¸¾érØ„7Zÿ”æòkÙuº,¦°Ð:†,Œ¤@—ãLçÒiU!é~'ËNÂ:Óö¬JÁÈ€ž²µ`Ö˜‘œòÌÀ]û“‚êlÒè³)\ ;s‚Ä‹.‹0C­g„-äÓa¯¼'wÀØÐðÁ@tPð£z=y°º)£o–‘p˜WýÀ×E(Áä»t›kÚ¼ÀÝóNÅ«¹žµÇõ¥609°ß"=¸úT®X×’˜¤9Â!Wê‘y ´Ù†dýÁ¬5KI?îæ]}¿³ÞUãÙõ<„K«¶^bzÁS#O~OOÔà11‚àÓ÷L‰^)N¡iF‡ŠJwR+˰ê_*Úñ 9 ç,ø¹dˆ4…|qŸßI#CÜkJ}Û&k’¡—ŒNEøÊ³·^Òö¶f;×õz,…ì]WfMàKô .ñý÷2Ü‹ÄÙ‡"!órVŸ»|]6‘~§º‹ kLÃ÷úKÿ>î•/zͰ§âel†Vñ‘ræQ¨W¿(=m½ŸÅWꂉÂëYÇ‹u¡µ.« ·ÔäÔæŽ |Ó„ [ĉ„Ø×v?ËËuT}Êá /;~9‘û•¶_ìF¼–mïäÑÁ ˜¶¯¸6‰žŽÆ^F£Z2’y÷À°l,-Eqpw Aºª|i¬n|Ç'‘‘ȼ†—šÝz7ê_álj7a}ú‰.àå8]QŒV•ûÄãôǘjuëÒ,ã‰d!;ÔŠ1t;FÊü$éà {¶ü€¥~9H» Þk8¡Ñ¢î¢ Æ ¬tà¾BUiΛÎ3¤ŒÛ×,Cð‰èQe-—É… °b·Îp¾ö®lÆ¿”’XHXQН0( î~ÃÊ0F§1•03ßʣÿlz$¶¢Ö¤ž¤I€ö/g½ާî›Éqû4íl&>åR…ƒçTq/ZÛŽ"b>ÝÈJËea§ñëj’µ‰g´ÏÍ<„”Fj®Cç|b˜âR»¹ØåóqYðOsAr£»¤h9vá¾K‡Þð© nˆÔG…æk©‰IÒ}‚‹Ò+£|§]h:+±†ïh–l]RÂÐÈ«C ^IÄ‚§³ë=2׸_¾Èý±¢/L‚™ºþ|íÐ8˜/g¨eåpYÒ!(?Ú—ÕF¤„M¤æHOÓqúôF"÷€™®÷Ùla‹EC#æä´º:”VêøClK#P @ÃÑ`Öàïô^óAí¦Ø»O¿ ëÌœË}mòصô.ÜP䕆»áኖ?Æ10ƒ`HýÍnÉÐvÈnBŸ_îy#ÈÁæÖ~½ý´#°y„~“’¢«;)ì°¸c¾9N•¶Ií¼T@<ütss¿R ¸7 E™áþ‡1e Â@Œ*•ÙÑH𣠳Åì²îϨY÷@›v ¬åªœÓlžHò• XÃþÄHµ!²k¸Y3i—Ñ.û2x‰Ó}¼®þôû¶Ý}ß“CG7(‚sð4$©¬ÿ¾ïë~×÷seeüäøE…õCÄì) —ï6)i ww:Ÿ ½$Èûý7Y„ó°«=&—[kÆ=pGîºòá©@"Ɇ§ÛŽWûHBD«fíB{2)‰vªŸ†ív!j:6©úõ>N6˜gD•ºê[e¨|_°BË@Š›EÏ`*âLx¾N®#Xo1ë!q§±†PŽ”™T`MסÁ»ôÅ }—ôæÄ­^÷Ïòa–µÕöÍ©‹NCðsÔ'=,v>Ê÷ å¡.Ù“˜ ª'¬Ẕ»Wþ”Šx^ø‹šÓÞ¢üÓëJ¶2Ïñ¹¤™Ĝ˳Þ(ëeASÀaQåQ §›‚ár‡¾¾+}vTM­ ôÅ—$nê‰Î+v0P;%× e²›T),žd‹hÔïiH|íïÿè€u†ù@Ò¥ý`Ç1ðQWöÓœež|”ç‘Yi­eÿÎ<¬)Trz×O9’TÃôAòôgÔàž2\}õ˜$ê-\¤äNú:xâËkx]”È£‰¡SÅ"ZR¨b·%Yímñðz{õ“}è»òŠÚ'„ÝqOj¨PyK¹#’\w&9Ü—™C‚ÄŽœv~/ÖONž—/Rƒûupmÿòùçµ–-áix•.šL-bžã1j“OèxÉ¿§‘ûÃÛº›zº“€È]Î>™˜3U²@³Y °ÄQ‡ê;÷Ž„*Ó׎ëQ²>ÖÓ¢"¢ þlD>æ²’Msñlg7ÃÁ*æ5â/0ŠBºeø“Ÿ2zmÏ“º–[ "aų[·¾ÐÝÙl(eÞ[Aнfs#ß\©aü„±@̘’ü鹬%?z;*fßqF$&XÃäwß/·£ëk¦ªý(eë…K†?8]1÷EkzŸ¥Z‘üë,·ŒÔa.¨ô|³Cpç.„u¬*þò.2Lñ9U¥~»³ÌgÐϘFÃt¡m3¦´NÙâ7¨KÛVþê¬ê¦bVÂÏ$+‚ðF@7™«÷.̱T‹n@U»+½°çŠ·³*L‘|Tí"•jD[iy“/xØ÷])J#j~õ|»µÓä}†´êÐêÌ÷·¿sKˆ58}nü3*q¥M^lÈdÎÓ´‰6ýãˆEñ8žÒÓmuZw..þx—.<˜]Ýþ‘|‹fº Ý"-_ñ; ÛÁTXŸ$¹*ªC´l(P^Ñ9I2’já€ÚÔ,04É3™dÏÿÉM©BÍ‹.c×Þ I!aùEÓÿ¥Œ:Üšsåctó}{‰§Òvv®tÌ€x Æÿòq'‚Ç7L‚®'ôa2lD\ ·ö@9Þÿ½ ÙE ­³mz¥I¥aòÁ÷Á2 ê€}Ns5jÿÑP”kËΔK¢COÈûš£k?Y’Z5:ò2sëÞS/[Uç8QŸeûµTN“гDw7ZŠî»þIõ¥lñ7S[bNئ:¡jÇ&hÜT¯­‡S½[ØTéå+ÔÚÑN\ïӠϘ;®@޼/¸ëÚ¦Z”ÑB¼_i¡“‹» ‡#^Y¢àÊ%¼VÆKƒÕ`O,3«Žeu/GLGLocyÁW©”œVqá¼q5¯x³EÙn8<Ó[“Ó M‘ ‚Lš/ÀmîÀïFaÇ^ø†#‚´÷äW}gBMŒ®qªrnOä ú~ oOܹ­ONF›ï#Ó饯$9<¤þ…„wH4(Lèê|ÖÃP«Æª½!­[ ¦ÃE+>Ï×Ñ$‡ÉñÎÞ~TܤïWJÉßáN²J?Æâw8´ Ëü=íqÆ;Ъºç0WüX›>·ON#¶Œ£él-˜ËÃt× k¼”v–š._°‘¿…È—OäA2Õl˜ìúÕ³“ü|°$µ¦K©CÐ#X¿ôì=!’¼+æ‹!ÿñ-'p{S÷ÄIl•÷þÙ?6q©ØÌjUax¬É²0g¼®Ò@G_ˆ®Ù€9ÇَØ\”Ã~äÔ‘ ÔËv§»ÐqH¸Ô!w4§$yæ ëgÂÈ&lÒk$yC¯k´P—-´M@6i8YâAÂÌYÖý!úÐ?x•1Li·×%'g0‘ U4G…¶CÁËæã¹Ç7jå#c1þ:À¹jy¾ˆ@ÎÇT$íš]{F¤Œ8ÚijÜãEKê«xêÆÈü’ ±@¼f=2_gRŽ´$±®A\?wÜn.L 7 â×JØ4ÿøÞ¿‡bÜÕPíµ±òmøS¦íPªÃEBKÄÊImi:ïª]t[8Ç¿ð½áÜ/Q‹ÏùKéLkCc.#ì(Ì®“KÎ?Uƒ¹Ñ9ÈOGäòS3ãìqkFY%‹åÇÍ‡Õ xõ„ÍF¬¬ øuÝÇ¢®dÿÑG¿VæzÞ¶#*”ôî±OŽr¦F¡®Ù vÊ<ޱ{H~Å-Ç\Ù´ÃiÒÖVÓ£ñOBGçlªm×$vq*3Hë,·!é.kAÒVvF¸é§b&èÏDÎ…5gŒŠú°¥(l¾Þý:e¶‡ SÇ“H±œ»çl—küS>ÓjóóÅ‹µ¦Hì~r˜wˆŒÅಚO§æEÆ"ÒÂŽwaNpQ)L“Áà¡‚$±!i„$åB$Ã=ë8PdÊižÑ)A6••/>Œë¯¶úŠõ.>"|°hQg1äQ§ÂU1š†;øçQ³rRÙ£S[Ýàà‹r.úÛ$Wè/|¿ZH>ŽìC™3 Dë`¼šoˆa¥D“zjmÔìèÅè_Çá[‘âäIÇi §Ã†¦¥K¤&/–‰Íb5D‹Ù_‘>1Q²OyÆ;"‚Ÿ¥ÖmÉÕm¯æ 8ÝÁ²ž¶éÇqnNn”ú;ûÐåÝ9o¿9ZŒ˜R¦[1û(Ypœ°ë¤ê³‘¢M›±jëÌ´ÅûŠgaW‘â][¹BåùÓM•qi£F}]…»™‘ïG0}˜Çû%:û¦ø¤Æ¸™Ùp€„9\ u‡¶øô‡M îu‡8©¢S>”¶3ÜW|ÄÝç7 ˜ÇÝ*: 1Ú©Ù¥Žl¯¶¡âJ~Ö|a=«9«(ß-ÐÇèÌÛ¿^Wú\䣌·q<÷r±]¼û²´árì•‹I.Êÿ| t„'ÍëzÃÞÛJ oez!±¶ù”œªÒTR&~áe4½¦Ön?ÿxa‘8FX«L2’z+2!T}ÔuÿšeiG7´ââY‡¨XM&îðÃŽìUJêœÿýîa¶ì:ýw ù‰bÒÃÜÅ5Í6Xî…ðéÒǺWôº]žæ‚SM§s§¡æûoâ¥lª“IU‰³8‘ý±I8ÖV‚ƒŸÈ¢þp œ–Љӣ¬éf%wÚeŠ ª¿ýÎL‰x4ö_×Ù‚(…ÿx?‹£\Ç kXXé Fä~ z‹þ)Aˆk‘å²¹Ö2T¿QtϾ¨íŸòÀ²2âîù•ð€rP¨V” >Ï”£ä«!C‚g¯.'/Bß@þ ÷OS´eS8âžû¡mAðy3Ì{Æ;êI§³QÈ8·Ñjç¹oª~U”±ói­?ÑÑý  â5/¡Bðþ9Åær ä·=zØÉ[ÓW£¢Í­h»2L]´ï÷º2gqƒÛxN}úœT/FEßìwUíØ¹¼:ß_P ¨úf'sFìDWÁî°ú4êã•ôß=‰’”;6:»5äòiç³4º™Ü#°a€°&¢ÚS÷Š?"µvÞwg"=‰èÍœaL ÂæÜè3Ò©æö0LèLag›véBßcnÏôÍ^Rh÷Äç•dÃ8M3œ½¡ÌVQ#ÁªÞn?Þ(ž—6¢/”Dó ¿»è3¾ƒ†sÍCù`×:åo{Ii@,$rò‚4Håy}ÕO¹$6ì‡òY¦é»°‚b0¢½UC'ˆ' ÉÞŒIhyMÚ@fÚÙNrz½ ŒahT0Þ뚘5hrC¨Ñ–¨”_mbŒ˜tÉP³[ð¦,‚÷#tÍ…ˆÊ¯Öú e&*ò .•žÌÁQÈ'Oá»_ŸG¾6ºUDW{æ¾Q˜eÔT5Z¤ï”²56ðí¶˜$lÆÑfåe©V™„NP¢ÌQÛS~Ž’Òölâ6ÍèÅ»‘ƒÝ^@à6~Л?Ðó,‰Þ5º^¹úøbÀ,m ÁñÒÙþ(l4q“o`ä´Ôk”‚ðƒ†»Ý‡Î¨S Sö¥áqŸ qx'jrfÄÖy¸-)õBècxëǸ´™wbà »6K†G ¹ÊËfœÍVC/ äq˜¥îîx^ºmŸ³DZò'²LûÌE@`=¹tÓÙ]Â%’pü&´¨¥Tÿ圮zGØ‘Ng=w]#Â:vá­Õ õ2bDÂðm t<´ÙȹíE« ¹±ÅV:ÑÜ<¶cú* 77뗊͉™™ÏÓd¾z(ËP[£“ ܨˆŒ$+ WéËù—ÌÄfÙ´‡ß7J;0=ÑkºHªNÄÛzÂÀ9ñaÙHK{÷e‡7¾“‰Ö ™;¢»@‚ µ—Í®‡]xg;„a…â³RäîÌÜ:?©R:m…¤V¼~8-oÓ·Z³ðö5˜TW´¸Åèfî꽺ą\wùÏ ƒ—]cWÅ2šVq-ŠP·DŽïE,Æ$Cº;ž±óª…6 åo®Œ0"LútevùÍ÷¿w ¶›\ïéÔ‰-™¹)ÿô8ÕÛôê†ÒAËëðä08¶ƒÔ׆Ë_ßÜ?md{ÔÇNˆ ™ÍÆšÞæg'Ø%‚Ö ›‚Ó'~)…èÜ‹²šwÝ÷]Š6ОWGâÜ2‘G>xZÒñ,Ì%cE¤jôÑ‚µdFÜãÀI»Á¦:Ìÿ k¯ÐÉ€;,Á‡l8âÉx» á9Ä­}án’æFGï®;†nNoÝÍž“2•@ Àʹµt«+8ŽW= ïàBz -1+†aøU¾x¤`ÙÖQG0Î+Æ7»3WœÔR*ö½¦äu6•Ó 7¨ÀmßU•’ ;WçÊU‹Í ÄN¿Êc 5Ÿ2“ø(G” åûj÷*E}>oaù¨br}9Þmkù¼ "ÇÈÞ¾@ïÔP9ÓrZyoë’o"ŸÁ0ünH™ž4ÖãJðþ•æG8"273ÒiÉæ'sÄŒñ8N¯!xT•ãwFm1RƤ–¡˜›BX³ QáÛ×àŽ¢Ñ=2X o¼ÇÇQ(:¯ê7 ~ÑÛÂÐó–™b•¯R¡hµWŠ>š;ò¶>ùF©kXμõï‘‚e?»Û˜¨… ¢ÿý/\X`¥[L©hü§P°¼¶‚„'¨ˆ{½çèçQB<[J¤'8CTÛ1g²ÏÁ#{9o¾i‚3“3q¬H êrµ"Á‘Œð·­ ÝJ‹‰v÷ÔÚÏ“»(ÅÅxAüýòÀÅN;£ñÇË­UÐÒóÊ%û¸R 0Q¹tÇÉ’ JðM–¤ÎYš½œ½à9$Œã:e¨½V™ágóòÌñ±Ò}é ŸÅ!Í/—عóoÏ­ ëSQ3Ú Wßðú¼è,{ó«bY¹ÈWùP¼ŸßÀmˈºŽioIo//¡PU´1 )oC¼?-Áa$p]«î.÷•SVÿRãøÁÖME¢Ï¯S£š³£MØir¢˜¡»©/)]Úô”‚>·(§ â¢U$ùSÄïÁ]¦Û(Z0ºù}ÒH“ƒ¿EQþõM bʪ^P4¹1Ž•ìª‚pu‘w½CïÕçäL(g:«•©r›~%ë'jH%uÿT$"*øÉ¸š d0HZr8ý_ÂÑ2}¤=Yü?ÐxwCó«Â  ‡Q6ê>¯+˜â!s¡k/j¬^óB¹µ1;Õï¡B,ç{°Ç¯˜IÐEHV<&/'®av¯ ÞÐß&kæ …F7_`u!§}ì’·ÖiîO›®6û* –€ J³d½q‚2Ù ýçkKT•ÒU\gÝqôï$^ò#ì¡MKÃj°°(AŽ28:>ã=!AÍ:ƒÞ°PÜ3ŽàIýz`~p¾eŠ>ÆzOöÃåßéçÌ»…8}Nc½Î²íX«dä¶Ín§¥–¼4Œ!dÏ„×äz&Wã@¯UPÿÌB¶ŒF“8gvÛ[š»,lœÔÙÛíWõÓØ|ÜU-) r;DÜV£‘¤ýS!õèèÊrØ7l#õEg°12¾> &Bz–Úßmåå=ËÃÔãìÆ‚í‡ÚI›©,G —´tÚÓ«†bjé^£#·Ÿ¨“–zÚË×r–вå•W(—f¼ÎÐfH#Õ>‰Kà©Ë°S¿?ŒâÍ]j_íƒÔ.gšø˜wnE*îO€óçŠ$ìPšl{¦mÿ­+á8E&¯^¯Éµ¢sÑCkþ'³]S|äÅœ9o}íïTy[»§œèÙ*Ü÷Ï…1‘:â­_èí)ó¸|ë/׉Ú“Fðçèþ!¡Õ4Dö¸ðm$ñí\Ç-œyÝKL;|\6a/š¶?äŸd´íK¥¹ÒBâF/i¬cu^(F •{’ÑÔïQ¡üƒW§3åÙ¬€êãOXkš¬jˆÏ¾Áµ`7– â{7­ Ê6ýœ–ß;Rë£þzw\ zb41Û¿AÔÇ‹“T^Rö+z–!Uý[æëÉ)Úì‡JA± ºBxÖ¼:$¸ôUŒ}{¤µí‘ wý@ÍB [Ä-xæÄÝ#†i4Ö;§xj_¾_ŽfHvf ÂæTÊß`çhkh+Éä|"”Y€)X²š4vß:ÅTÙ §+ÄC:•5Z¿bšÄg»©çö¿Sžò+òg2ÓC'’úÅUô(!hg²‰“RÝ^Ù#6£ÏtŽ•ï.⡲”²þ¼Ú)|«q„rÉ%nå‹Mö#j+ÀÃ>ÉA‚˜rõ„xÓF˜‘ç¹÷¯;xÃz0ÙèeŠì€ÛX½ÜXüó僧ã\›@à,–œ±åî á«‹IC˜îEåã¸vçÛŒC-® „¿5°åÅ”PrÍþno·EJ8øýãE§iaWNk0Ý w⻩ÌëŠí„}õÜ®ú2š²ÐÔáÔçÁ> m©Zþ+³HÐ!î‡cúíS9äùÚÃp\Ýô´¬ú·ƒÏdG:/Åù¼¿û¢\ž²(~œ_ `Ó¥y‹z±Å(ÜfÖ¥ÚãÁ"~*)ûíÞË{.“½í‹¶ô}g}€¤›Ldé…l&AuÂ_Î ®˜·q™{ÕöB0 ®Ð#Í\õ×õ°DR¹QPB/Ç{÷€R$8¾ÂÐIÖa5=Þá¬&RT×Å=ˆ?ìö—ƒÉ>c#¥Jœ\ä,*½ßî*~'ºã •|¤®Ë‘Ž'9Ø€ŒÌ»X¥kÆ{EK1ŒÆü¹‹ÞŠèOeßHÑФ¬&¾­~‚i9ÌBù6ú)ÑEOʸUMH}j'Ä †ðq0‘L6üÀúr8;`9µ¤k÷Aat*o” ©X?Qߥ!AÁÒÒù›G÷M[UɆËòû"X Ë~•˜Ÿ jÅÏÎâ›d¾Þê›®÷ºËúµÂ=®3…F‘««”c_9™g|_™lЬŒS!½ìñý[!¶Øž¬~û >^}ÙÉ~¡T‰Rå¯N´L¯«ö…Iª‰šîg;Ÿ©£â±©fï›ÅH–kÒnç²òÿ»­ JÈi—xuýãdgé³X˜>*K )UtŠ“Ìð#¥$D#AÕï ù£î|Ãø"*!È*àð±É±°<×o·õ´5üwm+ë’~å{I·¡v°°{¹Ç«û¼[½z–ù* [mY/à5ý=e&PòmÝY&w;&[jA”>Ä}Á—Òœ˜Ì} 0‰š l~ ”Œ"²‡>Ù\9 ™…æxÝ7…|ô"E O‰X3Rvh½k䢢LÎæ¯¬>p†Z’Ò¯½6 ÖX8Jô#ùc9¨Y`µ (Iá!C“{(§f„üšzر¼z¬ìžŠ½‰_ädð!D~Êð°ÎUcìž'rŒÖPkD<‚é÷d³xF íÇnÇŒÖÌÏ£€g›$ßßrEñ«¥¸–7ÞÃMƒïAÇ{|Á|¬¥œF4¼pÃ\ò™×%¸=zªÐ˜’ǵOG{ó»JM¦S¹1Pí:‹²ÃÃŒ‚HˆBˆ´Z\»°ªä:£œŸ”ܾƒÔH瀺é¼%¾ÿ G³»¹}F¬­´d(E ÙÔ Fô-³ÝÙÑo~£o²™àókÊP·?Åû(f&©ÛahiÐz±NXÃì{ÔôI+‡Žsn4¤rq< DÖ¹÷> ~¥³õEÅê„SÃz}@.åËò¹[û#¿VjRH;‘E¼\„2°´ª"tÆý»ùvÑú[è»âå;¿ÍÉcNjåzà{Á4Œ(²[·?>vCü£©ˆ ƒi›úêpA¼rÇÀš‚ÜÜÏCÛÙ„õ·Ë¥)a#ðK"Åþy{ì?·Ž¢T—4å³4Yp ÔïL!¥³bÅÿP'QÆèX“¦Ü¼vH[ퟦ 'ÓsqÞîmO÷W°·ù"$7wŸ^Ÿ¶ »qÃlùf X¬HV­ó~ÍXZuV¡‰€·—tå¬`Ùž`cH¼Å½ [íש.¡·”Ó“Qs'ìáÕ£p¬kª+Ç«ˆ0}0WÓM|ã[9ѨÍÉ@ä1Iebúr®˜~¸qâi}]ÝgJì‚Îñ€¼‘S×Qt_ 0Ó8Nµø}Ôˆcl"µõèÖ¾Nœ ¥Î©°Óð–U¨6(CÖ×?tlç I^·¨æ½ãJ8¢¡ù`Fš‹Ÿ0<‡4!»Y3Ê‹|«È¬XÄ7 ®¨ÿè{^b) È’ h|i±µêÎ y8\’|ÇÃGÞŸø–þôã´úµÐy9ÕÎRŒsù¥PÉ„²Äj‹Wò›«ßBÉòPö~º^øÙfž<ÜÌHq†­}û´rû|.I‘.ŸrNŠ:ç¹"yàò|Ø0Ù³NPY‹µ&t?;â–CœšY—×™BP‹É“’:ºkÆNîØÆ›è¹ÃWIº7°±iýØ}›Àð¥Ä@øeþ5Uc½˜5ã‰ý&{Ö÷ï’¡hÃŒœíhY…¸¿\êƒùš^‡;$Wn-K0ÿ`wqÏí °$äÚl/¾H 1ʺ~Þ䱡Ê;Ê0_I.e¦éWuGƒ‹{áÕD2ßÚ~¸Ü×׃>:šY;* "Ðè/¹¥æœ·¥4åi§âò¸ý }˜ƒ(À¢vZ7Dqµ°h¬-úÈŸ[½(”ë¤ N¶NVêö`èr&ú.¦³Ôp‚»É>3¤*| ¼ŸÍÆSKÍmÑ9Ÿ€k2+®¿½fxO!^ËÆCŽpð™VùG+ÆDéÀÉMlœÂ\„ !;ß½îÌMmÏOÝÐeÜ+i 5¶3®J?i<ÊœYFóå@ÀãdJ‰Ò]ùÞʃ+>9 ßÀ#ä„l59.\™„}ÊÖ¹ h{ÉΪ8wT@ŽöÆv¶ÚK¯Oüõç<ʉÉÓÞè‚Ì‘mx†~ºãjô XGà7‰¨×ït‚¹fŸÐ¥‹äCã±axÝV#zŽV–MgŒÚžô1ÎMS­]sFí:®¥³-äEÅPíaËŒªL[dó.”h P7o¬Øökr )ø¿02V¬|¾U\M•X{ßPœvn ì.ZßâÇ#²!-UN¿Úa&MÑ8Ë%Â6£X½2– „.ß&†tú±;Ÿ$?д¬É1 hßfƒ×lýzq õ~¼=Ù–Œ-ˆó0¡mÑC†ÈGFrTzÄ®|ø0gÍT¼‹-Ôî‚J‡ÚÒUÛ g*ØÜî%‚€g¯Ÿ4Š×ýÅýzÐK'‚XSÑ/gØCS$¤TW›AéPÏ!cE6™ña|ãÀ4²ZÎô‰å~Šé¸˜£¡Ù†.Q­òž”¤YŠ_ S qF$OR ʪ@öžˆÙ³ß)!=½`Îj@Ætl8B l$`©Â¯ã³g¢$ºÙ/YûcbË{§¨ › `7)w´¾€ùnQ™À]ÎÏ*{cšI™Ñ‰'cDI`¶Žñçæ‹,¶ÏCͪ<\ò«”ÓûTXy}|ˆ„Z®BûqXN[v üh˜ù;Õ]i‘ì»âmoF ªÝ¬á긆+á–;>8¡êŒ—Nb%‹›d8&£~ä¡0¹Y‘wõ8´®^–-!šÓÅÉ'8kŦ4_9Í£Êçøâ4Hú™åÖöȈº{§-{)iJ4áˆþJËxl5I©Õ5àLÿ'@Ø¿ýÙá-BÌ…Q’÷pH®ry23ŽñüÚå-6"èó÷T§‰¨°ç˜¹‚²;äHÛ>[òšù+W— ±ùÕÒ—ëíßbKçdñ€ù@(õ:Qöà3ç›j€Û+;ã7I_%Û¾Üô¬ÔM‹ª¿aVÈ+‘T¼Œ$„œŸ‰žèküb÷`¨ÎSþâ~ó °¤’Ûö‰·bÙ¯+ÿ’µKêÝ‘ 1W§ëÛÊ»zuóE`°eLÕ9–d!ÙŸr›äzSN¬0³Ñ‘!Z Imç¹³‹[ÒR­èxMéFËk°¦OÐ|mË1몗žCžû1“ [D¹Ï³5'Ýñ8“¯´UùT mWÊPÜ?(ÔÚåÙ‡•mˆ© k}•ÈòôÌ<ÏyeÆYü¤ÒáÆøL#²ÜÁ‡'Üü»wb¹jžJÍÅüJ†²ˆy Ñ,]è¢NÙÇP° ˆ7Vx(u`îJ1õ×¾¾¦¾£žèX˻ನXÒ–[z• CøŒ7ýsÄÐÀaÒõ§™ÍÿäÏC.”¤? å@-Å:`VÅO×ÞÀ}+ð°·òyóÏ…@#¨H ljš$P–¯‚ÛµáŽ4TQ?ä8þAìmá9[@„EÛyÀ%\€òêMHËÇmc³)ü&‚¡Ñjigi,ýÐw úcl#Sê³Ç›ªïÒC†–üÛ¬IÒæl»K¸|QDbÃmÊÐê¨v(Ý(–ž›¿í~ýh£m”„âÎó€XjBʵ’=æó()úè}Áùsüéz:õ¾*c@ ÍBH±Z—³Kðexé±wà©kÄw¹DÏÃ~9F>´1‚,‚f¸Ûp‘Oï>æßi¬Pôu_k÷ôböã‹j)øéš8ÒH,FÎI'ý -%_°|‘T¯¦ï0Ê[õ§ ¹ ü!7mÏÈC0#îbMkXÔÔCfÒZ]Vr\t¡Ÿ·ç€ª`ÑœìÕ~6#B© Äå rÅ<èiçPõQªÉ4cÌ‹¡’Àº³ð—~}™]] _~wV]^O‚ܰ)¥ ïÑØ¨ö0«?äÉ)V AR®}\£$¤Û dÈóm˳˜£²Ðw8Jˆ+\²ž‘‘UßMÄG£Lî`„5móèªú(€‡?l¼§˜úwñšŒh›%ÿUŸ•¶!Ú³Ömí`™SZMÍT¿¨â¹JÄ!ݼ—›¾TÜÌ•ÏRêî½ËÍ$ó¼ÖqsÓ}@¹r5( \©+÷Þ‘q:›?ê+áY€¿ÔIŠp±š'“Zy‹ìÛ0o–?á¸ówG0¯™“4 |ôm§Va³Þ!¹“«å“‡<±­MÐC„ޤe‘ÏÚE3xæ¼»¢¥¥Á0®qÈÚǾ(A`¶sÌ‘ˆ•âtìÕ› „nsSt}=ÆQ´Ò®] Òþͨ©ÿ]¥#¡n€UV½"(fÑ›y¸-Q.nEö\ûrá*¹¥uv®@èzñEµ¿ÔÅ×­8(g!Êä?I7¶˜ÃÛ Z™sÉ@±‰iáÆê¢IЩ”h uŒE’v=šzu3*-êÌOݬ.Ë;Ë,[ÁÝýîôü^€¡¥Ñ=`Ȭ’aÔ©I,U¤>ÌX–W‹ë üÿ„qÏ]{Sj9oYh£Š.j¨{·TÝ€V䉱@wû£q‰–jÒ#ÕµÝ9•oêc÷§›%¼;ÂÓÙ²»|EdŒcP_~¼BŒ¯ü;g“a™òÿ¨#¨î'sŽ_ßœ$|Ñ3ýÒÕ]× R* ”tL‚N) ”[H>ˆ†P|v–K\"Y!³ì°NµÎM¤¹NÖ’;ÄAQ‚ôR1ÝÞ61/é[–VãL!èæ"vBƒ§æ{çd»—Q#<9àdAOÉd–ü‘ މ0Sás9ë쩌øÐìÆäJO #‘:R\È#ç*|/’‚ÒÞ€‰Ÿ«Ø©Ïi†GkQ ¯±ËnÞ=!¬n»j` <›—´²©DŒT¾MzË'=gåL™‹úÙ⣊㶦}ƽ€¼-ÈŸ.^NQ›™Îidr!pH>ôK!kØ¥8gU`b³ÆòÁ䯲.üÂXÞDk å¸O8}eYzI^%àâÕlìŠÖ³D‘ß4×!ï]ý\˜OQ›ìÛŒôÿöz›æ·Å€õ`[(eU–!O·W|÷¿+ÔÀÀ}Xö­5³E¾òˆvÎ/´‰’CÝ©V˜°³Ú9~~y'Q®Ô=&ž /%1¥U'šÖ828ö »Mdº6Ö+†'=6ºt6ÃxõÝUÏ3öÊ"J µYÂTm ï|t *3zõtP6<‚÷Â&¶yV[}÷Okëf›õ²ñÇxvZyêòí€â³ â$EU‡³ã`sõ!PŒêà­–#Pðyþ5y覴÷,³OVþ% " ª×â'cbÔÄUiYpêÖ™BáKàš,ûÏ °©CEDå £nñ°£Š ûÊîÀû?;rÄÉ«öàxÂ3–Dd GµÆ. aÓß*@_b£ô!m*©`ûßP›ã†’ Ëò¢ÈqºÉ^(½DM–#Gp-J#ï,ÞȹÃS„Lf Yó”ñ3­nê,Ž3_ù’ή1˜Ô6ÉèömÑó[tƱ㞑0jlGcŒÏû!ËÐ8>Ƀg좆+ )*%]~ýÁ­†®•ˆfâ,93§ù ‹è =Ô»2ã0ŒúžXìRéÔœèý .óñŽ¢ÂX9/^ÛØá„füo*R&ÿ‚9UîÂFgW¦N£†™ƒ+6[{B‰jEהΛ«“–(á7†{YºÙ)ããå%O@v¢‰Þ¡°Û˜9Ù“i­ ~5h]*äKÏbO]«Å¶§—ïiÁy¯_æÁFVÐ,ÀÓ›T=+ÇjÃöe~r—8(r jçÅxª= ’±•„†”4ªÎSçlÀ|;>­øŠwÛº "¥×TÞTR[“|¾™‹ºÐ$İE¨pà:t@i 4:‚¬±ò-e:ßm -HÆ­Yš*•¨yZw/ZNPðÃì:µò=RƒYóÂhÞü“x Y¸µãá ËSþ1ÊÕoø!ÿÉ (¥ì_ÿ䣘tLч¹c<Ù‹ØÕ¡4¾ÒýðmëÜÝjºtV¯„X€¡èU<Œ Æz‘FEFÆüà´ýkÊw„+ Ì-*n=׬<¦l"‹ú§¾7è•Ì-»sëRu†ï§uï0Ñ?é£6/¼ñ–}¨¹b¾ðXƒÕq@ÅU™ƒ¤6.ž»ì¹ÃIÒ«k:Ôk*6Þ/‹üx.Þu á(jMl)+FÌ[¥/ò|g:iXxª¹y+(Ü›çá,¼H.Œ,ñ‘Í„R> íS‹Å|OÙ_æ2õàYìKO¬>T†"£y.EQÝø!)Í·À–˜Ã;é3³øhN«@wæzAä¬QwX¬?q¾²½Ò%l#/‰sÆÀ`²¸QÜÄ6¬ñxó*øÆR‰×¢•úØ9¦èËÃŒ7\'FȈuå´­Gç6îNÒ¥]}á à.2 };ögÁý".OeE!}VW‘ äšÒ^øà!ð[+ÍÄ8ý+˺K ºøg¢Þ÷`}}Mxh}4·1ïñíä®ð@Kñ¯‘¿úû·ŒfôñÉIf~1VT\9iÔ€¼ïé‹cØŸu_ÇOÊóņG{~bƒua"h·M†<ÁË^åËèH?WøÃEW,]×&Mí¾WpæÂ¦PWŸN2Fü7Ö>—â‘—Ûª:¦elÏÇé˜;ßïÎC܃ó‚bö:†iöé$×ðÔ%¼K JŒ¸;DÆlÅ—ýjÎ:ú Ý?>É<óT*5Ž ‚×1Õ · ‚óL2“TžR;2¡–O$PÑ–Õb H~Ì­¥°" É$îD¤Ñ›—³z%0ï_x%¬Kœ¼,µe “ï0ŸV®¸ï5œÆ…\µNáÃWàZ8mh¿ª53Kô…Õ‚ƒ »OQš«Jd­uŠ4H¯€‘ZÒÊçäÿ¼©ˆõÀh†èï:¼“L.‡Ï ö°ax‡_ƒÏ•œœL$ÆÍÛnÜr·¸¤óhV>:òh“ØèǸY‹Âð9pš®§þNc{E›IùÄœ¼ù–uÔ ÷T:jghwCUMCiE÷R›Ž¥ZЇñ‹ ÖCí1Gì%*Þ¨æ4z×Qºâ×Ìψ<[œˆ ‹‚¬õ=‰¤MÔ¸¡ðƒy’*cwVÏš´¶ PU"A’ºòñß.â(Ûd§Eœ(9eVÙøç güK|Öì[²¨»‘‹” ªK£ii¢š3Ÿ™#Õ µ„×YÙ À iÑL»X3ŸUál{ˆ“Ðßê),Œœbƒ¶›rM²Ðc ¾¼ÁœsùL±^”ì)Ä –ìOä±GcXJóýg®±zp°iÔÝÅÙEšÁ©Àr³‹ Ýæî]hÐFáMÆ^™Ô*vO´ß·<Òb¨}d¬ü!»´Í…(O÷°ˆå@¬¯n×Ý•|TWÝñ+gôHu‰ªís3s±5¼¦“ˆ6t-þËâºh!ô+ «¶ÓòŽ×; bsêºÇ·Ã§U6-?gŠBöÜè¬Þ ÅoÓÙÖIñÔ©nb¦HKºGÜ‹£Ü~܇cÑb<ùSûD3jn|¢[ESY—8†€ ÷û¶¼fŽ9Þl¯9´½W›ßàä]¯ðCØàn|®q?Ñ.ÓèGìOÔè(ŽªTZ&éŲçžïZÐòßklyÝ/LãNDæ[ ÆžU;X“+æ÷.LqzþCÊ%Þ†ŸëN L˜ç Ö„”9¬½øúZ>G”ôþuÐÃ¥øÍß\eŸ²Ø_&îöÁ ®ìÁ.üZdèÅxz,n€ ? —˜4á Œ>Ü­GñPi,xU&}5+h"Qì+•Àí+\Ãpr\Wg/5:Œ-wRoïß}€~!þXô'xéÎ0Xï[*þ²€Ó°~Ð}a³ð¶Oª'Þß¿©tÍÆÇ;£³ÉÊÑ霵ne'Ú¼U½qh–WVwËٮ€Åņ?Xtɦ،Ó@,õÈ”¬×n}5|Ž%E.¦¶ÉÙ`4´)v‰dlæSêÙû*Ê™÷¯ç×-—»“wżâåïO³±6þm©ÞrykÅÎy"°ý|òk¡€RéØp—V ÊA«÷©‘ÿ>R\iQ jŽ‚ãœo–h“9òÚÓÀͦx}hÐDÇ£ óL\ áÁrˆ–ª‚ñ¥3ãÄcJêP6iacœQï*JLM•¯ú¥êèóŰ#·éi9¼÷cÃŒ–ãŠVð,ªu/{>ÅÉiJ,¡¶16Û‚&g¶š%šMæü¥'èçgdò¨‹[úwŽ îçÀÀmZõ•Hû:(ËDjôrØU—o½_Å•#´}m“ñ“6éäf£¢ÅÆýXH¬ëQã@*A: ·›œ4Äÿ Åá^/sDžtosqÄÛêyF\‘iï© =ÑóË8IN ’Ï#”1b_6ÆÊØÑ$GÓY6ÎCþÖ¼Ýðý20ËuÎ,¥ÀI’ªÆ ¡<áÍúeiŸ‡?ÅÓ•øéO¨kO wª¾ ë(¹›.P²·‡ çk‰¨•1@£ƒÑêLnº/‚(`<™ƒ|G¤+äÐ:oÃútK¾0´ Ò‘¯YîòË},Z拇¯‹Lk.êÝÎt#Ï{8wâv¬Åã2ùï kžë¥áJóÙN[^¼6o^(ÍTN:î¸vzø2$ÚÛ„4<;¦.„ ¦÷lÖâ|yŒGQqì +¦HÎsÇ{ý'_jsíǘè1ë˽5ñ½`mN©šJ‡«¼~só£¸/ƒl‚…oêl¤jÁH]dËñ'“MϘ¨pÁ|2¿±#IÌ·³z§2{ ÄÎP¯RÉxFÀ²¬x[".]᾵îWSì3óìþ¯“³VÝ És=&[µPÇœ Œð'N§íOvÚûkʆ?2à´v›çô›ÖRk›[£îŽº-;Ó=«>?é†ymD1sÊ`«–Ú9ñêÏVæ1SŒÚò €\óÌ ­DõF1Ôí~׿xA!¢Û^;å¡p1\9Q£ÈƒÓJü4uõ^ÑqEÛóÛ²ž ½’oÝ#%„)¾RöF%Eºýƒn[bEà]ûÀòªÊ²5SEØþ¨¼ØžßÖ#øIª ÚùƒëÜ3 ¿¦}ù¶J aAÄh¡-Ôà)$"Áluê"âÁ¢9¤?år 2;ŒŽö‡WçØ´ô¿Q[Üž|d=ýièȺó‰ÿ ò…õóc¥“¯X¹Ã¤80¸¬Íy?âpýÞBÉ–íÍŽO0d«Àwéã)ÀjS¨æBJÅ©ç>jÕn uÜ‚ô#áo§Ù®œatûÌܵv@ãÛlî]u¥¨ñÇyp×·l{!YÌQÍŒo¿³bj mcv*›ò`hôS?) Í½Eúƒ œ×ÏÓn´|ä¡ét¡Ö®`8ÔË&×ñùÞ"cËb cÙüYpsÊÃ’å `O{îâ ž±îsµÊ³27‘!fÚãöXWg:=%ÅôqY̸QÆ1Ööœ¢W"Ôä;$6ëÊzÝ÷ã°×oò¡ç͵r²WhgÚ 80Oç¾g&þR­Á‚\íï6o/7Ô×/¶ÅË]K£oøâëÝìć­_ ¢ 3ÿ )zU=¹º›-ŠÃ]Ñ ‡…?´¾‡rA%&éjÕšâP“l¸‹w:ºMѹXÿB8ËOè$J0Ù„|6Õeß÷F%åF9É,šÎ›%øå¸\㾆ÙϾ«‰‰ËîvOßB”âH¾ùöA€bà†L Ý"´BÀörZx1@=&Ï;3hq*§éj‘–ï^ú<®c oï•li/aU ºyÛ$xë1gÕt«Áj1ÂÍðXþbNݱ¼µÚµ «Ä:¸ ¥´uÿ )Þná|oªà>¥<µÓIwlg-Ó,[ ™•¿ƒVôà ߈ËkóhS±³)øP˜YK{…0»—ç碌¬þO÷e+Ñ:Ž¥­Œ#l/z‘ –”a âG€œ%I±'WP—×W}”| TznrâߤiA¹é¤óí“y*,¢åü§Jû#dIÒôÞ¯fìù)1ÇV4a]ªòg ·|™CC‰é¸ÑfÝ‹ÿ[$×\«V]ð®÷î½F’§rà³ÿĦ9ÔWaâ7 L"Û &ê†Ñ·£™ÿV.OÈË>’”îû^žkÆi°<’ú°0~O¡3ÁêÊ+©ú*k›Á>°§Oô&—ƒ¥‘_©ÓŸþárö>tvÞjP#ê»ý‹£×Òx©i¥úh yt•­{#¶e2G“±—f€u/e\|£ú~ë—>¢¼âp‘%7™¦šIÙžæ2Ë ¬Tÿï ‹%:33¬æH…:§Ì\ ÕŸÊ® -Í£Þ¼‘9€ ºßU˜^„ÔïÙÁÇtOBظwã:_—CË<.YMÓJ.ÁõÅÇròQpv‚U™gMÐ4ÕÙ8à^ÎÇ`5Ey¨”ß¿`;c²÷PÝ2P%©é-Í3cç!Ù)çÖߊÄû›b4x£ÊÕ²Ðy»'(•Ü@ˆzXŠQkÝç€ìÛ0ˆÚÛöôžÚŽÞ멉­Ð‘O]6¤3}‡pš¢ƒ¨D]há¯÷x.¸]ëˆTíÅê(²¥MiØÙf%‘'§T2µ 1Àjò_÷ýh•ý·TdèÁQ÷‚ºšÛf‹ì¾& – ÖÔÁß_!É&É­CÃV,‘žò§H½è¹'Ém˜µÜŸ4p‚€ç6“ˆ$§Š>*U=¸ÞÐÞf;É ÖíÓÎæódH#¡)Öâz0ûpgNH:šÉy„y”¨u¬¾E*­€Œª1ÂÍðXþbNݶ#’pþ?ò•|”jb>×ýÑÇš¤ÞgR@¨t…}ÆÝg`Ê¥… ÈóŽìRncÇ8uÉÇËó«L!elðt\«@hËán2щ¶0Ô@ƘCTKZ…  Ýü/ÞÚaªôyÆl~ |t”{ó:{Y÷*j‘‰dr³„Á¦›K¨¢jžJ1€§ee+½<$Và°~¹„’o\_5¸ƒ8¼sïZ:5r~†ÚK(C¢&òÙ« ËâÍ0iè!S϶Qa[—ßíOɦ8B a$ð „Ô–=ÃÓE¸lCd¨Îhhöí’iÉZG(Ï– õKøE‚Poðá6ïï\Í”Ä\ zlj¹<ÂñΡ4•2o¯'SêI®t8Ú×è…g9Moa3•®½ß,T%D+2‡¨¦Ýåå¶XV†vKn^8Y=w³ˆÁÖ5@ªÓR×R.æ”X–ØÒžCÅiAoQ‹ ÂV$:¸S»†XW$†K˜'G>°®ñù+¦ÒÛ`ÀSMé´3r ‰—ËúÛçåm]k꫺®£5ƒG+‰gÍMR¼Qý­Kµ§5–øxr¤m£ñ|p® Il¥‚/ÉsüõÛ c÷ÞF6Ó„¯ÌLC£>f7‡×´ɇ„ñ<Ú cYFXX2Þ¹XC‘#Å웚fSÄò¼šlŽê©ùþ½½+<ünXJ—–Ó1÷Œ°ÇD׬N°’Šþ&¬Ê¼\1¾À”ãGíüs×iÔ^?‹ï`$ ÅetÙ꟢¦‰,d*¸ÏZëŽÚŠ5µVBf5hi^ "gåÕœ,up3M ™ÚGõeÍÏb„›ž™½fÎÛdBRŸèžj”¬ù€Ù­Î¼ûõ?(Ó­ bcJ šY”ޱއ*ÿ‡µ·G8ƒöå8#¼‚Rõ}Â~-8rS°…µÆ·Åäëû‡°ÌEââ~¸ut‹®%á”phºP·0‘Îj]ÓÞiýeɘ™Xð RŒbσälÞÏ‘€¿åòy¥ª™Œ#çtl³i"C€­×@KÍÅ”Rí^އrî¯öÛð½Ký~_Û~Mt}RAm¼(zW*@cÍẂ³ÕÎß8€Þ°:hLÆEÿÕ`m,˜(·™D©üÀ;›õ¨Ãþ¤è{%hà¿~™®«5Õ¼}õÍ’¤P%™húÉ?_èbêžùwŠÿ@÷‘ 'í´ þþÐ7v !;Eƒ‚"ó‰ œ¤œÁÜ„}N)Ï9ä(ÑücîqãËôºvßíÕkЭûªÎ Z¿ä™¬Ç,=Úa?T.ïWgeóÏF[è3—m ? ~!Øg£Ây¯(áqâ­®høƒ0LY¿15ù9Cʦx7µýb¨C¥ŸÂ¡1S%«[’qsÒèbÞÖ}©Rwr½y`²¥u«÷2ûAøz`—É#ö¤t¼c«î„õ…ÚWK61Ä'½] ·ôÔ³Ñgzçow=Ì¢ð&²”ñ|òó:Á—XÓ«K’xæRÂó d†oª=?a¦•±Ì;'ø³vûeuÌ/|¥Ç l g4L¼š}æ8+D-ÇÌt›Õ¨N,þ=¦VGõ?4¡ŠÔš<ÉQS®dM96ÍC‘ ™i^ÖpÔôÑ~AŒ§0±[W!HÑ;/ZÌÎðâÚL„*Ï~œðH¹ ð¤Ý1]o}СÔ›ù<×UIÞ©Žwh1ê`Æ¢ˆUþ‰Wf· ¬*]RkTtþë”WˆÁ²h†[*øœ R1è0›©E[íbi,œØÒµºŽþÞ|D>¼¾«Àø„A×ÝMúæŒó·86 Žø0ÕZP÷~qV…ã‰N4·za„º¼–Þv£º{`)eFï#søóªlŒãá[²÷3#´ÙÀrAyÏ:bKz˘"¤ô T³è0÷mÔ\ˆ¾À¬úíQˆ~%.Ò`…ÙÎQYG S£ +ü¾e8‰-Îë?øB†sãdÀì×þ~#‡’<5ÍtÝ*NY’pÆ!¬˜âׯBP¨òÐý!¿4Ü9jÕn ‘ ™{ ç±´ÈŽúUe¥8[œµL¬t–fá£pÆaM¦ ³…ƒ 'èÃ)Í‹©(C½E¸³®0oó~z.®óýÍ:€À«•lqÿ®ŸTgNfçI´c¹9Ï Âõ 6…¥¦n\SüØkÝß²è X*#˜rÄOñÆÅ©Žk§54Ò±”Æ·îZyH È ù>{t{Óð§ÁXQòºÄgå·úŒWæ°‡ï¾\îBj½šz^H¥£@wÓÆ»Ì`Ë~ãj«T߉h­¯»,•ºn¥ÖÌ=­h9<ì–>%e©OËíà1dرî. < Ë—°”&w(U±s ºžUŠñìfØJqÐ Œ̵ÿٌݱÂluCަ Qx‚¥_ÄY‰ì¿!Ñb®ÍÅÝ%¼™*¬Ö«áúÁQhÉïB^¾9Ùé¢ñ°5ÞÂQ®è96=‡ ·ªá‰ãèz(0vPV€ú]ðÞ"÷ÒÈ–?Êo)ûÛù%@AÏeȯɱîOzÙL¥&8Þ°Úû|±¸ˆ\èD‰ø®W}£U¹î~~õŒ(Íž?ÂÝo ÌÕóŠk=Û}¹bÉ[Z;6øÇí'­s /¾Zzë Ó¶Š\GŒ9&:®szÎ,\Ôª¦è'ïÛlqì¶9U´¬~ųU*5Ü2S@ Æ¥)žkÛ‹_kb¾ÉÁG]KI´TM m5íM¬dÒN}ÊéaBÎŽPÐJÕÄ¥†­ã…ŒŽ~ÐEë(÷Q£9$ú·ÄøÝä˺ËÙÕëPÜ­i$…nßJ GUŽ<²L >ßJZn×Ãý%·Ó,x}ài¶ÅUÏd¶?°ÎUJÜçÉWÚúco ž·Í£‚¢‡¦& ¹‚òÈcû滊"Ü ÎfÛ§Ý®• ‚ÄyÈØ&hܨDK®eûÛ[܉U(ÎÁþ¾QXW›‚Û>±¿åOˆMÆ*%NÓ>õ/eëhÒ)Æ”6µ¶@òË™çˆT-f˜Ó(BÆë†Ç4ö¯!¾íÎÖUaŠAÙÈ\=ÃÀ«>ñV£ãí8`Í©àSàdpÝ©“Yä—?«³a„̺$ÞXó_l÷?¶Å¡/ ¦¡ ®=ˆ gÑ@(¹¤'8¡ˆ•ÿ P• ÛÖbƉ«±ôm¸ª©±·Õ–¢dwè@Ól›À|úãö°?Âyï‡@ù"ñ ¬—)KÇxÞ ÕÁÄ›üJ—]ÞÿYLf ±™€¹ ž:{ádkí«ƒò›°CÝx"n6{ÊëXëÀ óÛË[È¨Ô 1¸sËôFÞ)hpÎ46’qèJBÑ=-áó·ƒK¯š©9{W+Ó#$f'•ñkó9ÜîÆüÝKN 9¤BÓîÙ4%-±µÚñ;yGCX;›Nîyãs5›í+"T‡ú–ph”>‹²< .©Ý‚ƒmý¹]Éý÷¨›ÅÏHI„øQ-±ØÖßsêA3IB«ÿK˜’@ÌA[Ìe´ødùß^k¬0ûtjIõ§¸B|“í*`¡”ÝðF9O˜dzoY¦ºìÇOu,:þ‘Ï!?|`rëïJÁ<ÛCÌYOö)âÒOKŸ~ŒÆ¹›72HŠ’*¤QEüº.Be±„3QÕºÉÀ'­i̵ –J/|´Ñ¦—¦M1­»îø™±WK!Bä|Ð$ìB¹“ù’ùë=¨³ÎÅ5;÷kçf‡n¼ÆJ=ÄoüaHÃuÊ[ËçèŸ æ ÞîL&ø#ñþ^m§FüÓTs±UDâoO~èt¥F¯éê¡~y¢·Ù•潂›×…0v 7„ÔÓ¾,¯:ݳqÚÅ÷Ìòæ‡T‹ð!üRnŠò²TOÁb Ô‰²G;¿u+º™F¹hYËØU ñâ‘q@Ì“j'äšÜvD3j<Ud-¬‹$Œ¢Åæ´J>Ëþ´#Òkñ¨êx0ÕÏg¦Š¹!®Bƒó|AcþU†7Õ,jmÈæAÈc]O¦â­]½ÑÙÞôòùkPÍ`”x¿ƒu±aŠÜP=qtŠä³HÎ’µÖQ𓸣îiõˆÖÎÍ«A ÍG¼™\)C¹f¹!ÖÕö·ÕÄ;fÎ8§i]TYõº¥–ÜOû-r EÀU?ðñµNV©ëþw§ªL÷ò¥4¸S·L‰ìÚÒïØ>£'ê%·P[‡.mB|ºO9îãDºüb šÐW(;³ÜåOÁ,ý´1yÌbáz²Uä§ß.cÁò1s@v˜4ƒ¸ë:÷ìž ùš¯J@b9Þ Òª’¶–(J[ßþ´ Eëb­Õ‘Íjw…󿸙¥DK="ƒ²I°uG–öAUZ©ÒZiæƒVþ3ÿ¡¡µ»?‘Àü0)®/õRx‹E%¥­×ÒÁØ<èUJŽ£:Ò^0WÄ1eÙ 5ض¼ÄHlņƒ¥TÙÑÓvHj×X Ï$rPÁ4ÿ3°šµ4vý°ÓùÚ¦võ÷/FW†¦ü2¬ç"Ì»#iòì#@µÎ·Z=m)êfƯõÜ®RÑÙ;u­kÁK‰f‚9Þ@%ÿÊí1Ï#}±uÀgä†$Žñ¿  B_” ÅÙHÚUêmjVv0gõH„vȶ _9ž²˜ßBg‹຺ïÄòÍßÅ0UKÇ!ö…µN\pÌNuîÅ6g^þí Ù'KÈ“3¥È-O¹ç‡óå{‘Ê‘òV²£ª¥û­«%K5}¨%_YfÍVI6Á`ùPþ ’®n2d؉]:ži„#´÷Q”ÄV"Jîžhð%h®ýT¯çqÄ·ª ¹Þ¾ š…¡dì©ØøÖ©Ào³+–H˶‚S€\×ñ˜öÓËý†^³g’^uÖ熳J)âZ3÷»ðØÆ6!.ôvÜ6»ÿÑr')—ªÚhð‘n°U¹]?§ä¦7/œa4†Až¶~®#2Iä7õÙ!Cìq긋.5¿ñx…° #TJŽÐdmHÅIáš°†sìÍx…>ené³ÒÒTÏÀb芕Œ¿#Ac•Cs«øeþ¢[*W0–ˆ›X ÂÍYѼ8ç =ÝÀÀÌ”Bcm2^yñŒîê0a"_$GÖÌ[ãôs9‡±,¢kR'GÿîzuKš~¦:µo¨rÌÈÙÒÀÑ·,<ÅÕÀFzjô¤¥Äkb„öSø»éÐ0[¿‡]p‡ÅeÑnÑý¬&y¿g¯y7À$ly¬e§¥´‚íÆÛx%®Ék*êuàÍô8‚¾8Ìœ¡Ê«Ú äï \~_²ªPo’@&²Yi'C½X¼SÑEçB¹ZmKƒâ™áä?Ñ­Ï~V”“ž‹ý*í™b7¨u LÆÌ Ã&áõÔÝ9Im Ÿ©”øXÛ *k'Âû™fVÓI$ŠÑ‰_MA>„¸Ø5‚”œ¹pí…ë,r t¬ ÞPÀÈ@WAoâÑîU¹p'j|^wûã—Ìü \èó)*€ :¹:ê%OwB°dÆäWŠ'¿<­î‡‘~¼‚Nˆu¶§å|"†!þe=(µïË9ªÉB;OÜ• ÑFäšô”_ÄVæåƒáF´i6¸Jv.-nT ʸ=EZ6Z]ÇGRĆiŽAÂ_l²cZÖŠ] ŸŒ¾NÊG#Þö")f™¯~Ýܬ‰ ¶ãšNìaóÞX†êËÿ-¥­â:ƒ·Zˆó#'KþJëRûå߀",¾óóàºdà#Ȭ+¤õ8,uÆõT|”Mç..›YJvSÚ„í0x‹¿:†’6m¦v7ú½eâ³o.k嘙9ÍÉ µlZk‘J[tz~âl#¿÷d_Vç¶ i±ïöÂy{(÷›xϤ¡”jm!â79#a¯oÙ¤9‹34RtÑqüq¹ °Vy¿©¨“£‹Vèˆn Lì†[jI5PšÜ&Р—ø4†4¹i„÷ܧ‚“–ÙÓpŸÎƒ¹í¾„üVðyÚXB‡eNi \tB’Æ*ÌÞŸzUíXŸ³&Q•_Øöµ›'è$R§Œz{qÅ|Eç±ycžÜ?ª¦Ä–7Ýåßé’Z:[bc4‹ kõÕïw>—!X¦rê¤&5ÙÜoVØ Ö’J •²hÆn$d€9©p[–òâ±v‘¹øs™~–L£‡½æüTИBÑå=‚k‚@¬ôÍ36‰?6l»¤ì[>­§Mv‰bt„Éû×5›Ë„œ@¶´URžöÚ$ÈVÙGËtZ?÷Îx& ^¢§ðž ?ñ»^J‘ÁöõÙðk„i“j~!Ð.b¡¿JÈØ_~íuG툗»ÃU‰ËùÖGªÕYTŸ} jn›,òfOþ×s1X¦†Àžæ—§áF€‡WÿËóydÙØÇi"ìöó¬>½k=Ôìlv‡»p%¬ä|ßÂUt/²Ì§ptDÚ’Å$¢m¼}Óý(»FðOôy3D·¾íæ›Íöáv’­—ðIÝ´Avÿ߉ΠJØÛœäª[/ w¯ nól!üŒ2Û®ìðÒ€BÃ:'ÁsíÒvSŽ/€ Ê-FK³ó’PVGþˆ¾ák42„–èûTÀÚ_ íú »NÖÄ=·›;@»Ií×ó¶ai¾óËYD…¾/AömòÀŠ_Ø/üY›ÁǨV(`k¢~ôƒ@—”÷™î¤ ¼¨‰>ìúÚ ¸€†SY“#k÷Z*KþÊø‚î ȇQ@ôIXa¨ ûPGwëTui38³*ŠÂdzÁEmÐ2Á3mõ <$îý *ÈhwF‡¬‰´ßT%ØÀA#—­+‹qù¨L%Aá;çøãëmÛÄe;…fû>\ØA×ó”“éàîs³R™R|kkç4þqòaîCKòq„M¢Í‹sU¿öÆ„“èd&åÍù$U½}IøziaŽel3…XÑ AXóVÀ`í/ f¬Sn?…ªB~<ŸmÅr¸mß.€“ \¥átÜG|¥œn.è²¥Œw!„ÞÿéÆ:'[ZbÅ&AVsô1RÆ’‰ÕÇ Yg4\Ä > ¿CÝ€F4ÈS1ó\},—ÀÁͪ%ÍÍÌ%­ &B¸ŒÑ–ž»ŸÓ<}œ¥ÏAë»wºìÌD”½#ô>$gÉð‚ÅÊ_æÿ´BbÇ…ÚÑ–8_žY; ŠûI†¿2)€$ÞyYFç°‚M¶Uý1§ý¥ ºP (ø¿KNû|#Eæ„ç‚'PTŸÞò )§bZqÅ54 +a8²HMª&4 uŒà*ý´#þ"¹ÓÁPŽÂO†‰§ð†nWìðŒ‰Ð¼ë ëg‘ã_µ½j@“—Oö²´-«Ép+=°Œ’Óé2zy“Ýa VØáO”aj“G«‚Ì N\'€üãt\Ì¥`|0ÈüžBÕš(ºèÌũբ–36öíò²ý”izSQhÇŽÔze—-ô,Œ”oêè”géÒ@î¿ÂÈF¢ÙÝò‚`z}ÚùÉQ2¿«ÁD;´Aÿ¿ÑýÔÖ‰9smNßu‹Ç–Û\ k8[ç\¤ê<^[êwswÏÌ0€|š ï,ëõÑ ™ð™Ë¿JÇþ‰,õvÚõx¬’Èá2&Í/U<à WÅzN mŠ'ä¥[kÉkWÄ«EUlÝi+ÇÉw›ÓÇíe 2YékbÒUFm›Ioj)059býTÖüzºðRiœ˜ )DT3)ZØdQ÷Žç@ÈõÞ¡ùm³ãÁmü$‘•X…»\$9‹V šM‚ÐÇš­b&]ú/÷ArNòæ:'È.^d¡É»gÉaJAî- }+»‘+Ä–ÊÞ µLà³Ý–\qì3´åDê\`–4|16GYc’r>\ñA`Ú OKó+8Kï—:jkؤ¬ÿbÅ»/ë–}ˆ”J‚öq|q)“»P3ïn¶Î»kr›Ä_ýìp/1‘zJÄÅi©×Œ^á¨Zo8­“IJÇ]®FB>JMW}b†ØŒ¹ûŽŒ“j"u ùª‡bZð \¥L¼7³S-þdy51ö0ïv äÓÍ釗 Ô‰µ²Ý”H¾féÇY­|–^kZû5ÂðmòÀo Ñã¡1Q…×Ö¼3dêâÜŽ{ËZ>Ì⃹&¾Ë¯•x̦¶¸7Þ#^cä«WE âp¤]•…á?LpÙ$rµaô¾åáIÜn†kKå9ËÖ¿õi:£ØSÍÙ"®ŽZûzéÓ}á·+£V“¶‘’NZ.!žëgÚŸ‚‹‹-(2µ“¿Öz׿M‰?ãUÓ…ñFgÅÀi‡ÕfTÔ¼ïQNÀ"ç­(´lïë#ïþ°ßí£õ¥… ƒxã‡èPÑÒÑ:Ìi-j2›Âc›¹æî ji¿ï….® ½¬±ªÎV4eì䟰©?tòš¾g½˜à{U^gîa V(#® ž¥ÎD?²ðçUÏË7@IŽ‚Þc_s&,¨°@ wV §K¨\ÒÐ31«O¢þØaý‡¾ÅðŒ†f{i8Å‘%9>k¹ùê„ ¤µ´I‘žÛ<.¤6Ö†•ŠkS MQ ÇéšÆ™%¼R4>˜óþÊ ‰/rN•9çp6 ¢CÑÌ}¤YÇÚA ÷Ð$`xÖ•oÖÝ×Fò½ºϽÇYüмXÕAcYžz™Ö‚Uµðlåß3ƒñ[–/µ‘1GIÜ–:XÌ*FÖïP–rUE™pÝ|/σ4%˜1åæÁ,(62ùÏñóhv>RdÍ×óVNZ‰ó¾±ÏŸPLû3™Ï;4 g6÷$(,P(<ÝÑÆNÝ?Ú ³x`àû"ŸèL‘☣:MœV4)PSÖïðêçÁˆi~¹Cw@ôy&¼i ¯g<ãceî?dpZ É gÔŠ•äÎJ¢ŒЇ"ûõÆD¢ÿI7ì: +õ$VòW-žR‘b*ËnO¼q‰(KˇM“ƒ ¼’¢,1.à+RÔqj7— £Al0îä¦ð¢+=»Â-GÓ­x]ÛÕ!†hWÌ›¶ã×<©«Ðà4ö‰“Yì$`|ºiº «œø–È£‚ÚÄ ¬§Î6/uÅÍÁ‡™xvÉj‡rh2dÂ×Ûféx<â“pþˆ î† Ð:ß¹K¨dŠÎ¶dÞméN{¶üïeÖ CÑ FNtüÄõË.&Ýðn\¶pí`E@åv%ýÁžÇÜçs7!7ØÎ íù¸„à0ŒãoðV{gª7»\êskïã‘ÖŠ€ëv$8› · ø‡¡[â5ñãMÆ3ž–¼ã³^^'‘<;Æ9""£8ïåÜœˆï®3ð~ív‹¹;lñ?6YHà@èfÎû|Rb´Ýz!“Äc¾&JôAíŒÆ™_×o‡ÚPE“²2»-’YÛÕzÕo¶Ó¦{2*FÃê¯K[s\nH‡ù÷¢>áê21;’±ŸN÷ü°Y"Å‘Íõ½dÜ´í _^&Û`Úï÷nO%Äð|šþ·ûÊé€÷ÖC¿gˆñL̯ÑÍþHtY©(zÉ|¦³¦™Wþ¸Ü)¬'¯”ÝžK:ž/¸]õ TrµrÓyôr†j“¬Ã rì‚«øXí+¢°½3Ÿ¦ÃzQ±ØoÇ únΗ3çžÐm"/JH=Dh·„poõ©³~T¦Ïm…5|Ì)1qu«qÊqâxVrõÍ™*k;Þ">ÆÈ¾!“³%CÖh ö=Ö¡Yf~ð·«4€XÝ©¤N=Ü\…ôTÊÄåÞÖ­ççGG‚ƒE*àê› †Lî%$]óàÐ$ #”§²î'áñ9i¤3ª[zZê¿Iõ¢‡Ë§‡¥Ü/.~;•¦ZÓö‹#zZ•@‡v§G§Usæ0³z wpÚ…,$%PÅ/™’“H†¢ÝHW=§ƒ!wò$«¿,KW+Ò'ˆ¦+{±&‰æŠ°rhh * ËÝ /à©#Ô×Ênï5u`@eáªô®¤íæDí|žh~½Óº+åëõÓšÅЫ ˆ“ò1|½^uú¼rö÷Ä*fTw‘*°ÓÔR¤‰IÕŸ q”–«ê0)Ïšç–úÏ­CòôcÍE%½”çÑá¯Þ0Z¾Á {-G¸ø8e ]qUÔ­CÑ`C”&ʰ"ÿ¡¥ž‰¾ü0}êL“ã¬ËN/€/5 ¦>-z¸#‡­$¯§A=ÌuE_6NªªNÃW*‰Å™oX’k‰˜FXk‘mχ4øC 4¾•ÉÙ+s#‘å|=ì¤'X m°u kì†lÂ\¾š§2FC ”£yÒFו(EØÊŽ~5>û!Þ­*‘d8¨ÊüDðÎñHÒ`òËCããÆå0ìåvA 4ç í_ã&Eho¨OÔ>\ ôî¼²Š–¦ £ÅGEM¼î¤i³ø H±…¾Ø ƒ#lì1᤭¿ªÛ0îës¹Î’¾:|寡˜´XfŒ‚ÛdÚ Í[×c˜Ë4kí¹<øhÌInR½ý½ûN)åL°v•0c¦G©€…XA*¸X~7õçÔ)¤(̆œš­80§UûÆÌÛnûjö÷ùРŶÍfW²9蕺Ö~-¹³Ð|›±œž(nv ³‡âᇤk™R]\‘íËОoiÈs”õS‡EœªsÉÑo!¥©EZ|'mVÉôÉõœc® Ö¶Ò¸„ø—t€Œ2/yÅéXˆ† —Ž¿­”J8»P¶JyÍ.š“svAÛšCp’::›9ß¶ƒÃ|47ËÍ)ͼ³º…X{hJBºã•GE^7?ëÉNŠŒ™RìðôÌu¤EVJ:Ü¥eçShš` >šß@ÌËŒær|ÄLSm:¢íºþReï÷½Z~—û¾h’µ,•ÍsÍ¢ÎP(±©å|Ç ¼+| ’öÚç/`‡ñ÷-Ëw¸4À#Œq`ÖÔ¤·€AyHü¿ &µØ8Ï„v£Iqr |;„B3÷•ΚƒúÙ e]˜†Î µ_x.â ©ªšX`ønVżëÎë®(9_QåVT•²þšwÑn}Ü~‡,‹V»Xê±vé½ùŽƒÅB4˜G§ð –"ˆÔ$ȸְ¿ýhE´i“51Ýi}È ˆ“³Ï û—ÔÉ£¹éº¯kÙܦ;Ê>‹XÌEÙÖ½S#—n«²¯ùoð„æÒ¬S[,Ó)ÝÎÅ7a˜ÿ§Œ$£k)c«”c;tMSm꫉·j¬%›„Î9¡F—¯wü]"a©O™g/ÕH}×®½8‹RM‹b»í™hzÓºü†üúY!™~þPpýM*¾ü9Mm¿Ãû0M²»c¶¶?_¬ñ½ñ–4Db¿×˜2—JSkÇš%„zxú³i|ÙpBJaJj¦“}¡š–´›:g¨°yÆ­b¼³Í Ù’:ÂOS-Á£b(У\ß0Ù1‹ylµNÓ1üÃ=gH‡ã*êýoñâ+þÝQÀÙ`eÅÄÛYeÛ¥ð <´ùÍÎUT/φFºó[Ÿp8rGV°yÔD/QHo ö#QaÀ°· ź:¿%H^rMu‹]¦ýþ0f?ÿ¸dvéfM\5…‹"’LFžª¤Äd+‰ ³—sÇÆ(Šç8vG”7mV8X'?sR±GŒJR“zZH­× Ë­kÚ›ÐqEé1ÍÃ:w½ƒ¶´9Hõh™]Cç~÷èÓS@ñÎýßP{ªðžE?§Ó€C•I/4ÊQþðîij®Û-w©¹°ž„î~Î-”ç!B¸ë}>%¡cCÙM‰äÛ=ÝÀV‹óüt²bi$ØMtƒAím#qˆWŒéÓ±FGöŠÆ¨zÃÞW?®y7U\ÜÝp^p£é_é5z-®þK¬gaô[Ý©íãb°L ºï¨)`Ê™¯“[ë§æ/¸I²CÞÿØ’{w^Wã Tb!P>Õx•—è.-¾þŸÅ= o ]sqBã+öy‹uF#ÿÒ2¥B~3ú­ÎZL„14^#ßxtbõfÓûGAAjÈ@!‚²ìØ“†ô¯D¹Ócà„˜¹SèM ¦e'äUÅ^‡Ÿ:lx¡÷½¾Ù†1Z·æþQ‡l’t`£Ö¥8æ·R:Ñt•À¬¾ («Ï[õÈ*+ñû’Bßñ1˜F&“ÃD·Ã²!ÔìS³æÓ$*ñì+˹õàØ3.ð¹t1}O±Y•$YxÔ"¸?J‡Æ¨ ¿±hq¿ÿ®;Ns„lf‰é=ÄïX^‡@•œW¼¹ús új®Åyc»~wUXjv¬¼ÁâxÒGO^—GÊ aþYªÛÑã mÄö²I€Vuú›L …óôqü¯ácédÃKœnN+Ñݬð#Lqò.ÊÁóRKºµÉ—ß’{£¢P1“ K_`ÃPD`ùYÑP"±óö$"$WH†@0ãÁ·èø{Œƒ½âe÷…¥ë;¾¾Är~F£Ð¬M äà~B¥2Y«&ñBÑOïH`EÎ)ë¬Á ˜øò&t@YaVŽˆÅ¸æJÖ‰F>öXÒð+$U¢À¹¯Šˆ;ÈÏHžNJŒ"H`hìGñä¢1MeS32¹cƒg™Á¹´À!¦ÑÙÍÓWÎü´“æ6ÚÝ*Sv˜]##T5Ô£Y"2ž¿|!z µˆÖ G‚‡õ.n\‹ÃA£fByŸ#mk2d«%çp¦ÚT.À-¿Ú×q,’齞 *4øpúTŒ½K•¶ Ž+öjrMfBž¸lÃdÒ¢ey`nÕ¶ã®BZ¥ä!GE ‚%„øÆFϱ>k*Äâ%o]IjWr«@¯jyÃK¦5ç8j4ÂYçp‚}9¦èºt´Ãªôl%aF¥÷¡ ÚqYÃ`z ,©c’ÌPžCχg9ÂOºqDå½DšeÀo„ì+sÀI~{ä 1Ö\…ìþ‚úÐãƒÓÈR±tÿ‘(—ét_dr-¥~¹A™ù•c$"عê=4‚AâU}ß1joDð¯4lò:Ë4«þ5θÔõI{k±§ûNù‰â&L– %³Í: „"éûƒvGÓQ~]I)’Y€ã"’/‹Þ+ D3k |5—ý?è±ÛîT¡û¶‹MCPÒÕ-³L€þáæª¸ðA»OŽè,œx¡°c:. ˜VŽ>Ñ‚á;vå#ÙyÛˆ»¤™ptÇÔ4¨Çm|ÛjÅç:ùp~¦G6±óâò8Z>ÂÓ•ŒyH¢“ÄÔ<­8.ŠÉp}>z¤WQ{}ÿhCLý"ø4_Ã׈Ç*q¯Š"‡„Pn„7qýuTæyT9öÍ£¿ÝºùkË;žŒâŠN¤šÕgÔä„}w Üƒ-Ò€µ¿å_¶uw¡±C1OrÜ傞ѯ0á´OdzΖºª«CöŠ2 ö̰HŠq¸#/ŠúøŒÍD+¢‚:×§G÷ŠHj C’FnÙ£Û¤ÃXÚƒfRªRNÕÆò‰¨ C*}¬³•Qëñí`g}ºiü¡rss)¦.¢ËG¬Ú`+KYQÏÿ‚+»KÅÿ‰ÃÖfe£R:ÔÖ†¦Y¯˜÷¦ƃ+ÜÎï…<ÙGBTǤ‘bXi¸®Ìü2A*|OKܧ=IÉ%ä&Iê”~â@d5#¸Ãæšœ;GÀ¾Ïšg§ºŸV}>#à ðìk‚ç”PcøbÇMî€Ùò‰x=ÖÐ}Ñ=°!É@-„pôI¸`g˜Øú÷£R ´$,øŸö ôÖZ8¥jç§ó4Iu¼J9ëíŠN°¯,Þùɯâϲ·f*.ºgâô±ªaQˆQJzñ„âá -+:'ÉJèÕÛ2…¸)Ä p%zU¡wù¦ÁÀÉ©·ººº®…)eÊ[ JHäêþéXäoÎ×ï¤4<2âÞ›Mãd÷§®Yÿå-;Ûw”¼ ÂaBr§ðÞB_çUQv›Ë¾C>£=ecÿ²~ÿXŸSERâ=õdáµBkþãˆgWP 8’jüJœw“»?vž‡ž¶)aö^vLÖÎz¿1DaZ›ÙNiîÛ21 f_ID—“ÈIJ1ϬvtÜ$ðÀÞ'‡§Ôázªë°üoûëß\wP›0¤`àHR ‘nô Ybw¤ôb>:FªGýÖ|Bd¿ÿô B3¤Ñ²ã7KEŽ.boÐ"ü;Ï?ã{ºQU‚ loÌÜ5Ù<äe A•3ñŽî+€‰98gº‹&’­ >ÎZ!ÃA¶Õ@Z°2ë6o_‘¿©äÉ’³†äMÈÏÿæ >tgD‡ƒÛ¯‚ÆËcì_Ô¡>šùÕXQŽJŸEÛa¬ T_3Á… fõy‰µ\åŸîqN2ué_ƒÉÓiêÞÕVÞ4›jš³4RzbÈO9_=”_E;¤ñæ7\à,ª§“”€GJº*SÊvÿQvt¼àüÒi91Wf™j•½¦“°:ù™ék‚¹h­ ¼ú)m,^IåbSéSõ¡¤èGÎŦöd,ÆKƒ•ʇ’õ´èí”^ì–I Û‡±øÕAùL¿³n"|ìJÊî¡?Çiä•3É;!‹{ÏkÝ¥HKÅ^vw’âÔÃuo+y‹ª›Âõ¶“P˜Æ¦Øæ\]ô/ÎŒ>Ë"&b ëÇÉQÍK=|œÆïx¸˜^F G7Ù,áŒ[ýñ´ÛÂõ¤F È z÷Y;Ð,ZAìÉ·‡ˆ_g:„©ž¶\Žþ]l‚E±¶¯É™)ã ­¶Boc8:s?ÍÂf)ÏZâk!ó7¨0_²&øÇu’D:÷–{"uwXÀÏ]é‚Cùõt}ÒRÝ3ZÇqçXGSˆrzË–¹>]Þ赆oª×Ÿ[ ™J„bfhQ(‘n·Cz^gÛ`¦v%Fé‹&{Ö°ÝŸzdÌíô§OW`:øÃVAIÊN˜$ÿu×9HwÖ͵&^5íçÕùǵԂz†r·ë™ír¸2Ⱥm+n†`ùEzŸó+†Ð>“Û2Y¥é€é*òþ-k޼jçÖ“mIKÑkÇÞÍÝøeùpõ]¿¯ QõfUÜFãÏ9Ý‚šêFp|¨·pcrÄy7[º| ZOé7mnÑñ²ì©´s éDÕkFêg–dD)„òî­œ³X/€«.eíÊ´RW¢ìq¾áy²Â¸ñá>«å7 ¦ZçQŠð»KÚW3.Iše'‰—ÒŠ‰ésaû¦5Ý0œ¢”!1à÷_zÇúLsê«ÜVÓ)¥ÒéjéN¤ºë:_U™`öåñ :Kþµ1¡7ïé즣cr¶±Uçç¨Øžå”·ÍÝ;xyœtú‡ûƒ*FYÚ¼…â¾ñ8±ñY^߯õ–9ø4ý a(Ê‚»² ïB‘w®D4ß›› _1Ãði[þ³4džfßhÃÞYŽ w槦½HóÛ¬ÞˆÏ"ãþ‘„îÝjKT`üŽm3©üdɪ(&ékoƒ¦z+‘ Ž T ‹U±Z:P,«:OÁ‹"uÔ™Ôit°bÔ¹œ¿èŽ~'Aòa06H§€&…ÐÄäF`Ëôáκ»·¬)ˆç_µoË3 H/^„¤M;¼‰?*þHéìÏuê¬>åú}®§ ü회þQÕpÕ¶_ÇycVc È×%B·Öïþ3­PA'f¶I“b<¬6„@1ãAˆòU …5ÑIm²ï¬äëšñWYUm¶z¦ñ@dð7a‚ü¥ÚäB” F.ÛºVºb æ.ª[ìÿÁ :Œé•cA<‡Â‰¸‹Å‚c;…­®Î-¾õ7ÆÉ® ,Š5ŠŒaY‡« `ÍC…\‚¹þøþ]÷h¼¿â+E:¹ê£¬‘yð€.«“—}€RòåîccÊÜ&B®è×ì„•PF7DbvŠôtl‘0ŒÎV‡¬£¿|k3ò§ û`×ͪH?TdP @}½á“îmv[ÂIš±UGZ°8¬‡Œ{Þv’q•,$Z¹7RW?¨*DÝCÕÒÖý€”åOçK‡ýìV’=§’Èdëj‚ÝÝPÿù1(àÕ>æa2=ãÇÿÑ:=oë(§ú‘R2>ä;©‡t£þƒæn‡¶Ü܈â"dÒÛë)È3ôG-+jÚöZÜW.Z Ï©øx¢É[°á3Ô&'NG›üш+ŠÑÉoÏÿ G•x*>É©ÛÚ°±~ !Q¯ÑˤºiûÆNî$‰/=%ØNn³e!¹²Ü)VÌÎ=Jœ¼Ð]ÆBj9nÐåmsU°ÄZm4ÁÛÉ~VØsPk½¤§Rªç«óÈ_(Ç&çÖýåpø5}`Ÿ7¶ð6aD÷-¥V#Ôa™´‰†^¼Â÷ G™Z›²¤U‹ž˜;k@*ŒžÑB¨FÆŒG4ìhšÌíþaH chTbEÊÀŠ´¿5[€Õ*-) ê—4|¥¡pU^uƒÍœ—ˆ¤Ùäèýa<9œ!ÂnBa‚@¾P¥%åG5k“Ç{ ÞìË…Ùá5ת.+fXÓü=ÃÃ(ìÙÛ¥èj¸´)vñ-…º§OÝ]³Ã«'¢Ã4# Þ•cw3¸ØîP¾áçoÆÎ£â7²2—…ÔK[{ó‰-«frÒ.PdªødUÛÀÛG••¢rÄ,Oñ?•÷'Cë÷h×Y õFÚµ÷ölž\&š»’ÙXÂÐ!Áܯ6Ç‘4"?¡š6?˜Wu·û阫¹‡·ÕÔƒIw2â2Ú/ßȸ¯¶Õmwv˜hÍ@Jå×íî{<è1~KE v¤¸hCí³­û~rÐÜR ŠŒ0PDhLYº‡ú°RîV6—MÌøgí¸qˆ8kÝfe¬ º¶piùÛ3Eµñ$6f}ÈyJê£ñ­¯$tQÏÇÈVó&Y%ÒÐXËtjõtÅ]ž¶\5‡‹m.{²sšP­s-Æ5¿ìäI¶{Þ! vµ!ydzø(|¦ï|ï8Í3>éùß (NJtáU0øß·xB6EK;Í®`Tï½§½wGKª2-®sÊ¡•¯~Y7(Ñ à·bï¼o¢žJ4•ò²x¿J¾-Q…ÃBúÜÌ’¯U·Ash^"vPtF‰ècÆÄà ÆIý–*4ÌôF¬iBY–@é!ÒVÛJ>Oj+±y+—eìIBü±* Ð\#l”çâ¡·cuúU­FÈâG"ý¸N¢‹ÍòËaPÍ[%™íß¾+Øü2Û=æiγ(å4ô Yî]é‚?ÊÂZž0¶™±fÁ?ÈwNQzÖ €Á°»¢|mËç57Î`ˆ„÷QˆÍd×7%Ü{Í“°8ÃÚc †…^¥«„•n¸9¥b™ç^ilG¸¿Š¶ ž‘Iºæ q*ƒ‘Â*Ž­œX'UƒE–nCYÞ¨vÞb@)G ; B¿GÖˆ9 òq§ö%Zç†7ÎÁ© ½«’Ïð¯SE<¸l?y”›Š@´B»+ ÝKŸ0OaVË/Éì½Å#ÄÄ×’Zg `#Ë-íXtó'H—µ ß{ ,¹ÑãÙÅõÌ܇Ñaíê²]Ì€ëWB$+íû>¼ƒb¼çøgîãÛó,F‘Ƙ¾ÐTMy6áòÄÊþvP-ŽË ‹¶é—1òü®•KÚy#(øFhüxÊYøkÂõqW·ìg÷Š‘‘£—¸¶ah¸Ðd´žù`vÏ-ÑCH¥åö‘Ÿ<:óéÑ™ŠºM0&^<‹¦­ŒÛ!(;ÿÖÄæ *bö›Ô91à*{„,Z-`)]- A4ca­¡S„BÛ‰§ÿ¤—Bþ·Oò ³ aý…:‘Å›^!ùý|&žïÄf0œMS}ª“Kr¬µŠç%QkcáüsW E¾‰7”k$q4ŽqòO*gǬ¬ àØªa}¿Fp~±¸bÚd±µj9Ò3 ÉÞÒ OP¶e×vSLRÒ%ôÏ*JÊ®Õ-t5DùÆï‰§#Ðò"Ѿ»9W¯<ª©´Aì›fÀ“”‡!œ P×”Œø~Rãã±Í}·Šô!ÜŒ Ã׎×a!• ¥@çpÚ/ä,­rz~y†Nßs˜eÍô`תéx–Œ‚Ù—"!Êèœq—ÑŽ”&º†`(Ó¾áô¨æÆ«ô¸\þƒwÚrÇ«h#¶Ñ†{Îöc0ô“•­J@†u~"©pÞø¿Ft9X³jCÖ[/™DóÃÎÛ¤sˆm¶Ú|ó²DÈC´}¸¼‚˜EÖE4ü>{ÞQ¯GÔÚ)õ·×9Ãc·"a’Î3füG7 t[n@²ˆðük|7Î2H‡3Þˆ © O‹rÌ*Qìôt÷míØpMëû}ÆeÆšnbú£œ™äpF·|+Ú(X–×O–"¿"+KÈh~ʾŽwOÇ'.îãÒ|ߨXÁ(¬¡ßÕAPà³á9úf-ŒÒR ¸­§ô`) 4V‹N ƒÖ>\É9Ú­nÛ:[ÏL8Xð  µ§§Ù3"žÊ"o'U4F‘Ëv{_aWX.j6!%hîp¡Ê€0S‘´îí¯FD›mÄâ½…¶vY¯]°ðÅdõµ6µ+þ%eÜF-ŠóñÆ Àlê o d,øH%éXÐ?Hجt`ìç:Sž ) Å1÷ èz(êÖº±èLPÊÏ2‹ÆI¼<­ÇÁŸª”• ÑçO6˜·*a´¿ü†ÃiÂÀ‡òO%Å)XH!\ÇïçÖ½˜¹pÒxš\Ú!>ŒIÃZÀ¯¬@Σª:êÎóY«$¢¹d¿·^]RK-AS˼šIaúyky0aïpg2íNL*¸–vˆÚõÔc¯œU‚ÜwJ}ŒÞÌVä³bÁü>ˆ'wMq”S»ÕEÆÊv¬¬¨e§­ßØVÔ»20e”éFD§˜«VÚ9In¾ûÌ)QvÕf'7[ßË Çè6ê#‹´àÎÿõàmJ¢héAç.o\Ÿ÷Ï9€ÈJiŽm²Í}%ûѱ³ [–‹¥3Õ_–â94ë•Ý.“&†^u‹ ‡Åò´[³ÉˆÝÎé{ uãŪ¦+¤³ëV3Ómì%›4£VYŸÍÄ)ŒN1Èì²bšð“ÊÍÔÌЖf(¦_¶üµš0 ÅzÉ®fS’ç&à \ýïy¥Óέ½,èêm¥(:H‚çï™Øª²V3Y©F°+ÞGàCM:6\Â÷ÓÝØŠý¦ø…PÃ?s|0 dÔâdeVÆ<îCü@Öy aºÆŸÛ,¤E¬˜§J2É..Âhæ4“‡©×]çÞý†¾m’{ÖØ£Ø¯¤9sV”£¯ÀJA£¹^ >ýžµzD”êEéM‡z;ä™}É[ËÉž#¡ÜAPr¹@fëw%¨þ^s¤œœž–‰Ü&!»ðö˜k†NÅLÌ$΃Լ¼ú(ï*¸÷±BÂ׎IΣ˜Ôµk‘o`N¾ÐïnpM`Ê $M¥¢å Û1‘2¥¦^ìNâ[ ¦8GG&‡NÔ Á ÀÌψ¾˜vÒu€ù–ƒáÉÈqÕy”é~ÁÚÞ‰-ç³øÌiùwDÏ%’ ÐÒxJ¶eénD– O ebf60‡_‘„cü¡È›7%#Ǽ”ˆe@Ú•ÞàbV«ÇN3N,³¾+_þ%òìÏÎAúr8Bü“KB …œŠÍeÉaÜ„ñ:Ìüܾ3ÑcÀ8HA6á͹Õòr>3m«{ܽrKqE*ê¹Ì²J>§t4& |n˜n¦¯ÓéJd—-”E³)Ýîõ$>Q±UÂIáyM¼žó@F°á9ûG¶z,ðxJùžø´Ž–½ÃFÖ]™¢?KþœAд_Çdo Lä.릓ˆK2¶.(:މå¨ÀŒ9 “wxpËiúÜ­Y»7XÍjžz4ï¢èMΖ°EØ/ú1º `FEåvk-Ç'su¦:M§œ/ñ÷Ópþ­æä'°?%؇±Ö}Ç ©fÓKK楒ô™'.àý€ 3rΆ¦N¬ŽC‚×dÛWìÖZ"åá ·n„¤_„¥´®ô Ó“—Ó0Óq>•ãCAã÷5uG­Ùõ‡½•휀UÙû´(Aþ)wÏüÀ‹ä y­†ñÀê›±“ì—šh?ˆ›/Æ(k!âÉØëç¬Ùé´´Ùªxr ¾§ÊMÙ¨‘ñžú£RJ@J¢G®Š>ñZfZ D\´À(øV/ä@׳X¹=e ñ¸\Wy¯4uýoeH\SËRËŶè=VO®þµ¹Xø[rÒÓ¬Øùg3p¡± ïQ8 ^ì2uæ NAƒw !Xå°Ö…I¡Å0iß4u «æýþD¨”\Crì‘nkU0¿õ"JÀã4i"\½UbgÎÏ~Ôi:,ÛËqd(ñÌ9W•ë‹ Ý(¤0¸YGWGÑ"ä8SêÛðá©[²ï¾}’êã™ü½²Æï·VzÊ`b¼“´h§ágXÞ$ŽûCǽqO¢$=é €GµGß¶>!’~¡u{5ÔéÚñÒò ¶â[Sú—3“©Dht€«{êd…¹ò&"’ÛÇkLÖÇq¢ý³TÒÍ'(×msѯXH˜äëE”f=Ǽ„—õrê O5Ž~óŽÂñ¨×ŽæQ9( Zd†t¡% ëO5%¨v…S¹»% Ñ¢½8FÍ “`êÿ‘þùìï0øqyÒ ÆhÑ:72è½»àÏ´–øZÁã»ç hÄ# ü‰§bìqÓ‡´Z)xaZš£‘Ö ÷„°¼wévŠŽŠÃ¥³ý¯}Ë·‘+F·Ic“°,ïIWjJGg¿à)§ãÉ)dMb85í4^¹à2Q¹ìæ Ú«dOË96ÛŒ¬EjòÞRLf¦€EƒµWÛ—‰^«×Nh..s)´ÝÄeš£ž¡ãeÝWhÄi…¹Ãe‡Å4¶—pœdjÃð ÍÁ»ÈªIÆ—,ìcèçj¾¦à“›ÍÐ:ÀÃJwÓÃu\®Ô^"X–>EB…F‹ÝÜÂý½‹iµÿ¬ÏÛròï#c[Ô¼ý)ÕP²q½ŒlàÙOº±QZLÎçÁóßÿñxV©6:@Ðæò«UBÎ?”ÂZ™VBT€¼ËÐ%é½C­]·t êSÕd.zO”¡ÄžÇt@QÇ—VºwRzí˜Ïq©wë†/z™3н¿ÈvIyË Ø‹üäžg½oScü–¹ŸÕ"_—Þ(GQ)Ç»ìE›R~ù¤®þ ÍPß„c8ÛªÔ{yú‰Ôlå+}YÉ^“ã‹H(Ѽ(ö~¹µpLF¾h¿Ì]‚'Åe4|„­˜»’_­»§/ÀðŒZD&-.Aàüÿ ²CJd¦s ºTOÙãÜ“–eõBo(L‹&d¾·=5O°ïŒÊéÊ,—°Ç·oøà…)xJí”G5z?ö_5¾îõø$§õê™Ð-VêÉçòC ¬0o»Ñæ¥{°q…òôÃe_¿Wñ*”OÄkA×ÄØrÎ]Ìl`ꙉŹÅ8KKŽ—óaiÊð®Ûz´7º6®œe˜²+ê¼ï”4Ãy àÕ({îRÅ”\ŸßPʼ\¹·O”ƒ¡ÀS޶6DPÑQ󩿍oÔ}$!Xßî†-[g!D\äÐô™¦OF•™þv‘Ð4®¬¥L¢(7@„ƒÙ˜IA,¾áF™üiÆâÍ$¼¨“ÈDùS§Å닊ôè}®79ªÇFçéVÇÎ#bwFž‚¶I5é__FÔSè«Ð–ì¶í™?ÜÁ}åÚ?­+ÿÈœ_³ƒ&„ãÒõè“!<¿4xÉb =èF;ïè²Cª£'×ÙÌíÊU±‚s'! 2²1й£»mcX”}é€E‰‹žËÜRï~ÇÏý3ž8S\ª§Žmê_*cžãĽË,}L-Hkf] ˆÑçVz8öèÀN-Í@&Ÿ3Gç‘ï@}ÁlU;«´ ëy ÉØéê’Óu˜ý¦ߎg•>ÆÚ{Õ¸2ö—{OTôs؃Œ§ô’q¤u +³öî½4ƒvÄÚøizZXI0‹®™y=ŠD,ê¨fR( è°ymÞZ³OYhI0ý úÌáSMÕxX«¿GaËɆÙÖö.ñÔÒšw§˜jÓ=EL®¹y}ã`þ×=Žú‹faUU/&ò·ðýÜ„™Ãçj·nNpu[ m>á¨ÔñBe=TJ|§š˜ù,a7ˆhïCÄ ß©y3àƒ>Zð‰“[“Ù5À/;;st½¤"1ÀRÒ­ Ž+|üûQ-‰ÉûLDÄ©í=†Ç×€b‚}×X¬'_ôÃe iе3Òpí¼D£÷@m¿Šrßò‹k¼p’ƒ87M[Â4ÑŠÒÓù¸URzÂÑ%¶ÿoÉ‚ø;œKê˜øìÉP64 ÝlVãBÑÁ#ÕQÒ»12 Y+ùé;_®í” ¤šm ¾šA*d§)'’%X¨%…F'd>WÎ<µßÍ:ôèõ¬V¦3øq±ÁçÎ:ëh¼g1mz ¿Í×ðá‚”ÝEÜü |µ¯ϳMn-gþ-ˆhOva“÷“ïnpÏ>â]÷W¢ÖÇyØSÃtÖSÆßù –9·7[ÃÎï§eæ>á Í„N ^qýÀá‰ýÐ9<1­Ø MP€¬§¡¬’ÜŠr C$->Û‰Ó¹£rŸ˜oÔ@­ˆ®ò].µËp»aþÄz¡‚{Ö RrT6þ"±ŸØøŠ¢ßóC10YËG5=ÙËÕeo[ò®—ïMðžÈǹb8ǹ|qÁáš¶ë!ú!iF^Íå™wž¢«I^,búj4q¸ Ä@2†Uu›fÁ(Ìî†}³4©_RV‘34Ý}‡ n£’¦ÔÔ=ƒÀ [û·ðdRú® W<Ú¸Hõ;÷ðÐ j€/ï¶Í y•ßjIïÄîìê…ožbl¯ ôCƒÇ_CòrÚä>Ýi´€PÔÐ ~ý(µM,‡#›Ãgªx§ÃäNîË —úŠÕ Ì䇎©ÞKON¦<½Cvè²x¸›Ô–%’J˜ mޝ¥³¸‹¸×ßt g{Æ&kÊ]ûTg˜×ÃÐñÙvU¼£ »¸[­£üW /Žæu x†t§Fm³¡²¶§nêÎÍ…ãž(´€6UoëÚcˆ8ÞûZ³X±Ò”©Žü±½%Ì™¹Æì3xͦyÌžÕèR#yI±«d±¢^7+còÂå­©âÙä‹¿9ÍÙéH…é‰×Eص-²Û —PcFf\ Xï®Ü6m":bµYP2AÛRtÂÇñ±‹Ö¼wÎÒJÛlòyt%‘uuŒ´Eú Ù÷"Ký/~GµÝ±bVƒ“ù°% ìq®Cc~@s ,ôTw¼Å@þÿd'ëkïå8ÞŒÊò˜ÛÕE‡£÷‡©èCqyͶãÜKO¥8è{gkl²Òì^…E¨¨Q{HVÛx‘˜\DýûÔ sÆS²8 e7î¤0tÖWñ˜y¢äÖþRÖöî|úg-’Û¦–Ì#YJù3·ëádYƒC“Z|¬ÜNMÀ§m ´7{PgÖ–Â9~{qÃ~Ï]öœgq)'Z­œq3É£ýøåÁ;óþ.ÿX̹Êpö[hƒÐÇ´d‚ôaY›_µ0ê_.j•ÒR¥Ð¦ýԦܑiâo| s½îVTñÄGÊ¢j9‡ò+U PEôp{åØÑ+gÉ8Iº³¯@7Õ÷( ެ¥¾‹YÄ×·wÀœôŽ0âûô'¨³_f)5¤Û4s D*Uf&"mD•diDÝ~ á6 1\Z… =@Á®€ «8~θA:Žs]ý¬ú±D ¿+puã™Uœ¯¦öÑÍÀËâèÅ 3#•õ³d^C –ð¥•x|D–訰¹âŽ•U–±âyWP¦àbØ\ÔýàZýÆB‚—Êú™ÏB÷ îÞóƒ£̉Ó’›P@×Qç†'ïÄ©ûßÔ¤Hd'žO gg`ô/(’ìMЩ H‘•)ÄqS~±jNz™Í´ËcqÃŽòlmbE±Á€\id úZÍZfkz=œÇä`Ç4&ȃZ€v§ËJ)A©‘sü\+ÅEòä3:ÿ XÇ žMÚ°Lüe±ñ”Œ‰¯ÜŒÑ—Øç©In3Ùm%=i®WýK¥¤ ïá×x¡Œ/¹×–kkwD㦒•VU æãt+_M«ÃçqÆÿø^YúÝcWQ‡)wñU¦YØÂÞs_…BwùèE¦è0×î|!€ÜNuÁÑA ØlÇ‘U€g±zÛ³^Ñè ^èád Æ T tE|°¸Š€šÜŽƒØë¿âpƒ0;p“KÌÿ«$wW£ÙÑàç?¤ŠûÃmç l{6 ½ÅDů›´púcûU§9õ˜¾½CÄ&툰œU>ªËè̹#·ŠŽ7ÐÿœrUîȱES\ì3OD·ã^›6F~L+t"~ =EÄè÷äøú‚"ó„×ø8#¥gª¬¹m%þ }·Í¼UyBeØ,àOW'áä¡°Ç׎zöÉ›dKÜÞmÏØA!½ñC?þ ªó²° À‚ |öÿbaBÅ‘GŒC*ì!Y9’_®å»Ñj×Cìï)H²Žëñîr‘ˆ;•škÁ@ Uц#C]<=ÿ±­'ù{K‘ðF}ìú¿Ÿ"º=…Æ“HÈB¾ú(²‡EÄ+ê×õüZ¦I4P,—.ÍkÁcèmàysòNyšu…ù‚Ït® Ó¹ä|—–ÒÙe5_Ú/#.jÞ¨0#k ˆ†t—3Œ³Bq½[šcþ3ô¨Œ»!R­²†Îùä>±*å4éjMÔDAçypp*ÒŒNåPz_”uATÆÛv:"ÂtÓnä—úa›h¯/ø4$­+·0aŸÉâóÝKAt„_¢Ff XwŠš…>H ÃEY© H áÛ© (o&ö;ÕÞe0Š´*òÁft§Jå°°2–¿aì% qTú+¬P'VdÏRT• ’’„"Z®™'Ü{gÝKkè¯XYà~ U]w(§;St‘®ÆnJÑæ¶6|&â9ŸeñmÛìéß¡Ôq…3{4¯ÚoMóyɪ‰kc]¬¤•_*êD5ƒ¼Ó¬†§ qRPñ jÄVKõV9(ÁèLõˆÍ…Â[„†À½¾Wÿñá¹i ‰ÈǰÙ2øÝoMщ*¡êW³ïrÞ…í¶ç—ªpØUS)êØçÅÖì–”A͹ð¡{ =AG,~Lq êÏ´hÅ1hãÄ(úÁi ÛH!7™eÿà±ßÝÁ¦„“Uf…m‚MŽ´qžûìʯßâi󄆸¦©#»5…,ªgþLz«¶þeè~®:.>¿ãj;!œέÛê­_»¹Øzðž³gFOÌcƒ÷[ ¦áý¿§ @ó¿C†”ò-&PlkÆm—oñÃ=(¡9 g¼Oí=YÛ¬ŠµŸ|ñ¼ÕáaÐuĉ|n±tû¸…ˆ&‹‹©d¬^¨Ô{’/Œæ#ÿTä4…“~çé¿H*=s‹á<¤Ý[¶ ’ q²$Yo÷ÔdŸü.¢U0☡JoßôÖIc5U¿íDOtÉmù ½©ùI  ÿƒh\SÀÚæž4[~sV•+3´ÞŠ54©.Er*î×?z 2Ç 3FD¶&ó µ¯fdGf× ŸØi¤žÜw²Š¹n{”±/íz Œ`¡,¯L°gQƧí—á»ðU¢O×9!RSÀgƒßÁ ñ¼FË£§ÝxÇwý+„ŠU~aÍYn'ðÞª½3» ~mª,™€Ô LÓßøÖiU6}êFŠPEz„®½‚§¨6!w1Aµá¯Š®ïçÅïµ8“нJíÄFi@¿¥Ð6ù›1m¢„=wo¥-s²ÞÈNc3ÈÇ !cGL”¼êêùÈ UЯ’•üµ>_|÷7Ö…ÌrÜUÙ'\9H/ìtj¶Hã~ñ3½Žä’öm¹0Ì—íaû|Ê ²¹Ü¤PÔaòêðr¶3±«üÔ㤵±›B¹ÔUrn2õFæÅ-SÍov? ÉÏtÖ6n@€.&ºD_ÖT“÷PI²iCêæŸ+6†ðKƒ錼š ?Ê3Ø¡`¸î~Jm|Üä¸rÇ{ iÜÌÿ‘Ì­ ¥vûGëÌÉNyî±J' %é‰rStúIƉ~&’«ú|2ÏKGõÈ›iá{’<´Ä¯FPúÞnÞÚ3ðÌÅ–*—µ78²ŠÝ‰hï"­ #³õ'h1û¬6pÙ­ðæh=éê ѼKtÊeŸ5b¨ÄiË@[ø[suüÃi)YΘﮘ!–ÖnY$¯ÎÃ"ijG(u­ä ä6K¢;­ôØÍc­¿ÿaÖT(±óªÄ£«±õ/ üö1)µ$&3ĤÃ9@‚€¯¤ôDö•Ül”³šÅ–ÿ|ýL4k"÷ôÂTs÷ImD$}  ŽË–]ÇûV‚ˆÂ  2 È­âlöBÝ'9©És:O›xýAF0ñ‹¹ÐH¤©$ûø7Bua+1C´´žÑ x«Ì⵩¹‡6¯ÅÁNO"Ré›qüïÂÊÖT‚Äá”ô€w’R•œYgHõ}-öC'ë,u‘-M1üc! $j}ÇK“}–öÖú_¼è§nÍÑ»h›Ë÷Ïè¨È”Œ ZT8ïÛs9é¨ßfO™i“pßv÷ÇÏCpÉŸy$dÙ/yé°i8:š}ÔAóâ©ÅêÏlߊÐh‹ÈõFÂnSñ¶ï¡E郬P¯±Ã¶¢¥Þ¬Ç1\šÛÝJ5¼à@ø…€Ü=0šÆ1šw¶|ýnyÉZS¢)KÑòý¥;éóA‘Z°¶çÍ_ù@¤”¡h FæàAÊÀmk<âŠCR9ÒÀ]—5äMêþöý¿;?Zñ׿|ÞŸIg˜Ä2å/]~F%Ÿþ‘Àï¬ÿø-ûRªÄÇ SÉòfؽ”~ BaÇŠQÔåDqh>D`ãÄY®é#P8¸“þAÒäsûñR‡Ãb¤°­wY3abÿGÔá‚3‹^²Ð„S@UÂe>/símtA°å #! .È27{~ñÔº„þ$ÞZcåªÏÖú#,þ\í‹ÍKÖ ¥æÄ¹ó‹óQ›@'c¥Šp€>*cêi6¼¬"ܺ ôºÓÇ|_<ÄÛ`:¢™j  ]"ºÞûÞ„çà-Q9{DõŸŒ›gÅfÿ@‚8p¼9ÞLßËæMEåµ{Y’Ÿ\?Ô$ÑÙøCÓJºKß^׺2ïoòo±Ñ„^¼#5ë{…¶üÛêšS4 § (™BkŸ õ¶U:YÛÅ„ÆãÃ…¨ÚêiøÄ¾ç0§mNžÜiü}í–¤Aæ¸<£%J¡Õv £‡¶j(¶£&Ôã vJÇReŽsÂ\‹^ÃkŠ â͆%§E¯¯jQ‘ÖÊK ó(KlÔ×]¶áàÓ…ÌÞ8œ%ÊÉìF ¶Óƒ¦P|VT¼${v·©Ö‹œ¼OÞÜLleN^lS‘_MgÈ#yíê3žá;#Žxt›$©üëTpáIØÁ8RÅl­ÊŸXùÂ.ç2é})Ë5—°G²|þ’Ýó‹s=<Óhuê=¢UžÂßKßË3.æ^GÖe}+×T( ¤¤ß¬›¡¤êczÆøYY†³Ä¤ö´*'r=\,¡]d ³‰?P-T‘FŸå†|HàùÊgörVœ‚°)}$¾Ýé,âïSóiT¤Ñ—Os#lèšôSƒýÀ¨œ‘,Y}ÖÇâ”IJ½Xžšs›UvdÏå8¬ú]~“ðê Ñ@’ÆÆ*O¼]‚åH‡ûþ¢C¯p»óç›w¯¼“n:"– “@)5pLh>'?7û0q ™-Î8wjåbÉ{®¥¦p;ÿIr² ø1‘zWoÏ·/Y¥Ã<>,~­ˆ¤:Fì4\¬ª •ã¿[ÝïüO5:ÅÑŠò̤åg‘ êOG¢Üæ% éòæ\{ýÊQu,hÔ•À <ç-Òî|ô ~m_ “«ÈªEöÓZ#%¦'Lõ $iàK‚WhtÀ-fOˆÄ®½õMpˆ¼ƒ¹Ì%\´Ú•AvJÁˆ`-ì.—j0uwéÁYìþžT'S‰ñ± :™ŽŸé ”£Â`¢dä&™‘Šÿ²íV`³+–ú­S› «‘Ïõ๵½þ Ëݲ¬ ÞŽÈðê#= ±›Æ7”—$—4*Ã3ýÛ"Šö´ÏI™€nË5iüÁû-Q.3$’¨ëê¹N*«&’qJot$,¢ì"6f©h¥VÁ…üæANWÙ Ayñ/%»™ ž»s¢Áe–§wg|hìÚhs¾(' 8˨ëDœâ‚ÉOõÈj¯>qnqÛ þ’ŒñàŸ'Ù’zØšô4uòëØŸ¯`Ô”ßT]X(bM½É•$ ü†cÜ}bnÜ™¨G¾gÿïSØØòWàU)) Õ !œ×ÿ®Àà ҤŒÙ}U/zѱ`ÈCì. ÖZº¥Õ˜ ÂŽMtjÓV{7EQ¹T¸… X*¡[Íè™H0‰ñøQ‘½Ò0±d´TLAðÎD›Ö3¶dúܼÄ[ÃúM¯Ñ ãz½­Ä²þ«¥˜KÜ΄džìàÊÕŒ4Ä6¯}¥ÌÀýlævª99ÎÌø(Ü“˜~ ¾ÚqcÒ£ ©kyøäRÙì@š9Ÿ¿ÐÐduÎ eåé”_’1ýêXú' ¯Jè˜_&Y•Œ.þ\WlqÞöŸ!?ÿÕxލ„ÇRGµÓ ¶I¼²Í)D„· îbÑã©V^ŸìZ™UÎŽºÜ@;ç ûRëAá´QgÐgÉì¥L)ñQܸ,8ÌD%ÈPæƒãŸ^yì6å¾¢Ó/0­àèLKxOOM,@fžâ=î+(~LÿÕí¢qÍ7lÍ(•ÁœÃ–(6¬Q=ýfñÏPKÒ>ˆ2²c!¨?üÒŽ ¼"¾šp¦ß«¡¼¾öÐ_+œïtŽiZPÑ‘óc $° ÿébúæÈÎzã³ø¡´Ì×4è lcõ ‡6®¹k ¾ '®¼씜–¥É£cùˆªs‰÷]Bú¨ùƒ%þ¹A8liXÚК[K¯+‰u·÷ݬ۹Á‡*A§RdÓO•Y”+ƒp_±Û’ý‹¶[é,c ?ê”EúK€lR™%weÂc)›¾zq]&’‰sû\Tó†éÊ©Ïó"B#Èw•š0¯­-¼Q2ÿ`¼@5ÉqE V3‰0ºÍ”Ъ—ô¾2ðô’œ´§o"Y\qŠž(}ùP­D€ñ?X _ºCÓ<‡û©ãQµéóÐʨôï&ø·v€ŸpKtâ0“ ÿ§«öo¹WwÍÿw…Z¯by©n7$Ï|_ž˜ù#´ìÓxÉÏ«ˆ´qõh$‡ä#’킜ÄË·½g¨zø ÍÆøyº‰¦˜mû_¤eÝU³ |Kñæ…®±ðŸu¢{–WÒÈYpîñ…þq,ùœ¸˜ËÖì=yà \ öriÆvÇ"Újé”l#ˆØLj¦À™Ê#þ~ÔÛ 8k;z ƱØó¿OLd ‘žƒmHH^¼eó£³å %‘ûtøC«H`ÇÅÝÀLš§bãš~£”ò‚;··†¾äϘÙgæº=ŠÑÙ¥-\è±Ûš¢i±á Õyœ¤ïN…QÜHÎ顚>GÁ K—»,™ØÖt‹_¶]Z¥v––Œ@a7Çæù‰zŠß‹þÅSKæ‘ÛÙ!ÍlúéÁ‘·fÌê#:=Îâv,,Œrq,³# bß;#[µ>‹zà”|ÄÈ-5ûÑñu “T¨ëûhÀ|²Xz^þ…ù< qÜæ‹A’xfNòd'G0ŽžËêV‰ï:¿_uZ‚•M&sÿS€V–OÜ‘’0£¯&˜N¶ ì Èê­ÁöCɶ1­ Æ~ÓT‘¿Â˜ïÈõÍÒ 0h IK‡½×Ò¸÷–{· Mýô u·÷Z¸²6ëÄÚ)ª=ç½míC켓ý“åC‰$3ÐÅú¯qÙ¦ú÷n6JòŽ©=6 íÙkû»×C³[$§Û<<è“#®0=DQ þ¨¥“Ua4 _¥ÁØ("> ä_qWbsU¥D‹¿§œÇóØ.¹.}–äti¦Hz²¬µÄ¾ ‚ìÆ¤“#TÑÌŽ{æ]{ļž®YaÂê—lÙÖ÷žÿï8@b =NK`CC#òB@~QÙ‡îdÔz»G¬ÐØE^³ kÔÍôß¿AqÀ—Z$.ìË0‡—±’0ðëæ” 5d@¤8e¨@C5»X¼4ˆ¹5©<ϱpDı4,¢—GÀ-îÀþô>ôóMë?¢WèuDØ×Âsº {Óÿ‡eáG-ìÜ þÓÝ8èÆfðº®ÛšÆ!þj™MrÊņ¿ßÚµ‹ü6!‡ÃâG³º@|gêGnédH`"UÀ;R¯¾-å~ÙËC;ÂfÞ9c„–‘õ•U}lˆ–‡[ÏŽå›´~_WM4QîÀ$‹pbuˆéÙ&’E:¡ñÇBé®û[/¡{¿»‹xy4 ÷ qëWæ°>¤VîÙ léáË•;ÚTwQ±Vœ¼ ^e*1ö­:‹3½<y]=[AÔAÃta®Ãÿ±U»?‰qµÝeÇ@ø„N>à 7`Ì©ž£8|Õ‚xÀ Ÿðñ!Çn´dà ºUô²mxì"`væb1Jˆ}e 8¢OúxÃÂøڼĠ8…ž²î_Ï-­^CàÖ½9.Ü7¾[hl‚kÈaݹگ‘Ø_ì3ïƒgTÆÏi§p¼áëú°ïê¦7ã3oúÈK1»?ÙLK;ì!jõÿ¿Žäº…Ê—tïSBÀþÝЪ«´|)ëMrê–?\ 4˼T¯nmĹY€J㿘BZvÒ½[h91ÆÀùýæŽÄG¹väb§œÅxo»ýÎfƒgxÍþ{Ö—ª¬ñWpÍ’_ðAÀ*Ç©qQÅsX. ÕMóŽi3—‰=KÑdÉ më²"Êwr®Ц÷Sëý)J•|NåX(Ðd„r§ÌT¬/9(7ìx‘?j:¢R‡°§µ¨;»ÑÖBâ7¦¼Ìäˆ ¶é+”‹qßuHsì|ƒÉ+CR—-ø¼ž–FŸp뮀vZ;[OaëŠj ‡1Íd,Œ HÈÁ<%wnk]Düc¥Ö$ËÉ¥£·ÅmåöÅLÜÎ3E§ë#›º YÕÙ÷R+/®·[xÛçÉïÒËŽð€GP Ü¢m8$,¼nÝÝ36¿&ÖukXÅœf!o†sÖÞß½r}«aWó'›ÝÙ5R^vˆ?Ýy|‚¸•÷ì¥ãu–¥Þø‹˜6S fíuKø€B»÷)DÔ:ÖÊbàíèýg+{¹ ¿”ÜC÷>³ïVš üŠÚôU!Vúѧë\#Ö _LÀ(“£ÍÙÄÃQ/Qúe§qt׬Âöº˜$a]X‘΀„6•¨@€5ƒï}èÍ÷£(‡Ë£6©‹ ©Cœç¬ùCœÙ>(‚Y"€R\Evö¼6½~dpc*\½º§i ›ÿÃÒ¨1½½æhD–ä°ÖWâJcœY”•z´7¼}A¾Óœ ̼V˜%:HÍ K8BUåµ9$xÁ‚ÐÓ… †\ÛkÄ>  f4¯ñÔˆ?+Ñ­$~4 íÌš6Õï“èsÚžf\ÊJÚ¸Ìì¬3³ië—:}g[[t—Ä‘ZKY†¦µ3Á·¤Hÿ‰N}OEüG–›ñmØú³6æÊCå_Ð[; ®¢}æ=° p>Þ?ÈÉ䫬`âùÑF¶‘á¦W}ÂïºåZ=r=¶ (FÐr`ÓM„šhyy3¯Ü4×+Æg øë~£ ß’¹gèJBrPZ$ƒªt­¦/¢<(ÕvŒJA¤]JUÑ™e?©ßÏ1jÅ)¤tÐ>‡Í4ЉƩ9óÏ~ó»ËDwiñ)µ¬ŠKïÒ ªÓlÊÒûÿ75d:±*ª„N5SÂç•ú”o{)Ï'·b¢Â}•žtˆ~î)møÛÀ6 *t¤&`*xÿwÂ`0ê5ÐaÂ\ÊÑ:(âÃ6'sišç2äœøgH¯/¸³ÎRðœAaÇ{ð%¢jóÏ4H€l.(bqØþÑ8ž­3k B©£‹J{A?ú€!á¯Ù‚Ù·ô·ËV^nÙˆüÇ´ÅÆÂ }(Æ ó¡Ü†ˆqóÁâ7ì“6¬¯€a$ÕQ¹=ƒÙ¨*P¥Ïbßø#0i#ªþ$䙇©™Ðú{ˆ>ÿ(ÔÖÓýµk?›ÙyúªÌª[‘ø/Cé5ïl ~ux™Ðì«Z8<صyû± €Er½Úë…—Éî$›¬¡æ¬-߸D©fãuO—¹¨ÆíSíEëiE0È"(LÿH–ÅhW}[—íÉîØM‡“%® «=@õžFóÆL¥\´8SðÌßb›bFWlWpC¦ÞðàŒ†žk½¥Ñµñ8¬Qeæ´ÎNÄ’®aønµ™þA5Í2K‰=Q6ü0‰)|M»ux<gìrÃÀŽAcgúzE_kwV'Ä›VŸšRÞ9R>Sε¶¢5$±T|B€#d1 E³°£?-^Øú’…!¬ÅÁ)ô÷}üÕ üW[â !&zû•fйæ}—êÃÇÿ?!¾”ˆ‘ž|É¢…²Zé°gVÉ¡¼•¨òC­6/á;rƒ¯ƒ2=ù€Œs*]âݬ;á‰DWé½q TÏE*JÚ¬N~•`ÇlyÞ"ž(Sßm0”zî­aßx¸õ{¡ãGÓ ½'{ABó²Ð!Y4ž“?ã8×€W’˜ïqôƒ¹ÌÞóHyˆÄ.JÎF^ÀîM$æg~{œÏ_Y2ì+[#‘ŸÃ ªJ.bíûZ qÝÕ¥õ=ÕmKyžÓø??ª^s4ÈeyÁ.È2ÿ \ìg¢fô‘Ö—„ŽˆÊ½¸'`‰…ÏÇQìQh–<ˆsÈùŸw‰ =`H<îíSlûÒ8i<7€à0¿£êÍôï®ÉZŒ1<É1åyc<ïZÏ¢.ø 2ÆP-Êy|´«³y5ü“\κÍ=.£Ç÷¯ÙŽ/D—¼‚Å4ûè&”M'lqñ|7!üšÅçô[é±.’”«}p9çJ+Ëìyïì ©ˆ¿+p±ü‡mrVÅVRög+ŸÍKSˆð£zïJJš…OÝÎŒB D+yÉ›ÔÒLÿiÊ433*¹pW¢tOî µ–µ?ÊXcþà²x‰+‰²>#4'í)” ·â whK—$jQÏKNɯ˜)uªåm£žœ¤½/»^”ñÉmðåoó¿ËHG\`4*Ó®2p"Ä'ÜâŽì\9o½ŠÐ½Y¨‰f…-áaB§GÿªL2¬Êf !h˜ìK@æH?ë šC•DñÅÝÔ}Œc–}ÇYeÆ+0ªG™s^¤Â‹ÿ.?µ˜lòNÁ¾â¨§ˆ°£p§½ÂZí}É:²Sbì±C¡ÃHK@d–^<.Ùlw¡:oʼ¤H==åò·„•³ÎtY‚í|>‘ så1#Ó»ñ6r-vÄšcŒÆR“8ñÑ]k} MóÃÀÚ.'q1¹ÈB“}}APäéÿýì#ýÁºiÕ;l)‰áY3ô=ß°ñ8“5ï]‡^Š–šŠj± Üÿl‘Ýx1}côŒóÂã8À¾y2ڊ̇p¬ÁºÔY¹äÐ ~'Üé%Øo\u™7éç—fï‰Ò`C³ñY—tP’+–DyöÒÐ'ÒÔC•–‰Ò6Ðù#e»D7dæ¸4ÔÉŸxÞ”,†œZ´{щ½LŸÿ^rÊ4ƃ=z™\.í`qãC‘´­¸‚H0ºÆ²nvAŽÛøKeÃHBÕ¤•¬‹ÝO¯eäc3o·sJèmÈE=J-[Ѱô§üƒ“FÌXòø%w<~|5 šé1U[G) ±7=£(éP‹RnYP*–‰ªMO-P!7l6Áûæ ]΃0-7 m…yÍôˆÈç.i˜5æZ“À”õwšqµ©Á]Žæil˜¯ç1F»ê]"!öJó¤©Wû)¢”Ò øâÚÒ";èdú ¤¡N7ÿ%%ªÀ“Šzì#ÛC» j{—T°?£kËÄkÁ_SîžéVx>ÔT´"`‡—w†ƒa´ “V2Эˉó €Àîö±«N«›GHGüb“ÀêÎÏq~@Ú׈GVXm$ÀÎQÓ°nPa1ü+˜™ U©]Êä¥É› :o÷÷ Xx- ÌØp|éž–†±9õ ZÛP;à#=^5¡àóR6•„X¶»Ÿ¢˜èäu>Ëä¡¡²°Ss„O'Žß¼ öü‰ß«B*ÁpôFÎJªÞká†**©K±Þf ³”î’•²S³î~ÎÈ9 V?•ré4q~6¬h ê[Y>”57™ØeõVŽ×Ò€SBèÇ+O8rú+ùµ_“Y¥Öî"¸ëåÞn!§’E|ku?=Q°ÒmûŽ [æʘŸ@rÿ1!-Ùûkrõ‡uè$amÜ )Œ,ÂÊ1y2€¾¶šFÝIQÛå±kƒ>Ð)D㵦²%ÄŸ•Ýzá]J^4ðÿ¿=Ü"MK2bëákç´y~FtªŽDá)g¥ÏUhð ö”YŸ-ŒmæÔç"›ųŠ~0ÛS#´bò¥²–¼Ã¿Ó±-u¥µZX¡ŸÑiÂ~™è6±–ܓՊfbK°ÿ—²<… ÔZÚVv’Ìö޹5h2-‘pf;#Nl"ŠÛ-¢6âPÔ©àÔ:Ã¡Ï Yr]b}Dk§»K¬`jáÖ¯(×€ô®•ÌÝ羂…'oÑ10¢«ržT íÅ™Lñ˜bIL·¦uÆa/uMŠ˜.sUI[>u(\²c [šÎcwÜqžËdÝçî!&’Ç>O”«‹]9õü§n¸Ùø°sdòAJ æIJŸ'£7‚™ÊàÞ©/ÙÛJt= ižo%buÕšq£ýg;7XWÓg¿zÜ3ú䢭钸ßÿ;ü}NÞv„ƒòÃWfz½\Xhûໆ¬Š{¤O3 hK®&Ž$Gª:s rVöQöbc8%Uå. Ðég9F=¢À †ñÝ¡'|[\üÿcVpgƒöÀI‘]†Þuq¡šZá¢nhmžÈ± FÖLÿ§âBý¥ ›ùF€n‰Ÿÿlmœ@ÜÜ8ŒÈ§8\°=¼ÕKÇvN˜ÕÿÈ’ÚÓˆJhæ%u¢7(Úãò·&ÈYŸúŠ“í'³rãÒy'àbšì!ï+¼473i¡Ô’oBнÃÛjçÒ»¤3чz™ÁVW`ÍHÂuäoÌƼîþY S4+T«B)Kë)'—wþäE¬óZ„AÅÖ\M+NiòCû‡0Úûƒyå|+¤b¬ç/h#Ð’Q½£Úa’³çÚC„ƒÕ9ÓOl(@yd‚÷/Zšoƒ‰ÿm@9™ÃÄ_Ò‚ˆ´CǼK0¾CîsxÎU*nª~¡N)²™9GéÐ7Øz«Û &…‡‰ø£^:ØÑC˜­,"ëî` G‹=]5Žúsq-èïD?Ƚë¶‹®„-¼7¡Igˆ ‘ǠǯBK"5”@Å»úz&´#{Ï×þté”?~“sIÃ=6‰èc¨êÂÉÝ ÿzzíŠsÇKßÒ´Ü qÞói}Îé47x„¢‚zÏݶ¹ | »6%‹=”™ùñdií0«Çc1í}03îDn4 f\'g ?e´XÐByéõƒóý`à•™54NO¥J‹ k“¾¢I8F³¦Ð¥ÎÈ4°JošÌÑ6šOê0dË…ûµ‘úχIð! ŽÁêØuê-:Ÿü ÆÕ{¯‰ß—‰ ñ¦­ÿñRñ¸‡!£ …åž %õ Š  pô¹+j¥=¤¯Z«Tš.=q&\OHö &ª¡¹¢Kžddö§»V¹¸Þ£(v£\¸RïL²žÚ€Ã}[œq%‹A¯ûK´3œ]²†g{=S©wÊ÷œ„è -~~g3mÏ€M[«¹ã„oièòý€ƒ º\>/¡D3Ĉ-Ä"ã&‡Db×0A×l&˶àW¾é™ƒ·þ&˜Öº4 ªÞùqŽ7éŸ&•nÝ#xš,‡Uû]µÅ2œf êâÆûCâЖˆ`°Š/æÔjÎ@D!›Þ¸<~ÔÆÙ×\%a;™ûš_Àeêóä¦5–¥Ê›ù "H—ȰüoBÅýë‰íEÀ”#âé¿}×3p"“ø4#ÊUn# žSqúí0eƲ۠¹jéoñ¦%«ÆÆó³6Þ[6CËWÓà!¤¯äéXFõÇ£6$2DŽô‹m¢vâÙ äpûùS:ÏeƒÂšÑ¯ûü*/îÉb$ÊͶ&×TaR=“?öÉ®<Àè «u§Œ—:7OvÁó2¾EÝà«“òÌ ªôK"{€2M`]3и„I¾ªa¨)*çXŽŽ…¼BxíÝ`æéÔÄàº}…úu G bc€¢gøYâºW¼K;Øüì E*‡CŠaUФ[?Ás›G}ã}# kÓ¾\2yýÖ=èÖ¨¿©>8w6ÒôY‡mô @s56ú"R*S×µ †8eÃ>6¢»kÔ?ÊPY_CÁ#ïß»\—a„˜±‘Gø˜L[JšÆ'ó®c7gÎZ1(Rsúï(•ÏØUëDœÒUãÓÃõÊl´¹—Þ;f„ªK&:„lô)bœ–ÅÑÐÜ$}~vΘ]oòŒÞxᆤšß1ÔYÞß Ç•Øä´õ´ÿ½2„iP!èíî)rG´Äˆ?E¶²˜JÃ\êÊjÀŽmô©¥˜eeû_9¼maDÏ”ÎÎÞ€Þ÷Ü3íš~Y‘6ž,r6±Ò ›œµj·œÙ®Qò÷Ð=!R+c®:Ä Ë)§¤(|ºFº÷ämš)bŸ‚Æ‘½cÌ¢·µÊÈÍd€jG`Ú=.Ú"„=8u QÒ7´¼ÑŸXÝYú‘\á¾¼ úQ䀂ht:ª¹¢EÃ$ÉÊádæS;\úù Yl›Ÿ‹Gˆ Öãžâð—äµ5 Tþyø0©a1áňø‡ð: õoK{îÎíÐÿârÞ ©‰b¥Ë߃àkÖãRL=¡÷ò»f²«ZÜôbnS[:ôé³?Ë•{Ô€b­v@ÔjIJ¬ÝL÷]Š}ËŽÔR7øÿoªÚ\öhÛtê`~_«²ðÚO¹CGñ3ôè¤bCØ«K DkáÆmž²P£¾6?3x;tÓwÛ­t‚á¿2Xrê¸ëIi˜X6_²'·ˆ¦ç’]<Žˆ^Gèuâ9Ä´@e`  ¢S)€ÖTìC8Ú}fÁÓÓá<À4IJÂÞÃÛò6c^–1xÏWœ÷‡Lãü3—ÒhQÀeÄAÚZË|bT¬÷˜ë zaÖi);µ²ò×½¹¨kaX8YF·Æ' ©ñÈ禱4Göu0½s4vý›WQ½¹pbëžH8a›ž$ÓŠ%¹™ßT¿aî7ôÜ·œv¾äm>ŒT á–BCtüŠ)PÁñϳ¤EL-y>Ç4ÕìÆ®Š˜ãRéî{™ZH=¦ëAGÌRë(‰öF8â!5Dc8Ö²Œ¤éÉÖ/Ž-žžÝ¾éŸuÀf+dñ¥2›¤;¢‰´šú¯vŸ‰j«blèq<ƒzöØ„‰3Òaý ­±¬cË[`› )ijw×a¦71uÁ™Õ’Ц@¾æBqzM³ v½f™¤µe#½†,‡÷Ù…[€P~z´¢Æ‹8k?j%ËÎàaS¿){Ÿêé N–x÷;Ébf€_ÁZc ­;©p@v¨tº­™ βËDŽó×:Ç÷«]ïI.@ÉJÀÆà-AæK@Ë=¡ß\…Ö]®‡ )D6+ËŽM¹Í@ðÆo{ 4Dd %DŸ8cò‰5ìèâ3"Ÿ”iNƒ+ ÂCpp準z<Ñ*¡%å3©"¼öåôT°§T¡ ÙjîžNt4û–TDWÍn›šè¿ˆup›:(É¥—ñ*÷zW£ëèÑÌ@(3Ü%§§ÆD VøÇ͵ë"ÕB8·.-÷˜8‡”ZZh1>'úUw–w‘—€ÅÆÚ‡ÒÑXo7¡±Ñk¨îû$¥“<`×MèdÁ {[qEUcãuÏ›ÄXõQHÄ]wšçPÒ3g·îÅÒÑ M)‰JÅdKòjhžhÕd̮ŗgÊMôìËP,IìæoU‹g,vÜ]ìh«‰aÎÝgl_àÙÌOu?²Âcj€F ›xaŽSo´r+h²(<‘[B¯¥$}àÛó;¤ãùb­¾lòºß’e ¤Œ¨Íª"Tv&öî*ž3&²¹RâFòÑ9Ô£‰Sb3C@gµa秬ÙA`éï3àoœ¸°ÄZHQIüÒ¸g(¾Bõ£ y'Š­}1·®CEý3Å…ñ7y¶¨—]21_^—^N´~BÏ„¶Ã7í³ãQóðíŠX²hT zƒ P­É=s¼œ«Î†/¼­…—E¹'b¶ ÂÁà ‰º“\+X׃D˜uï’©Ã âT8z½ÉwÁWîdb¦½}°EC^Piš-³‹ Õ¿­±¼ºÃl£öhPu,´RE"Çqû ɯ›œÌ”“àf ênв–& Aú1¨: æ—ˆ7`£ƒ“`TPáaÚAN;N_ÕB¸Ã±hȘw,Iø`F¤­Ó¡†î[\;MAxÎ>N/uØgè¼PÑ-®ëpR…`9ðžH˜õXÞÔt½Š´Œ™éÛ ûÕö7€|wó‡‚ìïæcÑqÈ M¦ŠÌ“±d È=‹X…ÿzrû.C+ãf¿Ð}]qöasÞ†¿‡ÞáÕ°yš¡Ë _Æù2å,ÊȘ¨¢/µf¯FtŽ€¶½ˆvû7²Ë¶éó6àËíá{0Ü3—Ø*óWgçnˆÛJÂ[îí¥Bý^ÆÚ(b|ñ¯¥XÛ^ƒË|ú€_œ2y¥¢šoS’ƒÊ}á­Çƒ–Ó°A|dîx±G±$O7ˆàî‹¥¨•·üÌH¨ÙçÊ+‚Jp¸ìÆCý,˜–Iµ$fî/³t±Ú¢«¹ŸP&ÆCSµÏj …1~Jçÿ)˜×NÏ»NTªX'W2Sc‚¡É€ó+E¨OÒ}¤hék àÔW#ÃÁÿîáTU…ªáÍž3Ë=)¦KúÐØqøÇºÐá(/qQ-º uëÆºŸMÊtŠÉÌþ¯«„‚íðÒob}oåÆp0¾û®ŸâJi~RGøòûÁ7V&UÞ+³]è«<ŽJ‡+uäd`aBÈ&^wÒ“½~‹z† †.Žmø *K²ƒË“e¡µ´kìpO [q¦3X\[2 l<5HÓ¥|uã8Æu ½FŽ)ÈœæIß¾áMöù´Qªú‹›Å¬ÀUúˆ:¦n£#@TÍ»,6ÝúßàßhCÖ9ÁÔ1S@/=$ðD\”¼í<>®¡qðFÉÛÎú÷‚lcÒ“" ºÔ¯mÁÓdý”Æ>3_輂 ü.ÚÛ•¯ÙÐ*¸Ö“ÂÐõS‰Çe€3i¸­Qõ|5òÙ®Û}®ÿÞ¦Õ†MñÃ’#‰ÖÈ•ua15‚§äÅCRÙM‚ –çf²c‰ $®SG@,`çÔëfõVH’v@W'P=lŽ dn“ÕyS8€^‰o¾ ÀÁkÞ†òÄvRý§o‹³6O‘©ØÐÝì\ô×2w[EÊaµ2ÞfR3ÔÐ0]à¥Z㽡k)·ú® ÷æ YPüßJ·ŽJ†S0‰ v*Û˜ä³ÑP[@@ÓòuølxNµÆ×sÁ]ôü*1“×ûp[[;J,kW6ž‚û½¿fÛ9djf¢7 ܜ_}8õHÑ«;žøÁß±Rªõd[¥ü]ªsšóRÕñÜÉAéÐÚ§ÊÑ9óÖX§¤N0çN]ŽvW.l8QQ(Ã7õ‚c†ëÚóñ&X¸²’]€ø ¼€}‚Ï1Lû@³¨2šìˆÌöâ”"V(TØ£r-ó–)©é˜ÅF¾`>׆À%1ÐïS.¼_U'~ÕFÏ¥²‡Þ¤1·_z¦TH[ú»Ow;öSÑþ4ˆ6šÍˉ‘¢»ÍŒ¨•–õ4s–¢€G5¹á?½Íì£ó‹Û掺-;zÈŸQémd¡ÒIßÐ!D‚‘`<ŒÎÁMù ­T %Yè$O›È’K0Mª[§ ×¬wR’ÝÉ% âã½ñB# #—TcÓ <–Hz}×9¯¥¡îTlB«ˆûðEN|üá ljê¶J“Ñ^Ž^Ø%£I½@ÚÞ.X𜙇þ«é@LN¨È]e¹¢k¬G0³HóðyåÆX÷¨ð´[K±<ƒJ´Æƒz‚ùÀ$p¾Ê|EN²T‰¨è„-.×9#vq-ΧÎbx4Œ Ò\nÚ!£y­º§Ž  MÓHà?§«k6cYÄ>É´Ó9×@o†¹püæ²6[lŠÆ¿³éj-mªÃËcšIbëNwžéࣂÚv3«“ë=is:ˆà‘Ÿxƒž<8˜­ ’ 4HFÞe-OTøã²'0/üõ¡íä΀œÐÓ} ×™§¬Eæ‡v G‹é¦ ôÙÏKe!i¦.Ø¢£ 8a=|ÇPõ«JŸ¢I/˜’.]úê]ˆ5â¬ic›ú¿¿œ·ú‚ÔP°¯ªÐ¬>ô:›îÊæñÑR,ññ޹ú¡ýÖ×Öªí=KìÉ#‘H¶X³1!½´' ®£¤@É7ô¼Kõ£kÄ îÂÒþRp¢æ2à JÃ#½¢ÎŒfKɬ­af¹–ZÜsH'–#ˆ'iÓ¶Èß XúyÈ®¢ ‚¡n~Ã/»ã5B"äT¸ÀâëÉ‘†|Áe¡ÂºGLaLDBm´Q#¶éRv³ƒÂû1–‘L0à%º.šdZÕxüÃ÷;;ÒŒ…KÕä©kZZ¬eýK©vÝËà¦A.sû Ï=a¾çT&~îeúêF“à\Ü›Ÿ˜Ã‰—ššÍ¢Ÿ¥%Šg]Eßs°y ”¾Uu‡PŒYVŽbèÈà>u¯pl¼Ç–‰~éÉš:7Smูù”8¢ˆšø›`zgm ½}ixQßF²a” ‚ôàµFU‚{‚¨óQè¢ÜZc]PÇNÌýX´m(1š)’H™xb£{“qá úé¬DdxlÿAç /R¼Úi]µ&–í!n äú^4HºI¾°õå¸übòr££E®ï\ØeÕ |Ú@†€¿8Ó_ÉBÎ —Å$Ö'vX—äM›OLúßN‘êå­TDÀ D[¶JDõõX¥DÎ ù;û&ÞÙø$#L–ÀÝ;fÛás2æè2Æ,–pe ê Ø`,£ )ÿ šiD›ÛhÖˆ.¨¿­"Py`A´žãአu­JNå¸rK5Pj› '¿/wS±ÓþÏ¢¨g•œA÷)¯Ùð¾ ùäêgGóuúÞG=&šýãâJ_•Ë—Æ 5Ïø{v rü Ç„÷1b}ÝõO÷¢ÙEegA€ç¤ËGë‡ÏбÖïþ&›ø=—ç^®8høq”±äwÂSÑ„ér8wã¡M³æÙ)ðb’›¾ñr™­— ‘©'W@ÞF¥Óï/èõ+‡¦œ¨âltîZ ƒËÜŽ÷ó8¦]}¦æ‚ì”ß“V·bHü[ hS'ƒÇÖ—òÒ°®žõZ­Š†LÀLd»M\¢8ĵˆ,gq)`(öEŽhõÿs¸70,gÃXN¢~Ÿëz•LªŠHÒ+QÂVÃ%×¼¶îËcÂÚ…YŸB,u«Èú©*EFÖí[¾L¦Ï–邵òOXeÔà®”¨‘é.AÞÚŠ è¯ÖwV/Bùœø HÖ±›Äü¡‘¼GºÉÒ· s„¨Ð †Îö¥Ý`è'JjR³B»¾–À 5¬È^mpo˜¡ÿÔi\¹—E^ÿsÙŒ™^–oy”5 $ä°‚-¾‘ßhšÇ¾§•mv†f½;@þRÚbÖÅÀ¹µ/M< /›÷®ebÈ|ì°ˆ)0TsÉ‹éÙÍ3ø7k“oeúCªÁÌ q›âH»›À:P¬ÎKÛà¹ôêuãW'+ïS8‡•+/€b7àóö¿ûX`JMë'_ÌËt«ï,BêçÌPYAKfddÒ«¯)£Q2TbõÀ2Í÷# ᇺŸœÓò0A—[1ϾÄg rË gäJ‹Åg©’’0#)8P«:+ñOzœ×‚³ã“QŸÐe0šÞÿ!÷ÕØ¾¸ÊÈêqôÁ "eÆš2G0Äh‹tÕYez±h<;+åÜßD$°t›«úš$I¡S²k …rpl9MTùi>¯ø7(.cÎE)¼[É4~B wF]$5^¦¹\CXןõ°J±rv m,?ï¹g¼ °ÊýGkÆ@/©‘üÇ@òqÕ7S—Ôe¢éDš¦oàXb£A©ÔÄÖ°3ÓD'=aÉ)MˆÔêh°nT/˜haºÜÇsZÝõ¯?îÙß•ÛVvkÓƒ}£óz*ñ›~ÕÝGÉ®ì¼@šö‹.SÒKìB%E„ó´DÇ ¯-#\Ý¢ÃàÙÌnQ}L;êìçuçv˜g.ÅÉM%ÏH¤ k¿9ƒ(§â†-|TÊt§tÝ*³ €U =2 c<[Å»÷P=ªZ·co'ðU¹˹^y¥ƒõ·lÝËR1C¡%¿³å=P,¬.Ž& rªEŸ™–ÌÐk‡–Þ)æ“2ªó²€sÀWÀu \Ó1<»ª2N 5Qþ;–=mBþ,®Ë"ð»“5±Œ–›÷“Âÿ_2“h{/6¦™}`¬.ÊÜ81Iêè‰^¤ÅŸ¼VšÜrj\"3ÿÍ\‘¸³ýALwé‹"ŠIÝw•Ë>É~)®:l®=qK}9\4çQ»ô]PRã²²ÉFóvÁRLë)tBg©ÿÛ.ªNfé^×=kÕßðÅ5šŒ5÷Ç@&½…25L·×0\5!­6áÝjÃÅ.;×ÎF3ygËè¥?l(¯'-f¸$PþÑ)f-âĵN¹Ø_r†ÇÜ– }Š"ö>·Ó5 UsØpUA†ðævj½Åƒ¯¡[á™ßõ>uùåÐÆxiÝ(MY ùøMeÊ*F G¶ìwO3M¸ù*0<%j1ý6b0ð*èÆM¡@ÍQ‘’:<Éü×½ON =S)ãEcœ…By™œÜ1Eíõ=ž,z f¨8òéÃn_Ž ‰È`Çœ¹>“ 9/Ì19(>&¾ßd×.˜–­8ÉZ|5ºÎ6ðȇâpG°.§¢8{Á2";õ‡Ëö\pmÄ$´áÂÙÌöÆO`3xíF¹ý>õA{‡€SćbyõóÛm¦8•៊9•qž›Å"SÜ¿ö| üPꜤrᾩ³÷•âèîÝ "ùãã"ˆãÏA¼œ@Žo¨ØæÆíœÓv% €¬cìØìØØ±í¤cÛ¶m۶ݱ“ŽmÛ¶ÝÑüë¼Â¹›5õuYUßM¹i+¾J¸Å°=ìío[º~à;Ót˜~:o£»²í^ûv¬qdH Ë/=inú®`@²kdÉlÖ°§;!Õ9ˆ²¦é——Rƒxþ1¦!F›RBÖb+iÔ=«à‚¡(æÕŽVtãŽNI7Éã{`ÌŸ1L“‘ ÛÌ‘ûü&ˆ5KKêùU•–´•ey kùn…«çBæ˜4Û›yÛ6Ú[ìñ0νX~ÌÙ?”‘1˜Gfˆe,»yì®;&gw·µCFJír´ICø´·Jû!]Ïà+qì(GYCi`¢ôI§‘ó”ÎÛdc«T¹aŸ~?Rá2U'ÎO®ñ¡zÞ5dTøõ!„˜oˆ|´¥°êw`2Æ\çÈ” }ºã½0¾;¯A_ÀyÕ¼?ɺHÛoØð0ˆ(P¨eKå#”–ÁKJ‰g“™ëæf…íÂqF¨PNÿ(‹Ž®ÒÒM‘ ÞºaU‚ЀÙe:Õ¹Z™-ÿfàF¡(¶>/r ³¸ FáK$´ÃÆ9Åê×+naiÎ*‹Ò×€ A(|{¢ªM¾üH-¾1¸Ä ­peíiK—áñ¿¢)üodo=BG FÞulg…¸•~•¿¾™¼87$sš‘þ3žqLÎU„1éGÏo(QªsîküØÓ½zzl2œj‚Š)ÎÉÓ†!Œ“2ç`z³û¡«Î mA¼­k—,fœbÚºËzÝÈ/®tbvEÆ ˜–‘î>ø SÁÃÏßf†ÃŒ[ûêo®¬¢Å<ÉQU¨/…¶c“™+M.õKk*n¢4­8zªÄôw8lØè=“üi©ëouQü<_ÝÁ ã•MtÑ ›;œ))“‚pûþ½ÏßO½¦{íFǸòÒãv08ÿo^Ô|l»‹’@°õü^~èqÏís¿oÜõA̾$h3ž:hô˜‰‡Aó+p—ï|Ä%œû¡&V·9üdÑj¥3¸1rüÑéÑ&×n!£\°·'“;¼É7¡9ðG(" Õª-Y8£Åö½e»FÍ€uÀXÍCR}PÿÍ»qä¼úC–š<èTME’Úoß/ø®¯ÙpÀ=òÜ!æòýè,Õ’ÕMµÖò©¹3¹`™4ÊÀN¶jio;žÈTž‹LÃ2CWê¢éDÀiÉóÖÀ¸†sÚ8榔Hk›ÈRUò¡¿Tì×§&L2ˆI+ÚcqÝyðÖ½g(Fò×ÌÝi8e%ü¨Wƒ¾C{Vžm»ýEóõí)‹]ÆM:ÿ­²™Ic _0ìââ«wTÙÄ‹”~Ñœ¸Àâ»#3ɑזvô W«ZIà­ò¢{ÀFå®h½C7,ì’ ß)ãd¿–ÎG1E¿CʰZs!i ¨í“QÆ‹è„Êíyã2¬}¬u¯R’!Ãbý¸¯fD*íìk£#wäX×üòѹXòèr–ŸƒÐUöiÐa²Ì8“Q¢-8”'>%ÇŠ£ô}»¶Ã¢q ‘ÓÆò6êBÐÄ®†?þ•6 ªä 'ŒN̬Â3[y<<õ÷Ý)äÈ//¡aмî”}—‘ÜÁgžWڑĨ®£|þUvÆî6ýÛºŽï¿ÚFæº,r~àuÆÒùç8Î.úo}{D>UÒ‘ˆi4„±¡2U¬…5dTÏBÒX_Æ…×·Äik ÖEÁËâµG¿XÓ -Zë·o°ðÇ~µáüü¿käOêïÜ™\}.A ´æÀÊctfNÑ®†ï—² 9í@ØØ§†½©À*Ë$Ÿ$ïéje&FºV‰´ý¹¾WOH[–÷ºžÊ"‘¼‰‡èvâúë4²¼s¥+1(5¥føeshćýÌó¼Å‚y$;Õ£ëg~Ò0›œA›‹‘.Ç›™òŸÌ:åtÒ=1Ÿ¢ 7ô`;2U½úšíDM½6І:C­Â?PÇG‡ï'+šò[!•ª}”ë²ýr¦=¼Vmàpä{xXhS‡ÉäüØ47\pCí2š©$áXÊíñN=ü PövœÞB¤µØ@±í z½ãf…½¤á_R?™:QÎG(»¦_ÕÉ ŠVÆTHlJæÉ8¦´«Q}*‡Ì,©_‘Æc¶BB¡#]Ÿâ*ðd¯Œ 7?…Ø;+fò#’pïa¤=ÑDû8²H ëêÛI–õÏxÌw2:#h‰BM¯l M™Î3…­Tj UaˆxÀ{ár„¼BÆ® ^…à»Eæ|VØ£–å=è&3kÍ*ѶJK´bžV¯§:^-'¼¸ôßàT*@Í! /œ °ˆÃ»$ÔŒÅy=§ýì½Í:tZV†fºÁ‘[_ȉu¤ÃºûœLq…›N^°Né:Õ?rÐ|ýTÕ{F»ˆ8÷#Ô#˜e–Ÿ›çNô!²7¦ Ä^ÿ~°{¤$QïŸEZÕ8YBg‡ •B‡õ_K:ß) íö†é°¹‡·-qæŽ*uâÜð¬(dNÙG½áFb2ˆnh<Ç4Þ‘ÌaNÎ¥ià™Ì'Ây|Þ…/ݾA”KoÎm²&O³ª˜•lglêñEòUDÇB2#ڮɻ<áÈ“`y“k²q¼5‡N*v>\Ö)£—ŒVÇë¡ñmyç¿®2_y<²Ï'Ò1×Çxþ\h35çâw¾ð鉀ŸAäBåÃ/è´Rì)Þæ¯~¢Þ­wî)Èoè8aqµŸÉ•@›sÜv[·7x ƒf.à8¨XÙ\aظ3llî;§¸èÜÙßeXɸl.~—õ¨ø|Êy§¶±h?cºË—í¢%"ïM] "]ëdÞÆè¿…Ú%¶R1PÜÆô÷¦ {ÌŠP 5áá¬Ù¶-RO=JÓ!à§Ê‘’µ±a©]zˆ¯/ù§„çiHÀ•¹(ž%êe™½M<‹ Ž9ðÕ½™ª‘#Ô2«¢ÎUKÊÉEÎZ–¯D‡p¸ ÷S9fDÕA ¥hE–„‰>ÅSKâUéàœlŠ\no_‹Šžö-çzs0o?Z”03åÚI*Êü _cTòJŠu‰”èÆÏ©À½¦5˜›úë¡ÀRˆËsU^2³5‡æŽ 'bÔæf´šÞéÚ´Fdz·†˜E÷𹲤>…7úÃ'ÓÙñ .Pò4²¿ªÎ̵3–æâ‹;ddSÖW!„Ë|ãä³¢ÙaŒ uÕVÚLsn+mœLò%¦ûùÔ¯°’°Ü‘ ú°Ln±÷žå$RxÜ—v©ƒSV¥çå–Gñ]Ü+Ù.Ýsú‡Hyþ¡ArcÐ]–í‘ÐÎx±ßèÝ)hXÛ‰£È}—Ϊ»tÚ¹¡Ý±¶©ËÆ"Ó½G…sûhèt©Š‚'Z\nR·—2AUïߌ2V÷F:aüÔÎÑ•œ7ªþÀ'ü0bºûÓ´eP£)/7q7ðŠêsLê×Óߦޱå|¿Ôzów„' IPš~ÿ{4ï©^CäëujÊm!Âç&C¥4Œƒ¿;X÷/$r LE›í ¬@Ùæù&–ÄŽ­ƒ‡VÒ°ùTŠÆ«»ßZil1ê¼ TIY{^UÖ¶é1ŽÆä+'$5pæL(ÿEnÒ>?ãB0ëgZ¬J5CíÍMíX<‹6Ý*ý*²”.…Ln‹jÆæ   ’ž”:jÝèôÆ=³¬ â1±µeê±@­ÇOn ]/{£âW—NÃny¬ABËêpê蟲4ud õk ê“è>– ækóñší¯£¯òf7mžT¢ º]™’)Òp ܵuÃuòÙúåÁñ›·F¶3q7i¥Héê7B^0Û! ‘|tîsÈŽQÇå Î_mcÛÅ'ÁO³÷ÿ ÿÝ?{àN™„õ‘¾rµWWöpÈ@ô8É™Ä Íüä ÜKs8hÚÙøŠÚ©‚A$ Ì5¢Í­D&9nà X¦É›æˆÒdPÁ$bþ#ÒdüõóHäÂV28[O¸Ã0ÒA™bhUáq|I°un1"1ëÖRn~… ȼÔùûH9X­À /_‚Þ‚w”c`0AøÁ•öêŸä€9´-ã$'7âJˆ%ÅMú-nų7çö¥Œ²¨ÚUâÁ! _èf†pÃkÖIápìíÍj ‘Xã®ß¦fy-ÝînÉRþ+ðþºè@vÞ ÉïjGžÒ›F¶øXJ´xmd%ÅdwPþ~õZØÿÄL8Ó–+û×Ù“Clø±Ñ³Í²ÖìjÁ«®Xr«¨Ý™Ò­2tƒS»ãJ€åòýlYÜ䲪'>ûÈdëñÇŠˆûô·òèÚVà|þ$ wâ1—Oæå¯³ØT 1ØšO#0†1ä" –âõíéÕÆ qõÝ/Y0¡Î€-4tÂ.xýa—ĥŕlkU)¨à²n’Â…Ksêý܈’H¼î1¶2EI_,\,Ø0HûœååW>´÷͹ºP¦Å\}°Äú«·¼á¶†µ|îšÕíß lOD¸ð>¸68‘3©È +C:3&exWá3ÌZ|塯jù¨©uôñ³±¹†\ÐL ÒJ°†BþjäaÆ/êÒ%Ñà§? #âƒsÔ½ð{1¨r?:à†ï—"ÂrŸb„°„'9û«£ˆùéQÐqÍyNR1X+¢dsÅkkcvvt’!ù…vTNÁ1%:VµB"jÞî*Ë®äùUˆèªÿ`Ü "“?kOoÊB‹ëB–§órá Ý(.J¡ÚCÉÆ€¦üóAÛ?[í7e]‚›B˰_ì>;¥´™­°"ûÅ¥öTêºzÛ´F´áO¾w½Ö‰m-ºÌ{T"¤YIû0Å0¶RQ\­Ö»…TüoÉ÷·*•8¸ù\¼f.›úN0}¤:àSöùq e±ID²g’0}Oî°Æ×ÜÀpý¾4 Æ1¡¤/i†(EþCóõÇÝQš: šŸ×AöçNŒÂb|ô©÷110y0Æý•€‰îÅé;ÇU³´æ"£'?Z†é–oÈÝÐ ,ìq °’:߿ܵ©ªØ¶g^«õÊØ²Zîݰ¥ú' ¿y%²yö2MÙîàdÅ%_?¯®¾H2'Ô_d?7*-Òæ‡Š&Ì­KÁ¨ˆÉÂÇŸÑ_I)JoA†[ÿ`ÍZìœjs­|Ì^<÷T-Îà³æµÀò3§yË̓,Žtw|ÃÁätŠè{.›&‰p,„eÔ4×gK&Óø 81þU’³>›ÑltwñÖ^¼¾Ô5… L‘ÅÁ¡6ï<¿ ‚ÈS€°»±kH¢À3|+Ë›ËÃ_aót*´ÇÕßÝÚd¥CÆŠ)|bÃ¥Ø ³ý»Í&È&ÖF®¬¥LIé›-0,Ø_áçj×ô<óÕºuÛÊi\”yÞSÒ7âã›ô¯ §Òµ·™žÒÎÖ2jÜúV¥ ˜º[¿êŽEÎóFµ7ëªäZŽ“üŽ©÷tœÕ#IÔ¼4’íŽKýN!ePKÀ²Ðds€GƵœÂNÃ0‚@˜Î‘ÃD‰)˜:-U‡ZC‘e/g4²u‰£g¸J_Pì/ ¼¯*5 –:ÇÇ62Ñ•l,÷T¶ÔZ{‹Ó)Ä6ÏbyLÈ›fL*6©Ó¥='Í–.šì£Owõ°x• ³·™o/„%ÕÔiL»Àà±ôd+Qd.H0=‰ü-L ¨âã—c‰“ÜÊÈDd¾Lð? TqÇ0åÁ|p²8’o4;9 Ç3¤Ñ;@ýM+£¢7¿’Œ- “_ÝÉlß\5‰žnzL›¶ìÓJøF"ÆnŽŸŠk}ºôTÒ?÷ Êžp,VŠêU1zc¶þŽÄÏÑ£R53•\ÅWKÙHq[_›ºY=p<>NîB[+;××Xw°¥8è$￯v­rzýÛ3”Ò“æ<…ޤ &J¡Mw&¼Þ»%ÿ5½À”Ͻ×à—ë&³(x×6UÛt‚9lêü7çÊÞ^¨ä»KU”:Æa¸BPPDʘòý¥€ªm0k¨|ýtS`úªÁþ¥l.B‚AÇÖ ÉÛÅ/l½ÚVéA AÝI“Y¼ygø^hÎbß;Dˆx÷¤çiR®}Áß æk ÖÄ]zŠúZc99æm^ìϲe7}]‚Cbþ‡¨¢rÏɵ^ê~™ë—k¦1Kä¶·bmêrŒWïˆ]QûÜ©üƒöŠ™ 67 5b8^(ÒOOßn KYyŒ'.MˆÛM„ûSÂ"Ôgí8a‰€Y»‘”¦¬ =DÇïåAÄ~“¾ */ú£„O2Mw6‚݆È;0ŒAÇþïˆ?öë1¹6yqë™C¯Nœæ\@1ñý`RÞz¾ßC;R•Mÿ›\渘mGZÜ%gÜÓË ÒÅSÛ—ñ’rúZƃ\“ΫNh׫ÃîØŸhExÞ¿úŸ ß„ì–ÉTu´{ŒHÜy=˜ô0” U ¾wˆQ°´ü¡*nt]ÒÞ4œÖ%ÍôåôµžÒ’¨a65÷ª=BùéŽÀ÷“êÑ.N–DBvX ½¤ƒäj¢;»4I¥?ˆ«‰ìƒÔÓIWàâ$^]OÅÃ6D#, 9‚ ?cšX?PIXðG¶MË:‘¥S•"}”¤AIµW“=©šÌÚ†WyUڵ˽Ðñ$O¡Õo•_˜ªCWÊðJÊe®Å°£DKºOçcFor´fƒtÖß–ý£Î|aîÐϘ$gƒ'…F#S1Ì[vEF:å‹ÄØÕ„>šYbmI'(Íȯ³ÁÂ=ë[]{„Ð5æ‹h\Úí¤ùæ´ˆsÆí;Ëèiem.…tnÅy´G™¯¯Œ`jEOÃôMïV죛0p^PAñ•±W¶¶‹íåðʘÒü&¯µb‰±p?Ȇþ{&ÔËÝ·q\¢<i’[a•0ªÒÀFNë»Ú_‘æµL/ëÖŠæ‡x¹Ô¶ú!ˆN‚¼Q‡ì?ŽirR„ŽÙVÁë³½}&šÀÜW³ZvwVÀœ騾–~ õ½ËCuÒ­Äë²\7È{1zݔš†›k<0m›+"Ólô?Û4óÚ\•ZyɯK×}(k¶Q´5•‰õÄòfƒ·T˜ÓH︽ y5y䔿ãRÖ! =GëÔEûw9UøÓm8ö|­çµýÍÛqnÂJÌü@…mQ¥YsŽ…Æœü~ZtJ®ëñÀnXˆv<ð}ç—¼Ük*zŸ:#UA6ÏbóÒj= Ãàq’?“§¡"ÄÆÞk s9lªO£3Ùi™ÀÉ4ØBùt?TD¨v¶Þ4á?Ûâ1·Ž^Xmó¡©½¡<«›$ÔíLrn™\uù¼f: gH¥Ó<3]­ß‹5ðR6«·Dj)€}õeãoõxËrBœeRý‰!#ÊÐÿX[4(2ˤ.Y|â viíA°~_âל©o!Q>¢·n‘쟮o âh˜©“˜%HóVo¸QÿY©+&~\±eR™¸î!HºŽjêtÖ.™gw¨kØ”ªþ᧪!-/pIC.IzRN0t_]Îô‡Ø8å p –#Pe!¬”¢‚úd”‘™‡oÒÎAVWyn~N­®#÷“u§®„äœî0ú J&nˆX Gèã5 ¶J¦˜`6M{î;¼¾6’¬ íÇKKÎ+ޤ©ƒM5¼ŸvÃñ^„ÕºÙØWëÜž§à1Ž)W™ùqåú'Àd“älÆ'ñ3½brwN^U:ë4UASš|õz¬GFè¿ð¯Uuz¯Ýо* ßÔîQûØ—RúûŒb.ps’E!˜6J]ì­Å´ÿd`½’i~BÅkˆŸŸ3ŰF1QÀŽy*†lFó³iB11t¬F»ÝuöÄÁ«ÄÍ6¡“£ò7áËáçÝ7‡?‰˜µú&y¬*þ~Ö_w9GùyÓq¶^BzP÷R©Î¨1D¶ú¦À†ú:ؘ–¥€pŽÚÊ왎ö@öK^šž~œøÒV2ˆM]=7aP4É£“ X×±þ€h54BjÊ`ñBy‰hEø¤ØK)D†‡îB/GѪÅèˆÇnŒ§ƒgôñšÅP.®.;f@¾þ½%’€ céž â´Ý 4Í»kâIê,°“Ä”kiyòOö9cnAÆHÀ£"ÚúœÝ>_2{ÆØöµý9Bpœ½ddе×8ÄüžÀk“™õÈêªÆÝìÿ ¨Àή܅Ÿæð÷ïŽÌÊSÐÜc„9A¬ÂÁ¦We <ûS {…ÛïáÍSRß* BLÜ€‡«ýk×=Z»Y‡mò«C”ÄÙj2RúÐâÁÖ›f}ÐÏ€Æõ·ÕAÐN-m<»Q1-ªÕTÒa¢ìЖk‘^Ø»àŒÑ Ûظ!p,ñÜc«÷R‚Éëóóå?$Q=uýaøƒé¶±RsV¨³ñÇ»P·Ì í+ÛtçéÀ.èÈß`L ¥JþÛ%8£öj/»Õþ‘‘¢UÓ ¿OmDát%}Y> ßy°#èý=”ɪÌûð1HֈϢ³Jþ£ê²ƒ8PWõtZ™i£ÇÛ05¾¶€VH°—©îc+9þø`—kP!à$íwO²Þؤ™´ÜÓê?„n)[´âk!Éñ ·ÀV©]6¥p¢§®ûåEŸØQ¾¯ˆnbi~/…¡wiþÓ„+wÿÖO;„nò¥/BÆ=¬ÂVݽü Åìí„=JürI‹¸Dùçñ„0ÁW/Ñà’I¿B].µŠ&“ÏlT;îþÄÐú,gÑ»¼Õàãf–8œ7õ&L†ö'x­½¶„¡àŸ¶ÔMf™ì?&U¬ö3JÄ^£¤bíñ?¸¸Z¤Ÿi‹-a¤çówVyNÔÑ Àh„Š¢ÞÔ—áÁ½Ç—“4f5ÁSÀg‚ 4;Ý72¿¯g_5PN¥Íq_!—{Â[P=.$™€"˜W°Ú l£ÄPº5Ùö ô¦#g·ÿ–æÆ(–¬Y<±"ÄÿëOä!B íDû8…-ÂkEçF²€¦„¦2<½ße‘˜¦à+x¡ÁŸIšÖÈÚ ‹6™ÊL¸°Ô Àh=ÄO¼iQAdi¯½HFá+l¼ßÍo ôœ¼æô•£ÿìƒWûŽ=œ"ô KÞ–»IðÏ‘~ÐÆ¸È¬÷œ‹Ü¨õúÙ7[šÄ–L‰ L“ Â«qîè€çéÆ£Æ ¿§ <Õ$€G?•|eOg74®.§±,3Ì{l¹®‹ŸÉ3Þ©E2«•Ìá½7à’XÇϼø’Êr¬ßÆ<…T¶*€žH·Ø‹¼ÎÙ(|2­.u\ÅýJ ëãJéS”TUkáìï-3Y§ ™Ü…”М–wY~oõ.›…ªc/wFæ ª”b v>8_Æ^Á Åù;ñ}Ŭža“ôepæfGÿ†L¼OžÝ Ö[™Š®T²¼7˜o"Ô“‡’fštL©'™ô´p,Ýܲúo>ãöó%êK5•›s«“6û²94œFJŠðé Ò[AkÅG7Zùå‰úÑÓÇ"åW›}¬Ö…–: gÊi"yÝÜ©Ì#ò¹* A~A,k V£`ry§#1òɸ[Ø=¸—(P‘j3¥°ÒJ©±ñï%ËãÁè‚GÉë–ñ¿TŠ6§Zý˜‰ -ídV¿œµ8ù‘ïîÆáðv¹ Y™V> ~rñ“)#R×*®ÚFecËí5jRŸŸUf,^­`êÕˆ>¨bO)×¥¡¡têöºâØ3‘ÏOÄø©.•$>ÖF]Ë]e´Y6©j#{óiTF¸Ëåu:¶žòj°°ÿèôøÈZ¬v&:±3¥RMÕ<Ô»çx‡1­ýc¬Fn¶ šìȹã†ÔS·Ê°N}TyÐÖ¶#ÝŽ®ñ‚á.®fýKŸÐè 9úhO´,çÍÛ5K¶-aéŒÄý6 …û¦Ë|·8Q¾PRjÙdšã²®çÓp¤¹«Ÿ-÷ÍNê°Ëœ´\–hõ£Gñ{mèàŽŽ“ŸKá©NŠêE'ŽN·ãU« èBÜ¥9©Yöc¥ÙtÉâ/OJx8æoe) ²M¡o·B›¼ó®jšÏÇ 0Õ«ÅššôäŒéL¾ê¨iï0I0f½§l3üÍÐPç ‚†Ó?ͬ²µ´˜ÂI<ö'vkªDKõ…ŽšY kß 3iÓ:WeÑ«Ã_܈Ö;úÞ8¿fts¥]Œ*dDÐÆ‘·2ñ.ˆÏô;£5ÑLFhr¸bp#²ÀІÔí*7gÀÏR—(êÌ8b¡ƒB1½»*àͧRq^ Úô)ª«ù~ûX½³85ü—YD§xÛ^gbfŽŸ% à*†>Q”ÌÍ+‰2¬¢ 0ü!LžµûðD€º=5 V/:q†ÆÇõ]Ìå±ëŽ /A*Ø)r¡w1¼ÂÁÞz Ï£ñlN#Òƒ T~ƒSL¾Vò›ãqO3qW=1ÐI¯ž% ‹ð¤ƒÜëów…i¹Õ¨ ¬Ñ*;ƦãAÄ(VÃ|s–®MÃ^P#w+Yôc`áä©€Z”Ñ£!:Éެ¾x$ïÎk׋%Ã}T™ð|ÅPQ ´ÓÏrç€þµŠÝ×»­ÉÛØŠÍ&Z/»ÀÔ÷f£(Lg"´¦Lá¨ðo_Ž^ ª_DË)k{ 2õŸcìe>K1!LÒ_Ì~w8Ä`².Ù÷9²žëÕõòé±Rû™yÆMpo¡xœãtæsÀ«Ü‡MhÈÙ(ü—Üý*IÏï,Y#j±ü¨«@ÇO¿=ó[ß;e' d8A‘­`T 2Ja+Vê£-¢þC>>_ƒŒ-û“­Y’%wrL2<åuýà~fŽàÝrú¶1Ú(ßðVêõ?ã,Õ’QHr#•üx$2Y_½+¡æ^©™\]·¯˜$:ñ#f&Ö)´†¥ÔôÃ<à"Htd”À{¯¾:µ°”Ž\ø \ò;r‰ŒkV®Ec{ë¶çÚþþ§]â|‹BEž’oeåG-´ÚO ´ùå×ñ&ò˱£;é¦ëûŸ‘«fÓãÒ›û“óÇŸÏϺqs}F´€Ak[ À…%÷ñ%^zj6רÖùÇèš3hár9]‚÷!äwƒÕ 3ˆ,‹l•Ý„WÁ¶‚í÷À?Œ@U†ŽV¥:ܪ#„¤+¤êé«*´ äå'ÍÍyá9e™Â6(¤­ûÖ®‰uÊûB+L¡éJ'lí-u ¤E*_Dxûª™øÂõo7q‰WÔrLÑÊì£$ÇB×°ÀÕ¸ -IÈVbÙ,tø‡[öŽ›Ö*Ço¾Å¢š r¹«éÞJzåëy¯¶Z^wJÔ4e’"ÕŒG/òæ¥m?›µJ§? Ì'¹ø÷­ê¡ëR°§ä"¿Ï?Sxô틞*T7 V¡=ÎRûäf¸U\t/Dî@¼/’ÅGÞV´éWƒ¿¹Egl›šTµ¤© o1'°¸Ì¸ ¬™~p˜:$ÿž¯ Z[È>©ë¼RÚ"³"›®yˆÌP*>Q:;6cSöÆJŽ.\¶ñ-ÓS?l_|Ðrõ½Ï^M}ð°ä%³ý±vˆñB!«ZÄhg¦øøFÓ…ø<×;÷©hþØ $^tÿU | º·Újj†¥ÉØë_8FÛžÜf!wQã#ÃÀ$v% )ôˆfï€62‰®k¨?Ñ"„¿qû˜çsGE]£ž®.ðÆOûø]j›¾êFc$]¥9ÐC‘Ò‹#0’tcéòw¸Â˜É?Æ{‰» øKßÞÚåõœºO¦¹&Ù×Ðd휋¸‚Ù²`+½½5ÏX0ÓœHûGîPAØ7¶?5oû-HçýÅ*Œ•²U]ýèp[§Ë%‰Ñ ÏŸÆÓOȧQ ÷3‹&{g ö„rò0x"ÓÆ;CàÕ¨}ÔØàjøkfø½âr•új;Áƒ,³ãŒŒ²~Ê>åXƒàøûD\݉¬Éèó̳=O ÉH™Vÿ†›°§üaùª¨¾¯zÏ:UÏ!|¿K÷=köÚZ]öç/Y½µë¦³ÏSJW]™å  €•ð S¨;AR³E÷H¶(á‘5b LNW¯1UÁ²ô ì]?Ÿ!½9­  ü#ùmî¾ZW#A…æ|±Ýa¸§Ñ¸‚Ãòú…7ϯl«êf^´Ý.…úøû2=DRS$ ê˜:-áÏfý“oT‘|–ŠÕ^Ñž=‰ÐOë–|¡@¢8  y€(ƒÃ¸w“váS4]ËÚ_å;Ó l`¡…ÿnÒlS, &®™T»*ÂÝ#ZÑÖ°$Œõ‹ª´ÅMAyZÍO+ZvªhóE÷3æqñÒ>âÊ“î9è%Mo¯,,Èô†Æ¼Ï1­Þ­l·1â Øžµ$Réç ãJÿ“¾ï.§}œk“‚©ÀTä RŠëòþºu'ÍíJõQj!ËNäÐg’Ÿ·†¢§Ì œ5…°3J8`\`0»úòÑÄœ$Uýî÷“Ûpz¬Œ¡E%Näw˜`4XøE¡4ÍpE„:LÝG9q Ü…¯§×—JÕ¢ 2¨DNÖÕ£ 7J Ö[ïyÕ¿jÃ…€òµe¾ùr¤+ûà Âö#5f ÇZ˜ªÅÜ5RØ, ,ô†ˆzö3-•×^ðV7)ÈýYwc:”÷z¸ÒœUßD¿1W›C|ÿÕ“<Ø5aÂóõE¤ŠÞ~qW?iø¨€åŒ/ÿý®êmFuÓ:£®n½AlÁ¬Æ]•ýÈÌ…ÅéSXŒ9®y=šüʽþ&Oæià/"kÒR_&Má(%ÃzÕD#¨ƒD]F㯸?70ÔŸÄ„‰TI“ÙCƼã¢ËÑy"(Çh3HL’ãìêl¨"rb™ÑwѼõ=ŒõOÛW<³5`N&mvòq¦;JŸŽžBšPG!"1²¯õs´çÈæü JâNzßN~+2²Q»stU],lr[:qPˆ®{eËõø&;S ú±‹-¯ ?XÕ«[;*ª´mYÛå¿©fzùèF~…h&®úƒø+üº¿ÿß›§ÉÛ‘ /X6ûHè8Áœx("CXb` 5¶eýìF°Í> endobj 31 0 obj <> stream xœ]ÖÍnÛ8ཟBËvQXïO HY²˜é iÀ±™Ô@#гÈÛW‡GÎt‘øˆ’®>R4éuw¿¿Ï·õ?ÓåøoÕÓy¼¿ÞòËýøtÙnWë/ó¹×Ûô^}ˆ§Ëcþ¸ZžNy:ÏÕ‡oÝÃ|üðv½þÈ/y¼Uõj·«Nùi®ó×áú÷á%¯Ë]ŸîOóéóíýÓ|Ëï ¾¾_sՖ㆔ãå”_¯‡cžãs^mëzWm‡a·ÊãésM]óžÇ§ã÷ôڶ¸¶®c½›sSòü1ç–¹EÌY˜Y™Ù˜ ÙçÜÖÍùŽíwÈæÒ™#rbNÈs‡¼§mܳ½G˜çnýþ@€?Ðàôøýþ@€?ÐàÎìÈôøýþ@€?Ðàôøýþ@€?Ðàú~¡_àú~¡_àú~¡_àú~¡_àú~¡_àú~¡_àú~¡_àú~¡_àWú~¥_áWú~¥_áWú~¥_áWú~¥_áWú~¥_áWú~¥_áWú~¥_áWú~¥_á·šsõ~ƒßè7ø~ƒßè7ø~ƒßè7ø~ƒßè·RŸ~ƒßè7ø~ƒßè7ø~ƒßè7ø~ƒß9þŽñwú~§ßáwú~§ßáwú~§ßáwú~§ßáwú~§ßáwú~§ßáwú~§ßátF8#ÎHg„3ÂÙ¶ l‘Îù+Ú²rÉæÿ Y,h6¥;ÑÈDt8. Pi|ñ€Fv ¢±+íåK÷ÌèdD†TôÀŒg¥†u€NmÉ-^F ̸>-AÍÄNèÄ…²,²éŽuð¬´aÆ`¥Å‰ALt&8eÁM‹³<—“#artË„F{ÇN‡® tÛáÞ®Lˆvqè”ípvÆv¼øÎ™Kû2ž¥=²æn±•ö=Ûaîzf˜»õ1þûå‹OOgñôË$@;<«) bÏwW<}ynS—~y.®X§G¡ô¥)›Á°ÔÁõë ¨3,uðîÖÙÿdØ@±ÃÿÚ˜«ãÛ4Í›rùPvcìÃç1ÿûKáz¹â®ò÷pר endstream endobj 32 0 obj <
> endobj 33 0 obj <> stream xœœ·std_·³Ó±U±mvlۮضm'Û¶mtÔ±tl'¯ß}ß»÷¯7jŒ:gϹÖÜkÏ3ëŒQdD Êt‚&vF@1;[g:&zFn€œ…‘‹“²¡­ ÐÌEÒÙÐð—`‡##S±p¶þŸpdj@G' ;[îÿ®v:ÿD ÿ¶¨˜»]Ìf+7 7#€™‘‘ã¿ í¹¦ŽvFpdÂvöŽfæÎÜ€Ý(U•Ô©hhhÿaâââyü7:Y˜ÙÈÿMà/ê ´¶³·Ú:ó„ÿÂÖÖÆ3k{s'€¡‰ Ðä 5Ck @ÌÂÚÂÞÞÎ@)Lõï*e¢ûûÅGÚÿé?ÿ1MÌÎÑ øgaä`fPš;;Ûs30˜þ¥Lÿ¡èLémÎ 5ÉDmM„ílþ™Æ îŸf G ñßÃ{0ü_®[ÙÚ¹ÙzýŸ”©…­É?[L\ìTm-\€’"ÿÕð‚ûÌ è `cdfäbä@wcs†¶Vñ°þÉôlhkâãeog05´vúX˜ÿ^༜ ]gG ×ÿ›ø÷ÀÄÂØ`4³°…ûõ¿0Ðô?ײ†ÎŽîmFú¿^ÿùüëN÷oLìl­=þ§\ÎÐø?þ¯!!;w€'€Ž™“ÀÄÄÂàâàøü»Ü¿ŒøoþU0´ø¯!ÿGRÒÖÔÀõŸgùkâÀàúŸÑPþm*À¿éÿÒÎÙÂø75ÿʦ#ãßXþ½0ýŸ™ý7þ_ÉýÿÖ´„ÿQúŸ”þ¯ Å\¬­ÿÃQÊÿtð×R'€ àS­ ÿkaü¿Û m,¬=þÆÿU©üÏ_é þ/þ?7´5³蘘ÿ µp³pš(X8›ÿgîþ‹Pµ5:Z[Øìœ,þy‡ümbcúÿ’*æÆV¶@'§¿Oö?8 ­É¿oÌ jklgbakPvþpCG“ÿÐÆ.ŽŽ½þÇý·÷¿×¦§ÝÆpv¬!ü…h;`aƒUŒé`ÂêqÑ'•V-\ý¸n)Žð$•öÓ ˆÊvÑ×Ò­åœk‚âg¥45¯$‰ÝʧCØ+æ½é~”|f¼»×¨’ûë“E.#„ªYFXâ¸.ßÈ¥Þ§¸ilé'P.ٽ׬”íœý'QÂ*TÀæì${íѿˤ“Ú3¥Ê”ý89´µô"/ÿ‘²¹ÚöŒ¬4yÉ‹“Ÿ/`¢sý°Íg‘>@šMs¥ˆˆ–[¯Ž.]GÔ÷3#€Å[ŠÞBKhO.Ï'9H¾×ŸÐ—¼L—áì×û~…_V4ã@Ãn²“§-¶Ãá¥9ÁWñ;Nóseh0XûЉËÏ™ä^h­ ˆp¬Ÿˆž¸Û/å ÖgþßhA…„'hù =u° Q»Â†~äzèe¹ÅÌ …ïX¿®ÉÀ (P%›Ÿ>ðæøúíâûqÝân jEUº’É”lθÈzO•GRܦ^§Þúz’¸M‘Ä6pNÖ;aäºrXàÜg*ÇÁKèÙuÊZ…DQ‹¸Ó~èØwâ?Œä­¯X4é„™²6‹ojSFºâ_o"•‚zòUíô þüiÙl‡ÎD––È•°‡Ñ¶‹§9± Áû­j­}"azL–ºc8ïí8˜©uáQì+hWçðõf2Äk²BÿµÆÁyÜõ†¼FÀGÒöTÄ»ì*üBd*¿‘?™þ—#E±½cØ™=Ʀëïmõ¾öI´¢röÄôyÅ_ßË·Qo†Í) |¦oÍBªòÉ­{’»´†DIÿJ%#£ûYoÛR¡æ^p)!µ»Î¯$õY´ÊgÚA}»uR›ãÞ[¬@¥BH¥‡\…ÎDø…夼⽌ó§O¸¼n‡eÐz•ž†B4‘ÓG×ð–€-ùä¬m¿:¹K¯ÃZ0>Ðx²nšËº*QC¼ QoÛ$wôKNjÝšé³«Õ R™V=?¬\ÅÚ‘~ l‹æúsüQÞd$XiÞÎgø*ï²ÉÎ;X¹¾”Á­äl…®_äò,{¦eWžSpºy,¼ Öþ£s¼§KÒâÝÿ[;¾ºˆ¼}.0Õ[ñþ|3ÿ{€–A'ׯ÷ø2%ü]^RF9C79GmÑk¨›h®*ȪñÖøâ¶3®`>†-1ã¾S“íÈRéJê´&±$¿Mr¤Z ö1.;­¢I]:rÔ…þBä B@öøº\#`2` ¥¤/Ò–‡ƒÏçMƒ¯Ü÷ W€ì96³{¿¡§Àµã­A±¦ôŒd´vüª~°¨ ¥)ÙÆgYåP¯ ˜1dû²®Q›Ì|ü¹öG«îÝ•|”Ü|*Áp…ŒûL›[Þç kçæ«JP‹²O*˜aƒ›7B× üÔü$õ‡|!C ˜©7úW[cØñHÌp>)Õ`·$s€=áÉ1i³ÁŽÙÁ&á¤#1ùšýŽ€9*´ô\á ºÉ’°§üеî4ÍS{—†ÌÅ"·)ûX+_XÖM¦FËcLÇ·FÊΖÿJ«øÍy‚Ô…<þF<ŠàÿB m´=¯IÐhåûé 2Ì‹¸Ê}²fWÄt2OCˆÕ…‰åYÕØ‹Â Úä™.óN9ëîxwL][¸€v‹ùÙ6 €ÆEÐKæËùJ‚tµ”`@”Î5FjvÓW‡¶×¢­ÃÂÖ´½°òéùÞãfZ¼WIBóÈ·ºµåÉÿ[y|¨{önçOÿk|ÌîÅös¦Q’?%Nù/éRÔß¡G<õ]W Î&l{1Ž©LÍoþWĵê1è²é|hUí„S{ňȠŠ^t…FFbíÞ€c ÅV,Ÿ&P1‚à£d`ê"mµ†¹³Œ³‰žØãX,îiòx4O[MË·ˆ´Ø*„ï ú³ÚyBH…°9¢Ú=êNÐ Ðír$Ÿ¹ Žš¡7ì 鯘×ĆŒ7È4E%8õUmФˆ{¿(r¿Ýné‹\fçƒbÌK‰â˜]Þ£à×ûµÃ©äJu 5WUÓÞÊ.µ©3€SKúz´ì7Ñft–¦CeßÎU!tY±Sß i³«YÆ|ŒãÖ]·âCCTÛYÁ\[5u^­ÞÖKd² Ç‚ ï,Þà†k¹Î~Wv´zT zñ„óFý–F?ŠÌú ”7çÞ<³,jÓFÙ2oÌÚP2+¸Os¼Ë<úC«ÞŒ´éÉiN‘F’OìþÏ¡7p›RT4Çux"O˜éJCÑhkµèè!øñ¸ ®×”á‚c·ðTÙ§CJÑçVé!wø»)fšÚˆi,ªKÅã>ùIàïuißhX¡j›á³Ô¬÷ƒ|ñêD(07®ÁçåArê-XmàÙ% vpO‡±¾5-ñO› Ò¯´ ç[7Žß·2ÎÖ”Ó­cçJ)ßgå Ò¬é¨ÃŨ!=w+è‡eGÆåú1ÍøÊj”‡Áðpúl©`áìþBÓç9Û1Ôa`ãVA¼4¸¯©Œ?t€Q•ö®Æzû“»F²‡+K_Âlïæ¼r– qÂ=|‡gsKYGˆI FÛn?Õ:‹W 㔊¿%+³§2ΚŮ;¨•ÞWÃÃg!õ¢ããÔUñî›Oê=Aç÷bÆ!P÷Õ5ŠtH'•›é•+º$×BU,ñðKm09÷Eœ¶m}'ðZ/qJ94ê­³}%«²–¢[î3_T¾ùöT;ÆÖRï‚ï;á@'!‰3‡›ó«Ö‹ÓjÈhtN#Ýs\A)*ب~A ž‚$+•óήý! †ÅŸ?¸¬¯o¶Y; ÆhÌC¼Ú®Âï¡z΂_b¶4øÐ’ùS ƒn n‰àL‰I>¼h®™h]L[ÚudGÏö)HF›îÚQÙySšbl¸vª&ñ†ËDÜf~ÛDý‰›ÀwÑI }¹xBˆxƒŒUÅ{ºÎ— m2i,LKŠQ,Æhje¡¢Ÿ`êB9Þ˜ žÕâ²L™lá9h=Øú&¤Ë÷Òæqä¥WÊÕõô·RŒªRbÜͲƒxXÚ÷–ƶW½ÙH’â.=zO¹9¿åªFêadmW<-ÒE´G·"ðiÛã«ùÍ»¯e Þ{bu¦zP¸Ò_ Â,ˆ«“¦sa˜Üqr6í¡ÙžëÍ+«©ðT–\8[£Yb5/û9ô»gÊ»8þì_¢á’‹Ô@3šcÉbƺâ͘“¥u[Øpm´îãžVðÅvA¾¡Ù€ OÍ×BÖHŸD lÂý1i{1'¥ÀÍ-zbQýíún@”¼‘¬‘TÑãÈüæþ q.I˜ã£Š ¡¿þÄ}tÿ¾ä(Ã,7÷˧«[áO¿fYõDí{]¸·s|pà¤v^.¢¶qLähK*ªr<#:¡ç w@²_%ÑWÑœwAMcÁÕü‘¢ þü]„£Ç‹S3Íï³;÷½‘§ê8%ãKcGÿy÷eúhÒ„ÐR];,wÚ> xNÓH:WbLà§§0 ½ÏÄņ‚L+ödZÿqî)\¼*èåSnû·8.däzS&iå`æ‚Á7÷˜è–É×|>Ÿú{þëj ç?5ð Íœð½•ãNhóá5#mÉ‚TAâ*,zI¬5#¥ÊÑÙêa§<®z@ZÌ´"‹u`MQdž@«^¯Ck©ëÍ8Ð!²4kE «Û8é&Î; RÓ®ö3ËPAïpk1’ú5Ù?[ïÚÄG|öTP“`ªd/¯f$ЪÎvÙ[®Øan+ÉDóc9";vÅXâ|°5‚CW>%FTv[Nü®bÒ¯A$˜¨ž~·¾À—h(ýwòiʨuC¤¿*FÅ]£¢lKòjN'ûªœRn ÈÈžsØ2ÐgLi#¾©'ž>´ G¾,Þt.ÈâÖ³ÓÜ*oY£ £©ì¸Óaë0ÉÉSwz ÇÎ ^8ɱóyàåº0ÍÛɳDƒø×ïÕ6š·Pngô#Žº£Ã­åD6ýò¨šë†'%ìØ°ëd×ó•ù––ãËóWŶ“)p„Št'#£¾§lÕâ'Ûs™ÌixØÊvþÁ¼c7Æ*sAü9»b²^õ¸æ@—æïÌï*AG-`RêÍ5€ ¹(–M¯¦ç 2ä’§Í=8K>é¬à‡Tbt «~ >›~nʸjàÚ¨ÜÁ§)[.—W3A‚}«’'œ4™„âBHÐMÏmÂ@XÒ{L ýÑå ”¬+!Ò¡‡â3yõëy‹Ãƒ)3 °"€Hº °î¬CÞV$uó±ÍÇÂx¦çÏ<εÙ.\ÕÇ‹‘gl.¦KÑõEÁ$‰šò…ÑM'¹9”¬s¨5–üiN'ž˜ÁÚõr´ÌF¡’EpëºïdO>|z&sºGÉÛÄ¥Õ¼½÷ŸsKç³ÅüyÅ”Ò'æ˜ysy0™½O¦Œ¥LSÇ­íë乫ñ_?P®…=;¶ÔkÑÐ9©—2¦î^"›6é]KÒEœ„F õÔ=®Ðý¹]?šëOµP”ãüšFOÕI Ã[ ZLDÀH¾X²Ä#íåîBôtPDbèÂäŽGÚ‚Y7ÅÀ5·7Ý\b|+×Wãnì‡×ìwW¿y5†Ö„7r/$ì¡YáÈ€}ÕlŸõ¼«o9³Ü:JÉPçqŒ«Éÿ¹õ’vÐp} <>¨!O„À“ÿ~tˆ+«YÆ MޏøeïЀbUù(o§qâomNDyÛ*ôüÃÞ8†G=ŠÊ™m 4!LNèþdT@‘ Ž¡6£Q´¹gKþP狦Âôù×›ÝÉ{þÆh^ó £Ü¶¼ðV¼$IÐ^÷A6åsz÷ËÒ„a†ŠDz<y¶P±Ÿ¯D ùž1¥H-ÍQøÄ¡š=]Z²¹0wÈƒß FŠÄ I¾A—/l93û[ »ßù¬ÚxX¼* ¯Ù¸[[_³äÎwØ:í^µ©Æ@¸·`J¸ç4N¤Ñ%(‰ýT]b 1Pí«¨Ñ,›/PžÐìû[Û©óúLˆ|{Ô¿1`PøW¾ö\á>’¨,¦÷îiïâ³mZ'B×n håƒvX¯—HÀxêÖ™¼Ä{„ØÄ(Nî¾Ë²%u[,‰«H•YË@ÄÓ²h¿têªüÒŠ´uø.ý $ºª~ —¨ƒ;ÁíåÛŽµŽ÷‹îß1gÎ}ŒbxŒ¨¤î›K0—¸|æé+K‘¾F!ó®–ÍF½üðš- }”ã1È\…›c±üó Ž`AË_éö³IæöÇ;¿Æx_AÓÒ·;^C󃸜ð¦}40´Ð!£§¦îH4tKrQº1•ÜùØ6NÇç4]¼Åclø,œÃÉMªM «n3Ò•Ëä¤?eVóŽ‹p‘’Ù&J@­÷ü2ð›Qb¡Ñäè ÌË¥¥AB:¹üÊ÷Qäœ2ܰ½ÂàAB–Ú…öñLðt60øṈ̃,ýÄh_¡žJ”Ò[BÄÅ|1—yED pšÉƒgáü {×EÚùÓsjÜî£SÁÊ#ð"Ú„/yÿw´o¯R]Ÿ÷¿¡L’‰XKÖVúÚ¦Þ¶j~'”ˆ±Ð¸,‚«1}øßW¼£Û°ßÿŒï¡¨Ðš}ì™êêêë“t½EãA—žäŒ–úwR 8}%e{,/•߇“E ?Öý/Æ“{ú ã¹^°gŒãž,S‡ÛçJl€äExõbÛµÝ1x‡ÇYñH~…ªßÞn1•ßåÖžî)YlÄa’Ú芻J½Û‚F¿ûÖö¨Ç>Ú€t‚¤uŒTKÍ/ûùøñÑî¤ü.¯$ò×û‰B‡Š¬¶P»øE"@«oÈìûªUt&0ëSÁÑ›aeü$+ÑNVŠÌ}D™Ÿçkë5M°ûÓÈ-Ñ$ÕÊÓJ‰°lù£­ð 䕽¼éÛ&t Õ^¦§eæ té½ýðÆ&LÛÁˆ‡½6™@×–ÕpÙ¥‘M샦®÷µ×,´BŠÉªo Ë»ÎÖ\ù¢³CTfƒ­Žî÷šÌf™»© 9 0eªyœr¹úÀ¬qV /åNS0šIe/;”%DÙyÎ쟡Ñcû®ÏNð®ç¥}˜Ñå&]C9ÒE0¶FÚÄ“C‹9‰D“ ª÷³ëtl-Ó¬'æ¡êWÄäÍ‚c2ÒæÝàÓüb¯±‹Ò–åÍNÎ Åøâ›c;?M\’)—b¦þ„ˆ…ñ¶I<Õ[ÿü£¬£Ÿ¶7EÑC,Ä {(=Ä×rlg¹2NªÌǃɚClW®RÍë‚ÿérË©…C²€Ìý™[ùÄ‘ >¬Ò%5ÒªªÅæLYei[àÍzí{ýaÉŸî÷¨ÝD¶(ܺ±zxdDfH§‰ï*($_c䌉)ºÈ¿*K²Q…Û—kå÷;ÝfX/_dq•—L<ÂÌÞb.—Æ­f²‹³"ÄùÚ =ræ›û°ái7¼Þ$lMƲ rý=áÄÅÆàõ=*œ@•Çfµ1*¬ÄÆÓÏq‡Ÿ¦ó.N~ri»m#5¬´ügЦ“^r)÷ó¶yb1:ÄxDÑ6¼-ò˜quÓ*bÔ¸I´JÁµOɳ‘+ÊC!bC]÷•&=ÚÞ#ž²9F¬(ø4]¾‹L¬ˆô(¾çSä¬cœÔ\el[Ç–ŽÙìž~j¥€Ém®ôß/£;¥ ’Íç,ÇoÁq`;M^ÖHZ R|,Dè׉1œÝ2nÙYÌÞ×dÃݯD'Ü!FŒÆì˜ßµ"T`Ld­ÌÍ2„•yõE)ª¸ùlj‘ŠÌ!áB5…M^À¨ÃãÃDvE6¯‘\ îÔm»ŒMf4:çwÆñLÑϘtFšÙ¿Ô"}ÒËüñ®º Ó«æ{[1S IwÆQ©)KïŽ Ð[,¿9.7v¹Äœ³‚—êOÉŽŽ=×ÐjΖ²´joBhh›SôÜžÈYzŸG§ø¶2‰¯9Aæëo^§eÆøÆ[L ¹¨‡Q§ù@¬’®/k‡¶ã8ºñ ŠÌ”ȧ•2QtŸqJÂöÞtÆÕfdÞ”×;p™ êHì§ÿ§*Ác›X8¨;H–4'v? s4¥ÈÖ­wm%¦^RèÏãÈfpSPn z°ï|Â7_xéu!Ì6­Û±ùRXF¼ƒfx6 ê®"k`—G¬@¬QhÔº‰Cy‰äÇ^I½ åÖv"ئGêºLB^HàåQGG 0ãa4,9ïô–ÉV-P.‰{½Âé²ï7SöǼKù¹ª[tÇð2N@Ÿð¼êÔåĤ•ÆÁ`Vw,÷rÓ:#„R}”àQ’µ.Æ5þ¸æ›5ˆ¿‰ªG¼îèI|—t@Z§ãWo¡€¼a!¸ŸA’k`9ÞtRɉú<ó…•È0ÁÐÉ+JÈiRŸf·gþíž&9œí×tbRñ¦k¹”„•–IC÷0Ȥý–sû`—¨R‚*ò³K¤XÝL­ÜמFŸº¢,±Åô3ÝRݺ9å½iµ®ËòJ/.w›ÔÔÑ9Jº ã¾ —õs2ûº”ô³OL Á14x!JÅèãKÞ¨[ÙS½‹Ü­³,¨$?Ë-3¢ÍåÝ»åx¾z¹@„ÆÛ3UõŘsÓkûñH".—*¾wj±Öû§­¹žÚ-zƒ*ªk}ÝÈN\ïÁÞŒswjÁËÞÆ£ñdè’@ÿÚ.3À™éA•@àä\¸ãLç¡“ƒ²æjyº Ϻø»@ F B¢| ¤ìñ”±c½~ ä}ý[æ'ÃL²ÿbÂÄÔ U?†î-¾'_Dýd¹ŸðÂàE¸(R’HëÙ œÅ˜i_¾¤ÞX1ºÿ¯k/¶qB Ç7ãйüù´¬å€3[ÃkâÁø0ÊQ¢£ÈgutÍÝ@ÂÖza—¶¬¥ÌØ?¬"¡“F ÜvÒï<\€.’O‹ø®2AØâ¾CÍ>r7†Ÿ]“åUXQ'²‰´i ÈÓ»î]Îè3•tÄãÆ‘ëóÁøASg½,.Ù|öÔ!LxÎnÿÐæAtp®&ë(Ý"lOiÏÀq;’`-8‹=]’»fì(’ÊŒýGw2zg޶vüa¼´ÂUôb²ä¨4evGOð@¾"}¤·pG{=›B1Ž8 ÜÜeÚ †#–­D1ç0ŠÞ{æ\XÏCúó‘ º¸•Õ=‡óËŠ"/TøåijÞåÆb¼º†giBGm`)™[×  Á$JàšþV;°¹Hû€šþÕ6?rôâJþdŒû®¾Ý ÍóÆAŽç®‰¾oÿéÒ:¾æPìýñAŠG¢D>ñ`ÆËXTGp1t)Ç9É{öÄxÇH[AñëÈkN\µ‚É7€ß ýÛ•àͼOóAM®q(—yÖ}ÎÞ@ïDµ¶›_"¦ „÷ð3íë‹„¼i9{– åâÔÔÕ[&k»¼#üK8ÁJ8 •5oj\*ÉÆ¥¸=½™amæÀ=^o6«lE‘›´yYá±°;þ¬ºšÙ×.Ç$õ¼·Jö@ÛIì@€æ)Xzˆ]¢í·¹{6å¥ E›Ò‰š¡ ùü©‡³HÜÔ"èmÅE<ïaÃ|eYÌËaôXZk Ý0aîiàï‚‹a"2þ!šïà—ây-¢L(uizŽhuU{÷ xr¯YVS¿Ú…ÛéÑÓb‰Fƒbª/l_mÆÍs-5lŒ4Á¦ u¸»gÏ]Ýh ¢vŒÙŠÁÀ<üÎ(Ñ êç¬Qëãb ¾»P甿Xt+‰¢€óݦ‘]Xÿï† Ëªa5ë¼fÿA $]O¶Zbzð¿&¿6Ñ^ É?£Û§ øL÷@è@m*Aû±~,¼k6qq<Ñ'Ììµsgüœœ¥çz°{%y¯ê 9E?â?”©õÊûꙵ7ÍeïjÀq~.Fû,_ÓÍÝmžº’‡¥ëÒK!åÖÜBïµ€…w Ø/X³8üýý‚ÎMF¸Ök¨À!]á„5ç<¥òúœ ú{⇌µBîø8l%EĔԌn¿Y˜‘¶@hz€{žm3]Ç$ ¶Ã:½˜ðeBúϲX$ð(=5}U”â£Q?$wäÂï"iéºìæôÁ¯CÌg#u®÷ÓL“9ìû3*ÐøAåûݪ1{$6ŸA>Ñ"Qälú" íYË«­Õ7ˆ7Ù >9f¡Õ¢¨UÁ¶Ük¿_e˜Ï—ñ{ÞÕ ¦›°±l’l‰°äO}£4Zç’pP6Hç(c÷.3æ¯ß^žñåþP,›'©Çç¶¢&ýð õŒ?šÙI¼±δî~lèí‰á,¡ÊQG¡"d\ÌYÓ´€"ÃìˆHøu7¢Ãí”èö³þ—Ö2­oãu¡ øê´W"ʉ1Ô-Šœ%ê+|䙳Ü*'CƒRÏZ9ОíMur¤a_)>Œs£¡$¿•|.Ø=äã0+É‹wì쓈-4vët«nŽè#¬¼€!PdÚL÷ûg˜1Ö2}ß)çãzâv )hײ§c¨Plj «YÉž§×T·ûècÆ»mneøZ'Óm.”¡µóØFþMàKò kíž“o¡O'Uõq9€ìR%CwreÔ½ 7< ém æ~³c£ibMDAoK’žHÄÂ1Ò¶ÎÝžôkTR‰G-è9·bƒ Ù\DmÈsc·óêí=ÌDKt˜Œ ¾Öik—kýöE5…µoOÚÃè[=\ ýS® ºh^õyà SsLè­7‚&6÷¯K¡;$B‘,âÝ_ܪCBG«ñŠÒ«ãƒ{E-ˆ—‘4KC9ztôàé;ÃÖ‹:Ë€˜éYgrWþÔÛ½´M›>:˜Æeò4s#ÔHè8uŠ]õöŠ@2?À0‚‚ ™˜ Õ6U±´·‡³‚Z~s‰¥´“|¨æk \ûI6±ÇþCd˜Nê%vX4ÎvHèýå‰þ5“ûw{z[8Š'±ý˜ƒûõï£I¹ßÍÉ9Ca‰µ?רX½A…”C‘DåÎ(”(¯.@Bl*\äO³/„‡¯$=×»¨–0V'@gµ?¾Ø†¿«Ð¥ìCÓv87,–ïëÙ®ÜÖ7 j¹ˆ«›Gjm÷mê¯<ùBùMÕÒÓqõ<-v»S;ÄÈ]ÈýF’Õ‡qsš¹Ñ&´dX²{&_Öê (êÒ"üÁb3ì‚uB„80B ¦f‡ÆÅ”T®.¨ÏñédÓ] Goç*ˆÎ„ @qÂæÁ•Í5ÿ%^œdoN¬ŠÆ³á®Ñj€D.‘ŽWJ·çÖ®Q+è„ë‘_Fû~z(%QM…½‘ÉfH­<&ù•ßÑèäÌãÇÎ,¤Ÿú‡|Ñ+¹œòèë-õâ|õ5à\ê5Ù_Gë™&ùÍü °úO·"MÞ.b0 riÄ d×I7žÏ¼ÔXºÏU›†E賆U%DáÇî|Všº]):z­ÑÚ¾Y›oV€V—’ê¥@ciN…½û¾ó,#eÚz¿¤¥¹ŒìJœFpÖ*ÞMýíÊ"36I=RãyR#ä¶xÔºãK{¨ôqý°(D‰ nÅ!W¨9½Y²ôc½‹XǯÈù;·G‰†é ׳“á²Æ …JؤÖÉ^eÎË„ßPhé:6-­Ù\Så~1Yíž½¤ÔPõp)íBÙB~è0θz¦çÙ胘‘ëåFBi†à!YðÔãôt{êËæ©)ÈÞö‘6l ü^€÷¨üK´®Ü‰Äˆ³ì¸•%ƒzúý¤€Áˆß”òT¯Lƒ|CÎvœ{{Êá‚ãô•§52Iböé~¨ &¯aüD=åÞ†ÈìĶxn‡",žêsPðãçliÛªd™–iL+‘‡°Ì›m¯V–ö‡Idöì°i Pu–vþçK›Û'‡*Ÿ[ƒ¤I±„ ?ÀU$sí&z;^ìï=i½è³Î¯³nhÓQHt·t«(˜ªÁÁxó»‹Tí/øóǶB\7/¸qÃ&ÉCø[oa r#»>ˆ7=ž®! èRÑoR:§×¦íR¡Gâ'Ÿ¾Ÿö¬ÎK,¯‚ "‰3uò‘ì˜ØÃË™)†hkÊ‹œS¬¯–¾6õ 8•/Ç §¾kAºt% -ǻԲë¥|R« þlºLÆÄÖ„¨3Ï?KD 4¡Ù‚¶Ó{Ü1 Kq2 EGŒ@"¡î,TN‰C¡ÜOa6´Ž‚ðéO—%»èÔ‘äu­6œ}hm'*ð'ÒÄu>º0#?î ·òžÌÿq‰ÐEŸcaÏ ˆ §óæ…CùæaÙ U÷@SdÔ{ÚÚ4OsØë0r5+È¥îf”ú¥r3¾} +Œ¦S¼ÍÛooM«¢‰²à%â±åè# Šé e¯,`Sò;ž-®ÇÀ§§æli®åiß©%Œ§˜æo± FXI<ÓÁÑLàl÷Z‡/GÝ|ëØ°ƒ·ÙQã&aGªšs±–n'!LŠ>f »Fž¢~‡b €ß˜9l ÏÚ÷‡<®ø÷¿/b”»{øS@áôæèuiõ㞘}¨hAáæB-×!+/-–ýèPþ¾­Ëg3¾ûL¥+oBùX·À‡QÔãÝ»îf~mô4¦@”‚¤‹§¦øU³N÷ä9C¯÷Q~ŒXx¸™É‘öI'Dd{RÓŠPÉE]ôœ»y(ŒË {T.4OIÈ$Õ¥ ®èÂÇò_I–mw˜Ä §n;cõý)ŸÛ턆r:ÈÒ3;M–¤H⩸?VƒE¹<UÉJ¦£õáÎçm«¬ûÏôj.€ ¦SÊé:ºß£0wyÀ>e𵸠8§ÙAÒ/a{kDÏÖƒGƒ¬´»á³çÀDþMó»Œä ¬UÄÐz4ÈÄ×2Úø6SqÓm—ö-*¨„ˆñŠÃ»YRÕÒÊLS²—ëúÍÕ‰áÒbTðXk:Ïà…k¥\PDòæ`!‡³:H¾WÅ뢯¤‘o«„CŽ5wÞŠu‚ë‹;¦§!ÆÞnò5T—XÕ„µ™¼%ƒ:=Ûd+Y?P:ÊH€šé«)i¢çúÍKG;T¹Í ƒ’FéSÜÍÌ@7pa¦ÌJ$UºfŠT`WßLÁ™ð•ÒWç5–˜x—(«ÎˆxÎòjZ°j¯æºkSË…z*#ÂÜm¡0f³Æ©a â&e´ 9$‚0&Eړ厔è^Zzé˜òÞbPQÙóF¯¼þ¼4¾¬¿´ž#Ê †¾µÌÆÄ˜UÊRÁè±5xQÈö”+•è¿w“§]îë%%Ó`ÝêãÝ&F7Kd‚.Ì`¨Œ Þàd‡íËÇ ¹f’°(›b‚8HÈè Á[=¢ë;.™J;8v}/½ž=Þ“¡„-óØ;À`xätUyøA°{¢ÈÚ]'™ QÍxl~”Ôãí½º7LÕª;oz)¹){Îpòšµ Ó9çþÃïÆŸÛ39|/‡/ï!&µWÕ’¥nÚ½w"úAà„lÌ +`þr·°ù-úbWhI.ÜÓþ&3ß'®îð  ¯Ý0œ½õQw¬ÚÏa*.n¸.åÂõCèX‰ºw*™WkþÐÚö6ƽ(è'ºPëæÚŽ8{£èI‹û|(c®Ç×Ù¶.ߦ{Æzá  ]ÄòTBm¢…îÒ\ÙÍTD8б%¨…qi…÷úM|h‚cÝ ge£6?}•rQgÄ…˳Üé[ð-c&ä’”OP¢c¿úXü1­ÏB:P´âÊ.|]®ŽÞX×´$¸Ñà–UüG¦©˜Í)siB—€¾ÿ˜bsáC ÄB:çL@àOŽyf•1óìbýê=£LW&åubwÏ¶ïøµ&wþ'™pLjš{¿mÿ€´}pôHçüð9Í:Âaç±Äú~¯9§dYòie¹ÜäÏ>+N:oÖŵÕtOMd[˼:4…Í)µkA£3Íù®vº†½ã­]H 9ð¹•ÕÈìoi£jË áø)¬§UÍX< ^õ“¼hß_ˆSžþ¾´c¿k㸕 3ðÛßš}Ô!Ú»¢ôŒnb²r¿'‹´Øï×òx ÷^”OZr£ly ßC´ë–ÝŠR)†[ ëP£w Ü$®?}º=t#²wózPˆÝßKÃó[2<~%g]´h£„å¯Fã»ÇÃèG7—-¥/ìÑ.›h8{}·}„šã!<)'2õRcX—h%}nþdvQ°öeQÑMëÎÖ)ÌeÆÎ\IàZªõIÍËùéû€çî„F¢Ú¾²rœL‘Wˆ,‡$†~¤ÝûåJ×IJÀy¡I%µïÓwÀ¦u±Ø0) º- mÊÎígºZ]’ãT"al±tuYRSŠƒÒœ ^Ä¥K[À—9"’Q¦Yî"SNÆöƒ«=ˇópzXìžûtXVŠ£áÃr>­¡ÂóGú…ô4Ìé3ƒ$‚¡èªZÑZAÐYó¯­"Åw8AJEžÆ-䧯ƒMÙµ˜pðN•Ð îÿ‚@Q7Eäýwÿ†Êþ²„6KW%LòEíãY !}1Fõƒœì´~¾B¨´7È© _‚$Íæ]-˜å«ô¡.Š,Ëð(Gb·ÁeòYܬ†¾X¶ùå¾tÐ* OJK‚ØÄ£Ÿ)BÉ®#O&?+Ë„ UŠ]È ;?L•\GmÍrz¨¦òû‡úVBØo˜ŠÍ,Aét6¸fEvǧ7–Ä”p&*™³9F J¹½ž¾Ü7x3Â)æøRTW!³‘ òz®ße6YÙ«9V}ý.½¢Duõ޲YÑ×bÉRôg“É¤ÔøÏ{ï•÷ÐØû†Üeƒ“ÔJµæ²‘„3W ~XÀé"#º„EfÊîU¬1¯Ã¤*ÿþ]³S澩1±9w!èë4Gö–{UAêµ9S ‡V”.gdB–íQˆQöi÷€ÇF¢-~ʉ&¢:íÐ=éSýø±Y_9ö3MÍÍî¹Í'Ê—yKæA¿ÉXÁän&´ 6³¦.·F×·þ¯ëK[Ÿñ–ºæÐ£žFá Th¸BtZaÊ(dÉ @"}âSÉ6F¬{ˆtD'ú«ô\fÜn”êŠ_%±¿î¨ÓçôÎ{qéêP·kÎá•”‡ÞaeÒ¼ß L—J¸CЈ,ïÜHQrâY{\Þ±wò¾â;Hx ç-ÙŠ²ë±”¼õbys…*Úñ´¯QIkàF~LP×ÈêÐ:vRˆŠSŸöŸçmÄN=u¯seðVdù4*Ÿ;qÃ^Jý ÷¹)S¦Q„qÈí-@ñËzía—8«y·7¢ýF›/;21©*xA=d ¹éØG§Ô•“¯*%ó™,¦¡§’¤-”cµ¼VÓqÃ3GÌh0f#xÕEè«Í8L­7—ærƒPÍñ‹/·ø¶=ŸIÿ¢Á,šŸµ µó.šÎù­§yh«UþovzÞ›¡Í.ÕçÀSàúIqEß ðí«I$vÂÕ$ØN_öBy¥ù€Ì~4¥Ã™í,Þ–é~ÂU`äycéQ8½Ÿhdû¶__ãC¬Íu¹Ž˜2ÁçY/›a}§ÃÎþòÓKMjdvÀxßdË´»HéñÞVQª±Â,§g‹VÚ[O]Ë¿mzJ²·ús‹àQúæ¨Îv“$ÕrS7”¹Sî41+ë2phÙËõÊùvªX"¬s\‡~´â…ˆOôBЗ6Á˜LQÜôÄË`ÖСûN^»ïZÛäç¢aÁkù0bôdNÍ^z¸"ns²‡ÖÝÂŰW¶; ;íißcÊ51JgSKßà‚:Έ'«z¬HÉ5‡ÐùDõbD +äaÚ‡ÍC^uA´ìOŸ—™àNè6 BþûÐÆA–/sœxgceòÊ´°¿¼ŽÈ@Bg}ÑÅCsꦊRázìÒBYUCs€dE²VÇh !¨„Z1íÌ9\úJð”´ ¹ÇwŒù‘ݧžÚÕ‹ŒZ›hH<åªC $¦Ds]£Î»–ß ÂÙÙmÁÓH¡°¹öÁƒÎQ5Sì*Àá ­× á¦/²è)©Ã# ö·zd{x‚ߊ7Ã@îÏ®¹c\­jR8ëò¾ª¾{w»zx_ÚÝý•ð‰lu«WqÅn³¯Oê-œ×i‰¾•ÂzÃú­U²ÇËQ½‡Ä¹\ôõŠ0·`cÉW^@·‘Ÿñ¨¼0jÚi2 žçâi7iqpA3ð8zb㎢š™64T¾T*Pš-þüJç9´Ÿáò…rIDjK¾ŽÀ>ã õ • ÙÎ5{Kw.Ÿc‚ò‹è«NПhŸ ˆ‹œÑC£‘!Œ„©ò-ŒVÙ€ñ."N5ñl65l¢îuf{5’iuJsfKã*«n[Ò»lµ€8KÒs½‚ám¦¸#× Nß•® M$Â4 Ò¸oó¹Ágœw·˜Î)T°ûãZ³[PÍÄÕBË€‰ðèTÏ@ŽòiX e’¦!~@—‚ ½î•wŸÁ*ï,TJ­… #â÷UÊ=B•/°•íþ\Èà+Õ«KÌk,kŽò p:xÜ?î<³Æ"? é-Pۺ̀ÃA=G_ìÒS$þ[L•^´¢ñiìý3JÑ{|Ú›¨þÞ­‘å:w›hà"Ú~MH  ¤9ÓO60$CH5V`Ä2r©é¥:“„ Šê|@œ_¼W¡ÌÍÍgc8¤xòúAãÇ?ýú«Ó! ´¹M¼F™B’°vÎÇÍÓŒ¡Â…hS©l)Ry9jîk³ñ‡\Æî¸,`гîÖAÜtŸì¡ÉÅ•‡<$“›Ì1 ï€"Ž~!Ók.ä´Ë˜„ˆ@:Á¨ ˜Ö-RÍ0z1ˆbhÜf½ðz§…2*ü6Ÿ!—øþ,O~,ÄFfúŦÒ{çwÆÊlý.×> ¾O²×'V«;K<dÆK3qNFʙɤäó’?þ…¯ü¦vŽ«c$Ì{Ïîè î7AÝôMYå묌X¡¸TGÄkÑ”ïþ¶x’±fY]‘±-Ôcä]¾'~ ¾h?aSâƒrê÷‡VP`,+×ȃmÐTp8ÒeŠç¾ƒ«È–•#ÔIVUÐGäçU‡J–YKFÒQ³Ñ\mG —ŠŒîeB«söaøÁ6äáóÝ¡Dý1þìÅøÞÓ·Y¹µ Ī’bî­Ÿ_–ÔïK {LàaNyЋ¸²›l?/#·ên{¤#È?.vÄL¤L”Ϋ¹(m²²rJØ0*LiŒÀUbTùb—œêP¦uó¯3:èpÇ:q#ƒ+®ûé›-,¹Üååè näYK~ák!£˜»7µ „‘̽œ#$bXÇ»š[¦Ähü1± ½c Ç s¹eˆèÒG…û­ôHÊ*Ï m™ÕÍ uî‹.‚“«$ÓþŽÂù º©°‘J¢ÑU(¡\XZãÛf&[Mñ4"™^Eu†wnß3Œûš€tsö¦çE+ó`}¢~58îÿÒR±Ñ¶N5¹…{¤×Ùšÿ¹¼•ð ìRbk9?‘Ð"7ÔÛä$³9Kj*(¤M^È7úèx06ôå³e`Fféϲ€mDà4—(S ꉾ0YœÉòU÷ááYL=\›â\öúÄêsX)® <…]«wvaìýÓ&PU®…x~Pãæòƒ2M¦O/Ï¿¸¯Ö¹;ã»­[xùcÛgbDðoYÛØÝÞ=¬Î¢$Ò ¡ÊCC<®s„ÓŠŒ/¬trJq+f»1ĕ L=,YnxçÄ–ÖÁ4u¬îqùwKšŸò$úñ*áob…µ‘Ú¹4ÈËÊH]ÌqQ™G ¸MݺSuŠy;oïÒXì{U©wÑm6˜SB¬%60%Ýݯ²)Øy³°Ã{®.}fŽ+M½žê¢Ø3¹aD½ï÷âdÙ^÷¾’ÙØu_$HÛòdb® ðå8áÄù{ãÀºN ˜ú=¹c¢QHûÖZ~!d߸°…üTÒ/Ó_Óz#jRÜBú>re™3Îè-)¦uþ8®~Õ?u­7¸4Ú…:’Ý1g4å·õå¼fg¢«µöLen¸³„g-[o&IIžcüºRÜ™‡b‡­à”RŸOÞõ êuXæýÔVÓWºƒCDdàH‚Êno3YàJ» Ý?}Å@Cð™ä ÀŠ  îKm ¶¤l°'¬ºòžK\Õ|,úž ¨šÒø Gôâ7MègØnü^Êbsß<ë@d¡gâýü\G0g^ºæn_© ¥_òšes|lÿdȾ¦º•ÏbÖ8âTH4Ofµh´S:Y¡iq~£Z¤;ÃiT/[x ­c|MuýšIp·Ã)‘-¡Ï‡ j±»Æ^e&p UMê»ޏ󼏂Ò%ótMIeÈÐU9:΀€Óã¥ö‹†Ø"ãÇ®LÏŠÔ»òKU숗=åÄO’0¤f„mÿ8ç}ÊÍ:ÇØ ZâºÑݤƒ +æ=OˆUO&Í!ä‹úÀ€N¹¬Ð>ùf6Ú'«j¡lcŽª¿Â4ÍRý™Ì¾‚ŠúèFyÎ°ÕæžwÅ‹ÖR<_A¿‡ßÿ“S·Å÷D‚dt•u…sd}e·Â%ZÔYº|÷½r«t8Œì¹ÿAõ<ÆÎþ~ƒÂóyºo;•ƒ:ø€Ñ¹j¦ð¥° B¼&|×’ÔÜhʆ”³8¦ƒãÂÜ›008®—%íÕŒ$òkf×Þ ®îî ´ûB®Yå¢aMô†-­ð óƒ®Ò‡K«L„)íÙØC’žÐI :x\,õÈÉ ˜UuìpqÇ"P‚ OœÔdÉ`ÛòÊš&g*ÕÆW”ÜÃûg’òhÓl;”B@èŸ8þÏÎ3”³p·;~*«V¦ëÅzêŒ#³‰¨œ¬™Ðôš“Ã[o¦ƒX ÏwÕc˜CÐ*}!˜Íeû6#›Vröås{7OñAÄ ÷}7IµoÈJ»q›X\± ßÞ@½¯DíKO÷myó<_…2 ƒ?O²Š}•èAdÃÔÊ]êÈâAÉãÈ…£ÜZwXëÃ7+¶_c1¦ˆ'|ù"œŒ^ì NlQ¬<Ë;mïFàXœÔ{Ï@¥·UfxÙM’4Ön8Â2=÷v€ÕKIãâïÈ¥â¼R·Ôé{M“¢ TFpìÍ·Æþà©ø)–œbÏ ˜k^2p'a8“|ô€»þÍÁzæ˜äm‡˜?ÐV=¢…*Cæ^èLu$%m±Ë~ë‡ÎÒ)tŸ®´wMÔ´ü—³` [ÏÔb†Di\º O{ñßë7T#Ž%\bíî '󗸣 <, wp›LÀ`âý†~úÿÖïÏÙUÕÙ\™gÌ¥sØa‚8ó»N6¯Š%ª¨¶}Ìx—K2(êY–S³§ EuqŒõf ¹ÒTf‹|·«Î„7Bi͇ê vD¥B²ÙÜ9 ^`^B;BnüªaY’¿æá¸&çÿòÓz^Vh´µÄìdj¹àŒ Ý®ù‚ Ó;ô sBÕFH¼¤Qæ³¥`ê r¿É8Óœðò¥×–2Ú8Á0ªö-w/´ASùËß:_篰~yÏMI,ˆœAg —î¹÷Û£!®¸Óúß¼NZôý´Ê݈7Óº©¯ÙsÄJ´i+‹{9'œ—–]˜€ü÷â˜^2Rt`uZ"÷%óÎM$é Æ: °OÜ?ÔS5>RpÕûÔË:ù¾}ðg© ;0&æRž÷^2DúÀ<]—ƒX÷[N…ÌŠâ!I§ÆÅ¹h€^òͶÅÀóËo$3úW¼­F¿›+ÆTKõV_ÞeZÜQȦlQéNGçMGÃA/ð Ë }MVY=ZHgdM2ÐÙ4o¥Ö÷ç¶ÀÇ.£å$ØŶ°Ø»O sŠ;‹w"°%NËÞ°+Òœ[®€Å|ßcBvQ“uÂYAî®Ì”Ì)ë ðÏSÜJïó’C}ðáX‹ÙsÏtÃygXÒú{ó‡Õ(üɰ MÙàµB´E¥‡xLàÒôUÌqéšÊ¤øÂ¹±°;X"·-N¨Á‚ÁÔYˆ\‡kÌŸé·eRd¾†tê4É깈ßT= o0ö‡iÃïòÀçõ4Û·ÿ” Dÿ5l*èëxY-ßuÅá›’ª7Á`4HrÛü.†$ƒª.[ -^$dr….fó"šV±™öd§¶·ŸÙï φkó_å!ñ À û. ÊUyóήyC³O´œ•TîpŦüœÉÐ}0o1’À¢8ðFG½ ŠÌ'Ñ4|ÿÓBøS΀#×t½ªÔÕ&ycŽ…3–ʵÑ“Æ\Z[ño:€EòzTHjÏIª™ ]×bç‡8 OpìhòUëu½Œ‹¶“ õ΀¿qos‘¹2œ ÛÙÖyƒÔ˜ëùq¨u¥gÒþ×Ú÷@µ«½E%p§ºÆNµ*éB7¹‹¾S牉íAg¸3²£Q}Aö,u¤ç‡x!”#ì$J%ÿ‚l„ä×z ‘Q û³;1­ §õÿ™r€Û•|–ÎV“âà™kWFÝKg&Ì0м¥íž/Z~OÁ8ë‡K<>Ç +[= úŽäM> Ëh§;Ù™V·œÓÎâYÉa˜ØD¢ŒªcÜv—Ò‰ ˜ãt's|R’Ï_ü`KXiay[` SÁb'q¦e™´öÕ¡šÐH‡ÿ¬üñ‰9‡ "0·˜ϰf3vh8¶dh½«ëö¾RTÏ*ècDzCÔš#izÏi( s XwÿªŸz…“P8¦$Ÿú›V½Ý6®Y‹-ûw¼ß~iÅ|ɪ¾~Ë!§òžç¬×ë¤ËåKOúsãó·Â5zýK¬7Œá뾩^§rÚj¿ÕâFÊ©"9”¼;²T«¸ÿ_óÞ´$EÓR¡o¿<À:‡+\ê‚Ç ”íÐ$šÎèõî~Û1’PËZ/ 5Š-x.}úýíq2Õ‚ìHpûšÈáñpŽSòÞ«ž1Gǥ 3Ây/^·æ×ÌÑ©™®íüXà” í9Bqg ¥ .1eSi¼çy)Jí<6wÑ)ƒ~nw1yÓhàœùær éâ}ëðìj‚ñL,§é­zåÍ=)ã ¯]ôÏäM_‘qàôð%?¤‹@=}S“•­Ä‚³…‚ãGÕÊßvŸ6Ö>ùÜj¨ŽG”) ">G¾È£Ø¡)ß\€ÀÕsN´«’Õê€gPëÌ!7ŽßÿBAqÏwˆŸlüŽv4ÀêzÜíÞ‹™«2¿µ@p¡Öá;°;ö‰.¨?+×aÀ»õ¯Í¥‚jÀ™¶møÔ¶(4'?Áª¾ÿ·XQ©]Õߎmexb‡b,L9P¼*™5M¯7ÅÕjrÿß:@nu*û§ÀtUŽ_#óÃýXe-ø—õ~UVV$-æ/»æŸÌôK&' í×ùêxûUÀ[ÐÕ$À’ ·>F«P'†³…l D“ ?;=“"-#ÁRþ§È9%ã ºt@Ñ_­d#®Ó§X  Ä+‚v=¶·¾eÍUàçÃàè·!ýä ï°Sð¢ÌÛH&õVîXøVtÒxÜÑ[5e|ñ5Û=?QVó`VŠÀ~h!CÎVš[ ÎB¯ð½/»4QÏŒúÐºí·ØAüYî!ÂÂ/ŒÜÈ{æVlWG†RŽÑqwcâc0ÔÁ¦™jæR°Ä€,F!ÍÅý¬ŠŒcÞ>@™/²_HøW³ºùþh‡´êâøÏ)˜´ƒ·Ìœ ô¾:äuLÒfŒ¬ûq̲>bo½®T¢´Û ÈOª*Ôa=A79çs&Yp$yþSœqvuD×Ï`Í÷è "¾n¶R§4l#Ôèýo&ÌNüÌøÈ=h9ÉÍ@€©®BŽÚž¥:U) ÂVƒ–X6.Ä$¹FÍUãø­îË\Þb„dt(/¬"*–MH£hªªg¢~Ì3ê½¾ŒIµ\%,}û¯zˆøÒGsÂcCË’€‘å@[ q D™XµP­Lìï²àÝ2Nž6rk/2ê=Ä´¤8¤ÈŒ¾9àAàÑã;К6°+| )>˜2š™ÛN.Úk™–¯K Ù•xò;>l|]¯a=ÉZÒ²i­bÅß, IáÞ–°|,Åb‚Ý@$.ÏãJÜù&€îÿÜ_¼­>Îý;E1i@ 0ËR=ë;H­sÂë‚4º=¾V(C ¦ØZFU@.™/¤BB‚è—°[Štšµœn»o0D'£Y´^Ç ˆ+]3:šÍ$þãë7¦ùeÇÚƒã©éŽt€-…£3}^C¼¢Ï˜@ÿ*gÇ­'ýºkR+”rÿ›~õYb¦#!e¢ÛJ~ÛꉽY¾§¤È9ƒÙ°*.ÈN©z0Ý Øq%j`÷uÏ´éÁžŒfˆÌžhÛ!¤o›ÖXWmÑÅÅZÄ“òìWµz1éä5ðOû0„Æ9 ŸA ,¹¼id…½õ«8±Þ JIâž`ýJ+=HÙ»üç4Ì·s j2FŸaùNj¯ß–NÐŽGº¿,‰š@«Êÿ¿¶š@÷m ´–¥6îÕÝ#ÃA¢cÍU.û“­¹Y瓎C „¥ì¤AáGSGËLjSˆÊ hˆëSR˜Àý¯F0-ÇM<é"€ƒ´‚5¾ëáÈ&Œœw3¼sîÛþ§l¥ µžJÀËwŽÈßðä+ jt¯“à‡úlÂîâ[We ‹ú->.vHYÛ¶o@tО™FS_ ¥Šnt0ÏS®Ó¢æ£€4(ÁƒÈº”ߢÇ­åÜCÎ}¨Ý[w}¯[ÔT8;¹¾1ä<«U-.f×§·Ûþù. uÇ5\¥—ôWÁ{ »ôõ4#UäzMEdTÃqŸ14°öŽõ§°Ñ`§U¯ }eý•U6ù?NÔBtÐ1‹Y½zÈÄGA¥|·)üc Ï¥^¾S³—|.ók¿‡Ky(Wɰ…Ížl“öx_åzÌl0Ò³¾¬ôä\PÓ’~}r‡‡OA¦¥t‚‰@áÖ?p…È«(ñ¬SÑ8£É=ÓΚ«ø†Q[e²{gÂêßcl9d Lo#•†a4lz#¡)ï&\mÁRežN&Ë•РÔûºùˆûÓA² 1½÷kB‡Í‡ ý!írÆ(“´]É”âs‹·÷)Y!§Tª\ˆ ¿ÀK ðâh8Ý„4–*ÙÀ#zï’Ñ©&üïY‚ø¦åu)‰…;ã¦7Ô²SƒËAà5”yàò5³ªæÀÏçóÁG䑃ñöñ©‰»C: ¬bü üòˆ )iñb5q”kðEí[êZ²¸ŸØ:—Ü´.;Á…o[Þ>Ǥ{)ü\ëž×B*‹Ïb\Âï̺ÐFªÖ½0Æ±Š£E/j»…7~ÁL‰3nÕ—ë@t;[ò|äsÕRë&Ɇ¯=*UNù{‰Èçe»‡dÍ®^•& ,”ìç<Ý褒FÆ,D&_!íç› q¯ Í*ÂÜú Ä/þ#„w}+nÌ}!L,$Ó¸4üê”UògÚN:Ýòºï…Ç» 4&Öí”À34ÂD{Ä0ñỌAŸßaõ?6XjßÝâg’qÅ7~ÃÐXot_o ^œþµéÈû2é¾Fn1¾(XÜlm*Tb²QDBú§ônn†íXº|‰… ëzJB>2TŸ¶¤z>ô‹?†p6¯6S(Lö“OrîçúHÜ-ÓÆ>‰£*í¡«›éˆ1½áô0»CcàÂ59öµ£ò~‘¯ˆ]k¿ðÜ¡?–‹ÅçK†žÇïdpí^¼Äè ÖõgBq­µqBŒ9×·6^)ÿ¼är^]æVKe JbN\Óêra Í\6;°•Å”<¦É)a½«}X¯Õ‹÷‰²Eâ§i%ÔÔ8lÂ-,M¢!mw÷¦y&ì±ãßÊÃ86`5~hJu˜*±¼:¯äRÄ!Ú¼8Õ²HFwg\ÏXeb(™¦|?A;@õ|£ûáÆ±ce ±|uÂ&ô¤ûÿ;Z2Ù¡éŧ8r­_èrÁWFg—Ëèþ‹C™ÎV0D¢úÞ}Ëmõø-| ê/}Í.?•ءƼö£ÖIyìç‰Îɳ˜›V€»GL‘`Òe.|ïJù>j_#÷Ê9V£àöQÊšZš0¥e|@¥fe\1BI×¢±`óJö¡ÐL)*y‹ØŠØx'ö$!åS©sÆŠ –ÑDÓ&I\q¦’IY³¥%£2Ír°{æÚæˆ`z4§í„ezõshbÊJˆËzžçUT±îxáÌäõŸþƒ“û¸ÀÃ4–'ò )·®(u9d@¤úiªÝHo²ùÁàU ¾ö|’õ£¼çp!÷g÷°§¤ Œ€¡_)z©ŸyœÃ#/<ÂÇzB^ĦDþv“ï¨ôókýañÚ¥ÜÒ¨¶ñ¿•ŒPk¦Ýgwš¾^£Úß™§­ÒñúÂhmoÖ~ƒëók9C@ÇG]»ÃÓ¦Gê8ÕT E”’±’mÙ ñ¨è¾í¿|áÖ½Ñö-*¥}©5ºFO.æ·Ú”»DîˆõŸTõÁM—ˆÀIS˜0|9NYñòcù¼ê1MSƒŸ9°#F_~«IÒ;·¾qŽoæ`R¶­ OéP°ÍŸ çc*X¾Z‚FÒûý{çÀËXòòÐ3½`·% ÿ ×EgÀ*ÐU_ÞˆûòÏF > ¿°2X‘a²,ÞYM€Ë)_Ôåèþl€MHf2>Òª!åmäѪ¿‰â÷ë”Uó*Á}Ï»¼L»§‘fZn ÂÛ}VAجUHnçìí^퇸Šý¯–°,ÿʹvæÕÐcª!.™ÂðAf§ôþ縺¦2CwØav7±ƒø·TÅrÊÇHÖà\ RóùIÿ€£Ä__Ý­½6ÑÃêê[¡_Ã×ë°p’пÒíš™aÕ9B¶±_pFB¶ûÑQ ×ûÚ1 ¶åƒz¼—w_2zdiín‹úYnbÍÖ2 ©ÇܘãñqìÓB$%¶ªZGzüÙZÁVðè N¨btòÂš× Þîx”h¾G¶¾|bH„*K„¹Ö¬a³›ÍwÎ÷Ï]\ ~òÙ%·€Å”HŠ#¬Z{µê”TÀ ? î‰t €€¶ÁaÍ¥Ëwn¶Wå¾{wÍET³D6¯Ž‹éeL³I3!&LÏZŒJf(•×sÙX[Iî=5’þÈ6f³j©5Ýh6˜èoVûku"ghcö5î~^Y!\q <‰NÖ úL9Î~;ÆNBòQyø¬›œ;ÎÚX¢Þ“6%ȲÐѦ*‘æP9€]ªæ×VQ?Ø‘¶Y?4ù™§¢¼Ó·Í^kUBÆf"7›ýÂÞ'¡HéÉJ2ç~55hãKÑL!+³ÉÖ ã–‹¾ë§ôPš§2N%u.ÈLJGËÁ_éX(®8.Ýø™ +×ç¤qOŽã(˜è¨¯¼«ôahU*Ìóï:/Ó-Okk¯ŽËeš Ï4J-"Yåow°µÈ–ä!இ†KŽ›>Á*…“ao|àÒ€²-í%î l̽*¾ ÷ŽÇñ>†V;Ð$yËÂ9‡ì ‹á;¯+•µõZI”-Õµ ã}'þÉ:z¬ÖžŽ7Ym &g}°ÍédjââQ"µè½.˜Óž!£™ˆ©Š5³PÕ¯þYÈ`™ö1ƒ¼½M¶˜È)ÖÇV‚.åºÝö×—ÄàröÈ ±­µH4• ÜÍ/~·TÂ'ýoaÌpº ¤ÃTìÐ÷8Uâ}Ì « Í÷†CóxSt[ð9  ¯,hKò«ù§i¯0ŠìÙqƒÑRnºÔõŠÄóÈ`—Ó‡ºd±Q(Ýð/1Ñ¥å(“ò[‰S½£@2e;À®/H¯ìèù¡?¹Ð†×xep˜²Fl7Ø16}yóOç̺(B&<¾Ã\KzÉR5â  T 6ø£_™ UÁP'”,‘èÀ'̳{ì4½dkÊñcùý‡1>L>£ñT“ Ò%—c’ñ *k3‘M²Å~N77®pùÏÁPÆÓJ¼tÜ]ÍÝ•ª¡pxµ_ ›†~ñ·3¹-²Àx¢—Y·ƒsu N¿0û½Üj|gºZMYNˆE,´{.±{™|BˆPLØhÇAÎý+óÁ˜žBfÅèžÌW•6°ù v/—VÄý°æÔ¯.6‚PWî\WáOÖ\MºQg1Ð^Õ  d9šªƒï™iA~ÒЃòzÉš)Ä’¢x,\ª/>ý–›‘£ö_yÁíð¸†lË[!uyîÀìÎSNyíº ;ãâ|ªÄ„Úi¾À‹ØHøW³­ƒU­ h{?ožèª]Óö5ÙÂTMdÂq×_D;—7Ä÷Ú8†Vú¢~Ye¼\íÄ@kk»pÏ0ñÆq¼•Ôôw4êÑŸ½˜ —f˜U˜k¬ž)B¥Å×JF` ÖN²ñ<ÖóΧòˆ1>Ó:c%/Ç´L1ÒÕE‡)§ˆ‘F‹bš¬!y9_ǺqÑÙê¿ » ëLfÙb¹l#^M9öpX—“<.ž~ïZPz¸—àË­Ù½·Þ‘Љïês©™!ÄØ }úÄîáòûÑ9¸™Â¶GêšíCO7¸MGÔjAàK1‰¿V+oüì#V¹¡¦772xµé¡(«=ƒåOÀç1ÿÀH¡E§Ó«í0C&Cœ™Ùm¸+I”|ˆž:ÑÚc¢²v9H«z±{¹kq„, `‚s©.äHÁgI?Ù‘’cª •a¬4ÖÛ Ä8|‘ëJŸ‹Rì:Ø^åÉ×óçCãlwÂj ÎÑgë çý]ý}–9;æš¾f¦¤^Þô|–5*2H•šÚI\dB»/Q ?g¢¿pïêb8Ha.bœ^ËÛ}iÅj—£y•É…³_¡RÂŇs[‡ÁTQë{BM‘øH½ŠQßËËøKëµåݰ]¦]^lê}X>ƒDî' ¹Ç$­«´8ZE(ß·ÊXZ¢ÜÇ9O a%ݧ/å–çb¾¤îŠ€0×ÏqyÔØik1@¶ÿD"õ=ð1‹ÕGœhùõQ\Püý§È‚Bj“›ävÉß_=ù†Êφ>Í«L1yaÈ ³¹÷‘ÔB.½Ÿßh’{2NE‹´][ ¸+ØÖc™IV¾Qý6B£n"ðýšÐͯÊÎ×,‚ ô1/q/Ú[Ë›uuе"ô/ ‰PJîU•LÆFq”D@üãÀÇo Âbí:0Ú žs±ÖpÙ=¬„sPûèU† ½xžóß]cÆÒÔÍ] eèè®!YÝþûžv%sH^÷üH¹öW<·ÿ‚:C^Ìm€‡£`=ká`N—LH'ë',•cÉɤ5ýUìÜàa•;!„ó•‡phV‘MµnØE¯—ÉïÆ*'-^–rDð„)dÂå~®ÙájUéÁ‡ MCŠ&ÿ`=ãõÃóð.;cåM´·œjP¢W­am‰ï ß*w‡©ÏHkå ¨‡Ï²•tª¾ ëîC˜ÂÀ·Í¿ ¬³;Ú4f¯™ÚÃZN`ŸŠJª#E£ûWeÏx4)À~p{CBØ4F¿¡SŽòæþh vuöâ]+¶\D²zpÚ—ÉÅÄ–9>×ÀV08W´•Œ&¼³&R¹Î&Ó\4‹2Î?™µ¸*Ë`ÝÉæìP´\?'ʨM¾t1;Ðxa0Ú3ýïˆù/)#Õ:+ûÜÏÌq¨µ9äž/«ª¦h}®7ôÀÏ\%?}v­=õ‚fTŒõº¤ðþ:„¡›×°?ú g—9–½H7h¥}\´Ébñ‹xTlc\EïQhé¸á„r<\:Câkô„¶lpW1êÊ;RÄ`þ1 àÏ×'dolzS§|ùóÅLªõ0ž`u )B8Þýĉ°äИ×JðXùÕ€‡êëœÆôé"ÅùùÕ?4T…æ"¥um†Ð‹Së³è[XJ±g0Å¥.޼ÆÛl| àÐ gZ…óy«{<<  ÐLa^5O™yGÐŽ"¸@€C^¸/ɘø)ÀÕþNÙ‡¨+ŠHƒ]èß_÷àþ·l™Øpcmð°iOn&ç­0§cÍø°Pkl²nþª0dÝd†ƒdY¨U#B'D½uÏG}¨ Î?oeÇ\ƒ¯ðwZ /€¯èð_;Pm_—5æk7ß?1ž#£ôl¿³|QÍB÷hÊÎ0©bM¾;øMNº‹Ðû‰wj“ë•tqðÍöx£ÀÎÊÂX$¶D-'®õÍN~Ûùgƒ¬¬AùBq·p‘J+WÚÎAzY\ø6$D—˜ :¯Åey˜Xn}Aˆ~ÙDñk¹5€J¢*HùZ¢›{ˆ «vv³´!8nþñ¨@†lϦOš;ŸÈÍLýšÿâŠ1=íI™.kB:˜X,KruX*ˆ’  ÚøÎ—^,ŠÜH“J©Kìy—ªO÷à/ŠUZ| ›ÁÏo )Ö¢¡·»ã“üò ÊaÍÌþ>š~GùoG *º4®sŒ‚§ IÆe–Ý·™ ;@¡íóÏ30Þú yÑÌB•ËË_çB”Ð*¿r¹–Ú{MÁôõÎBüæšek­àßmmë&6ð0ìëX±‚‰ÚŒéâ‡ò(ÝfD}§ñêè‚]IŸ&ãüÈþ3 dÂLÞ@Šr ê•£(0wû2×þ´ì‹Ç¾k©ÂɾâÄ ßP†Ò2_®VDóÿq¾þQŠ÷'å,cż²Ò¥œK.Þ!†°&ùd}¡çƒ³‹ ŒY$áß—V7“Ê~&M}¯|p;!³@42 'Fuó`¬øÒÖAÕÏ]“€“Ž  *Ú>ožBDcNœ#@n,òÍ$ ß>DÏYr;¶-¦r< #Í(Äç®´µ{ Qþa!pœ;f)š¹Þ ›Ä©¼”Ü_·éf@ß5nE˜>¼Ùv¶¿ÉŽ0²YÁaØ(H¶ö“ßÙÂ;S ^Râÿ®t²Ì­\¸LVU6*}ÿ)A&æI3±Kk똢_NtÄï†ä„ùA*^ù<±BŸ³µ’)œcŠQMeJHÂ$1ƒZJ‘î}E*‰ÏrY•*=5±óQa8ïÌßyHË ÏSæ ã_²÷*]?2±€ 4½MÈl¸Ó‘ѽ—€Y¨hL6=ȇàÇKæ¡¶™{Êf ^‹[ÒêvS1g!“X¾G‹Y’£™«ãì‰÷Ðq¡*ûØJ#âgÀMò”…yÎB~`”àá9Ê>êÖv°n™}Ï¡—Ðl·©–\¿ÄßXn”]xÕ§0-ûï ÔˆVV—–(Ò?—‰¨ÿ¦øX%`yØh[a"‹èÖÒo‹æ.ª÷ƒdäÒˆbî„·ÃÌÀ ]³û.0‘úæþŸ×šÇ…E¿ãW¦eÿç ÿjq„ˆ€­Ÿ»³6MåÞÓKâa– ³•½i¿^"ÅIrUž=!Uüh· ý,ÿÜRL¿2ÛíPØ{NÇ„ýÉëåÔ8@ÝŠÌ=.ø/£öÝ<­Ò|ÐnÛØî# Ÿ½vô¨2y‡hî%€½Mþ$‡»•¯rC}Ù‹Ž²ó«/à¨ì‰âÞ+AÆÌm”‘ñt°ž¨ nWܽ‹0±p`÷—ì~ˆŠb7Õ” ÁL[Ü3ïQÉú’¥b{«Ó§¤,|p¨èĆ„øã'(Ì%äý¾› }„õ*H¿‘Lî"ÝŽ!B4uCöxÒ]1®AIöúþì…-Ð"§]³_±1̹H%5ÕE:#NPDyXâl+õÏYc—³äãÒOã¯ÑÉÿdT+8b‰ë‡L´—HŽ£ø¨èCéŠÉ«²èÓ(Ôå}–¢ž]š~U(ÎÔG墹]ÿñ«®4¶K­œ'š„sÓ'\U~ ß½ÄWR³ejIž0és›± ž¾+¹] k”výESþ¤ª…´É®£4ÁK§Ì÷WÙÄ]3M7 ™¨ûˆr½úPó ÝãDžï“Ar’@ÿ'áüù)øyjà]Gðó·Jð ">]Å$î÷IÞ‹™ÖW0†²§6´ul/Šÿ;8 &ÑÕÖgø byâQ2Ĉn,é)]ó'è^ݳ=T’—5è£\-gL@ñoèrüïCè—ñ“MKz ˜ì~PA¨ìxøÁJææ†N1;1…ù“8~ìaÓé/6ùªA ójsNíLOûwð"t¶²g½ðí„We…YÊi—¡S}{4)’?7„ã‘ð?( {ñ›¥"A b0DŒ'- #èQ’©ªJ§é奮6]I>\6GŸ‡T3ŸÍ’:QLßšCàÈ[.ÚbS€çT=„Ö¥hÙ*Gü‡}'mj« pÇÔJÍ«pezDÈst3‹™jìã&KaT-Šˆ'âÏêØù¯K†K騋¾ó*ìïÎØò¡Ï?°(°I´õßà~Ü…£BÔ@Ö\þrÈ}^ìû2 gšõ’õÚ<ãÞAA½çåÔŽ¿Õ3.ŽxÈNg8@e5 ;ÚÔ$ù#LÃ3T¬žIù ÿwêûz2ÐÇú(ãj+JûA».]MéÑËB Z6´K-e~2”º)“JàŽh—÷>·8~Í7wËŸÏ¥fÚ\rEÅL»[6wøfãy})˜fþX‘f,aR9-Bºz•0©,›ŸŽž hFÇþ:…*HιR×èzt‡é*;eíeQ4w7Þ‚6K’øæ}EþÛs«s4Û)^˜_Ö.³´µQ(0°N1FEqDxŽP–óÓ×äX-W‚,HŽ1•’‚Y#4«¦ÍùþGíý±â.ÿã±Ñxûý¸:g¨Çã_ Ÿ§ã]žõš¢dYünw)‚ÊûO©ÐC\ £I ß ÛÍžsNÇaŽ”ž»Mý›¥DÎ ù8@ÓÀ_ •®G3Q«Ã“® Wõ(†rÏWv èÖêß Òƒ%øåÈ«>@A6-a¾Uú¹rt³yÙ±fô9¯»G ÇGYµîP<®ÔG¼비;~-ÿŽEÚø‰ËNöm«9ms6%Ríš’H6Ê€3Tß^ÖÇøÄøBbèÆÃ¬ù­ømo™5T©§¿Y'æçó'ðE+•€J¶5–¨V<¶ñŠ(d^ëøÛ5¿ Þ(2œƒ<â²Ä›„Ëž¥@ ÕìM]>ª’=W¢wdÙ˫ƇXïÓ*>ÁA¥ÈkÔ÷&ŸA½r4¥ö ¾-XvÛe¦ºŠ£ÍKèŸÌG1“ÛÍϦÀWÝðãO)5†ÝkŸ¦NM\ Œ…[T;âd$¡/…™Ó‡ìiÀˆó±ú7ž®}y;€àªÂÔ®¨(ÀgB•…3r˜LM;æÈzEK¨i™Õ¿?=hÅJß/ @Ï;Ñûé©ûã³·b´‹»üNÛ;›ÔNÄô˜HºÐ¸!ëíbš@—Yé·Ü¹ÃX†gâNwªQߑɦx JF3ÀA†å˜†_}ϳômm dù?ó•Îàð°*™ó¦ü•ý8zÿ「9àä# rbÚËý° ûÍÇËÉs°Ð_QFŠðö{|,½ßÙÇØä±#ö_.Äðµ@R tø@=æGtPfüÏOwâé‰xÚyÏ¥ v$o2û¶ ¹ú ÿfbF´¼Öˆ9ä'šž¦—÷ƒtr”ƒ¬Æk&o\ݧ~4AÑ ¶Ý•r°$‰]›S?·{Ï6ÏQpfcºV‡Àóû<¯¿#|ÙO, m£4˜Óˆˆ%r\©Ñí¿n°Ž§bè#2ŽˆVU„ÞóǽápyÈw³Š¶Šu\ç$Ò¥tÉ ê°të!Ü]|;¡ƃ¯·a[*&: -‰à„q´ß÷»;Úé*8d?Çq†3+ŽMîrË"Î"¯¸5PØ‚ †÷¬Çn2tÝŒëÐqöÎXdƒªà9«‘ gæ~甑†Ñéjµ>ë¸ÇÁk˜³`~?¨å—«ß_…ôä–ÎõðÖ&ý©C%ÂU¦R ÿG7…êݼ; ÚØ)yFfRÇ?Vc~œ7eyR¤gÛ°7H#,êéŽ!=#Ž KØ·. …~šMÉ*@x£ ™Ð°Bð¨bÿ)•δ|×€ FÌÅôö†ƒ/'p+W–(v`i¡lìC1¿EV¼ùá¾;•IA¿É³=ÃâËÇÙê5Ö³v`6ʘwiZwó¦[­ëY-ˆ7~nËY­¤Cîg–j8P(1e[Í|5éôðxZï¸Ý7Ì1›­$åüVŠY{»ÕÃÖB^QÔyynWÞ'8åÁu䎵00ÀÒç87œþ.ŒC ¢ÿA5!b¯÷庬ô?†b“¶Èôt ýÉŽÏ÷朷ÉÿmU/P—H:_!ÈdXÓ3.§`* v[ïÍ@¦ÇNÓE7±>Ë¥Õ÷°ÈïÂâ;.]CüÚºÍØ^®iþ‘ïÈ•Gì:Å·WnΚ¨s€ëò¿Ÿ=ž½¡ÿµ0ØË<‡Ô è~Û[iÄNCí³ üÄýÅÑyÉ+8Öµ+G\>CeŸúèׄ'ß÷™VH£Ö|ìäG p1 ŠþÔ1þm$5+[É àjÈÍ^—`†p<8IÀguÛ!ÓÈW>ÑÊX г<=x46ûœ–L/2tñóTÎÄ W‚+:¾b#@‚Úž?©y½ëj©\(˜•Á•„LÃÌ„B`åV ¬«2“p¾¤§ñq"ËŒ3Ú6Øv뽨ÜLzŠ”-äHqÊä"ˆLé‘´’[±:(·)ƒ¶éaÉñÓJ‰£Ò€ 1%ü®4¾=²3ã{õí¾V‘®iÜ.pÜTAŠÖPž¨ ··(],³”YMYþéZ’ñ§¨™Ðøy€B¥í*hÿ­Sg»®ü:n68ºˆXœî³]ê·ØsŸìÇDê]Æ1VCÇhc@^¦(Wg*›+žíîk­9È4-$õŠ”×ǧ·2†$0gH¼O£i^wŠ“_¯þ2”b¦çp×¼55:¬va,*‘¤%ºwD¼X«öS«}:ÌÏÓO¡5ß³/Úm|@[bÝ’b)Ö¤¬$„Ya@ï¢XÑdrKEÚ‡#€˜‚‚&þ^'`[”FÕ>§K´˜‹ÒE6) ¨<ãÝ.ý^8Fö­šˆíqW24c½‚ÌþbxsüŽÔÃ*³T)¢X‰Þ²óαÖE|WÚ×›Ö’’tr,fÿŒ†"º­º“]¾/ô¬Õ!ÍLèZ©Ü›Ú§?Esý• Z˜©Ý~,µ¶DLO-})êß\!n¾çˆÝÔªœúð•<¦Ö =Pzp¯ø¿¬¿m’¸€˜U Ù7Q»˜“^\øçU»§fˆÎV«Óˆ¯ŸºÉp¤UóiÖÏà4y;8ÞÉNÄ$Ý6Ú®Ñ"éÈ¿Ô2õÊ?þ2pðãçàÓ%°„c¦(ll4`Œ< ,=h¡Hpâícî’Yh×ß³­úŠ.%8Š1 èÇ}ãqº«7ÉðâÔ_øeYCç±UF¨ŽÛ‘5ÙqS@2ÆÅ¦ßù(9Ê®‰¥BƒôT’u¶˜¯"ƒ“9׸.ÅfT½¼Èëáäœà‡|lʲ˜µ¾øÔƒAAWð»óïs$Ëo-^ü½•*¤ºçk95 %›'å ¿côyñîs¶ô̤lw¹x‘Ú’êë\¹.l¸ÅË7A‘…ÂeŸ\@$Âatì ©ž ìÍ-sfÂ7•ûÙ>{ÁDeïm„™¸-Ür"šF÷‹ñ®{7 2f¯È…«ƒF [£–õt•¬7¤'ÿ—Í)ÔLŸ¢ Ã{©ÊÙŠÖ;æ[;S{èçÇg‰Ä߯óHã¶EÁÚ ¥Z¹1 Ú Y¹6Ĥ9ŽAàé˜/Cùà<í Ïíü‘ûMp§WåKÕ/2/\Õ—™´}P ³\:ùˆaŽ;OÝQ¿Ôj?²âÎRZñ2§¨gjȪœÞÎ4¦[nDo 1ê*º7P–s*O™Æî¯MÇöuWäÞŠæ“«E ó噜úþ#“ö‚ &ÉË©ÙË%Š `P#ˆù×µ›¡Ï 3ˆtN(€² ˜Æ$®àÖ ]®þº+'ÞäÙ ÉÿK3 "—D±Æôì5‹=8Ïÿ5,¼, ‚”YÏbHMÙ-=µË£Åá0¾8“=/·9q€JËS}ÀP¬”ë¾m'0݉=ªG0¦™lãÀˇâ˜bD<®ƒä´Ðȵ#æúز0 µ&eâ{—‡W\ØÑdµ}ë”XqC¦àe»ëŸy¥ÏÚÝ«žZªÿ°}ûj H” ½ïþÆÐ÷òLÇ7YòètWó…‹áòÈ2ÅÿDS`OΛ2ðÇ:µia1Øœf]Ê•ÕÈ–˜Oý»Ÿ7§*¾¨:ýîMù>”:lÆiŒ ²†?ê‹"Û/§c×0Ø´Žà€íŸì6bRH„ùÓu—ûq—ƒñ¼ÅMJT¥nˆòH€0Ó˜öƒƒžÄç×ãáàÅz UöŸ/Òжýjº àx fLÂU8áVø›èÍkÆ?Èo",úVcšçóóeUo±QÙú‰–H¯ä,Ò ™¡ŒÖ‘¥Ò×üQAL?‚E‚)xÝ"•’ÐÄß lAòx‹ú5µ[Z&#‡š£ª1˜ æêÀ¾`6L˜`r¹‰üH—Õ˜KBϣ̻S[…CNãÕ>HŸªÁþeNŒ ")²y îùË =oku˜Ä”Wɵ! .|:—Bø\. ÐÒû|UÙ’ƒÓæ{|£ýw$­½y7ã¿]r·èŠ}þ®ÉÀN¸‘nÅ=éI{`ùI,Ú—ç¥è6<æIöý^5î ­f¼6Ê&§åž‚¥µC®ãTø³ÕØ\áÊ"NDл¶W^CnSQE1•¯SrG÷p÷ê ?‹ ¼.CCcæ‡õ\©ÔÒo1üÊŒ2³ ˆ£¼ŒLoIŠÝ·ÀµŒ»‰¶}Ÿi‰Gû-¹ií«Î'Ð0·à:%[ˆ!&O%>ubÒeɰkü ª8ç÷B]î¢Þ¿Œ6-a7ü‘> zø•"š#Õ†]{D·ÚýqêŒTŸÿ5ƒñ·þ,+ÓªHÄÙïжDZ™.Gÿ6Õûr=‚2¨d)2:h«A#âdu0›]D>׿ÞòÌÌN$Z¶Æö[_|oJÄÞÒr#†[<ì*Q}_'‹aŸ‡¦ÙxÙ¯à1(e ªO8ÆÎtçÒ5ÂrŠ÷§*|Ý~Òex5 ã³ m;ºÿdÀ$˜p…/åÄ=éÃÄ‹°Rs€þØQÜ[ØB+E‹ODWÔ=w†ññnDMgæ<À?£…cºÀÑ/KUõ| æ%6¾…¹£©B~²eãAFµ·^Ætúœ½;\–÷r‘c÷ï«"Rƒ^𱹎¿”Ž’X|¡ßÐÑ;à¼`A§å’…ap×BmÄ¥ŠñÇ ÒEƒw~z¬$óî9ø'SˆØ4Ñš‰Ñ„ÍŸ¨u3øÆIÕ”¢r½]Jù°‡.¶fa8ÍÒsîùÿK8‚HÜ$âóz©ò_Ïè¦  7¾ÿÍïª_òõ4d÷v¨™Îˆ†Ö @õ¿ 4c׸Ðɘ‹ÄHÕ{1Z¸E† 3„À/Z(ãYÎVD4f¶ºs#c팹—xóT³‡¬džå·orÖ×øÒörÓûXÙxŒ-׳å9Š€Þ=AÌøèƒ¡ú*ãB³ ÄÅe› ¸à‚ª"  8_h}Hd€ Y™¶\™›ônlio7ǧÕÀ‰±Î6“+[¸ü3²ï6™œÞ¶0QÚœÔXÖ“¨{ 41R„UÛ"bñ"”‚¬¸Ú›:Bváí¶ƒ•H›Àñ5%=l F<Ë]/žc°F§ Q¾-9L¤ŠÅÝpaó«ù*z8R´È÷ºÔ½<Æ ½–d$£,¼Îû&íI¥™'pÿ‰|ËŽNƒˆ…?Äè+ÒrùwdþfàZÐa2$ÍŸEU× E=Ô„ÌFâ^HîÕÝÖJx’'Cut§2Sñ¡a¦‘Pa©{$Ø-nfA8tOê1§´­põÇ»Iö H ÄÅÒ]ÊvÖ­>dÿ˜UP½“žúÕCü˜äñÇgÇŽÂÞIèÝo1þ‹G ]Õ¶Îa“ ¼PŸáÿ®ªÃ³&è÷…®£Ëá}D+ò…ƒL¾¯mP÷pAjÄÖcSùÅaþìQµ\˜úVSÿ1”ln0’y(vF1‚WÇJŠ¿ˆZHœn4êQ{v…7+Eˆq^é1 ^ÄŽTFIÈ¿—ÂéФ‹dVÄ'I~–1ÉyŠwND{¥Å®² #ËæFØX2;nß9ÉôÑ6i˜Æ‘$„‘2åqW¨ï\괆ƾ}EXD"HäUˆÓÁºIÕÉvMºœcvÕåµ`NPpð¢H;­|ÅnÁú”.KÌ}e_†¿+•8x¦Oè”N±XܲE؃8´]‘˜—FÊsT©6Ü–1 #ÂMù˜NæÞ_ìñ4H¹ ƒØC>ûxµƒ FNuIƒÞî.·m&·ƒIÍ=dì¢ï›VÈ<éÞOxÊS¦{‡‹‘Z?{(}Ÿc„(#Ѝƒ\òÈ0^/þÏ|àøÝðNQûš ÷C˜ž~2ƒ™i ó†ÛݸÑ1ýÐ4YÛ¥àK#8W]ì|äõC¨zg@ò½@Ÿù­y6G*»¤4pq¾åŠ[]²5f­Äàx,µVWq  1÷ÁØ$ }µmŸÙRQƒJ–Ö ¢Ñƒ–k+yX§àyª«8ûª¹og¿×Ã7†Ø 4 K•ÓÔý8Œ—¡AP²WÈ™§Í(Ê‘MMú±E‘±(yÁj©4n›\o:ƒîMÚvð§]K¹ ôÄ%[‚í53Žø8[Wf®øÔPnóéˆú"ÇËuYZü"ÔM 'Þ“5ׯUj¾#‰ÏþÉz[F*/•¹ÙF¾q©¯Ä?ˆIz8ÉŽßÙ Öâ-n1ÙßœŠc+9%ÉãÇÐAëmþèîÐJ‚¿P¼IÕ½$ïÐF€¹XòqQ§ Üè%áÆQt+·?L`ƒÀ]FX\ÉDös¡´1Íåf9Â…M ¿hh€›ªH 䎚ãö: ”±Õ" İ÷e{f¶ˆâf»6Î"Ëõ¼ âvhƒU¢÷ê?óRÞLìŸÝsî:$O€ÑRV0Ôl4×fðˆw±Š7kLpAgeøVïM`F¼HMÉë1H=[Ð};‹c M´]c5È?J5z(9GÏï,eë‚øç+¯Ù&·ø4*¹Et@19½ß!®»ÛÆ5PS1¯÷=8NuŽþ|ÍòÛÕ¨Ê1Í—eö[FV8lÔ´—Þÿ0A ~ÿCɾ©åw†ˆÃé÷ |æ_¨Ôì?ù_‹ò`?eAyÏAäË$À•]j³)«ÄåÍ9‡*)™°FZVJH²/—¾ü¼bš†5< †£®°ñ½ðNÛ¡ÍOžý:Ê oaý!r¼Ü+¯ÅcLD? “ŸX•é™ìÊ=±I{)˜!&‘ú¦­‡Òº/Pëdjz4—¹}‡­ªS¨ƒ7ÀLü‘Í F²ß÷ Å‹¼ÿñ˵“ ¬{×Ò5i‹'If+sn#ÖÍ;;¢ûÔ~s¸q>/ÀE#ãÆ›üqžä-§Ø]+LD¸Ž]+Ü|¥W¿² â#PÞÔ2b R »WãœãbÙ‡âb µ… Ûw]Û;äeê5^¹UJx8”PøŒ›j6ÌhU¹Ü4KYÛ¶7)°6õ.)Q!2¡¹’ÄÈx0Û9ϧ_uº¡JÕ‡Fùº`òÚ„3O–°ƒêæF‰£k¯÷Ë{º; þôa9"ha§wVÇÒ£ ];7ŠûïÙirŽ»~xRf–ÌÞ£á8žN§£Ìˆæqä´6¶ ¡·Ã)ülwfhLˆucNCÿìÞþ “íÈ# \O€ƒ°JÀ}3QdìC3.lÒï4tÝQùŒÁñ—½Ûl‘BrDd £:ì}!Æ·nÓ¼à!Œ4ÒøÿI”³¼ÐÖ46:/c‡,}+?sµ]8ôÔó=µñê¯|9I@».¨æ”ˆ |Žódžgè3!j„õóŒ—Ýþ÷ƶéÕponlYgÙÆÕ íǽ&®Éžcb ¤eßþÄÛS3õÕ^Ä”4ä.ïw|7ì•ù;sé×3^Ô œz¡ñ]–MåIj÷8©3–éßAmq[oa@ÌÁAu©zŽýಽUÖþ¯ÜñÇêQÝ'Ê}¡VÜ=qW¾Ã(…ãܵPwç¿ê3Ò¸Jž¤bâG\2”eœ[¸E*³ ­K›q8ël9žîÎ>•×–Ÿ€ÝæÒØÕå8rÆN Ú-"Èwft'ØWý¥Ç€åÇx~0ÒÇm‰¶óóºÎ(@ß’ü¸ŽÝÒ^Š\à½`KMh#&«NÆMÇk† Ûz6³EÃ‚é Ÿ0^ºh⪾%Ô„õ5îˆ5&ðwúb¬|¡|˜ ³¯(8@«HhÕjÜBúä6”6ð‰ ÙÈÓûП»¥šT׬OhëøCà…ÐJRÕŠöÙkÔ`2ö` þk,ºPÌoôbƒþ‡b ý Pb·Ñ×¹…l‹~aó2ìå`Ž&PPsc9‘Eèt\ úùòõ¥Ò¨ë— ÃÂÛ:W…Z7,’I8<_“… É®cYpޱ‚‘ÁæÊÐ#ÑÎò®,&›–6A¤nÊP/¤¿ÖÒäF…óõ4†Åq¶HÑ3ºïåt!ÿ-šœU(åäáª8§Ÿs‡¸ŒÙdO,FY2êƒéãXeM_À “¬;̹LaÆöG!u¿lš<¢Ã{š½b°­Ç>öž©Ðê^ežrb¾íVŒì¼‡s 7€×w4HE­‘Y¡î³&pÏ h¬ƒ »ñ¨§‡ý`ø…”rc¡’§Ê„<>[ØVº5ðãljó ñ¢ˆøþrì”Slæh¸žxfòú}QyN8¶Û5ÿ0®ªðë¬à+"øƒ…¶Í8c–ž—Z´=HÑ•'µÂÏûè“éš —Œq#²îÔŸVšßœÄçÒuªÁ¿rq½+_ð°‡]î—«‚‚úªÄªÓYE¢Ì¾³ènm]fø¹î¶Bè`^¾ù9”ËbÌʾ}ZKUôI%³³AІTG°É?dTÁűg_iâÎb½OœšêJ•…³—Žh·!•ÅÐÙ,—’àd“íOEŒâÓ=4/øì€ÜxK¤E›É«ÇîB'MÎp÷Rýœ<ÃRVY‚ŸWs1ȪÛbÃJ|‰ˆÚ-–ëmbp‰SèÈ}«ÝKR"xïÔ¬˜e”•âk;OÓ~¨Fm7ûb§¦3Þ®n+ªØ;øúeýCï@ÑQ`·uÅhÈ`ÍÝ53j«1_heþöUè¥-çPñ`…˜¾‹É®1é"6±ÍQlîÔð°`m5ê$´SÆ.ЕÕ\ó.'+oWÀ°pê#ëÍÿ]¤R{ö ö²MÄXœ\Yó\¯VÚh[YÖî`ø»¥AiÐÏØ‡Ûâ..ýס%4½Ò9m{W]ÒÒD"g:nCWºjÏvD\Nr¸ fÁXÇÌg§‘èµc¼¼'—Øê§Þtupí¸XùIý1ÆÛ޵µEÌ ª³.‘ûÙ›ûX„½mV,î$Kl0OM½îÅ(B2ž ¤dâJH3𝵠ƒq{:¬ã~Þux!L/ºÔãÊPê8(ÞÎþé:.©SÓŸô°· ]§“ë­¸5˜p‚°FÅH–O¥'@HÖˆQbk¾D-ý^ïš„Äߦ¸­jÚýà|ÈÚ`à껳éXÝÔ›³yr!Ùâ]¸ìÓ÷ØPgà‚°¥ FÙ«1ã[5šR8ø†(=žäXhÈ;…!DSþ0•¦5Qܤ.ÊV-ëÇ“²å»–1Z$šÁ¿uÁ&±+Î`Güié5“4™Ë{ÖoQ¼«MÏÏàýc$[iZ fþSYý UsÖ%_-"—Í„Úg©+/L»snBdºM‹£a8*üõÚî1ʃ|­ó™®ð§65Z„ÂY 6Ÿ–çõ¼©¹­$ÞóPHß™p €º£ÑsðPàÎâ½k…>˜S”#LÝ{#’Þg*Ç€‡šr…Ìjaõ¥¡fdºx.Sõ°Â`^§eG0¶S’SÞ‡3ÉÏ݆Ñl«~nå?¬÷XOÓ­ "rt}€šBê?vhUKú;4‡Ôº—^8°3'¬u¥—ü«ÑÛÈÌe@ÅZ`Ë?çcÞ ­È̵´ÃP«Ý’lÖlÐ_zˆÁ™ü Žê\\’•Í“´ìL3Á¦þKÄ]+yýA!&UºSt˜Ps(ºÏBD [Ÿ¢˜;`‹ý)•-èÍ]šÖ!\tyðm5¥Ç–½•‰;ÝÖr dæƒEæ¦K[ŸÁO¦ë)i‘…øyîÿÆš©ßÅ¡g§˜ÎèÕA!,ü˜Zò×"‘òüÍ»NÚªL±÷üÌøÖŠ7U±­,DÅ ÖP4‡Êµ‘–aIƒæAkoÉR7½e^ƒP¯òäÿ÷æ ]uUDË?ðžÛÚ,9åQd¦?4H®).Ý÷Õ!vØÙáO…>Y;ìF»ó+Ï“]à‰[Dõšg’~ü[/$uó8Bmt½ÀÐ*ˆÔTRçWÛVrp&jÆÁSL ç¦ðÔ­ßíú…ƒbtiŠš¡öS•´ja/u}~ÚDˆÊéV»ø^!uâÿ›[z8‡ ì´1ÜÔžPA>Ôy4 Ê$éwDV/ù~‡[T,¶{³¶v¢ø9^+L;û4¬ô4b<ÓÈ7Þµ< ÐËYá²:!ZshœX“#fÍ)®O;š¤ÿqM4#v ãfÀGXIeÙ[˜Þ£~9g» Y,»IFlØ8å;[‰!¥3MæX@i¼»~£#ú¯%$–GœôÞ8†*éТë4)¾!¥yvÇôwh]¶óˆ "Úß?âq¦¸Çéf¦ÓÉ›„‰ÊS¡áåRÛ9{cUìó>,] Ɖð¿÷i’rf?«ìxÁm¢ÜÅTËPé¹RÆé1ƒ’C[&’‘ÎL?hê9º¯óg sŠát4¸äÒX”4|³Î粆[-^q´SJ0²Ä²\§ëî/“Æ/G¦.úVÜsv&n.-DÓ§øhÿsõVn…Eמ¯‚l\ΪÄB«ô ËHÇ@ù¤vcÉf´ ³éÃq[1g»{òi&>rZ“yÚ(L¸A(v )Å!lím§Ù³¥§_›š«WnÑ6ù—¸-âr5Ø’T™v2Ñ Ç˜9ÂA¶jõ¼„é:ïv2~éÒ5qHõßµ¬+š1Þ‰f9F¸¼HžÑÑ’<‡g⯓œ­¼'IÎöŸ[Œép¢‚ÑÜÞ$$49fŠúÿÛ©kÀÀÆ7q/U e’N,lè²ÎKrI S=C½Ý€ßXû¥üElÌ«)‚CZÖ¸×9 ÿ£‚Q*lÉÀO>c®û±Õ)f^À­U‘ú ÁŒéHµÔkEBËêú’ì,¢ÉOl>zWã7†PFE¥UhÕis‚Õº ®Sx; •Ûœ²7€sË»†‰m³Ÿ¶~ZLe­0“šnÙêµÊ~;ò×IéÝyÿ½!æÞÅù¦SlØH»&ûÏ3+PùÙ ṙÚ1Xc£ý â…øR„¡ê™Ì ùíoDqrKéx‡?‘þôÖ³)›E‘6ê$¢>QEC1íÀt„ˬ>§Àí›Õ )r'Çšä0+í¢ ï»iQ8bY–‚4:€»09x“ôeãI¦÷.ªàˆ(“ªš§¬…‰¿kdµ¤X-hT²=Pc?œUÓÛI-ˆ@øÒ!Ü0\:‚³Äs³›þ ¤ Ä'IÙ8o üãâÝcX¯g¶RæAðý|Òæã9é ľ1Ú—c}?cL ¬Ÿ_Ãcסӯ t V.ª“ÒÇè¿9úÀLW3`¢D›“+{‹'l¦W ÷KOsÏÅp?"£ñ8תä}¶o ¿Ðó+‚Ü4õ÷áf¹èÿ5¿‰ÏJïNnш‹b ‰ÆÜžÆP“ÿØß6ßwR“ç&m 7§Ž'*ÑA4ö9(2~¿"âȺæ" ZÕ¹6›© h£ÖVƒÛ$åê¢,DÆá?œ²»ÀüÖj”²ë"÷Q¢cÎe‘ð:>aSÖ®ÅÕ] üjR£éÅýf¹µ¼ÍFÐâ=žB±íñçn%sŠÔ€i~Ÿ„vv/zTIÅF&É÷õÛi´ãå.tÒÆg Nµ¯dƒ¾©˜|yÛ¾°önœ÷hàޒ0Ù+á*,[^ñF´½k¦É²Œhô!Oyê6y”‹`>!7àî^i0Ð!õlý`J®³œŠBÐ÷Pkþ©‚>\Øt.'âÏm¶Ïm[T:â*Àðâ€Úi’"-‰ÏùÎ|ä´ìÉÙ¹ÃÂðþkù~Ú³Œo}ƒÍÄ)3$í†À M™£b¨!à(w8a$ ­Ò8^©ˆûšs æi¦°’…ĉû¸±Ë³mDQ·añ£D¡'½Kš5ª— cq_K>|“ðç ¤–•½Ìáa§×öl‡»j戎I[˳R}z®Ÿ- ò@ ïÃ!ÓÃãÜøZ¸÷ýéð¸ÔV¯XÔæ÷ü—{lŽ. ‰´¸è¯ÞîC´Èog–8ùùÌÜš‚ýŠÐΰÃ*çL3 4h ¼1lSI4 :¹Žd Š¡obŒouv°þ(ì$åY0|;#ÅÏ…‡íõT±‡)¿›öúü¥Зi›´í˜,Û2"±°ª¸Þv÷ˆÇ·ÞD£µjï1$ã˜wˆ%A Ná P®”ïÿýÅ_“”Êom,rn\Š>·Ÿï1¥drE›X,Rg/…ûD §ÒÒ›DG%F-£œçͲX§Ì2=h ‰‡Ü‘FLÛBl¶Ù½¯ßrqÙÄYËè¤_9ÂvÛ fâ/x:éjˆG¬ïtš–y]'ßkLx èêô•AšPOЏÓQÅÚ¾ˆ"ˆ+¬,É™£‚A€¯D9]g Úï`ë݇ðafcDÊôrET/ùRÊðÔD>M[A)šÑjqÓ˰½Æ³ƒÒüŠæZÄbbŸ|äYÖFÿ*©¨MÊnË}Јy œ"¯t¸Çfÿ—oo„’²#Í 1"‡Í oº,v·æ²0…vÇ;þ•ˆ9¯XØíŽCz9jŸ•Xtòç7*5ä² rÕÊØñÃhn†úM›d£{ñä4«Nùì³VØ}´hË ]{¤È›— †__j«œ>Vô¡A2³¦mó'õŸ'¹9´kÐ…“Dþ±-L˜ZôaËàÚl&”•ú8—¿C´ðÍ‹S‰Ä¶þ¤ã 2ø=#Øß‡®Ž¸ºnÏõ­dî^}íeóA(ˆ$ñYØß7ð´N :_láÞÁœƒUEó ,•?öø^¯þ•‰¿µ/x ð² lÖ!§x™j¯AÁ….¶ºe¯A|z5ýîIBåWo=©òn1Û¥)­÷ð°^¯ô÷b›þ§æDäå¥fuǼ¯Lbä Ýw®›¹Âü7 Y €ÄN¤ýò¨Ií…kÛ_9Û„Y@Póg70µKÈìLXæGñ=%Ùû+P³^å1¡BvÔø¾Ç=à”ê´!œa.5¹0ôŠ5œ¡µ#<”Ä2ÜÙð‘¶äêÃ]‘äZK–Ç ÎffDN pÈé½f,Ò#?Pæ.¿ßT©"šãÿÂù ÈKnâ• Ð'÷ÇÏE:‘ øX<^KÁÇæ Fýªq@X°…J5ÒÓ Üx®cB»Šz¥%ÊdÛÊék/ `µ†«÷²»E¬7VÈùB :1XrêÿØ-Ã+ îm0 ÑlÆ € µªÓÅv¸¿‹q¬¢IbÅóô- ~dkÊ@_#¥ŒØ€«R,{Zéy2MÐEç?[‚‡«ií¼]ÌIÁ_(Úèw‡¸\ø‹}ö}t¸êŒní8³®Ëséù‰cyM‰˼ F‰Ä®î¬Ã@ÆØßYð­Ýr_üåÈŒSàÊ×r§1 SdTŸ´OF™ïôäŸÙ*¿B|~*tÞ4 ñö6eµâ%nªvbÎw •UëR ÊÒJªâzÔÄ|æú2£/7~Û¡)S·IC· ë¥ÆS@W*§™h tD«2ÐñÏjœ™Œ)„ŽÕ KQ©ÁŽ º‹à$›:C×Õ]5IãVGÃæÔ`ùÙ¾L‡,CÀ¼éóQfÉJ7ø¯›Ô@=Ü«Áoö9š*‚ ‰œé5f·ÞÎî;®Æ£Xø“•¬›‹BWÒ@Š‚%*ÂMªƒA áôЈ5€W¨˜Ím£YSߎÎÍÞÔÀ”Ü~ ©h…B®Ž€h=à„“bN6X×t.¬rbR ]œÍY&¿œV×Hõ¨Õœ׺ Ç䈖ΒÒIGwЀŒ¦ÆW*Q›¡–5æfÀ€J¥®óटeb&Ê|õQ†¿ÊK ‘ ‡P³9ßÒyL*ÉŒ \RÀ¦Ó§ë”Ÿÿav¢-ý¤ÎÄGÑ‚¶ÛNT¥gj^§=[VYÓ€æBkûJ*«ˆ‚dÆ~²ùÜIw^ƒ‡«ÿçAA.Ÿ«8 îæjâ¯Oúë_J‚ˆÂkfÞ–«xZ~ÝP¬û“Ì÷€íåGÄ>5tê™ ³ )=¿¼¨" âÛ ¬«nG`Ù~é—‚ÝûEif•Qƒ§ÎR 9Ãâ%gE[„ëÁýþà÷tŠ™cÏÞEu0èÖM#ªkÜ7‹3õµå³ŠÑ(Ó3ãæ¯y6¡׆â6*EvÊ¥èì®g¡Uê+®‚QÃð ƒV Ÿ\¸­É7ü\– ÄꙂ¢€:ªÙíʰ<9‘ÍGÜ÷ë ÞóÚs ì2t­µ“zŽSH¦9O[„QBf«’† kŸZ’R †'ãèôÍ=ÊÂÈh´æƒ:®Æ“ú4vÊ ¥”ãbƒJ#Òèô XYõÜk‹4ZŒ´F1ùàΗ߷¹j²ϯ±7ã-ØÃH|¯FrÎS;¦ZÃãRæÃ9¸ ÷ðÞ¢•=îž:á“Ë^Ò‡Y~2rêkBK}&tÖ2c7!^Iyc2Éûܧ\XBe.ø×æÅ0ÚhÍÔ©5MJG [œœsÚ)Ð÷´î*Z“DušŸ 0ÀC`¿]ŠîYêBך ŒÏ6•EO°¹ÐÑú¿ˆôyh ³y³@Ç„ÿÓ1v¸´W¦:²'9ÛMbà,Z‘ôBû$’ΪÁæl¦YµÃ£Æ§9ÛHàõ}'¾.pöâšóÒÝÍ)ÉdÒýqƒI è/CDl&Anâå"_“žµñò €Î\4ûyŽBÕ±ëÈ·ÿý…ú±r‡Qòé·§Ï`ìÀlÏû[‰ÌÉsû™µä} ÷`•¼ ‡{‚Ô•Hèï†F¸ž¼?‡@v (Ë(Û­¢€¡kø°gÏh †x,Ý…‡½Éµ¿.zÔ»ïœÑ„8„9ª\t‘½È× /mÆr{>jÝÚáÞ”Œ¨ ‘ÖÈG´;§«8#9𻫇ÐLª€89èÑ=øÊFIÜåþÔýÎ,Z×Ùe¨ü€±bE†‚:ÖÅè‘fÑ>þ\¯^PuDR&ŠÝ?›?0È*\àÄ iU|^F#ëí_í¢¹p` lý#'ÝášL+zÿ¿àÔ(_Ï’ÇÅuëÔ•‰sS£2ámËXyIP¤œæçÝ_Ö8Y0ð³–!-Ò·á>}çŽ «ñåŒì Xä’ëdÚ z¨ö‚nNF5t‹q´ì—VzŸ:•ƒ>±¸+e#CÑÇ`ß> }Y*PuœZI¦u2œ¤«Hc<˜1IAyaý[=9載 mXÿÎ §õe?QìÞätg´þ*æÒDÔ¿[â’bWá‘áK“ï>šözÝ©Ì<ºIX=è÷¯µ­òø)€ª_“!*aÒ÷Õת+‚´ŽP\öÁ%ÌI€MûC?RÇ:áe§VÙ¯©‡v®Òu«Èrn Òq¸ïÔdŠÒO3Ê$öºRX¤˜ç^ð²FSVPHqþEÉ'¯®õ_ˆã¯í44ã ש—ôÀ}ÿBˆ]6þIBt° XŒ‹;ô´/­»eRš/†C©üç Ó 0 »q / !Õƒ#tœ²!Wûè|'1&îNýó•ÔÐ(¶–!‡Þï/KîYüÖX¯‚du.Þã?T­z…GŠ0 c§<³¨JUqaÉ´—À9d…$hæxóE½c¼àž¾ÕÌšHŽÆºâØžŒ÷K£îD爖ökExȼhƒ 5 Þò»#à‚5 ÙˆH\ô4¿ÿf&K¹gÏ{• }&'\.õ¦l_ÙáWNPöWf:uü“צÔnu«Š!Pà:i€  ¤êcêQ©v­@œª`’#ï$gô«¸7°Vl<îwóS¹¨°ˆ»%²W@ÄVªŠ‡†•ŸŸ¼Xw_ê«`ÚZ b*_œôò˜=äï7Ø(∱¿DÃÀ[“̉Úþw° IT‘‡PÍeЉPµ‘û¹»MØñYZÁ"²4,ð]1 ý|ºCúŠöhP`bxh¡cr !ëïö…FØïïLKŒ¿‹é ÔrôveÒ¸ûKLñ˜¦éʑ䤎¢Ns:¿ØçÑф݀† ÚÓþ6›tS‚‰õFó¥¿ÂC…ÍøGï4 Ù+¡ðÑŠ°£— ¥ÑÅ%±–>uŽÑ¢W£ÌÂöãÇÿlÅRYcp¶Ä V#ÔÜZ,`ìî3 Ç»|ŸpŠZ:ˆEå"{µf+Ö׈ã BŽeµ˜÷»ä£ØÙ–CNˆ0ÄøbÙb=Óë‡{É—þ›`c- Oö!þ=û$gµ6k}d¤Ã½%i;ñzŸú•pÂÔñqàóGÙ·I¹KvP° æp7ñ^Øk]N » DhR)vHàÛì(·õpºþ¦4@?¹$º½uÞE\Y›æt·¢P­°ëgXÂi_ï¦÷ŽCûp:ÿP™árÁ²:Ku#RÞùFPÕÅúÔö­9œ*VÝÆ¢‰µÉÆ\ünà{üÌ1P>P|AØûÉ<õæ3‡Q±Œ(éèUMÛìp0Ð3­÷%Ñíõg·qò^ %•¬:ƒQ„¤|Æ\xÙåß_Håf˘‘Í¿fhŸã¿TªÁè›J~r8ó½yø~ù÷†)ʨ ’"¹6é†Gu*O8ƒ<ýŽÔ 2Ýk£Ö¬ÓýeíœOW €˜ ŸëâszEL‘¸mƒe‘œ™¾6ö>šýËÈD¸—ƒocA; î^Ì0³›6 Î©eê¡Áó¸uÁ+ìOVÀ‰ëŸ— :öÒ—· )\yHÖÛ‰©ùêþátå¾_Åûût¥ 9.YÖ 6“8—U¤ÆYûW¡r>¢ K‚g6÷OkžˆóYyýXA÷sãÊ ¸PYü9 l#øÕ?¥ßõù×&Ë™iÆ’Çõm#(5¡UÎOHQLý†;ÕîL¸iƒµÍq¢ó-ZÆú£Á¢C¨0¾Ÿ'JYI¾àFË®Þ×jGäm›ë ^ 垥£rMsñƒ€QÉ Š@¤tY]U£¼laŽ»0Ç)Öó¢5u·®¹tˆ›@¥ÝÅ̧hÎb#»Jv4\6ÔA¼¶AóŸRµ³•bÝ`9½²Ç0‹óÓëOAayFA¡ÝÜBðóÝ÷°W| Ä&ŒX=Ær0&8$ ghÎa”N3h`&#avz¼áOpË(4Ž?Ì—eXÌg‡[uƒÎTký¡¨öÜ ê˜t |ÊÛ÷cü„ê›K/Å™=a„ù°~ÆQæ$ÅòMv-µ~ –¼ËÚ0á'\ÓCpj«Üµ:Ø ÌûNÄÿSN³¡š× urÚQ?0ËÜ;ÈYøÒÑ8²¸ Väñc”륕 ,abòÙê8¨bHÔO'â™[Ê7oD¾[º‰&rbðÖuÍü!#×BœKª R–®Ý%" ó»l…£=†Q‹q(Ó"…kEU»ðÌ„»qÿg£e¢Q3©hTìáhì9-BhKó™œ öCÖÆ•?¥6¸ß”‚J'ŸG º’˜jæ¹T·©r¹‹[5Åìj\š‡|æxPSÿ9b¤¬rJj2ƒçNK_7NòËš<j¢þ–®X µÎŸ™oÛØèàhëé²¢†ˆ\ÓÅnß•*!DÂze¢ã\¡´L*q c—ï¯ïa¿Õª °fç—¿5“ [ÖÕyC/\‚ÿd_§ ¼éW-*ôŒ•yÅS&F&D5è— fIãàÜpø‹ÌæP¤,ʇc ~ æÜ£3äÔuë OkíWÁ­Ù–ޝD˜|0^†qC)kãêSàëÓ²øk¿/§ÁTÚ™èrß›·4ãfÖ¨_Y&uÿžq8Œ~A!“äɬà€ëCc³y‹ÍXتäÆYåeÉå˲ӮÖK¨ž§6^~’UúÇÀꛦüJœª¡t=áñ!gïØ®ÃCŒqOj®Û-`œT ·‡ ÎßšHYÙvÃ/u‰ÜÓœEØW]Àì/9#Rßóˆ4G(™@…N9ôÎHì*JÄ\Û¥Eéª íbËEsFÒK!¡íy·”\m#Wo“6š a­@“yfšÈDÑ ýn!ÀªøºÏD«¡{AÄ-“ ½(ˆJñÿRrö«ÔLÕíÁæWK;°Í"Ó-¯ lu—ÄqérÄìVlƒ¤¬„ ñ]äTaTÉÁ@i¤EhOµó%€î—VÔ0:, Ç›xuúfE>Gÿkx£Þ¯…J»{­‚c0 –Í>sݧÒpɜ较všÀSĪhèþÏnÍŒ€ë¾”?{K§¨}®Mÿwꦀã!ù»MÇê²è|ÚæÁ³néš`éÜ"O–BÁbÖFÈ+?}_½œW¿£N‘K™kgßôæßç¤fÄñ¨³ë+!{®ps…ó8& ¼©ŠáC¦ adNÜÓA÷Ý+¬VP]5rŸoË̦angê>ýUýS‚T`ÒæºðP½­A –¼­p*©ïñ¶Ž¢aá!ö @ËÄ’ Q54 ?ÉÅ| "ˆæË-o“<úò {ÂŒû+S%³-¥sT"QÏÜSœ€O“à†¡ásÝsÉ®ÑeE‰ÚnäC–…33Ó¾ÌUyÚ­çì1ɸ`³J9:òO%L|˜õI Àaÿ&'ØÝó-„:­ÙB™»»OO­"z^êA)Z©×K¤ÏM9KÉyÜî9åNkŒdd t`êMp \üm–·;8‡,ù†á€å Ý:‘ÂGºÎÉ.ˆ³Íú"ÐDìÔ)ÿޱÀ×1•ÉrŸž¬O‰ÆöhœØk·´LnVÂIiï,W†2‚a}©Å,]x]»Ç“7[¾ê÷tFJßáH{&Ú+qÛj¾¾Šýèók Oÿ߸YG]˜Ãÿ@¸EÓ½DôchŸ+ò„pm9w?u(ªWÄ;@#÷én Ö´ó.žf8?Xœ^“ÉQ%°±-Ϙ÷:IþÀŽ/aJ²cêG ãSHç§?¨×]ˆü©Wqä ™[ÏúÃdY~BÔS~´)·¹á^Ü0"ÓÑ×Ò8L ½yGGyK*÷Çп]΃³6”xwV!xÅÛ¶½œú2qzÊó“eW•ÑKµl=\…]>öáTØÌÄq‰ïÌ뙵M‡„j´¿ŒØŒH¯ÇM–lp•a¸m?á)-yïò¹Ä´ÃPhQéO†=ÕXä¹'{à´¥5’ŸfÐëM7Uè×ò%N,3ûŽO?@#,"ê¦+æñlö8á B€FýªN¼2bv›«5Ò1°(€7ÐW–ôWÐf ñ4=§t²Ç$#çZÜÖÏ¢#¨‡#ý“®¯9‡ô’71˜³B’y»Ðds$#ê #ÆZª¸‰i=FJOIBNòè/¸R†©þ¤üͨ,q ngÉG:çƒñr’5´¤…ý4÷kzÙm°ž(\;–Ÿ7%$c/¥¼éR&ºm@u.küdäÀ‡«ëùtÝeÔÊ&ŠTö+^ ›Á QûvµO¢“|=-ÜV±B¹:ŒE7Ø*{¡s€¬†4ì\E˧M¢ï@lƒM;ºˆŠXl?ûgo9­f8I5Šj‘Âÿó5Ò,’ äÇë¦kɆ5=ézÖä?T§?UÐ¥NttÍ/iúÜ­YŸÚ߀b•8†æ:µÐõ†i HËôœôØËŸ••àa”Ós=ÿþß«NK Y•&§ŒŒ˜¡ê¾™op›.ŠyYú…Y@¨D·xû<¦"-2„†•‹EÒ<ˆÅ|U裋½\'cP퇤™å¬ìÝéš¼S”ër¼®×*¬£!5>ÅxIl C×øÊ;»ù<(æúxF :OÎz?TH¼¤y©™¬Æ—X±„]f8ĉÛ9èmz`ÚÞ‰½¤jGßÿÙVo.k«“š|BÞ·r*ëÎüóÀ ¾A}F\Wÿø¥Õ ¾±mb­?F„ LöÚf·v%‚±!xžÎsêÙņˆ0þÈRvºtň›½JO ë…õÒgBò!.R¯Ÿï´EÒ—§RžÎ³üv±tTºD^phöµ~êzÓÇôƒ6äM´„@λ-nu×ìíRï¿Í7ïÂöþÉ]rõq79žÅc«br"Á‡ç×óSÁÈÑCÑÜȽ‘ØÀ1ÆìreØ4øH3[¿m4ƒÌK!ùH{¥b‘×¶f*=šJTbõŽáMÚP$gÔååWgϪ”ËK{ç{ÑP|Ÿb¹Ýý)¶iñÜo5µ_ÙzÍԜ隳AÀ ¢¨’ÀþÔF*È~¿È<œ0²,1(ì­Ñ/Ç¡`×_¿½=bUsïYžÈâxŒU5Èþ£-°ÉgÎ/`Ü àþ±kœ5«”®0a-ïÂ@<›ØšÚ©8n …7–œôS× ûB·SCo†å¢ê׿'Ù¥•…TÅ€|wVÄàV¤ %€kqÐÜèï„/‘fYÆ{Èx‡!ÿbŽñFGûv)Èm#ᨮ,nXÌS\¶\R=)/Lhø$-Ñ3É­ñ3"Vf 2]av«Å’>Ë, }Ài6ܾîÿ J0î72wmÜ{ùb›êÜBUh”¿JþHÅÛD¶¬+UŠH—×!¦\—5Im¿¬´¹˜ýêds™Ùãõ™£›yÑ’~.ºÏ³Llº½$ÿêýœ;k. Ùyáš àúîÌT-‹äÇþ u­(SÔDXÅø¯ç'I(WÌeý-‹KÀLØàž,â$Ëße ±B­µcQ £­¹sÈøT*(jáŠü£À8~3ÊÜF¢_ÝâJAì0Q‘?{ †®&m$%u¼þ¬ú¥ÚFt³£QÒ0ÄÝ•S%*ü ó‹Ý=&ƒÉñ‰ñ:›;˵é#” Íèsƒ@\šSé:™aÒ¯CÉÏ¢¬  µÁu¬MÏ^µ³½ 9·d>Ï%B|\@uÔpl6výš9ή¡_•®µÔû˜$Ö›û‹üEJ>Åú{t¾åÅ«Y0Pôd€Se«1ö«¦-À(¤ÆöŠWÑqÄWˆ‡Ö¥Á×¶xH…­ôï ‡äôª>…Ǧ6(›–3¿ÕD°“Bë„c¤Nr}àë43xev‹þÄÊŠ n•x-X%KÊ¢«ŸäÞ iÝĶrŒ;Æ@ÉhœC¹O ²n$!µë0ãY6×G¿¯w$±õ°Ã°…‘ú•1è0ÑEbØŽyF+°£+¢éâÄ_lY!ëù™MÊí:!ÔRX©QEM´hè:ÂsF ðŸÍÛO¦Êžî·ŵí% ñw™ïÒßíP û¥¾jšƒIÓ *œ6<ÐÁÕ“ mÏt)³éáåIÕ ”ÂØÏó%Ô4ªÌÓ ½“ìmÛ†ã~m¸p‰ dníbw]yØÛï`îÓê?Su6óa=‰×FÊZ[·95Dåo’à×ìå×&8º@BG³×·¿FFb_=ª€3hãp›¤15û¾wr傈†]çMò5ŸÏ§†‹öìÐE8·Îc¦3ÏY»G^ßR«,n»øŠÌ®+«ê_ FÂI¨§y‰Sypª¡ûÑû‚§.ÖåòD¯SÏ­kѵSª×XcÆopî¤ávº~œœë¡ ·ï…N1@ÓïHM/ «eçË’7¢Š“›êoäkg€Z%ücCkµæ¬Fb‰0/ôW5 –©8cÖÝQ*žWkµ0:¹ž’rZ…TÔÁæŽñ]nmwh¯ëÜb1ŠxKãÇÃM‹+gU—À„ã¦66ó·¬{ÕWÑ—5¤ˆuyý [šÊöØYÝ1©!Q%²÷â@=¤~8½Ž¦³ ꈨÑP÷ÃÒ„FuëKé*íO°ê£gå’|ÜÂëìÁÒ OÛ¹ïwû®¼M?X¹vê»ÌT?ö—z´ÂÈçÈŠôÀ<ÿþPt{&Òò˜z3ˆc6vzR’–ý}s‚¼½ž¿ë^?— pÆj²{8¢§F)ñÀï ýõÒ,cÑCW&¢Êo\£PwºÝÂê_¨Ø„ýÿòñL‘ì«Ý u𛍙!=1Cˆëv±måC Žt¦¹|®Tv,<Ï/& \˸_ÍgØ-0ªk6(ŒÕæ¶mA]ˆ¹®Æi“JÒ=Müúo¡¨`kd°BÎwvÝÔ+rcÅPUWª‡PÎÜ“ÍA[ÜÔ½.ÉPh×MTD,OjvSÁm@Š™Ý…g</£ƒ§ŸÑU˜‰íFÕŸ£ +pŸZ‘ù¿ˆy¹¢‘M1ËKø€JaÓ¢m¾§ƒ»ÀRT:]™iÖÖ¯ª{ã-'öOèïÝa¨l|õ¸pªÇØZí¶žz]Ž..\b5“²¦Öµwõ¦jóE²ƒË’:ùVeá‡@}Ó Ì ËF8p“Ae9òÂ㉬œr9r¨…ý@[²¤Æ0Y¶ØH—$œeTC6NGYg8…›uÿœA]]3¹"á&U9Žs³¸žë~ªÛIžË–‘Ú0gùÎ_íArP–Da-TZ]RpPŠr¹#ȉ'—ÞaSa™îÅߘöƒu4ú´FÔø2z1h•|ifTµ•í%•µÑ§Ïv G`âWáÄö¢…1Ð=k $ELSs»å30GS¶@[ó924¥ÿæú“Z% ÂÙke<º‡dy5£´\Ç´•Âd}Âýc_ö'žªVé¶Vj $’ûù‰áæ𦹠Õ=÷KëíÅŒ/ËêñLMØ„\-ûéÇÊhŒ ³“'è Þƒwø‚Kö>hXí\Ï6.ÖUs£Ñ—6Ö*õ\Û€Q)ª }qGt|ƒe}p|­4¼Ø8P“ÁïPøkH”žG7”šÉÿ hG\¹n´ øì–Ï<ô¬õܺò}ª¯_®wQiAšÍ}öëø¬TæJ pkö…úØ‘(Ãá3ŒÍÎH VœýŠ5²Aó8 "ç}äJi}j`_‹íþK*Àó¾r~ïÿúv^­£ê(ï:æÔlcºv‰JséË{XaŒnÆ ¢Òø¯+pÜ&‘¡çŠdRS˜­/»‰É0Ê;G+2ʽ×}h-”–ÚÃyÏöÔKh[ê¥ÚA¾Âj-ëP¨nerD_[h„/`ÓôpJôNÁO%Ò_qézO u’À°ã,ö+LiT#oËž$‘§ÈªXIÄS$uã6SôÉ•tè¾á`ën%ôƒ¶r¼ÖÏfç¸RÉn®²!‹BNpX˜ïht&þyÓ˜x÷8„Þ¢¯ÊRV¸9ÈEïÆ³Ë)²$)ß¿7/Šò•­cfÎÄ}$;¡xÂfžʰàe¿:T2ÿˆs“.ÃÉzvÿ%´|Düþ’¥¡Ø­v ŠÄÚ:Rë¢ÿE>ïã‘ðv˜rƒkvx>чA_AކƟ”Ü­rJ¬3e43‰t¢‘¿ŸyzêÇæÈcÖó„ÿUfÞÂ8AN94¿n”m˜'>ºÙv‡ûº^ÐÆv’*£Äyª/tÆúîã ¬o£þâi0HK*Jàs^dxˆE˜Ø§†L,õª¨ÇÊ©ã“Ãóp!ü’Òcû–¹?}jãøÊOË8ʇ©ë„a‹'~à—`smS?­i“éè8q´Â=”ºÿv à9¼ÑÔ²§«Ó°êë&œôQ<"V|²>_ 7±&ö+d^âyJú¥}gP8¹†Š²Ÿ†£]NLͤ¨¡’È7 CFùºƒró0w+XÿCÕ¢©ät„Ö’—ÚcŽÌ^|Í~KÚjF 1þþnV°pß—}a›FÂ^.Ÿ5;Í×Äž’{Î^rÀ´#­üS[}ÙÁ•Å¥¡N¾ñ?QrlÆm6܉ÙËwjÄ ´ä´'ÉWÕŸ„ÎQ¿MÏ…âé öÿ(«Pt «Ä²• ­þÚ@ãÑì’agV3Õšm~ë²±¸Ézuñ gÝw)ýÉÀa½h,1 J«—|²>ç Ý› È*?ÌGÃKmâ2ó*í«ÀcáôöœÚȵ{Œ×…o4(’šgõ†yp=‚vgõçä˜2ˆ¨±I?— !ˆP9)‘‰D–¿~^ÌÃýò ÃHÅÖ5ÐÙ‰Ïî‡jJÆ;^dÛN4<¹Gt<qW€½À=äuE:ü–C6öØâGã¸uH+£0Ç›œ?\’Ö™VÓqlb²º-´ÇµÁ!Ž;;`ç˜Îû-EжBXö3K]•9§³¹ž ð€Øf¼æ¬›qïšÀê\²Ý÷Ïc¤7»ì•{B9€°ösiªmÑôÊ(Æ?öÊ¥ ˜ª,™Í×›aL´íW±S¸$™@š,ÈÒ¢4ßQBýöçHºõ\y u1 ‹í¡O8\N9V©I8s„½Õ¦ôôÊôò~DeÂO¦tœo,´æ ÚŠ¤šjI×a¤ UVƒF)¯Pµo-݈ñÆé¹|—¬:ñŸÁ5˜“ë{MX^Þ®þ™–×pÔ§§ÂAƒüë¨ÆÓéýŽ2þS@½Ø×öÙÎy>žÇÂm©³ú ßjîñ³Š?êb‚Ä餗S†%Ð6v@ì¿`ùŽƒOQ·ÀßJ¡ž× Ê}ID„ª­ (×—5‡ ‘KVÉÆù“¥øÝ‘¢P×áIúÅeDD¹ÞõW¸ÓÏ@47åy v*q¼mïÔÜ£ªIO¦u±sív¨4;RE'@~¡hWnöBâál®ÔP8LðÞDÕp4Ãîã7ËÑc‰9èù{9Âçô£¾‡ûNF~# WhVªk¢$˜½A[«{Ÿåe$q›‹ú}Ä-¯îX·}gXß·óº@Ü¢áÀ®—€{M·•`ìAò‰å¤Ä–šg|¶´yBñQR×g š¬ØWØïœ]QI[íì”Ú´­úRuÇ~n ÿ TÆŸkzMÕ%þ¸ñWBòŽ‚LSc v~IÁdÝOm>ìzhÿO±ì¹wŒ«î:ok§~Ú9ù…èÓjîÔ™ËØ8«½}ÈÁu¡>v}·§Š´×I3+zeŒd(Zl –½»(ãgN¹÷T–ë|uˆ„[9˜Ç‰KupÆËPÆ@ÇÆB3{©9ßÓ'/¯ÇUýѽB6;J :“~Õþ»“hÄeÅ ¬ô4ñ¢‚SXé­Y«×÷G ºìu¯úr/sÒY‡ß@UË×3W‹ü¤Äº( XÈOñtõiZÊOóöjXN#Hy0Ôp6Üþd§ž%]W­UØ´Ú;ûYâ-æ&“§Š“;€Á\wâGù¯ A°D6̨bÊâ\=¨0vÑ.NÐ2WŠ×fÂ|öª¢¾ò‡~ÕYß?"*gøÀ¸ÖÒFª5€#,-} ²Ä|„ǯ¹`áA9v`šaúžÚ16|jaì zø‚Ú=6òm²ÔSˆ„ ëÅ&ø;ì¶±-¨ô ª|Þű“R*ðÛ…¿ÐÓsPÚÚ% €¦¼ZìO$ õÇ]‚SA‚'³5Ï7UIþéô1¬-â†ïDè)j»ŽŠ£ö‹’ºjnlo‘#0X”_ G!237rÞ„øÂ< ”è£ä†fUÇëþ tŒh4åè„ýh_š®¹Gñ:?9ª0¤åÌ•‰÷«dåXv_s\HtÌQä¿WKžNÎJÓÁÎïXTǦ޳Ÿ›9ÓÊËÛ²dfÓ‰Ú@ÄèŠ RûŒf\k<ë0á¿úµõUcxxà7w³¿tš’ÀäýÅu´0,«dÖwCG JÛ~ÆH@¢H³>oqgoÚÇ—&]Ýo^Qv­"Ðv] ©æêûc€+ñÏ蕪C²9| ?‰–ÌÈÇî r0RæÀà‘ñ©Ÿ¸…çÂïC¦PšàÇm[ U†ŸñÍ¡4i“0t°¥÷,¦JmŽôøÆqAì*Z°›$ÖÖ¢ïÿÎZãXMœž\MCÝ[è?êJÙYÂWC‰Þ‘Ø(ù‘‘'!ëÀakOã”òù‹ +Áø©wüÁ™Ǭ ¡ïx7Ñb¶ËÌK:2Ùa‰tÖ_åCòP$L^tuŸÄú5q h»Y‘ –(š°§AJó¸-A÷z[Ú«~ó“ªbGªàÑf(ÇAmwàFÅŠð,Ý䬌´‹£¸ìðÛø U¯‹žà¾EdK¦_*Mës0)GZäªÁÍâÜ”‡~÷ó ü¾Û^á¾qTæ… Ö0«À;3¯\¡ —3_3"â5§yãùTØ9‡ý¹ª[Ä®ùª$Ò#~Îæ×ãDãøÉÃ3p/%õˆ.VçVÊi¤_)¶Ôs>rÑ]‰¼’˨P0]©º8úð~4_j*?–²yjqõîá’·"ií;Ì_à—\¸ÜLa%ö„3Ó.¾gZóez§&b&®Ø€p8\î¡:v³½ù’tì_X`>:¾¿ÞÒ~Ò©@Šxžº—ÉæÀ¢¢ÂAxö‘~9òOl5™…&RË‹©ÅwgTr¯ìxP˜WµBxyžÆ;“<§êB»àFþ'ÒjiH ôP'#ƒ,}Ò"{èþ2=½­Y|˜9óé¥ö ;j@C?õ#·g¶zµó²]ÑgÛïáª~]×v4b›Ldzì“Ðð\^¡ÝŠí(‹æ®Q¹ÅhõÏJ؃ŒÉÿcDµÑUÊžâý’¦œ;+•­U#ÍØÎ³‘<]oœ°KØ-Œ›*ÀÄ)˜§Hw•$è»_¼E•`ÂèŽdÞƒ§õ_z¤Ì T7ÑYh|@úDœÙ±’°%:·¤º‹,ôSÒNX™k‚ˆUf²çqyî†@^ï- „Kã¹ïuÖP¶FMÁy±ôµÞŠnáŸ>ÃÆ…ïËN³ù'3„Ï”A¾=–Ôwµz+¨ÛHξy}/ú–.`/,<03ŒŒPhÁ&â:(™l_—6´B²Mà²HD~#QÑÓgÙ#¤ÕÐÌ`>¤«~í07¦N”J„nRëЄs2-é´l+ S!¾UˆúHeóÜðÕOuÿèwî»Êä[â‡| æ|@61é’a\dáÙ má–Í(±Ê`7(Ú½ÇKT÷[ûq±nDªûœ¸ÉŠŸ Ðjßtz!•—Rÿº7/ÞSÅ„|y©ÊÙ°jlJÄhÄC-KL‡z/uh½Ëóî1M£ãÂciŒ"3ÊD¼¦ÝÑMÖ2º6”¦F×áîÉhºJ¼G¶Èå㌫ÀCaŸÓýܵÏ<T?æÌ6™Uº5±ƒi2µªsãú,ªb¼/ÖÎüÛ…”kNPй¢ƒ\LiCI’o|v"ú?q¹®‡Z8%óÿÛÇôáVhZLM—7©Â” ï£›A”?—u'#Vb)§GN‘6£w-Íßïv FøòS&„ÞsrQ«ÝÙínÃz¦>¬Ù?6bxr"‡ÜrA,XЉ‚zÃ+KÄPˆ=ój½wžbÊ™XcšúĆY^€¿é—WFÞ•°nÉÎöá|˜˜ËT…ˆ™mÅÆ4ª1ÁeÄ€ºEŒML½djŒ·Járx1ìz4N: ”U_$Ët{xüº(UQl¬ÜÎX¡¡d& Ô(åjô;› †5"ôáEO'õ¥,5|*ǃÔ5J™nz¨´ë¤©è»L,ÁLFMô}sìú½3òAX«r.À­Ž¼™¨1‘¯4?¾<6ªmãß7cJðHH mKûn”gMs)Y­‘Æ.$ŽÂhÝ#$Í!†õö½ÎcEæ0;!­Ro‰®ÌíËu=tÁî›CfCV6`µWŒ>ðÐö Ò!Êf©»ÓÈI$u?}0j–}ïd†Ëé-[[ûß«“* Ý 1/+åtÓËEêDuy7Vg$E–&ÔÉy´IAÜG1…ÔqÇTxWuÖêv»„‚Nþ̦*n„ÊÖ¥IC ($¼š®R‹(±9Öa±XÞ$áî~ƒLéÛºe¾¤N˜Å;”JR Á|ÏôðÂcªé—­CQÐ/¢àÉÝ£4ªlÃOY,´Ê3皆ðyS…ØÁ¥ï\°Å qã,òµ[Ïf`tÓ½yMN™2$8OLûuØz/P_)hq “TeÖCäšüØë zÂk™ËÓá¼$v*dœ<ˆ õ-Bû…#áyV4¡±y,k…N)°üù)ì~×'gëq(¦ðøWKVb`ú Y×5…ó0*m'¶T?sÈ\ßëð™õž¡'«íhò Õ²/TÙU»™Ÿ/CGR&ÏÕiÎUíãŒ/¨‰ú¦tDo›8L“´š…›Rÿ×\Ž ·&&ì&”ì£cþš"rG1ë‰ëû8™€¦ÔˆD…ž XI»ðí-,¡\O½™ED2œœ<®º"‹ »BžïÒ)®¡t«Áø=k­µ§ËÉí]<×Èr™H3ë´B¹=g²¨33^î™ßµ¾Ôµãaø²˜ ¾tcÁ/–GùˆYä~ ྮAø‚vÞ*¼ûŽ41?ÜfäJI †» (^Ö—Ö5ŽÑ‚ÁÑÑ/¢‘ñŽÝ <~-©õV„€Ë «j «sÔ‡…LQ£L_ü[‚¨•™øj$}Ü”ˆ¯+KÀ70_ù~½`ˆH—~tùRï hŸ_8Ø$8šËj§ûëH+|£ÂÃAøbï£UUÜ•Ýȹ³®à¹YÌ5›#˜Vð>ÓJ~pÅDF¾uß1¶B#¯ÉnéyÆëƒ/Ç•¯yòŠz·¯‡~)«ÇœFSÝ "× ÖN+£Û8×9“hJCŠ‘pÑ…¡h±¥ùÔÕ!‹pá”HVš¦D„+úžég:…}$ s‚ÿžbøó-aB[%ð\DÁ- F—krÝÒßP/MF¨)  Lq‹czó£¿ËÈÐÎl…DwœÕ7:”@PÄ„¼¥ÕŽ^2ù“vœ¡—™g⌠ÏÈV|R° Y@¾Í@(¾îI<êzÙ5û¿çª´e –#™dkk”xÝüLèø½)Å$¾Vç>à)ËoÅQB;DÞ@‡-ÿÔFwüß Qò%öytR઱A›¯ó‹_´žÛ"™ŸÆÚ½^`saü0(Qûeç©^›Ë0gêÿÜ'¼z‡ãš?8ê1ÿ÷ÿT‹™Ñèû[HQM—)ö<îy­Å³ÛS(ÍÏDj@JLГϷ%Eù !Ãå&™J¸„[n1ìýÖûÍd§Ä5õV½¸„ŠvFƒõ9怩V›*y * ßr¶XÄ!±cƒ:Ä–Çóö-¿Ýqoüc&ÁB[J“<Ô'¿YÔ gdn~eåc^ݘè3EäVÓáø@ÝÛD>I—Ô_ìæ³„WZ—€ÁÖü܇9S(Ibð‡„¸9 ³â‡±ˆÕG›˜VœË=–Â2ŽåÿxÄ£ò»ûsƒžƒ½±¼Ò ýîâÁ{ŽùhèncqS[é2i±P7»‡ƒRÆÇ %áx½KGÍ4(˜ýv: å ­ü1\¦Â*+7‡Bþ…Pؾ¨Çñ†¦é{þ#ªq¿+ûýUı„Œí”d¦0p¼¤4*74ù}”˜Û_uã§gGýÅy–nq*7ge0uŠ”fX‘q7@¡˜øÌ¯0oŒwófúmì'\A?Àœ¼R‰ÚNrc?*¹iï¨,âÍÖl·Ò~ôMÍ^G þòB““˜,"¾c¾?ˆÆiÂë ;s2EˆY¯üèe qDA"\Cæ]Ïý‹«›bí'É·¤ã¿ñ$¶liœ}åü¿^cö-²^mýïKç«70¯s@Y‰ Õ–Å·àRZžQ¯W©œ4y–Òb§Í+¡SŠˆ[€@ÂçÁIç$7û´‰äÐÁº~4ðUhn1õ’ÝâØºÊ&³pLùãߊ7Îꌇ)|¡Èb˜¢…­l‰‹<•i¬oA¶›˜÷](ƒ“3ÐYát895 æúcMÁâp\{Ç,²u¨jIZB¯·ÌF&˜Ò8ç™ Ðéàf3Ù-ñ­”&a˜¼àP4Ðÿ¨Ž[Ñܸ¤˜ì@e5Úp›žNU‡šîþJ³|ߨt*¤´Èå lGú¨/)±{)Ö&ÅÓ^>‹Ñ}Ôôãmm\vªJ}Ýí)ÌqêJ0ØxÌO0*<ö´µºä©¿'À °Á)’—ªéÀ4*ýÄÀÇÌ⃹&¤ÀT·dÀfêÿg.5ñžÉÉtß|X×úmOha©T;Nït˜E=fô¯ì÷; …0ÇÊjSœHÔc¾lVú`Aá&´[äžJ)µà7¾ŽÕÔ0óÂ,põlgaššøoO53†×8¼IXב¡}>¢ ¨SÚÁ*´­F´FÞõU»ªÚ¦ï„¡iU H­æ7ËfAâ_Ìkf¯™ýW5¸êQqy‰N°u"åAu´¢Ý;ÒIDi Ô>•pU,üFFðsfJï6‰˜W„¾IÞ·[ÀµÊ¡YÿNv¾¤8G=϶¥9‘@Ô)£]°hÈbñö¨e¸¤.Æ~õ´½‘•úÇ ²d%ß3Xd5ò”RõfY;ôå–¨-!BO1!ÿ‘9¬OJ©MFM{I.¹!O‹…?´Z¤”¶û^¼ uJÑQ¯l$P—!{>Jáôs›ÿŠÀí`ÜAé ä¿ #¹P¤xíKnwƒ”É!ÂÁìr)Ö±˜$k˜(ÆÑÜ]"l¥©ŒÁAPV–hþCÈ ,Ø$²‚kˆdøÛ#Ihy hä'™xƒã{#ó”úÆn5ñ¢ œBK¾=v–<ÐF­ mFÈÍFµåšÏ¾= ­4øã8ìQ}KµŠ‰ÀÍFŽsYAsº5Ukw‚àýã(ëajìM˜Ø#‡i=wy>cÒ™ìDZA¸’X—v¨Ó&ìðñ3ŒbÑûFjT²ø2'ºôux·û¥â$ýa Wš¿MÁijt ACöþÚHv#üÆó¡›TAsŽ`ÒÒem©=û­[R²‡Ü¡L›%¿èòäB:¢^ñR9Ž˜Q§‰e¶k¹š­-–ÞÆÈ?†ÒvüÒqÇk{—ë†Ú„:/£®+U\=Ü?*€9 DJîUò˜«­|§’;ûC‰²µ±“;Ç3-¥¤2C$¾E¬ÈÉŒxZ–/ "h¡ îb!‰T^Ÿ ¹”‡hk5>Xåc³–L^ÅjP¾¬g;’< lxp,@ªªʶÏé#-b¿Ô» Z¿¹5X'ýþüÖjDèb„¤I-¡ªƒ«óvS®éêym# )øø$ñ“Y†•×ÂBº&W#µâQ¾› I|)?À‚°uÿÓcßpqÓ.ÞBóÑCY;û–šÿµuÑ¢“ÔÞƒM¨€®|sç‚óã—IûÙ¾|CN³Û‚«­Bƒ^Œÿ'cÿ‘â? ‚S_Jƈ”{(”ªíH e²¡ÜÊ‹‰›¶£¤§QswKB™~œõÓå%·F¼÷2PH‹Ch,#—ká•„rE€rùadóxÐÈéRì‡ÏºÊozŒ ßëYd‰ÌŠí¢5ñÄ “ùo­1à­ª_“uQ· “‡p8)Eg0ÑÁ€äè©Ã…4ן#ÏxÖ-ß^‚ÖÖæb³oÇ"©ôû‚­+øêbuáÄûw·•ýéd^ü¼C¯:¢‚¢®~š½0ßuDú iUÏFWþŠ, š÷§k NÒ3é©ä 9åÁú¹ÐFHƒ«¯K]í ‰ë-ˆ¢0Ñ“u°\9™·×>#Gs+5³Xiþ>ý8ôɵäÎBcsº¥}kûu&ƒç„3¶â”õѦ‚"Mš5L, ¨À´[RY>¤ô§^ž2À}È5c®-Ù¥8Y¬€‹Wp:&ò©I•ù›f…jè˜ PŽølžËÂ`Ì:x/xõðç¦YÀ†s ë¾¥‰¥>rj‰9î#~ eHÚ[Q›àLöÛÚÍÄÄ~(±3+ˆ°ˬD{çÙgàª!]·im<ó6=p´[«á%¦°Ùä¬ ïü£Æ£ÅòpâúöÓjPÿÁÏ5MÛTIýîë9íø_ÝÄÿKhز0AǸ½Ìót0ož¼eY§1Eä|~s~èÑ7Iw66úÕ)ý·lÉë’»!!˜¿·½:N@¸²š:À:Óu°d¢ñBåŒ&( ƒ¨: 2ÌPŸ¦GÄss‰ÛaÓ~ú¬kVô¬Df)dç›gì`VÞÞærð!—€†¨¤½—±“î©]¸BWÔÝ{<-O»¤¢ú¢€´¯’‰¨!”¹$Iã÷ ÌáÙ‚ÿg(·,5üÖù‰¬3=(\ !%Œ¥Qz»Ó(‹?q_‡¥½ y·Q5ɦԡ]¯‹¸·s´ÆÙ üt®<¢=I~f u¢TæÂîðéÂU8û°ìàêúÎß~\説?dÓ†›H³áîgUUtEíï§?_ø>ÃL‘F‹Š¸Kdœç ›#†.ŸÆZ‚D®R¯á>^ˆ‹'}dT=^ñx¥s×Î9Á<²qDÕ[híÍg.u~O€uŒ:]Ìh–àÚä\ÅŹ}6­¾Dj” 'ª’ÆÃ”uäa¶Çý|Ze)ˆgÔ‘:H¢›ö¬±{ ”'2îçq‚Û¡·øÞt:xdc#Ѭlýª£º È_é¹Ü¿h½!Åo?ùÛBhÉÑìsyR`ïN j†¹›Î6Ñj‰ËÌ=)ÁÍØcºÎ³LH1~, íÖί¼èìnr¤>rœ©9a\ñ–½O¥øÀe;έV.gãtçô1p™äTƒ¡Ÿ‘ÍPekmY D^ˆ>U"²±±sȎ׀–@eê‘ ›ýv«† ¸u÷àzˆqåÝñ0 »L×pâÓ‚yO9ξà®Eê©+±TP•¿;NyÔ¢JÓm©NúW\°ÊOFÊg‘ °ÊüÈÑkg¥>#!SŸþ¨š³¡ÒAá_íÒl]ÜÀJž­,:—èÛ[ÜDåµNɦJeÙ{îÔ7•ÔëR¸æ˜@{DŹ™¼ŠZ2¯…%ÓdB¼óÇ[[ eŠ–~9Ê1t¨âDñ(otÝR))¸ó9 b"tÿrö[ay?~Ζ‚ó’13€$z÷…ªlõ^ÖXÒÌAë)é8ÍO1rˆê칕št½(=“Ù¶+àÛ;À ê10Th\„M\%’„3 Pc(š&*¢¼¹k ¥¬zÂmŸ¢ ÞÐè'8ÿFÑ¡9h‚èæp¸ÜBMêB…!Ð~¨ÄNæ Ôr¼{GÈ™¥>åÒŒE¶fyw¦‡ƒ@-§ÆV“«ç?Tªˆ·:-,·ß"k/†äjµP ¶ã~„VäqŒ~ÄæZ26â>”ƒ‘}¸)%̵w‡ Œ•@¡d¡ÿÛeQ–-Å™†óÙ­ùJÄv‹öNí}Çß'cH{QW(9+Ü:ÏLj½¨×8Xiýš‡Ezí‘ÂÃJMcéÉÌò3­ä¶Ëýú° âÆ o‚ Ó8¬q.V;­òŸ< „ó’’t%9ßç3ÞÏ`í‚MC®T3 5'þ™w'nMƒùwnP+Š?Íû[þÖ"Õ#pÙõLJ7K{ò`€•œ }º” —,b©¡ ‰‘ ȃÊqP-Pûˆ*©Ë;†“Nl31SÚ±ŸíGŸ`¤¾•0ÀÌXb¼Àj\×ð›ŽT‘ÇäFŽÝã2Ãi‹á±ŽzJE~âTwäÃ-2÷­/`*~²€’ãÁTF 2«>¡˜ƒ5¤¸•öÇV5û56C…uåqµõ¼“¡œ×Ýê"k-ù¦Q© ¶Ò¤ÕsL>~ÿ=¦2MEM[c MGEâcë5°¾Þ‘ØÌl%9ÀÏ_­µÊû!5çDÓ'ð¤ÏrÓ;WYÐiªíðhCé)¾}ÎÛ|œªò7Ùq-fIÜT)¼†O¿˜©ÁPÖ goqÇâL/òϘbSØ|¸ZünÁˆÐXÿ™É‰¥éðŒN$Ô„$1înC1ñSξø¨®NOP8†,£Ä…¹dwÕPÓ 纳3|Âf¬B+´kk•,œÍ– ž·GË •£ô\7ott2Çž*è¾8ÜäÕÏbõµA¶”3öÅÂ娦=[ÁBÄ·¸kRx¢kÏËç«5V6â²aaò\É"kve> N Ⱥв‹ –µ7ÿwöyä)ÔÎ:ñMWmüooò®G«Ó$ªÛË[Z!›fi"Üð"Œ}¥Ç5†¯‚zI‹_´žÛ"™ŸÆö­‰>g  )kÚž½×E[ ôK~éy›ÞÛ9yo f–Ä'¥·g“¥y¢ûk=P Á"PÚ„Ð>¨e|±üŠ ¡"½}«®_ô³5èÔyÆŽÝkÆsƒ ¼ÞTô±3¥ˆ¨ô*ñ¬”« fË_ž;ŠŸg7}?ØõÛV€3°VƒþxçÌ1'¦ôXÙ,ùtZa[ìŒO¤§ÉŠÚä%¿ï•PLÄÒJìÎÏͬÊ' óÜøjÞ(½Ø§–™\ÜÙ”‹wžò¢¹Ï*^Ãà|­ 5÷¯ iGÎZ­€Ê 0D™Qê!/ILÊ?9|c€Wñ¾È-?;®â¥áS ¸Ø“¥þ¤$µ<Í1m’íXØÂ›¥×¿\9’ zqå÷ï­Ì÷dóæâ°–ó&{ý{±yÂÞ‡£ÚÆ´aZÉÖ*…²]|äüxõÖÍÖép(§û3’Pz¸àfb½‘ ž·•¤ÔËDð³^ù~.ãÈo¾(˜ÔâÈ{\sö1têÜ ã9›Ï]Ä¡È>ÍEÝ8ðS’DÎvYTŒ Ž0I„«j¾?\Ôi7Ú¦çÃŽ\è†|÷ò4$ɪ’ö¼ rÊgA 9ãFÒY>ˆ bïî&·a#Ñêt#þatÓ—-„e¬¨Æ]d¡ü»R­Ò1"à ïT3e|“ü*8„a`7(ß%F–£½ÖÛšâóð­kc]l">ìÝðWò³´F‡¬cLäçäù´†oaÕ£\nÍ—á ÌYœ”Åîk‹Áß¹à BX:–¼*.6QÅ^™ Ñ\þj&.2µ²^ %«NAk|ý²Ž<ÅT»iNí»JB4fI뎨&›ò£7رÝJ6É€gb¹}T¶2îD²¸ÚÔE«“‚ùu_A½ WŸû:ðŸHؘ\†Š*–yžîÑ$Ÿ}Û,5Ý ãµ^ªÜ‡ÁÉsûˆ?7™|þ¾“u†ì'ÃDZŠyN&AlïíÑÍ—xÿqÓPr?öH$yÈlê2ü )Nštm”‘S¥dĦß"טºÞEVr<•ÉÇ}îXJ<šxøš"דªZ£Å-­àhç¦)õ_!ÔçQü›€§Y›åoLžvø°ZþÃÿàX*ÿ›ÝP0þ¦œžÈûÓðb ŸÞ_ÕFÜ`Xº6óÕö8ãÑçÿpü…‘E—«©ö¬±~ÌI¥‡E£}§«XHNÞÂ@šû_Hën=n=)x‰˜n¯ßùä?:xÆØYçgƒ®Æ|3EVj\€:¤§®,ûºÑ`32}Us­4²Ù'V\áÊú™ûR­ª©s„÷­Ò×I&”ÌðäZÇÉ †Â©jÓ­™“]?cÿK>W™üž†`iùOæ±Ç̨{9»Âá÷4@e¨LX0òX3ÎÊV»ÏÎ’Ø=®ÿÝAuìVtí^~Ô &Ž›cJåK‰IÀíB’°ßN6ªL2Ô['«59!ë.Gà»Ì¸r±C Q¿0„Äѽ …jÝ“ÔÅô•äh‰Uç›—¡>8LÄo¾Î¢´—ü„©²hDC4ï9G-/E ^«KkQWU³îAa‘؉¿yãHSù­›¸Ül‹tí´ Ê:|Ÿž^t`—ì˜x¥¶–eIéˆZ"ÿ:Â϶é Í{YIÃ]©5yØý^z ")Mž©Sɉ¤x˜á3³Ù’üm@§_ÄzszŠÐý­ŒnóÃIË@gØ|±Û½æZ áú/nÚàäªl]~o×BðÙc¶¯?²õõ®lˆ´Ä·žâeoO½–èa¤ âöeT^„‡Cï:…(tLUÖžOYúÕXÍSÜN%äQÒ‘YCñì‡ÅGn‰Âl9Ù„M`í ºò”Ê`~•5¼|dŠäB¹R#4ŸÑûF}9d%ÿ¥©¦bªá7®ÿ,ÐŽ©¿¯4ù¬5-¡Âêaã}0{uzgÿUCkæ4,ü Î …ÏäI¿äS‰ZHé¬öL Ìž¹ñ£5ø& ]â­‰PÿÎ{æ ’ûÊÇK K™j7Jô¬_~ÈøC­O…Ùà¾Ã‘Yí àUÖ¨ `‘$$ºóæÆeœy`˜ŠÐ˜73ó+¦Œ!?8Ò&o±l“^ðÂ¥ÙàýÛƒyÕa²!Š¡… }Ÿ§t–u‰7a%^ć ¸mŒf3(ƒ¾ µ<ÕÕØ¨5¤çJBÞ(ÈjÅ *¶·ZJf3ö§È¸>úŠ®þrJ3;mT,ÇLN0a)?‹ J»{#Õæj¹? 5€ÅÛϧ‘§ã*I?Áßæ[ èï¶zág» TèëŸ^³¬yn¢‹Ð§ñºîÊåÔýÖÏG,»:þ§EÓ\JW®‰–Ô—yѵ+©?›&®Ý*tg~6yˆEµ,žÑï{àÛ%½à‘Xë#‘uzR\ç «Gu¾Ó?ò£uþÏ_x²ŠA"ìê!N>J1¢º[7lúÛÁ«q»¡V½Õ­ÐEY 6¢i*!ŽÝWX_7twWÒNC³ËrðÐ)ˆµp÷ö3Ôƒ#Ÿ›×öh;õQÌ÷Zh†Ia"¡kúpÜ€¼üâÑ‚d@²zÅón£f'§¨ÕgÓ}¥•QT³8BÀò¬D5Ó{I¬þõÞݽÆã}+›v=š7ýÖùþàŒù¢X¦ÍØ+ˆ6SÓջ†­þÓé¡ÏÐÏrú¨j<+ }ÑŸ3 k´š’¦A£Óá›)lȸÇj$浚ýg&Aï\v Æ C"U ¹qNœ‹œd 0g†$¶QÏà‹.…ž» G;>x”ƒÆÖn=ìê.§9ý\·ÁÅ•IÏ„Ç<Ÿ/6 ˜}¶’Lh?á>3’~I·æýÿ…G8œás™$ÔŽþit@Ȭö$]4™–?ûžWÕ‘‚Û†bóhÔú.@·]DHØxs ™²æD§æ(âÙç£ç×v¸y3¡.¹·‰¨FG…Gä<®šZ’¯r‡X\¸Uí”/èý¢8_ ZMZU±øDSE‹|÷œnÿ&ÿê8*¸Â™Ãê½>̽îRo¶ItÀ÷;`T¿Â9†ù³È§K„šs1ŒÅ1røá$yÐ!V†IˆÂÖŠ’…Wó WËëÇiW2®ÊL߈rßAº—‡³‘xr?I½ãŠrI–ª¹»’uUÄ—ªôZв:6<«MààÄ¡m[ÄÀk­‚ß~G¼v/\œA¼É.t£Æ€àÆI ýxpdÖùtE?±£QlÝ…H ü õèÞT7Íarfz^6¸g©ð²jÁ]„"aÛPþ>W†rù·rQ•—.¶¿ÌV2A4Ëô'ªžkábÓF# w³àÕfÑeC” nOÅ·Œ¦>}ŠQ˜&áöÃÒu,üð':Zk÷x®. ìjæÞž×ÜçX‘vvÖ§oÅTGé¥6)­f`LÚñMæõ2†âßÝ“ù^vÞÌuÕ„+Û‹C¥ŸÏóÕïÓó;ýRFeS²hÈ=VbâÚ=ô{Ü%Ø|ûÍ}7[0+ÞÇwÆ }ZÕGD¦rÄÍ–[r^åbÒ™®.˜i™wÙ¡ícákVM@û^ÀÆÎ§ÖûÞEœ—Ñu io³w[íuåæÊªCëèå=4L×äÿ†÷œÔ[’Ïíèá=&ôsoú…É-éú!(d£eÌUÞšZUu^oƒÓ+¤G·/Ù\Ï[/ØZ.–µþ…ݬôœz*ñ̑ͨhÂí£Áʃ›ÁœÛÚ¶¤,N7Ï6"eÅ—xÐôÝÈF@fõ.ëø Lí×BH”ã^B<"rÕ„ŸØ÷¹…kÌf‚]ìôµ§»™Œ4-ëͤð¬áRcù݇HŠé}j´¤<¥’£áCa)‚¢Q!¦ä”ðµÍЕWwÌÒÉgoóÊ !N†q¢çVoUührªdïG6I`ôroÞªõ‰Ï¯³Ù!:»H >vÆ7´€ªÜ=TfÖð…öÿ 6>|…ð~¢æì£(í¬(“epEùOÀí*ž˜×èì'g÷¸vÂ,×nF’Þ‹Ç|»ÁXŒpîÚ9ázž †cÏŸµ@ö1ÇÒe³>%ªñµWÈá^è¿"ä[GÛBð¨ñ–nŸÈ«’õ@~òœ«/~(Cè1SímíW•Ç퇧…ZNòúå!ñ¾\|%(òãâ*&[l"ù˽1Åcê´¶XLu×¹v«]Bº·ÉPÊÿYì¸ÊÝÂg:c%Çwá«=Ëi›:Œ uM Ï÷R,7ù0³î=úÕIñH²ü`ô/±Ã.n_¬jÖ}!¾üS³ÀÀ8¢îí¡pi5HçËÌí8;¹`å\Yòƒìásù[Dö»ãü[(ˆ˜lž·Ñœ­ZbZ¦síÑR›ŠÏü–Öê–€ëßþÆ$¶ê‚‡Ú´9;@ÐÚ¬‰¾"l`ì#Æ‘Áb æ6Ít¥PZ?½,qPŸ6·®Ûøx4{ÿ6ùÌi*£2ÊZñµUïûeµ4a´À—º½,åó‰¾úû ›öÈþÓŒ¦pè†À]7Á-AX¦‰Øö¨¸!Ò—Xx;Ëå| /¢Ág¶úêh¨è~á˜$VOûÙAü^¯k$ÿéÀ}›–ñü$°Œo}rø¦ïÚâÓ›ÙjGwV‘~´:¦ œþ1¢'ñ;Z$”Î}ÊŸ_c¿ÚSöKØígû‹|£U’cgX}–íE“HR!OòšB;»€Ò$ÞËíHÝ¥*Ùª„Ø›¨ÆŒb)¤õÔÛöo펉¿iˆâí?NŸÒÇ?uNÍÁí/tR®é.`͸Ÿ·fg¯ |š»ù¤ÚÀCñ@Þön´H’ÍhÖÅhvi÷T¥8zù»õ,ÐbÔ:D:ïÕå¥èܲóδÓê˧vÄ’c§J9Õ‡(ñ9ñ؟lj¾[’Ò/DpÕ¼ü¿ã€ypµívKu“V©È£Â‰ñû[{uôV DT(aš©y«¡L†Î‡s/˸RÜ’ê Ví"ÇmT< Å"÷ü¶X2¸„[ªûªs ë]1ú¿›J;ç‚RJÕ0­W­¶1‰Â€Ë·uÖCŸÏÜË\þ$íöó¬5¢X¼1oá/î†R)äÛw ÿ0–îŽç_ºí³^ ;˜¾ƒÿÎa<–N¬`~‘m®ûXTžþ㔩Ü#_ŵºCtƒÉÖz)´øô*ÝŽZP/Þ¬F™‚¤#˜ðíËú®ù¢KÁPÞF*MvÄë†I»2q8k‘Ö¡SÊÎ%Ö™†yJxRº6x(ÚÐ'ª'D¯slðå+*þŽ{kFiª÷ËT)qß ü,c[Ò‰îß_§cØëú"¬‘½Ô}]ËúþDp¸^4ï6;«¡ÄaÍŽ^’Än¦[¦ ‘¥ƒÝÄŒZ¼3ǃ–ÆØê‘“e A´6,ƒ._18:ûx+ä«/·Z+ò3ÎÔ!ßùÔA½¢22ÖµE-Ýê꿼q¨Ø "¸î±–7«ÖÁÙ$låÇœñ_TÅ…ú’c´–°ßçÖ¿!ÖI HÕ›íL–T>Ï„*}‡g dÏ‚dáWà޾РŠJM€UŸ­áêݶ²ö+¦’çƒw£EÈ\߯ÁÒù˜A v·CTå÷Ñ.Ÿö\*C¡šÁIá0ˆ3µ¶ÛÔ¹v&²û;³'ìA9wêD'ôzI 8`‰ŒÂÍWÁ?küŸq\'j…ý?Hm&6›-+â¿gˆnpžÑŒk¬Ùwl\d“äÚÙ7,¹êÇ1ÄG }7!?#¢?‚·™Ð÷xÌ×ÊxcBñä9Ú“ô˜g/¾½Ê5Ö¡¹›#Ýtv¡!à:Ïü¬0æØ¥=­5O4ÐÃ\dPL¥« 95°*€ZG{ì’´ÀéT€¾óãpì¯ê"¢D<}êþÛ²€×9̶mä~$¦´G9Óüña™zã ãJÁÂsf,å_yÊLr [ n’³ÙwÝ:Þcè_‚ª¤E«ak‚»IÓ u¾¶"Yv¿¿«–ÉrN0ì«6Ñf ±Æÿ V6°ñj¬JhOîÚè/7ø:/}sqºeÿ·Ø¹ê‘b¯Øò8ß‹²QD1OAŠ¢‹ð›?Òç&fÎ.…ÅI>‡râCg:öb²LþE$òv}|w3-¹›Ð¯ªN·Ç¸Ðàóÿî²qZ†®ãâÝÍ“µOýe¥öÇÉKº’«¯Kí/-q#InÝç>DÜ™{Ç/=…& ò¡bYÕdúßÉ?Ýf¨‡eTÀèöï»FKf”`-ÿƒÀ´w_™ž·–ðAéÍ)4P$oW¯(Ã6ô Êsa1êz—€ @*á߯~ÎoëÕ;}¥ÊT„©ãNÿÖ&Wõ êvw:œçJÔøùî1‹Ðô‘Ú,ì}RžA ÷ð6!w¥?3èÐ}¢¥d¯g7+ì´æ«å!ÒŒ AE²ÛÛÀ»Sd‰qXH‘GèHÛmSÞ¡v8U‚áKœïÙ[úû¦!‚GÃÊÍ™¡S´ótpœ»7 ¶Sk l&ót ù3W[« Ìé Wˆ~¤¬^"öEJkÜL£„#ßb,¸þÚo· ©5¢{Ž_®»Þ…`¥Ì.’.åd¬ŸoÊn$§s «“$ß÷ß3ʉ)<óî{s™L’Á—$\ãx¼âÂÏ0úQB¹™(WS¶ú€šMsBû*hƒö÷òÒãý(’šfEü/ÍL©˜„øKþ]úe×vxâÂ¥ôs † °a‘Gs]×·×gü>YÞîµC¾ä]µå y± ¶}`Q²ˆ>ã1<#Í|ž}63,û©Ø Nk©†_½=ì '§¤%¬/©qç›'•@àÙ,+FÁžœï|žÔz[lRXSåÄñï,üš¯Y£Dë¬/)‘!tÑIDšÛWs‰‡ö`{.4-A³)ŽÅâ|,W±lª)Ø ïp?åý~R‰˜aŽih¥lά§ÕÒ ¹±y]ƒs&8VUëdÇ­ÃÙ.©Ö€m ” X–nuØn× –B(Õï$ÆÏÝÓ'`ûZê£Ê0½ýV[€ý‚Ìî´ZZ¥§Ø=O²½Á©{Ü7ê+Â]T.¢3†ÑÄnáÙzâéõï ­Hs“{Mˆ³¡A! ]Ûß‘ g±ñšµ›9Ÿù³ô-ÁëÕ¹N{žáPC]X˜ƒØ:È (Ÿ)X“˜²B0wËE«~Öžgá’mÿ©<'ÝUÒ.v‘®òä>…þ…¦O©;¬í$9VõF“<(2µEnÉ„!ž YÓ^B´™ v—j©Õ´zå‡î"]%lŸD8õ…LæP©ïOýfa¡ƒN&ùYÊðo‹¨)zè¼ÌØÙ•&£Û­Â:vȲÔR6úŸˆC ÞN¹o†i\ɼ®6V8ÕÆs—x©ñÉ]œÇ^Õ‹»éxí–‚,GO ø¥!ùìfí¤^™ð¢&.C8@pØÌ7jE]"ºƒBX2ô,ìñ‡÷q+lå-\Bí-tD¥‡ÿGCf@ SAJx–QÀüRú³I{üJZŒ¸…Tž3ZíÖRaJ<À»’=¥rö7ΖÍX®¤î²66wRÌVú((QAû<ó”$ H…MŽÌä˜Ç¯1¹Î|…]Ï“Hueê‘vyo;.þê0 9Ý0|[ §T0HÙ¿ªMúÖ.éé‡(sñÝßu•ÕÝÐ*:Ë$”ߺbçÀê0Nx̯UO–ÄcÆRS´‡é[ A×(Ðü”àÌÈfñx¶Á]0¾í‚ãs÷?ð»l½0}×Ì¥@oËTØz×ú¼mº*q0“F ² F9•ÈÏ’’*-_ÊæÂˆØÇ|g+íUgƒ’¤õ^øÕ ìÚÕêPH¦AİaϵxívØ›œÝ ®öÅœ‹›¦ Ùî- Gão“W»8L7ǃYòÐÛº ºrÈi‡©ÈŽ­¶º’5è }‚°|0O´Ÿ"-ÿ𻌛ÎzÖäõë°RÁôO®¹ˆ%\PáÜ–îÿòv”r€èòÈ-Ëjÿ/à¦9甞Ÿ¡wV>îî|G/![åF%ÅŽC$Õ_JW{GóBÑ KÚ6!U¹¥+m›/Q ÔÉxÉJüs$å½í°·Ø·OP# B}e6’f…ð7±Ø±åt?Êw,‰{uñç„è±ÉaoÔÁL#Ùô8ZáðLÎYþ¢ ë;_ÕØ˜ ¦d ÷ÞÒq0·`“×K|wð†XŽ4ÑZP%¢ï—4áû^  ŠQR?{Ø,ý®™§ È¢D•ÇײÔs#n¤»Á4, »jŸvu]M5èÕñ¦_+\|gߟöŠb$¯Á¬ ?èÑAJ¿D%”ÎÃ? ”‹bEzÀv Ñ3}“V´‹øó­U µÙí’ ®¸·5Â'r‰€Øtnr:8ü·û¦:ÄEºgþÅ/XßÎ-ZGé`ìGX;0Å–êÄ¢ž }aÙA¸çÝ„RK@èd¼˜Aë…«ÁA›Ìœ?ødÔ¦üuF78™²ý‡rãø‰ß¨™Q™s“ß}DµNÒCc4.£<ùî;—Søhm8™ýåö°„€3ÚßNfAægNY © "ÿÝKZî;ùº·Qy?2–mA¤”؇³íÎYè÷e²Ç&¬-ã!;s*ÌrÑ®œö‘.¸h'º [a¶®Vb>œdKðåÈíý½ª8;éVeÆZŠP:‡ ÈäcHO¤¼§úÁÂëy„ÒöiGslá=†yЀÖvIK µôgÊ ‘,F]É¥µr EÞûWœ°“Æ*†‘»@’ȸÍ<½¬K¯ºª¼Æ™J^'«‘W»Æ‰”ŸÔnm(Dp„å,ׇÀÖJ„-=ášîRþ>rÐqÝ# ‹á-Ä€£$f™¦ãŽ7$âQ¹Ê×+çŒüäéí²€Ò @Ž1u—ËWtáµ! ð2^bŽö'VAøé‚?õ§Wx±~¬¹QÊ~&½Á^5†1 Ú C,éaÕïGNfU;²JVXÙ–Iïu „½Í,Ki­ùß‘Æ ;W¿ú†íÌy;Û`J¨ êÚoŽ:ÒÒGÐÆYFŒ˜3®ºV:]2•!MÓ9+ÚTÕlûhÍPAT…(æhMœ¡j""i&º¨¨Y4Ž e¢ÿíÙû^'°ç:¼+èéŒR,²Ví2bhñ }³L˜~ä·#ñ%çR¯äÊøîPáˆ<ž;ýЈËÄYoº$¨CÞx{زëèÑ •‘_±&Qe‹ŒFƒü¿&1"Щõ§×+CMEÛUh^Hª²JX/·jÅèGLÓû8Ÿr*”­Ø¤LVž}×Îaµižy$P)*‚éUf©ö)AD~‚r ?$_B}|ò±©/ÙDý(kŽõã:N»E`wo}iõ”Eñ»Û»ü(5ØÖ1ñN^Ã$ • KP>TM?;¾‘ MGÙŒŽ.%›óÝ™÷$é¼~•‚c¨zj@†þ€KIJäj¾Ñ–žS0FÓfìÐvŸfýª¼wøÎâÞ3…ÓœèøzxKë)Mgó*혜±¦ wG¶³f<Ašôq-im•íŸÜlK4 fõ&ävdAö'´ŸQS‹0Ã2Í ^ñÊ1Ãi•vŠÐ?ûLª"nØÞľ±K©cØNè´¥à†÷Û©’ˆJµëåÍŒ:ª$AšÍ«]ñy^‹5k¨î×2R¸“µÊqû©ž\’_Ù¤>Tì_"‹½ù'›û*^ŸíåYÎLGMô,Yâæúí÷a‚#sbÊÅÍ@ª…ØQÖ6¶>ëi)c¤­u¸HˆXØSýËLÝ-eîðY“NÂ\¿§Qú%íAnèOÄŠ†4u8êro€uôLŽ!8>šà€!Ê s›úã§Žr½6|± ËÝy¡žj&þçd­Ðó1+ _Yß4œV>ëú>ðï]„:qžÒX!?ÍçXÍd$@`/\ú5GTWMyýF):º"Mt09Ï2)”\å“/¶¼oÀË©û‚7F+wÉú„sï>¿_ÑÍÜÿÚxqJ`lZµ×VòÞx™ºmVÁ[öâk´†½îU<ë~†q7yæI~Èfº úºŸÀÍ”5”ˆUßÀT£K‹±fmnÄÖ•R°§|@ú–æyÁüü‰à°§Ìé1ǦßllcÇ!ùþç¹jíC{¢<–?è4ØUe!çóöÍõÜà  å¿#´¸/õHœõ¥¢õñ¹0²ÌVú²ÓL£Pr äúçqã1^èÂS¶oM¯£cl=‚—+±µÕÕ&›û‚•–-P]sÂm;'uÖæ$óÈ.ú½f÷ñ‚U—™/’kR [>\EÒûÂíÉá•Yh¶wú÷ÛþøqŽtPAlG-ÑÖ=Ô æFæï9k\až¾š]³„äù ¿ë kE{D 2« h‡\J ?tDÅ X0ì#ýü7‚Økqè¤<„g&Å%§à“ân'`Àÿ[{ø endstream endobj 34 0 obj 66940 endobj 35 0 obj <
> endobj 36 0 obj <> stream xœ]ÖÍnÛ8ཟBËvQXïO HY²˜é iÀ±™Ô@#гÈÛW‡GÎt‘øˆ’®>R4éuw¿¿Ï·õ?ÓåøoÕÓy¼¿ÞòËýøtÙnWë/ó¹×Ûô^}ˆ§Ëcþ¸ZžNy:ÏÕ‡oÝÃ|üðv½þÈ/y¼Uõj·«Nùi®ó×áú÷á%¯Ë]ŸîOóéóíýÓ|Ëï ¾¾_sՖ㆔ãå”_¯‡cžãs^mëzWm‡a·ÊãésM]óžÇ§ã÷ôڶ¸¶®c½›sSòü1ç–¹EÌY˜Y™Ù˜ ÙçÜÖÍùŽíwÈæÒ™#rbNÈs‡¼§mܳ½G˜çnýþ@€?Ðàôøýþ@€?ÐàÎìÈôøýþ@€?Ðàôøýþ@€?Ðàú~¡_àú~¡_àú~¡_àú~¡_àú~¡_àú~¡_àú~¡_àú~¡_àWú~¥_áWú~¥_áWú~¥_áWú~¥_áWú~¥_áWú~¥_áWú~¥_áWú~¥_á·šsõ~ƒßè7ø~ƒßè7ø~ƒßè7ø~ƒßè·RŸ~ƒßè7ø~ƒßè7ø~ƒßè7ø~ƒß9þŽñwú~§ßáwú~§ßáwú~§ßáwú~§ßáwú~§ßáwú~§ßáwú~§ßátF8#ÎHg„3ÂÙ¶ l‘Îù+Ú²rÉæÿ Y,h6¥;ÑÈDt8. Pi|ñ€Fv ¢±+íåK÷ÌèdD†TôÀŒg¥†u€NmÉ-^F ̸>-AÍÄNèÄ…²,²éŽuð¬´aÆ`¥Å‰ALt&8eÁM‹³<—“#artË„F{ÇN‡® tÛáÞ®Lˆvqè”ípvÆv¼øÎ™Kû2ž¥=²æn±•ö=Ûaîzf˜»õ1þûå‹OOgñôË$@;<«) bÏwW<}ynS—~y.®X§G¡ô¥)›Á°ÔÁõë ¨3,uðîÖÙÿdØ@±ÃÿÚ˜«ãÛ4Í›rùPvcìÃç1ÿûKáz¹â®ò÷pר endstream endobj 37 0 obj <
> endobj 38 0 obj <> endobj 39 0 obj <> endobj 1 0 obj <
>/Contents 2 0 R>> endobj 4 0 obj <
>/Contents 5 0 R>> endobj 7 0 obj <
>/Contents 8 0 R>> endobj 10 0 obj <
>/Contents 11 0 R>> endobj 13 0 obj <
>/Contents 14 0 R>> endobj 16 0 obj <
>/Contents 17 0 R>> endobj 19 0 obj <
>/Contents 20 0 R>> endobj 22 0 obj <
> endobj 40 0 obj <
> endobj 41 0 obj < /Producer /CreationDate(D:20110130132755+01'00')>> endobj xref 0 42 0000000000 65535 f 0000263578 00000 n 0000000019 00000 n 0000000784 00000 n 0000263722 00000 n 0000000804 00000 n 0000002013 00000 n 0000263866 00000 n 0000002034 00000 n 0000003463 00000 n 0000264010 00000 n 0000003484 00000 n 0000005163 00000 n 0000264156 00000 n 0000005185 00000 n 0000006979 00000 n 0000264302 00000 n 0000007001 00000 n 0000009045 00000 n 0000264448 00000 n 0000009067 00000 n 0000011098 00000 n 0000264594 00000 n 0000011120 00000 n 0000111694 00000 n 0000111718 00000 n 0000111909 00000 n 0000112854 00000 n 0000113819 00000 n 0000192163 00000 n 0000192186 00000 n 0000192374 00000 n 0000193319 00000 n 0000194284 00000 n 0000261338 00000 n 0000261361 00000 n 0000261556 00000 n 0000262501 00000 n 0000263470 00000 n 0000263523 00000 n 0000264734 00000 n 0000264819 00000 n trailer <
<6F03F71E2C0CBECA6EB87A3334542145> ] /DocChecksum /5489B167EB40E05EF34B23982DB768B2 >> startxref 265010 %%EOF bobcat-5.09.01/ptriter/0000755000175000017500000000000014050437223013575 5ustar frankfrankbobcat-5.09.01/ptriter/ptriter1.f0000644000175000017500000000014414050437223015515 0ustar frankfranktemplate PtrIter::PtrIter(Iterator const &iter) : d_iter(iter) {} bobcat-5.09.01/ptriter/ptriter0000644000175000017500000000177614050437223015224 0ustar frankfrank#ifndef INCLUDED_BOBCAT_PTRITER_ #define INCLUDED_BOBCAT_PTRITER_ #include namespace FBB { template class PtrIter: public std::iterator { Iterator d_iter; public: typedef decltype(&*Iterator()) PtrType; PtrIter(Iterator const &iter); // 1.f PtrIter(PtrIter &&tmp) = default; PtrIter(PtrIter const &other) = default; PtrType operator*() const; // opstar.f PtrIter &operator++(); // opinc.f bool operator==(PtrIter const &other) const; // opeq.f bool operator!=(PtrIter const &other) const; // opneq.f }; #include "ptriter1.f" #include "opeq.f" #include "opinc.f" #include "opneq.f" #include "opstar.f" // Free functions #include "ptriter.f" } // FBB #endif bobcat-5.09.01/ptriter/opstar.f0000644000175000017500000000017714050437223015261 0ustar frankfranktemplate typename PtrIter::PtrType PtrIter::operator*() const { return &*d_iter; } bobcat-5.09.01/ptriter/opinc.f0000644000175000017500000000016414050437223015055 0ustar frankfranktemplate PtrIter &PtrIter::operator++() { ++d_iter; return *this; } bobcat-5.09.01/ptriter/ptriter.f0000644000175000017500000000016414050437223015436 0ustar frankfranktemplate PtrIter ptrIter(Iterator const &iter) { return PtrIter(iter); } bobcat-5.09.01/ptriter/opneq.f0000644000175000017500000000020314050437223015061 0ustar frankfranktemplate bool PtrIter::operator!=(PtrIter const &other) const { return d_iter != other.d_iter; } bobcat-5.09.01/ptriter/opeq.f0000644000175000017500000000020314050437223014703 0ustar frankfranktemplate bool PtrIter::operator==(PtrIter const &other) const { return d_iter == other.d_iter; } bobcat-5.09.01/ptriter/driver/0000755000175000017500000000000014050437223015070 5ustar frankfrankbobcat-5.09.01/ptriter/driver/driver.cc0000644000175000017500000000217014050437223016672 0ustar frankfrank#include #include #include #include #include #include using namespace std; using namespace FBB; int main() { cout << "Enter lines, the first word will be the map's key; " "^D when done.\n"; string key; string line; unordered_map map; while (cin >> key && getline(cin, line)) // fill the map map[key] = line; cout << '\n'; // initialize a support vector // vector, using ptrIter support(ptrIter(map.begin()), ptrIter(map.end())); // sort 'support' typedef unordered_map::value_type VT; sort(support.begin(), support.end(), [&](VT const *p1, VT const *p2) { return strcasecmp(p1->first.c_str(), p2->first.c_str()) < 0; } ); for(auto &element: support) // display sorted by key cout << element->first << ' ' << element->second << '\n'; } bobcat-5.09.01/qpbufbase/0000755000175000017500000000000014050437223014054 5ustar frankfrankbobcat-5.09.01/qpbufbase/text.cc0000644000175000017500000000012714050437223015347 0ustar frankfrank#include "qpbufbase.ih" void QPBufBase::text() { flush(); d_buffer += '\n'; } bobcat-5.09.01/qpbufbase/dodecode.cc0000644000175000017500000000015714050437223016134 0ustar frankfrank#include "qpbufbase.ih" void QPBufBase::doDecode() { d_action = &QPBufBase::decode; // setBuffer(); } bobcat-5.09.01/qpbufbase/escape.cc0000644000175000017500000000030114050437223015615 0ustar frankfrank#include "qpbufbase.ih" void QPBufBase::escape(unsigned char ch) { d_pending.push_back('='); d_pending.push_back(s_hexChars[ch >> 4]); d_pending.push_back(s_hexChars[ch & 0xf]); } bobcat-5.09.01/qpbufbase/insert.cc0000644000175000017500000000022414050437223015665 0ustar frankfrank#include "qpbufbase.ih" void QPBufBase::insert(int ch) { if (isprint(ch) && ch != '=') d_pending += ch; else escape(ch); } bobcat-5.09.01/qpbufbase/data.cc0000644000175000017500000000027214050437223015275 0ustar frankfrank#include "qpbufbase.ih" string const QPBufBase::s_hexChars { "0123456789ABCDEF" }; void (QPBufBase::*QPBufBase::s_encode[])() = { &QPBufBase::text, &QPBufBase::binary }; bobcat-5.09.01/qpbufbase/qpbufbase0000644000175000017500000000313714050437223015753 0ustar frankfrank#ifndef INCLUDED_BOBCAT_QPBUFBASE_ #define INCLUDED_BOBCAT_QPBUFBASE_ // See also https://en.wikipedia.org/wiki/Quoted-printable // And https://www.ietf.org/rfc/rfc2045.txt (section 6.7) // // #include #include #include namespace FBB { namespace IUO // the facilities defined here are not further documented: { // the QPBufBase class defined below should be // used by IQPStreambuf only. class QPBufBase: public FBB::IFilterBuf { enum { MAX_LENGTH = 76, LAST_IDX = 75 }; std::istream &d_in; // stream to read bool (QPBufBase::*d_action)(); // encoding or decoding size_t d_bufSize; std::string d_buffer; bool d_allDone = false; std::string d_pending; // used by encode void (QPBufBase::*d_encode)(); static std::string const s_hexChars; static void (QPBufBase::*s_encode[])(); public: QPBufBase(std::istream &in, size_t bufSize); protected: void doEncode(bool binary = false); void doDecode(); private: // 'filter' controls the conversion bool filter(char const **srcBegin, char const **srcEnd) override; bool encode(); // false means: end of input on d_in, but there // may still be chars to process in d_buffer bool decode(); void insert(int ch); void escape(unsigned char ch); void text(); void binary(); void flush(); }; } // IUO } // FBB #endif bobcat-5.09.01/qpbufbase/decode.cc0000644000175000017500000000234514050437223015612 0ustar frankfrank#include "qpbufbase.ih" #include // returns true if the buffer must be flushed, otherwise return false // bool QPBufBase::decode() { // read d_in character by character // if the character != '=' then store the character in the buffer // otherwise if the next char is \n then store \n, otherwise // convert the character from the next two hex-value representing // characters, otherwise (at EOF) return false. while (true) { int b0 = d_in.get(); // get a character if (b0 == '=') // found a '=' char { b0 = d_in.get(); // get the next char if (b0 == '\n') // =\n means soft line break continue; // and so not a real \n int b1 = d_in.get(); // get 2nd of 2 hex chars // convert to real char b0 = (s_hexChars.find(b0) << 4) + s_hexChars.find(b1); } if (!d_in) return false; d_buffer.push_back(b0); if (d_buffer.size() > 100) // flush if the buffer is full return true; } } bobcat-5.09.01/qpbufbase/binary.cc0000644000175000017500000000012514050437223015645 0ustar frankfrank#include "qpbufbase.ih" void QPBufBase::binary() { escape('\n'); flush(); } bobcat-5.09.01/qpbufbase/doencode.cc0000644000175000017500000000024514050437223016144 0ustar frankfrank#include "qpbufbase.ih" void QPBufBase::doEncode(bool binary) { d_encode = binary? &QPBufBase::binary : &QPBufBase::text; d_action = &QPBufBase::encode; } bobcat-5.09.01/qpbufbase/qpbufbase.ih0000644000175000017500000000017014050437223016344 0ustar frankfrank#include "qpbufbase" #include "../exception/exception" using namespace std; using namespace FBB; using namespace IUO; bobcat-5.09.01/qpbufbase/flush.cc0000644000175000017500000000201514050437223015502 0ustar frankfrank#include "qpbufbase.ih" void QPBufBase::flush() { if (d_pending.empty()) // empty line return; unsigned char ch = d_pending.back(); if (isblank(ch)) // escape final blank { d_pending.pop_back(); escape(ch); } size_t pos; while (d_pending.length() > MAX_LENGTH) // split long lines { pos = d_pending.find_last_of(" \t", LAST_IDX - 1); if (pos != string::npos) // found a blank { ++pos; d_buffer.append(d_pending, 0, pos); d_buffer += "=\n"; d_pending.erase(0, pos); continue; } pos = d_pending.find_last_of('=', LAST_IDX); // find an esc. seq. if (pos == string::npos || pos <= LAST_IDX - 3) // not at the end pos = LAST_IDX; d_buffer.append(d_pending, 0, pos); d_buffer += "=\n"; d_pending.erase(0, pos); } d_buffer += d_pending; d_pending.clear(); } bobcat-5.09.01/qpbufbase/filter.cc0000644000175000017500000000101114050437223015641 0ustar frankfrank#include "qpbufbase.ih" // #include bool QPBufBase::filter(char const **srcBegin, char const **srcEnd) { if (d_allDone) return false; d_buffer.clear(); d_allDone = (this->*d_action)() == false; // false: all conversions // completed *srcBegin = d_buffer.data(); // set the begin and end ptrs *srcEnd = *srcBegin + d_buffer.size(); return d_buffer.size(); // any chars available: true } bobcat-5.09.01/qpbufbase/qpbufbase1.cc0000644000175000017500000000017614050437223016420 0ustar frankfrank#include "qpbufbase.ih" QPBufBase::QPBufBase(std::istream &in, size_t bufSize) : IFilterBuf(bufSize), d_in(in) {} bobcat-5.09.01/qpbufbase/encode.cc0000644000175000017500000000065114050437223015622 0ustar frankfrank #include "qpbufbase.ih" bool QPBufBase::encode() { while (true) { int ch = d_in.get(); if (not d_in) // eof encountered { flush(); return false; } if (ch != '\n') insert(ch); else (this->*d_encode)(); if (d_buffer.length() > 100) return true; } } bobcat-5.09.01/randbuf/0000755000175000017500000000000014050437223013525 5ustar frankfrankbobcat-5.09.01/randbuf/randbuf0000644000175000017500000000053114050437223015070 0ustar frankfrank#ifndef INCLUDED_BOBCAT_RANDBUF_ #define INCLUDED_BOBCAT_RANDBUF_ #include #include namespace FBB { class RandBuf: public std::streambuf { int d_min; double d_max; std::string d_buffer; public: RandBuf(int min, int max, size_t seed); private: int underflow() override; }; } #endif bobcat-5.09.01/randbuf/randbuf.ih0000644000175000017500000000021614050437223015467 0ustar frankfrank#include "randbuf" #include #include #include #include using namespace std; using namespace FBB; bobcat-5.09.01/randbuf/randbuf1.cc0000644000175000017500000000041114050437223015532 0ustar frankfrank#include "randbuf.ih" RandBuf::RandBuf(int min, int max, size_t seed) { if (min <= max) { d_min = min; d_max = max; } else { d_min = max; d_max = min; } ++d_max; srandom(seed); setg(0, 0, 0); } bobcat-5.09.01/randbuf/underflow.cc0000644000175000017500000000063314050437223016043 0ustar frankfrank#include "randbuf.ih" #include int RandBuf::underflow() { ostringstream ostr; d_buffer = to_string( d_min + static_cast( (d_max - d_min) * (random() / (RAND_MAX + 1.)) ) ) + ' '; setg(&d_buffer[0], &d_buffer[0], &d_buffer[d_buffer.length()]); return static_cast(*gptr()); } bobcat-5.09.01/randbuf/driver/0000755000175000017500000000000014050437223015020 5ustar frankfrankbobcat-5.09.01/randbuf/driver/build0000755000175000017500000000056314050437223016051 0ustar frankfrank#!/bin/bash # use the std bobcat library: # g++ --std=c++2a -o driver driver.cc -lbobcat # use librandbuf.a and the std bobcat library # g++ --std=c++2a -o driver driver.cc -L../tmp -l randbuf -lbobcat # use librandbuf.a and /tmp/libbob.a g++ --std=c++2a -o driver driver.cc -L../tmp -l randbuf -L/tmp -lbob # g++ --std=c++2a -o driver driver.cc ../*.o -lbobcat bobcat-5.09.01/randbuf/driver/driver.cc0000644000175000017500000000137614050437223016631 0ustar frankfrank#include #include #include "../randbuf" using namespace std; using namespace FBB; int main(int argc, char **argv) { if (argc == 1) { cout << "expect: nruns min max seed\n"; return 1; } RandBuf rb(stoi(argv[2]), stoi(argv[3]), stoul(argv[4])); istream istr(&rb); for (unsigned idx = stoul(argv[1]); idx--; ) { int c; if (!(istr >> c)) { cout << "extraction failed\n"; break; } cout << "next: " << c << endl; } int count = 0; while (istr.unget()) count++; cout << "number of successful unget()-calls: " << count << endl; istr.clear(); istr >> count; cout << "and read: " << count << endl; } bobcat-5.09.01/randbuf/driver/driver.h0000644000175000017500000000076314050437223016472 0ustar frankfrank// driver.h #ifndefH_driver_ #defineH_driver_ /* $Id$ $Log$ Revision 1.1 2005/11/11 14:22:42 frank Added local* classes, randstream randbuf and mailheaders Revision 1.1.1.1 2003/05/31 13:17:04 frank Initial import of RandBuf Revision 1.1.1.1 2003/05/31 12:41:09 frank Initial import of RandBuf */ //#include //#include //#include //#include //#include //using namespace std; #endif bobcat-5.09.01/ranger/0000755000175000017500000000000014050437223013362 5ustar frankfrankbobcat-5.09.01/ranger/ranger.f0000644000175000017500000000017214050437223015007 0ustar frankfranktemplate Ranger::Ranger(Iter const &begin, Iter const &end) : d_begin(begin), d_end(end) {} bobcat-5.09.01/ranger/ranger4.f0000644000175000017500000000017714050437223015100 0ustar frankfranktemplate Ranger ranger(Data *begin, size_t count) { return Ranger(begin, begin + count); } bobcat-5.09.01/ranger/ranger3.f0000644000175000017500000000017414050437223015074 0ustar frankfranktemplate Ranger ranger(Iter &&begin, size_t count) { return Ranger(begin, begin + count); } bobcat-5.09.01/ranger/begin.f0000644000175000017500000000013514050437223014614 0ustar frankfrank template Iter const &Ranger::begin() const { return d_begin; } bobcat-5.09.01/ranger/end.f0000644000175000017500000000012514050437223014275 0ustar frankfranktemplate Iter const &Ranger::end() const { return d_end; } bobcat-5.09.01/ranger/ranger0000644000175000017500000000131714050437223014565 0ustar frankfrank#ifndef INCLUDED_BOBCAT_RANGER_ #define INCLUDED_BOBCAT_RANGER_ namespace FBB { template class Ranger { Iter d_begin; Iter d_end; public: Ranger(Iter const &begin, Iter const &end); // .f Iter const &begin() const; // .f Iter const &end() const; // .f }; #include "ranger.f" #include "begin.f" #include "end.f" // Free functions #include "ranger1.f" // ranger(Iter &&begin, Iter &&end) #include "ranger2.f" // ranger(Data *begin, Data *end) #include "ranger3.f" // ranger(Iter &&begin, size_t count) #include "ranger4.f" // ranger(Data *begin, size_t count) } // FBB #endif bobcat-5.09.01/ranger/ranger1.f0000644000175000017500000000016014050437223015065 0ustar frankfranktemplate Ranger ranger(Iter &&begin, Iter &&end) { return Ranger(begin, end); } bobcat-5.09.01/ranger/ranger2.f0000644000175000017500000000016214050437223015070 0ustar frankfranktemplate Ranger ranger(Data *begin, Data *end) { return Ranger(begin, end); } bobcat-5.09.01/ranger/driver/0000755000175000017500000000000014050437223014655 5ustar frankfrankbobcat-5.09.01/ranger/driver/driver.cc0000644000175000017500000000274214050437223016464 0ustar frankfrank#include #include #include using namespace std; using namespace FBB; int main() { vector iv {1, 2, 3, 4, 5}; // display and modify a subrange for(auto &el: ranger(iv.rbegin() + 1, iv.rend() - 1)) cout << el++ << ' '; cout << '\n'; // display a reversed range for(auto &el: ranger(iv.rbegin() + 1, iv.rend() - 1)) cout << el << ' '; cout << '\n'; // same: display using a count for(auto &el: ranger(iv.rbegin() + 1, 3)) cout << el << ' '; cout << '\n'; int intArray[] = {1, 2, 3, 4, 5}; // display and modify elements // in a pointer-based range for(auto &el: ranger(intArray + 1, intArray + 3)) cout << el++ << ' '; cout << '\n'; // data now modified for(auto &el: ranger(intArray + 1, intArray + 3)) cout << el << ' '; cout << '\n'; // using a count rather than an // end-pointer for(auto &el: ranger(intArray + 1, 3)) cout << el << ' '; cout << '\n'; int const constInts[] = {1, 2, 3, 4, 5}; // data can't be modified for(auto &el: ranger(constInts + 1, constInts + 3)) cout << el << ' '; cout << '\n'; } bobcat-5.09.01/READLINE0000644000175000017500000000012714050437223013212 0ustar frankfrank# This file is read from icmake/special readlinebuf readlinehistory readlinestream bobcat-5.09.01/readlinebuf/0000755000175000017500000000000014050437223014364 5ustar frankfrankbobcat-5.09.01/readlinebuf/readlinebuf2.cc0000644000175000017500000000130414050437223017233 0ustar frankfrank#include "readlinebuf.ih" ReadLineBuf::ReadLineBuf(string const &prompt, size_t historySize, Type type) : d_history(historySize > 0), d_prompt(prompt), d_readline(&ReadLineBuf::readLine), d_timestamp(0) { if (!d_history) { if (type == EXPAND_HISTORY) throw std::logic_error("Can't EXPAND_HISTORY without history"); } else { if (type == EXPAND_HISTORY) d_readline = &ReadLineBuf::expandLine; using_history(); stifle_history( historySize > static_cast(numeric_limits::max()) ? numeric_limits::max() : historySize ); } } bobcat-5.09.01/readlinebuf/readline.cc0000644000175000017500000000027514050437223016462 0ustar frankfrank#include "readlinebuf.ih" size_t ReadLineBuf::readLine() { char *buf = readline(d_prompt.c_str()); // readline(3) if (buf == 0) return 0; return nextLine(buf); } bobcat-5.09.01/readlinebuf/instance.cc0000644000175000017500000000030014050437223016470 0ustar frankfrank#include "readlinebuf.ih" ReadLineBuf &ReadLineBuf::instance() { if (s_readLineBuf.get() == 0) throw logic_error("ReadLineBuf not yet initialized"); return *s_readLineBuf; } bobcat-5.09.01/readlinebuf/data.cc0000644000175000017500000000012514050437223015602 0ustar frankfrank#include "readlinebuf.ih" std::unique_ptr ReadLineBuf::s_readLineBuf; bobcat-5.09.01/readlinebuf/initialize2.cc0000644000175000017500000000054614050437223017123 0ustar frankfrank#include "readlinebuf.ih" ReadLineBuf &ReadLineBuf::initialize(std::string const &prompt, size_t historySize, Type type) { if (s_readLineBuf.get() != 0) throw logic_error("ReadLineBuf already initialized"); s_readLineBuf.reset(new ReadLineBuf(prompt, historySize, type)); return *s_readLineBuf; } bobcat-5.09.01/readlinebuf/nextline.cc0000644000175000017500000000107114050437223016520 0ustar frankfrank#include "readlinebuf.ih" size_t ReadLineBuf::nextLine(char *buf) // malloc allocated buf { if (buf == 0) d_buffer.clear(); else d_buffer = buf; if (d_history && not d_buffer.empty()) // add line (+ maybe a timestamp) { // to the history add_history(buf); if (d_timestamp) add_history_time((*d_timestamp)().c_str()); } free(buf); // done with the malloc-ed buf. d_buffer += '\n'; return d_buffer.length(); } bobcat-5.09.01/readlinebuf/expansionerror.f0000644000175000017500000000013714050437223017612 0ustar frankfrankinline std::string const &ReadLineBuf::expansionError() const { return d_expansionError; } bobcat-5.09.01/readlinebuf/expansion.f0000644000175000017500000000013114050437223016532 0ustar frankfrankinline ReadLineBuf::Expansion ReadLineBuf::expansion() const { return d_expansion; } bobcat-5.09.01/readlinebuf/initialize1.cc0000644000175000017500000000043714050437223017121 0ustar frankfrank#include "readlinebuf.ih" ReadLineBuf &ReadLineBuf::initialize(std::string const &prompt, Type type) { if (s_readLineBuf.get() != 0) throw logic_error("ReadLineBuf already initialized"); s_readLineBuf.reset(new ReadLineBuf(prompt, type)); return *s_readLineBuf; } bobcat-5.09.01/readlinebuf/readlinebuf1.cc0000644000175000017500000000050114050437223017230 0ustar frankfrank#include "readlinebuf.ih" ReadLineBuf::ReadLineBuf(string const &prompt, Type type) : d_history(true), d_prompt(prompt), d_readline(type == DONT_EXPAND_HISTORY ? &ReadLineBuf::readLine : &ReadLineBuf::expandLine), d_timestamp(0), d_expansion(ERROR) { using_history(); } bobcat-5.09.01/readlinebuf/setprompt.f0000644000175000017500000000013114050437223016563 0ustar frankfrankinline void ReadLineBuf::setPrompt(std::string const &prompt) { d_prompt = prompt; } bobcat-5.09.01/readlinebuf/destructor.cc0000644000175000017500000000014714050437223017073 0ustar frankfrank#include "readlinebuf.ih" ReadLineBuf::~ReadLineBuf() { if (d_history) clear_history(); } bobcat-5.09.01/readlinebuf/setexpansion.cc0000644000175000017500000000044014050437223017411 0ustar frankfrank#include "readlinebuf.ih" bool ReadLineBuf::setExpansion(Type type) { if (!d_history) return false; d_expansion = ERROR; d_readline = type == DONT_EXPAND_HISTORY ? &ReadLineBuf::readLine : &ReadLineBuf::expandLine; return true; } bobcat-5.09.01/readlinebuf/expandline.cc0000644000175000017500000000112114050437223017015 0ustar frankfrank#include "readlinebuf.ih" size_t ReadLineBuf::expandLine() { d_expansionError.clear(); char *buf = readline(d_prompt.c_str()); // readline(3) if (buf == 0) return 0; char *expanded; switch (d_expansion = static_cast(1 + history_expand(buf, &expanded))) { case ERROR: d_expansionError = expanded; break; case NO_EXPANSION: break; default: std::swap(expanded, buf); break; } free(expanded); return nextLine(buf); } bobcat-5.09.01/readlinebuf/underflow.cc0000644000175000017500000000060014050437223016674 0ustar frankfrank#include "readlinebuf.ih" int ReadLineBuf::underflow() { size_t end = (this->*d_readline)(); if (end == 0) return EOF; setg(&d_buffer[0], &d_buffer[0], &d_buffer[end]); // the static_cast is required to prevent // promotions of 0xff characters to -1, thus returning EOF... return static_cast(*gptr()); } bobcat-5.09.01/readlinebuf/readlinebuf0000644000175000017500000000425514050437223016575 0ustar frankfrank#ifndef INCLUDED_BOBCAT_READLINEBUF_ #define INCLUDED_BOBCAT_READLINEBUF_ #include #include #include namespace FBB { struct HistoryExpansion { enum Type { DONT_EXPAND_HISTORY, EXPAND_HISTORY }; enum Expansion { ERROR, NO_EXPANSION, EXPANDED, DONT_EXEC, }; }; class ReadLineBuf: public HistoryExpansion, public std::streambuf { bool d_history; std::string d_prompt; std::string d_buffer; size_t (ReadLineBuf::*d_readline)();// calls readLine() or expandLine() std::string (*d_timestamp)(); // return a timestamp Expansion d_expansion; std::string d_expansionError; static std::unique_ptr s_readLineBuf; public: static ReadLineBuf &initialize(std::string const &prompt, Type type = DONT_EXPAND_HISTORY); static ReadLineBuf &initialize(std::string const &prompt, size_t historySize, Type type = DONT_EXPAND_HISTORY); static ReadLineBuf &instance(); ~ReadLineBuf() override; void setPrompt(std::string const &prompt = ""); // .f bool setExpansion(Type type); Expansion expansion() const; // .f std::string const &expansionError() const; // .f bool useTimestamps(std::string (*timestamp)() = 0); private: explicit ReadLineBuf(std::string const &prompt, Type type = DONT_EXPAND_HISTORY); explicit ReadLineBuf(std::string const &prompt, size_t historySize, Type type = DONT_EXPAND_HISTORY); int underflow() override; size_t readLine(); // reads a line, adds it to the history size_t expandLine(); // reads a line, expands it if necessary, // then adds it to the history size_t nextLine(char *buf); }; #include "setprompt.f" #include "expansion.f" #include "expansionerror.f" } // FBB #endif bobcat-5.09.01/readlinebuf/driver/0000755000175000017500000000000014050437223015657 5ustar frankfrankbobcat-5.09.01/readlinebuf/driver/build0000755000175000017500000000055414050437223016710 0ustar frankfrank#!/bin/bash # CMD="g++ --std=c++2a -o driver -Wall -I../../tmp driver.cc -L../../tmp/lib \ # -lreadline -lbobcat -s" tput clear GPP="g++ --std=c++2a" # Using tmp libraries and bobcat CMD="$GPP -o driver -Wall -I../../tmp driver.cc \ -L../tmp -lreadlinebuf \ -lreadline -lbobcat -s" echo $CMD $CMD bobcat-5.09.01/readlinebuf/driver/driver.cc0000644000175000017500000000232714050437223017465 0ustar frankfrank#include #include #include #include #include #include using namespace std; using namespace FBB; int main() { ReadLineBuf &readlineBuf = ReadLineBuf::initialize("", 10, ReadLineBuf::EXPAND_HISTORY); istream in(&readlineBuf); size_t count = 0; string line; while (true) { ostringstream prompt; prompt << setw(2) << ++count << ": "; readlineBuf.setPrompt(prompt.str()); if (!getline(in, line)) // uses the last-set prompt break; cout << "Retrieved: " << line << "\n" "Expansion status: "; switch (readlineBuf.expansion()) { case ReadLineBuf::ERROR: cout << "ERROR: " << readlineBuf.expansionError() << '\n'; break; case ReadLineBuf::NO_EXPANSION: cout << "no expansion performed\n"; break; case ReadLineBuf::DONT_EXEC: cout << "don't execute the expanded line\n"; break; case ReadLineBuf::EXPANDED: cout << "expansion successfully performed\n"; break; } } } bobcat-5.09.01/readlinebuf/usetimestamps.cc0000644000175000017500000000025714050437223017602 0ustar frankfrank#include "readlinebuf.ih" bool ReadLineBuf::useTimestamps(string (*timestamp)()) { if (!d_history) return false; d_timestamp = timestamp; return true; } bobcat-5.09.01/readlinebuf/readlinebuf.ih0000644000175000017500000000032014050437223017161 0ustar frankfrank#include "readlinebuf" #include #include #include #include #include #include using namespace std; using namespace FBB; bobcat-5.09.01/readlinehistory/0000755000175000017500000000000014050437223015311 5ustar frankfrankbobcat-5.09.01/readlinehistory/opdecpost.f0000644000175000017500000000020514050437223017455 0ustar frankfrankinline ReadLineHistory::const_iterator ReadLineHistory::const_iterator::operator--(int) { return const_iterator(d_idx--); } bobcat-5.09.01/readlinehistory/instance2.f0000644000175000017500000000020714050437223017345 0ustar frankfrankinline ReadLineHistory &ReadLineHistory::instance(bool useTimestamps) { return s_readLineHistory.setTimestampsIO(useTimestamps); } bobcat-5.09.01/readlinehistory/timestamp.f0000644000175000017500000000014214050437223017460 0ustar frankfrankinline char const *ReadLineHistory::HistoryElement::timestamp() const { return d_timestamp; } bobcat-5.09.01/readlinehistory/readlinehistory0000644000175000017500000001032114050437223020436 0ustar frankfrank#ifndef INCLUDED_BOBCAT_READLINEHISTORY_ #define INCLUDED_BOBCAT_READLINEHISTORY_ #include #include #include namespace FBB { class ReadLineHistory; class ReadLineHistory { friend std::ostream &operator<<(std::ostream &out, ReadLineHistory const &history); friend std::istream &operator>>(std::istream &out, ReadLineHistory &history); static ReadLineHistory s_readLineHistory; bool d_timestamps; public: class HistoryElement { friend ReadLineHistory; char const *d_line; char const *d_timestamp; public: char const *line() const; // .f char const *timestamp() const; // .f private: HistoryElement(); // 1.f HistoryElement const &set(HIST_ENTRY const *element); }; class const_iterator: public std::iterator { friend ReadLineHistory; friend std::reverse_iterator; size_t d_idx; mutable HistoryElement d_element; public: const_iterator &operator++(); // opinc.f const_iterator operator++(int); // opincpost.f bool operator==(const_iterator const &rhs) const; // opeq.f bool operator!=(const_iterator const &rhs) const; // opneq.f HistoryElement const &operator*() const; HistoryElement const *operator->() const; // oparrow.f private: const_iterator(); // last element 1.f const_iterator(size_t idx); // 2.f // for the reverse iter. const_iterator &operator--(); // opdec.f const_iterator operator--(int); // opdecpost.f }; typedef std::reverse_iterator const_reverse_iterator; ReadLineHistory(ReadLineHistory const &other) = delete; ReadLineHistory &operator=(ReadLineHistory const &rhs) = delete; const_iterator begin() const; // begin of the history .f const_iterator end() const; // end of the history .f const_reverse_iterator rbegin() const; // .f const_reverse_iterator rend() const; // .f ReadLineHistory &setTimestampsIO(bool useTimestamps); // .f size_t size() const; // .f size_t maxSize() const; // .f bool timestamps() const; // .f static ReadLineHistory &instance(); // 1.f static ReadLineHistory &instance(bool useTimestamps); // 2.f private: ReadLineHistory(); // .f static void insertHistoryElement(HistoryElement const &he, std::ostream &out); static void insertLine(HistoryElement const &he, std::ostream &out); static std::istream &extractTimestamps(std::istream &in); static std::istream &extractLines(std::istream &in); }; #include "readlinehistory1.f" #include "begin.f" #include "end.f" #include "instance1.f" #include "instance2.f" #include "maxsize.f" #include "rbegin.f" #include "rend.f" #include "settimestampsio.f" #include "size.f" #include "timestamps.f" // ======= HistoryElement members ============ #include "historyelement1.f" #include "line.f" #include "timestamp.f" // ======== const_iterator members #include "constiterator1.f" #include "constiterator2.f" #include "oparrow.f" #include "opeq.f" #include "opinc.f" #include "opincpost.f" #include "opneq.f" } // FBB #endif bobcat-5.09.01/readlinehistory/data.cc0000644000175000017500000000012314050437223016525 0ustar frankfrank#include "readlinehistory.ih" ReadLineHistory ReadLineHistory::s_readLineHistory; bobcat-5.09.01/readlinehistory/extractlines.cc0000644000175000017500000000027114050437223020325 0ustar frankfrank#include "readlinehistory.ih" istream &ReadLineHistory::extractLines(istream &in) { string line; while (getline(in, line)) add_history(line.c_str()); return in; } bobcat-5.09.01/readlinehistory/readlinehistory1.f0000644000175000017500000000005514050437223020746 0ustar frankfrankinline ReadLineHistory::ReadLineHistory() {} bobcat-5.09.01/readlinehistory/maxsize.f0000644000175000017500000000012314050437223017134 0ustar frankfrankinline size_t ReadLineHistory::maxSize() const { return history_max_entries; } bobcat-5.09.01/readlinehistory/inserthistoryelement.cc0000644000175000017500000000034714050437223022124 0ustar frankfrank#include "readlinehistory.ih" void ReadLineHistory::insertHistoryElement(HistoryElement const &he, std::ostream &out) { out << he.line() << '\n' << he.timestamp() << '\n'; } bobcat-5.09.01/readlinehistory/operatorextract.cc0000644000175000017500000000044514050437223021051 0ustar frankfrank#include "readlinehistory.ih" namespace FBB { std::istream &operator>>(std::istream &in, ReadLineHistory &history) { if (!in) return in; clear_history(); if (history.d_timestamps) return history.extractTimestamps(in); return history.extractLines(in); } } bobcat-5.09.01/readlinehistory/begin.f0000644000175000017500000000015014050437223016540 0ustar frankfrankinline ReadLineHistory::const_iterator ReadLineHistory::begin() const { return const_iterator(0); } bobcat-5.09.01/readlinehistory/set.cc0000644000175000017500000000034714050437223016417 0ustar frankfrank#include "readlinehistory.ih" ReadLineHistory::HistoryElement const &ReadLineHistory::HistoryElement::set(HIST_ENTRY const *element) { d_line = element->line; d_timestamp = element->timestamp; return *this; } bobcat-5.09.01/readlinehistory/opinc.f0000644000175000017500000000017614050437223016574 0ustar frankfrankinline ReadLineHistory::const_iterator &ReadLineHistory::const_iterator::operator++() { ++d_idx; return *this; } bobcat-5.09.01/readlinehistory/readlinehistory.ih0000644000175000017500000000023314050437223021036 0ustar frankfrank#include "readlinehistory" #include #include using namespace std; using namespace FBB; #include "opdec.f" #include "opdecpost.f" bobcat-5.09.01/readlinehistory/extracttimestamps.cc0000644000175000017500000000044714050437223021406 0ustar frankfrank#include "readlinehistory.ih" istream &ReadLineHistory::extractTimestamps(istream &in) { string line; string timestamp; while (getline(in, line) && getline(in, timestamp)) { add_history(line.c_str()); add_history_time(timestamp.c_str()); } return in; } bobcat-5.09.01/readlinehistory/end.f0000644000175000017500000000014514050437223016226 0ustar frankfrankinline ReadLineHistory::const_iterator ReadLineHistory::end() const { return const_iterator(); } bobcat-5.09.01/readlinehistory/rend.f0000644000175000017500000000017514050437223016413 0ustar frankfrankinline ReadLineHistory::const_reverse_iterator ReadLineHistory::rend() const { return const_reverse_iterator(begin()); } bobcat-5.09.01/readlinehistory/size.f0000644000175000017500000000011314050437223016425 0ustar frankfrankinline size_t ReadLineHistory::size() const { return history_length; } bobcat-5.09.01/readlinehistory/operatorinsert.cc0000644000175000017500000000054514050437223020704 0ustar frankfrank#include "readlinehistory.ih" namespace FBB { std::ostream &operator<<(std::ostream &out, ReadLineHistory const &history) { for (auto &he: history) ( history.d_timestamps ? ReadLineHistory::insertHistoryElement : ReadLineHistory::insertLine )(he, out); return out; } } bobcat-5.09.01/readlinehistory/insertline.cc0000644000175000017500000000021714050437223017774 0ustar frankfrank#include "readlinehistory.ih" void ReadLineHistory::insertLine(HistoryElement const &he, std::ostream &out) { out << he.line() << '\n'; } bobcat-5.09.01/readlinehistory/instance1.f0000644000175000017500000000012614050437223017344 0ustar frankfrankinline ReadLineHistory &ReadLineHistory::instance() { return s_readLineHistory; } bobcat-5.09.01/readlinehistory/rbegin.f0000644000175000017500000000017514050437223016731 0ustar frankfrankinline ReadLineHistory::const_reverse_iterator ReadLineHistory::rbegin() const { return const_reverse_iterator(end()); } bobcat-5.09.01/readlinehistory/timestamps.f0000644000175000017500000000011514050437223017643 0ustar frankfrankinline bool ReadLineHistory::timestamps() const { return d_timestamps; } bobcat-5.09.01/readlinehistory/oparrow.f0000644000175000017500000000020414050437223017145 0ustar frankfrankinline ReadLineHistory::HistoryElement const *ReadLineHistory::const_iterator::operator->() const { return &operator*(); } bobcat-5.09.01/readlinehistory/opincpost.f0000644000175000017500000000020514050437223017473 0ustar frankfrankinline ReadLineHistory::const_iterator ReadLineHistory::const_iterator::operator++(int) { return const_iterator(d_idx++); } bobcat-5.09.01/readlinehistory/opneq.f0000644000175000017500000000025114050437223016600 0ustar frankfrankinline bool ReadLineHistory::const_iterator::operator!=( const_iterator const &rhs) const { return not (*this == rhs); } bobcat-5.09.01/readlinehistory/operatorderef.cc0000644000175000017500000000026314050437223020462 0ustar frankfrank#include "readlinehistory.ih" ReadLineHistory::HistoryElement const &ReadLineHistory::const_iterator::operator*() const { return d_element.set(history_list()[d_idx]); } bobcat-5.09.01/readlinehistory/settimestampsio.f0000644000175000017500000000020514050437223020707 0ustar frankfrankinline ReadLineHistory &ReadLineHistory::setTimestampsIO(bool useTimestamps) { d_timestamps = useTimestamps; return *this; } bobcat-5.09.01/readlinehistory/historyelement1.f0000644000175000017500000000014014050437223020607 0ustar frankfrankinline ReadLineHistory::HistoryElement::HistoryElement() : d_line(0), d_timestamp(0) {} bobcat-5.09.01/readlinehistory/opeq.f0000644000175000017500000000025114050437223016422 0ustar frankfrankinline bool ReadLineHistory::const_iterator::operator==( const_iterator const &rhs) const { return d_idx == rhs.d_idx; } bobcat-5.09.01/readlinehistory/constiterator1.f0000644000175000017500000000013014050437223020433 0ustar frankfrankinline ReadLineHistory::const_iterator::const_iterator() : d_idx(history_length) {} bobcat-5.09.01/readlinehistory/opdec.f0000644000175000017500000000017614050437223016556 0ustar frankfrankinline ReadLineHistory::const_iterator &ReadLineHistory::const_iterator::operator--() { --d_idx; return *this; } bobcat-5.09.01/readlinehistory/driver/0000755000175000017500000000000014050437223016604 5ustar frankfrankbobcat-5.09.01/readlinehistory/driver/build0000755000175000017500000000042214050437223017627 0ustar frankfrank#!/bin/bash LIBS="-lreadline -lbobcat" #CMD="g++ `cat ../../c++std` -o driver -Wall -I../../tmp driver.cc -L../../tmp/lib \ # ${LIBS} -s" CMD="g++ `cat ../../c++std` -o driver -Wall driver.cc ${LIBS} -s" echo $CMD $CMD bobcat-5.09.01/readlinehistory/driver/driver.cc0000644000175000017500000000261414050437223020411 0ustar frankfrank#include #include #include #include #include #include using namespace std; using namespace FBB; void showHis(ReadLineHistory::HistoryElement const &element) { cout << element.timestamp() << ": " << element.line() << '\n'; } string timestamp() { return DateTime().rfc2822(); }; int main(int argc, char **argv) { ReadLineStream in("? ", ReadLineBuf::EXPAND_HISTORY); in.useTimestamps(×tamp); cout << "Enter some lines, end the input using ctrl-d\n"; string line; while (getline(in, line)) ; // argument means: write/read // history timestamps ReadLineHistory &history = ReadLineHistory::instance(argc > 1); cout << "All lines, from the first to the last:\n"; for_each(history.begin(), history.end(), showHis); cout << "\n" "All lines, from the last to the first:\n"; for_each(history.rbegin(), history.rend(), showHis); cout << "\n" "History out and in:\n" "\n"; ofstream hisout("history.out"); hisout << history; hisout.close(); ifstream hisin("history.out"); hisin >> history; cout << "All lines, from the first to the last:\n"; for_each(history.begin(), history.end(), showHis); } bobcat-5.09.01/readlinehistory/line.f0000644000175000017500000000013014050437223016401 0ustar frankfrankinline char const *ReadLineHistory::HistoryElement::line() const { return d_line; } bobcat-5.09.01/readlinehistory/constiterator2.f0000644000175000017500000000012714050437223020442 0ustar frankfrankinline ReadLineHistory::const_iterator::const_iterator(size_t idx) : d_idx(idx) {} bobcat-5.09.01/readlinestream/0000755000175000017500000000000014050437223015103 5ustar frankfrankbobcat-5.09.01/readlinestream/readlinestream1.f0000644000175000017500000000026614050437223020336 0ustar frankfrankinline ReadLineStream::ReadLineStream(std::string const &prompt, Type type) : std::istream(&ReadLineBuf::initialize(prompt, type)), d_readLineBuf(ReadLineBuf::instance()) {} bobcat-5.09.01/readlinestream/readlinestream2.f0000644000175000017500000000037614050437223020341 0ustar frankfrankinline ReadLineStream::ReadLineStream(std::string const &prompt, size_t historySize, Type type) : std::istream(&ReadLineBuf::initialize(prompt, historySize, type)), d_readLineBuf(ReadLineBuf::instance()) {} bobcat-5.09.01/readlinestream/expansionerror.f0000644000175000017500000000016014050437223020325 0ustar frankfrankinline std::string const &ReadLineStream::expansionError() const { return d_readLineBuf.expansionError(); } bobcat-5.09.01/readlinestream/expansion.f0000644000175000017500000000015514050437223017257 0ustar frankfrankinline ReadLineStream::Expansion ReadLineStream::expansion() const { return d_readLineBuf.expansion(); } bobcat-5.09.01/readlinestream/readlinestream.ih0000644000175000017500000000010514050437223020420 0ustar frankfrank#include "readlinestream" using namespace std; using namespace FBB; bobcat-5.09.01/readlinestream/setprompt.f0000644000175000017500000000015214050437223017305 0ustar frankfrankinline void ReadLineStream::setPrompt(std::string const &prompt) { d_readLineBuf.setPrompt(prompt); } bobcat-5.09.01/readlinestream/readlinestream0000644000175000017500000000227614050437223020034 0ustar frankfrank#ifndef INCLUDED_BOBCAT_READLINESTREAM_ #define INCLUDED_BOBCAT_READLINESTREAM_ #include #include namespace FBB { class ReadLineStream: public HistoryExpansion, public std::istream { ReadLineBuf &d_readLineBuf; public: explicit ReadLineStream(std::string const &prompt, // 1.f Type type = DONT_EXPAND_HISTORY); explicit ReadLineStream(std::string const &prompt, // 2.f size_t historySize, Type type = DONT_EXPAND_HISTORY); void setPrompt(std::string const &prompt = ""); // .f bool setExpansion(Type type); // .f Expansion expansion() const; // .f std::string const &expansionError() const; // .f bool useTimestamps(std::string (*timestamp)()); }; #include "readlinestream1.f" #include "readlinestream2.f" #include "setprompt.f" #include "setexpansion.f" #include "expansion.f" #include "expansionerror.f" #include "usetimestamps.f" } // FBB #endif bobcat-5.09.01/readlinestream/usetimestamps.f0000644000175000017500000000017514050437223020160 0ustar frankfrankinline bool ReadLineStream::useTimestamps(std::string (*timestamp)()) { return d_readLineBuf.useTimestamps(timestamp); } bobcat-5.09.01/readlinestream/driver/0000755000175000017500000000000014050437223016376 5ustar frankfrankbobcat-5.09.01/readlinestream/driver/build0000755000175000017500000000040014050437223017415 0ustar frankfrank#!/bin/bash CMD="g++ `cat ../../c++std` -o driver -Wall -I../../tmp driver.cc -L../../tmp/lib \ -lreadline -lbobcat -s" CMD="g++ `cat ../../c++std` -o driver -Wall driver.cc -lbobcat -s" echo $CMD $CMD bobcat-5.09.01/readlinestream/driver/driver.cc0000644000175000017500000000216214050437223020201 0ustar frankfrank#include #include #include #include #include #include using namespace std; using namespace FBB; int main() { ReadLineStream in("", 10, ReadLineBuf::EXPAND_HISTORY); size_t count = 0; string line; while (true) { ostringstream prompt; prompt << setw(2) << ++count << ": "; in.setPrompt(prompt.str()); if (!getline(in, line)) // uses the last-set prompt break; cout << "Retrieved: " << line << "\n" "Expansion status: "; switch (in.expansion()) { case ReadLineBuf::ERROR: cout << "ERROR: " << in.expansionError() << '\n'; break; case ReadLineBuf::NO_EXPANSION: cout << "no expansion performed\n"; break; case ReadLineBuf::DONT_EXEC: cout << "don't execute the expanded line\n"; break; case ReadLineBuf::EXPANDED: cout << "expansion successfully performed\n"; break; } } } bobcat-5.09.01/readlinestream/setexpansion.f0000644000175000017500000000014514050437223017772 0ustar frankfrankinline bool ReadLineStream::setExpansion(Type type) { return d_readLineBuf.setExpansion(type); } bobcat-5.09.01/README0000644000175000017500000000276514066363031013000 0ustar frankfrank BOBCAT Brokken's Own Base Classes And Templates This library contains C++ classes (and header files) I frequently use in my programs. Practically all its entities are defined in the namespace FBB. Those that are not are, e.g., overloaded versions operator<<, which should normally be defined as a free function. To use the library in your programs, add `-lbobcat' to your link-command, to include a header file for the class `Class' include 'bobcat/class' unless advised otherwise. To compile and install this library unpack the tar.gz file, and follow the instructions in the INSTALL file. If you want to use the .deb precompiled binaries, do as follows: - to use the bobcat library to run executables depending on the bobcat shared library, bobcat_*.deb must be installed. - to compile programs using the bobcat library, and to have the class-manual pages you must install the bobcat-dev_*.deb package. This distinction is not made if you compile and install the bobcat library yourself. When installing the bobcat-dev*.deb version, or when installing bobcat according to the instructions in the INSTALL file, accepting the settings in INSTALL.im, - html versions of the manual pages are found in the directory /usr/share/doc/bobcat-dev/man/ - man bobcat - will show the main class-index - man -e bobcat xxx - shows the man-page for class `xxx' Frank f.b.brokken@rug.nl bobcat-5.09.01/README.class-setup0000644000175000017500000002360214050437223015231 0ustar frankfrankThe following diagram shows the class dependencies. Classes listed on the same line have no mutual dependencies. Classes listed on lines starting with the digit 0 are not depenent on other bobcat classes. Then, diagrams showing dependencies of other classes. Dependencies should be read upwards, e.g., String depends on A2x, Hostname depends on Hostent and Exception. Dependencies refer to the construction of the class members as well as the use of the class headers. So, when compiling the class Msg the class Exception must be available (if not compile-time then most likely run-time). The dependencies are not necessarily related to inheritance. The file CLASSES lists all classes, in something resembling the order of addition of the classes to the Bobcat library. The classes `Milter' and `Xpointer' are optionally compiled, and are therefore not listed in the CLASSES file. The label IUO does not refer to a class but to functions defined in the FBB namespace for internal use only. They are declared in the bobcat/iuo header. Entries below, tagged with `(cont)' were mentioned earlier in the next hierarchy. Entries tagged with (Obs) are obsolete and should no longer be used. 0 Eoi | EoiBuf | +--------------+ | | CryptBuf | | | 0 MultiBuf SyslogBuf ReadLineBuf LinearMap OMutexStream | | SyslogStream ReadLineStream 0 X2a Hash Hostent TypeTrait Swap Indent ReadLineHistory | +-----+------+ | | binops repeat 0 EoiBuf RandBuf (cont) | | IRandStream 0 DateTime Exception IFilterBuf | | | | | | | | +-----+-----+---+------+----------+ | | | | | | | | | | User Signal CSV | | +----+----+------+ | | | | | | | | +---------+ Mbuf | SharedMutex | | | | | | | | | BigInt | Mstream | SharedBlock | | | | CryptBuf | | | | | +------+ (cont) | SharedSegment | | | | | | | | | | | | +---+----+--+ | | | | | | | | | | | | | | | +---+ | | | | | | | | | | | | DecryptBuf EncryptBuf | | | | | | | | | | SharedEnum__ SharedPos +-------+ | | | | | | | +------+--------+ | +--------+---+ | | | | | | | | PrimeFactors | | | | | | | | DiffieHellman | | | | SharedMemory | GS__ | | | | | SharedBuf +----+ | | | | +------------+-------------+ | | | | | | | ISharedStream OSharedStream SharedStream Stat | | | Glob | LogBuf +--------+-------+-----------+-----+-------------+ | | | | | | | | | Pattern OneKey | | +--+--+ | | | | | +--------+ | | Log | | | | Hostent | | | | | (cont) level ConfigFile | | | | | | +---+--+ | | | | | Hostname GetHostent | | LocalSocketBase InetAddress | | | SocketBase +-------------------+ | | | | LocalClientSocket LocalServerSocket +------+---------+ | | ClientSocket ServerSocket Exception(cont) | 0 +---------+--------+----+----+-----+------+----------+ IOBuf | | | | | | | | | Xpointer MailHeaders Milter | Pipe Fork Selector Redirector IOStream | | | | | | | +-----+------+----------+---------+ | | | | +------+ | | | | TempStream | | | | 0 A2x | | | | | String | +----+ | | | +--------+----+ | | | | | | | +---+----+ | | | | | | | Arg ConfigFile | | | | (cont) | | | | | | CmdFinderBase | +---+---+ | | | | | | | ArgConfig | | | | CmdFinder +----+-------------+ | EoiBuf | A2x(cont) (cont) | | | | | Eoi | | | | 0 OFdBuf | IFdBuf | OFilterBuf | | | | | | | | | +---+ | | | | | | | | | +---+ | | | | | | | | | OHexBuf | lm mlm | | | | | | | +-------+ | +----+ | +-------+------+---+ | | | | | | | OFdStream +-------+--+--------+ IFdStream | | | | OFoldBuf Process | | | | | OFoldStream Exception(cont) | | | EoiBuf +----+----+ (cont) | | +---------+ | +-----+-----+ | | DigestBuf HMacBuf 0 Align StringLine Exception(cont) | | | | +------------+ TableSupport | | Cidr +----------+ | | String (cont) TableBase TableLines | | +----+ +----+----+ | | | | | +-----+ | | | | | Table TableBuf | | | Stat(cont) Pattern(cont) X2a(cont) | | | | +-------+-----------+-----+------+ | | CGI bobcat-5.09.01/README.fnwrap0000644000175000017500000003301414050437223014261 0ustar frankfrankFnWrap: new implementation (as of Bison 2.15.00) FnWrap's new implementation reduces its size to slightly less than 50% of its previous size: from over 415 lines to 200. What follows is a description of its inner workings. All function implementations are given as in-class implementations. In Bobcat's FnWrap class all implementations were moved out of the the class interfaces, keeping the interfaces as clean as possible. Almost all of the functionality is encapsulated in the class FnWrap, as before. Although the FnWrap::unary and FnWrap::binary functions remain in existence, their implementations are now identical. In fact, their use is discouraged, promoting the use of the free function FBB::context instead. To start out, the class FnWrap defines several support structs that are not made visible outside of FnWrap. They are: template struct Dissect {}; template struct Dissect { typedef Ret ReturnType; }; The struct Dissect's specialization may receive any function pointer and determines the function's return type. The function's return type may then be obtained from the type ReturnType, defined by Dissect. In addition to determining a function's return value Dissect is also used to define a stand-in type for unary functors. Here care must be taken that no user-software can use this type to avoid confusion. By putting Dissect in FnWrap's private section user software cannot use this stand-in type, which is defined as a pointer type using the typedef: typedef Dissect *NotUsed; The second support struct is: template struct At { typedef typename std::tuple_element::type Type; }; This is a simple typework-saving struct, allowing the retrieval of the type of count's tuple's argument. It expects a count, which is converted to the corresponding index. FnWrap's core business is found in its nested struct Functor. Functor defines a unary or binary function object. The unary or binary function object is typically used by a generic algorithm. FnWrap::Functor objects are created (returned) by FBB::context, and also by the functions FBB::FnWrap::unary and FBB::FnWrap::binary. These three functions have identical implementations. FnWrap::unary and FnWrap::binary remain available for reasons of backward compatibility, their use is discouraged from now on, and they are no longer referred to in this description. FBB::context is a free (classless) function, having the following implementation: template FnWrap::Functor context(Function fun, Args &&...args) { return FnWrap::Functor (fun, std::forward(args) ...); } The function FBB::context receives the address of a Function, as well as any number of additional arguments. Since this is a function template, callers noramlly do not have to specify any of the types, as function templates are usually able to determine the types themselves. Having determined Function and the parameter pack's types, these are used to construct a matching FnWrap::Functor object, whose constructor receives the function's address (i.e., fun) and all remaining perfectly forwarded arguments that were used when calling FBB::context. Here FBB::context's work ends. Its purpose in life is to make a unary or binary function object available. By returning an FnWrap::Functor it has fullfilled that purpose. FnWrap::Functor is a nested struct in FnWrap's public section. Functor determines the function's return type (defining it as its RetType type) and its constructor saves the function's address in its d_function data member. In addition, it saves any remaining arguments received by the constructor in a tuple d_args, again perfectly forwarding the arguments originally passed to FBB::context. FnWrap::Functor's outline and constructor look like this: template struct Functor { typedef typename Dissect::ReturnType RetType; Function d_function; std::tuple d_args; Functor(Function fun, Args &&... args) : d_function(fun), d_args(std::forward(args)...) {} // two members, see below }; Functor defines two member templates: a unary and binary function call operator. Since they are member function templates they can determine the types of their arguments when they are actually called. Here are their implementations: The unary function: template typename Functor::RetType operator()(Arg1 &&arg1) { return CallPack >::call(d_function, std::forward(arg1), 0, d_args); } The binary function: template typename Functor::RetType operator()(Arg1 &&arg1, Arg2 &&arg2) { return CallPack>::call(d_function, std::forward(arg1), std::forward(arg2), d_args); } These members merely pass their arguments, as well as the values of Functor's data members d_function and d_args, to a static function 'call', defined in the CallPack struct. The real meat of what happens inside FnWrap becomes apparent when we turn our attention to CallPack. The CallPack struct has two tasks: * First, it must unpack tuple's arguments so they can be passed as arguments instead of a tuple to the function that is passed to its call member; * Second, it must call 'd_function' with the appropriate arguments. Whereas packing (variadic) arguments into a tuple is not difficult, unpacking a tuple back into a parameter pack is not a trivial tasks. CallPack uses the following algorithm: Initially there is a tuple, there are 'size' elements in the tuple and there is an empty parameter pack. Tuple element [size - 1] is obtained, and prepended to the parameter pack while recursively calling the function call. At each recursion size - 1 is passed to the recursive call as well, so 'size' eventually decays to 0. Once size has decayed to 0, a non-recursive partial specialization is selected by the compiler which will call the function (d_function), passing it arg1, arg2 (for binary functors), and the perfectly forwarded arguments of the parameter pack, which now contains all the arguments found in tuple. In addition to passing the correct arguments to d_function, CallPack also defines the types first_argument_type and second_argument_type, which are required by some generic algorithms. Here is the setup of struct CallPack, and its generic (recursive) call member: template struct CallPack: public CallPack::Type, Args ...> { typedef typename TypeTrait::Plain first_argument_type; typedef typename TypeTrait::Plain second_argument_type; typedef typename At::Type LastType; static RetType call(Func fun, Arg1 &&arg1, Arg2 &&arg2, Tuple &&tuple, Args &&...args) { return CallPack::call(fun, std::forward(arg1), std::forward(arg2), tuple, std::forward(std::get(tuple)), std::forward(args) ... ); } }; There's no CallPack object construction: the call function is static. It finds the type and value of the last not yet processed element in the tuple object and prepends that using perfect forwarding to the existing variable argument list, passing this series as the next variable argument list to the recursive all. Eventually all tuple's elements have been processed. As each recursive call reduces the size parameter by one, it will eventually decay to zero. At that point d_function can be called. Once size has reduced to 0 four situations must be distinguished, each using its own partial specialization of the member function 'call': * A void unary function was used. In this case Arg2 has type FnWrap::NotUsed, and RetType is void (remember that Functor's operator() members are called with either one or two arguments and that the unary Functor::operator() functions passes an FnWrap::NotUsed as Arg2 to CallPack::call). * A non-void unary function was used. In this case Arg2 has type FnWrap::NotUsed * A void binary function was used. In this case RetType is void. * A non-void binary function was used. Each alternative has its own specialization. Here are their implementations: * The void unary function (RetType is specified as void, Arg2 as FnWrap::NotUsed): template void CallPack::call( Func fun, Arg1 &&arg1, FnWrap::NotUsed &&arg2, Tuple &&tuple, Args &&...args) { fun(std::forward(arg1), std::forward(args)...); } * The non-void unary function (Arg2 is specified as FnWrap::NotUsed): template RetType CallPack::call( Func fun, Arg1 &&arg1, FnWrap::NotUsed &&arg2, Tuple &&tuple, Args &&...args) { return fun(std::forward(arg1), std::forward(args)...); } * The void binary function (RetType is specified as void): template void CallPack::call( Func fun, Arg1 &&arg1, Arg2 &&arg2, Tuple &&tuple, Args &&...args) { fun(std::forward(arg1), std::forward(arg2), std::forward(args)...); } * The non-void binary function: template RetType CallPack::call( Func fun, Arg1 &&arg1, Arg2 &&arg2, Tuple &&tuple, Args &&...args) { return fun(std::forward(arg1), std::forward(arg1), std::forward(args)...); } Now that we've designed and implemented FnWrap, here's how it can be used: Assume we have a class Strings having the following basic setup: class Strings { vector d_vs; public: Strings() : d_vs({"one", "two", "", "three"}) {} ... }; It simply defines a vector of strings: four elements, the 3rd one empty. All functions below are members, all implementations are given in-class: * Unary predicate: display all strings until the first empty one: void display(ostream &out) const { size_t nr = 0; find_if(d_vs.begin(), d_vs.end(), context(untilEmpty, nr, out)); } Using the following context-aware predicate function: static bool untilEmpty(string const &str, size_t &nr, ostream &out) { if (str.empty()) return true; // done out << ++nr << ' ' << str << '\n'; return false; // continue } * Unary functor: display all strings: void show(ostream &out) const { size_t nr = 0; for_each(d_vs.begin(), d_vs.end(), context(all, nr, out)); } Using the following context-aware void function: static void all(string const &str, size_t &nr, ostream &out) { out << ++nr << ' ' << str << '\n'; } * Binary predicate: count strings containing 't' void count() { size_t nLines = 0; cout << "Number of counts: " << count_if(d_vs.begin(), d_vs.end(), context(counter, cout, nLines)); cout << '\n' << nLines << " lines processed\n"; } Using the binary predicate function: static bool counter(string const &str, ostream &out, size_t &nLines) { out << "Line nr " << ++nLines << ": " << str; if (str.find('t') != string::npos) { out << ", contains 't'\n"; return true; } out << ", no 't'\n"; return false; } bobcat-5.09.01/README.immovable0000644000175000017500000000301714050437223014737 0ustar frankfrankCurrently immovable classes, hence classes using them will not offer move facilities: std::streambuf, std::ios Singleton classes are not provided with move facilities: there's never another object: arg argconfig Move aware classes: CGI CmdFinderBase CmdFinder ConfigFile Glob Hash Hostent MailHeaders Pattern Stat TableSupport TableLines User No need for move-operations (no class type data members, no move-operations defined in the base class, streams, or obsolete): Arg ArgConfig DateTime Errno FnWrap FnWrapXY (obsolete) Fork GetHostEnt Hostname Indent InetAddress Milter TableBase (used by classes derived fm streams) autoptr (obsolete) bigint decryptbuf digestbuf encryptbuf for_each fswap hmacbuf ifdstream ifdstreambuf iostream iostreambuf irandstream lc (obsolete) level localclientsocket localserversocket localsocketbase log logbuffer mbuf msg mstream multistreambuf ofdstream ofdstreambuf ofilterstreambuf ofoldstream ofoldstreambuf ohexstreambuf onekey pipe process randbuffer readlinebuf readlinehistory readlinestream redirector refcount repeat selector serversocket socketbase string syslogbuf syslogstream table tablebuf typetrait xpointer bobcat-5.09.01/README.milter0000644000175000017500000000253514050437223014264 0ustar frankfrankWhen using the milter library in combination with Bobcat, make sure the milter library is passed to the linker before the bobcat library is specified. E.g., use -lmilter -lbobcat If the bobcat library is specified before the milter library the following stand-in function defined in the bobcat library will be used: `smfi_register' This symbol was included in the bobcat library to prevent an `undefined reference' linker error from being generated when shared libraries are used but the milter library is *not* used. What happens when milter is specified before bobcat is that although the bobcat library defines a stand-in function it is presented to the linker only after the linker has seen the similarly named symbols in the milter library. The linker uses the symbols first encountered, and will therefore properly use the symbol defined in the milter library. However, if the milter library is not used (e.g., Milter is not used) and if bobcat itself would not define the above symbol then that symbol would not be defined in the shared libraries inspected by the linker, producing a linker error. Although the error could be prevented by specifying the option -Wl,--allow-shlib-undefined requiring this option seems like a more complex instruction than requiring that when using the milter library it must be specified before the bobcat library. bobcat-5.09.01/README.optimization0000644000175000017500000000754314050437223015522 0ustar frankfrank The `build' script uses -O3 as one of its compiler flags. Why -O3 and not -O2? (See also changelog 2.09.05 (2010/12/13) explaining why I reverted back to -O2) Compared to -O2, the compiler applies the following additional optimizations: -finline-functions Integrate all simple functions into their callers. The compiler heuristically decides which functions are simple enough to be worth integrating in this way. If all calls to a given function are integrated, and the function is declared "static", then the function is normally not output as assembler code in its own right. This is what we want for all class member functions defined inside their classes. These functions are always simple, consisting of at most one line of code. There are probably no other situations in this code for which the compiler will find it useful to integrate, but for the inline members. But in the case of the inline members (especially with the accessors) the overhead of the additional call seems to be needlessly spillfull. After all, C++ explicitly offers the in-class function definition for these kinds of functions, and thus, integrating their code rather than calling them seems like the right thing to do. -funswitch-loops Move branches with loop invariant conditions out of the loop, with duplicates of the loop on both branches (modified according to result of the condition). Since they're invariants, they can safely be moved, even though it will enlarge the code somewhat (because of the duplication). It prevents the code from testing a condition time and again for each individual iteration within a loop when that's not required. -fgcse-after-reload When -fgcse-after-reload is enabled, a redundant load elimination pass is performed after reload. The purpose of this pass is to cleanup redundant spilling. This refers to things like: removing dead code and reusing where possible values that can be proven to be already available in some registers. In `Contributions to the GNU Compiler Collection' the following paragraph is found: The first case, where redundant loads appear before register allocation, is handled by redundancy elimination optimization. Redundancy elimination removes redundant calculations of expressions by reusing previously calculated values that are stored in some register. The redundancy elimination pass of CCC did consider loading a calculation of an expression from memory, but did not consider store operations as expressions. Thus, GCC did replace a load following another load from the same memory location by a register copy, but did not replace a load following a store to the same location. We enhanced the redundancy elimination pass so that it would also consider stores as expressions, and hence replace subsequent loads from the same location with register copies. The second case of load-hit-store events was due to poor register spilling (i.e., the reload pass in GCC). (43) We handled this case in two ways. First, we added a "cleanup" pass after the reload that removed such redundancies, similar to the first case. However, this solution is limited because it works with hard (that is, allocated) registers. We reused the existing redundancy elimination infrastructure and added a special consideration of register availability for the register moves that we generate. We also took care of partial redundancy elimination by adding loads on basic blocks that are less critical (according to profiling), provided we can replace loads from critical blocks by register moves. Again, this optimization is considered a desirable one and thus it was decided to use -O3 rather than -O2. Frank. bobcat-5.09.01/README.process-pipe0000644000175000017500000000633414050437223015402 0ustar frankfrankThis file contains a description of the operations of the Process::operator| function. There is an accompanying file process-pipe.odp (and its pdf-equivalent: process-pipe.pdf) that illustrates the steps described below. Assuming we're calling (p1|p2|p3).start() and that p1 is defined with the CIN flag and p3 with the COUT flag, the following happens (the numbers refer to the odp slides / pdf pages): 1. P1 and P2 are passed to operator| as, resp. their lhs and rhs parameters. Process objects have two FBB::Pipe objects that are relevant here: oChildIn is the Pipe written to by the parent process and read by its child using stdin; iChildOut is the Pipe read by the parent process and written to by its child when writing its stdout. 2. operator| calls lhs.start(). Since lhs is the first process for which operator| is called (which can be deducted by operator| as lhs does not have the PIPE_IN flag set) it sets it CLOSE_ON_EXEC flag. This flag will cause lhs's oChildIn writing end of the pipe to close with future child processes. Why is this necessary? When later on the rhs process starts its child, it will contain a copy of all the parent's data. This includes, as lhs and rhs are both objects of the same main program, lhs's oChildIn. If lhs's oChildIn wouldn't be closed by rhs's child process then an open pipe to the lhs's child's input stream would remain available preventing the lhs's child process from ending at end-of-input. The start() function sets up the redirections: from the parent to its child, as shown in page/slide 2. 3. operator| copies lhs.iChildOut to rhs.oChildIn This too looks initially looks a but weird as an (for the parent) IN-pipe is copied to an OUT-pipe. However, when rhs.start() is called its child receives a copy of its parent oChildIn from which the child will read. So, the rhs parent never uses its oChildIn pipe for reading, but rhs's child process does. As rhs.oChildIn itself is lhs's iChildOut, rhs's child process will actually read the lhs's child process's output, setting up the pipe between lhs and rhs. 4. Next p2 and p3 are passed to operator|. Now p2 acts as lhs, p3 as rhs 5. operator| calls lhs.start() This is the point where lhs's child also receives p1's oChildIn pipe, which is now automatically closed due to its CLOEXEC flag. Note: not all operating systems, in particularly FreeBSD flavors, support the CLOEXEC fntl flag, even though it's been defined by POSIX since 2008. For those systems Process offers a work-around. The child redirections are standard, so the child reads oChildIn, which in fact is the output from p1's child; the parents obtains its child's output from its iChildOut pipe. 6. The lhs's iChildOut pipe is assigned to the rhs's oChildIn. Same reason as given at 3. 7. (p1|p2|p3).start() starts p3's child process. Once again the child process receives a copy of p1's oChildIn, which is again closed because of its CLOEXEC flag. Now, when the information inserted into p1 ends its oChildIn writing pipe is closed, informing p1's child that its input has been exhausted and the child process properly terminates. bobcat-5.09.01/README.X110000644000175000017500000000273214050437223013340 0ustar frankfrankWhen using the X11 library (which may be implied, e.g., when linking the GTK library) in combination with Bobcat, make sure the X11 library is passed to the linker before the bobcat library is specified. E.g., use -lX11 -lbobcat If the bobcat library is specified before the X11 library the following stand-in functions defined in the bobcat library will be used: `XOpenDisplay' `XCloseDisplay' `XFlush' `XWarpPointer' `XQueryPointer' `XGetWindowAttributes' These symbols were included in the bobcat library to prevent `undefined reference' linker errors from being generated when shared libraries are used but the X11 library is *not* used. What happens when X11 is specified before bobcat is that although the bobcat library defines stand-in functions they are presented to the linker only after the linker has seen the similarly named symbols in the X11 library. The linker uses the symbols first encountered, and will therefore properly use the symbols defined in the X11 library. However, if the X11 library is not used (e.g., Xpointer is not used) and if bobcat itself would not define the above symbols then those symbols would not be defined in the shared libraries inspected by the linker, producing linker errors. Although these errors could be prevented by specifying the option -Wl,--allow-shlib-undefined requiring this option seems like a more complex instruction than requiring that when using the X11 library it must be specified before the bobcat library. bobcat-5.09.01/redirector/0000755000175000017500000000000014050437223014246 5ustar frankfrankbobcat-5.09.01/redirector/redirector1.f0000644000175000017500000000007014050437223016635 0ustar frankfrankinline Redirector::Redirector(int fd) : d_fd(fd) {} bobcat-5.09.01/redirector/swallow.cc0000644000175000017500000000027114050437223016245 0ustar frankfrank#include "redirector.ih" void Redirector::swallow(int alternateFd) const { if (dup2(d_fd, alternateFd) < 0) throw Exception{} << "Redirector::swallow(): " << errnodescr; } bobcat-5.09.01/redirector/accessvia.f0000644000175000017500000000012714050437223016356 0ustar frankfrankinline void Redirector::accessVia(int alternateFd) const { swallow(alternateFd); } bobcat-5.09.01/redirector/through.cc0000644000175000017500000000031514050437223016234 0ustar frankfrank#include "redirector.ih" void Redirector::through(int alternateFd) const { if (dup2(d_fd, alternateFd) < 0) throw Exception{} << "Redirector::through(): " << errnodescr; ::close(d_fd); } bobcat-5.09.01/redirector/redirector0000644000175000017500000000106314050437223016333 0ustar frankfrank#ifndef INCLUDED_BOBCAT_REDIRECTOR_ #define INCLUDED_BOBCAT_REDIRECTOR_ namespace FBB { class Redirector { int d_fd; public: enum StandardFilenos { STDIN = 0, STDOUT, STDERR }; explicit Redirector(int fd); // 1.f void accessVia(int alternateFd) const; // .f void swallow(int alternateFd) const; void through(int alternateFd) const; }; #include "redirector1.f" #include "accessvia.f" } // FBB #endif bobcat-5.09.01/redirector/redirector.ih0000644000175000017500000000014614050437223016733 0ustar frankfrank#include "redirector" #include #include "../exception/exception" using namespace FBB; bobcat-5.09.01/redirector/driver/0000755000175000017500000000000014050437223015541 5ustar frankfrankbobcat-5.09.01/redirector/driver/build0000755000175000017500000002670714050437223016602 0ustar frankfrank#!/usr/bin/icmake -qt/tmp/driver string CLASSES; void setClasses() { // ADD ADDITIONAL DIRECTORIES CONTAINING SOURCES OF CLASSES HERE // Use the construction `CLASSES += "classname1 classname2";' etc. CLASSES += " "; } //#define BUILD_LIBRARY #define BUILD_PROGRAM "driver" #define COMPILER "g++" #define COPT "-Wall -I../../inc" #define LOPT "" #define ECHO_REQUEST 1 //#define GDB "-g" #define LIBS "bobcat" #define LIBPATH "../../lib" // local namespace is: FBB // using-declarations generated for: std:FBB // qt-mt can be used to select the threaded QT library //#define QT "qt" // NO CONFIGURABLE PARTS BELOW THIS LINE /* V A R S . I M */ string // contain options for cwd, // current WD libs, // extra libs, e.g., "-lrss -licce" libpath, // extra lib-paths, eg, "-L../rss" copt, // Compiler options lopt, // Linker options libxxx, // full library-path ofiles, // wildcards for o-files sources, // sources to be used current, // contains name of current dir. programname; // the name of the program to create int nClasses, // number of classes/subdirectories program; // 1: program is built list classes; // list of classes/directories /* parser.im */ void parser() { #ifdef GRAMBUILD chdir("parser/gramspec"); #ifdef GRAMMAR_LINES system("./grambuild lines"); #else system("./grambuild"); #endif chdir(".."); if ( exists("grammar") && "grammar" younger "parse.cc" ) // new parser needed #ifdef BISON_FLAGS exec("bisonc++", BISON_FLAGS, "grammar"); #else exec("bisonc++", "grammar"); #endif chdir(".."); #endif } /* S C A N N E R . I M */ void scanner() { string interactive; #ifdef INTERACTIVE interactive = "-I"; #endif #ifdef GRAMBUILD chdir("scanner"); if ( // new lexer needed exists("lexer") && ( "lexer" younger "yylex.cc" || ( exists("../parser/parser.h") && "../parser/parser.h" younger "yylex.cc" ) ) ) exec("flex", interactive, "lexer"); chdir(".."); #endif } /* I N I T I A L . I M */ void initialize() { echo(ECHO_REQUEST); sources = "*.cc"; ofiles = "o/*.o"; // std set of o-files copt = COPT; #ifdef GDB copt += " " + GDB; #endif #ifdef BUILD_PROGRAM program = 1; programname = BUILD_PROGRAM; #else program = 0; #endif; cwd = chdir("."); #ifdef GRAMBUILD if (exists("parser")) // subdir parser exists { CLASSES += "parser "; parser(); } if (exists("scanner")) // subdir scanner exists { CLASSES += "scanner "; scanner(); } #endif setClasses(); // remaining classes classes = strtok(CLASSES, " "); // list of classes nClasses = sizeof(classes); } /* O B J F I L E S . I M */ list objfiles(list files) { string file, objfile; int i; for (i = 0; i < sizeof(files); i++) { file = element(i, files); // determine element of the list objfile = "./o/" + change_ext(file, "o"); // make obj-filename if (objfile younger file) // objfile is younger { files -= (list)file; // remove the file from the list i--; // reduce i to test the next } } return (files); } /* A L T E R E D . I M */ list altered(list files, string target) { int i; string file; for (i = 0; i < sizeof(files); i++) // try all elements of the list { file = element(i, files); // use element i of the list if (file older target) // a file is older than the target { files -= (list)file; // remove the file from the list i--; // reduce i to inspect the next } // file of the list } return (files); // return the new list } /* F I L E L I S T . I M */ list file_list(string type, string library) { list files; files = makelist(type); // make all files of certain type #ifdef BUILD_LIBRARY files = altered(files, library); // keep all files newer than lib. #endif files = objfiles(files); // remove if younger .obj exist return (files); } /* L I N K . I M */ void link(string library) { printf("\n"); system("mv ../../lib/libbobcat.so ../../lib/libbobcat.OFF"); exec(COMPILER, "-o", programname, ofiles, libs, "-L.", libpath, lopt #ifndef GDB , "-s" #endif ); system("mv ../../lib/libbobcat.OFF ../../lib/libbobcat.so"); printf("ok: ", programname, "\n"); } /* P R E F I X C L . I M */ void prefix_class(string class_id) { list o_files; string o_file; int i; chdir("o"); o_files = makelist("*.o"); for (i = 0; o_file = element(i, o_files); i++) exec("mv", o_file, class_id + o_file); chdir(".."); } /* R M C L A S S P . I M */ #ifdef BUILD_LIBRARY string rm_class_id(string class_id, string ofile) { string ret; int index, n; n = strlen(ofile); for (index = strlen(class_id); index < n; index++) ret += element(index, ofile); return ret; } #endif void rm_class_prefix(string class_id) { #ifdef BUILD_LIBRARY list o_files; string o_file; int i; chdir("o"); o_files = makelist("*.o"); for (i = 0; o_file = element(i, o_files); i++) exec("mv", o_file, rm_class_id(class_id, o_file)); chdir(".."); #endif } /* C C O M P I L E . I M */ void c_compile(list cfiles) { string nextfile; int i; if (!exists("o")) system("mkdir o"); if (sizeof(cfiles)) // files to compile ? { printf("\ncompiling: ", current, "\n\n"); // compile all files separately for (i = 0; nextfile = element(i, cfiles); i++) exec(COMPILER, "-c -o o/" + change_ext(nextfile, "o"), copt, nextfile); printf("\n"); } printf("ok: ", current, "\n"); } /* U P D A T E L I . I M */ void updatelib(string library) { #ifdef BUILD_LIBRARY list arlist, objlist; string to, from; objlist = makelist("o/*.o"); if (!sizeof(objlist)) return; printf("\n"); exec("ar", "rvs", library, "o/*.o"); exec("rm", "o/*.o"); printf("\n"); #endif } /* S T D C P P . I M */ void std_cpp(string library) { list cfiles; cfiles = file_list(sources, library); // make list of all cpp-files c_compile(cfiles); // compile cpp-files } /* C P P M A K E . C CPP files are processed by stdmake. Arguments of CPPMAKE: cpp_make( string mainfile, : name of the main .cpp file, or "" for library maintenance string library, : name of the local library to use/create (without lib prefix or .a/.so suffix (E.g., use `main' for `libmain.a') ) Both mainfile and library MUST be in the current directory */ void cpp_make(string mainfile, string library) { int index; string class; if (nClasses) ofiles += " */o/*.o"; // set ofiles for no LIBRARY use // make library name #ifdef BUILD_LIBRARY libxxx = chdir(".") + "lib" + library + ".a"; #endif // first process all classes for (index = 0; index < nClasses; index++) { class = element(index, classes); // next class to process chdir(class); // change to directory current = "subdir " + class; #ifdef QT moc(class); // see if we should call moc #endif std_cpp(libxxx); // compile all files chdir(cwd); // go back to parent dir } current = "auxiliary " + sources + " files"; std_cpp(libxxx); // compile all files in current dir #ifdef BUILD_LIBRARY // prefix class-number for .o files for (index = 0; index < nClasses; index++) { current = element(index, classes); // determine class name chdir( current); // chdir to a class directory. prefix_class((string)index); updatelib(libxxx); chdir(cwd); // go back to parent dir } current = ""; // no class anymore updatelib(libxxx); // update lib in current dir #endif if (mainfile != "") // mainfile -> do link { link(library); printf ( "\nProgram construction completed.\n" "\n" ); } } /* S E T L I B S . I M */ void setlibs() { #ifdef LIBS int n, index; list cut; cut = strtok(LIBS, " "); // cut op libraries n = sizeof(cut); for (index = 0; index < n; index++) libs += " -l" + element(index, cut); cut = strtok(LIBPATH, " "); // cut up the paths n = sizeof(cut); for (index = 0; index < n; index++) libpath += " -L" + element(index, cut); #endif } void main() { initialize(); setlibs(); #ifdef BUILD_PROGRAM cpp_make ( "driver.cc", // program source "driver" // static program library ); #else cpp_make ( "", "driver" // static- or so-library ); #endif } bobcat-5.09.01/redirector/driver/driver.cc0000644000175000017500000000062014050437223017341 0ustar frankfrank/* driver.cc */ #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) { Redirector redirector(Redirector::STDOUT); redirector.swallow(Redirector::STDERR); cerr << "This appears at the standard output stream\n" "use `a.out > /dev/null' to suppress this message" << endl; } bobcat-5.09.01/repeat/0000755000175000017500000000000014050437223013364 5ustar frankfrankbobcat-5.09.01/repeat/repeat0000644000175000017500000000172214050437223014571 0ustar frankfrank#ifndef INCLUDED_BOBCAT_REPEAT_ #define INCLUDED_BOBCAT_REPEAT_ #include #include namespace FBB { template struct Repeat__; template <> struct Repeat__ { template static void call(Fun fun, Params &&...params); // 1.f }; template <> struct Repeat__ { template static void call(Class &obj, Member member, Params &&...params); // 2.f template static void call(Class const &obj, Member member, // 3.f Params &&...params); }; template inline void repeat(Counter counter, First &&first, Params &&...params); // .f #include "call1.f" #include "call2.f" #include "call3.f" #include "repeat.f" } // FBB #endif bobcat-5.09.01/repeat/call1.f0000644000175000017500000000023114050437223014523 0ustar frankfranktemplate inline void Repeat__::call(Fun fun, Params &&...params) { fun(std::forward(params)...); } bobcat-5.09.01/repeat/call2.f0000644000175000017500000000037414050437223014534 0ustar frankfranktemplate inline void Repeat__::call(Class &obj, Member member, Params &&...params) { (obj.*member)(std::forward(params)...); } bobcat-5.09.01/repeat/call3.f0000644000175000017500000000040614050437223014531 0ustar frankfranktemplate inline void Repeat__::call(Class const &obj, Member member, Params &&...params) { (obj.*member)(std::forward(params)...); } bobcat-5.09.01/repeat/repeat.f0000644000175000017500000000053114050437223015012 0ustar frankfranktemplate void repeat(Counter counter, First &&first, Params &&...params) { for (; counter; --counter) Repeat__::isClass>::call( std::forward(first), std::forward(params)...); } bobcat-5.09.01/repeat/driver/0000755000175000017500000000000014050437223014657 5ustar frankfrankbobcat-5.09.01/repeat/driver/build0000755000175000017500000000007014050437223015701 0ustar frankfrank#!/bin/bash g++ `cat ../../c++std` -o driver driver.cc bobcat-5.09.01/repeat/driver/driver.cc0000644000175000017500000000240414050437223016461 0ustar frankfrank#include #include #include #include "../repeat" using namespace std; using namespace FBB; class Object { public: void member(int argc, char **argv) const; void member2(size_t &rept, int argc, char **argv); }; void Object::member(int argc, char **argv) const { cout << "member called\n"; copy(argv, argv + argc, ostream_iterator(cout, "\n")); } void Object::member2(size_t &rept, int argc, char **argv) { cout << "member2 called, iteration " << rept++ << "\n"; copy(argv, argv + argc, ostream_iterator(cout, "\n")); } void fun() { cout << "Fun called\n"; } int main(int argc, char **argv) { Object object; cout << "\n" "*** The number of arguments determines the repeat-count ***\n\n"; cout << "Fun without arguments:\n"; repeat(argc, fun); cout << "Object receiving argc and argv:\n"; repeat(argc, object, &Object::member, argc, argv); cout << "Object receiving argc and argv, showing the iteration count:\n"; size_t count = 0; repeat(argc, object, &Object::member2, count, argc, argv); Object const obj; cout << "Const Object receiving argc and argv:\n"; repeat(argc, obj, &Object::member, argc, argv); } bobcat-5.09.01/required0000644000175000017500000000120414050437223013644 0ustar frankfrankThis file lists non-standard software only. Thus, standard utilities like cp, mv, sed, etc, etc, are not explicitly mentioned. Neither is the gcc compiler explicitly mentioned, but a fairly recent one is assumed. Required software for building Bobcat 4.00.00: ---------------------------------------------- libmilter-dev (>= 8.14.4-8), libx11-dev (>= 2:1.6.2-3), libssl-dev, libreadline-dev icmake (>= 8.01.00) For the man-pages: yodl (>= 3.07.01) Note: required libraries are C libraries. Since C does not do name mangling the mentioned (or more recent) libraries should continue to work with Bobcat 4.00.00 bobcat-5.09.01/scripts/0000755000175000017500000000000014050437223013573 5ustar frankfrankbobcat-5.09.01/scripts/check1.20.00000755000175000017500000000103614050437223015235 0ustar frankfrank#!/bin/bash if [ $# -eq 0 ] then echo " Find from the current working directory all files containing the classes Arg Glob OneKey Pipe ServerSocket SocketBase User or Xpointer Run this script with any argument to obtain a list of filenames only. Press Enter to continue and search for files or ^C to abort" read else OPT=-l fi /bin/grep -E $OPT \ '\b(Arg|Glob|OneKey|Pipe|ServerSocket|SocketBase|User|Xpointer)\b'\ `/usr/bin/find . -type f \ -exec /usr/bin/perl -e 'print "{}\n" if -T "{}";' \;` bobcat-5.09.01/selector/0000755000175000017500000000000014050437223013724 5ustar frankfrankbobcat-5.09.01/selector/rmwritefd.f0000644000175000017500000000010614050437223016073 0ustar frankfrankinline void Selector::rmWriteFd(int fd) { FD_CLR(fd, &d_write); } bobcat-5.09.01/selector/writefd.f0000644000175000017500000000014114050437223015533 0ustar frankfrankinline int Selector::writeFd() { return checkSet(&d_writeidx, d_ret_write); } bobcat-5.09.01/selector/addwritefd.f0000644000175000017500000000010614050437223016205 0ustar frankfrankinline void Selector::addWriteFd(int fd) { addFd(&d_write, fd); } bobcat-5.09.01/selector/setalarm.cc0000644000175000017500000000046114050437223016044 0ustar frankfrank#include "selector.ih" void Selector::setAlarm(int sec, int usec) { d_alarm.tv_sec = sec; d_alarm.tv_usec = usec; long long testTime = usec + 1000000LL * sec; if (testTime < 0 || testTime > numeric_limits::max() * 1000000LL) throw Exception{1} << "Selector::setAlarm()"; } bobcat-5.09.01/selector/nready.f0000644000175000017500000000006414050437223015355 0ustar frankfrankinline int Selector::nReady() { return d_ret; } bobcat-5.09.01/selector/addfd.cc0000644000175000017500000000021114050437223015267 0ustar frankfrank#include "selector.ih" void Selector::addFd(fd_set *set, int fd) { FD_SET(fd, set); if (fd >= d_max) d_max = fd + 1; } bobcat-5.09.01/selector/noalarm.f0000644000175000017500000000011714050437223015523 0ustar frankfrankinline void Selector::noAlarm() { d_alarm.tv_sec = d_alarm.tv_usec = -1; } bobcat-5.09.01/selector/exceptfd.f0000644000175000017500000000014514050437223015675 0ustar frankfrankinline int Selector::exceptFd() { return checkSet(&d_exceptidx, d_ret_except); } bobcat-5.09.01/selector/wait.cc0000644000175000017500000000132214050437223015175 0ustar frankfrank#include "selector.ih" int Selector::wait() { timeval t = d_alarm; if ( // no fd available and no waiting // time isEmpty(d_read) and isEmpty(d_write) and isEmpty(d_except) && t.tv_sec == -1 && t.tv_usec == -1 ) return 0; d_ret_read = d_read; d_ret_write = d_write; d_ret_except = d_except; d_readidx = 0; d_writeidx = 0; d_exceptidx = 0; d_ret = select(d_max, &d_ret_read, &d_ret_write, &d_ret_except, t.tv_sec == -1 && t.tv_usec == -1 ? 0 : &t); if (d_ret < 0) throw Exception{} << "Selector::wait()"; return d_ret; } bobcat-5.09.01/selector/checkset.cc0000644000175000017500000000032114050437223016020 0ustar frankfrank#include "selector.ih" int Selector::checkSet(int *index, fd_set const &set) { int &idx = *index; while (idx < d_max && !FD_ISSET(idx, &set)) ++idx; return idx == d_max ? -1 : idx++; } bobcat-5.09.01/selector/isempty.cc0000644000175000017500000000024014050437223015721 0ustar frankfrank#include "selector.ih" // static bool Selector::isEmpty(fd_set const &set) { static fd_set empty; return memcmp(&set, &empty, sizeof(fd_set)) == 0; } bobcat-5.09.01/selector/selector.ih0000644000175000017500000000021014050437223016057 0ustar frankfrank#include "selector" #include #include #include "../exception/exception" using namespace std; using namespace FBB; bobcat-5.09.01/selector/rmexceptfd.f0000644000175000017500000000011014050437223016224 0ustar frankfrankinline void Selector::rmExceptFd(int fd) { FD_CLR(fd, &d_except); } bobcat-5.09.01/selector/addexceptfd.f0000644000175000017500000000011014050437223016336 0ustar frankfrankinline void Selector::addExceptFd(int fd) { addFd(&d_except, fd); } bobcat-5.09.01/selector/selector1.cc0000644000175000017500000000031014050437223016126 0ustar frankfrank/* selector.cc */ #include "selector.ih" Selector::Selector() { FD_ZERO(&d_read); FD_ZERO(&d_write); FD_ZERO(&d_except); noAlarm(); d_max = 0; } bobcat-5.09.01/selector/selector0000644000175000017500000000432114050437223015467 0ustar frankfrank#ifndef INCLUDED_BOBCAT_SELECTOR_ #define INCLUDED_BOBCAT_SELECTOR_ #include namespace FBB { class Selector { fd_set d_read; fd_set d_write; fd_set d_except; fd_set d_ret_read; fd_set d_ret_write; fd_set d_ret_except; timeval d_alarm; int d_max; int d_ret; int d_readidx; int d_writeidx; int d_exceptidx; public: Selector(); int wait(); // nReady() and the get...() members // perform defined behavior only after // wait() returns. int nReady(); // number of available fd's. 0: timeout .f // occurred, -1: select() failed. int exceptFd(); // .f int readFd(); // -1 if no more available .f // descriptors otherwise the next // available fd in each category int writeFd(); // .f void setAlarm(int sec, int usec = 0); void noAlarm(); // .f void addReadFd(int fd); // .f void addWriteFd(int fd); // .f void addExceptFd(int fd); // .f void rmReadFd(int fd); // .f void rmWriteFd(int fd); // .f void rmExceptFd(int fd); // .f private: int checkSet(int *index, fd_set const &set); void addFd(fd_set *set, int fd); static bool isEmpty(fd_set const &set); }; #include "addexceptfd.f" #include "addreadfd.f" #include "addwritefd.f" #include "exceptfd.f" #include "noalarm.f" #include "nready.f" #include "readfd.f" #include "rmexceptfd.f" #include "rmreadfd.f" #include "rmwritefd.f" #include "writefd.f" } // FBB #endif bobcat-5.09.01/selector/rmreadfd.f0000644000175000017500000000010414050437223015652 0ustar frankfrankinline void Selector::rmReadFd(int fd) { FD_CLR(fd, &d_read); } bobcat-5.09.01/selector/readfd.f0000644000175000017500000000011714050437223015317 0ustar frankfrankinline int Selector::readFd() { return checkSet(&d_readidx, d_ret_read); } bobcat-5.09.01/selector/driver/0000755000175000017500000000000014050437223015217 5ustar frankfrankbobcat-5.09.01/selector/driver/build0000755000175000017500000000005614050437223016245 0ustar frankfrank#!/bin/bash g++ -o driver driver.cc -lbobcat bobcat-5.09.01/selector/driver/driver.cc0000644000175000017500000000135714050437223017027 0ustar frankfrank#include #include #include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) try { Selector selector; selector.setAlarm(5); // every 5 secs: alarm fires selector.addReadFd(STDIN_FILENO); // look also at cin while (true) { if (!selector.wait()) // 0: alarm fires cout << "Are you still there?" << endl; else { string s; if (!getline(cin, s) || !s.length()) return 0; cout << "Thank you for: " << s << endl; } } } catch (exception const &e) { cout << e.what() << endl; } bobcat-5.09.01/selector/driver/testempty.cc0000644000175000017500000000075214050437223017570 0ustar frankfrank#include #include #include using namespace std; bool isEmpty(fd_set const *fdset) { static fd_set empty; // initialized to 0 -> empty return memcmp(fdset, &empty, sizeof(fd_set)) == 0; } int main() { fd_set demo; cout << isEmpty(&demo) << '\n'; FD_ZERO(&demo); cout << isEmpty(&demo) << '\n'; FD_SET(1, &demo); cout << isEmpty(&demo) << '\n'; FD_CLR(1, &demo); cout << isEmpty(&demo) << '\n'; } bobcat-5.09.01/selector/addreadfd.f0000644000175000017500000000010414050437223015764 0ustar frankfrankinline void Selector::addReadFd(int fd) { addFd(&d_read, fd); } bobcat-5.09.01/semaphore/0000755000175000017500000000000014050437223014067 5ustar frankfrankbobcat-5.09.01/semaphore/wait2.f0000644000175000017500000000072314050437223015266 0ustar frankfrank template // wait for duration timeunits void Semaphore::wait_for(chrono::duration const &relTime) { unique_lock lk(d_mutex); // get the lock while (d_nAvailable == 0) d_condition.wait(lk); // internally releases the lock // and waits, on exit // acquires the lock again --d_nAvailable; // dec. semaphore } bobcat-5.09.01/semaphore/notify.cc0000644000175000017500000000040114050437223015701 0ustar frankfrank#include "semaphore.ih" void Semaphore::notify() { lock_guard lk(d_mutex); // get the lock if (d_nAvailable++ == 0) d_condition.notify_one(); // use notify_one to notify one other // thread } bobcat-5.09.01/semaphore/notifyall.cc0000644000175000017500000000040514050437223016376 0ustar frankfrank#include "semaphore.ih" void Semaphore::notify_all() { lock_guard lk(d_mutex); // get the lock if (d_nAvailable++ == 0) d_condition.notify_all(); // use notify_one to notify one other // thread } bobcat-5.09.01/semaphore/wait.cc0000644000175000017500000000055414050437223015346 0ustar frankfrank#include "semaphore.ih" void Semaphore::wait() { unique_lock lk(d_mutex); // get the lock while (d_nAvailable == 0) d_condition.wait(lk); // internally releases the lock // and waits, on exit // acquires the lock again --d_nAvailable; // dec. semaphore } bobcat-5.09.01/semaphore/waituntil.f0000644000175000017500000000074114050437223016260 0ustar frankfranktemplate // wait until abs. time std::cv_status Semaphore::wait_until(std::chrono::time_point const &absTime) { std::unique_lock lk(d_mutex); // get the lock while (d_nAvailable == 0) if (d_condition.wait_until(lk, absTime) == std::cv_status::timeout) return std::cv_status::timeout; --d_nAvailable; return std::cv_status::no_timeout; } bobcat-5.09.01/semaphore/waitfun.f0000644000175000017500000000073614050437223015721 0ustar frankfranktemplate bool Semaphore::wait(Fun fun, Params &&...args) { std::unique_lock lk(d_mutex); // get the lock while (d_nAvailable == 0) { d_condition.wait(lk); // see 'wait.cc' // called on notifications if (not fun(std::forward(args)...)) return false; } --d_nAvailable; // dec. semaphore return true; } bobcat-5.09.01/semaphore/waitfor.f0000644000175000017500000000065414050437223015716 0ustar frankfranktemplate std::cv_status Semaphore::wait_for( std::chrono::duration const &relTime) { std::unique_lock lk(d_mutex); // get the lock while (d_nAvailable == 0) if (d_condition.wait_for(lk, relTime) == std::cv_status::timeout) return std::cv_status::timeout; --d_nAvailable; return std::cv_status::no_timeout; } bobcat-5.09.01/semaphore/set.cc0000644000175000017500000000020414050437223015165 0ustar frankfrank#include "semaphore.ih" void Semaphore::set(size_t available) { lock_guard lk(d_mutex); d_nAvailable = available; } bobcat-5.09.01/semaphore/semaphore0000644000175000017500000000257114050437223016002 0ustar frankfrank#ifndef INCLUDED_BOBCAT_SEMAPHORE_ #define INCLUDED_BOBCAT_SEMAPHORE_ #include #include #include namespace FBB { class Semaphore { mutable std::mutex d_mutex; std::condition_variable d_condition; size_t d_nAvailable; public: Semaphore(size_t nAvailable); template bool wait(Fun fun, Params &&...args); // wait # available void wait(); // wait # available // wait for duration timeunits template std::cv_status wait_for(std::chrono::duration const &relTime); // wait until abs. time has been reached template std::cv_status wait_until(std::chrono::time_point const &absTime); void notify(); // notify a single waiting thread if initially 0 void notify_all(); // notify_all # available, notify if initially 0 void set(size_t available = 0); size_t size() const; }; #include "size.f" #include "waitfor.f" #include "waituntil.f" #include "waitfun.f" } // FBB #endif bobcat-5.09.01/semaphore/semaphore1.cc0000644000175000017500000000014314050437223016440 0ustar frankfrank#include "semaphore.ih" Semaphore::Semaphore(size_t nAvailable) : d_nAvailable(nAvailable) {} bobcat-5.09.01/semaphore/size.f0000644000175000017500000000010414050437223015203 0ustar frankfrankinline size_t Semaphore::size() const { return d_nAvailable; } bobcat-5.09.01/semaphore/semaphore.ih0000644000175000017500000000010014050437223016363 0ustar frankfrank#include "semaphore" using namespace std; using namespace FBB; bobcat-5.09.01/sep/0000755000175000017500000000000014050437223012673 5ustar frankfrankbobcat-5.09.01/sep/sep0000644000175000017500000000045614050437223013412 0ustar frankfrank#ifndef INCLUDED_BOBCAT_SEP_ #define INCLUDED_BOBCAT_SEP_ #include namespace FBB { class Sep: private std::string { friend class CSVTabIns; public: Sep(std::string const &sep); }; inline Sep::Sep(std::string const &sep) : std::string(sep) {} } // FBB #endif bobcat-5.09.01/serversocket/0000755000175000017500000000000014050437223014623 5ustar frankfrankbobcat-5.09.01/serversocket/serversocket.ih0000644000175000017500000000027514050437223017670 0ustar frankfrank#include "serversocket" #include #include #include #include #include "../exception/exception" using namespace std; using namespace FBB; bobcat-5.09.01/serversocket/serversocket1.cc0000644000175000017500000000102114050437223017724 0ustar frankfrank#include "serversocket.ih" ServerSocket::ServerSocket(size_t port) : SocketBase(port), // uses INADDR_ANY -> current host. d_msg(0) { int val = 1; // Make sure the socket is reusable upon restarts if (setsockopt(socket(), SOL_SOCKET, SO_REUSEADDR, &val, sizeof(int))) { d_msg = "ServerSocket::ServerSocket(port) setsockopt() failed"; return; } if (bind(socket(), sockaddrPtr(), size()) < 0) d_msg = "ServerSocket::ServerSocket(port)"; } bobcat-5.09.01/serversocket/accept.cc0000644000175000017500000000067114050437223016375 0ustar frankfrank#include "serversocket.ih" SocketBase ServerSocket::accept() { sockaddr_in address; socklen_t size = sizeof(address); int sock = ::accept ( socket(), reinterpret_cast(&address), &size ); if (sock < 0) throw Exception{} << "ServerSocket::accept(): " << errnodescr; return makeBase(sock, address); } bobcat-5.09.01/serversocket/serversocket0000644000175000017500000000060614050437223017267 0ustar frankfrank#ifndef INCLUDED_BOBCAT_SERVERSOCKET_ #define INCLUDED_BOBCAT_SERVERSOCKET_ #include #include namespace FBB { class ServerSocket: public SocketBase { int d_err; char const *d_msg; public: explicit ServerSocket(size_t port); void listen(size_t backlog = 5, bool blocking = true); SocketBase accept(); }; } // FBB #endif bobcat-5.09.01/serversocket/listen.cc0000644000175000017500000000107714050437223016435 0ustar frankfrank#include "serversocket.ih" void ServerSocket::listen(size_t backlog, bool blocking) { static char name[] = "ServerSocket::listen()"; if (d_msg) throw Exception{1} << d_msg; int sock = socket(); if (::listen(sock, backlog) < 0) throw Exception{} << name << ": " << errnodescr; if (blocking) return; if ( fcntl ( sock, F_SETFL, fcntl(sock, F_GETFL, 0) | O_NONBLOCK ) == -1 ) throw Exception{} << name << ": " << errnodescr; } bobcat-5.09.01/serversocket/driver/0000755000175000017500000000000014050437223016116 5ustar frankfrankbobcat-5.09.01/serversocket/driver/build0000755000175000017500000000017114050437223017142 0ustar frankfrank#!/bin/bash tput clear GPP="g++ `cat ../../c++std`" CMD="$GPP -o server -Wall server.cc -lbobcat -s" echo $CMD $CMD bobcat-5.09.01/serversocket/driver/server.cc0000644000175000017500000000604014050437223017733 0ustar frankfrank#include #include #include #include using namespace std; using namespace FBB; class IBuf: public FBB::IFilterBuf { std::istream *d_in; char d_key[sizeof(unsigned long)]; size_t d_idx = 0; size_t const d_maxSize = 100; IBuf(unsigned long addr, uint16_t port); bool filter(char const **srcBegin, char const **srcEnd) override; }; IBuf::IBuf(std::istream &in, unsigned long addr, uint16_t port) : d_in(in), d_key(reinterpret_cast(&addr), reinterpret_cast(&addr + sizeof(long)), { char const *cp = reinterpret_cast(&port); for (auto &ch: d_key) { ch ^= } bool IBuf::filter(char const **srcBegin, char const **srcEnd) { d_buffer.clear(); while (d_buffer.size() != d_maxSize) { char ch; if (not d_in.get(ch)) break; ch ^= d_key[d_idx++]; d_idx %= sizeof(unsigned long); d_buffer.push_back(ch); } if (d_buffer.empty()) return false; *srcBegin = d_buffer.data(); *srcEnd = d_buffer.data() + d_buffer.size(); return true; } int main(int argc, char **argv) try { if (argc == 1) { cerr << "Provide server port number\n"; return 1; } size_t portnr = stoul(argv[1]); ServerSocket server(portnr); cerr << "server listens on port " << argv[1] << endl; cerr << "serversocket returns:\n" << "address = " << server.dottedDecimalAddress() << endl << "port = " << server.port() << endl; int fd = server.socket(); // open the socket's descriptor cout << "File descriptor of the socket is " << fd << endl << "The server terminates when it receives a single `q' on a line\n" "A connection is terminated when no input is received anymore.\n" "Then another connection is possible" << endl; server.listen(); // listen in blocking mode while (true) { SocketBase const fdb = server.accept(); int fd = fdb.socket(); unsigned long addr = fdb.sockaddr_inPtr()->sin_addr.s_addr; cerr << "Client FD = " << fd << ", " << endl << "address = " << fdb.dottedDecimalAddress() << ", (" << addr << ")\n" "communication through port " << fdb.port() << endl; IFdStream in(fd); // stream to read from client OFdStream out(fd); // stream to write to client string cmd; out << (unsigned long)(fdb.port() ^ addr) << endl; while (getline(in, cmd)) { cout << "Got: " << cmd << endl; out << "Got: " << cmd << "\r" << endl; if (cmd[0] == 'q') return 0; } cout << "Ready for another connection\n"; } } catch (exception const &err) { cerr << err.what() << endl << "Server socket on port " << argv[1] << " can't be opened" << endl; return -1; } bobcat-5.09.01/sharedblock/0000755000175000017500000000000014050437223014365 5ustar frankfrankbobcat-5.09.01/sharedblock/sharedblock.ih0000644000175000017500000000010214050437223017161 0ustar frankfrank#include "sharedblock" using namespace std; using namespace FBB; bobcat-5.09.01/sharedblock/sharedblock0000644000175000017500000000062614050437223016575 0ustar frankfrank#ifndef INCLUDED_BOBCAT_SHAREDBLOCK_ #define INCLUDED_BOBCAT_SHAREDBLOCK_ #include namespace FBB { class SharedBlock { SharedMutex d_mutex; int d_id = -1; public: int id() const; void lock(); void setID(int id); void unlock(); }; #include "id.f" #include "setid.f" #include "lock.f" #include "unlock.f" } // FBB #endif bobcat-5.09.01/sharedblock/lock.f0000644000175000017500000000007014050437223015461 0ustar frankfrankinline void SharedBlock::lock() { d_mutex.lock(); } bobcat-5.09.01/sharedblock/unlock.f0000644000175000017500000000007414050437223016030 0ustar frankfrankinline void SharedBlock::unlock() { d_mutex.unlock(); } bobcat-5.09.01/sharedblock/setid.f0000644000175000017500000000007214050437223015643 0ustar frankfrankinline void SharedBlock::setID(int id) { d_id = id; } bobcat-5.09.01/sharedblock/id.f0000644000175000017500000000007014050437223015125 0ustar frankfrankinline int SharedBlock::id() const { return d_id; } bobcat-5.09.01/sharedbuf/0000755000175000017500000000000014050437223014047 5ustar frankfrankbobcat-5.09.01/sharedbuf/xsputn.cc0000644000175000017500000000024114050437223015714 0ustar frankfrank#include "sharedbuf.ih" std::streamsize SharedBuf::xsputn(char const *buf, std::streamsize len) { return mode(ios::out) ? d_memory.write(buf, len) : EOF; } bobcat-5.09.01/sharedbuf/showmanyc.cc0000644000175000017500000000014014050437223016361 0ustar frankfrank#include "sharedbuf.ih" streamsize SharedBuf::showmanyc() { return d_memory.showmanyc(); } bobcat-5.09.01/sharedbuf/overflow.cc0000644000175000017500000000016114050437223016217 0ustar frankfrank#include "sharedbuf.ih" int SharedBuf::overflow(int ch) { return mode(ios::out) ? d_memory.put(ch) : EOF; } bobcat-5.09.01/sharedbuf/sharedbuf1.cc0000644000175000017500000000026114050437223016401 0ustar frankfrank#include "sharedbuf.ih" SharedBuf::SharedBuf() : d_openMode(static_cast(0)), d_currentMode(d_openMode) { setg(0, 0, 0); setp(0, 0); } bobcat-5.09.01/sharedbuf/clear.f0000644000175000017500000000007214050437223015303 0ustar frankfrankinline void SharedBuf::clear() { d_memory.clear(); } bobcat-5.09.01/sharedbuf/pbackfail.cc0000644000175000017500000000034414050437223016273 0ustar frankfrank#include "sharedbuf.ih" int SharedBuf::pbackfail(int ch) { if (seekoff(-1) == -1) ch = EOF; else if (*d_memory.ptr() != ch) { seekoff(+1); // undo the seek ch = EOF; } return ch; } bobcat-5.09.01/sharedbuf/remove.f0000644000175000017500000000007314050437223015513 0ustar frankfrankinline void SharedBuf::remove() { d_memory.remove(); } bobcat-5.09.01/sharedbuf/xsgetn.cc0000644000175000017500000000022114050437223015661 0ustar frankfrank#include "sharedbuf.ih" streamsize SharedBuf::xsgetn(char *data, streamsize len) { return mode(ios::in) ? d_memory.read(data, len) : EOF; } bobcat-5.09.01/sharedbuf/kill.f0000644000175000017500000000006714050437223015154 0ustar frankfrankinline void SharedBuf::kill() { d_memory.kill(); } bobcat-5.09.01/sharedbuf/createsharedcondition.cc0000644000175000017500000000035114050437223020716 0ustar frankfrank#include "sharedbuf.ih" SharedCondition SharedBuf::createSharedCondition() { auto sharedCondition(SharedCondition::create(d_memory)); seekoff(sharedCondition.offset() + sharedCondition.size()); return sharedCondition; } bobcat-5.09.01/sharedbuf/meminfo.f0000644000175000017500000000012114050437223015642 0ustar frankfrankinline void SharedBuf::memInfo(std::ostream &out) const { out << d_memory; } bobcat-5.09.01/sharedbuf/setmemory.f0000644000175000017500000000013014050437223016234 0ustar frankfrankinline void SharedBuf::setMemory(SharedMemory &&tmp) { d_memory = std::move(tmp); } bobcat-5.09.01/sharedbuf/sharedbuf.ih0000644000175000017500000000010014050437223016323 0ustar frankfrank#include "sharedbuf" using namespace std; using namespace FBB; bobcat-5.09.01/sharedbuf/mode.cc0000644000175000017500000000025414050437223015303 0ustar frankfrank#include "sharedbuf.ih" bool SharedBuf::mode(ios::openmode flag) { if (not (d_currentMode & flag)) return false; d_currentMode = flag; return true; } bobcat-5.09.01/sharedbuf/setopenmode.f0000644000175000017500000000017514050437223016543 0ustar frankfrankinline void SharedBuf::setOpenMode(std::ios::openmode openMode) { d_openMode = openMode; d_currentMode = openMode; } bobcat-5.09.01/sharedbuf/seekoff.cc0000644000175000017500000000041614050437223016001 0ustar frankfrank#include "sharedbuf.ih" ios::pos_type SharedBuf::seekoff( ios::off_type offset, ios::seekdir way, ios::openmode mode) { offset = d_memory.seek(offset, way); if (offset != -1) d_currentMode = mode; return offset; } bobcat-5.09.01/sharedbuf/sharedbuf0000644000175000017500000000542014050437223015736 0ustar frankfrank#ifndef INCLUDED_BOBCAT_SHAREDBUF_ #define INCLUDED_BOBCAT_SHAREDBUF_ #include #include #include #include namespace FBB { class SharedBuf: public std::streambuf, public virtual SharedEnum__ { std::ios::openmode d_openMode; std::ios::openmode d_currentMode; // initially openMode, thereafter // either ::in or ::out SharedMemory d_memory; public: SharedBuf(); // 1 SharedBuf( size_t maxSize, SizeUnit sizeUnit, // 2 std::ios::openmode openMode = std::ios::in | std::ios::out, size_t access = 0600); SharedBuf( // 3 int id, std::ios::openmode openMode = std::ios::in | std::ios::out); void clear(); // clear all existing data and reduce // until only the segment at // d_sharedData int id() const; // id of the shared Memory segment void kill(); // kill all shared segments w/o locks // the object is unusable hereafter void memInfo(std::ostream &out) const; void remove(); // remove all shared segments. // the object is unusable hereafter void setMemory(SharedMemory &&tmp); protected: SharedCondition attachSharedCondition(std::ios::off_type offset = 0, std::ios::seekdir way = std::ios::beg); SharedCondition createSharedCondition(); void setOpenMode(std::ios::openmode openMode); SharedMemory &sharedMemory(); private: bool mode(std::ios::openmode flag); int pbackfail(int ch) override; std::streamsize showmanyc() override; int underflow() override; std::streamsize xsgetn(char *buf, std::streamsize n) override; int overflow(int c) override; std::streamsize xsputn(char const *buf, std::streamsize n) override; std::ios::pos_type seekoff( std::ios::off_type offset, std::ios::seekdir way = std::ios::beg, std::ios::openmode mode = std::ios::in | std::ios::out) override; std::ios::pos_type seekpos( std::ios::pos_type offset, std::ios::openmode mode = std::ios::in | std::ios::out) override; }; #include "clear.f" #include "id.f" #include "kill.f" #include "meminfo.f" #include "remove.f" #include "setmemory.f" #include "setopenmode.f" #include "sharedmemory.f" } // FBB #endif bobcat-5.09.01/sharedbuf/sharedbuf3.cc0000644000175000017500000000056114050437223016406 0ustar frankfrank#include "sharedbuf.ih" SharedBuf::SharedBuf(int id, std::ios::openmode openMode) : d_openMode(openMode), d_currentMode(openMode & (ios::in | ios::out)), d_memory(id) { if ( openMode & ios::trunc || (openMode & ios::out and not (openMode & ios::in)) ) d_memory.clear(); setg(0, 0, 0); setp(0, 0); } bobcat-5.09.01/sharedbuf/attachsharedcondition.cc0000644000175000017500000000056714050437223020730 0ustar frankfrank#include "sharedbuf.ih" SharedCondition SharedBuf::attachSharedCondition( std::ios::off_type offset, std::ios::seekdir way) { auto sharedCondition(SharedCondition::attach(d_memory, offset, way)); seekoff(sharedCondition.offset() + sharedCondition.size()); return sharedCondition; } bobcat-5.09.01/sharedbuf/sharedbuf2.cc0000644000175000017500000000051314050437223016402 0ustar frankfrank#include "sharedbuf.ih" SharedBuf::SharedBuf( size_t maxSize, SharedMemory::SizeUnit sizeUnit, std::ios::openmode openMode, size_t access) : d_openMode(openMode), d_currentMode(openMode & (ios::in | ios::out)), d_memory(maxSize, sizeUnit, access) { setg(0, 0, 0); setp(0, 0); } bobcat-5.09.01/sharedbuf/underflow.cc0000644000175000017500000000035314050437223016364 0ustar frankfrank#include "sharedbuf.ih" int SharedBuf::underflow() { static char buf; int ret = mode(ios::in) ? d_memory.get() : EOF; if (ret != EOF) { buf = ret; setg(&buf, &buf, &buf + 1); } return ret; } bobcat-5.09.01/sharedbuf/seekpos.cc0000644000175000017500000000027414050437223016032 0ustar frankfrank#include "sharedbuf.ih" ios::pos_type SharedBuf::seekpos(ios::pos_type offset, ios::openmode mode) { return seekoff(offset, ios::beg, mode); } bobcat-5.09.01/sharedbuf/sharedmemory.f0000644000175000017500000000011014050437223016705 0ustar frankfrankinline SharedMemory &SharedBuf::sharedMemory() { return d_memory; } bobcat-5.09.01/sharedbuf/id.f0000644000175000017500000000007714050437223014616 0ustar frankfrankinline int SharedBuf::id() const { return d_memory.id(); } bobcat-5.09.01/sharedbuf/driver/0000755000175000017500000000000014050437223015342 5ustar frankfrankbobcat-5.09.01/sharedbuf/driver/build0000755000175000017500000000013314050437223016364 0ustar frankfrank#!/bin/bash g++ `cat ../../c++std` -o driver -I.. driver.cc -L../tmp -lsharedbuf -lbobcat bobcat-5.09.01/sharedbuf/driver/driver.cc0000644000175000017500000000510614050437223017146 0ustar frankfrank#include #include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) try { if (argc == 1) { cout << "argument i shows info about the shared memory segment id\n" "argument W uses write() to write info to a shared stream,\n" " displaying its id\n" "argument w writes info to a shared stream, displaying its id\n" "argument R use read() to read info from shared stream \n" "argument r reads the written info from shared stream \n" "argument k kills shared memory segment \n"; return 0; } SharedBuf buf; switch (argv[1][0]) { case 'W': { buf.setMemory(SharedMemory(1, SharedMemory::SizeUnit::kB)); ostream out(&buf); string text = "hello world\n"; out.seekp(0); out.write(text.data(), text.length()); cout << "Memory id = " << buf.id() << '\n'; break; } case 'w': { buf.setMemory(SharedMemory(1, SharedMemory::SizeUnit::kB)); ostream out(&buf); out.seekp(0, ios::end); out << "hello world\n"; cout << "Memory id = " << buf.id() << '\n'; break; } case 'R': { buf.setMemory(SharedMemory(stoul(argv[2]))); istream in(&buf); char buffer[100]; in.seekg(0); // essential! in.read(buffer, 99); buffer[in.gcount()] = 0; cout << "Raw read returns `" << buffer << "'\n" "now at offset " << in.tellg() << ", having read " << in.gcount() << " chars.\n"; break; } case 'r': { buf.setMemory(SharedMemory(stoul(argv[2]))); istream in(&buf); in.seekg(0); // essential! string text; getline(in, text); cout << "read returns `" << text << "'\n" "now at offset " << in.tellg() << "\n"; break; } case 'i': { buf.setMemory(SharedMemory(stoul(argv[2]))); buf.memInfo(cout); break; } case 'k': { SharedMemory(stoul(argv[2])).kill(); break; } } } catch (exception const &exc) { cout << "Exc.: " << exc.what() << '\n'; return 1; } bobcat-5.09.01/sharedbuf/driver/bobcat0000777000175000017500000000000014050437223016652 2..ustar frankfrankbobcat-5.09.01/sharedcondition/0000755000175000017500000000000014050437223015261 5ustar frankfrankbobcat-5.09.01/sharedcondition/wait2.f0000644000175000017500000000041414050437223016455 0ustar frankfranktemplate void SharedCondition::wait(Predicate pred) { Data data = prepare(); while (not pred()) pthread_cond_wait(&(data.condition->d_cond), data.condition->mutexPtr()); d_shmem->seek(data.offset); } bobcat-5.09.01/sharedcondition/notify.cc0000644000175000017500000000027214050437223017101 0ustar frankfrank#include "sharedcondition.ih" void SharedCondition::notify() noexcept { Data data = prepare(); pthread_cond_signal(&(data.condition->d_cond)); d_shmem->seek(data.offset); } bobcat-5.09.01/sharedcondition/waitfor2.f0000644000175000017500000000041514050437223017165 0ustar frankfranktemplate inline bool SharedCondition::wait_for( std::chrono::duration const &relTime, Predicate pred) { return wait_until(std::chrono::system_clock::now() + relTime, pred); } bobcat-5.09.01/sharedcondition/condition1.cc0000644000175000017500000000040614050437223017637 0ustar frankfrank#include "sharedcondition.ih" SharedCondition::Condition::Condition() { pthread_condattr_t cond_attr; pthread_condattr_init(&cond_attr); pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED); pthread_cond_init(&d_cond, &cond_attr); } bobcat-5.09.01/sharedcondition/prepare.cc0000644000175000017500000000051014050437223017222 0ustar frankfrank#include "sharedcondition.ih" SharedCondition::Data SharedCondition::prepare() { if (d_shmem == 0) throw Exception{} << "SharedCondition object not initialized"; Data data {d_shmem->offset()}; d_shmem->seek(d_offset); data.condition = reinterpret_cast(d_shmem->ptr()); return data; } bobcat-5.09.01/sharedcondition/notifyall.cc0000644000175000017500000000027614050437223017576 0ustar frankfrank#include "sharedcondition.ih" void SharedCondition::notifyAll() noexcept { Data data = prepare(); pthread_cond_broadcast(&data.condition->d_cond); d_shmem->seek(data.offset); } bobcat-5.09.01/sharedcondition/wait.cc0000644000175000017500000000031114050437223016527 0ustar frankfrank#include "sharedcondition.ih" void SharedCondition::wait() { Data data = prepare(); pthread_cond_wait(&(data.condition->d_cond), data.condition->mutexPtr()); d_shmem->seek(data.offset); } bobcat-5.09.01/sharedcondition/offset.f0000644000175000017500000000012014050437223016707 0ustar frankfrankinline std::streamsize SharedCondition::offset() const { return d_offset; } bobcat-5.09.01/sharedcondition/sharedcondition.ih0000644000175000017500000000015114050437223020755 0ustar frankfrank#include "sharedcondition" #include "../exception/exception" using namespace std; using namespace FBB; bobcat-5.09.01/sharedcondition/readattach.cc0000644000175000017500000000000014050437223017656 0ustar frankfrankbobcat-5.09.01/sharedcondition/lock.cc0000644000175000017500000000023014050437223016513 0ustar frankfrank#include "sharedcondition.ih" void SharedCondition::lock() { Data data = prepare(); data.condition->lock(); d_shmem->seek(data.offset); } bobcat-5.09.01/sharedcondition/unlock.cc0000644000175000017500000000023414050437223017062 0ustar frankfrank#include "sharedcondition.ih" void SharedCondition::unlock() { Data data = prepare(); data.condition->unlock(); d_shmem->seek(data.offset); } bobcat-5.09.01/sharedcondition/size.f0000644000175000017500000000011314050437223016375 0ustar frankfrankconstexpr size_t SharedCondition::size() { return sizeof(Condition); } bobcat-5.09.01/sharedcondition/destructor.cc0000644000175000017500000000015314050437223017765 0ustar frankfrank#include "sharedcondition.ih" SharedCondition::~SharedCondition() { if (d_shmem) unlock(); } bobcat-5.09.01/sharedcondition/sharedcondition0000644000175000017500000000500714050437223020363 0ustar frankfrank#ifndef INCLUDED_BOBCAT_SHAREDCONDITION_ #define INCLUDED_BOBCAT_SHAREDCONDITION_ #include #include #include #include #include namespace FBB { class SharedCondition { SharedMemory *d_shmem; // Note: not allocated std::streamsize d_offset; struct Condition: private SharedMutex { Condition(); pthread_cond_t d_cond; using SharedMutex::lock; using SharedMutex::unlock; using SharedMutex::mutexPtr; }; struct Data { std::streamsize offset; Condition *condition; }; public: SharedCondition(); ~SharedCondition(); void lock(); void notify() noexcept; void notifyAll() noexcept; std::streamsize offset() const; void unlock(); void wait(); template void wait(Predicate pred); // 2.f template // 1.f std::cv_status wait_for( std::chrono::duration const &relTime ); // 2.f template bool wait_for( std::chrono::duration const &relTime, Predicate pred ); template // 1.f std::cv_status wait_until( std::chrono::time_point const &absTime ); // 2.f template bool wait_until( std::chrono::time_point const &absTime, Predicate pred ); static SharedCondition attach(SharedMemory &shmem, std::ios::off_type offset = 0, std::ios::seekdir way = std::ios::beg); static SharedCondition create(SharedMemory &shmem); static constexpr size_t size(); private: SharedCondition(SharedMemory &shmem, std::streamsize offset); std::cv_status waiter(Condition *cond, int64_t count); Data prepare(); }; #include "offset.f" #include "wait2.f" #include "waitfor1.f" #include "waitfor2.f" #include "waituntil1.f" #include "waituntil2.f" #include "size.f" } // FBB #endif bobcat-5.09.01/sharedcondition/create.cc0000644000175000017500000000052714050437223017037 0ustar frankfrank#include "sharedcondition.ih" SharedCondition SharedCondition::create(SharedMemory &shmem) { std::streamsize offset; shmem.install(&offset); // return the SharedCondition object, which knows about the shared // memory and the Condition's offset return SharedCondition(shmem, offset); } bobcat-5.09.01/sharedcondition/waiter.cc0000644000175000017500000000065214050437223017066 0ustar frankfrank#include "sharedcondition.ih" cv_status SharedCondition::waiter(Condition *cond, int64_t count) { struct timespec timeSpec{ static_cast(count / 1000000000LL), static_cast(count % 1000000000LL) }; int ret = pthread_cond_timedwait(&cond->d_cond, cond->mutexPtr(), &timeSpec); return ret == 0 ? cv_status::no_timeout : cv_status::timeout; } bobcat-5.09.01/sharedcondition/sharedcondition2.cc0000644000175000017500000000023414050437223021026 0ustar frankfrank#include "sharedcondition.ih" SharedCondition::SharedCondition(SharedMemory &shmem, std::streamsize offset) : d_shmem(&shmem), d_offset(offset) {} bobcat-5.09.01/sharedcondition/waituntil1.f0000644000175000017500000000051014050437223017525 0ustar frankfranktemplate std::cv_status SharedCondition::wait_until( std::chrono::time_point const &absTime) { Data data = prepare(); auto ret = waiter(data.condition, absTime.time_since_epoch().count()); d_shmem->seek(data.offset); return ret; } bobcat-5.09.01/sharedcondition/waitfor1.f0000644000175000017500000000034014050437223017161 0ustar frankfranktemplate inline std::cv_status SharedCondition::wait_for( std::chrono::duration const &relTime) { return wait_until(std::chrono::system_clock::now() + relTime); } bobcat-5.09.01/sharedcondition/waituntil2.f0000644000175000017500000000101314050437223017525 0ustar frankfranktemplate bool SharedCondition::wait_until( std::chrono::time_point const &absTime, Predicate pred) { Data data = prepare(); bool ret = true; while (not pred()) { if (waiter(data.condition, absTime.time_since_epoch().count()) == std::cv_status::timeout ) { ret = pred(); break; } } d_shmem->seek(data.offset); return ret; } bobcat-5.09.01/sharedcondition/attach.cc0000644000175000017500000000060414050437223017034 0ustar frankfrank#include "sharedcondition.ih" SharedCondition SharedCondition::attach(SharedMemory &shmem, std::ios::off_type offset, std::ios::seekdir way) { streamsize currentOffset = shmem.offset(); SharedCondition ret(shmem, shmem.seek(offset, way)); shmem.seek(currentOffset); return ret; } bobcat-5.09.01/sharedcondition/sharedcondition1.cc0000644000175000017500000000014714050437223021030 0ustar frankfrank#include "sharedcondition.ih" SharedCondition::SharedCondition() : d_shmem(0), d_offset(0) {} bobcat-5.09.01/sharedcondition/driver/0000755000175000017500000000000014050437223016554 5ustar frankfrankbobcat-5.09.01/sharedcondition/driver/build0000755000175000017500000000024114050437223017576 0ustar frankfrank#!/bin/bash #g++ `cat ../../c++std` -pthread -o driver --static driver.cc -L../../tmp/lib -lbobcat g++ `cat ../../c++std` -pthread -o driver driver.cc -lbobcat bobcat-5.09.01/sharedcondition/driver/driver.cc0000644000175000017500000000553114050437223020362 0ustar frankfrank#include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) try { if (argc == 1) { cout << "Argument:\n" " c: create a shared memory segment + SharedCondition " ", display ID\n" " k : kill shared memory segment \n" " m : show a message every 5 secs, otherwise wait until\n" " being notified in segment \n" " n : notify the SharedCondition in segment ID \n" ; return 0; } switch (argv[1][0]) { case 'c': { SharedMemory shmem(1, SharedMemory::kB); SharedCondition cond = SharedCondition::create(shmem); void *ptr = shmem.ptr(); cout << "ID = " << shmem.id() << ", SharedCondition at " << cond.offset() << endl; break; } case 'k': { SharedMemory shmem(stoll(argv[2])); shmem.kill(); break; } case 'm': { SharedMemory shmem(stoll(argv[2])); SharedCondition cond = SharedCondition::attach(shmem); cond.lock(); cout << "Obtained the lock. Now waiting for a notification\n"; while (true) { switch (cond.wait_for(chrono::seconds(5))) { case cv_status::timeout: cout << "Waited for 5 seconds\n\n"; break; case cv_status::no_timeout: cond.unlock(); cout << "Received the notification. Unlocked.\n"; return 0; } } } case 'w': { SharedMemory shmem(stoll(argv[2])); SharedCondition cond = SharedCondition::attach(shmem); cond.lock(); cout << "Obtained the lock. Now waiting for a notification\n"; cond.wait(); cout << "Received the notification. Unlocking.\n"; cond.unlock(); break; } case 'n': { SharedMemory shmem(stoll(argv[2])); SharedCondition cond = SharedCondition::attach(shmem); cout << "Notifying the other after Enter "; cin.ignore(1000, '\n'); cond.lock(); cout << "Obtained the lock. Now notifying the other\n"; cond.notify(); cout << "Sent the notification. Now unlocking.\n"; cond.unlock(); break; } } } catch (exception const &exc) { cout << "Exception: " << exc.what() << endl; } bobcat-5.09.01/sharedmemory/0000755000175000017500000000000014050437223014603 5ustar frankfrankbobcat-5.09.01/sharedmemory/put.cc0000644000175000017500000000052214050437223015721 0ustar frankfrank#include "sharedmemory.ih" int SharedMemory::put(int ch) { char *cp = ptr(); // ptr() loads the proper data segment if (cp == 0) return EOF; lock(d_pos.blockIdx()); *cp = ch; ++d_pos; unlock(d_pos.blockIdx()); d_sharedSegment->updateNreadable(d_pos.offset()); return ch; } bobcat-5.09.01/sharedmemory/lockall.cc0000644000175000017500000000054414050437223016536 0ustar frankfrank#include "sharedmemory.ih" // unchecked: d_lockCount should be 0 void SharedMemory::lockAll() { for ( size_t idx = 0, end = d_sharedSegment->nBlocks(); idx != end; ++idx ) lock(idx); //cerr << "locking shared segment\n"; d_sharedSegment->nReadableLock(); //cerr << "lockAll done\n"; } bobcat-5.09.01/sharedmemory/showmanyc.cc0000644000175000017500000000016614050437223017125 0ustar frankfrank#include "sharedmemory.ih" streamsize SharedMemory::showmanyc() { return d_pos.eof() ? 0 : d_pos.showmanyc(); } bobcat-5.09.01/sharedmemory/get.cc0000644000175000017500000000050214050437223015666 0ustar frankfrank#include "sharedmemory.ih" int SharedMemory::get() { int ret; validate(); map(); if (d_pos.eof()) ret = EOF; else { lock(d_pos.blockIdx()); ret = static_cast(*ptr()); ++d_pos; unlock(d_pos.blockIdx()); } return ret; } bobcat-5.09.01/sharedmemory/seek.cc0000644000175000017500000000021614050437223016040 0ustar frankfrank#include "sharedmemory.ih" ios::pos_type SharedMemory::seek(ios::off_type offset, ios::seekdir way) { return d_pos.seek(offset, way); } bobcat-5.09.01/sharedmemory/insert.cc0000644000175000017500000000106014050437223016413 0ustar frankfrank#include "sharedmemory.ih" ostream &SharedMemory::insert(ostream &out) const { if (d_sharedSegment == 0) return out << "No shared data available"; out << "ID of shared memory segment: " << d_id << '\n'; if (d_data == 0) out << "No shared memory data block attached\n"; else out << "Shared memory block attached at address " << static_cast(d_data) << ", block index = " << d_pos.blockIdx() << '\n'; return out << *d_sharedSegment << '\n' << d_pos; } bobcat-5.09.01/sharedmemory/operatorassign.f0000644000175000017500000000014614050437223020013 0ustar frankfrankinline SharedMemory &SharedMemory::operator=(SharedMemory &&tmp) { swap(tmp); return *this; } bobcat-5.09.01/sharedmemory/sharedmemory0000644000175000017500000001350714050437223017233 0ustar frankfrank#ifndef INCLUDED_BOBCAT_SHAREDMEMORY_ #define INCLUDED_BOBCAT_SHAREDMEMORY_ #include #include #include #include namespace FBB { class SharedSegment; struct SharedEnum__ { enum SizeUnit { kB = 10, MB = 20, GB = 30 }; }; class SharedMemory: public virtual SharedEnum__ { friend std::ostream &operator<<(std::ostream &out, SharedMemory const &mem); static size_t const s_pageSize = 1 << 12; // updated by the non-default constructors. int d_id = -1; // id of SharedSegment SharedSegment *d_sharedSegment = 0; // points to the attached shared // memory. This is NOT a pointer // to dynamically allocated memory // but a static_cast pointer to // the attached shared data segment SharedPos d_pos; size_t d_lockCount = 0; // # of nested locks char *d_data = 0; // pointer to shared memory data public: SharedMemory() = default; SharedMemory(SharedMemory const &other) = delete; SharedMemory(size_t maxSize, SizeUnit sizeUnit, size_t access = 0600); // 2: creation mode; SharedMemory(int id); // 3 ~SharedMemory(); SharedMemory &operator=(SharedMemory &&tmp); std::streamsize blockOffset() const;// offset matching offset(), // relative to the current data // block. void clear(); // clear all existing data and reduce // until only the segment at // d_sharedSegment size_t dataSegmentSize() const; int get(); // get char from d_segmentData // locks), or EOF int id() const; // id of the d_sharedSegment segment // after kill/remove: shared segment is unusable void kill(); // delete all shared segments w/o locks std::streamsize maxOffset() const; std::streamsize nReadable() const; // beyond last readable byte std::streamsize offset() const; // read/write offset relative to // ios::beg char *ptr(); // 0 if at maxOffset int put(int ch); // put char at d_offset (locks), // ch == EOF immediately returns EOF // read len chars, return nRead or -1, // locks int read(char *data, std::streamsize len); template int read(Type *value); // 1.f template // 2.f int read(std::ios::off_type offset, Type *value, std::ios::seekdir origin = std::ios::beg); // after kill/remove: shared segment is unusable void remove(); // delete all shared segments. // returns -1 if inaccessible std::ios::pos_type seek(std::ios::off_type offset, std::ios::seekdir origin = std::ios::beg); std::streamsize showmanyc(); void swap(SharedMemory &other); bool truncate(std::streamsize offset); // nReadable is reduced to // offset // write len bytes at d_offset // locks, returns #written or -1 int write(char const *data, std::streamsize len); template int write(Type const *value); // 1.f template // 2.f int write(std::ios::off_type offset, Type const *value, std::ios::seekdir origin = std::ios::beg); template SharedType *install(std::streamsize *offset, Params &&...params); private: std::ostream &insert(std::ostream &out) const; // lockAll: d_lockCount should be 0. void lockAll(); // lock all block[] mutexes void unlockAll(); // unlock all block[] mutexes void lock(size_t idx); // (recursively) lock block idx void unlock(size_t idx); // unlock block idx void clearAll(); // clear without locking bool blockAvailable(size_t idx); void map(); // 1 maps shared data to d_data void map(size_t idx); // 2 only called by load int writeBlock(char const *data, size_t len); // locks, returns // #written or -1 int readBlock(char *data, size_t len); // same, but now reads // both update offset static size_t computeSegmentSize( size_t *nBlocks, long long maxMemory, SizeUnit sizeUnit); void validate() const; }; #include "blockoffset.f" #include "datasegmentsize.f" #include "id.f" #include "install.f" #include "maxoffset.f" #include "nreadable.f" #include "offset.f" #include "operatorassign.f" #include "operatorinsert.f" #include "read1.f" #include "read2.f" #include "swap.f" #include "write1.f" #include "write2.f" } // FBB #endif bobcat-5.09.01/sharedmemory/datasegmentsize.f0000644000175000017500000000017114050437223020140 0ustar frankfrankinline size_t SharedMemory::dataSegmentSize() const { return d_sharedSegment ? d_sharedSegment->segmentSize() : 0; } bobcat-5.09.01/sharedmemory/install.f0000644000175000017500000000232414050437223016421 0ustar frankfranktemplate SharedType *SharedMemory::install(std::streamsize *offsetPtr, Params &&...params) { size_t segmentSize = dataSegmentSize(); if (segmentSize == 0) throw Exception() << "SharedMemory::install: no memory"; // find a suitable offset for the shared memory object size_t begin = blockOffset(); size_t end = (begin + sizeof(SharedType)) % segmentSize; if (begin + sizeof(SharedType) != end) seek((1 + offset() / segmentSize) * segmentSize); // determine the object's offset and address std::streamsize location = offset(); void *address = ptr(); // go to the object's last byte if (address == 0 || seek(sizeof(SharedType) - 1) == -1) throw Exception() << "SharedMemory::install: out of memory."; // make sure shmem knows it exists by writing a byte at its last // byte location put(0); if (offsetPtr) *offsetPtr = location; // install the object at 'address' return new (address) SharedType(std::forward(params)...); } bobcat-5.09.01/sharedmemory/write1.f0000644000175000017500000000022614050437223016165 0ustar frankfranktemplate inline int SharedMemory::write(Type const *value) { return write(reinterpret_cast(value), sizeof(Type)); } bobcat-5.09.01/sharedmemory/swap.f0000644000175000017500000000012614050437223015723 0ustar frankfrankinline void SharedMemory::swap(SharedMemory &other) { FBB::fswap(*this, other); } bobcat-5.09.01/sharedmemory/read.cc0000644000175000017500000000114514050437223016026 0ustar frankfrank#include "sharedmemory.ih" int SharedMemory::read(char *data, streamsize len) { if (d_pos.eof()) return -1; validate(); streamsize begin = d_pos.offset(); //cerr << "read at " << begin << ", len = " << len << '\n'; while (len != 0) { int nReceived = readBlock(data, len); //cerr << "read " << nReceived << '\n'; if (nReceived == -1) break; len -= nReceived; data += nReceived; d_pos += nReceived; //cerr << "Next offset: " << d_pos.offset() << ", len = " << len << '\n'; } return d_pos.offset() - begin; } bobcat-5.09.01/sharedmemory/sharedmemory2.cc0000644000175000017500000000052314050437223017673 0ustar frankfrank#include "sharedmemory.ih" SharedMemory::SharedMemory(size_t maxSize, SizeUnit sizeUnit, size_t access) { size_t nBlocks; size_t segmentSize = computeSegmentSize(&nBlocks, maxSize, sizeUnit); d_sharedSegment = SharedSegment::create(&d_id, nBlocks, segmentSize, access); d_pos.reset(d_sharedSegment); } bobcat-5.09.01/sharedmemory/readblock.cc0000644000175000017500000000154214050437223017042 0ustar frankfrank#include "sharedmemory.ih" int SharedMemory::readBlock(char *data, size_t len) { if (d_pos.eof()) return -1; streamsize maxReadable = d_sharedSegment->nReadable(); map(); streamsize nReadable = d_pos.eos(); //cerr << "eos: " << nReadable << " maxReadable: " << maxReadable; if (maxReadable < nReadable) nReadable = maxReadable; size_t remaining = nReadable - d_pos.offset(); //cerr << " remaining: " << remaining; if (remaining < len) len = remaining; //cerr << " len = " << len << ", blockIdx = " << d_pos.blockIdx() << //" blockOffset = " << d_pos.blockOffset() << '\n'; lock(d_pos.blockIdx()); memcpy(data, d_data + d_pos.blockOffset(), len); //cerr << "-->"; //cerr.write(d_data + d_pos.blockOffset(), len); //cerr << "<--\n"; unlock(d_pos.blockIdx()); return len; } bobcat-5.09.01/sharedmemory/ptr.cc0000644000175000017500000000035414050437223015721 0ustar frankfrank#include "sharedmemory.ih" char *SharedMemory::ptr() { if (d_pos.atMaxOffset()) return 0; validate(); map(); // map block[d_blockIdx] return d_data + d_pos.blockOffset(); } bobcat-5.09.01/sharedmemory/computesegmentsize.cc0000644000175000017500000000306714050437223021052 0ustar frankfrank#include "sharedmemory.ih" // Memory computation // P: standard page size // x: required multiplication for P to compute the blockSize // b: sizeof(Block): blockEntry // h: size of the header: sizeof(SharedSegment) - b // M: max available memory // Each entry of SharedSegment::block points to xP bytes // If there are n entries in block, then n*xP == M // // The block array in the SharedSegment segment itself consists of xP - h bytes, // holding (xP - h) / e entries. // // Therefore, (xP - h) / b * xP == M. // // -> sqr(P) / b * sqr(x) - h P / b * x - M = 0 // --- a --- --- b --- - c - // // The quadratic equation is solved for x, which is rounded upward to compute // the real maximum memory size. size_t SharedMemory::computeSegmentSize( size_t *nBlocks, long long maxMemory, SizeUnit sizeUnit) { typedef SharedBlock Entry; maxMemory <<= sizeUnit; double a = static_cast(s_pageSize) * s_pageSize / sizeof(Entry); double b = -static_cast(sizeof(SharedSegment) - sizeof(Entry)) * s_pageSize / sizeof(Entry); double c = -maxMemory; size_t factor = static_cast( // size of allocated blocks ceil((-b + sqrt(b * b - 4 * a * c)) / (2 * a)) ); size_t segmentSize = factor * s_pageSize; *nBlocks = (segmentSize - (sizeof(SharedSegment) - sizeof(Entry))) / sizeof(Entry); return segmentSize; } bobcat-5.09.01/sharedmemory/read2.f0000644000175000017500000000057414050437223015755 0ustar frankfranktemplate int SharedMemory::read(std::ios::off_type offset, Type *value, std::ios::seekdir origin) { if (seek(offset, origin) == -1) throw Exception() << "SharedMemory::read: seek to " << offset << "failed"; return read(value); } bobcat-5.09.01/sharedmemory/map1.cc0000644000175000017500000000033714050437223015753 0ustar frankfrank#include "sharedmemory.ih" void SharedMemory::map() { size_t idx = d_pos.blockIdx(); // block idx to use //cerr << "map: using block " << idx << '\n'; if (not blockAvailable(idx)) map(idx); } bobcat-5.09.01/sharedmemory/kill.cc0000644000175000017500000000034614050437223016050 0ustar frankfrank#include "sharedmemory.ih" void SharedMemory::kill() { if (d_id == -1) return; clearAll(); d_sharedSegment->deleteSegment(d_id); d_sharedSegment = SharedSegment::detach(d_sharedSegment); d_id = -1; } bobcat-5.09.01/sharedmemory/offset.f0000644000175000017500000000012314050437223016234 0ustar frankfrankinline std::streamsize SharedMemory::offset() const { return d_pos.offset(); } bobcat-5.09.01/sharedmemory/remove1.cc0000644000175000017500000000015014050437223016464 0ustar frankfrank#include "sharedmemory.ih" void SharedMemory::remove() { validate(); lockAll(); kill(); } bobcat-5.09.01/sharedmemory/truncate.cc0000644000175000017500000000033314050437223016736 0ustar frankfrank#include "sharedmemory.ih" bool SharedMemory::truncate(streamsize offs) { validate(); bool ok = d_sharedSegment->truncate(offs); if (ok && offs < offset()) d_pos.seek(offs); return ok; } bobcat-5.09.01/sharedmemory/lock.cc0000644000175000017500000000032414050437223016041 0ustar frankfrank#include "sharedmemory.ih" void SharedMemory::lock(size_t idx) { //cerr << "locking " << idx << ": " << d_lockCount << '\n'; if (d_lockCount == 0) d_sharedSegment->lock(idx); ++d_lockCount; } bobcat-5.09.01/sharedmemory/clear.cc0000644000175000017500000000017314050437223016201 0ustar frankfrank#include "sharedmemory.ih" void SharedMemory::clear() { validate(); lockAll(); clearAll(); unlockAll(); } bobcat-5.09.01/sharedmemory/read1.f0000644000175000017500000000021014050437223015737 0ustar frankfranktemplate inline int SharedMemory::read(Type *value) { return read(reinterpret_cast(value), sizeof(Type)); } bobcat-5.09.01/sharedmemory/sharedmemory.ih0000644000175000017500000000013114050437223017617 0ustar frankfrank#include "sharedmemory" #include using namespace std; using namespace FBB; bobcat-5.09.01/sharedmemory/unlock.cc0000644000175000017500000000032714050437223016407 0ustar frankfrank#include "sharedmemory.ih" void SharedMemory::unlock(size_t idx) { //cerr << "UNlocking " << idx << ": " << d_lockCount << '\n'; if (d_lockCount && --d_lockCount == 0) d_sharedSegment->unlock(idx); } bobcat-5.09.01/sharedmemory/validate.cc0000644000175000017500000000023514050437223016703 0ustar frankfrank#include "sharedmemory.ih" void SharedMemory::validate() const { if (d_sharedSegment == 0) throw Exception{} << "SharedMemory not available"; } bobcat-5.09.01/sharedmemory/nreadable.f0000644000175000017500000000017214050437223016667 0ustar frankfrankinline std::streamsize SharedMemory::nReadable() const { return d_sharedSegment ? d_sharedSegment->nReadable() : 0; } bobcat-5.09.01/sharedmemory/sharedmemory3.cc0000644000175000017500000000030214050437223017667 0ustar frankfrank#include "sharedmemory.ih" SharedMemory::SharedMemory(int id) : d_id(id), d_sharedSegment(static_cast(SharedSegment::attach(id))) { d_pos.reset(d_sharedSegment); } bobcat-5.09.01/sharedmemory/writeblock.cc0000644000175000017500000000102414050437223017254 0ustar frankfrank#include "sharedmemory.ih" int SharedMemory::writeBlock(char const *data, size_t len) { if (d_pos.atMaxOffset()) return -1; map(); size_t remaining = d_pos.eos() - d_pos.offset(); //cerr << "eos: " << d_pos.eos() << " remaining: " << remaining; if (remaining < len) len = remaining; //cerr << " len = " << len << ", blockIdx = " << d_pos.blockIdx() << '\n'; lock(d_pos.blockIdx()); memcpy(d_data + d_pos.blockOffset(), data, len); unlock(d_pos.blockIdx()); return len; } bobcat-5.09.01/sharedmemory/operatorinsert.f0000644000175000017500000000015414050437223020032 0ustar frankfrankinline std::ostream &operator<<(std::ostream &out, SharedMemory const &mem) { return mem.insert(out); } bobcat-5.09.01/sharedmemory/destructor.cc0000644000175000017500000000023314050437223017306 0ustar frankfrank#include "sharedmemory.ih" SharedMemory::~SharedMemory() { SharedSegment::detach(d_data, false); SharedSegment::detach(d_sharedSegment, false); } bobcat-5.09.01/sharedmemory/blockoffset.f0000644000175000017500000000013514050437223017252 0ustar frankfrankinline std::streamsize SharedMemory::blockOffset() const { return d_pos.blockOffset(); } bobcat-5.09.01/sharedmemory/map2.cc0000644000175000017500000000072614050437223015756 0ustar frankfrank#include "sharedmemory.ih" // private, only called by load. void SharedMemory::map(size_t idx) { int id = (*d_sharedSegment)[idx].id(); bool newData = id == -1; if (newData) { d_sharedSegment->lock(idx); id = d_sharedSegment->newData(idx); } d_data = static_cast(SharedSegment::attach(id)); if (newData) { memset(d_data, 0, d_sharedSegment->size(id)); d_sharedSegment->unlock(idx); } } bobcat-5.09.01/sharedmemory/unlockall.cc0000644000175000017500000000050314050437223017074 0ustar frankfrank#include "sharedmemory.ih" void SharedMemory::unlockAll() { for ( size_t idx = 0, end = d_sharedSegment->nBlocks(); idx != end; ++idx ) unlock(idx); //cerr << "UNlocking shared segment\n"; d_sharedSegment->nReadableUnlock(); //cerr << "UNlockAll done\n"; } bobcat-5.09.01/sharedmemory/maxoffset.f0000644000175000017500000000013114050437223016741 0ustar frankfrankinline std::streamsize SharedMemory::maxOffset() const { return d_pos.maxOffset(); } bobcat-5.09.01/sharedmemory/write.cc0000644000175000017500000000150714050437223016247 0ustar frankfrank#include "sharedmemory.ih" //#include int SharedMemory::write(char const *data, streamsize len) { if (d_pos.atMaxOffset()) return -1; validate(); streamsize begin = d_pos.offset(); //cerr << "write at " << begin << ", len = " << len << '\n'; while (len != 0) { int nChars = writeBlock(data, len); // locks, updates d_offset //cerr << "wrote " << nChars << '\n'; if (nChars == -1) // hit maxOffset() break; len -= nChars; data += nChars; d_pos += nChars; d_sharedSegment->updateNreadable(d_pos.offset()); //cerr << "Next offset: " << d_pos.offset() << ", len = " << len << '\n'; } //cerr << ".write wrote " << (d_pos.offset() - begin) << " chars\n"; return d_pos.offset() - begin; } bobcat-5.09.01/sharedmemory/clearall.cc0000644000175000017500000000030014050437223016662 0ustar frankfrank#include "sharedmemory.ih" void SharedMemory::clearAll() { d_pos.reset(d_sharedSegment); d_lockCount = 0; d_data = SharedSegment::detach(d_data); d_sharedSegment->clear(); } bobcat-5.09.01/sharedmemory/blockavailable.cc0000644000175000017500000000063714050437223020053 0ustar frankfrank#include "sharedmemory.ih" bool SharedMemory::blockAvailable(size_t idx) { if (d_data == 0) // no data available return false; if (d_pos.blockIdx() == idx) // already loaded: done return true; d_sharedSegment->unlock(d_pos.blockIdx()); // clear an existing lock d_lockCount = 0; d_data = SharedSegment::detach(d_data); return false; } bobcat-5.09.01/sharedmemory/id.f0000644000175000017500000000007114050437223015344 0ustar frankfrankinline int SharedMemory::id() const { return d_id; } bobcat-5.09.01/sharedmemory/write2.f0000644000175000017500000000055014050437223016166 0ustar frankfranktemplate int SharedMemory::write(std::ios::off_type offset, Type const *value, std::ios::seekdir origin) { if (seek(offset, origin) == -1) throw Exception() << "SharedMemory::write: seek to " << offset << "failed"; return write(value); } bobcat-5.09.01/sharedmutex/0000755000175000017500000000000014050437223014435 5ustar frankfrankbobcat-5.09.01/sharedmutex/sharedmutex0000644000175000017500000000104314050437223016707 0ustar frankfrank#ifndef INCLUDED_BOBCAT_SHAREDMUTEX_ #define INCLUDED_BOBCAT_SHAREDMUTEX_ #include namespace FBB { class SharedMutex { pthread_mutex_t d_mutex; public: SharedMutex(); SharedMutex(SharedMutex const &other) = delete; ~SharedMutex(); // does unlock SharedMutex &operator=(SharedMutex const &rhs) = delete; void lock(); void unlock(); protected: pthread_mutex_t *mutexPtr(); }; #include "unlock.f" #include "mutexptr.f" } // FBB #endif bobcat-5.09.01/sharedmutex/sharedmutex1.cc0000644000175000017500000000051614050437223017360 0ustar frankfrank#include "sharedmutex.ih" SharedMutex::SharedMutex() { pthread_mutexattr_t mutex_attr; pthread_mutexattr_init(&mutex_attr); // pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_RECURSIVE); pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED); pthread_mutex_init(&d_mutex, &mutex_attr); } bobcat-5.09.01/sharedmutex/sharedmutex.ih0000644000175000017500000000014514050437223017310 0ustar frankfrank#include "sharedmutex" #include "../exception/exception" using namespace std; using namespace FBB; bobcat-5.09.01/sharedmutex/unlock.f0000644000175000017500000000011214050437223016071 0ustar frankfrankinline void SharedMutex::unlock() { pthread_mutex_unlock(&d_mutex); } bobcat-5.09.01/sharedmutex/mutexptr.f0000644000175000017500000000011114050437223016465 0ustar frankfrankinline pthread_mutex_t *SharedMutex::mutexPtr() { return &d_mutex; } bobcat-5.09.01/sharedmutex/lock.cc0000644000175000017500000000026114050437223015673 0ustar frankfrank#include "sharedmutex.ih" void SharedMutex::lock() { if (pthread_mutex_lock(&d_mutex) != 0) throw Exception{} << "SharedMutex::lock: failed to lock the segment"; } bobcat-5.09.01/sharedmutex/destructor.cc0000644000175000017500000000011114050437223017133 0ustar frankfrank#include "sharedmutex.ih" SharedMutex::~SharedMutex() { unlock(); } bobcat-5.09.01/sharedpos/0000755000175000017500000000000014050437223014074 5ustar frankfrankbobcat-5.09.01/sharedpos/showmanyc.cc0000644000175000017500000000056214050437223016416 0ustar frankfrank#include "sharedpos.ih" streamsize SharedPos::showmanyc() const { streamsize available = nReadable(); streamsize end = eos(); // offset at end of current segment if (end > available) // end cannot exceed writeoffset end = available; return d_offset >= end ? 0 : end - d_offset; } bobcat-5.09.01/sharedpos/seek.cc0000644000175000017500000000056014050437223015333 0ustar frankfrank#include "sharedpos.ih" ios::pos_type SharedPos::seek(ios::off_type offset, ios::seekdir way) { if (way == ios::cur) offset += d_offset; else if (way == ios::end) offset += nReadable(); if (0 <= offset && offset <= d_maxOffset) { d_offset = offset; update(); } else offset = -1; return offset; } bobcat-5.09.01/sharedpos/insert.cc0000644000175000017500000000046714050437223015716 0ustar frankfrank#include "sharedpos.ih" ostream &SharedPos::insert(ostream &out) const { return out << "Maximum possible offset = " << d_maxOffset << "\n" "Current offset = " << d_offset << ", located in block " << blockIdx(); } bobcat-5.09.01/sharedpos/reset.cc0000644000175000017500000000044514050437223015530 0ustar frankfrank#include "sharedpos.ih" void SharedPos::reset(SharedSegment *sharedData) { d_sharedData = sharedData; d_offset = 0; d_blockOffset = 0; d_maxOffset = static_cast(sharedData->nBlocks()) * segmentSize(); } bobcat-5.09.01/sharedpos/update.cc0000644000175000017500000000073514050437223015672 0ustar frankfrank#include "sharedpos.ih" void SharedPos::update() { bool beyondMax = d_offset > d_maxOffset; streamsize offset; if (beyondMax) { offset = d_offset; d_offset = d_maxOffset; } size_t segSize = segmentSize(); d_blockIdx = d_offset / segSize; d_blockOffset = d_offset % segSize; if (beyondMax) throw Exception{} << "Offset (" << offset << ") exceeds maxOffset (" << d_maxOffset << ')'; } bobcat-5.09.01/sharedpos/segmentsize.f0000644000175000017500000000013114050437223016573 0ustar frankfrankinline size_t SharedPos::segmentSize() const { return d_sharedData->segmentSize(); } bobcat-5.09.01/sharedpos/eof.f0000644000175000017500000000013114050437223015007 0ustar frankfrankinline bool SharedPos::eof() const { return d_offset >= d_sharedData->nReadable(); } bobcat-5.09.01/sharedpos/offset.f0000644000175000017500000000011214050437223015523 0ustar frankfrankinline std::streamsize SharedPos::offset() const { return d_offset; } bobcat-5.09.01/sharedpos/blockidx.f0000644000175000017500000000010514050437223016036 0ustar frankfrankinline size_t SharedPos::blockIdx() const { return d_blockIdx; } bobcat-5.09.01/sharedpos/operatorplusis.cc0000644000175000017500000000014714050437223017500 0ustar frankfrank#include "sharedpos.ih" void SharedPos::operator+=(size_t len) { d_offset += len; update(); } bobcat-5.09.01/sharedpos/nreadable.f0000644000175000017500000000013614050437223016160 0ustar frankfrankinline std::streamsize SharedPos::nReadable() const { return d_sharedData->nReadable(); } bobcat-5.09.01/sharedpos/operatorinsert.f0000644000175000017500000000016514050437223017325 0ustar frankfrankinline std::ostream &operator<<(std::ostream &out, SharedPos const &sharedPos) { return sharedPos.insert(out); } bobcat-5.09.01/sharedpos/sharedpos.ih0000644000175000017500000000014314050437223016404 0ustar frankfrank#include "sharedpos" #include "../exception/exception" using namespace std; using namespace FBB; bobcat-5.09.01/sharedpos/blockoffset.f0000644000175000017500000000011314050437223016537 0ustar frankfrankinline size_t SharedPos::blockOffset() const { return d_blockOffset; } bobcat-5.09.01/sharedpos/atmaxoffset.f0000644000175000017500000000012314050437223016560 0ustar frankfrankinline bool SharedPos::atMaxOffset() const { return d_offset == d_maxOffset; } bobcat-5.09.01/sharedpos/operatorplusplus.cc0000644000175000017500000000013514050437223020045 0ustar frankfrank#include "sharedpos.ih" void SharedPos::operator++() { ++d_offset; update(); } bobcat-5.09.01/sharedpos/eos.f0000644000175000017500000000017314050437223015032 0ustar frankfrankinline std::streamsize SharedPos::eos() const { return static_cast(blockIdx() + 1) * segmentSize(); } bobcat-5.09.01/sharedpos/maxoffset.f0000644000175000017500000000012014050437223016230 0ustar frankfrankinline std::streamsize SharedPos::maxOffset() const { return d_maxOffset; } bobcat-5.09.01/sharedpos/sharedpos0000644000175000017500000000423414050437223016012 0ustar frankfrank#ifndef INCLUDED_BOBCAT_SHAREDPOS_ #define INCLUDED_BOBCAT_SHAREDPOS_ #include #include #include namespace FBB { class SharedPos { friend std::ostream &operator<<(std::ostream &out, SharedPos const &pos); SharedSegment *d_sharedData = 0; // setup must have been called to // initialize data members std::streamsize d_maxOffset = 0; // max. possible offset, given nBlocks std::streamsize d_offset = 0; // next location to write size_t d_blockIdx = 0; size_t d_blockOffset = 0; public: bool atMaxOffset() const; size_t blockIdx() const; size_t blockOffset() const; bool eof() const; // true if no char can be read // because offset >= writeoffset std::streamsize eos() const; // abs. offset just past // block[blockIdx()] std::streamsize maxOffset() const; // abs. max. possible offset std::streamsize offset() const; // current abs. offset void reset(SharedSegment *sharedData); // returns -1 if inaccessible std::ios::pos_type seek(std::ios::off_type offset, std::ios::seekdir way = std::ios::beg); std::streamsize showmanyc() const; void operator++(); // caller must have locked the shared // data void operator+=(size_t len); // caller must have locked the shared // data private: std::ostream &insert(std::ostream &out) const; size_t segmentSize() const; void update(); std::streamsize nReadable() const; }; #include "atmaxoffset.f" #include "blockidx.f" #include "blockoffset.f" #include "eof.f" #include "eos.f" #include "maxoffset.f" #include "nreadable.f" #include "offset.f" #include "operatorinsert.f" #include "segmentsize.f" } // FBB #endif bobcat-5.09.01/sharedsegment/0000755000175000017500000000000014050437223014735 5ustar frankfrankbobcat-5.09.01/sharedsegment/updatenreadable.cc0000644000175000017500000000033014050437223020360 0ustar frankfrank#include "sharedsegment.ih" void SharedSegment::updateNreadable(streamsize offset) { d_nReadableMutex.lock(); if (offset > d_nReadable) d_nReadable = offset; d_nReadableMutex.unlock(); } bobcat-5.09.01/sharedsegment/sharedsegment.ih0000644000175000017500000000026014050437223020106 0ustar frankfrank#include "sharedsegment" #include #include #include "../ranger/ranger" #include "../exception/exception" using namespace std; using namespace FBB; bobcat-5.09.01/sharedsegment/nblocks.f0000644000175000017500000000010714050437223016535 0ustar frankfrankinline size_t SharedSegment::nBlocks() const { return d_nBlocks; } bobcat-5.09.01/sharedsegment/rawdetach.cc0000644000175000017500000000036514050437223017212 0ustar frankfrank#include "sharedsegment.ih" void SharedSegment::rawDetach(void *sharedPtr, bool requireOK) { if (sharedPtr == 0 || shmdt(sharedPtr) == 0) return; if (requireOK) throw Exception{} << "Failed to detach shared segment"; } bobcat-5.09.01/sharedsegment/operatorindex.f0000644000175000017500000000012714050437223017767 0ustar frankfrankinline SharedBlock &SharedSegment::operator[](size_t idx) { return d_block[idx]; } bobcat-5.09.01/sharedsegment/deletesegment.cc0000644000175000017500000000032614050437223020072 0ustar frankfrank#include "sharedsegment.ih" void SharedSegment::deleteSegment(int id) { struct shmid_ds buf; if (shmctl(id, IPC_RMID, &buf) != 0) throw Exception{} << "Could not discard shared segment " << id; } bobcat-5.09.01/sharedsegment/insert.cc0000644000175000017500000000162214050437223016551 0ustar frankfrank#include "sharedsegment.ih" ostream &SharedSegment::insert(ostream &out) const { out << "Access mode: 0" << oct << d_access << dec << "\n" "Information readable until offset " << d_nReadable << "\n" "Size of the data segments: " << d_segmentSize << " bytes\n" << d_nBlocks << " data segments may be defined, " "with a total capacity of " << static_cast(d_segmentSize) * d_nBlocks / 1024 << "kB"; bool firstBlock = true; for (size_t idx = 0; idx != d_nBlocks; ++idx) { if (d_block[idx].id() != -1) { if (firstBlock) { firstBlock = false; out << "\n" "ID(s) of data segments:"; } out << "\n" " at idx " << idx << ": id = " << d_block[idx].id(); } } return out; } bobcat-5.09.01/sharedsegment/size.cc0000644000175000017500000000044614050437223016222 0ustar frankfrank#include "sharedsegment.ih" size_t SharedSegment::size(int id) { struct shmid_ds buf; if (shmctl(id, IPC_STAT, &buf) == -1) throw Exception{} << "Can't determine segment size of segment " << id << ": " << errnodescr; return buf.shm_segsz; } bobcat-5.09.01/sharedsegment/newsegment.cc0000644000175000017500000000105614050437223017422 0ustar frankfrank#include "sharedsegment.ih" int SharedSegment::newSegment(size_t requestedSize, size_t access) { int id = shmget(IPC_PRIVATE, requestedSize, access); if (id == -1) // no block available throw Exception{} << "Cannot create a shared segment"; size_t actualSize = size(id); if (actualSize != requestedSize) throw Exception{} << "Incorrect size (" << actualSize << ", should be: " << requestedSize << ") of shared segment"; return id; } bobcat-5.09.01/sharedsegment/segmentsize.f0000644000175000017500000000011714050437223017440 0ustar frankfrankinline size_t SharedSegment::segmentSize() const { return d_segmentSize; } bobcat-5.09.01/sharedsegment/nreadableunlock.f0000644000175000017500000000012014050437223020226 0ustar frankfrankinline void SharedSegment::nReadableUnlock() { d_nReadableMutex.unlock(); } bobcat-5.09.01/sharedsegment/lock.f0000644000175000017500000000011114050437223016025 0ustar frankfrankinline void SharedSegment::lock(size_t idx) { d_block[idx].lock(); } bobcat-5.09.01/sharedsegment/unlock.f0000644000175000017500000000011514050437223016374 0ustar frankfrankinline void SharedSegment::unlock(size_t idx) { d_block[idx].unlock(); } bobcat-5.09.01/sharedsegment/nreadablelock.f0000644000175000017500000000011414050437223017666 0ustar frankfrankinline void SharedSegment::nReadableLock() { d_nReadableMutex.lock(); } bobcat-5.09.01/sharedsegment/truncate.cc0000644000175000017500000000042014050437223017065 0ustar frankfrank#include "sharedsegment.ih" bool SharedSegment::truncate(streamsize offset) { if (offset < 0) return false; nReadableLock(); bool ret = offset <= d_nReadable; if (ret) d_nReadable = offset; nReadableUnlock(); return ret; } bobcat-5.09.01/sharedsegment/clear.cc0000644000175000017500000000043714050437223016336 0ustar frankfrank#include "sharedsegment.ih" void SharedSegment::clear() { d_nReadable = 0; for (auto &block: ranger(d_block, d_block + d_nBlocks)) { int id = block.id(); if (id != -1) { deleteSegment(id); block.setID(-1); } } } bobcat-5.09.01/sharedsegment/detach.f0000644000175000017500000000021514050437223016332 0ustar frankfranktemplate Type *SharedSegment::detach(Type *sharedPtr, bool requireOK) { rawDetach(sharedPtr, requireOK); return 0; } bobcat-5.09.01/sharedsegment/nreadable.f0000644000175000017500000000012414050437223017016 0ustar frankfrankinline std::streamsize SharedSegment::nReadable() const { return d_nReadable; } bobcat-5.09.01/sharedsegment/operatorinsert.f0000644000175000017500000000023414050437223020163 0ustar frankfrankinline std::ostream &operator<<(std::ostream &out, SharedSegment const &sharedData) { return sharedData.insert(out); } bobcat-5.09.01/sharedsegment/sharedsegment0000644000175000017500000000632014050437223017512 0ustar frankfrank#ifndef INCLUDED_BOBCAT_SHAREDSEGMENT_ #define INCLUDED_BOBCAT_SHAREDSEGMENT_ #include #include namespace FBB { class SharedSegment { friend std::ostream &operator<<(std::ostream &out, SharedSegment const &sharedData); size_t d_access; size_t d_segmentSize; SharedMutex d_nReadableMutex; std::streamsize d_nReadable; // number of readable characters // (just beyond offset of last character // ever written) size_t d_nBlocks; SharedBlock d_block[1]; // Mutexes and IDs of shared data blocks // in fact SharedBlock block[nBlocks] public: SharedSegment(SharedSegment const &other) = delete; SharedSegment &operator=(SharedSegment const &rhs) = delete; SharedBlock &operator[](size_t idx); size_t access() const; void clear(); // clear all data, nReadable = 0 void lock(size_t idx); size_t nBlocks() const; int newData(size_t idx); std::streamsize nReadable() const; void nReadableLock(); void nReadableUnlock(); size_t segmentSize() const; bool truncate(std::streamsize offset); void unlock(size_t idx); void updateNreadable(std::streamsize offset); static void *attach(int id); static SharedSegment *create(int *id, size_t nBlocks, size_t segmentSize, size_t access); static void deleteSegment(int id); // delete shared segment `id' // attach/detach refer to the mapping // on the current process's memory space template static Type *detach(Type *sharedPtr, bool requireOK = true); // if sharedPtr != 0 the shared // segment is detached. throws // exception if requireOK == true // but detaching fails. // always returns 0 static size_t size(int id); // size of shared data segment id private: SharedSegment(size_t access, size_t nBlocks, size_t segmentSize); std::ostream &insert(std::ostream &out) const; static void rawDetach(void *sharedPtr, bool requireOK); // detaches // throws exception if // requireOK == true // but detaching fails // returns the ID of new shared memory static int newSegment(size_t segmentSize, size_t access); }; #include "access.f" #include "detach.f" #include "lock.f" #include "nblocks.f" #include "nreadable.f" #include "nreadablelock.f" #include "nreadableunlock.f" #include "operatorindex.f" #include "operatorinsert.f" #include "segmentsize.f" #include "unlock.f" } // FBB #endif bobcat-5.09.01/sharedsegment/create.cc0000644000175000017500000000064014050437223016507 0ustar frankfrank#include "sharedsegment.ih" SharedSegment *SharedSegment::create(int *id, size_t nBlocks, size_t segmentSize, size_t access) { *id = newSegment(segmentSize, access); SharedSegment *segmentPtr = static_cast(attach(*id)); new (segmentPtr) SharedSegment(access, nBlocks, segmentSize); return segmentPtr; } bobcat-5.09.01/sharedsegment/sharedsegment1.cc0000644000175000017500000000102314050437223020152 0ustar frankfrank#include "sharedsegment.ih" SharedSegment::SharedSegment(size_t access, size_t nBlocks, size_t segmentSize) : d_access(access), d_segmentSize(segmentSize), d_nReadable(0), d_nBlocks(nBlocks) { // initialize the data-table. d_block[0] already has // been initialized as `SharedBlock d_block[1]' for ( SharedBlock *begin = d_block + 1, *end = d_block + d_nBlocks; begin != end; ++begin ) new (begin) SharedBlock; } bobcat-5.09.01/sharedsegment/access.f0000644000175000017500000000010514050437223016341 0ustar frankfrankinline size_t SharedSegment::access() const { return d_access; } bobcat-5.09.01/sharedsegment/attach.cc0000644000175000017500000000036214050437223016511 0ustar frankfrank#include "sharedsegment.ih" void *SharedSegment::attach(int id) { void *ret = shmat(id, 0, 0); if (ret == reinterpret_cast(-1)) throw Exception{} << "Can't attach shared segment segment " << id; return ret; } bobcat-5.09.01/sharedsegment/newdata.cc0000644000175000017500000000025014050437223016664 0ustar frankfrank#include "sharedsegment.ih" int SharedSegment::newData(size_t idx) { int id = newSegment(d_segmentSize, d_access); d_block[idx].setID(id); return id; } bobcat-5.09.01/sharedsegment/driver/0000755000175000017500000000000014050437223016230 5ustar frankfrankbobcat-5.09.01/sharedsegment/driver/build0000755000175000017500000000011214050437223017247 0ustar frankfrank#!/bin/bash g++ `cat ../../c++std` -pthread -o driver driver.cc -lbobcat bobcat-5.09.01/sharedsegment/driver/driver.cc0000644000175000017500000001211114050437223020026 0ustar frankfrank#include #include #include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) try { if (argc == 1) { cout << "Argument:\n" " c: create a shared memory segment, display its ID\n" " k : kill shared memory segment \n" " l : lock a SharedMutex in shared memory segment \n" " L : create mutex, condition variable and count in " "ID \n" " W : condition wait for the mutex in shared memory " "segment \n" " w : wait for a lock set by 'l' to be released " "(id = )\n" ; return 0; } switch (argv[1][0]) { case 'c': { SharedMemory shmem(1, SharedMemory::kB); void *ptr = shmem.ptr(); cout << "ID = " << shmem.id() << ", data at " << ptr << '\n' << shmem << endl; break; } case 'l': { SharedMemory shmem(stoll(argv[2])); shmem.seek(sizeof(SharedMutex)); shmem.seek(0); SharedMutex *smPtr = new (shmem.ptr()) SharedMutex(); smPtr->lock(); cout << "Press enter to release the lock "; cin.ignore(1000, '\n'); smPtr->unlock(); break; } case 'L': { SharedMemory shmem(stoll(argv[2])); // room for the variables shmem.seek(sizeof(pthread_mutex_t) + sizeof(int) + sizeof(pthread_cond_t)); // set up the pointers to the variables shmem.seek(0); pthread_mutex_t *mPtr = reinterpret_cast (shmem.ptr()); pthread_cond_t *cPtr = reinterpret_cast (shmem.ptr() + sizeof(pthread_mutex_t)); int *iPtr = reinterpret_cast (shmem.ptr() + sizeof(pthread_mutex_t) + sizeof(pthread_cond_t)); // initialize the mutex pthread_mutexattr_t mutex_attr; pthread_mutexattr_init(&mutex_attr); pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED); pthread_mutex_init(mPtr, &mutex_attr); // initialize the condition pthread_condattr_t cond_attr; pthread_condattr_init(&cond_attr); pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED); pthread_cond_init(cPtr, &cond_attr); // initialize the variable memset(iPtr, 0, sizeof(int)); if (pthread_mutex_lock(mPtr) != 0) throw Exception() << "Mutex failed to lock"; cout << "Press enter to release the lock "; cin.ignore(1000, '\n'); // set the variable to check *iPtr = 1; // signal pthread_cond_signal(cPtr); // unlock pthread_mutex_unlock(mPtr); break; } case 'W': { SharedMemory shmem(stoll(argv[2])); // room for the variables shmem.seek(sizeof(pthread_mutex_t) + sizeof(int) + sizeof(pthread_cond_t)); // set up the pointers to the variables shmem.seek(0); pthread_mutex_t *mPtr = reinterpret_cast (shmem.ptr()); pthread_cond_t *cPtr = reinterpret_cast (shmem.ptr() + sizeof(pthread_mutex_t)); int *iPtr = reinterpret_cast (shmem.ptr() + sizeof(pthread_mutex_t) + sizeof(pthread_cond_t)); // obtain the lock if (pthread_mutex_lock(mPtr) != 0) throw Exception() << "Mutex failed to lock"; while (*iPtr == 0) pthread_cond_wait(cPtr, mPtr); // unlock pthread_mutex_unlock(mPtr); break; } case 'k': { SharedMemory shmem(stoll(argv[2])); shmem.kill(); break; } case 'w': { SharedMemory shmem(stoll(argv[2])); shmem.seek(0); SharedMutex *smPtr = reinterpret_cast(shmem.ptr()); smPtr->lock(); cout << "Obtained the lock. Now releasing it again\n"; smPtr->unlock(); break; } } } catch (exception const &exc) { cout << "Exception: " << exc.what() << endl; } bobcat-5.09.01/sharedstream/0000755000175000017500000000000014050437223014566 5ustar frankfrankbobcat-5.09.01/sharedstream/sharedstream.ih0000644000175000017500000000010314050437223017564 0ustar frankfrank#include "sharedstream" using namespace std; using namespace FBB; bobcat-5.09.01/sharedstream/clear.f0000644000175000017500000000013414050437223016021 0ustar frankfrankinline void SharedStream::clear() { std::istream::clear(); std::ostream::clear(); } bobcat-5.09.01/sharedstream/truncate.f0000644000175000017500000000015314050437223016561 0ustar frankfrankinline bool SharedStream::truncate(std::streamsize offset) { return sharedMemory().truncate(offset); } bobcat-5.09.01/sharedstream/sharedstream0000644000175000017500000000253614050437223017201 0ustar frankfrank#ifndef INCLUDED_BOBCAT_SHAREDSTREAM_ #define INCLUDED_BOBCAT_SHAREDSTREAM_ #include #include #include namespace FBB { struct SharedStream: private SharedBuf, public std::istream, public std::ostream, public virtual SharedEnum__ { SharedStream(); SharedStream( // 2 size_t maxSize, SizeUnit sizeUnit, std::ios::openmode openMode = std::ios::in | std::ios::out, size_t access = 0600); SharedStream( // 3 int id, std::ios::openmode openMode = std::ios::in | std::ios::out); using SharedBuf::attachSharedCondition; void clear(); using SharedBuf::createSharedCondition; using SharedBuf::id; using SharedBuf::kill; void memInfo(std::ostream &out, char const *end = "\n") const; void open( size_t maxSize, SizeUnit sizeUnit, std::ios::openmode openMode = std::ios::in | std::ios::out, size_t access = 0600); void open( int id, std::ios::openmode openMode = std::ios::in | std::ios::out); using SharedBuf::remove; bool truncate(std::streamsize offset); }; #include "clear.f" #include "truncate.f" } // FBB #endif bobcat-5.09.01/sharedstream/sharedstream1.cc0000644000175000017500000000014514050437223017640 0ustar frankfrank#include "sharedstream.ih" SharedStream::SharedStream() : istream(this), ostream(this) {} bobcat-5.09.01/sharedstream/open2.cc0000644000175000017500000000024714050437223016123 0ustar frankfrank#include "sharedstream.ih" void SharedStream::open(int id, std::ios::openmode openMode) { setMemory(SharedMemory(id)); setOpenMode(openMode); clear(); } bobcat-5.09.01/sharedstream/sharedstream2.cc0000644000175000017500000000043614050437223017644 0ustar frankfrank#include "sharedstream.ih" SharedStream::SharedStream( size_t maxSize, SharedMemory::SizeUnit sizeUnit, std::ios::openmode openMode, size_t access) : SharedBuf(maxSize, sizeUnit, openMode, access), std::istream(this), std::ostream(this) {} bobcat-5.09.01/sharedstream/sharedstream3.cc0000644000175000017500000000025514050437223017644 0ustar frankfrank#include "sharedstream.ih" SharedStream::SharedStream(int id, std::ios::openmode openMode) : SharedBuf(id, openMode), std::istream(this), std::ostream(this) {} bobcat-5.09.01/sharedstream/open1.cc0000644000175000017500000000041114050437223016113 0ustar frankfrank#include "sharedstream.ih" void SharedStream::open( size_t maxSize, SizeUnit sizeUnit, std::ios::openmode openMode, size_t access) { setMemory(SharedMemory(maxSize, sizeUnit, access)); setOpenMode(openMode); clear(); } bobcat-5.09.01/sharedstream/meminfo.cc0000644000175000017500000000025614050437223016532 0ustar frankfrank#include "sharedstream.ih" void SharedStream::memInfo(std::ostream &out, char const *end) const { static_cast(this)->memInfo(out); out << end; } bobcat-5.09.01/sharedstream/driver/0000755000175000017500000000000014050437223016061 5ustar frankfrankbobcat-5.09.01/sharedstream/driver/build0000755000175000017500000000026214050437223017106 0ustar frankfrank#!/bin/bash g++ -o driver `cat ../../c++std` -Wall -pthread driver.cc -lbobcat echo Start ./driver for an interactive menu. echo Optionally remove ./driver after the demo-run bobcat-5.09.01/sharedstream/driver/driver.cc0000644000175000017500000002213714050437223017670 0ustar frankfrank#include #include #include #include #include #include #include using namespace std; using namespace FBB; int main() { SharedStream sharedStream; int id = -1; while (true) { cout << "\n" " K kill (no lock) existing shared segment\n" " S show stats of current shared segment\n" " L Load segment \n" " C Install a SharedCondition at offset 0\n" " c create new shared memory (sets id)\n" // " l lock segment id until key pressed\n" // " p c put char c at offset x\n" " q quit\n" // " r read n chars from offset x\n" // " w args write all args at offset x\n" " i insert lines (until empty) at the current " "offset\n" " x extract lines (until EOF) from the current " "offset\n" " X extract the next line from the current " "offset\n" " when nodified via 'N'\n" " N notify a waiting X\n" " s seek (abs) offset x\n" "? "; char ch; cin >> ch; ios::off_type offset; cout << "Requested: " << ch << '\n'; sharedStream.clear(); switch (ch) { case 'c': { sharedStream.open(1, SharedStream::kB); id = sharedStream.id(); cout << "id = " << id << '\n'; sharedStream.memInfo(cout); cout << '\n'; } break; case 'C': { sharedStream.seekp(0); SharedCondition cond(sharedStream.createSharedCondition()); sharedStream.seekg(cond.width()); break; } case 'K': // delete segment { if (id == -1) { cout << "No segment loaded\n"; continue; } cout << "Removing segment id = " << id << '\n'; if (ch == 'R') sharedStream.remove(); else sharedStream.kill(); id = -1; } break; case 'L': cin >> id; cout << "Loading segment " << id << '\n'; sharedStream.open(id); sharedStream.memInfo(cout); cout << '\n'; break; case 'S': if (id == -1) { cout << "No segment loaded\n"; continue; } sharedStream.memInfo(cout); cout << '\n'; break; case 's': { size_t offset; if (id == -1) { cout << "No segment loaded\n"; continue; } cin >> offset; sharedStream.seekg(offset); sharedStream.seekp(offset); cout << "tellg: " << sharedStream.tellg() << ", " "tellp: " << sharedStream.tellp() << '\n'; } break; case 'i': { string line; getline(cin, line); sharedStream.seekp(0, ios::cur); while (true) { cout << "? "; if (not getline(cin, line) || line.empty()) break; sharedStream << line << endl; cout << " tellp: " << sharedStream.tellp() << '\n'; } cout << // " tellg: " << sharedStream.tellg() << ", " " tellp: " << sharedStream.tellp() << '\n'; } break; case 'x': { string line; sharedStream.seekg(0, ios::cur); while (true) { cout << ": "; if (not getline(sharedStream, line)) break; cout << line << "\n" " tellg: " << sharedStream.tellg() << ", " " tellp: " << sharedStream.tellp() << '\n'; } } break; case 'X': { SharedCondition cond(sharedStream.attachSharedCondition(0)); string line; sharedStream.seekg(cond.width()); cond.lock(); while (true) { cond.wait(); cout << ": "; if (not getline(sharedStream, line)) break; cout << line << "\n" " tellg: " << sharedStream.tellg() << ", " " tellp: " << sharedStream.tellp() << '\n'; } cout << "All done\n"; cond.unlock(); } break; case 'N': { string line; getline(cin, line); SharedCondition cond(sharedStream.attachSharedCondition(0)); while (true) { cout << "'enter' or 'q'? "; getline(cin, line); if (line == "q") break; cond.lock(); cond.notify(); cond.unlock(); } } break; case 'p': // put a char behind the last written { if (id == -1) { cout << "No segment loaded\n"; continue; } cin >> offset >> ch; if (!cin) throw Exception() << "cmd specification error"; sharedStream.seekp(offset); cout << "Segment id = " << id << " at write offset " << sharedStream.tellp() << '\n'; sharedStream.put(ch); } break; case 'r': // put a char behind the last written { if (id == -1) { cout << "No segment loaded\n"; continue; } int n; cin >> offset >> n; if (!cin) throw Exception() << "cmd specification error"; char buf[n]; sharedStream.seekg(offset); cout << "Segment id = " << id << " at offset " << sharedStream.tellg() << ", to read " << n << " bytes\n"; n = sharedStream.read(buf, n).gcount(); if (n < 0) cout << "No data at " << offset << '\n'; else { cout << "Retrieved " << n << " bytes, containing `"; cout.write(buf, n); cout << "'\n"; for (auto ch: buf) cout << static_cast(ch) << ' '; cout << '\n'; } } break; case 'w': // write chars at offset { if (id == -1) { cout << "No segment loaded\n"; continue; } string line; cin >> offset; getline(cin, line); if (!cin) throw Exception() << "cmd specification error"; streampos pos = sharedStream.seekp(offset).tellp(); cout << "Segment id = " << id << " at offset " << pos << ", to write " << line.length() << " bytes\n"; sharedStream.write(line.data(), line.length()); if (!sharedStream) cout << "No room left to write any bytes\n"; else cout << "Wrote " << (sharedStream.tellp() - pos) << " bytes\n"; } break; case 'q': return 0; default: cout << "request not implemented: " << ch << '\n'; break; } } } bobcat-5.09.01/signal/0000755000175000017500000000000014050437223013361 5ustar frankfrankbobcat-5.09.01/signal/signal0000644000175000017500000000234214050437223014562 0ustar frankfrank#ifndef INCLUDED_BOBCAT_SIGNAL_ #define INCLUDED_BOBCAT_SIGNAL_ #include #include namespace FBB { class SignalHandler { friend class Signal; public: virtual ~SignalHandler(); private: virtual void signalHandler(size_t signum) = 0; }; class Signal { typedef std::vector SignalHandlerVector; std::vector d_signals; // d_signals is a vector of vectors of pointers to SignalHandlers // the row dimension refers to the signal number // each row holds a SignalHandler object handling that kind of signal static Signal *s_signal; public: static Signal &instance(); Signal(Signal const &) = delete; Signal &operator=(Signal const &) = delete; void add(size_t signum, SignalHandler &object); void remove(size_t signum, SignalHandler &object); void ignore(size_t signum); void reset(size_t signum); private: Signal(); static void verify(size_t signum, char const *member); static void handler(int signum); // called by remove void signal(int signum, sighandler_t handler); // calls sigaction }; } #endif bobcat-5.09.01/signal/instance.cc0000644000175000017500000000023514050437223015474 0ustar frankfrank#include "signal.ih" Signal *Signal::s_signal; Signal &Signal::instance() { if (s_signal == 0) s_signal = new Signal; return *s_signal; } bobcat-5.09.01/signal/signal.ih0000644000175000017500000000016714050437223015164 0ustar frankfrank#include "signal" #include #include "../exception/exception" using namespace std; using namespace FBB; bobcat-5.09.01/signal/reset.cc0000644000175000017500000000023714050437223015014 0ustar frankfrank#include "signal.ih" void Signal::reset(size_t signum) { verify(signum, "Signal::reset"); signal(signum, SIG_DFL); d_signals[signum].clear(); } bobcat-5.09.01/signal/signal.cc0000644000175000017500000000217414050437223015151 0ustar frankfrank#include "signal.ih" // Text copied from stackoverflow: // // How to convert a signal call into the equivalent sigaction call? // // Suppose you installed a signal handler for the alarm signal, // // signal(SIGALRM, myhandler); // // The equivalent sigaction code is: // // struct sigaction sa; // sa.sa_handler = myhandler; // sigemptyset(&sa.sa_mask); // sa.sa_flags = 0; // sigaction(SIGALRM, &sa, NULL) // // However, we typically may also set the mask and the flags field. The mask // is a temporary signal mask used during the signal handler execution. The // SA_RESTART flag will automatically restart some (but not all) system calls // that otherwise would have returned early (with EINTR error). The latter // means we can simplify the rest of code somewhat because a restart loop may // no longer be required. // // sigfillset(&sa.sa_mask); // sa.sa_flags = SA_RESTART; /* Restart functions if interrupted by handler */ void Signal::signal(int signum, sighandler_t handler) { struct sigaction sa; sa.sa_handler = handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; sigaction(signum, &sa, 0); } bobcat-5.09.01/signal/handler.cc0000644000175000017500000000022014050437223015277 0ustar frankfrank#include "signal.ih" void Signal::handler(int signum) { for (auto &obj: s_signal->d_signals[signum]) obj->signalHandler(signum); } bobcat-5.09.01/signal/destructor.cc0000644000175000017500000000007114050437223016064 0ustar frankfrank#include "signal.ih" SignalHandler::~SignalHandler() {} bobcat-5.09.01/signal/ignore.cc0000644000175000017500000000024114050437223015150 0ustar frankfrank#include "signal.ih" void Signal::ignore(size_t signum) { verify(signum, "Signal::ignore"); signal(signum, SIG_IGN); d_signals[signum].clear(); } bobcat-5.09.01/signal/add.cc0000644000175000017500000000041114050437223014414 0ustar frankfrank#include "signal.ih" void Signal::add(size_t signum, SignalHandler &object) { verify(signum, "Signal::add"); if (d_signals.size() <= signum) d_signals.resize(signum + 1); d_signals[signum].push_back(&object); signal(signum, handler); } bobcat-5.09.01/signal/verify.cc0000644000175000017500000000065714050437223015204 0ustar frankfrank#include "signal.ih" // This is required for the hurd-i386 arch, which apparently // fails to implement the POSIX standard: #ifndef SIGRTMAX #define SIGRTMAX _NSIG #endif void Signal::verify(size_t signum, char const *member) { if (signum > static_cast(SIGRTMAX)) throw Exception{1} << member << " signal " << signum << " exceeds " "max. signum (" << SIGRTMAX << ')'; } bobcat-5.09.01/signal/signal1.cc0000644000175000017500000000005214050437223015223 0ustar frankfrank#include "signal.ih" Signal::Signal() {} bobcat-5.09.01/signal/remove.cc0000644000175000017500000000122114050437223015161 0ustar frankfrank#include "signal.ih" void Signal::remove(size_t signum, SignalHandler &object) { verify(signum, "Signal::remove"); if (d_signals.size() <= signum) throw Exception{1} << "no signal handlers for signal " << signum << " were installed"; auto iter = find(d_signals[signum].begin(), d_signals[signum].end(), &object); if (iter == d_signals[signum].end()) throw Exception{1} << "object " << &object << " did not register a handler for signal " << signum; d_signals[signum].erase(iter); signal(signum, handler); // handler is a private static function } bobcat-5.09.01/signal/driver/0000755000175000017500000000000014050437223014654 5ustar frankfrankbobcat-5.09.01/signal/driver/build0000755000175000017500000000056114050437223015703 0ustar frankfrank#!/bin/bash LIBS=" -lbobcat" GPP="g++ `cat ../../c++std` -O2 -odriver " # Using the std. bobcat library # ${GPP} driver.cc ${LIBS} -s # Using the sources in ../ and the std. bobcat library # ${GPP} driver.cc ../*.cc ${LIBS} -s # Using the library in ../tmp, the ../signal header and the std. bobcat # library ${GPP} -I../ driver.cc -L../tmp -lsignal ${LIBS} -s bobcat-5.09.01/signal/driver/driver.cc0000644000175000017500000000227114050437223016460 0ustar frankfrank#include #include #include #include "../signal" class SignalDemo: public FBB::SignalHandler { volatile size_t d_signal; volatile bool d_continue; pid_t d_pid; public: SignalDemo(); void run(); private: void signalHandler(size_t signum) override; }; using namespace std; using namespace FBB; SignalDemo::SignalDemo() : d_signal(0), d_continue(true), d_pid(getpid()) {} void SignalDemo::run() { while (d_continue) { cout << "Send a SIGINT (2) or SIGTERM (15) ... to process " << d_pid << endl; sleep(1); } cout << "Ending `run' after receiving signal " << d_signal << endl; } void SignalDemo::signalHandler(size_t signal) { if (signal == SIGINT) cout << "Process " << d_pid << " received SIGINT" << endl; else if (signal == SIGTERM) { cout << "Process " << d_pid << " received SIGTERM" << endl; d_signal = SIGTERM; d_continue = false; } } int main() { SignalDemo signalDemo; Signal::instance().add(SIGINT, signalDemo); Signal::instance().add(SIGTERM, signalDemo); signalDemo.run(); } bobcat-5.09.01/socketbase/0000755000175000017500000000000014050437223014227 5ustar frankfrankbobcat-5.09.01/socketbase/socketbase.ih0000644000175000017500000000017514050437223016677 0ustar frankfrank#include "socketbase" #include #include "../exception/exception" using namespace std; using namespace FBB; bobcat-5.09.01/socketbase/makebase.f0000644000175000017500000000017514050437223016151 0ustar frankfrankinline SocketBase SocketBase::makeBase(int socket, sockaddr_in const &address) { return SocketBase{ socket, address }; } bobcat-5.09.01/socketbase/socketbase2.cc0000644000175000017500000000056414050437223016750 0ustar frankfrank#include "socketbase.ih" SocketBase::SocketBase(string const &host, uint16_t port) : InetAddress(host, port) { d_sock = ::socket(AF_INET, SOCK_STREAM, 0); // 0: protocol, should be 0 if (d_sock < 0) throw Exception{} << "SocketBase::SocketBase(" << host << ", " << port << "): " << errnodescr; } bobcat-5.09.01/socketbase/setbooloption.cc0000644000175000017500000000045714050437223017444 0ustar frankfrank#include "socketbase.ih" bool SocketBase::setBoolOption(int optname, bool newValue) { bool oldValue = boolOption(optname); if (setsockopt(d_sock, SOL_SOCKET, optname, &newValue, sizeof(bool)) < 0) throw Exception{} << "SocketBase::getOption(): " << errnodescr; return oldValue; } bobcat-5.09.01/socketbase/socketbase1.cc0000644000175000017500000000041514050437223016742 0ustar frankfrank#include "socketbase.ih" SocketBase::SocketBase(uint16_t port) : InetAddress(port) { d_sock = ::socket(AF_INET, SOCK_STREAM, 0); // 0: protocol, should be 0 if (d_sock < 0) throw Exception{} << "SocketBase::SocketBase(port): " << errnodescr; } bobcat-5.09.01/socketbase/socketbase0000644000175000017500000000265714050437223016307 0ustar frankfrank#ifndef INCLUDED_BOBCAT_SOCKETBASE_ #define INCLUDED_BOBCAT_SOCKETBASE_ #include #include #include // int info coming in/going out: host byte order namespace FBB { class SocketBase: public InetAddress { int d_sock; public: bool debug() const; // .f bool reuse() const; // .f int socket() const; // .f bool setDebug(bool trueIsOn); // .f bool setReuse(bool trueIsOn); // .f protected: explicit SocketBase(uint16_t port); // 1 SocketBase(std::string const &host, uint16_t port); // 2 SocketBase(SocketBase const &other) = default; SocketBase &operator=(SocketBase const &rhs) = default; SocketBase makeBase(int socket, // .f sockaddr_in const &address); private: SocketBase(int socket, sockaddr_in const &address); // 1.f bool boolOption(int optname) const; bool setBoolOption(int optname, bool newValue); }; #include "socketbase1.f" #include "debug.f" #include "reuse.f" #include "setdebug.f" #include "setreuse.f" #include "socket.f" #include "makebase.f" } // FBB #endif bobcat-5.09.01/socketbase/socket.f0000644000175000017500000000007514050437223015670 0ustar frankfrankinline int SocketBase::socket() const { return d_sock; } bobcat-5.09.01/socketbase/debug.f0000644000175000017500000000011314050437223015457 0ustar frankfrankinline bool SocketBase::debug() const { return boolOption(SO_DEBUG); } bobcat-5.09.01/socketbase/setdebug.f0000644000175000017500000000014214050437223016175 0ustar frankfrankinline bool SocketBase::setDebug(bool trueIsOn) { return setBoolOption(SO_DEBUG, trueIsOn); } bobcat-5.09.01/socketbase/booloption.cc0000644000175000017500000000046714050437223016731 0ustar frankfrank#include "socketbase.ih" bool SocketBase::boolOption(int optname) const { int value; socklen_t valueSize = sizeof(int); if (getsockopt(d_sock, SOL_SOCKET, optname, &value, &valueSize) < 0) throw Exception{} << "SocketBase::getOption(): " << errnodescr; return value != 0; } bobcat-5.09.01/socketbase/setreuse.f0000644000175000017500000000014614050437223016236 0ustar frankfrankinline bool SocketBase::setReuse(bool trueIsOn) { return setBoolOption(SO_REUSEADDR, trueIsOn); } bobcat-5.09.01/socketbase/reuse.f0000644000175000017500000000011714050437223015520 0ustar frankfrankinline bool SocketBase::reuse() const { return boolOption(SO_REUSEADDR); } bobcat-5.09.01/socketbase/socketbase1.f0000644000175000017500000000017014050437223016600 0ustar frankfrankinline SocketBase::SocketBase(int socket, sockaddr_in const &address) : InetAddress(address), d_sock(socket) {} bobcat-5.09.01/SSLCLASSES0000644000175000017500000000031414050437223013504 0ustar frankfrank# This file is read from icmake/special pf_iterator pf_iteratorstream bigint decryptbuf diffiehellman digestbuf encryptbuf hmacbuf isymcryptstream isymcryptstreambuf primefactors symcryptstreambufbase bobcat-5.09.01/stat/0000755000175000017500000000000014050437223013057 5ustar frankfrankbobcat-5.09.01/stat/inode.f0000644000175000017500000000011014050437223014314 0ustar frankfrankinline size_t Stat::inode() const { return d_stat.st_ino; } bobcat-5.09.01/stat/stat3.cc0000644000175000017500000000013414050437223014422 0ustar frankfrank#include "stat.ih" Stat::Stat(string const &name) : d_name(name) { init(::stat); } bobcat-5.09.01/stat/modestr.cc0000644000175000017500000000077014050437223015047 0ustar frankfrank#include "stat.ih" string Stat::modeStr() const { string ret = "rwxrwxrwx"; size_t mode = d_stat.st_mode; for (size_t idx = 9; idx--; mode >>= 1) { if ((mode & 1) == 0) // bit not set ret[idx] = '-'; } if (d_stat.st_mode & SUID) ret[2] = ret[2] == 'x' ? 's' : 'S'; if (d_stat.st_mode & SGID) ret[5] = ret[5] == 'x' ? 's' : 'S'; if (d_stat.st_mode & SB) ret[8] = ret[8] == 'x' ? 't' : 'T'; return ret; } bobcat-5.09.01/stat/name.f0000644000175000017500000000007614050437223014151 0ustar frankfrankinline std::string const &Stat::name() { return d_name; } bobcat-5.09.01/stat/nblocks.f0000644000175000017500000000011514050437223014656 0ustar frankfrankinline size_t Stat::nBlocks() const { return d_stat.st_blocks; } bobcat-5.09.01/stat/stat.ih0000644000175000017500000000037214050437223014356 0ustar frankfrank#include "stat" #include #include #include #include #include "../string/string" #include "../user/user" #include "../fswap/fswap" #include "../exception/exception" using namespace std; using namespace FBB; bobcat-5.09.01/stat/lastchange.f0000644000175000017500000000014214050437223015334 0ustar frankfrankinline DateTime Stat::lastChange() const { return DateTime(d_stat.st_ctime, DateTime::UTC); } bobcat-5.09.01/stat/stat1.cc0000644000175000017500000000007114050437223014420 0ustar frankfrank#include "stat.ih" Stat::Stat() : d_errno(false) {} bobcat-5.09.01/stat/istype.f0000644000175000017500000000010514050437223014537 0ustar frankfrankinline bool Stat::isType(Type probe) { return type() == probe; } bobcat-5.09.01/stat/gid.f0000644000175000017500000000010614050437223013766 0ustar frankfrankinline size_t Stat::gid() const { return d_stat.st_gid; } bobcat-5.09.01/stat/error.f0000644000175000017500000000010214050437223014350 0ustar frankfrankinline size_t Stat::error() const { return d_errno; } bobcat-5.09.01/stat/set1.cc0000644000175000017500000000013114050437223014235 0ustar frankfrank#include "stat.ih" bool Stat::set(string const &name) { return set(::stat, name); } bobcat-5.09.01/stat/nlinks.f0000644000175000017500000000011314050437223014517 0ustar frankfrankinline size_t Stat::nLinks() const { return d_stat.st_nlink; } bobcat-5.09.01/stat/mode.f0000644000175000017500000000010614050437223014147 0ustar frankfrankinline size_t Stat::mode() const { return d_stat.st_mode & RWX; } bobcat-5.09.01/stat/device.f0000644000175000017500000000011114050437223014456 0ustar frankfrankinline size_t Stat::device() const { return d_stat.st_dev; } bobcat-5.09.01/stat/stat0000644000175000017500000001116014050437223013754 0ustar frankfrank#ifndef INCLUDED_BOBCAT_STAT_ #define INCLUDED_BOBCAT_STAT_ #include #include #include #include #include #include namespace FBB { class User; class Stat: public GS__ { struct stat d_stat; bool d_errno; std::string d_name; public: typedef struct stat stat; // Defines Stat::stat for clients enum Combine { ALL, ANY, }; enum SpecialMode { SUID = 04000, SGID = 02000, SB = 01000, }; enum Mode { UR = 0400, UW = 0200, UX = 0100, GR = 040, GW = 020, GX = 010, OR = 04, OW = 02, OX = 01, READ = UR | GR | OR, WRITE = UW | GW | OW, EXEC = UX | GX | OX, RWX = 0777, }; enum Lstat { LStat }; Stat(); // 1.cc Stat(Stat const &other) = default; Stat(Stat &&tmp); // 2.cc explicit Stat(std::string const &name); // 3.cc Stat(Lstat, std::string const &name); // 4.f Stat(std::string const &name, std::string const &pathlist); // 5.f Stat(Lstat, std::string const &name, // 6.f std::string const &pathlist); Stat &operator=(Stat const &other) = default; Stat &operator=(Stat &&tmp); bool access(User const &user, size_t mode, bool useEffective = true) const; DateTime lastAccess() const; // .f DateTime lastChange() const; // .f DateTime lastModification() const; // .f Type type() const; // .f bool isType(Type probe); // .f bool mode(size_t mode, Combine combi = ALL) const; bool set(std::string const &name); // 1.cc bool set(Lstat, std::string const &name); // 2.f bool set(std::string const &name, std::string const &pathlist); // 3.cc bool set(Lstat, std::string const &name, // 4.f std::string const &pathlist); bool specialMode(size_t specialMode, Combine combi = ALL) const; off_t size() const; // .f operator bool() const; // .f size_t blockSize() const; // .f size_t device() const; // .f size_t deviceType() const; // .f size_t error() const; // .f size_t gid() const; // .f size_t inode() const; // .f size_t mode() const; // .f size_t nBlocks() const; // .f size_t nLinks() const; // .f size_t uid() const; // .f stat const &statStruct() const; // .f std::string const &name(); // .f std::string modeStr() const; std::string path(); std::string typeStr() const; private: void init(int (*statFun)(char const *, stat *)); bool setPath(int (*statFun)(char const *, stat *), std::string const &name, std::string const &pathlist); bool set(int (*statFun)(char const *, stat *), // 5.cc std::string const &name); }; #include "stat6.f" #include "stat4.f" #include "stat5.f" #include "blocksize.f" #include "device.f" #include "devicetype.f" #include "error.f" #include "gid.f" #include "inode.f" #include "istype.f" #include "lastaccess.f" #include "lastchange.f" #include "lastmodification.f" #include "mode.f" #include "name.f" #include "nblocks.f" #include "nlinks.f" #include "opbool.f" #include "set2.f" #include "set4.f" #include "size.f" #include "statstruct.f" #include "type.f" #include "uid.f" } // FBB #endif bobcat-5.09.01/stat/set3.cc0000644000175000017500000000021014050437223014235 0ustar frankfrank#include "stat.ih" bool Stat::set(string const &name, string const &pathList) { return setPath(::stat, name, pathList); } bobcat-5.09.01/stat/stat4.f0000644000175000017500000000013214050437223014261 0ustar frankfrankinline Stat::Stat(Lstat, std::string const &name) : d_name(name) { init(lstat); } bobcat-5.09.01/stat/uid.f0000644000175000017500000000010414050437223014002 0ustar frankfrankinline size_t Stat::uid() const { return d_stat.st_uid; } bobcat-5.09.01/stat/typestr.cc0000644000175000017500000000127714050437223015107 0ustar frankfrank#include "stat.ih" string Stat::typeStr() const { string ret; switch (type()) { case BLOCK_DEVICE: ret = "BLOCK_DEVICE"; break; case CHARACTER_DEVICE: ret = "CHARACTER_DEVICE"; break; case DIRECTORY: ret = "DIRECTORY"; break; case FIFO: ret = "FIFO"; break; case REGULAR_FILE: ret = "REGULAR_FILE"; break; case SOCKET: ret = "SOCKET"; break; case SYMBOLIC_LINK: ret = "SYMBOLIC_LINK"; break; default: // ANY intentionally not handled break; } return ret; } bobcat-5.09.01/stat/init.cc0000644000175000017500000000030614050437223014330 0ustar frankfrank#include "stat.ih" void Stat::init(int (*statFun)(char const *, stat *)) { d_errno = (*statFun)(d_name.c_str(), &d_stat) ? errno : 0; } bobcat-5.09.01/stat/setpath.cc0000644000175000017500000000100614050437223015033 0ustar frankfrank#include "stat.ih" bool Stat::setPath(int (*statFun)(char const *, stat *), string const &name, string const &pathlist) { if (name[0] == '/') return set(statFun, name); vector element; String::split(&element, pathlist, ":"); for ( vector::iterator it = element.begin(); it != element.end(); ++it ) { if (set(statFun, *it + "/" + name)) return true; } return false; } bobcat-5.09.01/stat/set2.f0000644000175000017500000000012714050437223014103 0ustar frankfrankinline bool Stat::set(Lstat, std::string const &name) { return set(lstat, name); } bobcat-5.09.01/stat/specialmode.cc0000644000175000017500000000061514050437223015655 0ustar frankfrank#include "stat.ih" bool Stat::specialMode(size_t mode, Combine combi) const { if (mode & ~(SUID | SGID | SB)) throw Exception{1} << '0' << oct << mode << ": unknown special mode specification"; return (combi == ALL && mode == (d_stat.st_mode & (SUID | SGID | SB))) || (combi == ANY && (mode & d_stat.st_mode)); } bobcat-5.09.01/stat/mode.cc0000644000175000017500000000057014050437223014314 0ustar frankfrank#include "stat.ih" bool Stat::mode(size_t mode, Combine combi) const { if (mode & ~(UR | UW | UX | RWX)) throw Exception{1} << '0' << oct << mode << ": unknown mode specification"; return (combi == ALL && mode == (d_stat.st_mode & RWX)) || (combi == ANY && (mode & d_stat.st_mode)); } bobcat-5.09.01/stat/lastaccess.f0000644000175000017500000000014214050437223015350 0ustar frankfrankinline DateTime Stat::lastAccess() const { return DateTime(d_stat.st_atime, DateTime::UTC); } bobcat-5.09.01/stat/stat2.cc0000644000175000017500000000020214050437223014415 0ustar frankfrank#include "stat.ih" Stat::Stat(Stat &&tmp) : d_stat(tmp.d_stat), d_errno(tmp.d_errno), d_name( move(tmp.d_name) ) {} bobcat-5.09.01/stat/size.f0000644000175000017500000000010714050437223014176 0ustar frankfrankinline off_t Stat::size() const { return d_stat.st_size; } bobcat-5.09.01/stat/access.cc0000644000175000017500000000204014050437223014623 0ustar frankfrank#include "stat.ih" bool Stat::access(User const &user, size_t spec, bool useEffective) const { bool userIsOwner = (spec & (UR | UW | UX)) && ( user.userid() == uid() or (useEffective && user.eUserid() == uid()) ); bool userInGroup = (spec & (GR | GW | GX)) && user.inGroup(gid(), useEffective); size_t mod = mode(); return ( // Read test: (mod & OR) || ((mod & UR) && userIsOwner) || ((mod & GR) && userInGroup) || not (spec & READ) ) and ( // Write test: (mod & OW) || ((mod & UW) && userIsOwner) || ((mod & GW) && userInGroup) || not (spec & WRITE) ) and ( // Exec test: (mod & OX) || ((mod & UX) && userIsOwner) || ((mod & GX) && userInGroup) || not (spec & EXEC) ); } bobcat-5.09.01/stat/set5.cc0000644000175000017500000000023414050437223014245 0ustar frankfrank#include "stat.ih" bool Stat::set(int (*statFun)(char const *, stat *), string const &name) { d_name = name; init(statFun); return !d_errno; } bobcat-5.09.01/stat/stat6.f0000644000175000017500000000016714050437223014273 0ustar frankfrankinline Stat::Stat(Lstat, std::string const &name, std::string const &pathlist) { setPath(lstat, name, pathlist); } bobcat-5.09.01/stat/operatorassign.cc0000644000175000017500000000015314050437223016425 0ustar frankfrank#include "stat.ih" Stat &Stat::operator=(Stat &&tmp) { fswap(*this, tmp, d_name); return *this; } bobcat-5.09.01/stat/lastmodification.f0000644000175000017500000000015014050437223016553 0ustar frankfrankinline DateTime Stat::lastModification() const { return DateTime(d_stat.st_mtime, DateTime::UTC); } bobcat-5.09.01/stat/set4.f0000644000175000017500000000024214050437223014103 0ustar frankfrankinline bool Stat::set(Lstat, std::string const &name, std::string const &pathList) { return setPath(lstat, name, pathList); } bobcat-5.09.01/stat/opbool.f0000644000175000017500000000010014050437223014507 0ustar frankfrankinline Stat::operator bool() const { return d_errno == 0; } bobcat-5.09.01/stat/stat5.f0000644000175000017500000000016114050437223014264 0ustar frankfrankinline Stat::Stat(std::string const &name, std::string const &pathlist) { setPath(::stat, name, pathlist); } bobcat-5.09.01/stat/devicetype.f0000644000175000017500000000011614050437223015365 0ustar frankfrankinline size_t Stat::deviceType() const { return d_stat.st_rdev; } bobcat-5.09.01/stat/path.cc0000644000175000017500000000060714050437223014325 0ustar frankfrank#include "stat.ih" // This is required for the hurd-i386 arch, which apparently // fails to implement the POSIX standard: #ifndef PATH_MAX # ifdef MAXPATHLEN # define PATH_MAX MAXPATHLEN # else # define PATH_MAX 2048 # endif #endif string Stat::path() { unique_ptr buf(new char[PATH_MAX]); return !realpath(d_name.c_str(), buf.get()) ? "" : buf.get(); } bobcat-5.09.01/stat/type.f0000644000175000017500000000014014050437223014202 0ustar frankfrankinline Stat::Type Stat::type() const { return static_cast(d_stat.st_mode & S_IFMT); } bobcat-5.09.01/stat/blocksize.f0000644000175000017500000000012014050437223015204 0ustar frankfrankinline size_t Stat::blockSize() const { return d_stat.st_blksize; } bobcat-5.09.01/stat/driver/0000755000175000017500000000000014050437223014352 5ustar frankfrankbobcat-5.09.01/stat/driver/build0000755000175000017500000000055014050437223015377 0ustar frankfrank#!/bin/bash tput clear GPP="g++ `cat ../../c++std`" CMD="$GPP -o driver -Wall driver.cc -L../tmp -lstat -lbobcat -s" # CMD="$GPP -o driver -Wall -I../../tmp driver.cc -L../../tmp/lib -lbobcat -s" # CMD="$GPP -o driver -Wall -I../ driver.cc -L../tmp -lstat -lbobcat -s" # CMD="$GPP -o driver -Wall *.cc -lbobcat -s" echo $CMD $CMD || exit 1 echo Ready... bobcat-5.09.01/stat/driver/driver.cc0000644000175000017500000000236214050437223016157 0ustar frankfrank/* driver.cc */ #include #include #include "../stat" #include using namespace std; using namespace FBB; int main(int argc, char **argv) { if (argc == 1) { cout << "Usage: driver [-l] object [colon-separated searchpath]\n"; return 1; } bool lstat = "-l"s == argv[1]; if (lstat) { ++argv; --argc; } Stat st; if (argc == 2) { if (lstat) st.set(Stat::LStat, argv[1]); else st.set(argv[1]); } else if (argc == 3) { if (lstat) st.set(Stat::LStat, argv[1], argv[2]); else st.set(argv[1], argv[2]); } if (!st) { cout << "Can't stat " << argv[1] << ", errno = " << st.error() << endl; return 1; } cout << st.name() << ": access: " << st.lastAccess() << "\n" << st.name() << ": change: " << st.lastChange() << "\n" << st.name() << ": modif: " << st.lastModification() << "\n" "Mode: " << oct << st.mode() << " (" << st.modeStr() << ")\n" "Type: " << st.type() << " (" << st.typeStr() << ")\n" "Full path: " << st.path() << endl; } bobcat-5.09.01/stat/driver/driver.ln0000777000175000017500000000000014050437223017777 2driver.ccustar frankfrankbobcat-5.09.01/stat/statstruct.f0000644000175000017500000000011114050437223015437 0ustar frankfrankinline Stat::stat const &Stat::statStruct() const { return d_stat; } bobcat-5.09.01/stdextractor/0000755000175000017500000000000014050437223014632 5ustar frankfrankbobcat-5.09.01/stdextractor/stdextractor2.cc0000644000175000017500000000022114050437223017744 0ustar frankfrank#include "stdextractor.ih" StdExtractor::StdExtractor(StdMode mode, size_t bufSize) : IUO::ExtractorBase(bufSize), d_modeFun(close) {} bobcat-5.09.01/stdextractor/stdextractor0000644000175000017500000000067014050437223017306 0ustar frankfrank#ifndef INCLUDED_BOBCAT_STDEXTRACTOR_ #define INCLUDED_BOBCAT_STDEXTRACTOR_ #include namespace FBB { class StdExtractor: public IUO::ExtractorBase { void (*d_modeFun)(); public: StdExtractor(size_t bufSize = 100); StdExtractor(StdMode mode, size_t bufSize = 100); private: void childRedirections() override; static void close(); }; } // namespace FBB #endif bobcat-5.09.01/stdextractor/close.cc0000644000175000017500000000023614050437223016247 0ustar frankfrank#include "stdextractor.ih" void StdExtractor::close() // static { ::close(STDIN_FILENO); // close and reopen stdin ::open("/dev/null", O_RDONLY); } bobcat-5.09.01/stdextractor/childredirections.cc0000644000175000017500000000040714050437223020640 0ustar frankfrank#include "stdextractor.ih" namespace { int stdFds[] = { STDOUT_FILENO, STDERR_FILENO }; } void StdExtractor::childRedirections() { (*d_modeFun)(); // optionally close STDIN childOutPipe().writtenBy(stdFds, 2); } bobcat-5.09.01/stdextractor/stdextractor1.cc0000644000175000017500000000020514050437223017745 0ustar frankfrank#include "stdextractor.ih" StdExtractor::StdExtractor(size_t bufSize) : IUO::ExtractorBase(bufSize), d_modeFun(noClose) {} bobcat-5.09.01/stdextractor/stdextractor.ih0000644000175000017500000000015314050437223017701 0ustar frankfrank#include "stdextractor" #include #include using namespace std; using namespace FBB; bobcat-5.09.01/stdextractor/driver/0000755000175000017500000000000014050437223016125 5ustar frankfrankbobcat-5.09.01/stdextractor/driver/build0000755000175000017500000000017314050437223017153 0ustar frankfrank#!/bin/bash g++ -Wall -odriver driver.cc -L../../extractorbase/tmp -lextractorbase \ -L../tmp -lstdextractor -lbobcat bobcat-5.09.01/stdextractor/driver/driver.cc0000644000175000017500000000071114050437223017726 0ustar frankfrank#include #include "../stdextractor" using namespace std; using namespace FBB; int main() { StdExtractor extractor; extractor.execute("/bin/cat build out"); // out does not exist string line; getline(extractor, line); cout << "First line: " << line << "\n\n"; extractor.execute("/bin/cat build out"); // out does not exist cout << extractor.rdbuf(); cerr << "Returning: " << extractor.ret() << '\n'; } bobcat-5.09.01/string/0000755000175000017500000000000014050437223013412 5ustar frankfrankbobcat-5.09.01/string/splitpair2.f0000644000175000017500000000017114050437223015651 0ustar frankfrankinline String::SplitPair::SplitPair(char ch, Type type) : std::pair(std::string(1, ch), type) {} bobcat-5.09.01/string/escape1.cc0000644000175000017500000000107414050437223015244 0ustar frankfrank#include "string.ih" string String::escape(string const &str, char const *series) { string ret; string::size_type left = 0; while (true) { string::size_type right = str.find_first_of(series, left); ret += str.substr(left, right - left); // append until separator if (right == string::npos) // done when all copied return ret; ret += "\\"; // append backslash ret += str[right]; // append the special char left = right + 1; } } bobcat-5.09.01/string/string.ih0000644000175000017500000000035114050437223015241 0ustar frankfrank#include "string" #include #include #include #include using namespace std; using namespace FBB; #include "tolower.f" #include "toupper.f" #include "splitpair1.f" #include "splitpair2.f" bobcat-5.09.01/string/join1.cc0000644000175000017500000000047114050437223014743 0ustar frankfrank#include "string.ih" string String::join(vector const &words, char sep) { string ret; if (words.empty()) return ret; auto begin = words.begin(); ret = *begin++; for (auto const &end = words.end(); begin != end; ++begin) (ret += sep) += *begin; return ret; } bobcat-5.09.01/string/sqin.cc0000644000175000017500000000023114050437223014667 0ustar frankfrank#include "string.ih" bool String::sqIn(FSAData &data) { ++data.begin; data.entry.second = SQUOTE; data.state = SQSTRING; return true; } bobcat-5.09.01/string/data.cc0000644000175000017500000000127014050437223014632 0ustar frankfrank#include "string.ih" bool (*String::s_FSAtransition[][s_nCharTypes])(FSAData &) = { // DQUOTE, SQUOTE, SEPARATOR, ESCAPE, CHAR, EOS, { &dqIn, &sqIn, &sepIn, &escIn, &chIn, &eosIn }, // START { &chIn, &qEnd, &chIn, &chIn, &chIn, &eosSq }, // SQSTRING { &qEnd, &chIn, &chIn, &escIn, &chIn, &eosDq }, // DQSTRING }; // static void String::strsep(SplitPairVector *entries) // no action required {} void (*String::s_tuneToSplitType[])(SplitPairVector *entries) = { &tok, &toksep, &str, &strsep }; string (*String::s_join[])(SplitPairVector const &entries, char sep) { &joinIgnoreSEPARATOR, &joinAll }; bobcat-5.09.01/string/urlencode.cc0000644000175000017500000000134314050437223015702 0ustar frankfrank#include "string.ih" // after https://stackoverflow.com/questions/154536/encode-decode-urls-in-c // static string String::urlEncode(string const &text) { ostringstream escaped; escaped.fill('0'); escaped << hex << uppercase; for (auto ch: text) { // Keep alphanumeric and other accepted characters intact if (isalnum(ch) || string{"-_.~"}.find(ch) != string::npos) { escaped.put(ch); continue; } // Any other characters are percent-encoded escaped << '%' << setw(2) << static_cast( static_cast(ch) ); } return escaped.str(); } bobcat-5.09.01/string/argv.cc0000644000175000017500000000041014050437223014653 0ustar frankfrank#include "string.ih" char const **String::argv(std::vector const &lines) { size_t idx = lines.size(); char const **ret = new char const *[idx + 1]; ret[idx] = 0; for (; idx--; ) ret[idx] = lines[idx].c_str(); return ret; } bobcat-5.09.01/string/tok.cc0000644000175000017500000000056714050437223014526 0ustar frankfrank#include "string.ih" // Keeps the elements that would have been returned by strtok void String::tok(SplitPairVector *entries) { auto end = remove_if(entries->begin(), entries->end(), [&](SplitPair const &entry) { return entry.second == SEPARATOR || entry.first.empty(); } ); entries->resize(end - entries->begin()); } bobcat-5.09.01/string/split8.cc0000644000175000017500000000037714050437223015153 0ustar frankfrank#include "string.ih" size_t String::split(std::vector *words, std::string const &str, char const *sep, bool addEmpty) { return split(words, str, addEmpty ? TOKSEP : TOK, sep); } bobcat-5.09.01/string/string0000644000175000017500000001423014050437223014643 0ustar frankfrank#ifndef INCLUDED_BOBCAT_STRING_ #define INCLUDED_BOBCAT_STRING_ #include #include #include #include namespace FBB { struct String { enum Type { DQUOTE_UNTERMINATED, // unterminated d-quoted element SQUOTE_UNTERMINATED, // unterminated s-quoted element ESCAPED_END, // word with plain \ at the end SEPARATOR, // separator encountered NORMAL, // normal string-element in the original string DQUOTE, // string-element originally surrounded by " chars SQUOTE, // string-element originally surrounded by ' chars END, // end-of-string immediately encountered }; enum SplitType { TOK, // split acts like strtok (like addEmpty == false) TOKSEP, // same, but return separators (like addEmpty == true) STR, // split acts like strstr STRSEP, // same, but return separators }; struct Unescape { std::string str; size_t length; }; struct SplitPair: public std::pair { SplitPair(); SplitPair(char ch, Type type); }; private: typedef std::vector SplitPairVector; typedef std::string::const_iterator ConstIter; static size_t const s_nSplitTypeSize = static_cast(STRSEP) + 1; enum class CharType { DQUOTE, SQUOTE, SEPARATOR, ESCAPE, CHAR, EOS, size }; static size_t const s_nCharTypes = static_cast(CharType::size); enum State { START, SQSTRING, DQSTRING, }; struct FSAData { State state; std::string separators; SplitPair entry; SplitPairVector *entries; ConstIter begin; ConstIter end; }; static bool (*s_FSAtransition[][s_nCharTypes])(FSAData &); static void (*s_tuneToSplitType[s_nSplitTypeSize])( SplitPairVector *entries); static std::string (*s_join[])(SplitPairVector const &, char); public: static constexpr Type *const noType = 0; static char const **argv(std::vector const &lines); static int casecmp(std::string const &lhs, // .f std::string const &rhs); static std::string escape(std::string const &str, char const *series = "'\"\\"); static std::string join(std::vector const &words, // 1 char sep); static std::string join(SplitPairVector const &entries, char sep, // 2 bool all = true); static std::string lc(std::string const &str); static SplitPairVector split(std::string const &str, // 1 SplitType stype, char const *separators = " \t"); static SplitPairVector split(std::string const &str, // 2 char const *separators = " \t", bool addEmpty = false); static size_t split(SplitPairVector *entries, // 3 std::string const &str, SplitType stype, char const *separators = " \t"); static size_t split(SplitPairVector *entries, // 4 std::string const &str, char const *separators = " \t", bool addEmpty = false); static std::vector split( // 5 Type *type, std::string const &str, SplitType stype, char const *separators = " \t"); static std::vector split( // 6 Type *type, std::string const &str, char const *separators = " \t", bool addEmpty = false); static size_t split(std::vector *words, // 7 std::string const &str, SplitType stype, char const *separators = " \t"); static size_t split(std::vector *words, // 8 std::string const &str, char const *separators = " \t", bool addEmpty = false); static std::string trim(std::string const &str); static std::string uc(std::string const &str); static std::string unescape(std::string const &str); static Unescape unescape(ConstIter begin, // 2 ConstIter const &end); static std::string urlDecode(std::string const &str); static std::string urlEncode(std::string const &str); private: static void tolower(char &chr); // .f static void toupper(char &chr); // .f static FSAData process(SplitPairVector *entries, SplitType stype, std::string const &str, char const *sep); static CharType peek(FSAData &data); static bool dqIn(FSAData &data); static bool sqIn(FSAData &data); static bool sepIn(FSAData &data); static bool escIn(FSAData &data); static bool chIn(FSAData &data); static bool eosIn(FSAData &data); static bool qEnd(FSAData &data); static bool eosSq(FSAData &data); static bool eosDq(FSAData &data); static void tok(SplitPairVector *entries); // tuning members static void toksep(SplitPairVector *entries); static void str(SplitPairVector *entries); static void strsep(SplitPairVector *entries); // see data.cc static std::string joinAll(SplitPairVector const &entries, char sep); static std::string joinIgnoreSEPARATOR(SplitPairVector const &entries, char sep); }; #include "casecmp.f" } // FBB #endif bobcat-5.09.01/string/split4.cc0000644000175000017500000000036714050437223015146 0ustar frankfrank#include "string.ih" size_t String::split( SplitPairVector *entries, std::string const &str, char const *sep, bool addEmpty) { return split(entries, str, addEmpty ? TOKSEP : TOK, sep); } bobcat-5.09.01/string/split1.cc0000644000175000017500000000035314050437223015136 0ustar frankfrank#include "string.ih" String::SplitPairVector String::split(string const &str, SplitType stype, char const *sep) { SplitPairVector ret; process(&ret, stype, str, sep); return ret; } bobcat-5.09.01/string/unescape2.cc0000644000175000017500000000327314050437223015613 0ustar frankfrank#include "string.ih" String::Unescape String::unescape(ConstIter begin, ConstIter const &end) { // no chars, no backslash or nothing beyond // the backslash? Then no escape sequence if (begin == end || *begin != '\\' || ++begin == end) return Unescape{ "", 0 }; // a standard escape char if (string{ "abfnrtv" }.find(*begin) != string::npos) return Unescape{ string(1, *begin), 2 }; size_t nDigits; string str; for (nDigits = 0; nDigits != 3; ++nDigits) // inspect octal digits { int ch = *(begin + nDigits); if (string{ "01234567" }.find(ch) == string::npos) break; // stop at 1st non octal str += ch; } if (nDigits != 0) // got octal digit escape seq. return Unescape{ string( 1, static_cast(stoul(str, 0, 8)) ), nDigits + 1 }; if (*begin == 'x') // maybe hex escape seq. ? { for (nDigits = 0; nDigits != 2; ++nDigits) // inspect hex digits { int ch = *(begin + 1 + nDigits); if (not isxdigit(ch)) break; // stop at 1st non hex str += ch; } return nDigits == 0 ? // no hex, only \x Unescape{ "x", 2 } : Unescape{ string( 1, static_cast(stoul(str, 0, 16)) ), nDigits + 2 }; } return Unescape{ string(1, *begin), 2 }; } bobcat-5.09.01/string/split2.cc0000644000175000017500000000035514050437223015141 0ustar frankfrank#include "string.ih" std::vector String::split( std::string const &str, char const *sep, bool addEmpty) { return split(str, addEmpty ? TOKSEP : TOK, sep); } bobcat-5.09.01/string/lc1.cc0000644000175000017500000000022314050437223014375 0ustar frankfrank#include "string.ih" string String::lc(string const &str) { string ret(str); for (auto &ch: ret) tolower(ch); return ret; } bobcat-5.09.01/string/split6.cc0000644000175000017500000000041214050437223015137 0ustar frankfrank#include "string.ih" std::vector String::split( Type *type, std::string const &str, char const *sep, bool addEmpty) { return split(type, str, addEmpty ? TOKSEP : TOK, sep); } bobcat-5.09.01/string/join2.cc0000644000175000017500000000032714050437223014744 0ustar frankfrank#include "string.ih" string String::join(SplitPairVector const &entries, char sep, bool all) { return entries.empty() ? string{} : (*s_join[all])(entries, sep); } bobcat-5.09.01/string/casecmp.f0000644000175000017500000000020014050437223015164 0ustar frankfrankinline int String::casecmp(std::string const &lhs, std::string const &rhs) { return strcasecmp(lhs.c_str(), rhs.c_str()); } bobcat-5.09.01/string/eosdq.cc0000644000175000017500000000024514050437223015035 0ustar frankfrank#include "string.ih" bool String::eosDq(FSAData &data) { data.entry.second = DQUOTE_UNTERMINATED; data.entries->push_back(data.entry); return false; } bobcat-5.09.01/string/split5.cc0000644000175000017500000000104414050437223015140 0ustar frankfrank#include "string.ih" vector String::split(Type *type, string const &str, SplitType stype, char const *sep) { vector ret; SplitPairVector entries; auto data{ process(&entries, stype, str, sep) }; if (type != 0) *type = data.entry.second == DQUOTE || data.entry.second == SQUOTE || data.entry.second == SEPARATOR ? NORMAL : data.entry.second; for (auto &entry: entries) ret.push_back(move(entry.first)); return ret; } bobcat-5.09.01/string/unescape1.cc0000644000175000017500000000631114050437223015606 0ustar frankfrank#include "string.ih" namespace { char const escapeChars[] = "abfnrtv"; char const escapeValue[] = {'\a', '\b', '\f', '\n', '\r', '\t', '\v'}; size_t handleOctal(string *dest, string const &src, size_t pos) { size_t pos2 = min(src.length(), src.find_first_not_of("01234567", pos)); if (pos2 == pos + 1 && src[pos] == '0') // saw \0 { *dest += static_cast(0); return pos2; } size_t const nOct = 3; // need exactly 3 octals pos2 = min(pos + nOct, pos2); if (pos2 != pos + nOct) // need exactly nOct octals { *dest += src[pos]; // add next char if not so return pos + 1; // next to handle } // convert substr. to octal size_t ch = stoul(src.substr(pos, nOct), 0, 8); *dest += static_cast(ch); // append the octal value return pos2; // pos. of next to handle } size_t handleHex(string *dest, string const &src, size_t pos) { size_t const nHex = 2; // need exactly 2 hex digits ++pos; // skip the 'x' size_t pos2 = min(pos + nHex, src.find_first_not_of( "0123456789abcdefABCDEF", pos)); if (pos2 != pos + nHex) // found a hex character? { *dest += src[pos - 1]; // add next char if so return pos; // next char to handle } // convert substr. to hex size_t ch = stoul(src.substr(pos, nHex), 0, 16); *dest += static_cast(ch); // append the hex value return pos2; // pos. of next to handle } } string String::unescape(string const &str) { string ret; size_t prefix = 0; // prefix text before \-char size_t pos = 0; while (true) { pos = str.find('\\', pos); ret += str.substr(prefix, pos - prefix);// append prefix if (pos == string::npos) // done if no more \-chars return ret; ++pos; // skip \-char if (pos == str.length()) // \-char terminates: remove it return ret; // since we're removing \-chars int next = str[pos]; // determine next char if (char const *cp = strchr(escapeChars, next))// escape sequence ? { ret += escapeValue[cp - escapeChars];// then assign escape char ++pos; // next character to handle } else if (strchr("01234567", next)) // handle octal values pos = handleOctal(&ret, str, pos); else if (next == 'x') // handle hex values pos = handleHex(&ret, str, pos); else // handle lone characters ret += str[pos++]; prefix = pos; } } bobcat-5.09.01/string/tolower.f0000644000175000017500000000010514050437223015250 0ustar frankfrankinline void String::tolower(char &chr) { chr = ::tolower(chr); } bobcat-5.09.01/string/split3.cc0000644000175000017500000000043214050437223015136 0ustar frankfrank#include "string.ih" size_t String::split(SplitPairVector *entries, string const &str, SplitType stype, char const *sep) { entries->clear(); // clear the destination vector return process(entries, stype, str, sep).entries->size(); } bobcat-5.09.01/string/sepin.cc0000644000175000017500000000053214050437223015037 0ustar frankfrank#include "string.ih" bool String::sepIn(FSAData &data) { data.entries->push_back(data.entry); // store the current entry // store the separator data.entries->push_back(SplitPair{ *data.begin++, SEPARATOR }); data.entry = SplitPair{}; // start a new entry return true; } bobcat-5.09.01/string/peek.cc0000644000175000017500000000070614050437223014650 0ustar frankfrank#include "string.ih" String::CharType String::peek(FSAData &data) { if (data.begin == data.end) return CharType::EOS; if (data.separators.find(*data.begin) != string::npos) return CharType::SEPARATOR; switch (*data.begin) { case '"': return CharType::DQUOTE; case '\'': return CharType::SQUOTE; case '\\': return CharType::ESCAPE; default: return CharType::CHAR; } } bobcat-5.09.01/string/chin.cc0000644000175000017500000000021514050437223014640 0ustar frankfrank#include "string.ih" bool String::chIn(FSAData &data) { data.entry.first += *data.begin++; // store the character return true; } bobcat-5.09.01/string/toksep.cc0000644000175000017500000000100314050437223015220 0ustar frankfrank#include "string.ih" // Keep the elements that would have been returned by strtok, and indicate // separators by empty strings void String::toksep(SplitPairVector *entries) { auto end = remove_if(entries->begin(), entries->end(), [&](SplitPair const &entry) { return entry.first.empty(); } ); entries->resize(end - entries->begin()); for (auto &entry: *entries) { if (entry.second == SEPARATOR) entry.first.clear(); } } bobcat-5.09.01/string/joinall.cc0000644000175000017500000000044314050437223015352 0ustar frankfrank#include "string.ih" string String::joinAll(SplitPairVector const &entries, char sep) { string ret; auto begin = entries.begin(); ret = begin++->first; for (auto const &end = entries.end(); begin != end; ++begin) (ret += sep) += begin->first; return ret; } bobcat-5.09.01/string/uc1.cc0000644000175000017500000000022414050437223014407 0ustar frankfrank#include "string.ih" string String::uc(string const &lhs) { string ret(lhs); for (auto &ch: ret) toupper(ch); return ret; } bobcat-5.09.01/string/split7.cc0000644000175000017500000000033114050437223015140 0ustar frankfrank#include "string.ih" size_t String::split(vector *words, string const &str, SplitType stype, char const *sep) { *words = split(noType, str, stype, sep); return words->size(); } bobcat-5.09.01/string/process.cc0000644000175000017500000000065614050437223015406 0ustar frankfrank#include "string.ih" String::FSAData String::process(SplitPairVector *entries, SplitType stype, string const &str, char const *sep) { FSAData ret{ START, sep, SplitPair{}, entries, str.begin(), str.end() }; while ((*s_FSAtransition[ret.state] [static_cast(peek(ret))])(ret) ) ; (*s_tuneToSplitType[stype])(entries); return ret; } bobcat-5.09.01/string/joinignoreseparator.cc0000644000175000017500000000105414050437223020005 0ustar frankfrank#include "string.ih" string String::joinIgnoreSEPARATOR(SplitPairVector const &entries, char sep) { string ret; auto begin = find_if(entries.begin(), entries.end(), [&](SplitPair const &entry) { return entry.second != SEPARATOR; } ); auto end = entries.end(); if (begin == end || entries.empty()) return ret; ret = begin++->first; for ( ; begin != end; ++begin) { if (begin->second != SEPARATOR) (ret += sep) += begin->first; } return ret; } bobcat-5.09.01/string/dqin.cc0000644000175000017500000000023114050437223014650 0ustar frankfrank#include "string.ih" bool String::dqIn(FSAData &data) { ++data.begin; data.entry.second = DQUOTE; data.state = DQSTRING; return true; } bobcat-5.09.01/string/urldecode.cc0000644000175000017500000000064414050437223015673 0ustar frankfrank#include "string.ih" // static string String::urlDecode(string const &encoded) { string ret; for (auto begin = encoded.begin(); begin != encoded.end(); ++begin) { if (*begin != '%') ret += *begin; else { string convert{begin + 1, begin + 3}; begin += 2; ret += stoi(convert, 0, 16); } } return ret; } bobcat-5.09.01/string/eossq.cc0000644000175000017500000000024414050437223015053 0ustar frankfrank#include "string.ih" bool String::eosSq(FSAData &data) { data.entry.second = SQUOTE_UNTERMINATED; data.entries->push_back(data.entry); return false; } bobcat-5.09.01/string/str.cc0000644000175000017500000000054014050437223014530 0ustar frankfrank#include "string.ih" // Keeps the elements that would have been returned by strtok void String::str(SplitPairVector *entries) { auto end = remove_if(entries->begin(), entries->end(), [&](SplitPair const &entry) { return entry.second == SEPARATOR; } ); entries->resize(end - entries->begin()); } bobcat-5.09.01/string/escin.cc0000644000175000017500000000075114050437223015025 0ustar frankfrank#include "string.ih" bool String::escIn(FSAData &data) { Unescape ue = unescape(data.begin, data.end); if (ue.length == 0) // illegal escape seq. { data.entry.first += '\\'; data.entry.second = ESCAPED_END; data.entries->push_back(data.entry); return false; } data.begin += ue.length; // skip beyond the esc. seq. data.entry.first += ue.str.front(); // add the converted esc. seq. return true; } bobcat-5.09.01/string/qend.cc0000644000175000017500000000032114050437223014644 0ustar frankfrank#include "string.ih" bool String::qEnd(FSAData &data) { ++data.begin; // skip the single quote data.state = START; // start from the beginning return true; } bobcat-5.09.01/string/trim1.cc0000644000175000017500000000047414050437223014762 0ustar frankfrank#include "string.ih" string String::trim(string const &str) { string::size_type idx = str.find_first_not_of(" \t\r\n"); // find first non-ws if (idx == string::npos) // only ws chars? return string(); return str.substr(idx, str.find_last_not_of(" \t\r\n") - idx + 1); } bobcat-5.09.01/string/splitpair1.f0000644000175000017500000000013114050437223015644 0ustar frankfrankinline String::SplitPair::SplitPair() : std::pair("", NORMAL) {} bobcat-5.09.01/string/toupper.f0000644000175000017500000000010514050437223015253 0ustar frankfrankinline void String::toupper(char &chr) { chr = ::toupper(chr); } bobcat-5.09.01/string/driver/0000755000175000017500000000000014050437223014705 5ustar frankfrankbobcat-5.09.01/string/driver/build0000755000175000017500000000107214050437223015732 0ustar frankfrank#!/bin/bash rm -f driver case $1 in (loc) echo "g++ -c driver.cc" g++ -I. -c driver.cc || exit 1 g++ -o driver driver.o -L../tmp -lstring -lbobcat ;; (lib) echo "g++ -c driver.cc" g++ -o driver.o -c driver.cc -lbobcat ;; (*) echo " Usage: build loc - build the driver using the shared library created in ../../tmp/lib build lib - build the driver using the shared bobcat library installed in the standard location for shared libs " exit 1 ;; esac bobcat-5.09.01/string/driver/driver.cc0000644000175000017500000000406614050437223016515 0ustar frankfrank#include #include #include using namespace std; using namespace FBB; static char const *type[] = { "DQUOTE_UNTERMINATED", "SQUOTE_UNTERMINATED", "ESCAPED_END", "SEPARATOR", "NORMAL", "DQUOTE", "SQUOTE", }; int main(int argc, char **argv) { cout << "Program's name in uppercase: " << String::uc(argv[0]) << "\n\n"; vector splitpair; string text{ "one, two, 'thr\\x65\\145'" }; string encoded{ String::urlEncode(text) }; cout << "The string `" << text << "'\n" " as url-encoded string: `" << encoded << "'\n" " and the latter string url-decoded: " << String::urlDecode(encoded) << "\n" "\n" "Splitting `" << text << "' into " << String::split(&splitpair, text, String::STRSEP, ", ") << " fields\n"; for (auto it = splitpair.begin(); it != splitpair.end(); ++it) cout << (it - splitpair.begin() + 1) << ": " << type[it->second] << ": `" << it->first << "', unescaped: `" << String::unescape(it->first) << "'\n"; cout << '\n' << text << ":\n" " upper case: " << String::uc(text) << ",\n" " lower case: " << String::lc(text) << '\n'; } /* Calling the program as driver' results in the following output: Program's name in uppercase: DRIVER Splitting `one, two, 'thr\x65\145'' into 9 fields 1: NORMAL: `one', unescaped: `one' 2: SEPARATOR: `,', unescaped: `,' 3: NORMAL: `', unescaped: `' 4: SEPARATOR: ` ', unescaped: ` ' 5: NORMAL: `two', unescaped: `two' 6: SEPARATOR: `,', unescaped: `,' 7: NORMAL: `', unescaped: `' 8: SEPARATOR: ` ', unescaped: ` ' 9: SQUOTE: `thr\x65\145', unescaped: `three' one, two, 'thr\x65\145': upper case: ONE, TWO, 'THR\X65\145', lower case: one, two, 'thr\x65\145' */ bobcat-5.09.01/string/driver/splitdriver.cc0000644000175000017500000000502714050437223017567 0ustar frankfrank// compile with // gx splitdriver.cc -L ../tmp/ -lstring -lbobcat #include #include "../string" using namespace std; using namespace FBB; char const *typeName[] = { "DQUOTE_UNTERMINATED", // unterminated d-quoted element "SQUOTE_UNTERMINATED", // unterminated s-quoted element "ESCAPED_END", // word with plain \ at the end "SEPARATOR", // separator encountered "NORMAL", // normal string-element in the original string "DQUOTE", // string-element originally surrounded by " chars "SQUOTE", // string-element originally surrounded by ' chars }; // enum SplitType // { // TOK, // 0 acts like strtok (10: addEmpty == false) // TOKSEP, // 1 same, returns separators (11: addempty true) // STR, // 2 acts like strstr // STRSEP, // 3 same, but return separators // }; int main(int argc, char **argv) { while (true) { cout << "? "; int type; cin >> type; cin.ignore(); string line; if (not getline(cin, line)) break; // vector vect{ // type >= 10 ? // String::split(line, ",", type == 11) // : // String::split(line, // static_cast(type), ",") }; vector vect; if (type >= 10) String::split(&vect, line, ",", type == 11); else String::split(&vect, line, static_cast(type), ","); for (auto const &element: vect) cout << '`' << element.first << "': " << typeName[element.second] << '\n'; // String::Type strType; // vector vect{ // type >= 10 ? // String::split(&strType, line, ",", type == 11) // : // String::split(&strType, line, // static_cast(type), ",") // }; // // cout << "Final type: " << strType << '\n'; // vector vect; // if (type >= 10) // String::split(&vect, line, ",", type == 11); // else // String::split(&vect, line, // static_cast(type), ","); // // for (auto const &element: vect) // cout << '`' << element << "'\n"; } } bobcat-5.09.01/string/driver/bobcat/0000755000175000017500000000000014050437223016137 5ustar frankfrankbobcat-5.09.01/string/driver/bobcat/splitpair2.f0000777000175000017500000000000014050437223023262 2../../splitpair2.fustar frankfrankbobcat-5.09.01/string/driver/bobcat/split1.f0000777000175000017500000000000014050437223021530 2../../split1.fustar frankfrankbobcat-5.09.01/string/driver/bobcat/split4.f0000777000175000017500000000000014050437223021536 2../../split4.fustar frankfrankbobcat-5.09.01/string/driver/bobcat/string0000777000175000017500000000000014050437223021244 2../../stringustar frankfrankbobcat-5.09.01/string/driver/bobcat/split3.f0000777000175000017500000000000014050437223021534 2../../split3.fustar frankfrankbobcat-5.09.01/string/driver/bobcat/casecmp.f0000777000175000017500000000000014050437223022126 2../../casecmp.fustar frankfrankbobcat-5.09.01/string/driver/bobcat/tolower.f0000777000175000017500000000000014050437223022266 2../../tolower.fustar frankfrankbobcat-5.09.01/string/driver/bobcat/split2.f0000777000175000017500000000000014050437223021532 2../../split2.fustar frankfrankbobcat-5.09.01/string/driver/bobcat/splitpair1.f0000777000175000017500000000000014050437223023260 2../../splitpair1.fustar frankfrankbobcat-5.09.01/string/driver/bobcat/toupper.f0000777000175000017500000000000014050437223022274 2../../toupper.fustar frankfrankbobcat-5.09.01/string/eosin.cc0000644000175000017500000000016714050437223015042 0ustar frankfrank#include "string.ih" bool String::eosIn(FSAData &data) { data.entries->push_back(data.entry); return false; } bobcat-5.09.01/stringline/0000755000175000017500000000000014050437223014262 5ustar frankfrankbobcat-5.09.01/stringline/stringline.ih0000644000175000017500000000010114050437223016752 0ustar frankfrank#include "stringline" using namespace std; using namespace FBB; bobcat-5.09.01/stringline/opextract.f0000644000175000017500000000014414050437223016441 0ustar frankfrankinline std::istream &operator>>(std::istream &in, StringLine &str) { return getline(in, str); } bobcat-5.09.01/stringline/stringline0000644000175000017500000000035614050437223016367 0ustar frankfrank#ifndef INCLUDED_BOBCAT_STRINGLINE_ #define INCLUDED_BOBCAT_STRINGLINE_ #include #include namespace FBB { struct StringLine: public std::string {}; #include "opextract.f" // istream >> StringLine } // FBB #endif bobcat-5.09.01/symcryptstreambufbase/0000755000175000017500000000000014050437223016542 5ustar frankfrankbobcat-5.09.01/symcryptstreambufbase/checkoutbufsize.cc0000644000175000017500000000053314050437223022247 0ustar frankfrank#include "symcryptstreambufbase.ih" void SymCryptStreambufBase::checkOutBufSize(size_t inputSize) { size_t outBufSize = (inputSize + d_blockSize - 1) / d_blockSize * d_blockSize; if (outBufSize > d_outBufSize) d_outBuf.reset(new char[d_outBufSize = outBufSize]); } bobcat-5.09.01/symcryptstreambufbase/symcryptstreambufbase.ih0000644000175000017500000000113014050437223023515 0ustar frankfrank#include "symcryptstreambufbase" #include #include "../exception/exception" #if OPENSSL_VERSION_NUMBER < 0x10100000L #ifndef INCLUDED_BOBCAT_OPENSSL #define INCLUDED_BOBCAT_OPENSSL #ifndef BOBCAT_EVP_CYPHER_CTX #define BOBCAT_EVP_CYPHER_CTX inline EVP_CIPHER_CTX *EVP_CIPHER_CTX_new() { EVP_CIPHER_CTX *ret = new EVP_CIPHER_CTX; EVP_CIPHER_CTX_init(ret); return ret; } inline void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx) { EVP_CIPHER_CTX_cleanup(ctx); delete ctx; } #endif #endif #endif using namespace std; using namespace FBB; using namespace IUO; bobcat-5.09.01/symcryptstreambufbase/symcryptstreambufbase1.cc0000644000175000017500000000277514050437223023603 0ustar frankfrank#include "symcryptstreambufbase.ih" SymCryptStreambufBase::SymCryptStreambufBase( int (*evpInit_ex)(EVP_CIPHER_CTX *, EVP_CIPHER const *, ENGINE *, unsigned char const *key, unsigned char const *iv), int (*evpUpdate)(EVP_CIPHER_CTX *, unsigned char *out, int *outl, unsigned char const *in, int inl), int (*evpFinal_ex)(EVP_CIPHER_CTX *, unsigned char *out, int *outl), std::istream &in, char const *type, std::string const &keyParam, std::string const &ivParam, size_t bufSize, size_t filterBufSize, ENGINE *engine ) : IFilterBuf(filterBufSize), d_ctx(EVP_CIPHER_CTX_new()), d_inBufSize(bufSize < 100 ? 100 : bufSize), d_in(in), d_evpUpdate(evpUpdate), d_evpFinal_ex(evpFinal_ex), d_inBuf(new char[d_inBufSize]) { OpenSSL_add_all_ciphers(); EVP_CIPHER const *cipherType = 0; if (type) cipherType = EVP_get_cipherbyname(type); if (cipherType == 0) throw Exception{} << "FBB::ISymCryptStreambuf: cipher " << (type ? type : "0") << " not available"; string key(keyParam); key.resize(EVP_MAX_KEY_LENGTH); string iv(ivParam); iv.resize(EVP_MAX_IV_LENGTH); (*evpInit_ex)(d_ctx, cipherType, engine, reinterpret_cast(key.data()), reinterpret_cast(iv.data())); d_blockSize = EVP_CIPHER_CTX_block_size(d_ctx); } bobcat-5.09.01/symcryptstreambufbase/filter.cc0000644000175000017500000000164414050437223020343 0ustar frankfrank#include "symcryptstreambufbase.ih" #include bool SymCryptStreambufBase::filter(char const **srcBegin, char const **srcEnd) { if (d_allDone) return false; d_in.read(d_inBuf.get(), d_inBufSize); size_t inBufRead = d_in.gcount(); // we got this many checkOutBufSize(inBufRead); int outBufSize; (*d_evpUpdate)( d_ctx, reinterpret_cast(d_outBuf.get()), &outBufSize, reinterpret_cast(d_inBuf.get()), inBufRead ); if (outBufSize == 0) { // encryption checkOutBufSize(d_blockSize); (*d_evpFinal_ex)( d_ctx, reinterpret_cast(d_outBuf.get()), &outBufSize ); d_allDone = true; } *srcBegin = d_outBuf.get(); *srcEnd = *srcBegin + outBufSize; return outBufSize; } bobcat-5.09.01/symcryptstreambufbase/destructor.cc0000644000175000017500000000017114050437223021246 0ustar frankfrank#include "symcryptstreambufbase.ih" SymCryptStreambufBase::~SymCryptStreambufBase() { EVP_CIPHER_CTX_free(d_ctx); } bobcat-5.09.01/symcryptstreambufbase/symcryptstreambufbase0000644000175000017500000000342114050437223023123 0ustar frankfrank#ifndef INCLUDED_BOBCAT_SYMCRYPTSTREAMBUFBASE_ #define INCLUDED_BOBCAT_SYMCRYPTSTREAMBUFBASE_ #include #include #include #include #include namespace FBB { namespace IUO // the facilities defined here are not further documented: { // the SymCryptStreambufBase class defined below should be // used by ISymCryptStreambuf only. class SymCryptStreambufBase: public FBB::IFilterBuf { EVP_CIPHER_CTX *d_ctx; size_t d_inBufSize; size_t d_blockSize; size_t d_outBufSize = 0; bool d_allDone = false; std::istream &d_in; int (*d_evpUpdate)(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, unsigned char const *in, int inl); int (*d_evpFinal_ex)(EVP_CIPHER_CTX *, unsigned char *out, int *outl); std::unique_ptr d_outBuf; std::unique_ptr d_inBuf; public: SymCryptStreambufBase( int (*evpInit)(EVP_CIPHER_CTX *, EVP_CIPHER const *, ENGINE *impl, unsigned char const *key, unsigned char const *iv), int (*evpUpdate)(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, unsigned char const *in, int inl), int (*evpFinal)(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl), std::istream &in, char const *type, std::string const &key, std::string const &iv, size_t bufSize, size_t filterBufSize, ENGINE *engine ); ~SymCryptStreambufBase() override; private: bool filter(char const **srcBegin, char const **srcEnd) override; void checkOutBufSize(size_t inputSize); }; } // IUO } // FBB #endif bobcat-5.09.01/syslogbuf/0000755000175000017500000000000014050437223014121 5ustar frankfrankbobcat-5.09.01/syslogbuf/xsputn.cc0000644000175000017500000000024014050437223015765 0ustar frankfrank#include "syslogbuf.ih" // override streamsize SyslogBuf::xsputn(char const *buf, streamsize nChars) { buffer().append(buf, nChars); return nChars; } bobcat-5.09.01/syslogbuf/overflow.cc0000644000175000017500000000022614050437223016273 0ustar frankfrank#include "syslogbuf.ih" int SyslogBuf::overflow(int ch) { if (ch != EOF) buffer() += ch; else sync(); return ch; } bobcat-5.09.01/syslogbuf/reset1.cc0000644000175000017500000000036014050437223015632 0ustar frankfrank#include "syslogbuf.ih" void SyslogBuf::reset(std::string const &ident, Priority priority, Facility facility, int option) { eoi(); d_orgPriority = d_priority = priority; reset(ident, facility, option); } bobcat-5.09.01/syslogbuf/reset2.cc0000644000175000017500000000025414050437223015635 0ustar frankfrank#include "syslogbuf.ih" void SyslogBuf::reset(string const &ident, Facility facility, int option) { d_ident = ident; openlog(d_ident.c_str(), option, facility); } bobcat-5.09.01/syslogbuf/defaultpriority.f0000644000175000017500000000012314050437223017512 0ustar frankfrankinline Priority SyslogBuf::defaultPriority() const { return d_orgPriority; } bobcat-5.09.01/syslogbuf/setpriority.cc0000644000175000017500000000023214050437223017022 0ustar frankfrank#include "syslogbuf.ih" Priority SyslogBuf::setPriority(Priority priority) { Priority old = d_priority; d_priority = priority; return old; } bobcat-5.09.01/syslogbuf/priority.f0000644000175000017500000000011114050437223016142 0ustar frankfrankinline Priority SyslogBuf::priority() const { return d_priority; } bobcat-5.09.01/syslogbuf/syslogbuf1.cc0000644000175000017500000000046614050437223016534 0ustar frankfrank#include "syslogbuf.ih" SyslogBuf::SyslogBuf(std::string const &ident, Priority priority, Facility facility, int option) : d_priority(priority), d_orgPriority(priority) { reset(ident, facility, option); setp(); // no buffer yet } bobcat-5.09.01/syslogbuf/eoi.f0000644000175000017500000000005514050437223015044 0ustar frankfrankinline void SyslogBuf::eoi() { eoi_(); } bobcat-5.09.01/syslogbuf/setdefaultpriority.cc0000644000175000017500000000024714050437223020375 0ustar frankfrank#include "syslogbuf.ih" Priority SyslogBuf::setDefaultPriority(Priority priority) { Priority old = d_orgPriority; d_orgPriority = priority; return old; } bobcat-5.09.01/syslogbuf/sync.cc0000644000175000017500000000033014050437223015400 0ustar frankfrank#include "syslogbuf.ih" int SyslogBuf::sync() { if (bufSize() != 0) { syslog(d_priority, "%s", buffer().c_str()); buffer().clear(); d_priority = d_orgPriority; } return 0; } bobcat-5.09.01/syslogbuf/destructor.cc0000644000175000017500000000010714050437223016624 0ustar frankfrank#include "syslogbuf.ih" SyslogBuf::~SyslogBuf() { // eoi(); } bobcat-5.09.01/syslogbuf/syslogbuf.ih0000644000175000017500000000014314050437223016456 0ustar frankfrank#include "syslogbuf" #include "../exception/exception" using namespace std; using namespace FBB; bobcat-5.09.01/syslogbuf/eoi.cc0000644000175000017500000000016314050437223015204 0ustar frankfrank#include "syslogbuf.ih" void SyslogBuf::eoi_() { sync(); closelog(); // syslog.h } bobcat-5.09.01/syslogbuf/syslogbuf0000644000175000017500000001007314050437223016062 0ustar frankfrank#ifndef INCLUDED_BOBCAT_SYSLOGBUF_ #define INCLUDED_BOBCAT_SYSLOGBUF_ // see below for the options/facility/level overview #include #include #include namespace FBB { enum Priority { NOTICE = LOG_NOTICE, EMERG = LOG_EMERG, ALERT = LOG_ALERT, CRIT = LOG_CRIT, ERR = LOG_ERR, WARNING = LOG_WARNING, INFO = LOG_INFO, DEBUG = LOG_DEBUG, }; enum PriorityType { SINGLE, UPTO }; enum Facility { AUTHPRIV = LOG_AUTHPRIV, CRON = LOG_CRON, DAEMON = LOG_DAEMON, KERN = LOG_KERN, LOCAL0 = LOG_LOCAL0, LOCAL1 = LOG_LOCAL1, LOCAL2 = LOG_LOCAL2, LOCAL3 = LOG_LOCAL3, LOCAL4 = LOG_LOCAL4, LOCAL5 = LOG_LOCAL5, LOCAL6 = LOG_LOCAL6, LOCAL7 = LOG_LOCAL7, LPR = LOG_LPR, MAIL = LOG_MAIL, NEWS = LOG_NEWS, USER = LOG_USER, UUCP = LOG_UUCP, }; class SyslogBuf: public EoiBuf { Priority d_priority; Priority d_orgPriority; std::string d_ident; public: explicit SyslogBuf(std::string const &ident = "", Priority priority = NOTICE, Facility facility = USER, int option = 0); ~SyslogBuf(); void reset(std::string const &ident, // 1 Priority priority = NOTICE, Facility facility = USER, int option = 0); void eoi(); // .f Priority defaultPriority() const; // .f Priority priority() const; // .f Priority setDefaultPriority(Priority priority); Priority setPriority(Priority priority); private: int sync() override; int overflow(int ch) override; void eoi_() override; // .cc std::streamsize xsputn(char const *buffer, std::streamsize nChars) override; void reset(std::string const &ident, Facility facility, // 2 int option); }; #include "defaultpriority.f" #include "priority.f" #include "eoi.f" } // FBB /* options (default: none): LOG_CONS write directly to system console if there is an error while sending to system logger LOG_NDELAY open the connection immediately (normally, the con- nection is opened when the first message is logged) LOG_PERROR print to stderr as well LOG_PID include PID with each message facility type of program doing the logging. LOG_USER is used as default: LOG_AUTHPRIV security/authorization messages (private) LOG_CRON clock daemon (cron and at) LOG_DAEMON other system daemons LOG_KERN kernel messages LOG_LOCAL0 through LOG_LOCAL7 reserved for local use LOG_LPR line printer subsystem LOG_MAIL mail subsystem LOG_NEWS USENET news subsystem LOG_SYSLOGBUF messages generated internally by syslogbufd LOG_USER(default) generic user-level messages LOG_UUCP UUCP subsystem level (priority): LOG_NOTICE is used by default. This determines the importance of the message. The levels are, in order of decreasing importance: LOG_EMERG system is unusable LOG_ALERT action must be taken immediately LOG_CRIT critical conditions LOG_ERR error conditions LOG_WARNING warning conditions LOG_NOTICE (Used as DEFAULT) normal, but significant, condition LOG_INFO informational message LOG_DEBUG debug-level message */ #endif bobcat-5.09.01/syslogbuf/driver/0000755000175000017500000000000014050437223015414 5ustar frankfrankbobcat-5.09.01/syslogbuf/driver/build0000755000175000017500000000040714050437223016442 0ustar frankfrank#!/bin/bash tput clear GPP="g++ --std=c++2a" # Using tmp libraries and bobcat CMD="$GPP -o driver -Wall -I../../tmp driver.cc \ -L../tmp -lsyslogbuf \ -lbobcat -s" # -L../../eoibuf/tmp -leoibuf \ # -L../../eoi/tmp -leoi \ echo ${CMD} ${CMD} bobcat-5.09.01/syslogbuf/driver/driver.cc0000644000175000017500000000046714050437223017225 0ustar frankfrank#include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) { cout << "messages are logged in /var/log/user.log\n"; SyslogBuf sbuf("slb-"s + argv[0]); ostream sls(&sbuf); sls << "Hello world" << endl; } bobcat-5.09.01/syslogstream/0000755000175000017500000000000014050437223014640 5ustar frankfrankbobcat-5.09.01/syslogstream/alert.f0000644000175000017500000000014414050437223016115 0ustar frankfrankinline std::ostream &SyslogStream::alert(std::ostream &str) { return setPriority(str, ALERT); } bobcat-5.09.01/syslogstream/emerg.f0000644000175000017500000000014414050437223016105 0ustar frankfrankinline std::ostream &SyslogStream::emerg(std::ostream &str) { return setPriority(str, EMERG); } bobcat-5.09.01/syslogstream/setdefaultpriority.f0000644000175000017500000000020414050437223020745 0ustar frankfrankinline Priority SyslogStream::setDefaultPriority(Priority priority) { return SyslogBuf::setDefaultPriority(priority); } bobcat-5.09.01/syslogstream/maskvalue2.f0000644000175000017500000000022414050437223017057 0ustar frankfranktemplate inline int SyslogStream::maskValue(Priority p1, Priorities ...ps) { return ((1 << p1) | maskValue(ps ...)); } bobcat-5.09.01/syslogstream/strerrno.cc0000644000175000017500000000016114050437223017023 0ustar frankfrank#include "syslogstream.ih" ostream &SyslogStream::strerrno(ostream &str) { return str << strerror(errno); } bobcat-5.09.01/syslogstream/syslogstream.ih0000644000175000017500000000024614050437223017720 0ustar frankfrank#include "syslogstream" #include // strerror #include #include "../string/string" using namespace std; using namespace FBB; bobcat-5.09.01/syslogstream/setmask1.f0000644000175000017500000000015614050437223016541 0ustar frankfrankinline int SyslogStream::setMask(Priority p1, PriorityType upTo) { return setMask(maskValue(p1), upTo); } bobcat-5.09.01/syslogstream/stop.cc0000644000175000017500000000106514050437223016136 0ustar frankfrank#include "syslogstream.ih" namespace { unordered_map priorityMap = { {"EMERG", FBB::EMERG}, {"ALERT", FBB::ALERT}, {"CRIT", FBB::CRIT}, {"ERR", FBB::ERR}, {"WARNING", FBB::WARNING}, {"NOTICE", FBB::NOTICE}, {"INFO", FBB::INFO}, {"DEBUG", FBB::DEBUG}, }; } Priority SyslogStream::stoP(std::string const &name, Priority priority) { auto iter = priorityMap.find(String::uc(name)); return iter == priorityMap.end() ? priority : iter->second; } bobcat-5.09.01/syslogstream/defaultpriority.f0000644000175000017500000000014514050437223020235 0ustar frankfrankinline Priority SyslogStream::defaultPriority() const { return SyslogBuf::defaultPriority(); } bobcat-5.09.01/syslogstream/debug.f0000644000175000017500000000014414050437223016074 0ustar frankfrankinline std::ostream &SyslogStream::debug(std::ostream &str) { return setPriority(str, DEBUG); } bobcat-5.09.01/syslogstream/syslogstream1.cc0000644000175000017500000000035114050437223017763 0ustar frankfrank#include "syslogstream.ih" SyslogStream::SyslogStream(string const &ident, Priority priority, Facility facility, int option) : SyslogBuf(ident, priority, facility, option), std::ostream(this) {} bobcat-5.09.01/syslogstream/err.f0000644000175000017500000000014014050437223015572 0ustar frankfrankinline std::ostream &SyslogStream::err(std::ostream &str) { return setPriority(str, ERR); } bobcat-5.09.01/syslogstream/warning.f0000644000175000017500000000015014050437223016450 0ustar frankfrankinline std::ostream &SyslogStream::warning(std::ostream &str) { return setPriority(str, WARNING); } bobcat-5.09.01/syslogstream/maskvalue1.f0000644000175000017500000000011014050437223017050 0ustar frankfrankinline int SyslogStream::maskValue(Priority p1) { return 1 << p1; } bobcat-5.09.01/syslogstream/priority.f0000644000175000017500000000013614050437223016670 0ustar frankfrankinline Priority SyslogStream::priority() const { return SyslogBuf::priority(); } bobcat-5.09.01/syslogstream/close.f0000644000175000017500000000006114050437223016111 0ustar frankfrankinline void SyslogStream::close() { eoi(); } bobcat-5.09.01/syslogstream/notice.f0000644000175000017500000000014614050437223016271 0ustar frankfrankinline std::ostream &SyslogStream::notice(std::ostream &str) { return setPriority(str, NOTICE); } bobcat-5.09.01/syslogstream/open.f0000644000175000017500000000027514050437223015754 0ustar frankfrankinline void SyslogStream::open(std::string const &ident, Priority priority, Facility facility, int option) { reset(ident, priority, facility, option); } bobcat-5.09.01/syslogstream/info.f0000644000175000017500000000014214050437223015737 0ustar frankfrankinline std::ostream &SyslogStream::info(std::ostream &str) { return setPriority(str, INFO); } bobcat-5.09.01/syslogstream/setmask4.f0000644000175000017500000000040114050437223016535 0ustar frankfrankinline int SyslogStream::setMask(int maskValue, PriorityType upTo) { // if upTo, maskValue is 2**x, and all its lower bits are also raised return setlogmask(upTo == SINGLE ? maskValue : maskValue |= (maskValue - 1)); } bobcat-5.09.01/syslogstream/syslogstream0000644000175000017500000001160014050437223017315 0ustar frankfrank#ifndef INCLUDED_BOBCAT_SYSLOGSTREAM_ #define INCLUDED_BOBCAT_SYSLOGSTREAM_ // see below for an overview of options, facility, and priority #include #include #include namespace FBB { class SyslogStream: private SyslogBuf, public std::ostream { public: explicit SyslogStream(std::string const &ident = "", Priority priority = NOTICE, Facility facility = USER, int option = 0); Priority priority() const; // .f Priority defaultPriority() const; // .f Priority setPriority(Priority priority); // .f Priority setDefaultPriority(Priority priority); // .f void open(std::string const &ident, // .f Priority priority = NOTICE, Facility facility = USER, int option = 0); void close(); // .f static Priority stoP(std::string const &name, Priority priority = NOTICE); static Facility stoF(std::string const &name, Facility facility = USER); static int setMask(Priority p1, PriorityType upTo); // 1.f static int setMask(Priority p1); // 2.f template static int setMask(Priority p1, Priorities ...ps); // 3.f // MANIPULATORS: static std::ostream &emerg(std::ostream &str); // .f static std::ostream &alert(std::ostream &str); // .f static std::ostream &crit(std::ostream &str); // .f static std::ostream &err(std::ostream &str); // .f static std::ostream &warning(std::ostream &str); // .f static std::ostream ¬ice(std::ostream &str); // .f static std::ostream &info(std::ostream &str); // .f static std::ostream &debug(std::ostream &str); // .f static std::ostream &strerrno(std::ostream &str); // .f private: static std::ostream &setPriority(std::ostream &str, Priority priority); static int maskValue(Priority p1); // 1.f template static int maskValue(Priority p1, Priorities ...ps); // 2.f static int setMask(int maskValue, PriorityType upTo); }; #include "alert.f" #include "close.f" #include "crit.f" #include "debug.f" #include "defaultpriority.f" #include "emerg.f" #include "err.f" #include "info.f" #include "notice.f" #include "open.f" #include "priority.f" #include "setdefaultpriority.f" #include "setmask1.f" #include "setmask2.f" #include "setmask3.f" #include "setpriority.f" #include "warning.f" // The following private inline members, must remain here as they are used by // the setMask member template #include "maskvalue1.f" #include "maskvalue2.f" #include "setmask4.f" // options (default: none): // // LOG_CONS // write directly to system console if there is an // error while sending to system logger // // LOG_NDELAY // open the connection immediately (normally, the con- // nection is opened when the first message is logged) // // LOG_PERROR // print to stderr as well // // LOG_PID // include PID with each message // // // facility // type of program doing the logging. LOG_USER is used as default: // // LOG_AUTHPRIV // security/authorization messages (private) // // LOG_CRON // clock daemon (cron and at) // // LOG_DAEMON // other system daemons // // LOG_KERN // kernel messages // // LOG_LOCAL0 through LOG_LOCAL7 // reserved for local use // // LOG_LPR // line printer subsystem // // LOG_MAIL // mail subsystem // // LOG_NEWS // USENET news subsystem // // LOG_SYSLOG // messages generated internally by syslogd // // LOG_USER(default) // generic user-level messages // // LOG_UUCP // UUCP subsystem // // level (priority): // // LOG_NOTICE is used by default. // This determines the importance of the message. The levels // are, in order of decreasing importance: // // LOG_EMERG // system is unusable // // LOG_ALERT // action must be taken immediately // // LOG_CRIT // critical conditions // // LOG_ERR // error conditions // // LOG_WARNING // warning conditions // // LOG_NOTICE (Used as DEFAULT) // normal, but significant, condition // // LOG_INFO // informational message // // LOG_DEBUG // debug-level message } // FBB #endif bobcat-5.09.01/syslogstream/setpriority2.cc0000644000175000017500000000033314050437223017625 0ustar frankfrank#include "syslogstream.ih" ostream &SyslogStream::setPriority(ostream &str, Priority value) { SyslogBuf *sb = dynamic_cast(str.rdbuf()); if (sb) sb->setPriority(value); return str; } bobcat-5.09.01/syslogstream/crit.f0000644000175000017500000000014214050437223015745 0ustar frankfrankinline std::ostream &SyslogStream::crit(std::ostream &str) { return setPriority(str, CRIT); } bobcat-5.09.01/syslogstream/setmask3.f0000644000175000017500000000023114050437223016535 0ustar frankfranktemplate inline int SyslogStream::setMask(Priority p1, Priorities ...ps) { return setMask(maskValue(p1, ps ...), SINGLE); } bobcat-5.09.01/syslogstream/stof.cc0000644000175000017500000000165114050437223016125 0ustar frankfrank#include "syslogstream.ih" namespace { unordered_map facilityMap = { {"AUTHPRIV", FBB::AUTHPRIV}, {"CRON", FBB::CRON}, {"DAEMON", FBB::DAEMON}, {"KERN", FBB::KERN}, {"LOCAL0", FBB::LOCAL0}, {"LOCAL1", FBB::LOCAL1}, {"LOCAL2", FBB::LOCAL2}, {"LOCAL3", FBB::LOCAL3}, {"LOCAL4", FBB::LOCAL4}, {"LOCAL5", FBB::LOCAL5}, {"LOCAL6", FBB::LOCAL6}, {"LOCAL7", FBB::LOCAL7}, {"LPR", FBB::LPR}, {"MAIL", FBB::MAIL}, {"NEWS", FBB::NEWS}, {"USER", FBB::USER}, {"UUCP", FBB::UUCP}, }; } Facility SyslogStream::stoF(std::string const &name, Facility facility) { auto iter = facilityMap.find(String::uc(name)); return iter == facilityMap.end() ? facility : iter->second; } bobcat-5.09.01/syslogstream/setmask2.f0000644000175000017500000000013514050437223016537 0ustar frankfrankinline int SyslogStream::setMask(Priority p1) { return setMask(maskValue(p1), SINGLE); } bobcat-5.09.01/syslogstream/setpriority.f0000644000175000017500000000016614050437223017407 0ustar frankfrankinline Priority SyslogStream::setPriority(Priority priority) { return SyslogBuf::setPriority(priority); } bobcat-5.09.01/syslogstream/driver/0000755000175000017500000000000014050437223016133 5ustar frankfrankbobcat-5.09.01/syslogstream/driver/build0000755000175000017500000000045514050437223017164 0ustar frankfrank#!/bin/bash tput clear GPP="g++ --std=c++2a" # Using tmp libraries and bobcat CMD="$GPP -o driver -Wall -I../tmp driver.cc \ -L../tmp -lsyslogstream \ -L../../syslogbuf/tmp -lsyslogbuf \ -L../../eoibuf/tmp -leoibuf \ -L../../eoi/tmp -leoi \ -lbobcat -s" echo ${CMD} ${CMD} bobcat-5.09.01/syslogstream/driver/driver.cc0000644000175000017500000000056314050437223017741 0ustar frankfrank/* driver.cc */ #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) { cout << "messages are logged in /var/log/user.log\n"; SyslogStream sls(argv[0]); // via an explicit SyslogStream sls << SyslogStream::notice << "Hello world 1" << endl; } bobcat-5.09.01/table/0000755000175000017500000000000014050437223013173 5ustar frankfrankbobcat-5.09.01/table/opinsert3.f0000644000175000017500000000032614050437223015271 0ustar frankfranktemplate // Insert any other insertable type into a Table Table &operator<<(Table &table, Type const &ref) { reinterpret_cast(table) << ref; return table.flush(); } bobcat-5.09.01/table/clearstr.f0000644000175000017500000000010314050437223015153 0ustar frankfrankinline void Table::clearStr() { std::ostringstream::clear(); } bobcat-5.09.01/table/fill.f0000644000175000017500000000032014050437223014263 0ustar frankfranktemplate void Table::fill(Iter it, Iter end) { TableBase::clear(); while (it != end) { std::ostringstream str; str << *it++; push_back(str.str()); } } bobcat-5.09.01/table/append.cc0000644000175000017500000000044514050437223014754 0ustar frankfrank#include "table.ih" Table &Table::append(string const &str, char const *sep, bool addEmpty) { if (sep == 0) sep = " \t"; vector words; String::split(&words, str, sep, addEmpty); copy(words.begin(), words.end(), back_inserter(*this)); return *this; } bobcat-5.09.01/table/table.ih0000644000175000017500000000015514050437223014605 0ustar frankfrank#include "table" #include #include "../string/string" using namespace std; using namespace FBB; bobcat-5.09.01/table/setalign.f0000644000175000017500000000015014050437223015144 0ustar frankfrankinline Table &Table::setAlign(Align const &align) { TableBase::setAlign(align); return *this; } bobcat-5.09.01/table/opinsert2.f0000644000175000017500000000013514050437223015266 0ustar frankfrankinline Table &operator<<(Table &table, Table &(*fun)(Table &)) { return (*fun)(table); } bobcat-5.09.01/table/table1.cc0000644000175000017500000000032014050437223014645 0ustar frankfrank#include "table.ih" Table::Table(TableSupport &tableSupport, size_t nColumns, FillDirection direction, WidthType widthType) : TableBase(tableSupport, nColumns, direction, widthType) {} bobcat-5.09.01/table/def2.f0000644000175000017500000000007414050437223014163 0ustar frankfrankinline Table &def(Table &table) { return table.def(); } bobcat-5.09.01/table/pushback.f0000644000175000017500000000016314050437223015142 0ustar frankfrankinline void Table::push_back(Element const &element) { d_tabulated = false; d_string.push_back(element); } bobcat-5.09.01/table/flush.cc0000644000175000017500000000014514050437223014623 0ustar frankfrank#include "table.ih" Table &Table::flush() { push_back(str()); str(""); return *this; } bobcat-5.09.01/table/table0.cc0000644000175000017500000000022414050437223014647 0ustar frankfrank#include "table.ih" Table::Table(size_t nColumns, FillDirection direction, WidthType widthType) : TableBase(nColumns, direction, widthType) {} bobcat-5.09.01/table/def1.f0000644000175000017500000000010714050437223014157 0ustar frankfrankinline Table &Table::def() { TableBase::def(); return *this; } bobcat-5.09.01/table/opinsert1.f0000644000175000017500000000013514050437223015265 0ustar frankfrankinline Table &operator<<(Table &tab, Align const &align) { return tab.setAlign(align); } bobcat-5.09.01/table/table0000644000175000017500000000461414050437223014212 0ustar frankfrank#ifndef INCLUDED_BOBCAT_TABLE_ #define INCLUDED_BOBCAT_TABLE_ #include #include namespace FBB { class Table: public TableBase, public std::ostringstream { template friend Table &operator<<(Table &table, Type const &ref); public: typedef std::string value_type; // for C++-0x typedef Element const &const_reference; // required for push_back() Table(size_t nColumns, FillDirection direction, // 0 WidthType widthType = COLUMNWIDTH); Table(TableSupport &tableSupport, // 1 size_t nColumns, FillDirection direction, WidthType widthType = COLUMNWIDTH); Table(Table const &other) = delete; Table &operator=(Table const &other) = delete; Table &append(std::string const &str, char const *sep = " \t", bool addEmpty = false); template void fill(InputIterator begin, InputIterator end); // .f void push_back(Element const &element); // add an element to .f // the table, using the // default alignment. Table &setAlign(Align const &align); // set an alignment .f Table &def(); // fillup an incomplete table .f // automatically at insertions using TableBase::clear; void clearStr(); // clear the ostringstream part .f private: Table &flush(); // insert the text currently // inserted into the Table object // as ostringstream into the table }; #include "clearstr.f" #include "def1.f" #include "fill.f" #include "pushback.f" #include "setalign.f" // Free Functions // Insert column or element alignments #include "opinsert1.f" // Table << Align #include "def2.f" // Table &def(Table &def) // For def #include "opinsert2.f" // Table << Table &(*fun)(Table &) // Insert any other insertable type into a Table #include "opinsert3.f" // Table << Type const & } // FBB #endif bobcat-5.09.01/table/driver/0000755000175000017500000000000014050437223014466 5ustar frankfrankbobcat-5.09.01/table/driver/build0000755000175000017500000000011014050437223015503 0ustar frankfrank#!/bin/bash g++ -O2 `cat ../../c++std` -o driver driver.cc -lbobcat -s bobcat-5.09.01/table/driver/driver.cc0000644000175000017500000000163314050437223016273 0ustar frankfrank#include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) { TableLines tablelines; // width/separators of cols 0, 1 and 2 tablelines << 0 << " | " << " | "; // hline over cols 1 and 2 of row 1 tablelines << TableLines::HLine(1, 1, 3); Table tab(tablelines, 3, Table::ROWWISE, Table::EQUALWIDTH); // or: Table tab(tablelines, 3, Table::ROWWISE); tab << Align(0, std::left); // set column non-default alignment tab.fill(argv + 1, argv + argc);// fill range of values cout << tab << '\n'; // complete the table and insert tab << "hello" << "" << "wo"; // add additional elements. if (tab.nRows() > 2) tab << Align(2, 2, center); // set the layout of a specific element cout << tab << '\n'; } bobcat-5.09.01/tablebase/0000755000175000017500000000000014050437223014026 5ustar frankfrankbobcat-5.09.01/tablebase/vindex.f0000644000175000017500000000016314050437223015472 0ustar frankfrankinline TableBase::Element &TableBase::vIndex(size_t row, size_t col) { return d_string[col * d_nRows + row]; } bobcat-5.09.01/tablebase/nrows.f0000644000175000017500000000007714050437223015351 0ustar frankfrankinline size_t TableBase::nRows() const { return d_nRows; } bobcat-5.09.01/tablebase/tablebase1.cc0000644000175000017500000000067114050437223016344 0ustar frankfrank#include "tablebase.ih" TableBase::TableBase(TableSupport &tableSupport, size_t nColumns, FillDirection direction, WidthType widthType) : d_tabulated(false), d_nRows(0), d_nColumns(nColumns), d_widthType(widthType), d_align(nColumns), d_ptr(0), d_tableSupport(tableSupport), d_indexFun(direction == ROWWISE ? &TableBase::hIndex : &TableBase::vIndex) {} bobcat-5.09.01/tablebase/insert.cc0000644000175000017500000000232414050437223015642 0ustar frankfrank#include "tablebase.ih" ostream &TableBase::insert(ostream &ostr) { def(); if (!d_nRows) return ostr; d_tableSupport.setParam(ostr, d_nRows, d_nColumns, d_align); for (size_t row = 0; row < d_nRows; ++row) { d_tableSupport.hline(row); for (size_t col = 0; col < d_nColumns; ++col) { size_t colwidth = columnWidth(col); d_tableSupport.vline(col); Element &element = elementAt(row, col); Manipulator manip = element.d_manip; if (!manip) manip = columnManip(col); if (manip != FBB::center) ostr << manip << setw(colwidth) << element.d_text; else { int available = colwidth - element.length(); if (available < 0) available = 0; if (size_t skip = available >> 1) ostr << setw(skip) << " "; ostr << element.d_text; if (size_t skip = available - (available >> 1)) ostr << setw(skip) << " "; } } d_tableSupport.vline(); } d_tableSupport.hline(); return ostr; } bobcat-5.09.01/tablebase/clear.f0000644000175000017500000000012214050437223015256 0ustar frankfrankinline void TableBase::clear() { d_tabulated = false; d_string.clear(); } bobcat-5.09.01/tablebase/columnwidth.f0000644000175000017500000000012414050437223016527 0ustar frankfrankinline size_t TableBase::columnWidth(size_t col) const { return d_align[col]; } bobcat-5.09.01/tablebase/elementat.f0000644000175000017500000000016614050437223016156 0ustar frankfrankinline TableBase::Element &TableBase::elementAt(size_t row, size_t col) { return (this->*d_indexFun)(row, col); } bobcat-5.09.01/tablebase/element1.f0000644000175000017500000000025514050437223015711 0ustar frankfrankinline TableBase::Element::Element(std::string text, std::ios_base &(*manip)(std::ios_base &)) : d_text(text), d_manip(manip) {} bobcat-5.09.01/tablebase/hindex.f0000644000175000017500000000016614050437223015457 0ustar frankfrankinline TableBase::Element &TableBase::hIndex(size_t row, size_t col) { return d_string[row * d_nColumns + col]; } bobcat-5.09.01/tablebase/def.cc0000644000175000017500000000232314050437223015073 0ustar frankfrank#include "tablebase.ih" void TableBase::def() { if (d_tabulated || !d_string.size()) // no elements or already return; // tabulated then do nothing d_nRows = (d_string.size() + d_nColumns - 1) / d_nColumns; d_string.resize(d_nRows * d_nColumns); // enforce complete table // determine max width per column, // max column width, and alignment size_t maxWidth = 0; for (size_t col = 0; col < d_nColumns; ++col) { size_t maxColWidth = 0; for (size_t row = 0; row < d_nRows; ++row) { Element &element = elementAt(row, col); size_t len = element.length(); if (maxColWidth < len) maxColWidth = len; } d_align[col].setWidth(maxColWidth); // max. width so far. if (d_widthType == EQUALWIDTH && maxWidth < maxColWidth) maxWidth = maxColWidth; } if (d_widthType == EQUALWIDTH) { for (size_t col = 0; col < d_nColumns; ++col) d_align[col].setWidth(maxWidth); } d_tabulated = true; } bobcat-5.09.01/tablebase/setalign.cc0000644000175000017500000000040614050437223016143 0ustar frankfrank#include "tablebase.ih" void TableBase::setAlign(Align const &align) { d_tabulated = false; if (align.hasRow()) elementAt(align.row(), align.col()).d_manip = align.manip(); else d_align[align.col()].setManip(align.manip()); } bobcat-5.09.01/tablebase/tablebase0.cc0000644000175000017500000000072414050437223016342 0ustar frankfrank#include "tablebase.ih" TableBase::TableBase(size_t nColumns, FillDirection direction, WidthType widthType) : d_tabulated(false), d_nRows(0), d_nColumns(nColumns), d_widthType(widthType), d_align(nColumns), d_ptr(new TableSupport()), d_tableSupport(*d_ptr), d_indexFun(direction == ROWWISE ? &TableBase::hIndex : &TableBase::vIndex) {} bobcat-5.09.01/tablebase/destructor.cc0000644000175000017500000000010714050437223016531 0ustar frankfrank#include "tablebase.ih" TableBase::~TableBase() { delete d_ptr; } bobcat-5.09.01/tablebase/tablebase.ih0000644000175000017500000000015414050437223016272 0ustar frankfrank#include "tablebase" #include using namespace std; using namespace FBB; #include "elementat.f" bobcat-5.09.01/tablebase/opinsert1.f0000644000175000017500000000014714050437223016123 0ustar frankfrankinline std::ostream &operator<<(std::ostream &str, TableBase &table) { return table.insert(str); } bobcat-5.09.01/tablebase/tablebase0000644000175000017500000000603514050437223015677 0ustar frankfrank#ifndef INCLUDED_BOBCAT_TABLEBASE_ #define INCLUDED_BOBCAT_TABLEBASE_ #include #include #include #include #include namespace FBB { class TableBase { friend std::ostream &operator<<(std::ostream &str, TableBase &table); public: enum FillDirection { ROWWISE, COLUMNWISE }; enum WidthType { COLUMNWIDTH, EQUALWIDTH, }; void clear(); // clear the table-elements .f size_t nRows() const; // Number of rows currently .f // in the table (following def) protected: struct Element { std::string d_text; std::ios_base &(*d_manip)(std::ios_base &); Element(std::string text = "", // .f std::ios_base &(*manip)(std::ios_base &) = 0); size_t length() const; // .f }; bool d_tabulated; size_t d_nRows; size_t d_nColumns; WidthType d_widthType; std::vector d_align; std::vector d_string; // table contents TableSupport *d_ptr; TableSupport &d_tableSupport; Element &(TableBase::*d_indexFun)(size_t row, size_t col); TableBase(size_t nColumns, FillDirection direction, WidthType widthType); TableBase(TableSupport &tableSupport, // 1 size_t nColumns, FillDirection direction, WidthType widthType); ~TableBase(); void setAlign(Align const &align); // set an alignment void def(); // fillup an incomplete table // automatically called at // insertions into ostreams size_t columnWidth(size_t col) const; // .f Manipulator columnManip(size_t col) const; // .f Element &hIndex(size_t row, size_t col); // .f Element &vIndex(size_t row, size_t col); // .f private: std::ostream &insert(std::ostream &ostr); // returns element at particular location Element &elementAt(size_t row, size_t col); // .f }; #include "clear.f" #include "columnmanip.f" #include "columnwidth.f" #include "hindex.f" #include "nrows.f" #include "vindex.f" // Element members #include "element1.f" #include "length.f" // Free Functions // display the table #include "opinsert1.f" // ostream << TableBase } // FBB #endif bobcat-5.09.01/tablebase/columnmanip.f0000644000175000017500000000022514050437223016516 0ustar frankfrankinline Manipulator TableBase::columnManip(size_t col) const { Manipulator manip = d_align[col].manip(); return manip ? manip : std::right; } bobcat-5.09.01/tablebase/length.f0000644000175000017500000000012114050437223015450 0ustar frankfrankinline size_t TableBase::Element::length() const { return d_text.length(); } bobcat-5.09.01/tablebuf/0000755000175000017500000000000014050437223013670 5ustar frankfrankbobcat-5.09.01/tablebuf/fs.cc0000644000175000017500000000027214050437223014610 0ustar frankfrank#include "tablebuf.ih" namespace FBB { std::ostream &fs(std::ostream &out) { TableBuf &tb = dynamic_cast(*out.rdbuf()); tb.overflow(tb.d_fs); return out; } } bobcat-5.09.01/tablebuf/overflow.cc0000644000175000017500000000050314050437223016040 0ustar frankfrank#include "tablebuf.ih" int TableBuf::overflow(int ch) { if (ch == d_fs) nextField(); else if (ch == d_rs) { nextField(); endRow(); } else { d_str += static_cast(ch); d_buffered = true; d_insertEmptyRow = false; } return ch; } bobcat-5.09.01/tablebuf/setrowseparator2.f0000644000175000017500000000010214050437223017356 0ustar frankfrankinline void TableBuf::setRowSeparator(char rs) { d_rs = rs; } bobcat-5.09.01/tablebuf/setrowseparator1.f0000644000175000017500000000007314050437223017364 0ustar frankfrankinline void TableBuf::setRowSeparator() { d_rs = -1; } bobcat-5.09.01/tablebuf/setfieldseparator2.f0000644000175000017500000000010414050437223017634 0ustar frankfrankinline void TableBuf::setFieldSeparator(char fs) { d_fs = fs; } bobcat-5.09.01/tablebuf/setfieldseparator1.f0000644000175000017500000000007514050437223017642 0ustar frankfrankinline void TableBuf::setFieldSeparator() { d_fs = -1; } bobcat-5.09.01/tablebuf/setalign.f0000644000175000017500000000015614050437223015647 0ustar frankfrankinline TableBuf &TableBuf::setAlign(Align const &align) { TableBase::setAlign(align); return *this; } bobcat-5.09.01/tablebuf/endrow.cc0000644000175000017500000000034514050437223015477 0ustar frankfrank#include "tablebuf.ih" void TableBuf::endRow() { d_string.resize( ( (d_string.size() + d_nColumns - 1) / d_nColumns + d_insertEmptyRow ) * d_nColumns); d_insertEmptyRow = true; } bobcat-5.09.01/tablebuf/opinsert2.f0000644000175000017500000000014314050437223015762 0ustar frankfrankinline TableBuf &operator<<(TableBuf &tab, Align const &align) { return tab.setAlign(align); } bobcat-5.09.01/tablebuf/tablebuf0000644000175000017500000000355414050437223015406 0ustar frankfrank#ifndef INCLUDED_BOBCAT_TABLEBUF_ #define INCLUDED_BOBCAT_TABLEBUF_ #include #include namespace FBB { class TableBuf: public TableBase, public std::streambuf { friend std::ostream &operator<<(std::ostream &str, // 1.f TableBuf &table); friend std::ostream &fs(std::ostream &out); friend std::ostream &rs(std::ostream &out); int d_fs; int d_rs; std::string d_str; bool d_buffered; bool d_insertEmptyRow; public: TableBuf(size_t nColumns, FillDirection direction, // 0 WidthType widthType = COLUMNWIDTH); TableBuf(TableSupport &tableSupport, // 1 size_t nColumns, FillDirection direction, WidthType widthType = COLUMNWIDTH); TableBuf &def(); // fillup an incomplete table 1.f TableBuf &setAlign(Align const &align); // set alignment .f void setFieldSeparator(); // 1.f void setFieldSeparator(char fs); // 2.f void setRowSeparator(); // 1.f void setRowSeparator(char rs); // 2.f private: int sync() override; int overflow(int ch) override; void nextField(); void endRow(); }; std::ostream &fs(std::ostream &out); std::ostream &rs(std::ostream &out); #include "setalign.f" #include "setfieldseparator1.f" #include "setfieldseparator2.f" #include "setrowseparator1.f" #include "setrowseparator2.f" // Free Members #include "def2.f" // TableBuf &def(TableBuf &table) // Insert column or element alignments #include "opinsert2.f" // TableBuf << Align } // FBB #endif bobcat-5.09.01/tablebuf/tablebuf.ih0000644000175000017500000000014214050437223015773 0ustar frankfrank#include "tablebuf" #include "../exception/exception" using namespace std; using namespace FBB; bobcat-5.09.01/tablebuf/nextfield.cc0000644000175000017500000000023314050437223016157 0ustar frankfrank#include "tablebuf.ih" void TableBuf::nextField() { d_tabulated = false; d_string.push_back(d_str); d_str.erase(); d_buffered = false; } bobcat-5.09.01/tablebuf/tablebuf1.cc0000644000175000017500000000045214050437223016045 0ustar frankfrank#include "tablebuf.ih" TableBuf::TableBuf(TableSupport &tableSupport, size_t nColumns, FillDirection direction, WidthType widthType) : TableBase(tableSupport, nColumns, direction, widthType), d_fs('\b'), d_rs('\n'), d_buffered(false), d_insertEmptyRow(false) {} bobcat-5.09.01/tablebuf/def2.f0000644000175000017500000000010214050437223014650 0ustar frankfrankinline TableBuf &def(TableBuf &table) { return table.def(); } bobcat-5.09.01/tablebuf/operatorinsert.cc0000644000175000017500000000034414050437223017260 0ustar frankfrank#include "tablebuf.ih" namespace FBB { // displays the table std::ostream &operator<<(std::ostream &out, TableBuf &table) { table.sync(); TableBase &tb = table; return out << tb; } } // FBB bobcat-5.09.01/tablebuf/sync.cc0000644000175000017500000000015114050437223015150 0ustar frankfrank#include "tablebuf.ih" int TableBuf::sync() { if (d_buffered) nextField(); return 0; } bobcat-5.09.01/tablebuf/def1.f0000644000175000017500000000011514050437223014653 0ustar frankfrankinline TableBuf &TableBuf::def() { TableBase::def(); return *this; } bobcat-5.09.01/tablebuf/rs.cc0000644000175000017500000000027214050437223014624 0ustar frankfrank#include "tablebuf.ih" namespace FBB { std::ostream &rs(std::ostream &out) { TableBuf &tb = dynamic_cast(*out.rdbuf()); tb.overflow(tb.d_rs); return out; } } bobcat-5.09.01/tablebuf/tablebuf0.cc0000644000175000017500000000045214050437223016044 0ustar frankfrank#include "tablebuf.ih" TableBuf::TableBuf(size_t nColumns, FillDirection direction, WidthType widthType) : TableBase(nColumns, direction, widthType), d_fs('\b'), d_rs('\n'), d_buffered(false), d_insertEmptyRow(false) {} bobcat-5.09.01/tablebuf/driver/0000755000175000017500000000000014050437223015163 5ustar frankfrankbobcat-5.09.01/tablebuf/driver/build0000755000175000017500000000026414050437223016212 0ustar frankfrank#!/bin/bash #g++ -O2 -Wall `cat ../../c++std` -o driver driver.cc -lbobcat -s g++ -I../../tmp -Wall -O2 `cat ../../c++std` -o driver driver.cc \ -L../../tmp/lib -lbobcat -s bobcat-5.09.01/tablebuf/driver/driver.cc0000644000175000017500000000122114050437223016761 0ustar frankfrank#include #include #include #include #include #include #include using namespace std; using namespace FBB; int main() { TableLines tablelines; tablelines << 0; // set separator widths for (size_t sep = 0; sep != 8; ++sep) tablelines << 3; TableBuf tab(tablelines, 8, TableBuf::ROWWISE); ostream out(&tab); copy(istream_iterator(cin), istream_iterator(), ostream_iterator(out, "\b")); cout << tab << '\n'; // complete the table and insert } bobcat-5.09.01/tablelines/0000755000175000017500000000000014050437223014226 5ustar frankfrankbobcat-5.09.01/tablelines/outline.cc0000644000175000017500000000127714050437223016223 0ustar frankfrank#include "tablelines.ih" void TableLines::outLine(Field const &field, ostream &out) { if (field.width == 0) return; if (field.type == SKIP) out << setw(field.width) << " "; else if ((field.type & (LEFT_FULL | USE | RIGHT_FULL))) out << setfill('-') << setw(field.width) << "-" << setfill(' '); else if (field.type & LEFT_MID) { out << setw(field.width / 2) << " " << setfill('-') << setw(field.width - field.width / 2) << "-" << setfill(' '); } else { out << setfill('-') << setw(field.width - field.width / 2) << "-" << setfill(' ') << setw(field.width / 2) << " "; } } bobcat-5.09.01/tablelines/tablelines1.f0000644000175000017500000000012614050437223016577 0ustar frankfrankinline TableLines::TableLines(TableLines &&tmp) : TableSupport(std::move(tmp)) {} bobcat-5.09.01/tablelines/vhline.cc0000644000175000017500000000066714050437223016033 0ustar frankfrank#include "tablelines.ih" void TableLines::v_hline(size_t row) const { if (row == 0 || row == nRows()) out() << setfill('-') << setw(width()) << "-" << setfill(' '); else { const_iterator iter = begin(row); const_iterator beyond = end(row); if (iter == beyond) return; for (auto &field: ranger(iter, beyond)) outLine(field, out()); } out() << '\n'; } bobcat-5.09.01/tablelines/tablelines.ih0000644000175000017500000000020514050437223016667 0ustar frankfrank#include "tablelines" #include #include #include "../ranger/ranger" using namespace std; using namespace FBB; bobcat-5.09.01/tablelines/opassign.f0000644000175000017500000000015514050437223016221 0ustar frankfrankinline TableLines &TableLines::operator=(TableLines &&tmp) { *this = std::move(tmp); return *this; } bobcat-5.09.01/tablelines/tablelines0000644000175000017500000000105214050437223016271 0ustar frankfrank#ifndef INCLUDED_TABLELINES_ #define INCLUDED_TABLELINES_ #include #include namespace FBB { class TableLines: public TableSupport { public: TableLines() = default; TableLines(TableLines &&tmp); // 1.f TableLines &operator=(TableLines &&tmp); // opassign.f private: void v_hline(size_t row) const override; static void outLine(Field const &field, std::ostream &out); }; #include "tablelines1.f" #include "opassign.f" } // FBB #endif bobcat-5.09.01/tablesupport/0000755000175000017500000000000014050437223014630 5ustar frankfrankbobcat-5.09.01/tablesupport/nrows.f0000644000175000017500000000010214050437223016140 0ustar frankfrankinline size_t TableSupport::nRows() const { return d_nRows; } bobcat-5.09.01/tablesupport/hline2.f0000644000175000017500000000011014050437223016150 0ustar frankfrankinline void TableSupport::hline(size_t row) const { v_hline(row); } bobcat-5.09.01/tablesupport/sep.f0000644000175000017500000000012714050437223015566 0ustar frankfrankinline std::vector const &TableSupport::sep() const { return d_sep; } bobcat-5.09.01/tablesupport/hline1.f0000644000175000017500000000007314050437223016157 0ustar frankfrankinline void TableSupport::hline() const { v_hline(); } bobcat-5.09.01/tablesupport/ncolumns.f0000644000175000017500000000011014050437223016625 0ustar frankfrankinline size_t TableSupport::nColumns() const { return d_nColumns; } bobcat-5.09.01/tablesupport/sepwidth.f0000644000175000017500000000016414050437223016627 0ustar frankfrankinline size_t TableSupport::sepWidth(size_t col) const { return col < d_sep.size() ? d_sep[col].length() : 0; } bobcat-5.09.01/tablesupport/operatorinsizet.cc0000644000175000017500000000033014050437223020374 0ustar frankfrank#include "tablesupport.ih" namespace FBB { TableSupport &operator<<(TableSupport &support, size_t width) { support.d_sep.push_back(std::string(width, ' ')); --support.d_tableWidth; return support; } } bobcat-5.09.01/tablesupport/data.cc0000644000175000017500000000012314050437223016044 0ustar frankfrank#include "tablesupport.ih" vector TableSupport::const_iterator::s_empty; bobcat-5.09.01/tablesupport/hline0.cc0000644000175000017500000000052314050437223016316 0ustar frankfrank#include "tablesupport.ih" TableSupport::HLine::HLine(ColumnType margins, size_t row, size_t begin, size_t end) : d_row(row), d_begin(begin), d_end(end), d_type(margins) { if (d_type & LEFT_FULL) d_type &= ~LEFT_MID; if (d_type & RIGHT_FULL) d_type &= ~RIGHT_MID; } bobcat-5.09.01/tablesupport/hline1.cc0000644000175000017500000000025014050437223016314 0ustar frankfrank#include "tablesupport.ih" TableSupport::HLine::HLine(size_t row, size_t begin, size_t end) : d_row(row), d_begin(begin), d_end(end), d_type(SKIP) {} bobcat-5.09.01/tablesupport/vline2.f0000644000175000017500000000011014050437223016166 0ustar frankfrankinline void TableSupport::vline(size_t col) const { v_vline(col); } bobcat-5.09.01/tablesupport/colwidth.f0000644000175000017500000000017114050437223016613 0ustar frankfrankinline size_t TableSupport::colWidth(size_t col) const { return col < d_align->size() ? (*d_align)[col].col() : 0; } bobcat-5.09.01/tablesupport/operatorinhline.cc0000644000175000017500000000147414050437223020347 0ustar frankfrank#include "tablesupport.ih" namespace FBB { TableSupport &operator<<(TableSupport &support, TableSupport::HLine const &hline) { if (hline.d_begin >= hline.d_end) return support; vector &elements = support.d_elements[hline.d_row]; size_t nCols = max(hline.d_end, support.d_nColumns); elements.resize(1 + TableSupport::rightSeparator(nCols)); TableSupport::leftType( &elements[TableSupport::leftSeparator(hline.d_begin)], hline.d_type); int end = TableSupport::leftSeparator(hline.d_end); TableSupport::rightType(&elements[end], hline.d_type); for ( int idx = TableSupport::element(hline.d_begin); idx != end; ++idx ) elements[idx] = TableSupport::USE; return support; } } bobcat-5.09.01/tablesupport/element.f0000644000175000017500000000012214050437223016423 0ustar frankfrankinline size_t TableSupport::element(size_t column) { return column * 2 + 1; } bobcat-5.09.01/tablesupport/tablesupport.ih0000644000175000017500000000035614050437223017702 0ustar frankfrank#include "tablesupport" #include #include "../fswap/fswap" using namespace std; using namespace FBB; #include "leftseparator.f" #include "rightseparator.f" #include "element.f" #include "lefttype.f" #include "righttype.f" bobcat-5.09.01/tablesupport/operatorinstring.cc0000644000175000017500000000031614050437223020550 0ustar frankfrank#include "tablesupport.ih" namespace FBB { TableSupport &operator<<(TableSupport &support, std::string const &sep) { support.d_sep.push_back(sep); --support.d_tableWidth; return support; } } bobcat-5.09.01/tablesupport/out.f0000644000175000017500000000011414050437223015602 0ustar frankfrankinline std::ostream &TableSupport::out() const { return *d_streamPtr; } bobcat-5.09.01/tablesupport/tablesupport2.cc0000644000175000017500000000043314050437223017745 0ustar frankfrank#include "tablesupport.ih" TableSupport::TableSupport(TableSupport &&tmp) : d_streamPtr(tmp.d_streamPtr), d_nRows(tmp.d_nRows), d_nColumns(tmp.d_nColumns), d_align(tmp.d_align), d_tableWidth( move(tmp.d_tableWidth) ), d_elements( move(tmp.d_elements) ) {} bobcat-5.09.01/tablesupport/vhline.cc0000644000175000017500000000011414050437223016420 0ustar frankfrank#include "tablesupport.ih" void TableSupport::v_hline(size_t row) const {} bobcat-5.09.01/tablesupport/constiterator1.cc0000644000175000017500000000070714050437223020124 0ustar frankfrank#include "tablesupport.ih" TableSupport::const_iterator::const_iterator(TableSupport const &support, size_t row, bool begin) : d_support(support) { UMIter iter = support.d_elements.find(row); if (iter != support.d_elements.end()) { d_vector = &iter->second; d_iter = begin ? d_vector->begin() : d_vector->end(); } else { d_vector = &s_empty; d_iter = s_empty.end(); } } bobcat-5.09.01/tablesupport/align.f0000644000175000017500000000012614050437223016070 0ustar frankfrankinline std::vector const &TableSupport::align() const { return *d_align; } bobcat-5.09.01/tablesupport/vline1.f0000644000175000017500000000007314050437223016175 0ustar frankfrankinline void TableSupport::vline() const { v_vline(); } bobcat-5.09.01/tablesupport/begin.f0000644000175000017500000000021014050437223016054 0ustar frankfrankinline TableSupport::const_iterator TableSupport::begin(size_t row) const { const_iterator ret(*this, row, true); return ret; } bobcat-5.09.01/tablesupport/opstar.f0000644000175000017500000000021414050437223016304 0ustar frankfrankinline TableSupport::Field const &TableSupport::const_iterator::operator*() const { return *operator->(); } bobcat-5.09.01/tablesupport/opinc.f0000644000175000017500000000016514050437223016111 0ustar frankfrankinline TableSupport::const_iterator &TableSupport::const_iterator::operator++() { ++d_iter; return *this; } bobcat-5.09.01/tablesupport/opbitor.f0000644000175000017500000000041214050437223016452 0ustar frankfrankinline TableSupport::ColumnType operator|(TableSupport::ColumnType lhs, TableSupport::ColumnType rhs) { return static_cast( static_cast(lhs) | static_cast(rhs)); } bobcat-5.09.01/tablesupport/end.f0000644000175000017500000000020714050437223015544 0ustar frankfrankinline TableSupport::const_iterator TableSupport::end(size_t row) const { const_iterator ret(*this, row, false); return ret; } bobcat-5.09.01/tablesupport/rightseparator.f0000644000175000017500000000013114050437223020030 0ustar frankfrankinline size_t TableSupport::rightSeparator(size_t column) { return column * 2 + 2; } bobcat-5.09.01/tablesupport/width.f0000644000175000017500000000010714050437223016114 0ustar frankfrankinline size_t TableSupport::width() const { return d_tableWidth; } bobcat-5.09.01/tablesupport/tablesupport1.cc0000644000175000017500000000023214050437223017741 0ustar frankfrank#include "tablesupport.ih" TableSupport::TableSupport() : d_streamPtr(0), d_nRows(0), d_nColumns(0), d_align(0), d_tableWidth(0) {} bobcat-5.09.01/tablesupport/righttype.f0000644000175000017500000000032214050437223017013 0ustar frankfrankinline void TableSupport::rightType(size_t *target, size_t type) { *target = *target != SKIP || (type & (USE | RIGHT_FULL)) ? USE : RIGHT_MID; } bobcat-5.09.01/tablesupport/leftseparator.f0000644000175000017500000000012414050437223017647 0ustar frankfrankinline size_t TableSupport::leftSeparator(size_t column) { return column * 2; } bobcat-5.09.01/tablesupport/vhline2.cc0000644000175000017500000000012714050437223016506 0ustar frankfrank#include "tablesupport.ih" void TableSupport::v_hline() const { hline(d_nRows); } bobcat-5.09.01/tablesupport/destructor.cc0000644000175000017500000000007514050437223017337 0ustar frankfrank#include "tablesupport.ih" TableSupport::~TableSupport() {} bobcat-5.09.01/tablesupport/operatorassign.cc0000644000175000017500000000022014050437223020171 0ustar frankfrank#include "tablesupport.ih" TableSupport &TableSupport::operator=(TableSupport &&tmp) { fswap(*this, tmp, d_elements); return *this; } bobcat-5.09.01/tablesupport/width.cc0000644000175000017500000000024014050437223016252 0ustar frankfrank#include "tablesupport.ih" #include size_t TableSupport::width(size_t idx) const { return idx & 1 ? colWidth(idx >> 1) : sepWidth(idx >> 1); } bobcat-5.09.01/tablesupport/vvline1.cc0000644000175000017500000000015614050437223016525 0ustar frankfrank#include "tablesupport.ih" void TableSupport::v_vline() const { vline(d_nColumns); out() << '\n'; } bobcat-5.09.01/tablesupport/vvline0.cc0000644000175000017500000000020714050437223016521 0ustar frankfrank#include "tablesupport.ih" void TableSupport::v_vline(size_t col) const { if (col < d_sep.size()) out() << d_sep[col]; } bobcat-5.09.01/tablesupport/opneq.f0000644000175000017500000000022014050437223016113 0ustar frankfrankinline bool TableSupport::const_iterator::operator!=( TableSupport::const_iterator const &other) const { return not (*this == other); } bobcat-5.09.01/tablesupport/tablesupport0000644000175000017500000001531314050437223017302 0ustar frankfrank#ifndef INCLUDED_BOBCAT_TABLESUPPORT_ #define INCLUDED_BOBCAT_TABLESUPPORT_ #include #include #include #include #include namespace FBB { class TableSupport { public: struct Field { size_t width; // width of a field size_t type; // handlingtype (ColumnType) }; enum ColumnType { SKIP = 0, USE = 1 << 0, LEFT_FULL = 1 << 1, RIGHT_FULL = 1 << 2, LEFT_MID = 1 << 3, RIGHT_MID = 1 << 4 }; // define the columns to provide with a (partial) hline struct HLine { size_t d_row; size_t d_begin; size_t d_end; size_t d_type; HLine(size_t row, size_t begin, size_t end); HLine(ColumnType margins, size_t row, size_t begin, size_t end); }; class const_iterator: public std::iterator { TableSupport const &d_support; // iterators to vectors in d_elements. The elements of the // vectors contain the types of the column (SKIP, USE, etc) // to determine the width of an element call // separator.width(iterator) std::vector const *d_vector; std::vector::const_iterator d_iter; mutable Field d_field; static std::vector s_empty; public: const_iterator(TableSupport const &support, size_t row, bool begin); const_iterator &operator++(); // .f bool operator==(const_iterator const &other) const; // .f bool operator!=(const_iterator const &other) const; // .f Field const &operator*() const; // .f Field const *operator->() const; }; private: std::ostream *d_streamPtr; size_t d_nRows; // # of rows (defined after def()) size_t d_nColumns; // # of cols std::vector const *d_align; // pointer to alignment info, // passed to this by setParam, // (used by Table/TableBuf) size_t d_tableWidth; // total table width std::vector d_sep; // a vector of separators. 0: // before the leftmost col. // Element types per row per // column, wrt hlines typedef std::unordered_map> UMsizeVector; typedef UMsizeVector::value_type UMValue; typedef UMsizeVector::const_iterator UMIter; UMsizeVector d_elements; public: TableSupport(); TableSupport(TableSupport &&tmp); TableSupport &operator=(TableSupport &&tmp); virtual ~TableSupport(); // empty void setParam(std::ostream &ostr, size_t rows, size_t nColumns, std::vector const &align); void hline() const; // called after the last data row 1.f // called by Table/TableBuf for each row (0: before 1st data row) void hline(size_t row) const; // 2.f // same for columns void vline() const; // 1.f void vline(size_t col) const; // 2.f size_t width() const; // total width of the table .f protected: const_iterator begin(size_t row) const; // .f const_iterator end(size_t row) const; // .f size_t colWidth(size_t col) const; // width of a column and: .f size_t sepWidth(size_t col) const; // of a separator .f // (0: leftmost) size_t nColumns() const; // number of columns .f size_t nRows() const; // number of rows .f std::ostream &out() const; // stream to insert into .f // the table // col. alignmnts (not separators) std::vector const &align() const; // .f std::vector const &sep() const; // separators .f private: // called for each row (0: before 1st data row) virtual void v_hline(size_t row) const; virtual void v_hline() const; // called after the last data row // same for columns virtual void v_vline(size_t col) const; virtual void v_vline() const; size_t width(size_t idx) const; // return indices in d_elements of left separator element, etc. static size_t leftSeparator(size_t column); // .f static size_t element(size_t column); // .f static size_t rightSeparator(size_t column); // .f static void leftType(size_t *target, size_t type); // .f static void rightType(size_t *target, size_t type); // .f friend const_iterator; friend TableSupport &operator<<(TableSupport &support, size_t); friend TableSupport &operator<<(TableSupport &support, std::string const &sep); friend TableSupport &operator<<(TableSupport &support, HLine const &hline); }; #include "align.f" #include "begin.f" #include "colwidth.f" #include "end.f" #include "hline1.f" #include "hline2.f" #include "ncolumns.f" #include "nrows.f" #include "opeq.f" #include "opinc.f" #include "opneq.f" #include "opstar.f" #include "out.f" #include "sep.f" #include "sepwidth.f" #include "vline1.f" #include "vline2.f" #include "width.f" // Free Functions #include "opbitor.f" // ColumnType | ColumnType TableSupport &operator<<(TableSupport &support, size_t); TableSupport &operator<<(TableSupport &support, std::string const &sep); TableSupport &operator<<(TableSupport &support, TableSupport::HLine const &hline); } // FBB #endif bobcat-5.09.01/tablesupport/opeq.f0000644000175000017500000000022614050437223015743 0ustar frankfrankinline bool TableSupport::const_iterator::operator==( TableSupport::const_iterator const &other) const { return d_iter == other.d_iter; } bobcat-5.09.01/tablesupport/setparam.cc0000644000175000017500000000077214050437223016761 0ustar frankfrank#include "tablesupport.ih" void TableSupport::setParam(std::ostream &ostr, size_t rows, size_t nColumns, std::vector const &align) { d_streamPtr = &ostr; d_nRows = rows; d_nColumns = nColumns; d_align = &align; d_tableWidth = accumulate(align.begin(), align.end(), 0); for (auto &elements: d_elements) elements.second.resize(rightSeparator(d_nColumns) + 1); for (auto &src: d_sep) d_tableWidth += src.length(); } bobcat-5.09.01/tablesupport/lefttype.f0000644000175000017500000000031714050437223016634 0ustar frankfrankinline void TableSupport::leftType(size_t *target, size_t type) { *target = *target != SKIP || (type & (USE | LEFT_FULL)) ? USE : LEFT_MID; } bobcat-5.09.01/tablesupport/operatorarrow.cc0000644000175000017500000000031714050437223020046 0ustar frankfrank#include "tablesupport.ih" TableSupport::Field const *TableSupport::const_iterator::operator->() const { d_field = Field { d_support.width(d_iter - d_vector->begin()), *d_iter }; return &d_field; } bobcat-5.09.01/tempstream/0000755000175000017500000000000014050437223014265 5ustar frankfrankbobcat-5.09.01/tempstream/tempstream1.cc0000644000175000017500000000064014050437223017036 0ustar frankfrank#include "tempstream.ih" TempStream::TempStream(string const &base) { char *buf = new char[base.length() + 6 + 1]; strcpy(buf + base.length(), "XXXXXX"); base.copy(buf, string::npos); int fd = mkostemp(buf, O_RDWR); if (fd == -1) throw Exception{} << "TempStream: " << errnodescr; d_fileName = buf; delete[] buf; ::close(fd); open(d_fileName, ios::out | ios::in); } bobcat-5.09.01/tempstream/tempstream0000644000175000017500000000064314050437223016374 0ustar frankfrank#ifndef INCLUDED_TEMPSTREAM_ #define INCLUDED_TEMPSTREAM_ #include #include namespace FBB { class TempStream: public std::fstream { std::string d_fileName; public: TempStream(std::string const &base = "/tmp/FBB::TempStream"); ~TempStream(); std::string const &fileName() const; // .f }; #include "filename.f" } // FBB #endif bobcat-5.09.01/tempstream/destructor.cc0000644000175000017500000000013014050437223016764 0ustar frankfrank#include "tempstream.ih" TempStream::~TempStream() { unlink(d_fileName.c_str()); } bobcat-5.09.01/tempstream/filename.f0000644000175000017500000000012214050437223016207 0ustar frankfrankinline std::string const &TempStream::fileName() const { return d_fileName; } bobcat-5.09.01/tempstream/tempstream.ih0000644000175000017500000000024014050437223016764 0ustar frankfrank#include "tempstream" #include #include #include #include "../exception/exception" using namespace std; using namespace FBB; bobcat-5.09.01/tempstream/driver/0000755000175000017500000000000014050437223015560 5ustar frankfrankbobcat-5.09.01/tempstream/driver/driver.cc0000644000175000017500000000043214050437223017361 0ustar frankfrank#include #include "../tempstream" using namespace std; using namespace FBB; int main() { TempStream ts("/tmp/demo"); ts << "Hello world\n"; ts.seekg(0); string line; getline(ts, line); cout << line << ", removed: " << ts.fileName() << '\n'; } bobcat-5.09.01/TODO0000644000175000017500000000007314050437223012574 0ustar frankfrankProvide examples in the following man-pages: milter.yo bobcat-5.09.01/tty/0000755000175000017500000000000014050437223012724 5ustar frankfrankbobcat-5.09.01/tty/tty.ih0000644000175000017500000000026314050437223014067 0ustar frankfrank#include "tty" #include #include #include #include #include "../exception/exception" using namespace std; using namespace FBB; bobcat-5.09.01/tty/tty1.cc0000644000175000017500000000046714050437223014143 0ustar frankfrank#include "tty.ih" Tty::Tty() : d_fd(open("/dev/tty", O_RDONLY)) { if (d_fd == -1) throw Exception{} << "Can't open '/dev/tty': " << errnodescr; if (tcgetattr(d_fd, &d_tty) != 0) throw Exception{} << "Can't get /dev/tty's attributes: " << errnodescr; } bobcat-5.09.01/tty/tty2.cc0000644000175000017500000000011314050437223014130 0ustar frankfrank#include "tty.ih" Tty::Tty(EchoType type) : Tty() { echo(type); } bobcat-5.09.01/tty/echo.cc0000644000175000017500000000051414050437223014151 0ustar frankfrank#include "tty.ih" bool Tty::echo(EchoType type) { struct termios tty = d_tty; switch (type) { case ON: tty.c_lflag |= ECHO; break; case OFF: tty.c_lflag &= ~ECHO; break; default: break; } return tcsetattr(d_fd, TCSANOW, &tty) == 0; } bobcat-5.09.01/tty/destructor.cc0000644000175000017500000000006414050437223015431 0ustar frankfrank#include "tty.ih" Tty::~Tty() { close(d_fd); } bobcat-5.09.01/tty/tty0000644000175000017500000000111714050437223013467 0ustar frankfrank#ifndef INCLUDED_BOBCAT_TTY_ #define INCLUDED_BOBCAT_TTY_ #include #include namespace FBB { class Tty { struct termios d_tty; int d_fd; public: enum EchoType { RESET, ON, OFF }; Tty(); Tty(EchoType type); ~Tty(); bool echo(EchoType type); private: }; inline std::istream &operator>>(std::istream &in, Tty const &tty) { return in; } inline std::ostream &operator<<(std::ostream &out, Tty const &tty) { return out; } } // FBB #endif bobcat-5.09.01/tty/driver/0000755000175000017500000000000014050437223014217 5ustar frankfrankbobcat-5.09.01/tty/driver/build0000755000175000017500000000012114050437223015236 0ustar frankfrank#!/bin/bash g++ `cat ../../c++std` -o driver driver.cc -L../tmp -ltty -lbobcat bobcat-5.09.01/tty/driver/driver.cc0000644000175000017500000000065114050437223016023 0ustar frankfrank#include #include #include using namespace std; using namespace FBB; int main() { cout << "Enter some text (not echoed): " << Tty(Tty::OFF); string line; getline(cin, line); cout << "\n" "You entered: `" << line << "'\n"; cout << "Enter some text (echoed): "; getline(cin >> Tty(Tty::ON), line); cout << "You entered: `" << line << "'\n"; } bobcat-5.09.01/typetrait/0000755000175000017500000000000014050437223014131 5ustar frankfrankbobcat-5.09.01/typetrait/typetrait0000644000175000017500000000645514050437223016113 0ustar frankfrank#ifndef INCLUDED_BOBCAT_TYPETRAIT_ #define INCLUDED_BOBCAT_TYPETRAIT_ #include namespace FBB { template class TypeTrait { template static double fun(void (ClassType::*)()); template static char fun(...); template struct Type { enum { isClass = sizeof(fun(0)) == sizeof(double) }; enum { isConst = false }; enum { isPointer = false }; enum { isR_Ref = false }; enum { isRef = false }; typedef U Plain; }; template struct Type { enum { isClass = sizeof(fun(0)) == sizeof(double) }; enum { isPointer = false }; enum { isConst = true }; enum { isRef = false }; enum { isR_Ref = false }; typedef U Plain; }; template struct Type { enum { isClass = false }; enum { isPointer = true }; enum { isConst = false }; enum { isRef = false }; enum { isR_Ref = false }; typedef U Plain; }; template struct Type { enum { isClass = false }; enum { isPointer = true }; enum { isConst = true }; enum { isRef = false }; enum { isR_Ref = false }; typedef U Plain; }; template struct Type { enum { isClass = sizeof(fun(0)) == sizeof(double) }; enum { isPointer = false }; enum { isConst = false }; enum { isRef = true }; enum { isR_Ref = false }; typedef U Plain; }; template struct Type { enum { isClass = sizeof(fun(0)) == sizeof(double) }; enum { isPointer = false }; enum { isConst = true }; enum { isRef = true }; enum { isR_Ref = false }; typedef U Plain; }; template struct Type { enum { isClass = sizeof(fun(0)) == sizeof(double) }; enum { isPointer = false }; enum { isConst = false }; enum { isRef = false }; enum { isR_Ref = true }; typedef U Plain; }; template struct Type { enum { isClass = sizeof(fun(0)) == sizeof(double) }; enum { isPointer = false }; enum { isConst = true }; enum { isRef = false }; enum { isR_Ref = true }; typedef U Plain; }; public: enum { isClass = Type::isClass }; enum { isPointer = Type::isPointer }; enum { isConst = Type::isConst }; enum { isRef = Type::isRef }; enum { isR_Ref = Type::isR_Ref }; typedef typename Type::Plain Plain; }; template class LpromotesR { struct Char2 { char array[2]; }; static R const &makeR(); static char test(L const &); static Char2 test(...); public: LpromotesR() = delete; enum { yes = sizeof(test(makeR())) == sizeof(char) }; }; template struct Use { typedef typename std::conditional< LpromotesR::yes, LHS, RHS>::type type; }; } // FBB #endif bobcat-5.09.01/typetrait/driver/0000755000175000017500000000000014050437223015424 5ustar frankfrankbobcat-5.09.01/typetrait/driver/build0000755000175000017500000000010214050437223016442 0ustar frankfrank#!/bin/bash g++ `cat ../../c++std` -Wall -o driver driver.cc -s bobcat-5.09.01/typetrait/driver/driver.cc0000644000175000017500000000276114050437223017234 0ustar frankfrank#include #include #include "../typetrait" using namespace std; using namespace FBB; template void show(char const *name) { cout << "Type: " << name << boolalpha << ":\n" " " "is class: " << TypeTrait::isClass << ", " "is const: " << TypeTrait::isConst << ", " "is pointer: " << TypeTrait::isPointer << ", " "is r-ref: " << TypeTrait::isR_Ref << ", " "is ref: " << TypeTrait::isRef << '\n'; } int main() { TypeTrait::Plain int1 = 12; TypeTrait::Plain int2 = 12; TypeTrait::Plain int3 = 12; TypeTrait::Plain int4 = 12; TypeTrait::Plain int5 = 12; TypeTrait::Plain int6 = 12; show("int"); show("int *"); show("int const"); show("int const *"); show("int &"); show("int const &"); show("int &&"); show("int const &&"); show("std::string"); cout << "=======================\n"; cout << "string promotes char const *: " << LpromotesR::yes << '\n'; cout << "string promotes string " << LpromotesR::yes << '\n'; cout << "char const * promotes string " << LpromotesR::yes << '\n'; } bobcat-5.09.01/user/0000755000175000017500000000000014050437223013062 5ustar frankfrankbobcat-5.09.01/user/egroupid.cc0000644000175000017500000000011414050437223015203 0ustar frankfrank#include "user.ih" size_t User::eGroupid() const { return getegid(); } bobcat-5.09.01/user/shell.f0000644000175000017500000000010614050437223014335 0ustar frankfrankinline std::string const &User::shell() const { return d_shell; } bobcat-5.09.01/user/name.f0000644000175000017500000000010414050437223014144 0ustar frankfrankinline std::string const &User::name() const { return d_name; } bobcat-5.09.01/user/realname.f0000644000175000017500000000011414050437223015011 0ustar frankfrankinline std::string const &User::realname() const { return d_realname; } bobcat-5.09.01/user/user0000644000175000017500000000342214050437223013764 0ustar frankfrank#ifndef INCLUDED_BOBCAT_USER #define INCLUDED_BOBCAT_USER #include struct passwd; namespace FBB { class User { std::string d_name; std::string d_password; std::string d_realname; std::string d_homedir; std::string d_shell; size_t d_uid; size_t d_gid; public: User(); // 1.cc User(std::string const &name); // 2.cc details of user 'name' User(size_t uid); // 3.cc details of user whose ID is // uid User(User const &other) = default; User(User &&tmp); // 4.cc User &operator=(User const &rhs) = default; User &operator=(User &&tmp); void verify() const; // kept for bacward compatibility size_t eGroupid() const; size_t eUserid() const; size_t groupid() const; // .f bool inGroup(size_t gid, bool useEffective = true) const; size_t userid() const; // .f bool inGroup(size_t gid) const; std::string const &homedir() const; // .f std::string const &name() const; // .f std::string const &password() const; // .f std::string const &realname() const; // .f std::string const &shell() const; // .f private: void assign(passwd const *pwd); // assign pwd fields to this object static void failure(); // throws Exception }; #include "groupid.f" #include "homedir.f" #include "name.f" #include "password.f" #include "realname.f" #include "shell.f" #include "userid.f" } // FBB #endif bobcat-5.09.01/user/failure.cc0000644000175000017500000000023414050437223015017 0ustar frankfrank#include "user.ih" // static void User::failure() { throw Exception{1} << "Unable to determine actual user information from `/etc/passwd'"; } bobcat-5.09.01/user/userid.f0000644000175000017500000000007114050437223014522 0ustar frankfrankinline size_t User::userid() const { return d_uid; } bobcat-5.09.01/user/homedir.f0000644000175000017500000000011214050437223014652 0ustar frankfrankinline std::string const &User::homedir() const { return d_homedir; } bobcat-5.09.01/user/user4.cc0000644000175000017500000000043314050437223014433 0ustar frankfrank#include "user.ih" User::User(User &&tmp) : d_name( move(tmp.d_name) ), d_password( move(tmp.d_password) ), d_realname( move(tmp.d_realname) ), d_homedir( move(tmp.d_homedir) ), d_shell( move(tmp.d_shell) ), d_uid(tmp.d_uid), d_gid(tmp.d_gid) {} bobcat-5.09.01/user/euserid.cc0000644000175000017500000000011414050437223015025 0ustar frankfrank#include "user.ih" size_t User::eUserid() const { return geteuid(); } bobcat-5.09.01/user/ingroup.cc0000644000175000017500000000062114050437223015053 0ustar frankfrank#include "user.ih" bool User::inGroup(size_t gid, bool useEffective) const { size_t size = getgroups(0, 0); size_t listSize = size + useEffective; gid_t *list = new gid_t[listSize]; size_t nGroups = getgroups(size, list); if (useEffective) list[size] = getegid(); bool ret = find(list, list + nGroups, gid) != list + nGroups; delete[] list; return ret; } bobcat-5.09.01/user/password.f0000644000175000017500000000011414050437223015067 0ustar frankfrankinline std::string const &User::password() const { return d_password; } bobcat-5.09.01/user/user1.cc0000644000175000017500000000007714050437223014434 0ustar frankfrank#include "user.ih" User::User() : User(getuid()) {} bobcat-5.09.01/user/assign.cc0000644000175000017500000000062614050437223014661 0ustar frankfrank#include "user.ih" void User::assign(passwd const *pwd) // assign pwd fields to this object { d_name = pwd->pw_name; d_password = pwd->pw_passwd; d_uid = pwd->pw_uid; d_gid = pwd->pw_gid; d_realname = pwd->pw_gecos; d_homedir = pwd->pw_dir; if (*d_homedir.rbegin() != '/') d_homedir += '/'; d_shell = pwd->pw_shell; endpwent(); } bobcat-5.09.01/user/user3.cc0000644000175000017500000000042614050437223014434 0ustar frankfrank#include "user.ih" User::User(size_t uid) { passwd *pwd; while ((pwd = getpwent())) { if (pwd->pw_uid == uid) { assign(pwd); // assign pwd fields to this object; return; } } failure(); } bobcat-5.09.01/user/operatorassign.cc0000644000175000017500000000023614050437223016432 0ustar frankfrank#include "user.ih" User &User::operator=(User &&tmp) { fswap(*this, tmp, d_name, d_password, d_realname, d_homedir, d_shell); return *this; } bobcat-5.09.01/user/groupid.f0000644000175000017500000000007214050437223014701 0ustar frankfrankinline size_t User::groupid() const { return d_gid; } bobcat-5.09.01/user/user2.cc0000644000175000017500000000037414050437223014435 0ustar frankfrank#include "user.ih" User::User(std::string const &name) { struct passwd *pwd; while ((pwd = getpwent())) { if (name == pwd->pw_name) { assign(pwd); return; } } failure(); } bobcat-5.09.01/user/user.ih0000644000175000017500000000031614050437223014362 0ustar frankfrank#include "user" #include #include #include #include #include "../fswap/fswap" #include "../exception/exception" using namespace FBB; using namespace std; bobcat-5.09.01/user/verify.cc0000644000175000017500000000006114050437223014672 0ustar frankfrank#include "user.ih" void User::verify() const {} bobcat-5.09.01/user/driver/0000755000175000017500000000000014050437223014355 5ustar frankfrankbobcat-5.09.01/user/driver/build0000755000175000017500000000023314050437223015400 0ustar frankfrank#!/bin/bash CMD="g++ -o driver -Wall -I../../tmp driver.cc -L../../tmp/lib -lbobcat -s" # CMD="g++ -o driver -Wall driver.cc -lbobcat -s" echo $CMD $CMD bobcat-5.09.01/user/driver/driver.cc0000644000175000017500000000101714050437223016156 0ustar frankfrank#include #include using namespace std; using namespace FBB; int main() { User user; cout << "\n" "name : " << user.name() << "\n" << "password : " << user.password() << "\n" << "user id : " << user.userid() << "\n" << "group id : " << user.groupid() << "\n" << "real name : " << user.realname() << "\n" << "home dir : " << user.homedir() << "\n" << "shell : " << user.shell() << "\n" << endl; } bobcat-5.09.01/VERSION0000644000175000017500000000004114067263000013145 0ustar frankfrankVERSION=5.09.01 YEARS=2005-2021 bobcat-5.09.01/x2a/0000755000175000017500000000000014050437223012576 5ustar frankfrankbobcat-5.09.01/x2a/data.cc0000644000175000017500000000006114050437223014013 0ustar frankfrank#include "x2a.ih" bool X2a::s_lastFail = false; bobcat-5.09.01/x2a/x2a1.f0000644000175000017500000000024314050437223013517 0ustar frankfranktemplate // initialize from inline X2a::X2a(T const &x) // (insertable) type { s_lastFail = (*this << x).fail(); } bobcat-5.09.01/x2a/x2a.ih0000644000175000017500000000021114050437223013604 0ustar frankfrank#include "x2a" #include #include #include #include using namespace std; using namespace FBB; bobcat-5.09.01/x2a/opinsert.f0000644000175000017500000000014614050437223014611 0ustar frankfrankinline std::ostream &operator<<(std::ostream &ostr, X2a const &x2a) { return ostr << x2a.str(); } bobcat-5.09.01/x2a/x2a0000644000175000017500000000165514050437223013222 0ustar frankfrank#ifndef INCLUDED_BOBCAT_X2A_ #define INCLUDED_BOBCAT_X2A_ #include #include namespace FBB { class X2a: public std::ostringstream { static bool s_lastFail; public: template // initialize from X2a(T const &x); // (insertable) type 1.f X2a(X2a const &other); // 2.f X2a(double x, size_t behind); X2a(double x, size_t width, size_t behind); X2a &operator=(X2a const &rhs); // opassign.f operator std::string const() const; // opstring.f bool lastFail(); // .f }; #include "x2a1.f" #include "x2a2.f" #include "opstring.f" #include "opassign.f" #include "lastfail.f" // Free Functions #include "opinsert.f" // ostream << X2a } // FBB #endif bobcat-5.09.01/x2a/lastfail.f0000644000175000017500000000006714050437223014547 0ustar frankfrankinline bool X2a::lastFail() { return s_lastFail; } bobcat-5.09.01/x2a/opassign.f0000644000175000017500000000012514050437223014566 0ustar frankfrankinline X2a &X2a::operator=(X2a const &rhs) { str(rhs.str()); return *this; } bobcat-5.09.01/x2a/opstring.f0000644000175000017500000000010514050437223014606 0ustar frankfrankinline X2a::operator std::string const() const { return str(); } bobcat-5.09.01/x2a/x2a2.f0000644000175000017500000000011314050437223013514 0ustar frankfrankinline X2a::X2a(X2a const &other) : std::ostringstream(other.str()) {} bobcat-5.09.01/x2a/x2a1.cc0000644000175000017500000000056014050437223013661 0ustar frankfrank#include "x2a.ih" X2a::X2a(double x, size_t behind) { double power = pow(10, static_cast(behind)); *this << round(x * power) / power; string::size_type pos = str().find_first_of('.'); if (pos == string::npos) *this << '.'; else behind -= str().length() - pos - 1; fill_n(ostream_iterator(*this), behind, '0'); } bobcat-5.09.01/x2a/x2a2.cc0000644000175000017500000000020214050437223013653 0ustar frankfrank#include "x2a.ih" X2a::X2a(double x, size_t wid, size_t behind) { X2a tmp(x, behind); *this << setw(wid) << tmp.str(); } bobcat-5.09.01/x2a/driver/0000755000175000017500000000000014050437223014071 5ustar frankfrankbobcat-5.09.01/x2a/driver/build0000755000175000017500000000006214050437223015114 0ustar frankfrank#!/bin/sh g++ -I.. -o driver driver.cc -lbobcat bobcat-5.09.01/x2a/driver/driver.cc0000644000175000017500000000151614050437223015676 0ustar frankfrank/* driver.cc */ #include #include "../x2a" using namespace std; using namespace FBB; int main(int argc, char **argv) { string si(X2a(12)); string sd(X2a(12.25)); cout << si << " " << sd << endl; cout << "Two digits behind decimal dot: " << X2a(7, 2) << endl; cout << "Two digits behind decimal dot: " << X2a(7.1, 2) << endl; cout << "Two digits behind decimal dot: " << X2a(7.0 / 3, 2) << endl; cout << "Same, 8 characters wide: " << X2a(7.0 / 3, 8, 2) << endl; cout << " " << "12345678" << endl; X2a first(3); X2a second(4); first = second; cout << "first: " << first << endl; second = second; // auto assignment test cout << "second: " << second << endl; } /* Output: 12 12.25 */ bobcat-5.09.01/xerr/0000755000175000017500000000000014050437223013064 5ustar frankfrankbobcat-5.09.01/xerr/xerr.ih0000644000175000017500000000133014050437223014363 0ustar frankfrank// define XERR to activate the xerr/xerr(2) macros: // xerr(insertion) // inserts the '<<' concatenated elements into std::cerr // preceded by the name of the source file, and ended by '\n' // xerr2(insertion, code) // performs the insertion if X is defined, and (unconditionally) // executes the statement(s) in `code'. `code' must be valid // C(++) code. // #ifdef XERR #include #define xerr(insertion) std::cerr << __FILE__": " << insertion << '\n' #define xerr2(insertion, code) \ { std::cerr << __FILE__": " << insertion << '\n'; code; } #else #define xerr(insertion) #define xerr2(insertion, code) code #endif bobcat-5.09.01/xpointer/0000755000175000017500000000000014050437223013754 5ustar frankfrankbobcat-5.09.01/xpointer/get.cc0000644000175000017500000000052314050437223015042 0ustar frankfrank#include "xpointer.ih" bool Xpointer::get(int *x, int *y) const { Window rootret; Window child; Window root = DefaultRootWindow(s_theDisplay); unsigned int keys; int dum_x; int dum_y; return XQueryPointer(s_theDisplay, root, &rootret, &child, x, y, &dum_x, &dum_y, &keys); } bobcat-5.09.01/xpointer/data.cc0000644000175000017500000000013114050437223015167 0ustar frankfrank#include "xpointer.ih" size_t Xpointer::s_counter = 0; Display *Xpointer::s_theDisplay; bobcat-5.09.01/xpointer/xpointer.ih0000644000175000017500000000014214050437223016143 0ustar frankfrank#include "xpointer" #include "../exception/exception" using namespace std; using namespace FBB; bobcat-5.09.01/xpointer/set.cc0000644000175000017500000000077714050437223015071 0ustar frankfrank#include "xpointer.ih" bool Xpointer::set(int x, int y) const { Window root = DefaultRootWindow(s_theDisplay); XWindowAttributes XWA; // get root window info if (!XGetWindowAttributes(s_theDisplay, root, &XWA)) return false; // failure return if (x < 0) x += XWA.width; if (y < 0) y += XWA.height; XWarpPointer(s_theDisplay, root, root, 0, 0, XWA.width, XWA.height, x, y); XFlush(s_theDisplay); return true; } bobcat-5.09.01/xpointer/xpointer.cc0000644000175000017500000000036014050437223016132 0ustar frankfrank#include "xpointer.ih" Xpointer::Xpointer() { if (s_counter++) return; // One more object s_theDisplay = XOpenDisplay(0); if (!s_theDisplay) throw Exception{1} << "Can't open the display"; } bobcat-5.09.01/xpointer/xpointer0000644000175000017500000000100514050437223015543 0ustar frankfrank#ifndef INCLUDED_BOBCAT_XPOINTER_ #define INCLUDED_BOBCAT_XPOINTER_ #include #include namespace FBB { class Xpointer { typedef void (*DeleterType)(Display *); static size_t s_counter; static Display *s_theDisplay; public: Xpointer(); ~Xpointer(); bool set(int x, int y) const; bool get(int *x, int *y) const; private: static void deleter(Display *dsp); // .f }; #include "deleter.f" } // FBB #endif bobcat-5.09.01/xpointer/destructor.cc0000644000175000017500000000023614050437223016462 0ustar frankfrank#include "xpointer.ih" Xpointer::~Xpointer() { if (!--s_counter) // No more Xpointer objects ? XCloseDisplay(s_theDisplay); } bobcat-5.09.01/xpointer/deleter.f0000644000175000017500000000013114050437223015542 0ustar frankfrankinline void Xpointer::deleter(Display *dsp) { if (dsp) XCloseDisplay(dsp); } bobcat-5.09.01/xpointer/driver/0000755000175000017500000000000014050437223015247 5ustar frankfrankbobcat-5.09.01/xpointer/driver/build0000755000175000017500000000012114050437223016266 0ustar frankfrank#!/bin/bash g++ `cat ../../c++std` -c -Wall -o driver driver.cc -lbobcat -lX11 bobcat-5.09.01/xpointer/driver/driver.cc0000644000175000017500000000125214050437223017051 0ustar frankfrank#include #include "../xpointer" #include using namespace std; using namespace FBB; int main(int argc, char **argv) try { if (argc != 3) { cout << "Two arguments required: x and y pixel-pointerlocation" << endl; return 0; } Xpointer xpointer; if (!xpointer.set(stol(argv[1]), stol(argv[2]))) throw Exception() << "Pointer setting failed"; int x; int y; if (!xpointer.get(&x, &y)) throw Exception() << "Pointer getting failed"; cout << "Pointer now at " << x << ", " << y << endl; } catch (exception const &err) { cout << err.what() << endl; return 1; }