bobcat-6.07.01/a2x/0000775000175000017500000000000014736742656012623 5ustar frankfrankbobcat-6.07.01/a2x/a2x1.f0000664000175000017500000000015514673353433013535 0ustar frankfrankinline A2x::A2x(char const *txt) // initialize from text : std::istringstream(txt) {} bobcat-6.07.01/a2x/data.cc0000664000175000017500000000007614673353433014035 0ustar frankfrank#include "a2x.ih" thread_local bool A2x::s_lastFail = false; bobcat-6.07.01/a2x/to.f0000664000175000017500000000017414673353433013405 0ustar frankfranktemplate inline Type A2x::to() { Type t; return (s_lastFail = (*this >> t).fail()) ? Type() : t; } bobcat-6.07.01/a2x/lastfail.f0000664000175000017500000000006714673353433014563 0ustar frankfrankinline bool A2x::lastFail() { return s_lastFail; } bobcat-6.07.01/a2x/opis2.f0000664000175000017500000000012414673353433014012 0ustar frankfrankinline A2x &A2x::operator=(A2x const &other) { return operator=(other.str()); } bobcat-6.07.01/a2x/a2x.ih0000664000175000017500000000007414736315237013627 0ustar frankfrank#include "a2x" using namespace std; using namespace FBB; bobcat-6.07.01/a2x/a2x0000664000175000017500000000204614673353433013231 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-6.07.01/a2x/opis.cc0000664000175000017500000000046614673353433014101 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-6.07.01/a2x/optype.f0000664000175000017500000000012014673353433014272 0ustar frankfranktemplate inline A2x::operator Type() { return to(); } bobcat-6.07.01/a2x/a2x4.f0000664000175000017500000000010714673353433013535 0ustar frankfrankinline A2x::A2x(A2x &&tmp) : std::istringstream(std::move(tmp)) {} bobcat-6.07.01/a2x/a2x2.f0000664000175000017500000000012114673353433013527 0ustar frankfrankinline A2x::A2x(std::string const &str) : std::istringstream(str.c_str()) {} bobcat-6.07.01/a2x/a2x3.f0000664000175000017500000000011314673353433013531 0ustar frankfrankinline A2x::A2x(A2x const &other) : std::istringstream(other.str()) {} bobcat-6.07.01/a2x/opis1.f0000664000175000017500000000013214673353433014010 0ustar frankfrankinline A2x &A2x::operator=(std::string const &str) { return operator=(str.c_str()); } bobcat-6.07.01/a2x/driver/0000775000175000017500000000000014737552575014116 5ustar frankfrankbobcat-6.07.01/a2x/driver/build0000775000175000017500000003517514673353433015145 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-6.07.01/a2x/driver/driver.cc0000664000175000017500000000117114673353433015707 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-6.07.01/align/0000775000175000017500000000000014736742656013223 5ustar frankfrankbobcat-6.07.01/align/col.f0000664000175000017500000000006714673353433014141 0ustar frankfrankinline size_t Align::col() const { return d_col; } bobcat-6.07.01/align/setmanip.f0000664000175000017500000000011014673353433015171 0ustar frankfrankinline void Align::setManip(Manipulator manip) { d_manip = manip; } bobcat-6.07.01/align/align0.cc0000664000175000017500000000020214673353433014665 0ustar frankfrank#include "align.ih" Align::Align(int row, size_t col, Manipulator manip) : d_row(row), d_col(col), d_manip(manip) {} bobcat-6.07.01/align/hasrow.f0000664000175000017500000000007614673353433014667 0ustar frankfrankinline bool Align::hasRow() const { return d_row != -1; } bobcat-6.07.01/align/setwidth.f0000664000175000017500000000007714673353433015220 0ustar frankfrankinline void Align::setWidth(size_t size) { d_col = size; } bobcat-6.07.01/align/opsizet.f0000664000175000017500000000007414673353433015057 0ustar frankfrankinline Align::operator size_t() const { return d_col; } bobcat-6.07.01/align/align0000664000175000017500000000205514673353433014231 0ustar frankfrank#ifndef INCLUDED_BOBCAT_ALIGN_ #define INCLUDED_BOBCAT_ALIGN_ #include namespace FBB { using Manipulator = std::ios_base &(*)(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-6.07.01/align/align2.cc0000664000175000017500000000015214673353433014673 0ustar frankfrank#include "align.ih" Align::Align(Manipulator manip) : d_row(-1), d_col(0), d_manip(manip) {} bobcat-6.07.01/align/manip.f0000664000175000017500000000010014673353433014454 0ustar frankfrankinline Manipulator Align::manip() const { return d_manip; } bobcat-6.07.01/align/row.f0000664000175000017500000000006714673353433014173 0ustar frankfrankinline size_t Align::row() const { return d_row; } bobcat-6.07.01/align/align.ih0000664000175000017500000000007614736315237014631 0ustar frankfrank#include "align" using namespace std; using namespace FBB; bobcat-6.07.01/align/center.f0000664000175000017500000000011314673353433014634 0ustar frankfrankinline std::ios_base ¢er(std::ios_base &stream) { return stream; } bobcat-6.07.01/align/align1.cc0000664000175000017500000000017014673353433014672 0ustar frankfrank#include "align.ih" Align::Align(size_t col, Manipulator manip) : d_row(-1), d_col(col), d_manip(manip) {} bobcat-6.07.01/arg/0000775000175000017500000000000014736742656012702 5ustar frankfrankbobcat-6.07.01/arg/option3.cc0000664000175000017500000000110614673353433014571 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-6.07.01/arg/option4.cc0000664000175000017500000000054014673353433014573 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-6.07.01/arg/instance.cc0000664000175000017500000000022514673353433015003 0ustar frankfrank#include "arg.ih" Arg &Arg::instance() { if (!s_arg) throw Exception{} << "Arg::instance(): not yet initialized"; return *s_arg; } bobcat-6.07.01/arg/longoption1.cc0000664000175000017500000000021014673353433015442 0ustar frankfrank#include "arg.ih" LongOption__::LongOption__(char const *name, Type type) : d_name(name), d_type(type), d_optionChar(0) {} bobcat-6.07.01/arg/data.cc0000664000175000017500000000033414673353433014111 0ustar frankfrank#include "arg.ih" unique_ptr Arg::s_arg; string Arg__::s_dirsep("/"); char Arg__::s_optChar[] = " "; char const Arg::s_alreadyInitialized[] = "Arg::initialize(): already initialized"; bobcat-6.07.01/arg/longoption2.cc0000664000175000017500000000023614673353433015453 0ustar frankfrank#include "arg.ih" LongOption__::LongOption__(char const *name, int optionChar) : d_name(name), d_type(AsCharOption), d_optionChar(optionChar) {} bobcat-6.07.01/arg/arg2.cc0000664000175000017500000000715514673353433014043 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; // cf. ../iuo/iuo: Object containing 'n' // OptStructs 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-6.07.01/arg/initialize2.cc0000664000175000017500000000041414673353433015422 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.reset(new Arg(accept, optstring, 0, 0, argc, argv)); return *s_arg; } bobcat-6.07.01/arg/opindex.f0000664000175000017500000000016214673353433014505 0ustar frankfrankinline char const *Arg__::operator[](size_t idx) const { return (idx >= nArgs()) ? 0 : d_argv[idx].c_str(); } bobcat-6.07.01/arg/operatorindex.cc0000664000175000017500000000013714673353433016064 0ustar frankfrank#include "arg.ih" char const *Arg::operator[](size_t idx) const { return (*d_ptr)[idx]; } bobcat-6.07.01/arg/beyonddashes.f0000664000175000017500000000012114673353433015502 0ustar frankfrank//inline int Arg__::beyondDashes() const //{ // return d_beyondDashes; //} // bobcat-6.07.01/arg/initialize1.cc0000664000175000017500000000035314673353433015423 0ustar frankfrank#include "arg.ih" Arg &Arg::initialize(char const *optstring, int argc, char **argv) { if (s_arg) throw Exception{} << s_alreadyInitialized; s_arg.reset(new Arg(0, optstring, 0, 0, argc, argv)); return *s_arg; } bobcat-6.07.01/arg/nlongoptions.f0000664000175000017500000000010214673353433015562 0ustar frankfrankinline size_t Arg__::nLongOptions() const { return d_nOptv; } bobcat-6.07.01/arg/plainlongoption.cc0000664000175000017500000000065414673353433016421 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-6.07.01/arg/initialize3.cc0000664000175000017500000000053514673353433015427 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.reset(new Arg(0, optstring, begin, end, argc, argv)); return *s_arg; } bobcat-6.07.01/arg/end.cc0000664000175000017500000000014714673353433013750 0ustar frankfrank#include "arg.ih" vector::const_iterator Arg::end() const { return d_ptr->d_argv.end(); } bobcat-6.07.01/arg/argpointers2.cc0000664000175000017500000000013614673353433015617 0ustar frankfrank#include "arg.ih" char const **Arg::argPointers() const { return d_ptr->argPointers(); } bobcat-6.07.01/arg/filllongoptions.cc0000664000175000017500000000077514673353433016433 0ustar frankfrank#include "arg.ih" void Arg__::fillLongOptions(OptStruct *optStruct, std::string const &optString, LongOption const * const begin, LongOption const * const end) { // fill all long options, using their own specifications // (w/wo/opt args) or the specs from optString for (LongOption const *it = begin; it != end; ++it, ++optStruct) addLongOption(optStruct, optString, *it); // 2.cc } bobcat-6.07.01/arg/longname.f0000664000175000017500000000012014673353433014631 0ustar frankfrankinline std::string const &LongOption__::longName() const { return d_name; } bobcat-6.07.01/arg/arg0000664000175000017500000001165114736461670013374 0ustar frankfrank#ifndef INCLUDED_BOBCAT_ARG_ #define INCLUDED_BOBCAT_ARG_ // Singleton Class built around getopt() and getopt_long() (3) #include #include #include #include #include namespace FBB { class ArgTypes__ { protected: // struct option: cf. 'man getopt' // struct option // { // char const *name; // int has_arg; == Type, below // int *flag; // int val; // }; using OptStruct = struct option; using StringVector = std::vector; public: enum Type // Argument types, values as { // in 'man getopt_long' NoArg = 0, Required = 1, Optional = 2, AsCharOption, }; }; class LongOption__: public ArgTypes__ // in Arg: aka 'LongOption' { 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 std::unique_ptr s_arg; // points to the Arg Singleton static char const s_alreadyInitialized[]; public: Arg(Arg const &other) = delete; ~Arg(); using LongOption = FBB::LongOption__; using OptVect = std::vector>; // 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-6.07.01/arg/addcharoption.cc0000664000175000017500000000017014673353433016015 0ustar frankfrank#include "arg.ih" void Arg__::addCharOption() { d_optv[d_getOpt].push_back(optarg ? optarg : ""); ++d_nOptv; } bobcat-6.07.01/arg/begin.cc0000664000175000017500000000015314673353433014263 0ustar frankfrank#include "arg.ih" vector::const_iterator Arg::begin() const { return d_ptr->d_argv.begin(); } bobcat-6.07.01/arg/noptions.cc0000664000175000017500000000012214673353433015044 0ustar frankfrank#include "arg.ih" size_t Arg::nOptions() const { return d_ptr->nOptions(); } bobcat-6.07.01/arg/icmconf0000664000175000017500000000007514673353433014234 0ustar frankfrank#define LIBRARY "arg" #include "../icmconf.lib" bobcat-6.07.01/arg/basename.cc0000664000175000017500000000013614673353433014753 0ustar frankfrank#include "arg.ih" std::string const &Arg::basename() const { return d_ptr->basename(); } bobcat-6.07.01/arg/initialize4.cc0000664000175000017500000000055614673353433015433 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.reset(new Arg(accept, optstring, begin, end, argc, argv)); return *s_arg; } bobcat-6.07.01/arg/setoptiontype.cc0000664000175000017500000000130414736501654016124 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] != ':' ? NoArg : // no : -> no arg optString[pos + 2] != ':' ? Required : // no :: -> required Optional; // else: optional } bobcat-6.07.01/arg/help.cc0000664000175000017500000000033514673353433014131 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-6.07.01/arg/optionchar.f0000664000175000017500000000011114673353433015177 0ustar frankfrankinline int LongOption__::optionChar() const { return d_optionChar; } bobcat-6.07.01/arg/arg1.cc0000664000175000017500000000062514673353433014035 0ustar frankfrank#include "arg.ih" // accept: use -'accept' instead of -- // opstring[0] == '+': accept undefined options // Arg__: workhorse class, interface in arg.ih 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-6.07.01/arg/argpointers1.cc0000664000175000017500000000013014673353433015610 0ustar frankfrank#include "arg.ih" char const **Arg::argPointers() { return d_ptr->argPointers(); } bobcat-6.07.01/arg/destructor.cc0000664000175000017500000000006514673353433015377 0ustar frankfrank#include "arg.ih" Arg::~Arg() { delete d_ptr; } bobcat-6.07.01/arg/nargs.cc0000664000175000017500000000011414673353433014306 0ustar frankfrank#include "arg.ih" size_t Arg::nArgs() const { return d_ptr->nArgs(); } bobcat-6.07.01/arg/basename.f0000664000175000017500000000011114673353433014604 0ustar frankfrankinline std::string const &Arg__::basename() const { return d_base; } bobcat-6.07.01/arg/beyonddashes.cc0000664000175000017500000000012414673353433015645 0ustar frankfrank#include "arg.ih" size_t Arg::beyondDashes() const { return d_ptr->d_dashes; } bobcat-6.07.01/arg/noptions.f0000664000175000017500000000007614673353433014714 0ustar frankfrankinline size_t Arg__::nOptions() const { return d_nOptv; } bobcat-6.07.01/arg/firstnonempty.cc0000664000175000017500000000107314673353433016122 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(), [&](string const &str) { // bind2nd(not_equal_to(), "")); return not str.empty(); } ); if (sit == sv.end()) *idx = sv.size(); else { *idx = sit - sv.begin(); if (value != 0) *value = *sit; } return sv.size(); } bobcat-6.07.01/arg/option2.cc0000664000175000017500000000045514673353433014576 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-6.07.01/arg/option1.f0000664000175000017500000000020014673353433014421 0ustar frankfrankinline size_t Arg::option(std::string *value, int optChar) const { return option(static_cast(0), value, optChar); } bobcat-6.07.01/arg/option2.f0000664000175000017500000000021614673353433014431 0ustar frankfrankinline size_t Arg::option(std::string *value, char const *longOption) const { return option(static_cast(0), value, longOption); } bobcat-6.07.01/arg/argpointers3.cc0000664000175000017500000000023514673353433015620 0ustar frankfrank#include "arg.ih" char const **Arg__::argPointers() const { if (!d_argPointer) d_argPointer = String::argv(d_argv); return d_argPointer; } bobcat-6.07.01/arg/option6.cc0000664000175000017500000000057014673353433014600 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-6.07.01/arg/nlongoptions.cc0000664000175000017500000000013214673353433015725 0ustar frankfrank#include "arg.ih" size_t Arg::nLongOptions() const { return d_ptr->nLongOptions(); } bobcat-6.07.01/arg/argv0.cc0000664000175000017500000000013014673353433014211 0ustar frankfrank#include "arg.ih" std::string const &Arg::argv0() const { return d_ptr->d_argv0; } bobcat-6.07.01/arg/addlongoption2.cc0000664000175000017500000000134614673353433016127 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(); // set the name 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-6.07.01/arg/args.cc0000664000175000017500000000013114673353433014127 0ustar frankfrank#include "arg.ih" vector const &Arg::args() const { return d_ptr->d_argv; } bobcat-6.07.01/arg/longoption0.cc0000664000175000017500000000017614736467606015464 0ustar frankfrank#include "arg.ih" LongOption__::LongOption__(char const *name) : d_name(name), d_type(NoArg), d_optionChar(0) {} bobcat-6.07.01/arg/versionhelp.cc0000664000175000017500000000131114673353433015532 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-6.07.01/arg/option5.cc0000664000175000017500000000121414673353433014573 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-6.07.01/arg/arg.ih0000664000175000017500000001253714736315237013774 0ustar frankfrank#include "arg" #include #include #include #include #include "../string/string" #include "../iuo/iuo" namespace FBB { class Arg__: public ArgTypes__ { friend Arg; using LongOption = FBB::LongOption__; using OptStruct = struct option; using StringVector = std::vector; using IntStringVectorMap = std::unordered_map; using ISVMapIterator = IntStringVectorMap::const_iterator; using StringStringVectorMap = std::unordered_map; using SSVMapIterator = StringStringVectorMap::const_iterator; 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, // arg2.cc 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-6.07.01/arg/option1.cc0000664000175000017500000000036214673353433014572 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-6.07.01/arg/verify.cc0000664000175000017500000000051514673353433014505 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-6.07.01/arg/driver/0000775000175000017500000000000014737552575014175 5ustar frankfrankbobcat-6.07.01/arg/driver/build0000775000175000017500000000147114673353433015214 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 echo ' (to avoid linker confusion: temp. rename Arg to Xarg)' ;; esac bobcat-6.07.01/arg/driver/driver.cc0000664000175000017500000000651414736502613015770 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"; } int main(int argc, char **argv) try { Arg::LongOption lo[] = { {"optional", Arg::Optional}, {"extra", Arg::Required}, {"none", Arg::NoArg}, {"file", 'f'}, {"version", 'v'}, {"add", 'a'} }; try { Arg::initialize('t', "+abcd:e:f::hvt", lo, lo + 6, argc, argv); Arg &arg = Arg::instance(); // just to check ::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-6.07.01/arg/driver/deleter.cc.main0000664000175000017500000000100314673353433017034 0ustar frankfrank#include using namespace std; struct Class { static Class *s_class; static Class &initialize() { s_class = new Class; return *s_class; } struct Deleter { ~Deleter() { cout << "~Deleter called\n"; delete s_class; s_class = 0; } }; void deleter() { static Deleter deleter; } }; Class *Class::s_class; int main() { Class &obj = Class::initialize(); obj.deleter(); } bobcat-6.07.01/arg/driver/l0000775000175000017500000000007714673353433014351 0ustar frankfrank#!/bin/bash g++ -o driver driver.o -L../tmp -larg -lbobcat -s bobcat-6.07.01/arg/driver/getoptlong/0000775000175000017500000000000014673353433016346 5ustar frankfrankbobcat-6.07.01/arg/driver/getoptlong/build0000775000175000017500000003521314673353433017377 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-6.07.01/arg/driver/getoptlong/getoptlong.ih0000664000175000017500000000015214673353433021050 0ustar frankfrank#include "getoptlong.h" #include #include using namespace std; using namespace FBB; bobcat-6.07.01/arg/driver/getoptlong/getoptlong.h0000664000175000017500000000020014673353433020671 0ustar frankfrank#ifndef INCLUDED_GETOPTLONG_H_ #define INCLUDED_GETOPTLONG_H_ #include #include namespace FBB { } #endif bobcat-6.07.01/arg/driver/getoptlong/getoptlong.cc0000664000175000017500000000220714673353433021040 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-6.07.01/arg/driver/driver.ih0000664000175000017500000000014614673353433016002 0ustar frankfrank#include "driver.h" #include #include using namespace std; using namespace FBB; bobcat-6.07.01/arg/driver/c0000775000175000017500000000006614673353433014336 0ustar frankfrank#!/bin/bash g++ `cat ../../c++std` -I.. -c driver.cc bobcat-6.07.01/arg/addlongoption1.cc0000664000175000017500000000023114673353433016116 0ustar frankfrank#include "arg.ih" void Arg__::addLongOption(string const &longName) { d_longOptv[longName].push_back(optarg ? optarg : ""); ++d_nLongOptions; } bobcat-6.07.01/arg/nargs.f0000664000175000017500000000010114673353433014142 0ustar frankfrankinline size_t Arg__::nArgs() const { return d_argv.size(); } bobcat-6.07.01/arg/setbasename.cc0000664000175000017500000000025514673353433015471 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-6.07.01/argconfig/0000775000175000017500000000000014736742656014070 5ustar frankfrankbobcat-6.07.01/argconfig/option3.cc0000664000175000017500000000105214673353433015757 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-6.07.01/argconfig/option4.cc0000664000175000017500000000057514673353433015771 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-6.07.01/argconfig/instance.cc0000664000175000017500000000027414673353433016175 0ustar frankfrank#include "argconfig.ih" ArgConfig &ArgConfig::instance() { if (not s_argConfig) throw Exception{} << "ArgConfig::instance(): not yet initialized"; return *s_argConfig; } bobcat-6.07.01/argconfig/data.cc0000664000175000017500000000027714673353433015305 0ustar frankfrank#include "argconfig.ih" unique_ptr ArgConfig::s_argConfig; char const ArgConfig::s_alreadyInitialized[] = "ArgConfig::initialize(): already initialized"; bobcat-6.07.01/argconfig/initialize2.cc0000664000175000017500000000125514673353433016614 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.reset(new ArgConfig{ 0, optstring, 0, 0, argc, argv, fname, cType, sType, iType } ); return *s_argConfig; } bobcat-6.07.01/argconfig/opindex.f0000664000175000017500000000014014673353433015667 0ustar frankfrankinline char const *ArgConfig::operator[](size_t idx) const { return Arg::operator[](idx); } bobcat-6.07.01/argconfig/initialize6.cc0000664000175000017500000000127314673353433016620 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.reset(new ArgConfig{ accept, optstring, 0, 0, argc, argv, fname, cType, sType, iType } ); return *s_argConfig; } bobcat-6.07.01/argconfig/argconfig2.cc0000664000175000017500000000067514673353433016417 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-6.07.01/argconfig/argconfig1.cc0000664000175000017500000000062114673353433016405 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-6.07.01/argconfig/initialize1.cc0000664000175000017500000000077314673353433016617 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.reset(new ArgConfig{ 0, optstring, 0, 0, argc, argv, cType, sType, iType } ); return *s_argConfig; } bobcat-6.07.01/argconfig/initialize3.cc0000664000175000017500000000117714673353433016620 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.reset(new ArgConfig{ 0, optstring, begin, end, argc, argv, cType, sType, iType } ); return *s_argConfig; } bobcat-6.07.01/argconfig/argconfig.ih0000664000175000017500000000163314736315237016343 0ustar frankfrank#include "argconfig" #include #include #include #include "../string/string" #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 }; // inline ArgConfig::Deleter::operator bool() const // { // return d_argconfig != 0; // } #include "find.f" #include "findend.f" } // FBB using namespace FBB; using namespace std; bobcat-6.07.01/argconfig/argconfig0000664000175000017500000001177114673353433015750 0ustar frankfrank#ifndef INCLUDED_BOBCAT_ARGCONFIG_ #define INCLUDED_BOBCAT_ARGCONFIG_ #include #include #include #include #include #include namespace FBB { class ArgConfig__; class ArgConfig: public Arg, public ConfigFile { ArgConfig__ *d_ptr; static std::unique_ptr s_argConfig; static char const s_alreadyInitialized[]; public: ArgConfig(ArgConfig const &other) = delete; ~ArgConfig(); using Arg::begin; using Arg::end; // 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-6.07.01/argconfig/option3.f0000664000175000017500000000027614673353433015626 0ustar frankfrankinline size_t ArgConfig::option(size_t idx, std::string *value, char const *longOption) const { return Arg::option(idx, value, longOption); } bobcat-6.07.01/argconfig/initialize5.cc0000664000175000017500000000107014673353433016612 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.reset(new ArgConfig{ accept, optstring, 0, 0, argc, argv, cType, sType, iType } ); return *s_argConfig; } bobcat-6.07.01/argconfig/icmconf0000664000175000017500000000015214673353433015416 0ustar frankfrank#define LIBRARY "argconfig" #define EXTRAFLAGS "-I../tmp" #include "../icmconf.lib" bobcat-6.07.01/argconfig/initialize7.cc0000664000175000017500000000121514673353433016615 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.reset(new ArgConfig{ accept, optstring, begin, end, argc, argv, cType, sType, iType } ); return *s_argConfig; } bobcat-6.07.01/argconfig/initialize4.cc0000664000175000017500000000127514673353433016620 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.reset(new ArgConfig{ 0, optstring, begin, end, argc, argv, fname, cType, sType, iType } ); return *s_argConfig; } bobcat-6.07.01/argconfig/argconfig5.cc0000664000175000017500000000037614673353433016420 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-6.07.01/argconfig/destructor.cc0000664000175000017500000000010714673353433016562 0ustar frankfrank#include "argconfig.ih" ArgConfig::~ArgConfig() { delete d_ptr; } bobcat-6.07.01/argconfig/option4.f0000664000175000017500000000027114673353433015622 0ustar frankfrankinline size_t ArgConfig::option(size_t *idx, std::string *value, char const *longOpt) const { return Arg::option(idx, value, longOpt); } bobcat-6.07.01/argconfig/option2.cc0000664000175000017500000000035414673353433015762 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-6.07.01/argconfig/longconfigopt.cc0000664000175000017500000000027714673353433017244 0ustar frankfrank#include "argconfig.ih" ArgConfig::RE_iteratorPair ArgConfig::longConfigOpt(string const &longOpt) { string pattern = "^\\s*" + longOpt + ":?(\\s|$)"; return beginEndRE(pattern); } bobcat-6.07.01/argconfig/initialize8.cc0000664000175000017500000000131314673353433016615 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.reset(new ArgConfig{ accept, optstring, begin, end, argc, argv, fname, cType, sType, iType } ); return *s_argConfig; } bobcat-6.07.01/argconfig/option1.f0000664000175000017500000000027014673353433015616 0ustar frankfrankinline size_t ArgConfig::option(size_t idx, std::string *value, int optChar) const { return Arg::option(idx, value, optChar); } bobcat-6.07.01/argconfig/option2.f0000664000175000017500000000027114673353433015620 0ustar frankfrankinline size_t ArgConfig::option(size_t *idx, std::string *value, int optChar) const { return Arg::option(idx, value, optChar); } bobcat-6.07.01/argconfig/option1.cc0000664000175000017500000000027214673353433015760 0ustar frankfrank#include "argconfig.ih" size_t ArgConfig::option(int optChar) { auto iterators = findLongOption(optChar); return Arg::option(optChar) + (iterators.second - iterators.first); } bobcat-6.07.01/argconfig/findlongoption.cc0000664000175000017500000000101014673353433017407 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-6.07.01/argconfig/findend.f0000664000175000017500000000020014673353433015625 0ustar frankfrankinline std::unordered_map::const_iterator ArgConfig__::findEnd() const { return d_longOption.end(); } bobcat-6.07.01/argconfig/find.f0000664000175000017500000000022014673353433015140 0ustar frankfrankinline std::unordered_map::const_iterator ArgConfig__::find(int optChar) const { return d_longOption.find(optChar); } bobcat-6.07.01/argconfig/driver/0000775000175000017500000000000014737552575015363 5ustar frankfrankbobcat-6.07.01/argconfig/driver/build0000775000175000017500000000116314673353433016400 0ustar frankfrank#!/bin/bash case $1 in (a) g++ `cat ../../c++std` -o driver *.cc -L../tmp -largconfig -lbobcat -s ;; (A) g++ -g `cat ../../c++std` -o driver *.cc -L../../arg/tmp -L../tmp \ -larg -largconfig -lbobcat -s ;; (b) g++ `cat ../../c++std` -o driver *.cc -lbobcat -s ;; (*) echo $0 a links to the files in the current dir, ../tmp/libargconfig echo and bobcat echo $0 A links to the files in the current dir, ../../arg/tmp, echo ../tmp/libargconfig, and bobcat echo $0 b links to the installed bobcat library ;; esac bobcat-6.07.01/argconfig/driver/driver.cc0000664000175000017500000000457414673353433017166 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-6.07.01/argconfig/driver/config0000664000175000017500000000043414673353433016543 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-6.07.01/argconfig/driver/driver.rc0000664000175000017500000000051514673353433017174 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-6.07.01/argconfig/driver/driver.ih0000664000175000017500000000014614673353433017170 0ustar frankfrank#include "driver.h" #include #include using namespace std; using namespace FBB; bobcat-6.07.01/argconfig/line.f0000664000175000017500000000015014673353433015151 0ustar frankfrankinline std::string const &ArgConfig::line(size_t idx) const { return ConfigFile::operator[](idx); } bobcat-6.07.01/base64bufbase/0000775000175000017500000000000014736742656014545 5ustar frankfrankbobcat-6.07.01/base64bufbase/data.cc0000664000175000017500000000031214673353433015750 0ustar frankfrank#include "base64bufbase.ih" string const Base64BufBase::s_tabStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/"; bobcat-6.07.01/base64bufbase/doencrypt.cc0000664000175000017500000000015114673353433017047 0ustar frankfrank#include "base64bufbase.ih" void Base64BufBase::doEncrypt() { d_action = &Base64BufBase::encrypt; } bobcat-6.07.01/base64bufbase/encrypt.cc0000664000175000017500000000146414673353433016534 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-6.07.01/base64bufbase/bits.f0000664000175000017500000000026414673353433015646 0ustar frankfranktemplate inline int Base64BufBase::bits(int value) { return value == EOF ? 0 : (value & ((1 << (from + size)) - 1)) >> from << shl; } bobcat-6.07.01/base64bufbase/indexof.cc0000664000175000017500000000033014673353433016473 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-6.07.01/base64bufbase/base64bufbase.ih0000664000175000017500000000013314736315237017467 0ustar frankfrank#include "base64bufbase" using namespace std; using namespace FBB; using namespace IUO; bobcat-6.07.01/base64bufbase/base64bufbase1.cc0000664000175000017500000000020714673353433017537 0ustar frankfrank#include "base64bufbase.ih" Base64BufBase::Base64BufBase(std::istream &in, size_t bufSize) : IFilterBuf(bufSize), d_in(in) {} bobcat-6.07.01/base64bufbase/filter.cc0000664000175000017500000000052514673353433016332 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-6.07.01/base64bufbase/dodecrypt.cc0000664000175000017500000000017414673353433017042 0ustar frankfrank#include "base64bufbase.ih" void Base64BufBase::doDecrypt() { d_action = &Base64BufBase::decrypt; // setBuffer(); } bobcat-6.07.01/base64bufbase/decrypt.cc0000664000175000017500000000413514673353433016520 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-6.07.01/base64bufbase/base64bufbase0000664000175000017500000000634514673353433017103 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 #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-6.07.01/bigint/0000775000175000017500000000000014736742656013405 5ustar frankfrankbobcat-6.07.01/bigint/opshris.f0000664000175000017500000000011714673353433015231 0ustar frankfrankinline BigInt &BigInt::operator>>=(size_t nBits) { return rshift(nBits); } bobcat-6.07.01/bigint/opsub.cc0000664000175000017500000000023214673353433015030 0ustar frankfrank#include "bigint.ih" namespace FBB { BigInt operator-(BigInt const &lhs, BigInt const &rhs) { BigInt tmp(lhs); tmp -= rhs; return tmp; } } bobcat-6.07.01/bigint/opxoris.cc0000664000175000017500000000145214673353433015410 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-6.07.01/bigint/opisequal.f0000664000175000017500000000014314673353433015543 0ustar frankfrankinline bool operator==(BigInt const &lhs, BigInt const &rhs) { return lhs.compare(rhs) == 0; } bobcat-6.07.01/bigint/setword.cc0000664000175000017500000000132614673353433015374 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-6.07.01/bigint/submodc.cc0000664000175000017500000000023614673353433015340 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-6.07.01/bigint/opgreaterequal.f0000664000175000017500000000014314673353433016561 0ustar frankfrankinline bool operator>=(BigInt const &lhs, BigInt const &rhs) { return lhs.compare(rhs) >= 0; } bobcat-6.07.01/bigint/at.cc0000664000175000017500000000033614673353433014311 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-6.07.01/bigint/lshift1.cc0000664000175000017500000000023714673353433015257 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::lshift() { if (!BN_lshift1(d_bn, d_bn)) throw Exception{} << "BigInt::lshift() failed"; return *this; } bobcat-6.07.01/bigint/lshiftc1.cc0000664000175000017500000000016214673353433015417 0ustar frankfrank#include "bigint.ih" BigInt BigInt::lshiftc() const { BigInt ret(*this); ret.lshift(); return ret; } bobcat-6.07.01/bigint/isqrtc.cc0000664000175000017500000000016014673353433015205 0ustar frankfrank#include "bigint.ih" BigInt BigInt::isqrtc() const { BigInt ret(*this); ret.isqrt(); return ret; } bobcat-6.07.01/bigint/bitoperatorxoris.cc0000664000175000017500000000021514673353433017320 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-6.07.01/bigint/bit1.cc0000664000175000017500000000014114673353433014536 0ustar frankfrank#include "bigint.ih" BigInt::Bit::Bit(BigInt &bi, size_t idx) : d_bi(bi), d_idx(idx) {} bobcat-6.07.01/bigint/setbitc.cc0000664000175000017500000000020314673353433015333 0ustar frankfrank#include "bigint.ih" BigInt BigInt::setBitc(size_t index) const { BigInt ret(*this); ret.setBit(index); return ret; } bobcat-6.07.01/bigint/opindexc.f0000664000175000017500000000011414673353433015350 0ustar frankfrankinline int BigInt::operator[](size_t idx) const { return hasBit(idx); } bobcat-6.07.01/bigint/bigint6.cc0000664000175000017500000000015514673353433015246 0ustar frankfrank#include "bigint.ih" BigInt::BigInt(BIGNUM const *bignum) : d_bn(BN_new()) { copy(d_bn, *bignum); } bobcat-6.07.01/bigint/oporis.cc0000664000175000017500000000145414673353433015222 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-6.07.01/bigint/tildebits.cc0000664000175000017500000000054414673353433015671 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-6.07.01/bigint/bitoperatororis.cc0000664000175000017500000000021614673353433017131 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-6.07.01/bigint/rshift1.cc0000664000175000017500000000023714673353433015265 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::rshift() { if (!BN_rshift1(d_bn, d_bn)) throw Exception{} << "BigInt::rshift() failed"; return *this; } bobcat-6.07.01/bigint/opdivide.cc0000664000175000017500000000023214673353433015503 0ustar frankfrank#include "bigint.ih" namespace FBB { BigInt operator/(BigInt const &lhs, BigInt const &rhs) { BigInt tmp(lhs); tmp /= rhs; return tmp; } } bobcat-6.07.01/bigint/bitoperatorandis.cc0000664000175000017500000000021614673353433017253 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-6.07.01/bigint/exp.cc0000664000175000017500000000031614673353433014477 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-6.07.01/bigint/opmod.cc0000664000175000017500000000023214673353433015016 0ustar frankfrank#include "bigint.ih" namespace FBB { BigInt operator%(BigInt const &lhs, BigInt const &rhs) { BigInt tmp(lhs); tmp %= rhs; return tmp; } } bobcat-6.07.01/bigint/isone.f0000664000175000017500000000010214673353433014651 0ustar frankfrankinline bool BigInt::isOne() const { return BN_is_one(d_bn); } bobcat-6.07.01/bigint/addmod.f0000664000175000017500000000017514673353433014776 0ustar frankfrankinline BigInt &BigInt::addMod(BigInt const &rhs, BigInt const &mod) { return checked2(BN_mod_add, rhs, mod, "addMod"); } bobcat-6.07.01/bigint/littleendian.cc0000664000175000017500000000036314673353433016361 0ustar frankfrank#include "bigint.ih" char *BigInt::littleEndian() const { size_t nBytes = sizeInBytes(); char *ret = new char[nBytes]; BN_bn2bin(d_bn, reinterpret_cast(ret)); reverse(ret, ret + nBytes); return ret; } bobcat-6.07.01/bigint/opgreater.f0000664000175000017500000000014114673353433015527 0ustar frankfrankinline bool operator>(BigInt const &lhs, BigInt const &rhs) { return lhs.compare(rhs) > 0; } bobcat-6.07.01/bigint/sizeofword.f0000664000175000017500000000010314673353433015730 0ustar frankfranksize_t constexpr BigInt::sizeOfWord() { return sizeof(Word); } bobcat-6.07.01/bigint/bnctx.f0000664000175000017500000000006414673353433014661 0ustar frankfrankinline BNCTX::BNCTX() { d_ctx = BN_CTX_new(); } bobcat-6.07.01/bigint/submod.f0000664000175000017500000000017514673353433015037 0ustar frankfrankinline BigInt &BigInt::subMod(BigInt const &rhs, BigInt const &mod) { return checked2(BN_mod_sub, rhs, mod, "subMod"); } bobcat-6.07.01/bigint/negatec.cc0000664000175000017500000000016214673353433015310 0ustar frankfrank#include "bigint.ih" BigInt BigInt::negatec() const { BigInt ret(*this); ret.negate(); return ret; } bobcat-6.07.01/bigint/setbitc2.cc0000664000175000017500000000022614673353433015422 0ustar frankfrank#include "bigint.ih" BigInt BigInt::setBitc(size_t index, bool value) const { BigInt ret(*this); ret.setBit(index, value); return ret; } bobcat-6.07.01/bigint/tildebitsc.cc0000664000175000017500000000017014673353433016027 0ustar frankfrank#include "bigint.ih" BigInt BigInt::tildeBitsc() const { BigInt ret(*this); ret.tildeBits(); return ret; } bobcat-6.07.01/bigint/opindex.f0000664000175000017500000000013714673353433015212 0ustar frankfrankinline BigInt::Bit BigInt::operator[](size_t idx) { Bit bit(*this, idx); return bit; } bobcat-6.07.01/bigint/opinsert.f0000664000175000017500000000015014673353433015402 0ustar frankfrankinline std::ostream &operator<<(std::ostream &out, BigInt const &bn) { return bn.insertInto(out); } bobcat-6.07.01/bigint/adddigit.cc0000664000175000017500000000067014673353433015457 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-6.07.01/bigint/sqrmod.f0000664000175000017500000000014514673353433015050 0ustar frankfrankinline BigInt &BigInt::sqrMod(BigInt const &mod) { return checked4(BN_mod_sqr, mod, "sqrMod"); } bobcat-6.07.01/bigint/randrange.cc0000664000175000017500000000036114673353433015644 0ustar frankfrank#include "bigint.ih" // static 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-6.07.01/bigint/pseudorand.f0000664000175000017500000000015714673353433015712 0ustar frankfrank// static inline BigInt BigInt::pseudoRand(size_t size, Msb msb, Lsb lsb) { return rand(size, msb, lsb); } bobcat-6.07.01/bigint/negate.cc0000664000175000017500000000016214673353433015145 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::negate() { BN_set_negative(d_bn, not isNegative()); return *this; } bobcat-6.07.01/bigint/opxor.cc0000664000175000017500000000024114673353433015047 0ustar frankfrank#include "bigint.ih" namespace FBB { BigInt operator^(BigInt const &lhs, BigInt const &rhs) { BigInt tmp(lhs); tmp ^= rhs; return tmp; } } // FBB bobcat-6.07.01/bigint/checked1.cc0000664000175000017500000000045214673353433015353 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-6.07.01/bigint/rshiftc2.cc0000664000175000017500000000020314673353433015422 0ustar frankfrank#include "bigint.ih" BigInt BigInt::rshiftc(size_t nBits) const { BigInt ret(*this); ret.rshift(nBits); return ret; } bobcat-6.07.01/bigint/sqrmodc.cc0000664000175000017500000000020614673353433015351 0ustar frankfrank#include "bigint.ih" BigInt BigInt::sqrModc(BigInt const &mod) const { BigInt ret(*this); ret.sqrMod(mod); return ret; } bobcat-6.07.01/bigint/prime.cc0000664000175000017500000000070014673353433015014 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-6.07.01/bigint/opinsertbit.cc0000664000175000017500000000024414673353433016245 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-6.07.01/bigint/sqr.cc0000664000175000017500000000025514673353433014512 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-6.07.01/bigint/lshiftc2.cc0000664000175000017500000000020314673353433015414 0ustar frankfrank#include "bigint.ih" BigInt BigInt::lshiftc(size_t nBits) const { BigInt ret(*this); ret.lshift(nBits); return ret; } bobcat-6.07.01/bigint/isqrt.cc0000664000175000017500000000164014673353433015046 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-6.07.01/bigint/opbnctxptr.f0000664000175000017500000000007014673353433015743 0ustar frankfrankinline BNCTX::operator BN_CTX *() { return d_ctx; } bobcat-6.07.01/bigint/bigint5.cc0000664000175000017500000000020114673353433015235 0ustar frankfrank#include "bigint.ih" BigInt::BigInt(BIGNUM const &bignum) : d_bn(BN_new()) { // BN_init(d_bn); copy(d_bn, bignum); } bobcat-6.07.01/bigint/bn2oct.cc0000664000175000017500000000203314673353433015070 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-6.07.01/bigint/opshlis.f0000664000175000017500000000011714673353433015223 0ustar frankfrankinline BigInt &BigInt::operator<<=(size_t nBits) { return lshift(nBits); } bobcat-6.07.01/bigint/checked2.cc0000664000175000017500000000064314673353433015356 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-6.07.01/bigint/bigint7.f0000664000175000017500000000013214673353433015102 0ustar frankfrankinline BigInt::BigInt(BIGNUM *bignum) : BigInt(const_cast(bignum)) {} bobcat-6.07.01/bigint/hasbit.f0000664000175000017500000000014014673353433015010 0ustar frankfrankinline bool BigInt::hasBit(size_t index) const { return BN_is_bit_set(this->d_bn, index); } bobcat-6.07.01/bigint/insertinto.cc0000664000175000017500000000160714673353433016105 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-6.07.01/bigint/opinc.cc0000664000175000017500000000015514673353433015014 0ustar frankfrank#include "bigint.ih" BigInt BigInt::operator++(int) { BigInt tmp(*this); ++*this; return tmp; } bobcat-6.07.01/bigint/rand.cc0000664000175000017500000000033514673353433014630 0ustar frankfrank#include "bigint.ih" // static 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-6.07.01/bigint/bigendian.cc0000664000175000017500000000026214673353433015623 0ustar frankfrank#include "bigint.ih" char *BigInt::bigEndian() const { char *ret = new char[sizeInBytes()]; BN_bn2bin(d_bn, reinterpret_cast(ret)); return ret; } bobcat-6.07.01/bigint/oprshift.cc0000664000175000017500000000023114673353433015535 0ustar frankfrank#include "bigint.ih" namespace FBB { BigInt operator>>(BigInt const &lhs, size_t nBits) { BigInt tmp(lhs); tmp >>= nBits; return tmp; } } bobcat-6.07.01/bigint/tildeint.cc0000664000175000017500000000016514673353433015521 0ustar frankfrank#include "bigint.ih" // neg = toggle + 1 -> toggle = neg - 1 BigInt &BigInt::tildeInt() { return --negate(); } bobcat-6.07.01/bigint/opinc.f0000664000175000017500000000007714673353433014657 0ustar frankfrankinline BigInt &BigInt::operator++() { return *this += 1; } bobcat-6.07.01/bigint/opmodis.cc0000664000175000017500000000017414673353433015357 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::operator%=(BigInt const &rhs) { checked3(0, d_bn, rhs, "%="); return *this; } bobcat-6.07.01/bigint/bigint1.cc0000664000175000017500000000007714673353433015244 0ustar frankfrank#include "bigint.ih" BigInt::BigInt() : d_bn(BN_new()) {} bobcat-6.07.01/bigint/setbigendian.cc0000664000175000017500000000034014673353433016334 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-6.07.01/bigint/bitoperatoris.cc0000664000175000017500000000016714673353433016575 0ustar frankfrank#include "bigint.ih" BigInt::Bit &BigInt::Bit::operator=(bool rhs) { d_bi.setBit(d_idx, rhs); return *this; } bobcat-6.07.01/bigint/lshift2.cc0000664000175000017500000000026714673353433015263 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-6.07.01/bigint/checked4.cc0000664000175000017500000000061214673353433015354 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-6.07.01/bigint/setbit2.cc0000664000175000017500000000017714673353433015264 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::setBit(size_t index, bool value) { return value ? setBit(index) : clearBit(index); } bobcat-6.07.01/bigint/opdec.cc0000664000175000017500000000015514673353433014776 0ustar frankfrank#include "bigint.ih" BigInt BigInt::operator--(int) { BigInt tmp(*this); --*this; return tmp; } bobcat-6.07.01/bigint/sqrc.cc0000664000175000017500000000015414673353433014653 0ustar frankfrank#include "bigint.ih" BigInt BigInt::sqrc() const { BigInt ret(*this); ret.sqr(); return ret; } bobcat-6.07.01/bigint/diophantus1.cc0000664000175000017500000000100714673353433016140 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-6.07.01/bigint/mulmodc.cc0000664000175000017500000000023614673353433015344 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-6.07.01/bigint/opmul.cc0000664000175000017500000000023214673353433015034 0ustar frankfrank#include "bigint.ih" namespace FBB { BigInt operator*(BigInt const &lhs, BigInt const &rhs) { BigInt tmp(lhs); tmp *= rhs; return tmp; } } bobcat-6.07.01/bigint/opmovis.cc0000664000175000017500000000014314673353433015375 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::operator=(BigInt &&tmp) { swap(tmp); return *this; } bobcat-6.07.01/bigint/bigint0000664000175000017500000002645514673353433014607 0ustar frankfrank#ifndef INCLUDED_BOBCAT_BIGINT_ #define INCLUDED_BOBCAT_BIGINT_ #include #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: using Word = BN_ULONG; enum Msb { MSB_UNKNOWN = -1, MSB_IS_ONE, TOP_TWO_BITS_ONE }; enum Lsb { EVEN, ODD, }; enum PrimeType { ANY = false, SAFE = true }; enum Little {}; 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(size_t length, char const *littleEndian, bool negative = false); // 10 BigInt(Little endian, std::string littleEndian, bool negative = false); // 11 ~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; char *littleEndian() 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, // .f Msb msb = MSB_IS_ONE, Lsb lsb = ODD); static BigInt pseudoRandRange(BigInt const &max); // .f 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 "pseudorand.f" #include "pseudorandrange.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-6.07.01/bigint/nwordscheck.cc0000664000175000017500000000043314673353433016215 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-6.07.01/bigint/opand.cc0000664000175000017500000000024114673353433015001 0ustar frankfrank#include "bigint.ih" namespace FBB { BigInt operator&(BigInt const &lhs, BigInt const &rhs) { BigInt tmp(lhs); tmp &= rhs; return tmp; } } // FBB bobcat-6.07.01/bigint/bigint4.f0000664000175000017500000000036514673353433015107 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-6.07.01/bigint/pseudorandrange.f0000664000175000017500000000014214673353433016721 0ustar frankfrank// static inline BigInt BigInt::pseudoRandRange(BigInt const &max) { return randRange(max); } bobcat-6.07.01/bigint/opless.f0000664000175000017500000000014114673353433015044 0ustar frankfrankinline bool operator<(BigInt const &lhs, BigInt const &rhs) { return lhs.compare(rhs) < 0; } bobcat-6.07.01/bigint/addmodc.cc0000664000175000017500000000023614673353433015277 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-6.07.01/bigint/iszero.f0000664000175000017500000000010414673353433015051 0ustar frankfrankinline bool BigInt::isZero() const { return BN_is_zero(d_bn); } bobcat-6.07.01/bigint/inversemodc.cc0000664000175000017500000000022114673353433016214 0ustar frankfrank#include "bigint.ih" BigInt BigInt::inverseModc(BigInt const &mod) const { BigInt ret(*this); mod_inverse(&ret, mod); return ret; } bobcat-6.07.01/bigint/gcdc.cc0000664000175000017500000000020014673353433014573 0ustar frankfrank#include "bigint.ih" BigInt BigInt::gcdc(BigInt const &rhs) const { BigInt ret(*this); ret.gcd(rhs); return ret; } bobcat-6.07.01/bigint/expc.cc0000664000175000017500000000021214673353433014635 0ustar frankfrank#include "bigint.ih" BigInt BigInt::expc(BigInt const &exponent) const { BigInt ret(*this); ret.exp(exponent); return ret; } bobcat-6.07.01/bigint/modinverse.cc0000664000175000017500000000034014673353433016053 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-6.07.01/bigint/icmconf0000664000175000017500000000007414673353433014736 0ustar frankfrank#define LIBRARY "bigint" #include "../icmconf" bobcat-6.07.01/bigint/rshiftc1.cc0000664000175000017500000000016214673353433015425 0ustar frankfrank#include "bigint.ih" BigInt BigInt::rshiftc() const { BigInt ret(*this); ret.rshift(); return ret; } bobcat-6.07.01/bigint/size.f0000664000175000017500000000010514673353433014511 0ustar frankfrankinline size_t BigInt::size() const { return BN_num_bits(d_bn); } bobcat-6.07.01/bigint/bigint11.cc0000664000175000017500000000050314673353433015317 0ustar frankfrank#include "bigint.ih" BigInt::BigInt([[maybe_unused]] Little dummy, string bytes, bool negative) : BigInt() { reverse(bytes.begin(), bytes.end()); // convert to big endian BigInt tmp(bytes, negative); // construct the BigInt swap(tmp); // install it } bobcat-6.07.01/bigint/setnegative.cc0000664000175000017500000000017414673353433016223 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::setNegative(bool negative) { BN_set_negative(d_bn, negative); return *this; } bobcat-6.07.01/bigint/rshift2.cc0000664000175000017500000000030314673353433015260 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-6.07.01/bigint/opsubis.f0000664000175000017500000000014014673353433015222 0ustar frankfrankinline BigInt &BigInt::operator-=(BigInt const &rhs) { return checked1(BN_sub, rhs, "-"); } bobcat-6.07.01/bigint/expmod.cc0000664000175000017500000000036214673353433015200 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-6.07.01/bigint/setbit.cc0000664000175000017500000000026014673353433015173 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-6.07.01/bigint/mulmod.f0000664000175000017500000000017514673353433015043 0ustar frankfrankinline BigInt &BigInt::mulMod(BigInt const &rhs, BigInt const &mod) { return checked2(BN_mod_mul, rhs, mod, "mulMod"); } bobcat-6.07.01/bigint/destructor.f0000664000175000017500000000006314673353433015740 0ustar frankfrankinline BNCTX::~BNCTX() { BN_CTX_free(d_ctx); } bobcat-6.07.01/bigint/bigint3.cc0000664000175000017500000000014514673353433015242 0ustar frankfrank#include "bigint.ih" BigInt::BigInt(BigInt &&tmp) : d_bn(tmp.d_bn) { tmp.d_bn = BN_new(); } bobcat-6.07.01/bigint/bigint10.cc0000664000175000017500000000046714673353433015327 0ustar frankfrank#include "bigint.ih" BigInt::BigInt(size_t length, char const *bytes, bool negative) : BigInt() { // construct the BigInt BigInt tmp{ Little{}, string{ bytes, bytes + length }, negative }; swap(tmp); // install it. } bobcat-6.07.01/bigint/destructor.cc0000664000175000017500000000007714673353433016105 0ustar frankfrank#include "bigint.ih" BigInt::~BigInt() { BN_free(d_bn); } bobcat-6.07.01/bigint/opdivis.cc0000664000175000017500000000017414673353433015362 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::operator/=(BigInt const &rhs) { checked3(d_bn, 0, rhs, "/="); return *this; } bobcat-6.07.01/bigint/opis.cc0000664000175000017500000000020214673353433014647 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::operator=(BigInt const &other) { BigInt tmp(other); swap(tmp); return *this; } bobcat-6.07.01/bigint/oplessequal.f0000664000175000017500000000014314673353433016076 0ustar frankfrankinline bool operator<=(BigInt const &lhs, BigInt const &rhs) { return lhs.compare(rhs) <= 0; } bobcat-6.07.01/bigint/isodd.f0000664000175000017500000000010214673353433014636 0ustar frankfrankinline bool BigInt::isOdd() const { return BN_is_odd(d_bn); } bobcat-6.07.01/bigint/gcd.cc0000664000175000017500000000016514673353433014442 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::gcd(BigInt const &rhs) { checked4(BN_gcd, rhs, "gcd"); return *this; } bobcat-6.07.01/bigint/swap.cc0000664000175000017500000000012414673353433014652 0ustar frankfrank#include "bigint.ih" void BigInt::swap(BigInt &other) { fswap(*this, other); } bobcat-6.07.01/bigint/opandis.cc0000664000175000017500000000145314673353433015343 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-6.07.01/bigint/opaddis.f0000664000175000017500000000014014673353433015161 0ustar frankfrankinline BigInt &BigInt::operator+=(BigInt const &rhs) { return checked1(BN_add, rhs, "+"); } bobcat-6.07.01/bigint/opbool.f0000664000175000017500000000011514673353433015032 0ustar frankfrankinline BigInt::Bit::operator bool() const { return d_bi.hasBit(d_idx); } bobcat-6.07.01/bigint/bigint8.cc0000664000175000017500000000036014673353433015246 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-6.07.01/bigint/opextract.cc0000664000175000017500000000157514673353433015724 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-6.07.01/bigint/setnegativec.cc0000664000175000017500000000022114673353433016357 0ustar frankfrank#include "bigint.ih" BigInt BigInt::setNegativec(bool negative) const { BigInt ret(*this); ret.setNegative(negative); return ret; } bobcat-6.07.01/bigint/bignum.f0000664000175000017500000000010214673353433015015 0ustar frankfrankinline BIGNUM const &BigInt::bignum() const { return *d_bn; } bobcat-6.07.01/bigint/maskbits.cc0000664000175000017500000000027114673353433015520 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-6.07.01/bigint/nwords.f0000664000175000017500000000013014673353433015051 0ustar frankfrankinline size_t BigInt::nWords() const { return (size() + BN_BYTES - 1) / BN_BYTES; } bobcat-6.07.01/bigint/ucompare.f0000664000175000017500000000014114673353433015352 0ustar frankfrankinline int BigInt::uCompare(BigInt const &other) const { return BN_ucmp(d_bn, other.d_bn); } bobcat-6.07.01/bigint/compare.f0000664000175000017500000000013714673353433015172 0ustar frankfrankinline int BigInt::compare(BigInt const &other) const { return BN_cmp(d_bn, other.d_bn); } bobcat-6.07.01/bigint/bigint9.cc0000664000175000017500000000021514673353433015246 0ustar frankfrank#include "bigint.ih" BigInt::BigInt(string const &bigEndian, bool negative) : BigInt(bigEndian.data(), bigEndian.length(), negative) {} bobcat-6.07.01/bigint/opmulis.cc0000664000175000017500000000031414673353433015371 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-6.07.01/bigint/bigint2.cc0000664000175000017500000000020514673353433015236 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-6.07.01/bigint/isoctdigit.cc0000664000175000017500000000015514673353433016046 0ustar frankfrank#include "bigint.ih" namespace FBB { int isoctdigit(int ch) { return strchr("01234567", ch) != 0; } } bobcat-6.07.01/bigint/ulong.f0000664000175000017500000000011514673353433014664 0ustar frankfrankinline unsigned long BigInt::ulong() const { return BN_get_word(d_bn); } bobcat-6.07.01/bigint/opadd.cc0000664000175000017500000000023214673353433014767 0ustar frankfrank#include "bigint.ih" namespace FBB { BigInt operator+(BigInt const &lhs, BigInt const &rhs) { BigInt tmp(lhs); tmp += rhs; return tmp; } } bobcat-6.07.01/bigint/checked3.cc0000664000175000017500000000041014673353433015347 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-6.07.01/bigint/expmodc.cc0000664000175000017500000000025014673353433015337 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-6.07.01/bigint/opisunequal.f0000664000175000017500000000014314673353433016106 0ustar frankfrankinline bool operator!=(BigInt const &lhs, BigInt const &rhs) { return lhs.compare(rhs) != 0; } bobcat-6.07.01/bigint/isnegative.f0000664000175000017500000000012214673353433015674 0ustar frankfrankinline bool BigInt::isNegative() const { return BN_is_negative(this->d_bn); } bobcat-6.07.01/bigint/bigint.ih0000664000175000017500000000122214736315237015167 0ustar frankfrank#include "bigint" #include #include #include #include #include "../fswap/fswap" 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-6.07.01/bigint/div.cc0000664000175000017500000000022714673353433014466 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::div(BigInt *remainder, BigInt const &rhs) { checked3(d_bn, remainder->d_bn, rhs, "div"); return *this; } bobcat-6.07.01/bigint/divc.cc0000664000175000017500000000026614673353433014634 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-6.07.01/bigint/opnegate.cc0000664000175000017500000000016414673353433015506 0ustar frankfrank#include "bigint.ih" BigInt BigInt::operator-() const { BigInt tmp(*this); tmp.negate(); return tmp; } bobcat-6.07.01/bigint/tildeintc.cc0000664000175000017500000000016614673353433015665 0ustar frankfrank#include "bigint.ih" BigInt BigInt::tildeIntc() const { BigInt ret(*this); ret.tildeInt(); return ret; } bobcat-6.07.01/bigint/fromtext.cc0000664000175000017500000000264514673353433015562 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-6.07.01/bigint/clearbit.cc0000664000175000017500000000016214673353433015467 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::clearBit(size_t index) { BN_clear_bit(d_bn, index); return *this; } bobcat-6.07.01/bigint/oplshift.cc0000664000175000017500000000023114673353433015527 0ustar frankfrank#include "bigint.ih" namespace FBB { BigInt operator<<(BigInt const &lhs, size_t nBits) { BigInt tmp(lhs); tmp <<= nBits; return tmp; } } bobcat-6.07.01/bigint/opdec.f0000664000175000017500000000007714673353433014641 0ustar frankfrankinline BigInt &BigInt::operator--() { return *this -= 1; } bobcat-6.07.01/bigint/sizeinbytes.f0000664000175000017500000000011514673353433016110 0ustar frankfrankinline size_t BigInt::sizeInBytes() const { return BN_num_bytes(d_bn); } bobcat-6.07.01/bigint/opor.cc0000664000175000017500000000023214673353433014657 0ustar frankfrank#include "bigint.ih" namespace FBB { BigInt operator|(BigInt const &lhs, BigInt const &rhs) { BigInt tmp(lhs); tmp |= rhs; return tmp; } } bobcat-6.07.01/bigint/inversemod.cc0000664000175000017500000000016614673353433016061 0ustar frankfrank#include "bigint.ih" BigInt &BigInt::inverseMod(BigInt const &mod) { mod_inverse(this, mod); return *this; } bobcat-6.07.01/bigint/clearbitc.cc0000664000175000017500000000022014673353433015625 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-6.07.01/bigint/driver/0000775000175000017500000000000014737552575014700 5ustar frankfrankbobcat-6.07.01/bigint/driver/build0000775000175000017500000000121314673353433015711 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-6.07.01/bigint/driver/driver.cc0000664000175000017500000001265314673353433016500 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'; } #include int main(int argc, char **argv) try { if (argc == 1) throw Exception(1) << "Provide h (hex), o (oct), or d (dec) " "and read the value frm stdin"; 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-6.07.01/bigint/driver/example.cc0000664000175000017500000000077314673353433016640 0ustar frankfrank#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 << '\n'; } // shows: // (1258586273445895786081124957771 * 828997573545038) % // 1007205247048889 = 1 bobcat-6.07.01/bigint/diophantus2.cc0000664000175000017500000000100614673353433016140 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-6.07.01/bigint/maskbitsc.cc0000664000175000017500000000022114673353433015656 0ustar frankfrank#include "bigint.ih" BigInt BigInt::maskBitsc(size_t lowerNBits) const { BigInt ret(*this); ret.maskBits(lowerNBits); return ret; } bobcat-6.07.01/bigint/copy.cc0000664000175000017500000000024714673353433014660 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-6.07.01/binarysearch/0000775000175000017500000000000014673353433014572 5ustar frankfrankbobcat-6.07.01/binarysearch/binarysearch2.f0000664000175000017500000000070514673353433017477 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-6.07.01/binarysearch/binarysearch0000664000175000017500000000043214673353433017166 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-6.07.01/binarysearch/binarysearch1.f0000664000175000017500000000036014673353433017473 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-6.07.01/binarysearch/driver/0000775000175000017500000000000014737552575016076 5ustar frankfrankbobcat-6.07.01/binarysearch/driver/build0000775000175000017500000000004314673353433017107 0ustar frankfrank#!/bin/sh g++ -o driver driver.cc bobcat-6.07.01/binarysearch/driver/driver.cc0000664000175000017500000000223614736770464017701 0ustar frankfrank#include #include #include 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-6.07.01/binarysearch/driver/driver2.cc0000664000175000017500000000151114736770540017751 0ustar frankfrank#include #include #include 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-6.07.01/binops/0000775000175000017500000000000014673353433013412 5ustar frankfrankbobcat-6.07.01/binops/opmod1.f0000664000175000017500000000016614673353433014763 0ustar frankfranktemplate inline Class operator%(Class &&lhs, Class const &rhs) { return std::move(lhs %= rhs); } bobcat-6.07.01/binops/opbitand1.f0000664000175000017500000000016614673353433015445 0ustar frankfranktemplate inline Class operator&(Class &&lhs, Class const &rhs) { return std::move(lhs &= rhs); } bobcat-6.07.01/binops/opbitxor2.f0000664000175000017500000000040014673353433015503 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-6.07.01/binops/opbitxor1.f0000664000175000017500000000016614673353433015513 0ustar frankfranktemplate inline Class operator^(Class &&lhs, Class const &rhs) { return std::move(lhs ^= rhs); } bobcat-6.07.01/binops/opadd1.f0000664000175000017500000000016614673353433014734 0ustar frankfranktemplate inline Class operator+(Class &&lhs, Class const &rhs) { return std::move(lhs += rhs); } bobcat-6.07.01/binops/optimes1.f0000664000175000017500000000016614673353433015325 0ustar frankfranktemplate inline Class operator*(Class &&lhs, Class const &rhs) { return std::move(lhs *= rhs); } bobcat-6.07.01/binops/opbitand2.f0000664000175000017500000000040014673353433015435 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-6.07.01/binops/binops0000664000175000017500000000260114673353433014626 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-6.07.01/binops/opshr2.f0000664000175000017500000000040214673353433014772 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-6.07.01/binops/opdiv2.f0000664000175000017500000000040014673353433014756 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-6.07.01/binops/optimes2.f0000664000175000017500000000040014673353433015315 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-6.07.01/binops/opbitor1.f0000664000175000017500000000016614673353433015323 0ustar frankfranktemplate inline Class operator|(Class &&lhs, Class const &rhs) { return std::move(lhs |= rhs); } bobcat-6.07.01/binops/opdiv1.f0000664000175000017500000000016614673353433014766 0ustar frankfranktemplate inline Class operator/(Class &&lhs, Class const &rhs) { return std::move(lhs /= rhs); } bobcat-6.07.01/binops/opshr1.f0000664000175000017500000000017014673353433014773 0ustar frankfranktemplate inline Class operator>>(Class &&lhs, Class const &rhs) { return std::move(lhs >>= rhs); } bobcat-6.07.01/binops/opsub1.f0000664000175000017500000000016614673353433014775 0ustar frankfranktemplate inline Class operator-(Class &&lhs, Class const &rhs) { return std::move(lhs -= rhs); } bobcat-6.07.01/binops/opsub2.f0000664000175000017500000000040014673353433014765 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-6.07.01/binops/opshl2.f0000664000175000017500000000040214673353433014764 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-6.07.01/binops/opmod2.f0000664000175000017500000000040014673353433014753 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-6.07.01/binops/opshl1.f0000664000175000017500000000017014673353433014765 0ustar frankfranktemplate inline Class operator<<(Class &&lhs, Class const &rhs) { return std::move(lhs <<= rhs); } bobcat-6.07.01/binops/driver/0000775000175000017500000000000014737552575014716 5ustar frankfrankbobcat-6.07.01/binops/driver/build0000775000175000017500000000005614736771324015736 0ustar frankfrank#!/bin/bash g++ -Wall -o driver driver.cc -s bobcat-6.07.01/binops/driver/driver.cc0000664000175000017500000000147614736771222016517 0ustar frankfrank#include #include #include #include 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-6.07.01/binops/opbitor2.f0000664000175000017500000000040014673353433015313 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-6.07.01/binops/opadd2.f0000664000175000017500000000040014673353433014724 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-6.07.01/binopsbase/0000775000175000017500000000000014673353433014245 5ustar frankfrankbobcat-6.07.01/binopsbase/sub.f0000664000175000017500000000076014673353433015210 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-6.07.01/binopsbase/or.f0000664000175000017500000000076014673353433015037 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-6.07.01/binopsbase/binopsbase0000664000175000017500000000137414673353433016322 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-6.07.01/binopsbase/shl1.f0000664000175000017500000000075514673353433015272 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-6.07.01/binopsbase/shr1.f0000664000175000017500000000076614673353433015302 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-6.07.01/binopsbase/der.f0000664000175000017500000000060214673353433015164 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-6.07.01/binopsbase/extract.f0000664000175000017500000000040414673353433016064 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-6.07.01/binopsbase/mul.f0000664000175000017500000000076014673353433015214 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-6.07.01/binopsbase/insert.f0000664000175000017500000000042414673353433015720 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-6.07.01/binopsbase/mod.f0000664000175000017500000000076014673353433015176 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-6.07.01/binopsbase/xor.f0000664000175000017500000000076014673353433015227 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-6.07.01/binopsbase/and.f0000664000175000017500000000076014673353433015161 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-6.07.01/binopsbase/add.f0000664000175000017500000000074714673353433015154 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-6.07.01/binopsbase/driver/0000775000175000017500000000000014737552575015551 5ustar frankfrankbobcat-6.07.01/binopsbase/driver/driver.cc0000664000175000017500000000474614673353433017355 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-6.07.01/binopsbase/driver/README0000664000175000017500000000024714673353433016423 0ustar frankfrank * Self-defined binary operators take priority over the template instantiations: it's always possible to outguess/outperform the template definitions. bobcat-6.07.01/binopsbase/div.f0000664000175000017500000000076014673353433015201 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-6.07.01/binopsbase0/0000775000175000017500000000000014736315237014325 5ustar frankfrankbobcat-6.07.01/binopsbase0/shl.f0000664000175000017500000000175414673353433015271 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-6.07.01/binopsbase0/sub.f0000664000175000017500000000174614673353433015275 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-6.07.01/binopsbase0/or.f0000664000175000017500000000173614673353433015123 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-6.07.01/binopsbase0/binopsbase0000664000175000017500000000244714673353433016404 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-6.07.01/binopsbase0/shr.f0000664000175000017500000000175414673353433015277 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-6.07.01/binopsbase0/binopsbase.ih0000664000175000017500000000002614736315237016772 0ustar frankfrank#include "binopsbase" bobcat-6.07.01/binopsbase0/wraps.f0000664000175000017500000000074414673353433015635 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-6.07.01/binopsbase0/inlines.f0000664000175000017500000000502314673353433016135 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-6.07.01/binopsbase0/friends.f0000664000175000017500000000402714673353433016131 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-6.07.01/binopsbase0/extract.f0000664000175000017500000000047414673353433016153 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-6.07.01/binopsbase0/mul.f0000664000175000017500000000174614673353433015301 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-6.07.01/binopsbase0/insert.f0000664000175000017500000000050114673353433015774 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-6.07.01/binopsbase0/mod.f0000664000175000017500000000174614673353433015263 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-6.07.01/binopsbase0/xor.f0000664000175000017500000000174614673353433015314 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-6.07.01/binopsbase0/and.f0000664000175000017500000000174614673353433015246 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-6.07.01/binopsbase0/add.f0000664000175000017500000000174714673353433015235 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-6.07.01/binopsbase0/frame.f0000664000175000017500000000005314673353433015564 0ustar frankfrank#include "binopsbase.ih" BinopsBase:: { } bobcat-6.07.01/binopsbase0/driver/0000775000175000017500000000000014737552575015631 5ustar frankfrankbobcat-6.07.01/binopsbase0/driver/driver.cc0000664000175000017500000000230714673353433017424 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-6.07.01/binopsbase0/div.f0000664000175000017500000000174614673353433015266 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-6.07.01/build0000775000175000017500000001757714737165210013161 0ustar frankfrank#!/usr/bin/icmake -t. #include "INSTALL.im" #define MULTICOMP // used by default in icmake/libaries // #define SPCH "-n -u xerr/xerr.ih" #define IH ".ih" #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 == "headers") { 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" " headers - 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-6.07.01/cerrextractor/0000775000175000017500000000000014736742656015020 5ustar frankfrankbobcat-6.07.01/cerrextractor/cerrextractor.ih0000664000175000017500000000015614736315237020222 0ustar frankfrank#include "cerrextractor" #include #include using namespace std; using namespace FBB; bobcat-6.07.01/cerrextractor/cerrextractor2.cc0000664000175000017500000000022314673353433020264 0ustar frankfrank#include "cerrextractor.ih" CerrExtractor::CerrExtractor(StdMode mode, size_t bufSize) : IUO::ExtractorBase(bufSize), d_modeFun(close) {} bobcat-6.07.01/cerrextractor/cerrextractor1.cc0000664000175000017500000000020714673353433020265 0ustar frankfrank#include "cerrextractor.ih" CerrExtractor::CerrExtractor(size_t bufSize) : IUO::ExtractorBase(bufSize), d_modeFun(noClose) {} bobcat-6.07.01/cerrextractor/cerrextractor0000664000175000017500000000066514673353433017630 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-6.07.01/cerrextractor/icmconf0000664000175000017500000000010314673353433016342 0ustar frankfrank#define LIBRARY "cerrextractor" #include "../icmconf" bobcat-6.07.01/cerrextractor/close.cc0000664000175000017500000000043414673353433016424 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-6.07.01/cerrextractor/childredirections.cc0000664000175000017500000000027414673353433021017 0ustar frankfrank#include "cerrextractor.ih" void CerrExtractor::childRedirections() { (*d_modeFun)(); // optionally close STDIN and STDOUT childOutPipe().writtenBy(STDERR_FILENO); } bobcat-6.07.01/cerrextractor/driver/0000775000175000017500000000000014737552575016313 5ustar frankfrankbobcat-6.07.01/cerrextractor/driver/build0000775000175000017500000000017414673353433017331 0ustar frankfrank#!/bin/bash g++ -Wall -odriver driver.cc -L../../extractorbase/tmp -lextractorbase \ -L../tmp -Lcoutextractor -lbobcat bobcat-6.07.01/cerrextractor/driver/driver.cc0000664000175000017500000000065714673353433020114 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-6.07.01/cgi/0000775000175000017500000000000014736742656012673 5ustar frankfrankbobcat-6.07.01/cgi/chartoken.cc0000664000175000017500000000024614673353433015151 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-6.07.01/cgi/post.cc0000664000175000017500000000042514673353433014157 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-6.07.01/cgi/setfsa.cc0000664000175000017500000000050414673353433014455 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-6.07.01/cgi/get.cc0000664000175000017500000000027014673353433013747 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-6.07.01/cgi/escape.cc0000664000175000017500000000126314673353433014433 0ustar frankfrank#include "cgi.ih" string CGI::escape(string const &text) { string ret; auto begin = text.begin(); auto end = text.end(); while (true) { auto mid = find_if(begin, end, [&](unsigned char ch) { return d_escape[ch]; } ); ret.append(begin, mid); if (mid == end) break; ret += '\\'; ret += *mid; begin = mid + 1; } return ret; } // string ret = text; // // for (size_t idx = ret.length(); idx--; ) // { // if (d_escape[static_cast(ret[idx])]) // ret.insert(idx, "\\"); // } // return ret; //} bobcat-6.07.01/cgi/method.f0000664000175000017500000000010014673353433014300 0ustar frankfrankinline CGI::Method CGI::method() const { return d_method; } bobcat-6.07.01/cgi/opinsert2.cc0000664000175000017500000000064414673353433015122 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-6.07.01/cgi/acceptall.cc0000664000175000017500000000025014673353433015116 0ustar frankfrank#include "cgi.ih" void CGIFSA::acceptAll() { while (d_stack.size()) { char top = d_stack.top(); setEscape(top); d_stack.pop(); } } bobcat-6.07.01/cgi/setquery.cc0000664000175000017500000000115214673353433015051 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-6.07.01/cgi/accept.cc0000664000175000017500000000035214673353433014430 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-6.07.01/cgi/cgifsa.cc0000664000175000017500000000044714673353433014432 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-6.07.01/cgi/opindex.f0000664000175000017500000000014514673353433014477 0ustar frankfrankinline char const *CGI::operator[](std::string const &key) const { return getenv(key.c_str()); } bobcat-6.07.01/cgi/last.f0000664000175000017500000000011414673353433013770 0ustar frankfrankinline std::string Cidr::last() const { return binary2dotted(d_last); } bobcat-6.07.01/cgi/run.cc0000664000175000017500000000104214673353433013772 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-6.07.01/cgi/unpercent.cc0000664000175000017500000000162614673353433015201 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; if (pos < ret.length()) ret.replace(pos, 3, replacement); } } ++pos; // next char } return ret; } bobcat-6.07.01/cgi/maxuploadsize.f0000664000175000017500000000012514673353433015714 0ustar frankfrankinline unsigned long long CGI::maxUploadSize() const { return d_maxUploadSize; } bobcat-6.07.01/cgi/query.f0000664000175000017500000000010514673353433014172 0ustar frankfrankinline std::string const &CGI::query() const { return d_query; } bobcat-6.07.01/cgi/opinsert3.cc0000664000175000017500000000031114673353433015112 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-6.07.01/cgi/opinsert1.cc0000664000175000017500000000037514673353433015122 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-6.07.01/cgi/report.cc0000664000175000017500000000032614673353433014505 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-6.07.01/cgi/first.f0000664000175000017500000000012414673353433014155 0ustar frankfrankinline std::string Cidr::first() const { return binary2dotted(d_iter->first); } bobcat-6.07.01/cgi/multipartformdata.cc0000664000175000017500000000163014673353433016730 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-6.07.01/cgi/dos2unix.cc0000664000175000017500000000041414673353433014743 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-6.07.01/cgi/wordtoken.cc0000664000175000017500000000153114673353433015205 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-6.07.01/cgi/cgi0000664000175000017500000000776514673353433013366 0ustar frankfrank#ifndef INCLUDED_BOBCAT_CGI_ #define INCLUDED_BOBCAT_CGI_ #include #include #include #include #include #include #include #include namespace FBB { class CGI { friend std::ostream &operator<<(std::ostream &out, CGI const &cgi); public: using MapStringVector = std::unordered_map>; 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-6.07.01/cgi/cgi.ih0000664000175000017500000000442114736315237013747 0ustar frankfrank#include "cgi" #include #include #include #include #include #include #include #include #include #include #include "../string/string" #include "../stat/stat" #include "../fswap/fswap" #include "../ranger/ranger" namespace FBB { using PairCPPFunP = std::pair; 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)(); }; std::stack d_stack; bool *d_escape; bool d_setEscape; State d_state; size_t d_tokenIdx; std::string d_buffer; size_t d_setIdx; std::istream &d_in; struct Transition { size_t token; void (CGIFSA::*action)(); State next; }; static std::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 std::string s_cgi; public: CGIFSA(bool *escape, std::istream &in = std::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 using namespace std; using namespace FBB; bobcat-6.07.01/cgi/next.cc0000664000175000017500000000024514673353433014150 0ustar frankfrank#include "cgi.ih" void CGI::next(string *line) { if (!getline(cin, *line)) { d_status = "Invalid multipart/form-data"; throw false; } } bobcat-6.07.01/cgi/charclass.cc0000664000175000017500000000057414673353433015142 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-6.07.01/cgi/begin.f0000664000175000017500000000015114673353433014112 0ustar frankfrankinline CGI::MapStringVector::const_iterator CGI::begin() { setParam(); return d_param.begin(); } bobcat-6.07.01/cgi/addparam.cc0000664000175000017500000000036514673353433014746 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-6.07.01/cgi/iscgi.f0000664000175000017500000000013214673353433014123 0ustar frankfrankinline int FBB::CGIFSA::iscgi(int ch) { return s_cgi.find(ch) != std::string::npos; } bobcat-6.07.01/cgi/mask.f0000664000175000017500000000013114673353433013757 0ustar frankfrankinline std::string Cidr::mask() const { return to_string(d_iter->second); // X2a } bobcat-6.07.01/cgi/end.f0000664000175000017500000000014514673353433013577 0ustar frankfrankinline CGI::MapStringVector::const_iterator CGI::end() { setParam(); return d_param.end(); } bobcat-6.07.01/cgi/charrange.cc0000664000175000017500000000067514673353433015133 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-6.07.01/cgi/readpart.cc0000664000175000017500000000074714673353433015003 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-6.07.01/cgi/icmconf0000664000175000017500000000007114673353433014221 0ustar frankfrank#define LIBRARY "cgi" #include "../icmconf" bobcat-6.07.01/cgi/opinsert0.cc0000664000175000017500000000055614673353433015122 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-6.07.01/cgi/cgidata.cc0000664000175000017500000000617314673353433014574 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-6.07.01/cgi/typeof.cc0000664000175000017500000000040614673353433014477 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-6.07.01/cgi/operatorassign.cc0000664000175000017500000000012714673353433016231 0ustar frankfrank#include "cgi.ih" CGI &CGI::operator=(CGI &&tmp) { swap(tmp); return *this; } bobcat-6.07.01/cgi/isfile.cc0000664000175000017500000000064614673353433014452 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-6.07.01/cgi/setmethod.cc0000664000175000017500000000220514673353433015164 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-6.07.01/cgi/swap.cc0000664000175000017500000000040414673353433014141 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-6.07.01/cgi/cgi1.cc0000664000175000017500000000140314673353433014012 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-6.07.01/cgi/param.cc0000664000175000017500000000035714673353433014276 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-6.07.01/cgi/setescape.f0000664000175000017500000000011714673353433015004 0ustar frankfrankinline void CGIFSA::setEscape(size_t idx) { d_escape[idx] = d_setEscape; } bobcat-6.07.01/cgi/setmaxuploadsize.cc0000664000175000017500000000076514673353433016602 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-6.07.01/cgi/cgi2.cc0000664000175000017500000000121214673353433014011 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-6.07.01/cgi/param1.cc0000664000175000017500000000030214673353433014345 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-6.07.01/cgi/address.f0000664000175000017500000000011214673353433014450 0ustar frankfrankinline std::string const &Cidr::address() const { return d_matched; } bobcat-6.07.01/cgi/setparam.cc0000664000175000017500000000050114673353433015001 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-6.07.01/cgi/upload.cc0000664000175000017500000000724414673353433014464 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-6.07.01/cgi/setfiledestination.cc0000664000175000017500000000175614673353433017077 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-6.07.01/cgi/driver/0000775000175000017500000000000014737552575014166 5ustar frankfrankbobcat-6.07.01/cgi/driver/build0000775000175000017500000000203114673353433015176 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-6.07.01/cgi/driver/driver.cc0000664000175000017500000000347414673353433015767 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-6.07.01/cgi/driver/usage.cc0000664000175000017500000000222314673353433015567 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-6.07.01/cgi/driver/post10000664000175000017500000000036014673353433015145 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-6.07.01/cgi/driver/get0000664000175000017500000000032114673353433014653 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-6.07.01/cgi/driver/post20000664000175000017500000000044514673353433015152 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-6.07.01/cgi/driver/post2.cin0000664000175000017500000000230714673353433015721 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-6.07.01/cgi/driver/post1.cin0000664000175000017500000000026714673353433015723 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-6.07.01/cgi/driver/version.cc0000664000175000017500000000031014673353433016143 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-6.07.01/cgi/driver/main.ih0000664000175000017500000000055214673353433015425 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-6.07.01/cgi/push.cc0000664000175000017500000000015414673353433014150 0ustar frankfrank#include "cgi.ih" void CGIFSA::push() { for (auto &element: d_buffer) d_stack.push(element); } bobcat-6.07.01/cgi/tokenidx.cc0000664000175000017500000000114114673353433015013 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-6.07.01/changelog0000664000175000017500000031213314746121046013767 0ustar frankfrankbobcat 6.07.01 * Repaired an inconsistency in the returntype specification of FileSystem's removeAll() member -- Frank B. Brokken Tue, 28 Jan 2025 10:23:42 +0100 bobcat 6.07.00 * NOTE: Arg::Type::None was renamed to Arg::Type::NoArg * Added classes FileSystem (wrapping std::filesystem), FileClock (wrapping std::filesystem::file_clock), HighResolutionClock (wrapping std::filesystem::high_resolution_clock), SteadyClock (wrapping std::filesystem::steady_clock), SystemClock (wrapping std::filesystem::system_clock) * Constructing the libraries requires icmake >= version 13.00.03 * #ifndef SPCH_ checks were removed from the .ih files: not required anymore since icmake 13.00.03 * The deprecated classes EncryptBuf, DecryptBuf and CryptBuf were already removed from the libraries; they're now also removed from Bobcat's repository -- Frank B. Brokken Fri, 10 Jan 2025 09:32:03 +0100 bobcat (6.06.02) * Fixed Log's insertion of std::endl which didn't end the current log entry -- Frank B. Brokken Fri, 20 Sep 2024 15:22:05 +0200 bobcat (6.06.01) * Repaired the icmake --spch call in icmake/libraries, which didn't use the constructed headers in the ./tmp directory * One cosmetic change (mmapbuf/xsgetn.cc), suppressing a superfluous message to cerr. -- Frank B. Brokken Tue, 28 May 2024 10:37:50 +0200 bobcat (6.06.00) * Added the classes MmapBuf, ImmapStream, OmmapStream and IOmmapStream using mmap(2) for file I/O -- Frank B. Brokken Wed, 15 May 2024 14:32:21 +0200 bobcat (6.05.00) * Using SPCH en multi-threaded compilation using icmake >= 12.00.00 -- Frank B. Brokken Tue, 23 Apr 2024 17:31:19 +0200 bobcat (6.04.00) * The class Log offers faciities for non-hierarchical logging. * The class Milter by default ends a connection when its virtual 'close' member is called. Starting this version the close member is always called once a connection ends. -- Frank B. Brokken Fri, 01 Dec 2023 08:45:32 +0100 bobcat (6.03.02) * fixed a bug in Arg due to which optional arguments of long+short options were not recognized when the long option alternative was used. * changed 'typedef' specifications into 'using' declarations. * DateTime constructors defining TimeType parameters use DateTime::UTC by default. * Updated several man-pages. -- Frank B. Brokken Mon, 29 May 2023 11:21:41 +0200 bobcat (6.03.01) * Tony Mancill fixed left-over references to libbobcat5 in several files. -- Frank B. Brokken Thu, 02 Mar 2023 09:20:29 +0100 bobcat (6.03.00) * Added new class Proc. In time Proc may replace Process. * Added new classes IFdBufS and IFdStreamS using Selector objects to detect available information. * The member OFdBuf::sync() returns -1 when the characters in its internal buffer cannot be written to the device causing its using stream to clear its goodbit and to set its badbit and failbit flags. * The class OFdBuf has a new member 'warn(bool on)'. When sync returns -1 and on == true a warning is written to the standard error stream. -- Frank B. Brokken Sun, 05 Feb 2023 15:14:35 +0100 bobcat (6.02.02) * Accidentally the ArgConfig header file included ../arg/arg instead of causing compilation failures of files including . Fixed in this release. -- Frank B. Brokken Fri, 11 Nov 2022 20:44:02 +0100 bobcat (6.02.01) * The singleton classes Arg, ArgConfig, ReadLineHistory, and Signal now return their allocated memory when programs using them end. * Rewrote ReadLineHistory. * Repaired the linking option specifications in the ReadLine* man-pages. -- Frank B. Brokken Thu, 10 Nov 2022 21:09:55 +0100 bobcat (6.02.00) * Added new class 'ECDH' implementing Elliptic Curve based Diffie-Hellman key exchange. * Updated the table* and related man-pages -- Frank B. Brokken Mon, 10 Oct 2022 11:33:03 +0200 bobcat (6.01.00) * The class HMacBuf supports default and move construction and move assignment. * The HMacBuf(key, digest, bufsize) constructor does not define default arguments anymore. -- Frank B. Brokken Sat, 17 Sep 2022 12:06:24 +0200 bobcat (6.00.00) * BigInt, DigestBuf, HMacBuf, ISymCryptStream, and ISymCryptStreambuf are now up-to-date with openSSL >= 3.0.3. * Added new classes RandomMT, OSymCryptStream, OSymCryptStreamBuf (and IUO classes ISymCryptStream, OSymCryptStream, and SymCryptBase). * The classes EncryptBuf and DecryptBuf are now deactivated. Constructing objects of those classes throws exceptions, and these classes will be removed from Bobcat in a future release. Instead of EncryptBuf and DecryptBuf OSymCryptStreamBuf can be used. * The class Cryptbuf is deprecated and will be removed from Bobcat in a future release. See its man-page for alternatives. * HMacBuf now has a 2nd constructor offering sensible defaults. * The class RandBuf now uses RandomMT instead of random(3) and srandom(3). * Header files of classes that may throw FBB::Exception objects now include * Updated man-pages * 'icmconf' files used by Bobcat now specify -Werror. -- Frank B. Brokken Fri, 09 Sep 2022 14:04:14 +0200 bobcat (5.11.01) * LDC now also accepts 0-values (previously resulting in an exception). * Several man-pages were updated. * The BigInt, Diffie-Hellman, and HMacBuf classes specify #define OPENSSL_API_COMPAT 0x10100000L in their .ih files, and local definitions of various openSSL functions in their .ih files were removed. -- Frank B. Brokken Sun, 03 Jul 2022 16:32:58 +0200 bobcat (5.11.00) * Added members and constructors to BigInt for processing little-endian coded values; * Added class LDC (Large Digital Converter) to convert large digital values (as, e.g., handled by BigInt) to character representations using number systems from 2 through 36 or using number characters in a std::string using the string's length as number system. -- Frank B. Brokken Sat, 21 May 2022 17:37:31 +0200 bobcat (5.10.01) * The reverse(3bobcat) manpage was incomplete. Fixed in this release. -- Frank B. Brokken Sun, 17 Apr 2022 08:29:02 +0200 bobcat (5.10.00) * Added new class Reverse (and 'reverse' support functions) having members begin() and end(), returning reverse iterators for arrays, for classes offering begin() and end() members returning iterators, and for initializer_lists. * The const_iterators of ConfigFile, Iterator, MailHeaders, PtrIter, ReadlineHistory and TableSupport are not inheriting from std::iterator anymore as inheriting from std::iterator is deprecated. -- Frank B. Brokken Sat, 16 Apr 2022 13:10:00 +0200 bobcat (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-6.07.01/cidr/0000775000175000017500000000000014736742656013052 5ustar frankfrankbobcat-6.07.01/cidr/cidr2.cc0000664000175000017500000000010314673353433014345 0ustar frankfrank#include "cidr.ih" Cidr::Cidr(istream &fin) { setCidr(fin); } bobcat-6.07.01/cidr/cidr3.cc0000664000175000017500000000024714673353433014357 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-6.07.01/cidr/compare.cc0000664000175000017500000000110514673353433014773 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-6.07.01/cidr/match2.cc0000664000175000017500000000013114673353433014521 0ustar frankfrank#include "cidr.ih" bool Cidr::match(string const &line) { return matchLine(line); } bobcat-6.07.01/cidr/match1.cc0000664000175000017500000000054214673353433014526 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-6.07.01/cidr/parse.cc0000664000175000017500000000114314673353433014461 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-6.07.01/cidr/last.f0000664000175000017500000000011414673353433014147 0ustar frankfrankinline std::string Cidr::last() const { return binary2dotted(d_last); } bobcat-6.07.01/cidr/first.f0000664000175000017500000000012414673353433014334 0ustar frankfrankinline std::string Cidr::first() const { return binary2dotted(d_iter->first); } bobcat-6.07.01/cidr/mask.f0000664000175000017500000000014114673353433014137 0ustar frankfrankinline std::string Cidr::mask() const { return std::to_string(d_iter->second); // X2a } bobcat-6.07.01/cidr/dotted2binary.cc0000664000175000017500000000071114673353433016121 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-6.07.01/cidr/binary2dotted.cc0000664000175000017500000000042314673353433016121 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-6.07.01/cidr/pushcidr.cc0000664000175000017500000000024414673353433015171 0ustar frankfrank#include "cidr.ih" void Cidr::pushCidr(string const &cidrPattern) { MaskPair spec = parse(cidrPattern); if (spec.second) d_cidr.push_back(spec); } bobcat-6.07.01/cidr/icmconf0000664000175000017500000000007214673353433014401 0ustar frankfrank#define LIBRARY "cidr" #include "../icmconf" bobcat-6.07.01/cidr/setcidr2.cc0000664000175000017500000000061014673353433015064 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-6.07.01/cidr/cidr1.cc0000664000175000017500000000013614673353433014352 0ustar frankfrank#include "cidr.ih" Cidr::Cidr(std::string const &cidrPattern) { pushCidr(cidrPattern); } bobcat-6.07.01/cidr/cidr0000664000175000017500000000467414673353433013720 0ustar frankfrank#ifndef _INCLUDED_BOBCAT_CIDR_ #define _INCLUDED_BOBCAT_CIDR_ #include #include #include #include namespace FBB { class Pattern; class Cidr { using MaskPair = std::pair; // 1st address, mask value using VectorMaskP = std::vector; 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-6.07.01/cidr/operatorassign.cc0000664000175000017500000000016214673353433016407 0ustar frankfrank#include "cidr.ih" #include "../iuo/iuo" Cidr &Cidr::operator=(Cidr &&tmp) { swap(tmp); return *this; } bobcat-6.07.01/cidr/swap.cc0000664000175000017500000000012514673353433014320 0ustar frankfrank#include "cidr.ih" void Cidr::swap(Cidr &rhs) { fswap(*this, rhs, d_matched); } bobcat-6.07.01/cidr/matchline.cc0000664000175000017500000000150214673353433015312 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-6.07.01/cidr/setcidr1.cc0000664000175000017500000000017314673353433015067 0ustar frankfrank#include "cidr.ih" void Cidr::setCidr(std::string const &cidrPattern) { d_cidr.clear(); pushCidr(cidrPattern); } bobcat-6.07.01/cidr/cidr.ih0000664000175000017500000000040614736315237014304 0ustar frankfrank#include "cidr" #include #include #include #include #include "../stringline/stringline" #include "../pattern/pattern" #include "../fswap/fswap" #include "../ranger/ranger" using namespace std; using namespace FBB; bobcat-6.07.01/cidr/address.f0000664000175000017500000000011214673353433014627 0ustar frankfrankinline std::string const &Cidr::address() const { return d_matched; } bobcat-6.07.01/cidr/driver/0000775000175000017500000000000014737552575014345 5ustar frankfrankbobcat-6.07.01/cidr/driver/build0000775000175000017500000000112214673353433015355 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-6.07.01/cidr/driver/driver.cc0000664000175000017500000000433614673353433016144 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-6.07.01/cidr/driver/cidrspecs0000664000175000017500000000017714673353433016243 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-6.07.01/cidr/cidr.cc0000664000175000017500000000024114673353433014266 0ustar frankfrank#include "cidr.ih" string Cidr::cidr() const { ostringstream out; out << binary2dotted(d_iter->first) << '/' << d_iter->second; return out.str(); } bobcat-6.07.01/cininserter/0000775000175000017500000000000014736742656014456 5ustar frankfrankbobcat-6.07.01/cininserter/parentprocess.cc0000664000175000017500000000010014673353433017633 0ustar frankfrank#include "cininserter.ih" void CinInserter::parentProcess() {} bobcat-6.07.01/cininserter/execute1.cc0000664000175000017500000000034314673353433016477 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-6.07.01/cininserter/stop.cc0000664000175000017500000000023514673353433015741 0ustar frankfrank#include "cininserter.ih" int CinInserter::stop() { if (d_stopped) return ret(); flush(); eoi(); return setRet(waitForChild()); } bobcat-6.07.01/cininserter/cininserter.ih0000664000175000017500000000023114736315237017310 0ustar frankfrank#include "cininserter" #include #include #include #include using namespace std; using namespace FBB; bobcat-6.07.01/cininserter/cininserter2.cc0000664000175000017500000000023214673353433017360 0ustar frankfrank#include "cininserter.ih" CinInserter::CinInserter(StdMode mode, size_t bufSize) : ostream(this), d_bufSize(bufSize), d_modeFun(stdClose) {} bobcat-6.07.01/cininserter/childinpipe.cc0000664000175000017500000000041714673353433017246 0ustar frankfrank//#include "cininserter.ih" // ////namespace ////{ //// bool called = false; ////} // //Pipe &CinInserter::childInPipe() // const //{ //// deprecated__(called, "CinInserter::childInPipe()"); //// return d_inserter->d_pipe; // // return d_oChildInPipe; //} // bobcat-6.07.01/cininserter/icmconf0000664000175000017500000000010114673353433015776 0ustar frankfrank#define LIBRARY "cininserter" #include "../icmconf" bobcat-6.07.01/cininserter/close.cc0000664000175000017500000000043714673353433016065 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-6.07.01/cininserter/childredirections.cc0000664000175000017500000000016014673353433020447 0ustar frankfrank#include "cininserter.ih" void CinInserter::childRedirections() { d_oChildInPipe.readFrom(STDIN_FILENO); } bobcat-6.07.01/cininserter/parentredirections.cc0000664000175000017500000000027514673353433020664 0ustar frankfrank#include "cininserter.ih" void CinInserter::parentRedirections() { reset(d_oChildInPipe.writeOnly(), OFdBuf::CLOSE_FD, d_bufSize); // open(d_oChildInPipe.writeOnly(), d_bufSize); } bobcat-6.07.01/cininserter/destructor.cc0000664000175000017500000000010714673353433017150 0ustar frankfrank#include "cininserter.ih" CinInserter::~CinInserter() { stop(); } bobcat-6.07.01/cininserter/cininserter0000664000175000017500000000230014673353433016710 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-6.07.01/cininserter/execute2.cc0000664000175000017500000000031514673353433016477 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-6.07.01/cininserter/driver/0000775000175000017500000000000014737552575015751 5ustar frankfrankbobcat-6.07.01/cininserter/driver/build0000775000175000017500000000012314673353433016761 0ustar frankfrank#!/bin/bash g++ -pthread -Wall -odriver driver.cc -L../tmp -lcininserter -lbobcat bobcat-6.07.01/cininserter/driver/driver.cc0000664000175000017500000000133314736771432017545 0ustar frankfrank#include #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-6.07.01/cininserter/cininserter1.cc0000664000175000017500000000021314673353433017356 0ustar frankfrank#include "cininserter.ih" CinInserter::CinInserter(size_t bufSize) : ostream(this), d_bufSize(bufSize), d_modeFun(noClose) {} bobcat-6.07.01/CLASSES0000664000175000017500000000251114736321364013135 0ustar frankfrank// Classes compiled from icmake/special: xpointer, milter, ssl, readline a2x align arg argconfig base64bufbase binarysearch binops binopsbase cerrextractor cgi cidr cininserter clientsocket cmdfinder cmdfinderbase config configfile coutextractor csv4180 csvtabdef csvtabins csvtable datetime eoi eoibuf exception exec extractorbase fbb field fmt fork fswap gethostent glob gs hash hostent hostname ibase64buf ibase64stream ifdbuf ifdstream ifilterbuf indent inetaddress iobuf iostream iquotedprintablebuf iquotedprintablestream irandstream isharedstream iterator iuo level linearmap localclientsocket localserversocket localsocketbase log logbuf mailheaders mbuf mstream multibuf ofdbuf ofdstream ofilterbuf ofoldbuf ofoldstream ohexbuf omutexstream onekey osharedstream pattern pipe process processenums ptriter qpbufbase randbuf randommt ranger redirector repeat reverse selector semaphore sep serversocket sharedblock sharedbuf sharedcondition sharedmemory sharedmutex sharedpos sharedsegment sharedstream signal socketbase stat stdextractor string stringline syslogbuf syslogstream table tablebase tablebuf tablelines tablesupport tempstream tty typetrait user x2a ifdbufs ifdstreams proc npipe mmapbuf immapstream ommapstream iommapstream fsoptions filesystem clocktypes clockbase fileclock steadyclock highsysclock highresolutionclock systemclock bobcat-6.07.01/clientsocket/0000775000175000017500000000000014736742656014620 5ustar frankfrankbobcat-6.07.01/clientsocket/clientsocket0000664000175000017500000000067614673353433017232 0ustar frankfrank#ifndef INCLUDED_BOBCAT_CLIENTSOCKET_ #define INCLUDED_BOBCAT_CLIENTSOCKET_ #include #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-6.07.01/clientsocket/clientsocket.ih0000664000175000017500000000020514736315237017615 0ustar frankfrank#include "clientsocket" #include #include #include using namespace std; using namespace FBB; bobcat-6.07.01/clientsocket/clientsocket1.cc0000664000175000017500000000017214673353433017666 0ustar frankfrank#include "clientsocket.ih" ClientSocket::ClientSocket(string const &host, uint16_t port) : SocketBase(host, port) {} bobcat-6.07.01/clientsocket/connect.cc0000664000175000017500000000032214673353433016544 0ustar frankfrank#include "clientsocket.ih" int ClientSocket::connect() { if (::connect(socket(), sockaddrPtr(), size()) < 0) throw Exception{} << "ClientSocket::connect(): " << errnodescr; return socket(); } bobcat-6.07.01/clientsocket/driver/0000775000175000017500000000000014673353433016102 5ustar frankfrankbobcat-6.07.01/clientsocket/driver/build0000775000175000017500000000017114673353433017126 0ustar frankfrank#!/bin/bash tput clear GPP="g++ `cat ../../c++std`" CMD="$GPP -o client -Wall client.cc -lbobcat -s" echo $CMD $CMD bobcat-6.07.01/clientsocket/driver/client.cc0000664000175000017500000000352214673353433017671 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-6.07.01/clockbase/0000775000175000017500000000000014737164354014051 5ustar frankfrankbobcat-6.07.01/clockbase/clockbase0000664000175000017500000000354314737164221015720 0ustar frankfrank#ifndef INCLUDED_BOBCAT_CLOCKBASE_ #define INCLUDED_BOBCAT_CLOCKBASE_ #include #include namespace FBB { template struct ClockBase; template std::ostream &operator<<(std::ostream &out, ClockBase const &clock); template struct ClockBase: public ClockTypes { using Clock = ChronoClock; // std::chrono::system_clock; using TimePoint = Clock::time_point; friend std::ostream &operator<< <>(std::ostream &out, // .f ClockBase const &clock); private: TimePoint d_timePoint; public: ClockBase(TimePoint const &timePoint); // = now() ? template ClockBase(ClockBase const &clock); // .f template ClockBase &operator+=( std::chrono::duration const &amount); ClockBase &operator+=(int amount); // amount in seconds template ClockBase &operator-=( std::chrono::duration const &amount); ClockBase &operator-=(int amount); // amount in seconds Duration elapsed() const; // time_since_epoch // .f long int count() const; // .f TimePoint const &timePoint() const; // inserts the same as when // inserting the object itself template double toDouble() const; static TimePoint max(); static TimePoint min(); static TimePoint now(); }; #include "clockbase.f" } // FBB #endif bobcat-6.07.01/clockbase/clockbase.ih0000664000175000017500000000014714736315237016320 0ustar frankfrank#include "clockbase" //#include "../xerr/xerr.ih" // //using namespace std; //using namespace FBB; // bobcat-6.07.01/clockbase/clockbase.f0000664000175000017500000000745614737164354016162 0ustar frankfranktemplate inline ClockBase::ClockBase(TimePoint const &timePoint) : d_timePoint(timePoint) {} template template inline ClockBase::ClockBase(ClockBase const &clock) : d_timePoint(clock.timePoint()) {} template inline ClockBase::Duration ClockBase::elapsed() const { return d_timePoint.time_since_epoch(); } template inline long int ClockBase::count() const { return elapsed().count(); } template inline ChronoClock::time_point const &ClockBase::timePoint() const { return d_timePoint; } template inline std::ostream &operator<<(std::ostream &out, ClockBase const &clock) { return out << clock.d_timePoint; } template ClockBase &ClockBase::operator+=(int amount) { d_timePoint += std::chrono::seconds{ amount }; return *this; } template template ClockBase &ClockBase::operator+=( std::chrono::duration const &amount) { d_timePoint += amount; return *this; } template inline ClockBase operator+( ClockBase const &lhs, std::chrono::duration const &amount) { return ClockBase{ lhs } += amount; } template inline ClockBase operator+( std::chrono::duration const &amount, ClockBase const &rhs) { return ClockBase{ rhs } += amount; } template inline ClockBase operator+(ClockBase const &lhs, int amount) { return ClockBase{ lhs } += amount; } template inline ClockBase operator+(int amount, ClockBase const &rhs) { return ClockBase{ rhs } += amount; } template ClockBase &ClockBase::operator-=(int amount) { d_timePoint -= std::chrono::seconds{ amount }; return *this; } template template ClockBase &ClockBase::operator-=( std::chrono::duration const &amount) { d_timePoint -= amount; return *this; } template inline ClockBase operator-( ClockBase const &lhs, std::chrono::duration const &amount) { return ClockBase{ lhs } -= amount; } template inline ClockBase operator-(ClockBase const &lhs, int amount) { return ClockBase{ lhs } -= amount; } // static template inline ClockBase::TimePoint ClockBase::now() { return ChronoClock::now(); } // static template inline ClockBase::TimePoint ClockBase::min() { return TimePoint::min(); } // static template inline ClockBase::TimePoint ClockBase::max() { return TimePoint::max(); } template template inline double ClockBase::toDouble() const { return FBB::toDouble(elapsed()); } bobcat-6.07.01/clocktypes/0000775000175000017500000000000014737163600014274 5ustar frankfrankbobcat-6.07.01/clocktypes/clocktypes.f0000664000175000017500000000234414737163600016626 0ustar frankfranktemplate inline auto toClock(Src const &src) { return std::chrono::clock_cast( src.timePoint()); } template inline Dest toDuration(Src const &src) { return std::chrono::duration_cast(src); } template inline double toDouble(Src const &src) { return static_cast(src.count()) * Dest::period::den * Src::period::num / (Dest::period::num * Src::period::den); } // static inline ClockTypes::Period ClockTypes::period() { return Duration::period{}; } // static inline ClockTypes::NumType ClockTypes::den() { return Period::den; } // static inline ClockTypes::NumType ClockTypes::num() { return Period::num; } // static inline ClockTypes::Duration ClockTypes::zero() { return Duration::zero(); } // static template inline ClockTypes::Duration ClockTypes::elapsed(TimePoint const &tp) { return tp.time_since_epoch(); } // static template inline size_t ClockTypes::count(TimePoint const &tp) { return elapsed(tp).count(); } bobcat-6.07.01/clocktypes/clocktypes.ih0000664000175000017500000000002614736315237017000 0ustar frankfrank#include "clocktypes" bobcat-6.07.01/clocktypes/clocktypes0000664000175000017500000000350414737163467016414 0ustar frankfrank#ifndef INCLUDED_BOBCAT_CLOCKTYPES_ #define INCLUDED_BOBCAT_CLOCKTYPES_ #include // assignning a later value to an earlier value is OK // (minutes min = 1h -> min = 60 // // nanoseconds duration 1ns // microseconds duration 1us // milliseconds duration 1ms // seconds duration 1s // minutes duration> 1min // hours duration> 1h // // members: count() // static members: zero(), min(), max() // // Duration types: =, -, +(=) -(=) namespace FBB { using nanoseconds = std::chrono::nanoseconds; using microseconds = std::chrono::microseconds; using milliseconds = std::chrono::milliseconds; using seconds = std::chrono::seconds; using minutes = std::chrono::minutes; using hours = std::chrono::hours; template // less precise to more precise Dest toDuration(Src const &src); template auto toClock(Src const &src); template double toDouble(Src const &src); struct ClockTypes { using Duration = std::chrono::duration; using Period = Duration::period; using DenType = decltype(Period::den); using NumType = decltype(Period::num); static Period period(); // .f static DenType den(); // .f static NumType num(); // .f static Duration zero(); // .f template static Duration elapsed(TimePoint const &tp); template static size_t count(TimePoint const &tp); }; #include "clocktypes.f" } // FBB #endif bobcat-6.07.01/cmdfinder/0000775000175000017500000000000014673353433014053 5ustar frankfrankbobcat-6.07.01/cmdfinder/cmdfinder1.f0000664000175000017500000000026414673353433016240 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-6.07.01/cmdfinder/cmdfinder2.f0000664000175000017500000000025514673353433016241 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-6.07.01/cmdfinder/swap.f0000664000175000017500000000021014673353433015165 0ustar frankfranktemplate void CmdFinder::swap(CmdFinder &rhs) { CmdFinderBase::swap(rhs); fswap(&d_count, *this, rhs); } bobcat-6.07.01/cmdfinder/match.f0000664000175000017500000000017414673353433015320 0ustar frankfranktemplate inline bool CmdFinder::match(std::string const &key) const { return (this->*d_match)(key); } bobcat-6.07.01/cmdfinder/findcmd.f0000664000175000017500000000111314673353433015622 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-6.07.01/cmdfinder/cmdfinder0000664000175000017500000000333014673353433015730 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: using FunctionPtr = FP; // define template type // as a named type // elements of the array // of keys/f-ptrs using Entry = std::pair; 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-6.07.01/cmdfinder/count.f0000664000175000017500000000013214673353433015346 0ustar frankfranktemplate inline size_t CmdFinder::count() const { return d_count; } bobcat-6.07.01/cmdfinder/opfun.f0000664000175000017500000000031714673353433015352 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-6.07.01/cmdfinder/icmconf0000664000175000017500000000007714673353433015420 0ustar frankfrank#define LIBRARY "cmdfinder" #include "../icmconf" bobcat-6.07.01/cmdfinder/matchkey1.f0000664000175000017500000000022214673353433016104 0ustar frankfranktemplate CmdFinder::MatchKey::MatchKey(FunctionPtr *fp, CmdFinder *cmdFinder) : d_fp(fp), d_cmdFinder(cmdFinder) {} bobcat-6.07.01/cmdfinder/opis1.f0000664000175000017500000000017414673353433015257 0ustar frankfranktemplate inline CmdFinder &CmdFinder::operator=(CmdFinder &&tmp) { swap(tmp); return *this; } bobcat-6.07.01/cmdfinder/driver/0000775000175000017500000000000014737552575015357 5ustar frankfrankbobcat-6.07.01/cmdfinder/driver/build0000775000175000017500000000012514673353433016371 0ustar frankfrank#!/bin/sh # g++ driver.cc ../../cmdfinderbase/*.cc -lbobcat g++ driver.cc -lbobcat bobcat-6.07.01/cmdfinder/driver/driver.cc0000664000175000017500000000565514673353433017163 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-6.07.01/cmdfinderbase/0000775000175000017500000000000014736742656014717 5ustar frankfrankbobcat-6.07.01/cmdfinderbase/index2.f0000664000175000017500000000015614673353433016250 0ustar frankfrankinline size_t ConfigFile__::index(const_iterator const &iterator) { return d_index[iterator - begin()]; } bobcat-6.07.01/cmdfinderbase/findkeytail.f0000664000175000017500000000024314673353433017357 0ustar frankfrankinline std::string ConfigFile__::findKeyTail(std::string const &keyPattern, size_t count) { return searchFor("^\\s*" + keyPattern + "\\s+(.*)\\s*$", count); } bobcat-6.07.01/cmdfinderbase/index1.f0000664000175000017500000000012114673353433016237 0ustar frankfrankinline size_t ConfigFile__::index(size_t lineNr) { return d_index[lineNr]; } bobcat-6.07.01/cmdfinderbase/usefirstcmd.cc0000664000175000017500000000044214673353433017545 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-6.07.01/cmdfinderbase/opindex.f0000664000175000017500000000014114673353433016517 0ustar frankfrankinline std::string const &ConfigFile__::operator[](size_t idx) const { return d_line[idx]; } bobcat-6.07.01/cmdfinderbase/finder.f0000664000175000017500000000022414673353433016322 0ustar frankfrankinline bool ConfigFile__::finder(std::string const &haystack, std::string const &needle) { return haystack.find(needle) != std::string::npos; } bobcat-6.07.01/cmdfinderbase/endre.f0000664000175000017500000000017214673353433016152 0ustar frankfrankinline ConfigFile__::const_RE_iterator ConfigFile__::endRE() const { return RE_iterator(d_vsIter, d_vsIter.size()); } bobcat-6.07.01/cmdfinderbase/setsearchcasing.f0000664000175000017500000000016414673353433020224 0ustar frankfrankinline void ConfigFile__::setSearchCasing(SearchCasing type) { d_caseSensitive = type == SearchCaseSensitive; } bobcat-6.07.01/cmdfinderbase/casefinder.f0000664000175000017500000000030314673353433017154 0ustar frankfrankinline bool ConfigFile__::casefinder(std::string const &haystack, std::string const &needle) { return strcasestr(haystack.c_str(), needle.c_str()) != 0; } bobcat-6.07.01/cmdfinderbase/beyond.f0000664000175000017500000000012614673353433016334 0ustar frankfrankinline std::string const &FBB::CmdFinderBase::beyond() const { return d_beyond; } bobcat-6.07.01/cmdfinderbase/cmdfinderbase1.f0000664000175000017500000000011514673353433017721 0ustar frankfrankinline FBB::CmdFinderBase::CmdFinderBase(size_t mode) { setMode(mode); } bobcat-6.07.01/cmdfinderbase/begin.f0000664000175000017500000000013714673353433016142 0ustar frankfrankinline ConfigFile__::const_iterator ConfigFile__::begin() const { return d_line.begin(); } bobcat-6.07.01/cmdfinderbase/matchuniqueinsensitive.cc0000664000175000017500000000033014673353433022015 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-6.07.01/cmdfinderbase/setcommenthandling.f0000664000175000017500000000015014673353433020734 0ustar frankfrankinline void ConfigFile__::setCommentHandling(Comment type) { d_rmComment = type == RemoveComment; } bobcat-6.07.01/cmdfinderbase/opstar.f0000664000175000017500000000013214673353433016361 0ustar frankfrankinline std::string const &RE_iterator::operator*() const { return *d_vsIter[d_idx]; } bobcat-6.07.01/cmdfinderbase/opneg.f0000664000175000017500000000015314673353433016164 0ustar frankfrankinline int operator-(RE_iterator const &lhs, RE_iterator const &rhs) { return lhs.d_idx - rhs.d_idx; } bobcat-6.07.01/cmdfinderbase/cmd.f0000664000175000017500000000012014673353433015611 0ustar frankfrankinline std::string const &FBB::CmdFinderBase::cmd() const { return d_cmd; } bobcat-6.07.01/cmdfinderbase/end.f0000664000175000017500000000013314673353433015620 0ustar frankfrankinline ConfigFile__::const_iterator ConfigFile__::end() const { return d_line.end(); } bobcat-6.07.01/cmdfinderbase/findkey.f0000664000175000017500000000023414673353433016505 0ustar frankfrankinline std::string ConfigFile__::findKey(std::string const &keyPattern, size_t count) { return searchFor("^\\s*" + keyPattern + "\\s+(\\S+)", count); } bobcat-6.07.01/cmdfinderbase/setmode.cc0000664000175000017500000000145114673353433016656 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-6.07.01/cmdfinderbase/cmdfinderbase.ih0000664000175000017500000000030714736315237020016 0ustar frankfrank#include "cmdfinderbase" #include #include "../string/string" #include "matchexact.f" #include "matchunique.f" #include "matchinsensitive.f" using namespace std; using namespace FBB; bobcat-6.07.01/cmdfinderbase/icmconf0000664000175000017500000000010314673353433016241 0ustar frankfrank#define LIBRARY "cmdfinderbase" #include "../icmconf" bobcat-6.07.01/cmdfinderbase/matchexact.f0000664000175000017500000000017014673353433017174 0ustar frankfrankinline bool FBB::CmdFinderBase::matchExact(std::string const &key) const { return d_cmd == key && d_cmd.length(); } bobcat-6.07.01/cmdfinderbase/size.f0000664000175000017500000000010714673353433016025 0ustar frankfrankinline size_t ConfigFile__::size() const { return d_line.size(); } bobcat-6.07.01/cmdfinderbase/swap.cc0000664000175000017500000000021214673353433016162 0ustar frankfrank#include "cmdfinderbase.ih" void CmdFinderBase::swap(CmdFinderBase &rhs) { d_cmd.swap(rhs.d_cmd); d_beyond.swap(rhs.d_beyond); } bobcat-6.07.01/cmdfinderbase/oparrow.f0000664000175000017500000000013414673353433016544 0ustar frankfrankinline std::string const *RE_iterator::operator->() const { return &*d_vsIter[d_idx]; } bobcat-6.07.01/cmdfinderbase/matchinsensitive.f0000664000175000017500000000025214673353433020431 0ustar frankfrankinline bool FBB::CmdFinderBase::matchInsensitive(std::string const &key) const { return String::casecmp(d_cmd, key) == 0 && d_cmd.length(); } bobcat-6.07.01/cmdfinderbase/matchunique.f0000664000175000017500000000022114673353433017373 0ustar frankfrankinline bool FBB::CmdFinderBase::matchUnique(std::string const &key) const { return key.find(d_cmd) != std::string::npos && d_cmd.length(); } bobcat-6.07.01/cmdfinderbase/opneq.f0000664000175000017500000000015014673353433016173 0ustar frankfrankinline bool operator!=(RE_iterator const &lhs, RE_iterator const &rhs) { return not (lhs == rhs); } bobcat-6.07.01/cmdfinderbase/cmdfinderbase1.cc0000664000175000017500000000023714673353433020066 0ustar frankfrank//#include "cmdfinderbase.hh" // //CmdFinderBase::CmdFinderBase(CmdFinderBase &&tmp) //: // d_cmd(move(tmp.d_cmd)), // d_beyond(move(tmp.d_beyond)) //{} bobcat-6.07.01/cmdfinderbase/usecmd.cc0000664000175000017500000000017314673353433016476 0ustar frankfrank#include "cmdfinderbase.ih" void CmdFinderBase::useCmd(std::string const &cmd) { d_beyond.erase(); d_cmd = cmd; } bobcat-6.07.01/cmdfinderbase/cmdfinderbase0000664000175000017500000000406114673353433017420 0ustar frankfrank#ifndef INCLUDED_BOBCAT_CMDFINDERBASE_ #define INCLUDED_BOBCAT_CMDFINDERBASE_ #include #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-6.07.01/config/0000775000175000017500000000000014736742656013376 5ustar frankfrankbobcat-6.07.01/config/rmcommentandescapes.cc0000664000175000017500000000204614673353433017726 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)) < line.length()) 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-6.07.01/config/cfline1.f0000664000175000017500000000015214673353433015053 0ustar frankfrankinline CF_Line::CF_Line(uint16_t lineNr, std::string const &line) : d_nr(lineNr), d_line(line) {} bobcat-6.07.01/config/load2.f0000664000175000017500000000014714673353433014537 0ustar frankfrankinline void Config::load(std::istream &stream, uint16_t firstNr) { d_ptr->load(stream, firstNr); } bobcat-6.07.01/config/obs/0000775000175000017500000000000014673353433014150 5ustar frankfrankbobcat-6.07.01/config/obs/beginendid2.f0000664000175000017500000000045214673353433016472 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-6.07.01/config/cfpimpl2.cc0000664000175000017500000000026614673353433015414 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-6.07.01/config/opassign2.cc0000664000175000017500000000021214673353433015574 0ustar frankfrank#include "config.ih" Config &Config::operator=(Config const &rhs) { Config tmp(rhs); swap(d_ptr, tmp.d_ptr); return *this; } bobcat-6.07.01/config/find2.cc0000664000175000017500000000135614673353433014703 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-6.07.01/config/config3.f0000664000175000017500000000020014673353433015054 0ustar frankfrankinline Config::Config(std::istream &stream, Casing sType, Comment cType) : d_ptr(new CF_Pimpl(stream, 1, sType, cType)) {} bobcat-6.07.01/config/findre1.f0000664000175000017500000000050014673353433015057 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-6.07.01/config/clear2.cc0000664000175000017500000000051114673353433015041 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-6.07.01/config/opindex.f0000664000175000017500000000026314673353433015203 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-6.07.01/config/nextline.cc0000664000175000017500000000071414673353433015524 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-6.07.01/config/beginend.cc0000664000175000017500000000112114673353433015442 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-6.07.01/config/findkey1.f0000664000175000017500000000054014673353433015245 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-6.07.01/config/findre2.cc0000664000175000017500000000033014673353433015221 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-6.07.01/config/load4.cc0000664000175000017500000000041114673353433014673 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-6.07.01/config/config5.f0000664000175000017500000000016414673353433015067 0ustar frankfrankinline Config::Config(std::istream &&stream, Casing sType, Comment cType) : Config(stream, 1, sType, cType) {} bobcat-6.07.01/config/config2.f0000664000175000017500000000024614673353433015065 0ustar frankfrankinline Config::Config(std::string const &fname, Casing sType, Comment cType) : Config(FBB::Exception::factory(fname), sType, cType) {} bobcat-6.07.01/config/setcasing.f0000664000175000017500000000024414673353433015514 0ustar frankfrankinline void CF_Pimpl::setCasing(Casing type) { d_caseSensitive = type == UseCase; } inline void Config::setCasing(Casing type) { d_ptr->setCasing(type); } bobcat-6.07.01/config/framep0000664000175000017500000000006414673353433014562 0ustar frankfrank//#define XERR #include "config.ih" CF_Pimpl:: { } bobcat-6.07.01/config/findid2.cc0000664000175000017500000000162514673353433015217 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-6.07.01/config/findre3.cc0000664000175000017500000000076214673353433015233 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-6.07.01/config/trimleft.cc0000664000175000017500000000037614673353433015530 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-6.07.01/config/config4.f0000664000175000017500000000025414673353433015066 0ustar frankfrankinline Config::Config(std::istream &stream, uint16_t lineNr, Casing sType, Comment cType) : d_ptr(new CF_Pimpl(stream, lineNr, sType, cType)) {} bobcat-6.07.01/config/begin.f0000664000175000017500000000025314673353433014620 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-6.07.01/config/findid1.f0000664000175000017500000000047514673353433015060 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-6.07.01/config/config0000664000175000017500000001774214673353433014570 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, }; using LineVect = std::vector; using const_iterator = std::vector::const_iterator; using CIVect = std::vector; using CIVectIteratorPair = std::pair; }; 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-6.07.01/config/tailpos.cc0000664000175000017500000000040214673353433015343 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-6.07.01/config/value.cc0000664000175000017500000000032614673353433015011 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-6.07.01/config/linenr.f0000664000175000017500000000007514673353433015025 0ustar frankfrankinline uint16_t CF_Line::lineNr() const { return d_nr; } bobcat-6.07.01/config/end.f0000664000175000017500000000024314673353433014301 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-6.07.01/config/icmconf0000664000175000017500000000007414673353433014727 0ustar frankfrank#define LIBRARY "config" #include "../icmconf" bobcat-6.07.01/config/key.cc0000664000175000017500000000032114673353433014460 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-6.07.01/config/clear1.f0000664000175000017500000000006414673353433014703 0ustar frankfrankinline void Config::clear() { d_ptr->clear(); } bobcat-6.07.01/config/size.f0000664000175000017500000000020514673353433014503 0ustar frankfrankinline size_t CF_Pimpl::size() const { return d_line.size(); } inline size_t Config::size() const { return d_ptr->size(); } bobcat-6.07.01/config/load3.f0000664000175000017500000000014114673353433014532 0ustar frankfrankinline void Config::load(std::istream &&stream, uint16_t firstNr) { load(stream, firstNr); } bobcat-6.07.01/config/config.ih0000664000175000017500000000012514736315237015152 0ustar frankfrank#include "config" #include using namespace std; using namespace FBB; bobcat-6.07.01/config/config8.f0000664000175000017500000000012214673353433015064 0ustar frankfrankinline Config::Config(Config const &rhs) : d_ptr(new CF_Pimpl(*rhs.d_ptr)) {} bobcat-6.07.01/config/findkey2.cc0000664000175000017500000000036414673353433015412 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-6.07.01/config/setcomment.f0000664000175000017500000000024714673353433015715 0ustar frankfrankinline void CF_Pimpl::setComment(Comment type) { d_rmComment = type == NoComment; } inline void Config::setComment(Comment type) { d_ptr->setComment(type); } bobcat-6.07.01/config/cflineopinsert.f0000664000175000017500000000015114673353433016555 0ustar frankfrankinline std::ostream &operator<<(std::ostream &out, CF_Line const &cfl) { return out << cfl.line(); } bobcat-6.07.01/config/destructor.cc0000664000175000017500000000007614673353433016075 0ustar frankfrank#include "config.ih" Config::~Config() { delete d_ptr; } bobcat-6.07.01/config/load1.f0000664000175000017500000000016314673353433014534 0ustar frankfrankinline void Config::load(std::string const &fname) { load(FBB::Exception::factory(fname), 1); } bobcat-6.07.01/config/opassign1.cc0000664000175000017500000000016014673353433015575 0ustar frankfrank#include "config.ih" Config &Config::operator=(Config &&tmp) { swap(d_ptr, tmp.d_ptr); return *this; } bobcat-6.07.01/config/caseinsensitive.f0000664000175000017500000000030014673353433016721 0ustar frankfrank//static inline bool CF_Pimpl::caseInsensitive(std::string const &lhs, std::string const &rhs) { return caseSensitive(String::lc(lhs), rhs); } bobcat-6.07.01/config/trimright.cc0000664000175000017500000000034114673353433015703 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-6.07.01/config/beginendre.f0000664000175000017500000000045214673353433015637 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-6.07.01/config/beginendid.f0000664000175000017500000000045214673353433015625 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-6.07.01/config/config1.f0000664000175000017500000000013614673353433015062 0ustar frankfrankinline Config::Config(Casing sType, Comment cType) : d_ptr(new CF_Pimpl(sType, cType)) {} bobcat-6.07.01/config/config6.f0000664000175000017500000000024014673353433015063 0ustar frankfrankinline Config::Config(std::istream &&stream, uint16_t lineNr, Casing sType, Comment cType) : Config(stream, lineNr, sType, cType) {} bobcat-6.07.01/config/idchar.f0000664000175000017500000000011614673353433014764 0ustar frankfrankinline bool CF_Pimpl::idChar(int ch) { return isalnum(ch) or ch == '_'; } bobcat-6.07.01/config/find1.f0000664000175000017500000000046114673353433014536 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-6.07.01/config/next.f0000664000175000017500000000017514673353433014515 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-6.07.01/config/config7.f0000664000175000017500000000013214673353433015064 0ustar frankfrankinline Config::Config(Config &&tmp) : d_ptr( new CF_Pimpl(std::move(*tmp.d_ptr) )) {} bobcat-6.07.01/config/casesensitive.f0000664000175000017500000000031314673353433016376 0ustar frankfrank//static inline bool CF_Pimpl::caseSensitive(std::string const &haystack, std::string const &needle) { return haystack.find(needle) != std::string::npos; } bobcat-6.07.01/config/cfpimpl1.cc0000664000175000017500000000020614673353433015405 0ustar frankfrank#include "config.ih" CF_Pimpl::CF_Pimpl(Casing sType, Comment cType) : d_rmComment(cType == NoComment) { setCasing(sType); } bobcat-6.07.01/config/tail.cc0000664000175000017500000000040414673353433014623 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-6.07.01/config/driver/0000775000175000017500000000000014737552575014671 5ustar frankfrankbobcat-6.07.01/config/driver/build0000775000175000017500000000131214673353433015702 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-6.07.01/config/driver/driver.cc0000664000175000017500000000763214673353433016472 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-6.07.01/config/driver/config0000664000175000017500000000077114673353433016055 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-6.07.01/config/driver/driver.rc0000664000175000017500000000033414673353433016501 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-6.07.01/config/line.f0000664000175000017500000000010714673353433014461 0ustar frankfrankinline std::string const &CF_Line::line() const { return d_line; } bobcat-6.07.01/configfile/0000775000175000017500000000000014736742656014236 5ustar frankfrankbobcat-6.07.01/configfile/rmcommentandescapes.cc0000664000175000017500000000205514673353433020566 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)) < line.length()) 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-6.07.01/configfile/index2.f0000664000175000017500000000016214673353433015564 0ustar frankfrankinline size_t FBB::ConfigFile_::index(const_iterator const &iterator) { return d_index[iterator - begin()]; } bobcat-6.07.01/configfile/find.cc0000664000175000017500000000074614673353433015463 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-6.07.01/configfile/build0000775000175000017500000003436214673353433015262 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-6.07.01/configfile/findkeytail.f0000664000175000017500000000030414673353433016674 0ustar frankfrankinline std::string FBB::ConfigFile_::findKeyTail( std::string const &keyPattern, size_t count) { return searchFor("^\\s*" + keyPattern + "\\s+(.*)\\s*$", count); } bobcat-6.07.01/configfile/index2.cc0000664000175000017500000000017214673353433015725 0ustar frankfrank#include "configfile.ih" size_t ConfigFile::index(const_iterator const &iterator) { return d_ptr->index(iterator); } bobcat-6.07.01/configfile/ignoreindex.cc0000664000175000017500000000007514673353433017051 0ustar frankfrank#include "configfile.ih" void ConfigFile_::ignoreIndex() {} bobcat-6.07.01/configfile/index1.f0000664000175000017500000000012514673353433015562 0ustar frankfrankinline size_t FBB::ConfigFile_::index(size_t lineNr) { return d_index[lineNr]; } bobcat-6.07.01/configfile/setcommenthandling.cc0000664000175000017500000000016514673353433020421 0ustar frankfrank#include "configfile.ih" void ConfigFile::setCommentHandling(Comment type) { d_ptr->setCommentHandling(type); } bobcat-6.07.01/configfile/size.cc0000664000175000017500000000013014673353433015500 0ustar frankfrank#include "configfile.ih" size_t ConfigFile::size() const { return d_ptr->size(); } bobcat-6.07.01/configfile/beginendre2.cc0000664000175000017500000000022514673353433016717 0ustar frankfrank#include "configfile.ih" ConfigFile::RE_iteratorPair ConfigFile::beginEndRE() const { return RE_iteratorPair(d_ptr->endRE(), d_ptr->endRE()); } bobcat-6.07.01/configfile/opindex.f0000664000175000017500000000014514673353433016042 0ustar frankfrankinline std::string const &FBB::ConfigFile_::operator[](size_t idx) const { return d_line[idx]; } bobcat-6.07.01/configfile/nextline.cc0000664000175000017500000000072214673353433016363 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-6.07.01/configfile/configfile1.cc0000664000175000017500000000101314673353433016715 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-6.07.01/configfile/configfile0000664000175000017500000001010014673353433016245 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 #include namespace FBB { struct RE_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); using iterator_category = std::input_iterator_tag; using difference_type = std::ptrdiff_t; using value_type = std::string const; using pointer = value_type *; using reference = value_type &; private: // contains iterators to lines matching REs using VsIterator = std::vector::const_iterator; using VsIterVector = std::vector; 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_ { using const_RE_iterator = RE_iterator; using const_iterator = std::vector::const_iterator; using RE_iteratorPair = std::pair; 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-6.07.01/configfile/finder.f0000664000175000017500000000027614673353433015650 0ustar frankfrankinline bool FBB::ConfigFile_::finder(std::string const &haystack, std::string const &needle) { return haystack.find(needle) != std::string::npos; } bobcat-6.07.01/configfile/endre.f0000664000175000017500000000020214673353433015463 0ustar frankfrankinline FBB::ConfigFile_::const_RE_iterator FBB::ConfigFile_::endRE() const { return RE_iterator(d_vsIter, d_vsIter.size()); } bobcat-6.07.01/configfile/setsearchcasing.f0000664000175000017500000000017014673353433017540 0ustar frankfrankinline void FBB::ConfigFile_::setSearchCasing(SearchCasing type) { d_caseSensitive = type == SearchCaseSensitive; } bobcat-6.07.01/configfile/operatorindex.cc0000664000175000017500000000016414673353433017420 0ustar frankfrank#include "configfile.ih" std::string const &ConfigFile::operator[](size_t idx) const { return (*d_ptr)[idx]; } bobcat-6.07.01/configfile/README0000664000175000017500000000300114673353433015077 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-6.07.01/configfile/open.cc0000664000175000017500000000142714673353433015501 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-6.07.01/configfile/opsub.f0000664000175000017500000000015314673353433015523 0ustar frankfrankinline int operator-(RE_iterator const &lhs, RE_iterator const &rhs) { return lhs.d_idx - rhs.d_idx; } bobcat-6.07.01/configfile/operatorassign2.cc0000664000175000017500000000023614673353433017657 0ustar frankfrank#include "configfile.ih" ConfigFile &ConfigFile::operator=(ConfigFile const &rhs) { ConfigFile tmp(rhs); swap(d_ptr, tmp.d_ptr); return *this; } bobcat-6.07.01/configfile/casefinder.f0000664000175000017500000000031414673353433016475 0ustar frankfrankinline bool FBB::ConfigFile_::casefinder(std::string const &haystack, std::string const &needle) { return strcasestr(haystack.c_str(), needle.c_str()) != 0; } bobcat-6.07.01/configfile/end.cc0000664000175000017500000000015214673353433015300 0ustar frankfrank#include "configfile.ih" ConfigFile::const_iterator ConfigFile::end() const { return d_ptr->end(); } bobcat-6.07.01/configfile/trimleft.cc0000664000175000017500000000040514673353433016361 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-6.07.01/configfile/configfile.ih0000664000175000017500000000765114736315237016665 0ustar frankfrank#include "configfile" #include #include #include #include "../pattern/pattern" #include "../iuo/iuo" // 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 using VsIterator = std::vector::const_iterator; using VsIterVector = std::vector; 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" using namespace std; using namespace FBB; bobcat-6.07.01/configfile/begin.f0000664000175000017500000000014714673353433015462 0ustar frankfrankinline FBB::ConfigFile_::const_iterator FBB::ConfigFile_::begin() const { return d_line.begin(); } bobcat-6.07.01/configfile/reoperatorinc.cc0000664000175000017500000000014414673353433017407 0ustar frankfrank#include "configfile.ih" RE_iterator &RE_iterator::operator++() { ++d_idx; return *this; } bobcat-6.07.01/configfile/setcommenthandling.f0000664000175000017500000000015414673353433020257 0ustar frankfrankinline void FBB::ConfigFile_::setCommentHandling(Comment type) { d_rmComment = type == RemoveComment; } bobcat-6.07.01/configfile/configfile4.cc0000664000175000017500000000016414673353433016726 0ustar frankfrank#include "configfile.ih" ConfigFile::ConfigFile(ConfigFile const &rhs) : d_ptr(new ConfigFile_(*rhs.d_ptr)) {} bobcat-6.07.01/configfile/opstar.f0000664000175000017500000000013214673353433015700 0ustar frankfrankinline std::string const &RE_iterator::operator*() const { return *d_vsIter[d_idx]; } bobcat-6.07.01/configfile/reiterator1.cc0000664000175000017500000000020514673353433016772 0ustar frankfrank#include "configfile.ih" RE_iterator::RE_iterator(VsIterVector const &vsIter, size_t idx) : d_vsIter(vsIter), d_idx(idx) {} bobcat-6.07.01/configfile/end.f0000664000175000017500000000014314673353433015140 0ustar frankfrankinline FBB::ConfigFile_::const_iterator FBB::ConfigFile_::end() const { return d_line.end(); } bobcat-6.07.01/configfile/setsearchcasing.cc0000664000175000017500000000016414673353433017703 0ustar frankfrank#include "configfile.ih" void ConfigFile::setSearchCasing(SearchCasing type) { d_ptr->setSearchCasing(type); } bobcat-6.07.01/configfile/configfile2.cc0000664000175000017500000000060514673353433016724 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-6.07.01/configfile/beginre.cc0000664000175000017500000000026714673353433016154 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-6.07.01/configfile/findkey.f0000664000175000017500000000031114673353433016020 0ustar frankfrankinline std::string FBB::ConfigFile_::findKey(std::string const &keyPattern, size_t count) { return searchFor("^\\s*" + keyPattern + "\\s+(\\S+)", count); } bobcat-6.07.01/configfile/begin.cc0000664000175000017500000000015614673353433015622 0ustar frankfrank#include "configfile.ih" ConfigFile::const_iterator ConfigFile::begin() const { return d_ptr->begin(); } bobcat-6.07.01/configfile/icmconf0000664000175000017500000000010014673353433015555 0ustar frankfrank#define LIBRARY "configfile" #include "../icmconf" bobcat-6.07.01/configfile/size.f0000664000175000017500000000011314673353433015341 0ustar frankfrankinline size_t FBB::ConfigFile_::size() const { return d_line.size(); } bobcat-6.07.01/configfile/findkeytail.cc0000664000175000017500000000050414673353433017036 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-6.07.01/configfile/destructor.cc0000664000175000017500000000011214673353433016724 0ustar frankfrank#include "configfile.ih" ConfigFile::~ConfigFile() { delete d_ptr; } bobcat-6.07.01/configfile/operatorassign.cc0000664000175000017500000000020314673353433017567 0ustar frankfrank#include "configfile.ih" ConfigFile &ConfigFile::operator=(ConfigFile &&tmp) { *d_ptr = move(*tmp.d_ptr); return *this; } bobcat-6.07.01/configfile/index1.cc0000664000175000017500000000014714673353433015726 0ustar frankfrank#include "configfile.ih" size_t ConfigFile::index(size_t lineNr) { return d_ptr->index(lineNr); } bobcat-6.07.01/configfile/oparrow.f0000664000175000017500000000013414673353433016063 0ustar frankfrankinline std::string const *RE_iterator::operator->() const { return &*d_vsIter[d_idx]; } bobcat-6.07.01/configfile/findkey.cc0000664000175000017500000000045314673353433016167 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-6.07.01/configfile/storeindex.cc0000664000175000017500000000014014673353433016713 0ustar frankfrank#include "configfile.ih" void ConfigFile_::storeIndex() { d_index.push_back(d_rawIndex); } bobcat-6.07.01/configfile/opneq.f0000664000175000017500000000015014673353433015512 0ustar frankfrankinline bool operator!=(RE_iterator const &lhs, RE_iterator const &rhs) { return not (lhs == rhs); } bobcat-6.07.01/configfile/trimright.cc0000664000175000017500000000035014673353433016543 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-6.07.01/configfile/beginendre.cc0000664000175000017500000000043414673353433016637 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-6.07.01/configfile/resetvsiter.cc0000664000175000017500000000047514673353433017121 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-6.07.01/configfile/searchfor.cc0000664000175000017500000000113014673353433016503 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-6.07.01/configfile/findre.cc0000664000175000017500000000070114673353433016001 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-6.07.01/configfile/configfile3.cc0000664000175000017500000000016714673353433016730 0ustar frankfrank#include "configfile.ih" ConfigFile::ConfigFile(ConfigFile &&tmp) : d_ptr( new ConfigFile_(move(*tmp.d_ptr) )) {} bobcat-6.07.01/configfile/driver/0000775000175000017500000000000014737552575015531 5ustar frankfrankbobcat-6.07.01/configfile/driver/build0000775000175000017500000000137614673353433016554 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-6.07.01/configfile/driver/driver.cc0000664000175000017500000000427614673353433017333 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-6.07.01/configfile/driver/config0000664000175000017500000000073214673353433016712 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-6.07.01/configfile/driver/driver.rc0000664000175000017500000000033414673353433017341 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-6.07.01/configfile/operatoreqre.cc0000664000175000017500000000026514673353433017247 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-6.07.01/contrib/0000775000175000017500000000000014673353433013560 5ustar frankfrankbobcat-6.07.01/contrib/realpath.c0000664000175000017500000000161414673353433015526 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-6.07.01/contrib/c-conf0000775000175000017500000002767614673353433014675 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-6.07.01/coutextractor/0000775000175000017500000000000014736742656015037 5ustar frankfrankbobcat-6.07.01/coutextractor/coutextractor2.cc0000664000175000017500000000022314673353433020322 0ustar frankfrank#include "coutextractor.ih" CoutExtractor::CoutExtractor(StdMode mode, size_t bufSize) : IUO::ExtractorBase(bufSize), d_modeFun(close) {} bobcat-6.07.01/coutextractor/coutextractor0000664000175000017500000000066514673353433017666 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-6.07.01/coutextractor/icmconf0000664000175000017500000000010314673353433016361 0ustar frankfrank#define LIBRARY "coutextractor" #include "../icmconf" bobcat-6.07.01/coutextractor/close.cc0000664000175000017500000000043614673353433016445 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-6.07.01/coutextractor/childredirections.cc0000664000175000017500000000027414673353433021036 0ustar frankfrank#include "coutextractor.ih" void CoutExtractor::childRedirections() { (*d_modeFun)(); // optionally close STDIN and STDERR childOutPipe().writtenBy(STDOUT_FILENO); } bobcat-6.07.01/coutextractor/coutextractor.ih0000664000175000017500000000015614736315237020260 0ustar frankfrank#include "coutextractor" #include #include using namespace std; using namespace FBB; bobcat-6.07.01/coutextractor/coutextractor1.cc0000664000175000017500000000027314673353433020326 0ustar frankfrank#include "coutextractor.ih" CoutExtractor::CoutExtractor(size_t bufSize) : IUO::ExtractorBase(bufSize), d_modeFun(noClose) // Exec: no actions: don't close pipes {} bobcat-6.07.01/coutextractor/driver/0000775000175000017500000000000014737552575016332 5ustar frankfrankbobcat-6.07.01/coutextractor/driver/build0000775000175000017500000000031014673353433017340 0ustar frankfrank#!/bin/bash g++ -Wall -odriver driver.cc -lbobcat exit 0 g++ -Wall -odriver driver.cc -L../../extractorbase/tmp -lextractorbase \ -L../tmp -Lcoutextractor -lbobcat bobcat-6.07.01/coutextractor/driver/driver.cc0000664000175000017500000000066014673353433020125 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-6.07.01/csv4180/0000775000175000017500000000000014736742656013241 5ustar frankfrankbobcat-6.07.01/csv4180/tocr.cc0000664000175000017500000000020514673353433014503 0ustar frankfrank#include "csv4180.ih" bool CSV4180::toCr() { //cerr << __FILE__ "\n"; ++d_begin; d_state = CRSTATE; return true; } bobcat-6.07.01/csv4180/read1.cc0000664000175000017500000000033214673353433014531 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-6.07.01/csv4180/adddq1.cc0000664000175000017500000000021714673353433014675 0ustar frankfrank#include "csv4180.ih" bool CSV4180::addDq1() { //cerr << __FILE__ "\n"; d_field += *d_begin++; d_state = DQ1; return true; } bobcat-6.07.01/csv4180/data.cc0000664000175000017500000000134314673353433014451 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-6.07.01/csv4180/header.f0000664000175000017500000000012214673353433014622 0ustar frankfrankinline CSV4180::StrVector const &CSV4180::header() const { return d_header; } bobcat-6.07.01/csv4180/release.f0000664000175000017500000000012014673353433015010 0ustar frankfrankinline CSV4180::DataVector CSV4180::release() { return std::move(d_data); } bobcat-6.07.01/csv4180/nextline.cc0000664000175000017500000000032414673353433015364 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-6.07.01/csv4180/read.cc0000664000175000017500000000107214673353433014452 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-6.07.01/csv4180/csv41800000664000175000017500000000741614673353433014273 0ustar frankfrank#ifndef INCLUDED_BOBCAT_CSV4180_ #define INCLUDED_BOBCAT_CSV4180_ // See RFC 4180: Common Format and MIME Type for CSV Files #include #include #include #include namespace FBB { class CSV4180 { using StrVector = std::vector; using DataVector = std::vector; 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-6.07.01/csv4180/field.cc0000664000175000017500000000060214673353433014620 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-6.07.01/csv4180/csv41801.cc0000664000175000017500000000024514673353433014731 0ustar frankfrank#include "csv4180.ih" CSV4180::CSV4180(size_t nFields, bool header, char fieldSep) : d_fieldSep(fieldSep), d_nRequired(nFields), d_setHeader(header) {} bobcat-6.07.01/csv4180/verifytypes.cc0000664000175000017500000000225314673353433016132 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-6.07.01/csv4180/README0000664000175000017500000000550314673353433014113 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-6.07.01/csv4180/setspecs.cc0000664000175000017500000000135714673353433015376 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-6.07.01/csv4180/csv41802.cc0000664000175000017500000000036014673353433014730 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-6.07.01/csv4180/csv4180.ih0000664000175000017500000000021214736315237014655 0ustar frankfrank#include "csv4180" #include #include #include "../exception/exception" using namespace std; using namespace FBB; bobcat-6.07.01/csv4180/end.cc0000664000175000017500000000124214673353433014304 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-6.07.01/csv4180/dropfields.cc0000664000175000017500000000171414673353433015675 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-6.07.01/csv4180/peek.cc0000664000175000017500000000043014673353433014460 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-6.07.01/csv4180/nop.cc0000664000175000017500000000010014673353433014322 0ustar frankfrank#include "csv4180.ih" bool CSV4180::nop() { return true; } bobcat-6.07.01/csv4180/clear.cc0000664000175000017500000000022714673353433014626 0ustar frankfrank#include "csv4180.ih" void CSV4180::clear(size_t nFields) { d_nRequired = nFields; d_data.clear(); d_header.clear(); d_str.clear(); } bobcat-6.07.01/csv4180/addch.cc0000664000175000017500000000022414673353433014600 0ustar frankfrank#include "csv4180.ih" bool CSV4180::addCh() { //cerr << __FILE__ "\n"; d_field += *d_begin++; d_state = CHARSTATE; return true; } bobcat-6.07.01/csv4180/icmconf0000664000175000017500000000007514673353433014573 0ustar frankfrank#define LIBRARY "csv4180" #include "../icmconf" bobcat-6.07.01/csv4180/data.f0000664000175000017500000000011714673353433014307 0ustar frankfrankinline CSV4180::DataVector const &CSV4180::data() const { return d_data; } bobcat-6.07.01/csv4180/opextract.f0000664000175000017500000000013614673353433015410 0ustar frankfrankinline std::istream &operator>>(std::istream &in, CSV4180 &csv) { return csv.read1(in); } bobcat-6.07.01/csv4180/req.cc0000664000175000017500000000046614673353433014334 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-6.07.01/csv4180/err.cc0000664000175000017500000000020114673353433014320 0ustar frankfrank#include "csv4180.ih" bool CSV4180::err() { //cerr << __FILE__ "\n"; d_in->setstate(ios::failbit); return false; } bobcat-6.07.01/csv4180/nvalues.f0000664000175000017500000000010314673353433015046 0ustar frankfrankinline size_t CSV4180::nValues() const { return d_nRequired; } bobcat-6.07.01/csv4180/todq1.cc0000664000175000017500000000020214673353433014561 0ustar frankfrank#include "csv4180.ih" bool CSV4180::toDq1() { //cerr << __FILE__ "\n"; ++d_begin; d_state = DQ1; return true; } bobcat-6.07.01/csv4180/lastline.f0000664000175000017500000000011214673353433015204 0ustar frankfrankinline std::string const &CSV4180::lastLine() const { return d_str; } bobcat-6.07.01/csv4180/todq2.cc0000664000175000017500000000020214673353433014562 0ustar frankfrank#include "csv4180.ih" bool CSV4180::toDq2() { //cerr << __FILE__ "\n"; ++d_begin; d_state = DQ2; return true; } bobcat-6.07.01/csv4180/driver/0000775000175000017500000000000014744164541014522 5ustar frankfrankbobcat-6.07.01/csv4180/driver/build0000775000175000017500000000162214673353433015551 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-6.07.01/csv4180/driver/driver.cc0000664000175000017500000000210514673353433016323 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-6.07.01/csv4180/driver/input0000664000175000017500000000003414744163013015572 0ustar frankfrank"a",""" b", c d,e,f g,h,i bobcat-6.07.01/csv4180/driver/bobcat0000777000175000017500000000000014673353433016031 2..ustar frankfrankbobcat-6.07.01/csv4180/driver/semicols0000664000175000017500000000002214673353433016256 0ustar frankfranka;b;c d;e;f g;h;i bobcat-6.07.01/csvtabdef/0000775000175000017500000000000014736742656014072 5ustar frankfrankbobcat-6.07.01/csvtabdef/csvtabdef.ih0000664000175000017500000000016014736315237016341 0ustar frankfrank#include "csvtabdef" #include "../xerr/xerr.ih" #include using namespace std; using namespace FBB; bobcat-6.07.01/csvtabdef/csvtabdef1.cc0000664000175000017500000000021714673353433016412 0ustar frankfrank//#define XERR #include "csvtabdef.ih" CSVTabDef::CSVTabDef(std::vector &format, unsigned idx) : d_idx(idx), d_format(format) {} bobcat-6.07.01/csvtabdef/split.cc0000664000175000017500000000033614673353433015525 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-6.07.01/csvtabdef/opinsert2.f0000664000175000017500000000026714673353433016162 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-6.07.01/csvtabdef/insert2.cc0000664000175000017500000000134214673353433015756 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-6.07.01/csvtabdef/icmconf0000664000175000017500000000010014673353433015411 0ustar frankfrank#define LIBRARY "csvtabdef" #include "../icmconf.lib" bobcat-6.07.01/csvtabdef/insert1.f0000664000175000017500000000024414673353433015615 0ustar frankfranktemplate CSVTabDef &CSVTabDef::insert(Type const &value) { std::ostringstream str; str << value; add(str.str()); return *this; } bobcat-6.07.01/csvtabdef/add2.cc0000664000175000017500000000073514673353433015207 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-6.07.01/csvtabdef/destructor.cc0000664000175000017500000000012314673353433016562 0ustar frankfrank//#define XERR #include "csvtabdef.ih" CSVTabDef::~CSVTabDef() { d_idx = 0; } bobcat-6.07.01/csvtabdef/opinsert1.f0000664000175000017500000000036314673353433016156 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-6.07.01/csvtabdef/csvtabdef0000664000175000017500000000274314673353433015753 0ustar frankfrank#ifndef INCLUDED_BOBCAT_CSVTABDEF_ #define INCLUDED_BOBCAT_CSVTABDEF_ #include #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-6.07.01/csvtabdef/add1.f0000664000175000017500000000014014673353433015034 0ustar frankfrankinline void CSVTabDef::add(std::string const &field) { add(String::trim(field).length()); } bobcat-6.07.01/csvtabins/0000775000175000017500000000000014736742656014125 5ustar frankfrankbobcat-6.07.01/csvtabins/opinsert5.f0000664000175000017500000000026414673353433016215 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-6.07.01/csvtabins/csvtabins0000664000175000017500000000753614673353433016046 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-6.07.01/csvtabins/sep.f0000664000175000017500000000013014673353433015044 0ustar frankfrankinline CSVTabIns &CSVTabIns::sep(Sep const &sep) { d_sep = sep; return *this; } bobcat-6.07.01/csvtabins/opfun.cc0000664000175000017500000000034214673353433015551 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-6.07.01/csvtabins/insert6.cc0000664000175000017500000000110514673353433016012 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-6.07.01/csvtabins/hline.cc0000664000175000017500000000152614673353433015526 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-6.07.01/csvtabins/opinsert3.f0000664000175000017500000000027714673353433016217 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-6.07.01/csvtabins/insertformatted.f0000664000175000017500000000206014673353433017473 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-6.07.01/csvtabins/README0000664000175000017500000000365314673353433015003 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-6.07.01/csvtabins/width1.cc0000664000175000017500000000070414673353433015624 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-6.07.01/csvtabins/opinsert2.f0000664000175000017500000000026714673353433016215 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-6.07.01/csvtabins/insert2.cc0000664000175000017500000000262114673353433016012 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-6.07.01/csvtabins/opinsert6.f0000664000175000017500000000044314673353433016215 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-6.07.01/csvtabins/centered.f0000664000175000017500000000173214673353433016057 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-6.07.01/csvtabins/icmconf0000664000175000017500000000010014673353433015444 0ustar frankfrank#define LIBRARY "csvtabins" #include "../icmconf.lib" bobcat-6.07.01/csvtabins/insert3.cc0000664000175000017500000000055114673353433016013 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-6.07.01/csvtabins/csvtabins1.cc0000664000175000017500000000066414673353433016506 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-6.07.01/csvtabins/insert1.f0000664000175000017500000000100714673353433015646 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-6.07.01/csvtabins/csvtabins.ih0000664000175000017500000000013514736315237016431 0ustar frankfrank#include "csvtabins" #include "../xerr/xerr.ih" using namespace std; using namespace FBB; bobcat-6.07.01/csvtabins/destructor.cc0000664000175000017500000000060214673353433016617 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-6.07.01/csvtabins/opinsert1.f0000664000175000017500000000050114673353433016203 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-6.07.01/csvtabins/width2.cc0000664000175000017500000000025314673353433015624 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-6.07.01/csvtabins/opinsert4.f0000664000175000017500000000035614673353433016216 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-6.07.01/csvtabins/driver/0000775000175000017500000000000014673353433015407 5ustar frankfrankbobcat-6.07.01/csvtabins/driver/icmconf0000664000175000017500000000107314673353433016751 0ustar frankfrank#define CLS #define MAIN "main.cc" #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 " \ " -fdiagnostics-color=never " #define REFRESH #define LDFLAGS "-s" #define ADD_LIBRARIES "csvtabins csvtable bobcat" #define ADD_LIBRARY_PATHS "../../tmp/ ../../../csvtable/tmp" #define DEFCOM "program" bobcat-6.07.01/csvtabins/driver/main.cc0000664000175000017500000000104214673353433016637 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-6.07.01/csvtable/0000775000175000017500000000000014736742656013734 5ustar frankfrankbobcat-6.07.01/csvtable/stream4.f0000664000175000017500000000007714673353433015455 0ustar frankfrankinline std::ostream &CSVTable::stream() { return *d_out; } bobcat-6.07.01/csvtable/row1.cc0000664000175000017500000000027114673353433015122 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-6.07.01/csvtable/csvtable.ih0000664000175000017500000000016114736315237016046 0ustar frankfrank#include "csvtable" #include "../xerr/xerr.ih" #include "csvtable" using namespace std; using namespace FBB; bobcat-6.07.01/csvtable/csvtable3.cc0000664000175000017500000000041714673353433016122 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-6.07.01/csvtable/check.cc0000664000175000017500000000044014673353433015305 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-6.07.01/csvtable/fmt2.cc0000664000175000017500000000026414673353433015104 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-6.07.01/csvtable/csvtable0000664000175000017500000001330514673353433015453 0ustar frankfrank#ifndef INCLUDED_BOBCAT_CSVTABLE_ #define INCLUDED_BOBCAT_CSVTABLE_ #include #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-6.07.01/csvtable/prestreamswitch.cc0000664000175000017500000000062714673353433017463 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-6.07.01/csvtable/opindex.f0000664000175000017500000000013214673353433015534 0ustar frankfrankinline FMT const &CSVTable::operator[](unsigned idx) const { return d_format[idx]; } bobcat-6.07.01/csvtable/row2.cc0000664000175000017500000000036314673353433015125 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-6.07.01/csvtable/streamreset.cc0000664000175000017500000000035214673353433016570 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-6.07.01/csvtable/stream2.cc0000664000175000017500000000037214673353433015611 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-6.07.01/csvtable/stream1.cc0000664000175000017500000000033114673353433015603 0ustar frankfrank//#define XERR #include "csvtable.ih" void CSVTable::stream(std::ostream &out) { int fillChar = preStreamSwitch(); d_out = &out; // switch stream postStreamSwitch(fillChar); } bobcat-6.07.01/csvtable/limit.f0000664000175000017500000000023114673353433015204 0ustar frankfrank//#define XERR #include "csvtable.ih" inline unsigned CSVTable::limit(unsigned idx) const { return idx > d_format.size() ? d_format:size() : idx; } bobcat-6.07.01/csvtable/sep1.f0000664000175000017500000000010614673353433014737 0ustar frankfrankinline std::string const &CSVTable::sep() const { return d_sep; } bobcat-6.07.01/csvtable/csvtable4.cc0000664000175000017500000000076714673353433016133 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-6.07.01/csvtable/csvtable2.cc0000664000175000017500000000032614673353433016120 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-6.07.01/csvtable/more1.cc0000664000175000017500000000027414673353433015260 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-6.07.01/csvtable/csvtable1.cc0000664000175000017500000000024314673353433016115 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-6.07.01/csvtable/opfun.f0000664000175000017500000000017114673353433015220 0ustar frankfrank // insert fields values into d_out inline void CSVTable::operator()(std::string const &text) { row(text, ~0U); } bobcat-6.07.01/csvtable/fmt1.cc0000664000175000017500000000021014673353433015072 0ustar frankfrank//#define XERR #include "csvtable.ih" CSVTabDef CSVTable::fmt(unsigned idx) { check(idx); return CSVTabDef{ d_format, idx }; } bobcat-6.07.01/csvtable/icmconf0000664000175000017500000000010214673353433015255 0ustar frankfrank#define LIBRARY "csvtable" #include "../icmconf.lib" bobcat-6.07.01/csvtable/size.f0000664000175000017500000000010714673353433015042 0ustar frankfrankinline unsigned CSVTable::size() const { return d_format.size(); } bobcat-6.07.01/csvtable/sep2.f0000664000175000017500000000012314673353433014737 0ustar frankfrankinline void CSVTable::sep(std::string const &separator) { d_sep = separator; } bobcat-6.07.01/csvtable/streamflags.cc0000664000175000017500000000040314673353433016537 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-6.07.01/csvtable/destructor.cc0000664000175000017500000000012414673353433016425 0ustar frankfrank//#define XERR #include "csvtable.ih" CSVTable::~CSVTable() { streamReset(); } bobcat-6.07.01/csvtable/idx.f0000664000175000017500000000007414673353433014657 0ustar frankfrankinline unsigned CSVTable::idx() const { return d_idx; } bobcat-6.07.01/csvtable/checkinsertidx.cc0000664000175000017500000000062414673353433017243 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-6.07.01/csvtable/more2.cc0000664000175000017500000000034214673353433015255 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-6.07.01/csvtable/opcsvtabins.f0000664000175000017500000000007414673353433016426 0ustar frankfrankinline CSVTable::operator CSVTabIns() { return row(); } bobcat-6.07.01/csvtable/poststreamswitch.cc0000664000175000017500000000021014673353433017646 0ustar frankfrank//#define XERR #include "csvtable.ih" void CSVTable::postStreamSwitch(int fillChar) { streamFlags(); d_out->fill(fillChar); } bobcat-6.07.01/csvtable/stream3.cc0000664000175000017500000000052714673353433015614 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-6.07.01/csvtable/columns.f0000664000175000017500000000012314673353433015546 0ustar frankfrankinline std::vector const &CSVTable::columns() const { return d_format; }; bobcat-6.07.01/csvtable/rowstreamreset.cc0000664000175000017500000000016614673353433017323 0ustar frankfrank//#define XERR #include "csvtable.ih" void CSVTable::rowStreamReset() { if (d_idx == 0) streamReset(); } bobcat-6.07.01/csvtable/driver/0000775000175000017500000000000014673353433015216 5ustar frankfrankbobcat-6.07.01/csvtable/driver/icmconf0000664000175000017500000000132014673353433016553 0ustar frankfrank#define CLS #define MAIN "main.cc" #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 " \ " -fdiagnostics-color=never " #define REFRESH #define LDFLAGS "-s" #define ADD_LIBRARIES "bobcat" #define ADD_LIBRARY_PATHS "" // #define ADD_LIBRARIES "csvtable csvtabdef csvtabins bobcat " // #define ADD_LIBRARY_PATHS "../../../csvtabdef/tmp " \ // "../../../csvtabins/tmp ../../tmp/" #define DEFCOM "program" bobcat-6.07.01/csvtable/driver/main.cc0000664000175000017500000000205114673353433016447 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-6.07.01/csvtable/driver/main.ih0000664000175000017500000000015514673353433016465 0ustar frankfrank#include #include #include using namespace std; using namespace FBB; bobcat-6.07.01/datetime/0000775000175000017500000000000014736742656013725 5ustar frankfrankbobcat-6.07.01/datetime/setweekday.cc0000664000175000017500000000100514673353433016364 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-6.07.01/datetime/replace0000664000175000017500000000165414673353433015260 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-6.07.01/datetime/opleq.f0000664000175000017500000000017614673353433015207 0ustar frankfrankinline bool operator<=(FBB::DateTime const &left, FBB::DateTime const &right) { return left.d_utcSec <= right.d_utcSec; } bobcat-6.07.01/datetime/opaddis1.cc0000664000175000017500000000023014673353433015722 0ustar frankfrank#include "datetime.ih" DateTime &DateTime::operator+=(chrono::seconds seconds) { d_utcSec += seconds.count(); assignTM(); return *this; } bobcat-6.07.01/datetime/zonezoneseconds1.cc0000664000175000017500000000024214673353433017530 0ustar frankfrank#include "datetime.ih" // static int DateTime::Zone::zoneSeconds() { time_t seconds = 0; TM tm; gmtime_r(&seconds, &tm); return - mktime(&tm); } bobcat-6.07.01/datetime/settz.cc0000664000175000017500000000024314673353433015373 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-6.07.01/datetime/setmonthnr.f0000664000175000017500000000014414673353433016263 0ustar frankfrankinline void FBB::DateTime::setMonthNr(int monthNr) { setMonth(static_cast(monthNr - 1)); } bobcat-6.07.01/datetime/setseconds.cc0000664000175000017500000000015214673353433016373 0ustar frankfrank#include "datetime.ih" void DateTime::setSeconds(int seconds) { setFields(TM{ seconds }, SECONDS); } bobcat-6.07.01/datetime/data.cc0000664000175000017500000000125314673353433015135 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-6.07.01/datetime/utcseconds.f0000664000175000017500000000011114673353433016226 0ustar frankfrankinline time_t FBB::DateTime::utcSeconds() const { return d_utcSec; } bobcat-6.07.01/datetime/zoneinitialize.cc0000664000175000017500000000055214673353433017262 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-6.07.01/datetime/setday.cc0000664000175000017500000000015014673353433015510 0ustar frankfrank#include "datetime.ih" void DateTime::setDay(int day) { setFields(TM{ 0, 0, 0, day }, MONTHDAY); } bobcat-6.07.01/datetime/datetime10.cc0000664000175000017500000000102014673353433016151 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-6.07.01/datetime/parsesetzoneshift.cc0000664000175000017500000000032114673353433017777 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-6.07.01/datetime/sethours.cc0000664000175000017500000000015014673353433016073 0ustar frankfrank#include "datetime.ih" void DateTime::setHours(int hours) { setFields(TM{ 0, 0, hours }, HOURS); } bobcat-6.07.01/datetime/opgreater.f0000664000175000017500000000017414673353433016055 0ustar frankfrankinline bool operator>(FBB::DateTime const &left, FBB::DateTime const &right) { return left.d_utcSec > right.d_utcSec; } bobcat-6.07.01/datetime/opaddis2.cc0000664000175000017500000000054114673353433015730 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-6.07.01/datetime/setmonth3.cc0000664000175000017500000000153114673353433016147 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-6.07.01/datetime/seconds2str.cc0000664000175000017500000000063214673353433016475 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-6.07.01/datetime/parsefrommonth.cc0000664000175000017500000000222714673353433017272 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-6.07.01/datetime/hours.f0000664000175000017500000000011214673353433015215 0ustar frankfrankinline unsigned FBB::DateTime::hours() const { return d_tm.tm_hour; } bobcat-6.07.01/datetime/monthdaynr.f0000664000175000017500000000011714673353433016245 0ustar frankfrankinline unsigned FBB::DateTime::monthDayNr() const { return d_tm.tm_mday; } bobcat-6.07.01/datetime/utc.f0000664000175000017500000000013214673353433014652 0ustar frankfrankinline FBB::DateTime FBB::DateTime::utc() const { return DateTime{ d_utcSec, UTC }; } bobcat-6.07.01/datetime/datetime6.cc0000664000175000017500000000057114673353433016110 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-6.07.01/datetime/parsezoneshift.f0000664000175000017500000000012314673353433017123 0ustar frankfrankinline int FBB::DateTime::Parse::zoneSeconds() const { return d_zoneSeconds; } bobcat-6.07.01/datetime/zoneget.cc0000664000175000017500000000072314673353433015700 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-6.07.01/datetime/datetime1.cc0000664000175000017500000000020714673353433016077 0ustar frankfrank#include "datetime.ih" // UTC time = ::time(0) DateTime::DateTime(TimeType type) : DateTime(::time(0), type) // 6.cc {} bobcat-6.07.01/datetime/weeknr.cc0000664000175000017500000000017714673353433015523 0ustar frankfrank#include "datetime.ih" unsigned DateTime::weekNr() const { unsigned nr = yearDayNr() / 7; return nr == 0 ? 52 : nr; } bobcat-6.07.01/datetime/datetime8.cc0000664000175000017500000000026314673353433016110 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-6.07.01/datetime/zonedstfromvector.cc0000664000175000017500000000105014673353433020014 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-6.07.01/datetime/datetime9.cc0000664000175000017500000000105614673353433016112 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-6.07.01/datetime/yeardaynr.f0000664000175000017500000000012214673353433016054 0ustar frankfrankinline unsigned FBB::DateTime::yearDayNr() const { return d_tm.tm_yday + 1; } bobcat-6.07.01/datetime/setfields.cc0000664000175000017500000000101514673353433016202 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-6.07.01/datetime/zonenegate.cc0000664000175000017500000000054314673353433016364 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-6.07.01/datetime/zone3.cc0000664000175000017500000000033714673353433015264 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-6.07.01/datetime/setmonth1.cc0000664000175000017500000000021314673353433016141 0ustar frankfrank#include "datetime.ih" void DateTime::setMonth(int month) { // s m h md setFields(TM{ 0, 0, 0, 0, month }, MONTH); } bobcat-6.07.01/datetime/zonestore.cc0000664000175000017500000000062114673353433016252 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-6.07.01/datetime/opinsert.cc0000664000175000017500000000033114673353433016063 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-6.07.01/datetime/setutcseconds.cc0000664000175000017500000000016714673353433017115 0ustar frankfrank#include "datetime.ih" void DateTime::setUTCseconds(time_t utcSeconds) { d_utcSec = utcSeconds; assignTM(); } bobcat-6.07.01/datetime/zoneaddzone.cc0000664000175000017500000000273114673353433016546 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-6.07.01/datetime/rfc2822.cc0000664000175000017500000000134514673353433015316 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-6.07.01/datetime/clocktime.cc0000664000175000017500000000034314673353433016175 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-6.07.01/datetime/zonethiszone.cc0000664000175000017500000000074514673353433016770 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-6.07.01/datetime/month.f0000664000175000017500000000014414673353433015207 0ustar frankfrankinline FBB::DateTime::Month DateTime::month() const { return static_cast(d_tm.tm_mon); } bobcat-6.07.01/datetime/stdfind.cc0000664000175000017500000000037714673353433015665 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-6.07.01/datetime/utcforzone.cc0000664000175000017500000000035714673353433016426 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-6.07.01/datetime/frame.parse0000664000175000017500000000005614673353433016043 0ustar frankfrank#include "datetime.ih" DateTime::Parse:: { } bobcat-6.07.01/datetime/zone4.f0000664000175000017500000000011714673353433015121 0ustar frankfrankinline FBB::DateTime::Zone::Zone(Data &&data) : d_data(std::move(data)) {} bobcat-6.07.01/datetime/thistime.f0000664000175000017500000000020614673353433015707 0ustar frankfrankinline FBB::DateTime FBB::DateTime::thisTime() const { return DateTime{ d_utcSec, LOCALTIME }; // the computer's local time } bobcat-6.07.01/datetime/zonerequirealpha.cc0000664000175000017500000000065514673353433017607 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-6.07.01/datetime/zone2.cc0000664000175000017500000000121214673353433015254 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-6.07.01/datetime/zonestoreiuo.cc0000664000175000017500000000077214673353433016776 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-6.07.01/datetime/zoneadd.cc0000664000175000017500000000112714673353433015650 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-6.07.01/datetime/dst.f0000664000175000017500000000011214673353433014647 0ustar frankfrankinline bool FBB::DateTime::dst() const { return d_tm.tm_isdst == 1; } bobcat-6.07.01/datetime/datetime.xref0000664000175000017500000003331714673353433016405 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-6.07.01/datetime/opgeq.f0000664000175000017500000000017614673353433015202 0ustar frankfrankinline bool operator>=(FBB::DateTime const &left, FBB::DateTime const &right) { return left.d_utcSec >= right.d_utcSec; } bobcat-6.07.01/datetime/yearday.f0000664000175000017500000000011414673353433015515 0ustar frankfrankinline unsigned FBB::DateTime::yearDay() const { return d_tm.tm_yday; } bobcat-6.07.01/datetime/zonezoneseconds2.cc0000664000175000017500000000025414673353433017534 0ustar frankfrank#include "datetime.ih" // static int DateTime::Zone::zoneSeconds(std::string const &spec) { setTZ(spec); int ret = zoneSeconds(); resetTZ(); return ret; } bobcat-6.07.01/datetime/opsubis2.cc0000664000175000017500000000054114673353433015771 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-6.07.01/datetime/seconds.f0000664000175000017500000000011314673353433015514 0ustar frankfrankinline unsigned FBB::DateTime::seconds() const { return d_tm.tm_sec; } bobcat-6.07.01/datetime/opbitor.f0000664000175000017500000000043314673353433015541 0ustar frankfrankinline FBB::DateTime::TimeFields operator|(DateTime::TimeFields lhs, DateTime::TimeFields rhs) { return static_cast ( static_cast(lhs) | static_cast(rhs) ); } bobcat-6.07.01/datetime/zonedstconcatenate.cc0000664000175000017500000000047714673353433020126 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-6.07.01/datetime/opless.f0000664000175000017500000000017414673353433015372 0ustar frankfrankinline bool operator<(FBB::DateTime const &left, FBB::DateTime const &right) { return left.d_utcSec < right.d_utcSec; } bobcat-6.07.01/datetime/icmconf0000664000175000017500000000014614673353433015256 0ustar frankfrank#define LIBRARY "datetime" #define AUXFLAGS "-pthread" #include "../icmconf" bobcat-6.07.01/datetime/datetime5.f0000664000175000017500000000022314673353433015741 0ustar frankfrank// UTC time is ::time(0), zone shift is zoneMinutes inline FBB::DateTime::DateTime(Zone const &zone) : DateTime(::time(0), zone) // -> 8 {} bobcat-6.07.01/datetime/zoneseconds.f0000664000175000017500000000012314673353433016411 0ustar frankfrankinline int FBB::DateTime::Zone::seconds() const { return d_data.zoneSeconds; } bobcat-6.07.01/datetime/setminutes.cc0000664000175000017500000000015514673353433016424 0ustar frankfrank#include "datetime.ih" void DateTime::setMinutes(int minutes) { setFields(TM{ 0, minutes }, MINUTES); } bobcat-6.07.01/datetime/datetime12.cc0000664000175000017500000000023314673353433016160 0ustar frankfrank#include "datetime.ih" DateTime::DateTime(string const &timeStr, TimeType type) : DateTime(istringstream{timeStr}, type) // 14.f {} bobcat-6.07.01/datetime/parse1.cc0000664000175000017500000000144514673353433015422 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-6.07.01/datetime/datetime4.f0000664000175000017500000000034214673353433015742 0ustar frankfrank// UTC time is ::time(0), zoneMinutes is localZone (in minutes) // no dst, zone = local inline FBB::DateTime::DateTime(std::chrono::minutes minutes) : DateTime( Zone{ seconds2str(minutes.count() * 60) } ) // -> 5.f {} bobcat-6.07.01/datetime/zoneread.cc0000664000175000017500000000063014673353433016031 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-6.07.01/datetime/parsesetmonth.cc0000664000175000017500000000017314673353433017120 0ustar frankfrank#include "datetime.ih" void DateTime::Parse::setMonth(string const &mon) { d_tm.tm_mon = stdFind(s_month, 12, mon); } bobcat-6.07.01/datetime/timestruct.f0000664000175000017500000000013014673353433016260 0ustar frankfrankinline FBB::DateTime::TM const *FBB::DateTime::timeStruct() const { return &d_tm; } bobcat-6.07.01/datetime/rfc3339.cc0000664000175000017500000000112214673353433015313 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-6.07.01/datetime/zoneseconds.cc0000664000175000017500000000047714673353433016565 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-6.07.01/datetime/zonecheckdst.cc0000664000175000017500000000152014673353433016705 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-6.07.01/datetime/datetime7.f0000664000175000017500000000033514673353433015747 0ustar frankfrank // time provides UTC time, zone at zoneMinutes, no DST. inline FBB::DateTime::DateTime(time_t time, std::chrono::minutes zoneMinutes) : DateTime(time, Zone{ seconds2str(zoneMinutes.count() * 60) } ) // -> 8.cc {} bobcat-6.07.01/datetime/setmonth2.f0000664000175000017500000000013414673353433016004 0ustar frankfrankinline void FBB::DateTime::setMonth(Month month) { setMonth(static_cast(month)); } bobcat-6.07.01/datetime/datetime0000664000175000017500000003703214673353433015440 0ustar frankfrank#ifndef INCLUDED_BOBCAT_DATETIME_ #define INCLUDED_BOBCAT_DATETIME_ #include #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); using TM = struct 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; using ZoneMap = std::unordered_map>; 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); using StringVector = std::vector; 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 = UTC); // 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 = UTC); // 12 DateTime(std::istream &in, TimeType type = UTC); // 13 DateTime(std::istream &&in, TimeType type = UTC); // 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-6.07.01/datetime/zone.f0000664000175000017500000000012514673353433015034 0ustar frankfrankinline FBB::DateTime::Zone const &FBB::DateTime::zone() const { return d_zone; } bobcat-6.07.01/datetime/frame.pimpl0000664000175000017500000000005614673353433016052 0ustar frankfrank#include "datetime.ih" DateTime::Pimpl:: { } bobcat-6.07.01/datetime/datetime.ih0000664000175000017500000000045414736315237016035 0ustar frankfrank#include "datetime" #include #include #include #include #include #include "../string/string" #include "../fswap/fswap" #include "parseformat.f" #include "parsezoneshift.f" #include "parsezonename.f" using namespace std; using namespace FBB; bobcat-6.07.01/datetime/year.f0000664000175000017500000000012014673353433015014 0ustar frankfrankinline unsigned FBB::DateTime::year() const { return d_tm.tm_year + 1900; } bobcat-6.07.01/datetime/zonespec.f0000664000175000017500000000013014673353433015703 0ustar frankfrankinline std::string const &FBB::DateTime::Zone::spec() const { return d_data.spec; } bobcat-6.07.01/datetime/swap.cc0000664000175000017500000000015714673353433015200 0ustar frankfrank//#include "datetime.ih" // //void DateTime::swap(DateTime &other) //{ // Pimpl::swap(*this, other); //} // bobcat-6.07.01/datetime/parsezone.f0000664000175000017500000000013414673353433016067 0ustar frankfrankinline FBB::DateTime::Zone const &FBB::DateTime::Parse::zone() const { return d_zone; } bobcat-6.07.01/datetime/tm2cout.cc0000664000175000017500000000061214673353433015617 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-6.07.01/datetime/assigntm.cc0000664000175000017500000000062714673353433016055 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-6.07.01/datetime/setyear.cc0000664000175000017500000000024414673353433015677 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-6.07.01/datetime/opextract.cc0000664000175000017500000000036314673353433016236 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-6.07.01/datetime/opneq.f0000664000175000017500000000017614673353433015211 0ustar frankfrankinline bool operator!=(FBB::DateTime const &left, FBB::DateTime const &right) { return left.d_utcSec != right.d_utcSec; } bobcat-6.07.01/datetime/thiszoneshift.f0000664000175000017500000000012314673353433016760 0ustar frankfrankinline time_t FBB::DateTime::Zone::thisZoneShift() { return s_thisZoneShift; } bobcat-6.07.01/datetime/datetime14.f0000664000175000017500000000021314673353433016020 0ustar frankfrankinline FBB::DateTime::DateTime(std::istream &&in, TimeType type) : DateTime(in, type) // 13.cc {} bobcat-6.07.01/datetime/parseformat.f0000664000175000017500000000011114673353433016377 0ustar frankfrankinline int FBB::DateTime::Parse::format() const { return d_format; } bobcat-6.07.01/datetime/zonedstseconds.f0000664000175000017500000000022414673353433017126 0ustar frankfrank // at this point DST is known to be active (cf. utcFromTM) inline int FBB::DateTime::Zone::dstSeconds() const { return d_data.dstSeconds; } bobcat-6.07.01/datetime/opeq.f0000664000175000017500000000017614673353433015033 0ustar frankfrankinline bool operator==(FBB::DateTime const &left, FBB::DateTime const &right) { return left.d_utcSec == right.d_utcSec; } bobcat-6.07.01/datetime/zonedefaulttz.f0000664000175000017500000000012714673353433016761 0ustar frankfrankinline std::string const &FBB::DateTime::Zone::defaultTZ() { return s_defaultTZ; } bobcat-6.07.01/datetime/parsezonename.f0000664000175000017500000000013414673353433016730 0ustar frankfrankinline std::string const &FBB::DateTime::Parse::zoneName() const { return d_zoneName; } bobcat-6.07.01/datetime/setzone.cc0000664000175000017500000000023614673353433015713 0ustar frankfrank#include "datetime.ih" void DateTime::setZone(Zone const &zone) { d_type = LOCALTIME; d_zone = zone; // Pimpl::set(this, zone); assignTM(); } bobcat-6.07.01/datetime/parsefromyear.cc0000664000175000017500000000154614673353433017110 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-6.07.01/datetime/frame.zone0000664000175000017500000000005514673353433015703 0ustar frankfrank#include "datetime.ih" DateTime::Zone:: { } bobcat-6.07.01/datetime/minutes.f0000664000175000017500000000011314673353433015542 0ustar frankfrankinline unsigned FBB::DateTime::minutes() const { return d_tm.tm_min; } bobcat-6.07.01/datetime/timeexception.cc0000664000175000017500000000020014673353433017070 0ustar frankfrank#include "datetime.ih" // static void DateTime::timeException() { throw Exception{ 1 } << "error in time specification"; } bobcat-6.07.01/datetime/zonedata.cc0000664000175000017500000000302414673353433016027 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-6.07.01/datetime/opsubis1.cc0000664000175000017500000000023014673353433015763 0ustar frankfrank#include "datetime.ih" DateTime &DateTime::operator-=(chrono::seconds seconds) { d_utcSec -= seconds.count(); assignTM(); return *this; } bobcat-6.07.01/datetime/datetime13.cc0000664000175000017500000000172014673353433016163 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-6.07.01/datetime/zoneconvert.cc0000664000175000017500000000162114673353433016577 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-6.07.01/datetime/utcfromtm.cc0000664000175000017500000000046314673353433016246 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-6.07.01/datetime/parsedater.cc0000664000175000017500000000127414673353433016361 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-6.07.01/datetime/weekday.f0000664000175000017500000000016014673353433015511 0ustar frankfrankinline FBB::DateTime::Weekday FBB::DateTime::weekday() const { return static_cast(d_tm.tm_wday); } bobcat-6.07.01/datetime/driver/0000775000175000017500000000000014736770413015210 5ustar frankfrankbobcat-6.07.01/datetime/driver/build0000775000175000017500000000026014673353433016232 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-6.07.01/datetime/driver/tz.cc0000664000175000017500000002106714673353433016161 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-6.07.01/datetime/driver/zone.cc0000664000175000017500000000323714673353433016476 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-6.07.01/datetime/driver/datetime6.cc0000664000175000017500000000053314673353433017401 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-6.07.01/datetime/driver/datetime7.cc0000664000175000017500000000062114673353433017400 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-6.07.01/datetime/driver/datetime8.cc0000664000175000017500000000163714673353433017411 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-6.07.01/datetime/driver/datetime9.cc0000664000175000017500000000162714673353433017411 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-6.07.01/datetime/driver/setfields.cc0000664000175000017500000000427414673353433017507 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-6.07.01/datetime/driver/anyshift/0000775000175000017500000000000014673353433017034 5ustar frankfrankbobcat-6.07.01/datetime/driver/anyshift/showtm.cc0000664000175000017500000000031514673353433020663 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-6.07.01/datetime/driver/anyshift/showdesiredtime.cc0000664000175000017500000000075214673353433022546 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-6.07.01/datetime/driver/anyshift/data.cc0000664000175000017500000000036514673353433020260 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-6.07.01/datetime/driver/anyshift/getlocal.cc0000664000175000017500000000103514673353433021134 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-6.07.01/datetime/driver/anyshift/changehours.cc0000664000175000017500000000075314673353433021656 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-6.07.01/datetime/driver/anyshift/icmconf0000664000175000017500000000077314673353433020404 0ustar frankfrank#define CLS #define MAIN "main.cc" #define SOURCES "*.cc" #define OBJ_EXT ".o" #define TMP_DIR "tmp" #define USE_ECHO ON #define CXX "g++" #define CXXFLAGS " --std=c++2a -Wall -O2" \ " -fdiagnostics-color=never " #define IH ".ih" #define REFRESH #define LDFLAGS "-s" #define ADD_LIBRARIES "" #define ADD_LIBRARY_PATHS "" #define DEFCOM "program" bobcat-6.07.01/datetime/driver/anyshift/main.cc0000664000175000017500000000271314673353433020272 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-6.07.01/datetime/driver/anyshift/main.ih0000664000175000017500000000114714673353433020305 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-6.07.01/datetime/driver/anyshift/showlocaltime.cc0000664000175000017500000000025114673353433022213 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-6.07.01/datetime/driver/anyshift/getdesired.cc0000664000175000017500000000123214673353433021460 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-6.07.01/datetime/driver/zoneread.txt0000664000175000017500000000135014673353433017556 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-6.07.01/datetime/driver/auckland.cc0000664000175000017500000000127714673353433017307 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-6.07.01/datetime/driver/datetime12.cc0000664000175000017500000000370414673353433017461 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-6.07.01/datetime/driver/zoneread.cc0000664000175000017500000000022214673353433017321 0ustar frankfrank#include #include "../datetime" using namespace std; using namespace FBB; int main() { DateTime::Zone::read("zoneread.txt"); } bobcat-6.07.01/datetime/driver/datetime2.cc0000664000175000017500000000173214673353433017377 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-6.07.01/datetime/driver/rfc.cc0000664000175000017500000000076414673353433016277 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-6.07.01/datetime/driver/accessors.cc0000664000175000017500000000243514736770413017510 0ustar frankfrank#include #include 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-6.07.01/datetime/driver/midnight.cc0000664000175000017500000000057414673353433017327 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-6.07.01/datetime/parsefromdayname.cc0000664000175000017500000000063014673353433017557 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-6.07.01/datetime/resettz.cc0000664000175000017500000000030514673353433015721 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-6.07.01/dependencies/0000775000175000017500000000000014736315237014546 5ustar frankfrankbobcat-6.07.01/dependencies/inspectset.cc0000664000175000017500000000220114673353433017231 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-6.07.01/dependencies/store0000775000175000017500000000226214673353433015632 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-6.07.01/dependencies/required.classes0000664000175000017500000000612514673353433017751 0ustar frankfranka2x align arg exception argconfig arg configfile exception base64bufbase exception ifilterbuf bigint exception binarysearch binops typetrait binopsbase cerrextractor exception exec extractorbase fswap ifdbuf pipe cgi exception pattern cidr exception cininserter exception exec fswap ofdbuf pipe clientsocket exception inetaddress socketbase cmdfinder cmdfinderbase exception fswap cmdfinderbase exception config exception pattern string configfile exception coutextractor exception exec extractorbase fswap ifdbuf pipe cryptbuf csv4180 exception csvtabdef csvtabins exception fmt sep string csvtable csvtabdef csvtabins exception fmt sep string datetime exception decryptbuf diffiehellman bigint exception digestbuf encryptbuf eoi eoibuf exception exec extractorbase exception exec fswap ifdbuf pipe fbb field fmt exception fork exception fswap gethostent exception glob exception gs gs hash string hmacbuf hostent hostname exception hostent ibase64buf ibase64stream ibase64buf ifdbuf ifdstream ifdbuf ifilterbuf indent inetaddress iobuf iostream iobuf iquotedprintablebuf iquotedprintablestream iquotedprintablebuf irandstream randbuf isharedstream sharedbuf isymcryptbase exception symcryptbase isymcryptstream isymcryptstreambuf isymcryptstreambuf iterator iuo ldc level exception log logbuf linearmap localclientsocket exception localsocketbase localserversocket exception localsocketbase localsocketbase exception log exception logbuf logbuf mailheaders exception string mbuf milter exception mstream exception mbuf multibuf ofdbuf ofdstream ofdbuf ofilterbuf ofoldbuf ofoldstream ofoldbuf ohexbuf omutexstream onekey exception osharedstream sharedbuf osymcryptbase eoibuf exception symcryptbase osymcryptstream osymcryptstreambuf osymcryptstreambuf pattern exception pf_iterator pf_iteratorstream pipe exception fswap poller exception primefactors bigint exception process exception fork fswap ifdbuf iobuf iostream ofdbuf pipe processenums selector signal string processenums ptriter qpbufbase exception ifilterbuf randbuf randommt exception ranger readlinebuf readlinehistory readlinestream readlinebuf redirector exception repeat typetrait reverse selector exception semaphore sep serversocket exception inetaddress socketbase sharedblock exception sharedmutex sharedbuf sharedcondition exception fswap sharedblock sharedmemory sharedmutex sharedpos sharedsegment sharedmemory exception fswap sharedblock sharedmutex sharedpos sharedsegment sharedmutex exception sharedpos exception sharedblock sharedmutex sharedsegment sharedsegment exception sharedblock sharedmutex sharedstream sharedbuf signal exception socketbase exception inetaddress stat datetime exception gs stdextractor exception exec extractorbase fswap ifdbuf pipe string stringline symcryptbase exception syslogbuf syslogstream syslogbuf table align tablebase tablesupport tablebase align tablesupport tablebuf tablelines align tablesupport tablesupport align tempstream exception tty exception typetrait user exception x2a xpointer exception bobcat-6.07.01/dependencies/icmconf0000664000175000017500000000075414673353433016115 0ustar frankfrank#define MAIN "main.cc" #define SOURCES "*.cc" #define OBJ_EXT ".o" #define TMP_DIR "tmp" #define USE_ECHO ON #define CXX "g++" #define CXXFLAGS " --std=c++2a -Wall -O2" \ " -fdiagnostics-color=never " #define IH ".ih" #define REFRESH #define LDFLAGS "" #define ADD_LIBRARIES "" #define ADD_LIBRARY_PATHS "" #define DEFCOM "program" bobcat-6.07.01/dependencies/display.cc0000664000175000017500000000053114673353433016521 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-6.07.01/dependencies/main.cc0000664000175000017500000000015514673353433016002 0ustar frankfrank#include "main.ih" int main() { Map table; fill(table); inspect(table); display(table); } bobcat-6.07.01/dependencies/main.ih0000664000175000017500000000064014736315237016014 0ustar frankfrank#include #include #include #include #include using namespace std; using StringSet = set; using ValuePair = pair; // bool: circular dependency using Map = map; using ValueType = Map::value_type; void display(Map const &table); void fill(Map &table); void inspect(Map &table); bool inspectSet(ValueType &value, Map &table); bobcat-6.07.01/dependencies/fill.cc0000664000175000017500000000107714673353433016010 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-6.07.01/dependencies/using.classes0000664000175000017500000000630514673353433017256 0ustar frankfranka2x align tablebase tablesupport arg argconfig argconfig base64bufbase binarysearch binops binopsbase cerrextractor cgi cidr cininserter clientsocket cmdfinder cmdfinderbase cmdfinder config configfile argconfig coutextractor csv4180 csvtabdef csvtable csvtabins csvtable csvtable datetime stat eoi eoibuf osymcryptbase exception pattern gethostent signal sharedmutex user diffiehellman glob osymcryptbase sharedmemory fmt csvtable serversocket configfile localserversocket csv4180 socketbase log fork mstream stat cgi hostname onekey config clientsocket qpbufbase pipe arg argconfig bigint milter poller symcryptbase localclientsocket datetime tempstream cidr xpointer sharedsegment mailheaders sharedcondition process redirector selector base64bufbase tty randommt sharedpos localsocketbase cmdfinderbase exec extractorbase cininserter extractorbase coutextractor stdextractor cerrextractor fbb field fmt csvtabins csvtable fork process fswap sharedmemory pipe cmdfinder gethostent glob gs glob stat hash hostent hostname hostname ibase64buf ibase64stream ibase64stream ifdbuf ifdstream extractorbase process ifdstream ifilterbuf qpbufbase base64bufbase indent inetaddress socketbase iobuf iostream iostream process iquotedprintablebuf iquotedprintablestream iquotedprintablestream irandstream isharedstream iterator iuo level linearmap localclientsocket localserversocket localsocketbase localserversocket localclientsocket log level logbuf log mailheaders mbuf mstream mstream multibuf ofdbuf ofdstream process cininserter ofdstream ofilterbuf ofoldbuf ofoldstream ofoldstream ohexbuf omutexstream onekey osharedstream pattern cgi config pipe extractorbase process cininserter process processenums process ptriter qpbufbase randbuf irandstream randommt ranger redirector repeat reverse selector process semaphore sep csvtabins serversocket sharedblock sharedsegment sharedbuf osharedstream isharedstream sharedstream sharedcondition sharedmemory sharedcondition sharedmutex sharedblock sharedcondition sharedpos sharedmemory sharedsegment sharedpos sharedstream signal process socketbase serversocket clientsocket stat stdextractor string csvtabins config hash mailheaders process stringline syslogbuf syslogstream syslogstream table tablebase table tablebuf tablelines tablesupport tablelines tablebase tempstream tty typetrait repeat binops user x2a readlinebuf readlinestream readlinehistory readlinestream bigint diffiehellman primefactors cryptbuf decryptbuf diffiehellman digestbuf encryptbuf hmacbuf isymcryptbase isymcryptstream isymcryptstreambuf isymcryptstream ldc osymcryptbase osymcryptstream osymcryptstreambuf osymcryptstream pf_iterator pf_iteratorstream primefactors symcryptbase osymcryptbase isymcryptbase milter xpointer bobcat-6.07.01/dependencies/inspect.cc0000664000175000017500000000036214673353433016523 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-6.07.01/diffiehellman/0000775000175000017500000000000014736742656014720 5ustar frankfrankbobcat-6.07.01/diffiehellman/diffiehellman0000664000175000017500000000711714673353433017427 0ustar frankfrank#ifndef INCLUDED_BOBCAT_DIFFIEHELLMAN_ #define INCLUDED_BOBCAT_DIFFIEHELLMAN_ #include #include #include #include namespace FBB { class DiffieHellman { enum { MIN_PRIME_SIZE = 1024 }; BigInt d_prime; BigInt d_generator; BigInt d_privKey; BigInt d_pubKey; BigInt d_peerPubKey; // public key of the other party BigInt d_common; // common secret (after calling key) static char const *s_header; public: // no copy/move constructors/operations DiffieHellman(DiffieHellman const &other) = delete; // The initiator calls this constructor to compute the common // DH parameters DiffieHellman(size_t primeLength = 1024, size_t generator = 5, // 1 bool progress = false); // uses predefined prime 'prime' DiffieHellman(BigInt const &prime, size_t generator = 5); // 2 // this constructor reloads the public and private data DiffieHellman(std::string const &publicFileName, // 3 std::string const &privateFileName); // Alternatively, use this constructor expecting istreams: DiffieHellman(std::istream &publicStream, // 4 std::istream &privateStream); // After calling save() (see below) the public and private keys // are available on files. Each party semds its public info to the // other party. Next initiator and peer call 'key' to compute // their shared (symmetric encryption) key, using their own // private data and the other's public data. BigInt const &key(std::string const &peerPublicFileName); // 2 BigInt const &key(std::istream &peerPublicStream); // 3 static BigInt prime(size_t primeLength, bool safe = true, bool progress = false); // The initiator saves the public info (i.e., prime (p), generator // (g),and the initiator's public key (g^k % p)) on basename.pub // and the initiator's secret key (k) on basename.sec void save(std::string const &basename) const; // accessors (may return 0 if not yet determined) // use BigInt's bigEndian or littleEndian functions to obtain // the BigInt's 'sizeInBytes' bytes, returned as a series of // char values. BigInt const &common() const; BigInt const &generator() const; BigInt const &peerPublicKey() const; BigInt const &prime() const; BigInt const &privateKey() const; BigInt const &publicKey() const; private: static int callback(int indicator, int, BN_GENCB *); // params 2, 3 // not used. void checkKeys(EVP_PKEY *keys); static EVP_PKEY_CTX *cptDomainContext(OSSL_PARAM *param); EVP_PKEY *cptDomainKey(EVP_PKEY_CTX *domainCtx, OSSL_PARAM *param); void cptKeys(); static Exception &&exception(); // .ih BigInt getKey(EVP_PKEY *keys, char const *type) const; // type: BigInt const &key(); // 1 static EVP_PKEY *keyPair(EVP_PKEY *domainkey); OSSL_PARAM *osslParamBuild(); }; #include "common.f" #include "generator.f" #include "peerpublickey.f" #include "prime.f" #include "privatekey.f" #include "publickey.f" } // FBB #endif bobcat-6.07.01/diffiehellman/data.cc0000664000175000017500000000012614673353433016126 0ustar frankfrank#include "diffiehellman.ih" char const *DiffieHellman::s_header = "DiffieHellman: "; bobcat-6.07.01/diffiehellman/key1.cc0000664000175000017500000000226714673353433016076 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 // initiator computes // initiator-public = generator^initiator-secret % prime // and sends initiator-public to the peer // peer then computes // common = initiator-public^peer-secret % prime // likewise, the initiator computes: // common = peer-public^initator-secret % prime BigInt const &DiffieHellman::key() { d_common = d_peerPubKey.expModc(d_privKey, d_prime); BigInt qValue{(d_prime - 1) >> 1}; // (prime - 1) / 2 is also prime, as // d_prime should be a safe prime. // Then qValue, according to // RFC 2631, should be so that p = j * q + 1 // is prime. Here j == 2 if ( d_common == 1 || d_common >= d_prime - 1 || d_common.expModc(qValue, d_prime) != 1 ) throw exception() << "shared key is not resistant to the small group attack"; return d_common; } bobcat-6.07.01/diffiehellman/cptdomainkey.cc0000664000175000017500000000113114673353433017701 0ustar frankfrank#include "diffiehellman.ih" EVP_PKEY *DiffieHellman::cptDomainKey(EVP_PKEY_CTX *domainCtx, OSSL_PARAM *param) { EVP_PKEY *domainKey = 0; // Cpt the domain parameter keys. bool ok = EVP_PKEY_fromdata(domainCtx, &domainKey, EVP_PKEY_KEY_PARAMETERS, param) == 1; EVP_PKEY_CTX_free(domainCtx); OSSL_PARAM_free(param); if (not ok) { EVP_PKEY_free(domainKey); throw exception() << "EVP_PKEY_fromdata failed"; } return domainKey; } bobcat-6.07.01/diffiehellman/prime.cc0000664000175000017500000000474314673353433016342 0ustar frankfrank#include "diffiehellman.ih" // static BigInt DiffieHellman::prime(size_t primeLength, bool safe, bool progress) { BN_CTX *ctx = BN_CTX_new(); BigInt ret; BN_GENCB *cb = 0; if (progress) { cb = BN_GENCB_new(); BN_GENCB_set(cb, callback, 0); } bool ok = BN_generate_prime_ex2( const_cast(&ret.bignum()), primeLength, safe, 0, 0, // add, rem progress ? cb : 0, ctx); BN_GENCB_free(cb); BN_CTX_free(ctx); if (not ok) throw exception() << "BN_generate_prime failed"; return ret; } // If add is NULL the returned prime number will have exact bit length // bits with the top most two bits set. // // If ret is not NULL, it will be used to store the number. // // If cb is not NULL, it is used as follows: // // • BN_GENCB_call(cb, 0, i) is called after generating the i-th potential // prime number. // // • While the number is being tested for primality, BN_GENCB_call(cb, 1, // j) is called as described below. // // • When a prime has been found, BN_GENCB_call(cb, 2, i) is called. // // • The callers of BN_generate_prime_ex() may call BN_GENCB_call(cb, i, // j) with other values as described in their respective man pages; see // "SEE ALSO". // // The prime may have to fulfill additional requirements for use in // Diffie-Hellman key exchange: // // If add is not NULL, the prime will fulfill the condition p % add == rem // (p % add == 1 if rem == NULL) in order to suit a given generator. // // If safe is true, it will be a safe prime (i.e. a prime p so that // (p-1)/2 is also prime). If safe is true, and rem == NULL the condition // will be p % add == 3. It is recommended that add is a multiple of 4. // // The random generator must be seeded prior to calling // BN_generate_prime_ex(). If the automatic seeding or reseeding of the // OpenSSL CSPRNG fails due to external circumstances (see RAND(7)), the // operation will fail. The random number generator configured for the // OSSL_LIB_CTX associated with ctx will be used. // int BN_generate_prime_ex2(BIGNUM *ret, int bits, int safe, // const BIGNUM *add, const BIGNUM *rem, BN_GENCB *cb, // BN_CTX *ctx); bobcat-6.07.01/diffiehellman/common.f0000664000175000017500000000011414673353433016342 0ustar frankfrankinline BigInt const &DiffieHellman::common() const { return d_common; } bobcat-6.07.01/diffiehellman/callback.cc0000664000175000017500000000051214673353433016750 0ustar frankfrank#include "diffiehellman.ih" namespace { char info[] = {0, '.', '-', '+'}; } // . is put when a number is tested for primality // - is put when a prime has been found // static int DiffieHellman::callback(int indicator, int, BN_GENCB *) { if (indicator) cout.put(info[indicator]).flush(); return 1; } bobcat-6.07.01/diffiehellman/cptdomaincontext.cc0000664000175000017500000000110414673353433020575 0ustar frankfrank#include "diffiehellman.ih" // static EVP_PKEY_CTX *DiffieHellman::cptDomainContext(OSSL_PARAM *param) try { EVP_PKEY_CTX *domainCtx = EVP_PKEY_CTX_new_from_name(0, "DHX", 0); if (!domainCtx) throw exception() << "EVP_PKEY_CTX_new_from_name failed"; // Initialize the context. if (EVP_PKEY_fromdata_init(domainCtx) <= 0) { EVP_PKEY_CTX_free(domainCtx); throw Exception{} << "EVP_PKEY_fromdata_init failed"; } return domainCtx; } catch (...) { OSSL_PARAM_free(param); throw; } bobcat-6.07.01/diffiehellman/save.cc0000664000175000017500000000160414673353433016155 0ustar frankfrank#include "diffiehellman.ih" // save the prime, the generator, the public key, and the private key void DiffieHellman::save(string const &basename) const try { ofstream out = Exception::factory(basename + ".pub"); out << hex << d_prime << '\n' << d_generator << '\n' << d_pubKey << '\n'; if (not out) throw ".pub"; int fd = open((basename + ".sec").c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); if (fd == -1) // can't open the .sec-file throw ".sec"; OFdStream outSec{ fd, 512 }; outSec << hex << d_privKey << '\n'; } catch (char const *extension) { throw exception() << "could not write " << (extension == ".pub"s ? "public" : "private") << " DH info to " << basename << extension; } bobcat-6.07.01/diffiehellman/peerpublickey.f0000664000175000017500000000012714673353433017721 0ustar frankfrankinline BigInt const &DiffieHellman::peerPublicKey() const { return d_peerPubKey; } bobcat-6.07.01/diffiehellman/key3.cc0000664000175000017500000000100414673353433016064 0ustar frankfrank#include "diffiehellman.ih" BigInt const &DiffieHellman::key(istream &peerPublicStream) { BigInt prime; BigInt generator; if (not(peerPublicStream >> hex >> prime >> generator >> d_peerPubKey)) throw exception() << "could not read the peer's public key"; if (prime != d_prime || generator != d_generator) throw exception() << "the peer's prime and/or generator differ from " "the current values"; return key(); } bobcat-6.07.01/diffiehellman/privatekey.f0000664000175000017500000000012114673353433017233 0ustar frankfrankinline BigInt const &DiffieHellman::privateKey() const { return d_privKey; } bobcat-6.07.01/diffiehellman/diffiehellman1.cc0000664000175000017500000000032214673353433020063 0ustar frankfrank#include "diffiehellman.ih" DiffieHellman::DiffieHellman(size_t primeLength, size_t generator, bool progress) : DiffieHellman(prime(primeLength, true, progress), generator) {} bobcat-6.07.01/diffiehellman/icmconf0000664000175000017500000000041414673353433016247 0ustar frankfrank#define LIBRARY "diffiehellman" #include "../icmconf.lib" //#include "../icmconf" // //#undef CXXFLAGS //#define CXXFLAGS "--std=c++2a " ${AUXFLAGS} " -isystem " \ // "/home/frank/git/bobcat/src/bobcat/tmp -Wall -O2" bobcat-6.07.01/diffiehellman/diffiehellman2.cc0000664000175000017500000000074214673353433020072 0ustar frankfrank#include "diffiehellman.ih" DiffieHellman::DiffieHellman(BigInt const &prime, size_t generator) { if (prime.size() < MIN_PRIME_SIZE) throw exception() << "the prime must be at least " << MIN_PRIME_SIZE << " bits long"; d_prime = prime; d_generator = generator; cptKeys(); // cpt d_keys containing the private and // public keys, using d_prime and d_generator } bobcat-6.07.01/diffiehellman/keypair.cc0000664000175000017500000000150314673353433016661 0ustar frankfrank#include "diffiehellman.ih" // static EVP_PKEY *DiffieHellman::keyPair(EVP_PKEY *domainkey) { EVP_PKEY_CTX *keyCtx = EVP_PKEY_CTX_new_from_pkey(0, domainkey, 0); if (!keyCtx) throw Exception{} << "EVP_PKEY_CTX_new_from_pkey failed"; if (EVP_PKEY_keygen_init(keyCtx) <= 0) throw Exception{} << "EVP_PKEY_CTX_keygen_init failed"; EVP_PKEY *keys = 0; if (EVP_PKEY_generate(keyCtx, &keys) <= 0) throw Exception{} << "EVP_PKEY_generate failed"; EVP_PKEY_CTX_free(keyCtx); BIGNUM *tmp = 0; if (not EVP_PKEY_get_bn_param(keys, "pub", &tmp)) throw Exception{} << "get_bn_param pub fails"; BN_free(tmp); tmp = 0; if (not EVP_PKEY_get_bn_param(keys, "priv", &tmp)) throw Exception{} << "get_bn_param priv fails"; BN_free(tmp); return keys; } bobcat-6.07.01/diffiehellman/checkkeys.cc0000664000175000017500000000062114673353433017166 0ustar frankfrank#include "diffiehellman.ih" void DiffieHellman::checkKeys(EVP_PKEY *keys) try { auto *ctx = EVP_PKEY_CTX_new(keys, 0); if (ctx == 0) throw "EVP_PKEY_CTX_new failed for keys"; int ret = EVP_PKEY_check(ctx); EVP_PKEY_CTX_free(ctx); if (ret != 1) throw "EVP_PKEY_check failed"; } catch (char const *msg) { EVP_PKEY_free(keys); throw exception() << msg; } bobcat-6.07.01/diffiehellman/prime.f0000664000175000017500000000011214673353433016164 0ustar frankfrankinline BigInt const &DiffieHellman::prime() const { return d_prime; } bobcat-6.07.01/diffiehellman/key2.cc0000664000175000017500000000026614673353433016074 0ustar frankfrank#include "diffiehellman.ih" BigInt const &DiffieHellman::key(std::string const &peerFileName) { ifstream in = Exception::factory(peerFileName); return key(in); } bobcat-6.07.01/diffiehellman/diffiehellman4.cc0000664000175000017500000000055714673353433020100 0ustar frankfrank#include "diffiehellman.ih" DiffieHellman::DiffieHellman(istream &publicStream, istream &privateStream) { if (not(publicStream >> hex >> d_prime >> d_generator >> d_pubKey)) exception() << "can't read the public data file"; BigInt privKey; if (not(privateStream >> hex >> d_privKey)) exception() << "can't read the private data file"; } bobcat-6.07.01/diffiehellman/diffiehellman3.cc0000664000175000017500000000044614673353433020074 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-6.07.01/diffiehellman/diffiehellman.ih0000664000175000017500000000176714736315237020033 0ustar frankfrank// see also man evp_pkey-dh #include "diffiehellman" #include #include #include #include #include #include #include #include "../ofdstream/ofdstream" using namespace std; using namespace FBB; // static inline Exception &&DiffieHellman::exception() { return Exception{} << s_header; } void createKeys(char *nr, // create private and public keys [0 or 1] BigInt const &prime, BigInt const &generator, EVP_PKEY *domainKey, EVP_PKEY *keys); // OSSL_PARAM *param, EVP_PKEY_CTX *domainKeyCtx); //EVP_PKEY *rawKeys(BigInt const &prime, BigInt const &generator, // OSSL_PARAM *param, EVP_PKEY_CTX *domainKeyCtx); //EVP_PKEY *keyPair(EVP_PKEY *domainkey); // write secret/public // priv or pub void writeKey(char nr, EVP_PKEY *keys, char const *type); bobcat-6.07.01/diffiehellman/cptkeys.cc0000664000175000017500000000150214673353433016676 0ustar frankfrank#include "diffiehellman.ih" // cpt keys containing the private and public keys // writekey() with "pub" or "priv" used to write the keys // getKey() with "pub" or "priv" is used to obtain the public/private keys void DiffieHellman::cptKeys() { // Cpt OSSL_PARAM (man ossl_param_bld) OSSL_PARAM *param = osslParamBuild(); // Cpt the context. EVP_PKEY_CTX *domainCtx = cptDomainContext(param); EVP_PKEY *domainKey = cptDomainKey(domainCtx, param); EVP_PKEY *keys = keyPair(domainKey); EVP_PKEY_free(domainKey); // char nr = '0'; // createKeys(&nr, d_prime, d_generator, domainKey, keys); checkKeys(keys); d_pubKey = getKey(keys, "pub"); d_privKey = getKey(keys, "priv"); EVP_PKEY_free(keys); } bobcat-6.07.01/diffiehellman/publickey.f0000664000175000017500000000011714673353433017044 0ustar frankfrankinline BigInt const &DiffieHellman::publicKey() const { return d_pubKey; } bobcat-6.07.01/diffiehellman/generator.f0000664000175000017500000000012214673353433017037 0ustar frankfrankinline BigInt const &DiffieHellman::generator() const { return d_generator; } bobcat-6.07.01/diffiehellman/getkey.cc0000664000175000017500000000063514673353433016512 0ustar frankfrank#include "diffiehellman.ih" BigInt DiffieHellman::getKey(EVP_PKEY *keys, char const *type) const // type: "pub" or "priv" { BIGNUM *bignum = 0; if (not EVP_PKEY_get_bn_param(keys, type, &bignum)) { EVP_PKEY_free(keys); throw exception() << "can't extract the " << type << " key"; } BigInt key{ bignum }; BN_free(bignum); return key; } bobcat-6.07.01/diffiehellman/driver/0000775000175000017500000000000014737552575016213 5ustar frankfrankbobcat-6.07.01/diffiehellman/driver/build0000775000175000017500000000045314673353433017231 0ustar frankfrank#!/bin/bash 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 \ -L../tmp -ldiffiehellman ${LIBS} -s" echo ${CMD} ${CMD} bobcat-6.07.01/diffiehellman/driver/driver.cc0000664000175000017500000000372714736772255020024 0ustar frankfrank #include #include #include #include using namespace FBB; using namespace std; int main(int argc, char **argv) try { if (argc == 1) { cout << "1: create prime and generator, write to 'params'\n" "2: create secret and public parts, arg 2: 0 or 1,\n" " write secret and public parts to .sec and " ".pub\n" "3: create common key arg 2: 0 or 1,\n" " 0: write common0 using 0.pub, 0.sec and 1.pub\n" " 1: write common1 using 1.pub, 1.sec and 0.pub\n" ; return 0; } switch (*argv[1]) // using generator == 5 { case '1': { ofstream out = Exception::factory("params"); out << hex << DiffieHellman::prime(1024, true, true) << '\n'; } break; case '2': { char *nr = argv[2]; if (nr == 0 || "01"s.find(*nr) == string::npos) throw Exception{} << "mode '2' needs 0 or 1 as 2nd argument"; ifstream in = Exception::factory("params"); BigInt prime; in >> hex >> prime; DiffieHellman dh{ prime }; dh.save(nr); } break; case '3': { char *nr = argv[2]; if (nr == 0 || "01"s.find(*nr) == string::npos) throw Exception{} << "mode '3' needs 0 or 1 as 2nd argument"; DiffieHellman dh{ nr + ".pub"s, nr + ".sec"s }; cout << "common key computed by " << nr << ":\n" << hex << dh.key((nr[0] == '0' ? '1' : '0') + ".pub"s) << '\n'; } break; default: throw Exception{} << "undefined action `" << *argv[1] <<'\''; } } catch (std::exception const &exc) { std::cout << exc.what() << '\n'; } bobcat-6.07.01/diffiehellman/osslparambld.cc0000664000175000017500000000177114673353433017707 0ustar frankfrank#include "diffiehellman.ih" // called from cptdomainkey.cc // Cpt OSSL_PARAM_BLD (man ossl_param_bld) OSSL_PARAM *DiffieHellman::osslParamBuild() { OSSL_PARAM_BLD *paramBld = OSSL_PARAM_BLD_new(); if (!paramBld) throw exception() << "OSSL_PARAM_BLD_new failed"; if ( // Assign d_prime and d_generator. not OSSL_PARAM_BLD_push_BN(paramBld, "p", &d_prime.bignum()) || not OSSL_PARAM_BLD_push_BN(paramBld, "g", &d_generator.bignum()) ) { OSSL_PARAM_BLD_free(paramBld); throw exception() << "OSSL_PARAM_BLD_push_BN failed"; } // Convert to OSSL_PARAM. OSSL_PARAM *param = OSSL_PARAM_BLD_to_param(paramBld); OSSL_PARAM_BLD_free(paramBld); // see man ossl_param_bld: // OK after 'to_param' if (!param) throw exception() << "OSSL_PARAM_BLD_to_param failed"; return param; } bobcat-6.07.01/digestbuf/0000775000175000017500000000000014736742656014105 5ustar frankfrankbobcat-6.07.01/digestbuf/digestbuf1.cc0000664000175000017500000000064114673353433016441 0ustar frankfrank#include "digestbuf.ih" DigestBuf::DigestBuf(char const *digestName, size_t bufsize) : EoiBuf(bufsize), d_ctx(0) { OpenSSL_add_all_digests(); d_md = EVP_get_digestbyname(digestName); if (!d_md) { if (digestName == 0) digestName = "** unspecified digest digestName **"; throw Exception{} << "DigestBuf `" << digestName << "' not available"; } reset(); } bobcat-6.07.01/digestbuf/overflow.cc0000664000175000017500000000032414673353433016245 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-6.07.01/digestbuf/reset.cc0000664000175000017500000000031514673353433015524 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-6.07.01/digestbuf/digestbuf0000664000175000017500000000144614673353433016000 0ustar frankfrank#ifndef INCLUDED_BOBCAT_DIGESTBUF_ #define INCLUDED_BOBCAT_DIGESTBUF_ #include #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 *digestName, 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-6.07.01/digestbuf/hash.cc0000664000175000017500000000013014673353433015320 0ustar frankfrank#include "digestbuf.ih" string const &DigestBuf::hash() const { return d_digest; } bobcat-6.07.01/digestbuf/icmconf0000664000175000017500000000007714673353433015441 0ustar frankfrank#define LIBRARY "digestbuf" #include "../icmconf" bobcat-6.07.01/digestbuf/eoi.f0000664000175000017500000000005514673353433015017 0ustar frankfrankinline void DigestBuf::eoi() { eoi_(); } bobcat-6.07.01/digestbuf/operatorinsert.cc0000664000175000017500000000041014673353433017456 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-6.07.01/digestbuf/eoi.cc0000664000175000017500000000062514673353433015162 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-6.07.01/digestbuf/driver/0000775000175000017500000000000014737552575015400 5ustar frankfrankbobcat-6.07.01/digestbuf/driver/build0000775000175000017500000000156714673353433016425 0ustar frankfrank#!/bin/bash # # g++ -I. --std=c++20 -O2 -Wall -o driver driver.cc -lssl -lbobcat \ # -L../../ohexbuf/tmp -L../tmp -lhmacbuf -lohexbuf # tput clear LIBS=" -lbobcat -lcrypto" sed 's__"../digestbuf"_' driver.cc > src.cc GPP="g++ `cat ../../c++std`" # Using the standard bobcat library CMD="$GPP -o driver -Wall driver.cc ${LIBS} -s" # Using the library in ../tmp/ and libbobcat #CMD="$GPP -o driver -Wall src.cc -L../tmp -ldigestbuf ${LIBS} -s" # Using the library in ../tmp/ and bobcat as /tmp/libbob.a # CMD="$GPP -o driver -Wall src.cc -L../tmp -lhmacbuf -L /tmp -lbob -lcrypto -s" # # Using tmp libraries and bobcat # CMD="$GPP -o driver -Wall -I../tmp src.cc \ # -L../tmp -ldigestbuf \ # -L../../ohexbuf/tmp -lohexbuf \ # -L../../eoibuf/tmp -leoibuf \ # -L../../eoi/tmp -leoi \ # ${LIBS} -s" echo ${CMD} ${CMD} rm src.cc bobcat-6.07.01/digestbuf/driver/driver.cc0000664000175000017500000000102414673353433017166 0ustar frankfrank#include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) try { DigestBuf digestbuf(argc == 1 ? "sha256" : 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-6.07.01/digestbuf/digestbuf.ih0000664000175000017500000000023014736315237016365 0ustar frankfrank#include "digestbuf" #include #include #include #include "../ohexbuf/ohexbuf" using namespace std; using namespace FBB; bobcat-6.07.01/documentation/0000775000175000017500000000000014673353433014771 5ustar frankfrankbobcat-6.07.01/documentation/examples/0000775000175000017500000000000014673353433016607 5ustar frankfrankbobcat-6.07.01/documentation/examples/sockets/0000775000175000017500000000000014673353433020262 5ustar frankfrankbobcat-6.07.01/documentation/examples/sockets/forkserver/0000775000175000017500000000000014673353433022452 5ustar frankfrankbobcat-6.07.01/documentation/examples/sockets/forkserver/icmconf0000664000175000017500000000121114673353433024006 0ustar frankfrank#define CLS //#define LIBRARY "modules" #define MAIN "main.cc" #define SOURCES "*.cc" #define OBJ_EXT ".o" #define SHAREDREQ "" #define TMP_DIR "tmp" //#define USE_ALL "a" #define USE_ECHO ON // #define USE_VERSION #define CXX "g++" #define CXXFLAGS " --std=c++2a -Wall -O2" \ " -fdiagnostics-color=never " #define IH ".ih" //#define PRECOMP "-x c++-header" #define REFRESH #define LDFLAGS "" #define ADD_LIBRARIES "bobcat" #define ADD_LIBRARY_PATHS "" #define DEFCOM "program" bobcat-6.07.01/documentation/examples/sockets/forkserver/main.cc0000664000175000017500000000310414673353433023703 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-6.07.01/documentation/examples/sockets/forkserver/main.ih0000664000175000017500000000035514673353433023723 0ustar frankfrank#include #include #include #include #include #include #include #include "handler/handler.h" using namespace std; using namespace FBB; bobcat-6.07.01/documentation/examples/sockets/forkserver/handler/0000775000175000017500000000000014673353433024067 5ustar frankfrankbobcat-6.07.01/documentation/examples/sockets/forkserver/handler/chidlprocess.cc0000664000175000017500000000110614673353433027056 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-6.07.01/documentation/examples/sockets/forkserver/handler/handler.h0000664000175000017500000000064014673353433025655 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-6.07.01/documentation/examples/sockets/forkserver/handler/handler.ih0000664000175000017500000000020314673353433026021 0ustar frankfrank#include "handler.h" #include #include #include using namespace std; using namespace FBB; bobcat-6.07.01/documentation/examples/sockets/forkserver/CLASSES0000664000175000017500000000001014673353433023461 0ustar frankfrankhandler bobcat-6.07.01/documentation/examples/sockets/README0000664000175000017500000000616014673353433021145 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-6.07.01/documentation/examples/sockets/server/0000775000175000017500000000000014673353433021570 5ustar frankfrankbobcat-6.07.01/documentation/examples/sockets/server/server.cc0000664000175000017500000000240314673353433023404 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-6.07.01/documentation/examples/sockets/forkserver2/0000775000175000017500000000000014673353433022534 5ustar frankfrankbobcat-6.07.01/documentation/examples/sockets/forkserver2/icmconf0000777000175000017500000000000014673353433030034 2../forkserver/icmconfustar frankfrankbobcat-6.07.01/documentation/examples/sockets/forkserver2/main.cc0000664000175000017500000000350414673353433023771 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-6.07.01/documentation/examples/sockets/forkserver2/main.ih0000777000175000017500000000000014673353433027646 2../forkserver/main.ihustar frankfrankbobcat-6.07.01/documentation/examples/sockets/forkserver2/handler/0000775000175000017500000000000014673353433024151 5ustar frankfrankbobcat-6.07.01/documentation/examples/sockets/forkserver2/handler/chidlprocess.cc0000664000175000017500000000124214673353433027141 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-6.07.01/documentation/examples/sockets/forkserver2/handler/handler.h0000777000175000017500000000000014673353433033753 2../../forkserver/handler/handler.hustar frankfrankbobcat-6.07.01/documentation/examples/sockets/forkserver2/handler/handler.ih0000664000175000017500000000023714673353433026112 0ustar frankfrank#include "handler.h" #include #include #include #include using namespace std; using namespace FBB; bobcat-6.07.01/documentation/examples/sockets/forkserver2/CLASSES0000777000175000017500000000000014673353433027172 2../forkserver/CLASSESustar frankfrankbobcat-6.07.01/documentation/examples/sockets/client2/0000775000175000017500000000000014673353433021622 5ustar frankfrankbobcat-6.07.01/documentation/examples/sockets/client2/client2.cc0000664000175000017500000000276714673353433023505 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-6.07.01/documentation/examples/sockets/client/0000775000175000017500000000000014673353433021540 5ustar frankfrankbobcat-6.07.01/documentation/examples/sockets/client/client.cc0000664000175000017500000000245314673353433023331 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-6.07.01/documentation/man/0000775000175000017500000000000014746121307015536 5ustar frankfrankbobcat-6.07.01/documentation/man/log.yo0000664000175000017500000003563514673353433016712 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) or using the function operator in combination with the tt(str) member (see the the members tt(operator()) and tt(str)). By default all information that is inserted into a tt(Log) object is logged. Objects of the tt(level) class (cf. bf(level)(3bobcat)) can be inserted specifying insertion `forces' for the information that is subsequently inserted into tt(Log) objects. Only if these`forces' exceed the tt(Log) object's insertion `resistances' (see the member tt(setLevel)) then the information is logged. A single log-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). Alternatively information may be logged using category-selector characters. The member tt(str(std::string const &active)) defines the characters that can be used to define a non-hierarchical logging process. E.g., tt(str("abc")) defines the log-identifying characters tt('a', 'b',) and tt('c') which can then be used to define log-statements for each of those categories. These log-identifying characters may be redefined, activating only those log-statements whose identifying characters were specified in the last call of the tt(str) member. Although hierarchical and non-hierarchical logging can both be used in a single program, they operate in a mutually exclusive way: once hierarchical logging is defined the non-hierarchical categories are erased, and once non-hierarchical categories are defined the hierarchical resistance level is set to its maximum value, effectively suppressing hierarchical logging. 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() const) 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. itb(std::string const &str() const) The currently set of characters that can be specified by tt(Log's) function call operator to insert a log-entry is returned. By default no characters are specified; itb(void str(std::string const &chars)) The argument to this member is a tt(std::string) defining the characters that can be specified by tt(Log's) function call operator to insert a log-entry. If the function call operator specifies a character which is not specified in tt(chars) then that log message is ignored. By default no characters are specified. ) 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 OPERATORS) itemization( itb(Log &operator()(char ch)) If the function's argument is found in the characters specified at the tt(str) member subsequent insertions until (including) inserting tt(std::endl) or the tt(fnl) or tt(FATAL LogManipulator) are logged. If the function's argument is not found in the characters specified at the tt(str) member then subsequent insertions are ignored. By calling this member hierarchical insertions are suppressed until the tt(setLevel) member is called; itb(Log &operator<<(Log &, LogManipulator)) This operator inserts a tt(LogManipulator) into a tt(Log) object. When inserting tt(FBB::FATAL) an tt(FBB::Exception) is thrown; when inserting tt(FBB::nl) the line is terminated, and the next insertion won't start with a time stamp; when inserting tt(FBB::fnl) the line is terminated, and the next insertion will start with a time stamp (if applicable). After calling this insertion operator with the tt(FATAL) or tt(fnl LogManipulator) value category-based insertions are suppressed until the function-call operator is called; itb(Log &operator<<(Log &log, Type const &type)) This operator is defined as a template, where tt(Type) represents any type that can be inserted into a tt(std::ostream). The value tt(type) is inserted into the tt(Log) object; itb(Log &operator<<(Log &log, Type &(*fun)(Type &type))) In this operator tt(fun) represents the standard tt(ostream) and tt(ios_base) manipulators, allowing the insertion of manipulators like tt(std::endl) and tt(std::setw) into tt(Log) objects; itb(std::ostream &::operator<<(std::ostream &str, FBB::LogManipulator)) This operator is defined outside of the tt(FBB) namespace. It is kept for backward compatibility with previous bf(bobcat) versions, and calls tt(operator<<(Log, LogManipulatr)) when tt(&str) can dynamically be casted to a tt(Log *). If not, then the operator performs no actions. ) 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), bf(syslogstream)(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-6.07.01/documentation/man/ofdstream.yo0000664000175000017500000000366114673353433020107 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 an tt(OFdBuf) 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-6.07.01/documentation/man/sharedbuf.yo0000664000175000017500000001670414673353433020070 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::SharedBuf)(3bobcat)(_CurYrs_) (libbobcat-dev__CurVers_) (Shared memory streambuf) 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-6.07.01/documentation/man/a2x.yo0000664000175000017500000001143014673353433016606 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::A2x)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Text to X convertor) 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-6.07.01/documentation/man/sharedblock.yo0000664000175000017500000000341214673353433020376 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-6.07.01/documentation/man/process.yo0000664000175000017500000010020014673353433017564 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)(2) 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(proc)(3bobcat), bf(sh)(1), bf(stdextractor)(3bobcat). manpagebugs() None reported includefile(include/trailer) bobcat-6.07.01/documentation/man/cgi.yo0000664000175000017500000003505614673353433016670 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-6.07.01/documentation/man/ofilterbuf.yo0000664000175000017500000001226714673353433020266 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-6.07.01/documentation/man/stdextractor.yo0000664000175000017500000001046414673353433020650 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 tt(StdExtractor) 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-6.07.01/documentation/man/tempstream.yo0000664000175000017500000000417414673353433020304 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-6.07.01/documentation/man/socketbase.yo0000664000175000017500000000641114673353433020242 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-6.07.01/documentation/man/exec.yo0000664000175000017500000000562514673353433017051 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 tt(Exec) 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-6.07.01/documentation/man/ofdbuf.yo0000664000175000017500000001326414673353433017370 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. itb(void warn(bool on)) When tt(on == true) a warning is written to the standard error stream when its tt(sync) member returns -1. If tt(warn) is not explicitly called tt(on == true) is used. ) 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-6.07.01/documentation/man/exception.yo0000664000175000017500000002551214673353433020120 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Exception)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (insertable exception class) 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-6.07.01/documentation/man/include/0000775000175000017500000000000014736236147017171 5ustar frankfrankbobcat-6.07.01/documentation/man/include/trailer.yo0000664000175000017500000000127614736236147021212 0ustar frankfrank manpagesection(BOBCAT PROJECT FILES) itemization( itt(https://fbb-git.gitlab.io/bobcat/): gitlab project page; ) Debian Bobcat project files: itemization( itt(libbobcat6): debian package containing the shared library, changelog and copyright note; itt(libbobcat-dev): debian package containing the static library, headers, manual pages, and developer info; ) 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-6.07.01/documentation/man/include/namespace.yo0000664000175000017500000000024714673353433021477 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-6.07.01/documentation/man/include/header.yo0000664000175000017500000000132614673353433020772 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-6.07.01/documentation/man/multibuf.yo0000664000175000017500000001556314673353433017756 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-6.07.01/documentation/man/ldc.yo0000664000175000017500000001524414673353433016665 0ustar frankfrankincludefile(include/header) COMMENT(replace 'classname' by the name of the new class) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::LDC)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Convert (large) digital values to characters) manpagename(FBB::LDC)(Converts (large) digital values to characters) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() Objects of the class tt(LDC) (Large Digital Converter) convert (large) digital values (like values handled by the class tt(BigInt) (cf. bf(bigint)(3bobcat))) to character representations using radices from 2 through 36. For radices larger than 10 letters are used, using tt(a) through tt(z) to represent the (decimal) values 10 through 36. When specifying radices outside of this range an exception is thrown. Alternatively, the digits of the converted number can be provided in a tt(std::string) argument, where the string's first character (at index 0) is used for value 0, the next character for value 1, etc., until the string's last character. In that case the string's length defines the number system that is used for converting the (large) digital value. Usually the first 10 characters will be tt("0123456789"), but LDC doesn't enforce that. Instead, any series of characters can be specified, in which case the character at index tt(idx) is used to represent value tt(idx) in the converted value string. E.g., when specifying tt("abcdefghij") the hexadecimal value tt("deadbeef") is converted to tt("dhdfjciffj") instead of tt("3735928559"), which is the normally used decimal digit representation. Digit strings must at least contain two characters or an exception is thrown. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(CONSTRUCTORS) itemization( itb(LDC()) The default constructor initializes its value to 0; itb(LDC(std::string const &hexNr, size_t radix = 10)) The bytes of the string tt(hexNr) contains the character representation of a hexadecimal value, which is converted to its equivalent representation using the tt(radix) number system. The string tt(hexNr) should not begin with tt(0x), but its first character should be the value's most significant digit. E.g., tt(LDC ldc{ "12345" }) is converted to decimal 74565 (in this example tt("12345") is first converted to a tt(std::string), which is then passed on to tt(ldc's) constructor). tt(hexNr) may not be empty or an exception is thrown; itb(LDC(std::string const &hexNr, std::string const &digits)) Same as the previous constructor, but the number system is inferred from tt(digits's) length, using its first character to represent value 0, and its last character to represent the final digit of the inferred number system; itb(LDC(size_t nBytes, char const *bytes, size_t radix = 10)) The bytes of the string tt(bytes) contains the character representation of a hexadecimal value, which is converted to its equivalent representation using tt(radix). The string tt(bytes) should not begin with tt(0x), but its first character should be the value's most significant digit. E.g., tt(LDC{ 5, "12345" }) is converted to decimal 74565. tt(nBytes) must be at least 1 or an exception is thrown; itb(LDC(size_t nBytes, char const *bytes, std::string const &digits)) Same as the previous constructor, but the number system and the digit characters are inferred from tt(digits); itb(LDC(BigInt const &bigInt, size_t radix = 10)) tt(BigInt's) value is converted to its equivalent representation using tt(radix); itb(LDC(BigInt const &bigInt, std::string const &digits)) Same as the previous constructor, but the number system and the digit characters are inferred from tt(digits). ) Copy and move constructors (and assignment operators) are available. manpagesection(OVERLOADED OPERATORS) In addition to the standard copy- and move-assignment operators the following operators are available: itemization( itb(LDC &operator=(std::string const &hexNr)) The operator's rhs is the character representation of a hexadecimal number, which is assigned to the tt(LDC) object. The object converts tt(hexNr) to its decimal representation (see also the members tt(set), below).nl() Example: verb( LDC ldc; // initialized with some value ldc = "12345"; // assign a new value cout << ldc << '\n' // displays 74655 ) The rhs value may not be empty or an exception is thrown; itb(std::string operator()(size_t power, char sep = '\'') const) The converted value is returned using separator tt(sep) before each multiple of tt(power) digits. E.g., when tt(ldc) contains the converted value tt(3735928559) then tt(ldc(3)) returns the string tt(3.735.928.559). ) manpagesection(FREE FUNCTION IN THE FBB NAMESPACE) itemization( itb(std::ostream &operator<<(std::ostream &out, LDC const &ldc)) The insertion operator inserts the converted value into tt(out), returning tt(out). ) manpagesection(MEMBER FUNCTIONS) itemization( itb(void set(std::string const &hexNr, size_t radix = 10)) The tt(LDC) object's converted value is set to the hexadecimal value tt(hexNr), converted to number system tt(radix). tt(hexNr) may not be empty or an exception is thrown ; itb(void set(std::string const &hexNr, std::string const &digits)) Same as the previous member, but converting tt(hexNr) to the number system and number characters defined by tt(digits); itb(void set(size_t nBytes, char const *bytes, size_t radix = 10)) The tt(LDC) object's converted value is set to the hexadecimal value stored in the tt(nBytes) bytes of tt(bytes), converted to number system tt(radix). tt(nBytes) must be at least 1 or an exception is thrown; itb(void set(size_t nBytes, char const *bytes, std::string const &digits)) Same as the previous member, but converting tt(bytes) to the number system and number characters defined by tt(digits); itb(std::string const &str() const) The tt(LDC) object's converted value is returned; itb(void swap(LDC &other)) The tt(other) LDC object and the current tt(LDC) object are swapped. ) manpagesection(EXAMPLE) verbinclude(../../ldc/driver/example.cc) manpagefiles() em(bobcat/ldc) - defines the class interface manpageseealso() bf(bobcat)(7) manpagebugs() None Reported. includefile(include/trailer) bobcat-6.07.01/documentation/man/cidr.yo0000664000175000017500000001317114673353433017041 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-6.07.01/documentation/man/readlinebuf.yo0000664000175000017500000002752514737536733020417 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: -lbobcat -lreadline 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)(3bobcat), bf(readlinestream)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-6.07.01/documentation/man/pipe.yo0000664000175000017500000002454614673353433017065 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) object 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 when, tt(initialize == false), it initializes its read and write file descriptors to -1. This constructor may be used by classes that define tt(Pipe) data members which can only open their pipes after the object has been constructed. Having constructing a tt(Pipe obj{ false }) object it can be associated with an open pipe using tt(obj = Pipe{}). or tt(obj.reset()). When passing the argument tt(true) it initializes its pipe (cf. bf(pipe)(2)). ) 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(OVERLOADED OPERATOR) itemization( itb(Pipe &operator=(Pipe &&tmp)) The overloaded move assignment operator closes the current pipe and moves tt(tmp's) pipes to the current tt(Pipe) object. ) 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). The original read file descriptor and the pipe's write file descriptor are closed. 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. The original read file descriptor and the pipe's write file descriptor are closed. 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(int readOnlyFd()) Same as the previous member, but sets the internally used read file descriptor to -1 (this member can be used to, e.g., pass the read file descriptor to another object which eventually closes the pipe's reading end). itb(void reset()) Closes the the current pipe and reopens it with new pipe read and write destriptors. itb(void reset(int const *fds)) Closes the the current pipe and reopens it with the read and write file destriptors provided by the first two elements of tt(fds). 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. The original write file descriptor and the pipe's read file descriptor are closed. 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. The original write file descriptor and the pipe's read file descriptor are closed. itb(int writeOnly()) Closes the reading end of the pipe, returns the writing end's file descriptor. itb(int writeOnlyFd()) Same as the previous member, but sets the internally used write file descriptor to -1 (this member can be used to, e.g., pass the write file descriptor to another object which eventually closes the pipe's writing end). ) 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. itb(int *fd()) Returns a pointer to the two file descriptors (respectively READ and WRITE) currently used by the tt(Pipe) object. ) manpagesection(EXAMPLE) verb( #include #include #include #include #include #include using namespace std; using namespace FBB; int main() { Pipe pipe; // construct a pipe cout << "Read file descriptor: " << pipe.readFd() << "\n" "Write file descriptor: " << pipe.writeFd() << endl; int pid = fork(); if (pid == -1) return 1; if (pid == 0) //child { pipe.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; } pipe.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 a tt(Pipe) object goes out of scope, no bf(close)(2) operation is performed on the pipe's ends. If the pipe should be closed by the destructor, derive a class from bf(Pipe)(3bobcat), whose destructor performs the required closing-operation. includefile(include/trailer) bobcat-6.07.01/documentation/man/signal.yo0000664000175000017500000001300514673353433017371 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-6.07.01/documentation/man/hmacbuf.yo0000664000175000017500000001376714673353433017540 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. All the message digest and cipher algorithms defined by the OpenSSL library that can be selected by name, may be used in combination with tt(HMacBuf) objects. For the currently supported message digest algorithms issue the command verb( openssl list -digest-commands ) For the currently supported message cipher algorithms issue the command verb( openssl list -cipher-commands ) The defaults used by tt(HMacBuf) constructors are the tt(sha256) digest algorithm and the tt(aes-128-cbc) cipher algorithm. includefile(include/namespace) manpagesection(INHERITS FROM) bf(std::streambuf) manpagesection(CONSTRUCTORS) itemization( itb(HMacBuf()) The default constructor defines a tt(HmacBuf) object. It can be used once a non-default constructed tt(HMacBuf) object has been move-assigned to it; itb(HMacBuf(HMacBuf &&tmp)) The move constructor initialized a tt(HmacBuf) object by moving tt(tmp) into the current tt(HMacBuf) object; itb(HMacBuf(std::string const &key, char const *digest, size_t bufsize)) This constructor initializes the streambuf, setting it up for the message digest algorithm specified with tt(digest). 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 key's length must be 16 characters. An exception is thrown if an empty key is specified. The tt(bufsize) argument specifies the size (in bytes) of the internal buffer used by tt(HMacBuf) to store incoming characters temporarily. A value of 1024 should be OK for all normal cases; itb(HMacBuf(std::string const &key, char const *cipher = "aes-128-cbc", char const *digest = "sha256", size_t bufsize = 1024)) Like the previous constructor, but this one offers defaults for the cipher and digest algorithms and buffer size. When specifying another cipher algorithm the key length must match the cipher requirement. Usually the cipher's name contains a number (like 128), which can be divided by 8 to obtain the required key length of fixed-key length ciphers. ) manpagesection(OVERLOADED OPERATOR) itemization( itb(HMacBuf &operator=(HMacBuf &&rhs)) The move assignment operator moves the tt(rhs HMacBuf) object into the current object; 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(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')). When called from a default constructed tt(HMacBuf) object an empty string is returned; 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. No action is performed When called from a default constructed 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. tt(eoi) can also be called as a function, receiving the stream that uses the tt(HMacBuf) as its tt(streambuf), but it must be called either way as the tt(HMacBuf) object itself cannot decide whether all information to compute the digest for has yet been received or not. The general approach for computing a message hmac is therefore: verb( 1. create a HMacBuf object 2. use it to create a std::ostream object 3. insert information into the ostream object 4. call the HMacBuf object's eoi() member or insert eoi into the ostream object 5. obtain/process the hash value from the HMacBuf object. ) ) 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-6.07.01/documentation/man/logbuf.yo0000664000175000017500000001413314673353433017375 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-6.07.01/documentation/man/ibase64stream.yo0000664000175000017500000000476114673353433020576 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-6.07.01/documentation/man/readlinestream.yo0000664000175000017500000002666314737536760021140 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: -lbobcat -lreadline 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)(3bobcat), bf(readlinehistory)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-6.07.01/documentation/man/binarysearch.yo0000664000175000017500000001012714673353433020570 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-6.07.01/documentation/man/csvtable.yo0000664000175000017500000006542314673353433017732 0ustar frankfrankincludefile(include/header) 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 tt(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 tt(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. tt(CSVTable) objects always use the widest column specifications and alignment types that were specified last. When inserting elements into tt(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 still 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). E.g., verb( CSVTable tab; ... tab << 1 << 2; // two elements in this row tab << "one" << "two" << 3; // three elements in this row ) tt(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. tt(CSVTabDef) handles the table's column definitions, tt(CSVTabIns) handles insertions into the table elements. They offer 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 tt(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(FBB::FMT) objects are returned by several free functions (like tt(left), described below in section bf(FREE FUNCTIONS)), and tt(FMT) defines the enumeration tt(Align) (see the next section) specifying alignment types. tt(FMT) objects are internally used by tt(CSVTable) objects. A tt(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. tt(FMT) objects can be inserted into tt(std::ostream) objects showing its characteristics. tt(FMT) provides 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 field width in number of characters; ) The static member tt(char const *FMT::align(FMT::Align value)) returns the textual label corresponding to tt(value). manpagesection(ALIGN ENUM) The tt(enum FMT::Align) defines values indicating the alignment types of the table's columns: itemization( itb(FMT::Align::CENTER) The inserted information in the column is centered; itb(FMT::Align::LEFT) The inserted information is left-aligned; itb(FMT::Align::RIGHT) The inserted information is right-aligned (used by default); ) In addition, when inserting horizontal lines, the value tt(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 receiving the table can be altered using 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 tt(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 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 move 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 tt(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 tt(CSVTabDef). The member tt(fmt()) (cf. section bf(MEMBER FUNCTIONS)) returns a tt(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. tt(FMT) objects inserted into tt(CSVTabDef) objects must have been returned by tt(center, left) or tt(right) (see section bf(FREE FUNCTIONS), below), or an exception will be thrown. When redefining column specifications (e.g., when inserting tt(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); ) 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 table 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 tt(CSVTabIns) objects. tt(CSVTable's) conversion operator tt(operator CSVTabIns()) described below returns a tt(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. 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)) tt(FMT) objects are returned by several free functions defined in the tt(FBB) namespace (i.e., tt(center, left,) or tt(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 tt(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 tt(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 tt(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 tt(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 tt(FMT) specification of column tt(idx) (see also the description of the member tt(size()) below). ) manpagesection(MEMBER FUNCTIONS) In the provided examples tt(tab) refers to an existing tt(CSVTable) object. itemization( itb(std::vector const &columns() const) Returns a reference to the vector containing the format specifications of the table managed by tt(CSVTable); itb(CSVTabDef &fmt(unsigned idx = 0)) The elements inserted into the tt(CSVTabDef) object returned by tt(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 tt(FMT) elements. Repeated tt(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 tt(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 tt(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 tt(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 tt(CSVTabDef) object. 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 tt(CSVTab's fmt(std::string)) member or when directly inserting values into tt(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 tt(CSVTable) object returning a tt(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 tt(CSVTable) uses right-alignment. ) bf(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). ) bf(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 tt(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-6.07.01/documentation/man/milter.yo0000664000175000017500000006640214673353433017421 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) and tt(close) callbacks are called. Starting bf(bobcat) version 6.04.00 the tt(close) callback is always called once a connection ends: it may be specified when specifying the tt(callbacks) argument, but if not then the tt(close) callback is still called. 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 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(PRIVATE 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. The default implementation of the member tt(close) is verb( sfsistat Milter::close() { smfi_setpriv(d_ctx, 0); // delete this d_ctx data return CONTINUE; } ) By calling tt(smfi_setpriv) with second argumnt 0 any data associated with the current connection is deleted by the milter. Implementations overriding tt(close) should at least call tt(smfi_setpriv), passing the value returned by the member tt(id) (cf. section bf(PROTECTED MEMBER FUNCTIONS)) as first argument and 0 as second argument. Other data managed by the milter and specifically associated with a connection should be accessed via the connection's tt(id) (e.g., using a tt(std::unordered_map) using an tt(SMFICTX *) as key); 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(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-6.07.01/documentation/man/config.yo0000664000175000017500000003212014673353433017360 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-6.07.01/documentation/man/mailheaders.yo0000664000175000017500000001577414673353433020411 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-6.07.01/documentation/man/ommapstream.yo0000664000175000017500000000711414673353433020445 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::OmmapStream)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (std::istream using FBB::MmapBuf as streambuf) manpagename(FBB::OmmapStream)(Input Stream using mmap(2) through FBB::MmapBuf) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() bf(FBB::OmmapStream) objects are used to write information to files which are made available in the virtual address space of the calling process. Using the virtual address space is handled by the class's privately inherited bf(FBB::MmapBuf) (tt(std::streambuf) class. By mapping files in the process's virtual address space the time required for processing such files is usually dramatically reduced. An tt(std::exception) is thrown, and an error message is written to tt(cerr) if the bf(FBB::MmapBuf) base class cannot determine the size of the specified file, or when the (un)mapping cannot be performed. includefile(include/namespace) manpagesection(INHERITS FROM) bf(std::ostream), privately from bf(FBB::MmapBuf). manpagesection(CONSTRUCTORS) itb(OmmapStream()) The default constructor merely constructs an empty bf(OmmapStream) object. To change it to a usable object use move assignment; itb(OmmapStream(std::string const &fname, char const *bufSize = 0, std::ios::openmode openMode = std::ios::out, mode_t mode = 0644)) The constructor initializes the tt(OmmapStream) object for a file named tt(fname). The tt(openMode) parameter specifies how tt(fname) is used. The standard tt(ios::in, ios::out, ios::trunc, ios::app,) and tt(ios::ate) modes are supported. By default bfOmmapStream) uses a mapping buffer size of 10 times the standard page size, (cf. bf(sysconf)(3), and the member tt(pageSize) below). The size of the mapping buffer can also be specified using the tt(bufSize) parameter. To specify it use a value followed by tt(K, M,) or tt(G), representing, resp. 1024, 1024 * 1024, and 1024 * 1024 * 1024 bytes. The final buffer size is at least equal to the standard page size. When a larger value is specified the used buffer size is set to tt(specified / pageSize * pageSize). The tt(mode) parameter specifies the user/group/other access mode which is used when the file is created by tt(MmapBuf). Its default value specifies read/write access by the user, and read access by others. ) The move constructor and move assignment operator are available.nl() The copy constructor and copy assignment operator are not available. manpagesection(MEMBER FUNCTIONS) All members of bf(std::istream) are available, as bf(FBB::OmmapStream) inherits from that class. itemization( itb(size_t bufSize() const) returns the used t(mmap) buffer size; itb(size_t fileSize() const) returns the current size of the used file. The size is updated to a larger size when writing beyond the current file size. Once the bf(OmmapStream) object ceases to exist the used file's size is modified to the current tt(fileSize) value. itb(size_t pageSize() const) returns the smallest page size used by t(mmap). ) manpagesection(EXAMPLE) An example is provided in bobcat's source archive and gitlab repository at tt(bobcat/ommapstream/demo). manpagefiles() em(bobcat/ommapstream) - defines the class interface manpageseealso() bf(bobcat)(7), bf(chmod)(2), bf(immapstream)(3bobcat), bf(iommapstream)(3bobcat), bf(mmap)(2), bf(mmapbuf)(3bobcat) bf(sysconf)(3) manpagebugs() None Reported. includefile(include/trailer) bobcat-6.07.01/documentation/man/table.yo0000664000175000017500000002416514673353433017214 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. Tables are filled either column- or row-wise. Many of the table's characteristics may be fine-tuned using a separate bf(FBB::TableSupport) object (cf. bf(tablesupport)(3bobcat)). When no bf(FBB::TableSupport) object is used, a plain table, filled row-wise or column-wise, is constructed which can be inserted into a bf(std::ostream). Tables defined by tt(Table) consist of rows and a fixed number of columns. The number of columns is specified at construction time, the number of rows also depends on the number of inserted elements. Columns and rows are addressed using indices (starting at 0). Before the leftmost column, between the columns and beyond the last column em(separators) are defined. By default these 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). Rows can also be separated from each other using separators. These separating rows are 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, using a simple 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(TableBase) class is not intended to be used by itself, and no separate man-page is provided. Facilities provided by tt(Table) which were 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 tt(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 is found in the second row of the first column. ) bf(enum WidthType)nl() This enumeration defines two values: itemization( itb(COLUMNWIDTH) Specify this value when the columns may have variable widths. In this case each column will be as wide as its widest element. This is the default tt(WidthType) used by tt(Table) objects. itb(EQUALWIDTH) Specify this value when all of the table's columns must have equal widths (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 tt(Table) object. The tt(direction) parameter specifies the way new elements are added to the tt(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 tt(TableSupport) object. A tt(TableSupport) object offers additional formatting features used by the table defining elements like horizontal lines between rows, additional separators, etc, etc. The tt(TableSupport) object is passed as a non-const reference as the tt(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 tt(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 changes 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 also bf(align)(3bobcat)); itb(Table &operator<<(Table &obj, Type const &item)) This operator is defined as a function template: tt(Type) is a template type parameter instantiated to a type for which tt(std::ostringstream) insertions are possible. It inserts the value/object tt(item) into the tt(Table)'s tt(std::ostringstream) base class object as the table's next element. ) 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 elements to the tt(Table) object. Empty fields are ignored unless the parameter tt(addEmpty) is tt(true); itb(void clear()) The content of the table is erased; itb(void clearStr()) The content of its tt(std::ostringstream) base class buffer is erased; 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 tt(Table) object to a rectangular object, for which all column widths and alignments have been determined tt(def) can 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; 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 could e.g., be called from a tt(back_inserter) adaptor); itb(size_t nRows()) The table's current number of rows is returned. It is initialized to 0, and after that updated when tt(def) has been called; itb(Table &setAlign(Align const &align)) The alignment type of either a column or an element of the tt(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. ) manpagesection(MANPULATORS) itemization( itb(Table &CHAR(d)ef(Table &table)) This manipulator can be inserted into a table to call the table's tt(def) 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-6.07.01/documentation/man/cmdfinder.yo0000664000175000017500000002123514673353433020053 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-6.07.01/documentation/man/stringline.yo0000664000175000017500000000457114673353433020302 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-6.07.01/documentation/man/align.yo0000664000175000017500000000666514673353433017224 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 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(MANIPULATOR) The following manipulator (not part of the bf(FBB::Align), class but defined in the tt(FBB) namespace) can be specified as tt(Align)-object constructor arguments and can be stored in tt(Align) objects through, e.g., tt(setManip): itemization( itb(FBB::center) ) manpagesection(CONSTRUCTORS) itemization( itb(Align(Manipulator manip)) This constructor is used to specify an alignment which, when inserted into a tt(Table), is used for all the table's elements. This general alignment type may be modified of specific columns and/or elements using the following constructors; itb(Align(size_t column = 0, Manipulator manip = std::right)) This constructor defines how the content of column `tt(column)' of a tt(Table) object are aligned. When used, it is the responsibility of the programmer to ensure that the table's column exists (i.e., the tt(Table) must have a column index tt(column)); itb(Align(int row, size_t column, Manipulator manip)) This constructor defines the alignment of element tt([row][column]) of a tt(Table) object. Before using this constructor table element tt([row][column]) must have been defined. E.g., verb( Table tab{ 3, Table::ROWWISE }; tab << "xx00x " << " x01x " << " x02xx" << 10 << 11 << 12; tab << Align(1, 1, FBB::center); ) ) 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 tt(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 tt(row()) member returns a sensible value; itb(size_t row+nop()() const) Returns the object's row index; itb(Manipulator manip() const) Returns the tt(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 tt(Align) object refers; itb(void setManip(Manipulator manip)) Changes the object's currently stored tt(Manipulator). ) manpagesection(EXAMPLE) See the bf(table)(3bobcat) man-page. manpagefiles() em(bobcat/align) - defines the class interface manpageseealso() bf(bobcat)(7), bf(csvtable)(3bobcat), bf(manipulator)(3bobcat), bf(table)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-6.07.01/documentation/man/sharedcondition.yo0000664000175000017500000003537114673353433021303 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-6.07.01/documentation/man/osharedstream.yo0000664000175000017500000002003414673353433020755 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-6.07.01/documentation/man/iobuf.yo0000664000175000017500000001073014673353433017222 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-6.07.01/documentation/man/systemclock.yo0000664000175000017500000003063214740164423020453 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::*Clock)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Classes wrapping std::*_clock) manpagename(FBB::*Clock) (classes wrapping std::chrono::*_clock facilities) manpagesynopsis() bf(#include )nl() bf(#include )nl() bf(#include )nl() bf(#include )nl() Each of these files also includes the tt(std::chrono) header file. manpagedescription() The bf(C++) tt(std::chrono) namespace defines clock-types and their operations. The bf(bobcat) tt(*Clock) classes define wrappers around the four standard bf(C++) clock-types offering interfaces which are easier to handle than the standard tt(std::chrono) clocks. itemization( it() bf(FileClock) wraps tt(std::chrono::file_clock); it()bf(HighResolutionClock) wraps tt(std::chrono::high_resolution_clock);nl() it()bf(SteadyClock) wraps tt(std::chrono::steady_clock);nl() it()bf(SystemClock) wraps tt(std::chrono::system_clock)), and is the commonly used clock type. Member names of the bf(bobcat) clock-classes don't use underscores. Names consisting of multiple words are `camel-cased' (like tt(timePoint)). Note: quote(The type tt(std::chrono::file_clock) (and therefore bf(FileClock)) is available since the tt(C++-2a) standard: specify the tt(--std=c++2a) (or more recent) compiler option when using bf(FileClock).) includefile(include/namespace) manpagesection(INHERITS FROM) tt(FBB::ClockTypes)nl() tt(FBB::ClockBase)nl() tt(FBB::HighSysClock)nl() quote(these are internally used only classes; their facilities are covered in this man-page.) manpagesection(TYPEDEFS AND ENUMS) itemization( it() The tt(std::chrono) types tt(nanoseconds, microseconds, milliseconds, seconds, minutes) and tt(hours) are also available in the namespace tt(FBB); ) bf(Clock Types:) itemization( itt(FBB::FileClock) provides the tt(std::chrono::file_clock) facilities; itt(FBB::HighResolutionClock) provides the tt(std::chrono::high_resolution_clock) facilities; itt(FBB::SteadyClock) provides the tt(std::chrono::steady_clock) facilities; itt(FBB::SystemClock) provides the tt(std::chrono::system_clock) facilities. ) bf(Sub-types:) itemization( itt(Duration): each clock type defines the type tt(Duration) as tt(std::chrono::duration); itt(Period): the sub-type tt(period) of the tt(Duration) type. In practice its subtypes tt(den (DenType)) and tt(num (NumType)) are used; itt(DenType): the denominator type of the tt(ratio) type used by the clock type (see also the static member tt(den)); itt(NumType): the numerator type of the tt(ratio) type used by the clock type (see also the static member tt(num)); ) manpagesection(CONSTRUCTORS) The constructors are illustrated for tt(SystemClock) but are also available for the other clock types. itemization( itb(SystemClock(SystemClock::TimePoint = SystemClock::now())) each clock-constructor can be initialized with a time point. By default the clock's time point is initialized by the time point returned by the clock type's static tt(now) member; itb(SystemClock(Clock const &otherClock)) each clock type can be initialized with another clock type object (except for a tt(SteadyClock) type object): when constructed they refer to the same points in time. ) Copy and move constructors (and assignment operators) are available. manpagesection(OVERLOADED OPERATORS) Using tt(DurationType) to represent tt(std::chrono::duration), where tt(Ratio) is a tt(std::ratio) type (for clocks tt(Ratio) equals tt(nano)). itemization( itb(ClockType &operator+=(DurationType const &amount)) adds tt(amount) to the current clock's tt(TimePoint). E.g., verb( SystemClock sc; sc += 1h; ) itb(ClockType &operator+=(int secs);) adds tt(secs) seconds to the current clock's tt(TimePoint); itb(ClockType &operator-=(DurationType const &amount);) subtracts tt(amount) from the current clock's tt(TimePoint). Not available for tt(SteadyClock); itb(ClockType &operator-=(int secs);) subtracts tt(secs) seconds from the current clock's tt(TimePoint); itb(SteadyClock &operator-=(SteadyClock const &rhs)) only available for class tt(SteadyClock): tt(rhs.elapsed()) is subtracted from the current object's time-point. See also the functions tt(since) and tt(countSince) below. itb(std::ostream &operator<<(std::ostream &out, ClockType const &clock)) not available for tt(SteadyClock); tt(clock's) (UTC) tt(TimePoint) is inserted into tt(out). E.g., verb( cout << SystemClock{}; // could insert // 2025-01-04 08:25:10.035509381 ) itb(ClockType operator+(Type1 const &lhs, Type2 const &rhs)) not available for tt(SteadyClock). Either tt(Type1) or tt(Type2) must be an bf(FBB) Clock type (like tt(SystemClock)). The other type can either be an tt(int) (representing number of seconds) or a tt(DurationType) (like tt(seconds, hours)). A clock object of the same type as the tt(Clock) argument is returned, whose tt(TimePoint) is initialized to the sum of the argument's tt(TimePoint) and the value of the other argument; itb(ClockType operator-(ClockType const &lhs, Type const &rhs)) both argument types can be tt(SteadyClock). As tt(SteadyClock) objects are used for timing purposes this operator returns a tt(SteadyClock) object whose time specification is equal to the difference of the tt(lhs) and tt(rhs) time specifications (see also the functions tt(since) and tt(countSince) below).nl() Otherwise the tt(lhs) argument must be an bf(FBB) Clock type (like tt(SystemClock)), and tt(Type) can either be an tt(int) (representing number of seconds) or a tt(DurationType) (like tt(seconds, hours)), returning a clock object whose tt(TimePoint) is initialized to the difference of the tt(lhs's TimePoint) and the tt(rhs) value; ) manpagesection(FREE FUNCTIONS) itemization( itb(auto toClock(ClockType const &clock)) returns the tt(DestClock::TimePoint) corresponding to the tt(TimePoint) of tt(clock). It is not available for conversions from or to the tt(SteadyClock) type. E.g., verb( FileClock fc; cout << toClock(fc) << '\n'; ) itb(double toDouble(ClockType const &src)) returns the tt(double) value corresponding to tt(ClockType's std::chrono::duration) converted to the tt(Duration std::chrono::duration). E.g., verb( toDouble(90min); // returns 1.5 ) itb(Dest toDuration(Src const &src)) returns tt(src's Duration) converted to the (at least as precise) tt(Dest) duration. E.g., verb( toDuration(1min).count(); // returns 60 ) ) manpagesection(ADDITIONAL STEADYCLOCK FREE FUNCTIONS) The tt(SteadyClock) type is primarily used for timing purposes. The following two functions are available for tt(SteadyClock) objects: itemization( itb(SteadyClock::Duration since(SteadyClock const &time0)) The difference in nanoseconds (tt(Durations)) of a local tt(SteadyClock) object and tt(time0) is returned. E.g., verb( SteadyClock start; // do something cout << "Elapsed time: " << since(start) << '\n'; ) itb(size_t countSince(SteadyClock const &time0)) Same as the previous function, but the number of nanoseconds are returned as a tt(size_t) value. ) manpagesection(MEMBER FUNCTIONS) All of the following members are available for each of bf(bobcat's) clock types: itemization( itb(long int count()) returns tt(timePoint's value). The clock types have members tt(timePoint()): this member returns the number of nano seconds as an integral value since the beginning of the clock's era. E.g., verb( FileClock{}.clock(); // returns, e.g., // -4701673791896351066 ) itb(static long int ClockTypes::count(TimePoint const &timePoint)) returns tt(timePoint's value). This function can also be used for tt(SteadyClock) objects. E.g., verb( ClockTypes::count(SteadyClock::now()); // returns, e.g., // 8310904806233 ) itb(static DenType::den()) returns the denominator of the tt(ratio) used by the clocks (= 1'000'000'000); itb(Duration elapsed() const) returns the tt(Duration) value of the current tt(Clock) object (= number of nano-seconds since the beginning of the clock's era). E.g., verb( SystemClock{}.elapsed(); // returns, e.g., // 1735989478991599467ns ) itb(static Duration ClockTypes::elapsed(TimePoint const &timePoint)) returns tt(timePoint's Duration). Clock types have members tt(timePoint()) returning the clock's time point; itb(static TimePoint max()) returns the tt(TimePoint) of the used clock type corresponding to the clock's maximum (UTC) time. E.g., verb( cout << SystemClock::max(); // inserts: // 2262-04-11 23:47:16... ) itb(static TimePoint min()) returns the tt(TimePoint) of the used clock type corresponding to the clock's minimum (UTC) time; itb(static TimePoint now()) returns the tt(TimePoint) of the used clock type corresponding to the current (UTC) time. E.g., verb( cout << SystemClock::now() << '\n'; ) itb(static NumType::num()) returns the numerator of the tt(ratio) used by the clocks (= 1); itb(static Period period()) returns the clock's tt(Period) (having members tt(den) and tt(num)); itb(TimePoint const &timePoint() const) returns the object's tt(TimePoint); itb(double toDouble() const) returns the tt(double) value corresponding to the object's tt(std::chrono::duration) converted to the tt(Dest std::chrono::duration). E.g., verb( SystemClock{}.toDouble(); // returns, e.g., 482221 ) itb(static Duration zero()) returns the clock's tt(Duration) representing 0 nanoseconds; ) manpagesection(ADDITIONAL SYSTEM / HIGHRESOLUTION CLOCK MEMBERS) Primarily for displaying the clock's time the tt(SystemClock) and tt(HighResolutionClock) classes support these members: itemization( itb(std::time_t timeT() const) returns the object's tt(TimePoint) converted to tt(time_t) (cf. bf(time)(3)); itb(Clock &setTime(std::time_t seconds)) returns the current object after resetting its tt(TimePoint) to its tt(time_t) argument; itb(Clock const &operator()(char const *putTime, bool localTime = true) const) prepares the current object for the next insertion operator, using the tt(putTime) specification to configure the tt(std::put_time) manipulator (cf. tt(C++ Annotations), section 6.4.4 (The `put_time' manipulator)). By default the time is displayed using the local time. When the 2nd argument is tt(false) the time is displayed in tt(UTC). When the current object is inserted into a tt(std::ostream) after calling this member the tt(put_time) manipulator is used only once. By calling this member again tt(put_time) is repeatedly used. E.g., verb( SystemClock sc; cout << // inserts, e.g., sc("%Y") << '\n' << // 2025 sc("%y") << '\n' << // 25 sc << '\n'; // 2025-01-04 14:18:47... ) ) manpagesection(EXAMPLE) verbinclude(../../systemclock/driver/main.cc) manpagefiles() em(bobcat/fileclock), - the tt(FileClock) class interface+nl() em(bobcat/highresulutionclock) - the tt(HighResolutionClock) class interface+nl() em(bobcat/steadyclock) - the tt(SteadyClock) class interface+nl() em(bobcat/systemclock) - the tt(SystemClock) class interface+nl() manpageseealso() bf(bobcat)(7), bf(time)(3), manpagebugs() None Reported. includefile(include/trailer) bobcat-6.07.01/documentation/man/indent.yo0000664000175000017500000000623214673353433017401 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-6.07.01/documentation/man/datetime.yo0000664000175000017500000007606414673353433017726 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. itb(DateTime(std::istream &&in, TimeType type = UTC)) Same as the previous constructor, but receeiving an r-value reference as its first argumnt. ) 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-6.07.01/documentation/man/irandstream.yo0000664000175000017500000000447714673353433020442 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), bf(randommt)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-6.07.01/documentation/man/arg.yo0000664000175000017500000004464214737224041016671 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, bf(NOTE:) since bf(bobcat) version 6.07.00 bf(FBB::Arg::Type::None) was renamed to bf(FBB::Arg::Type::NoArg). 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(NoArg, Required, Optional). itemization( it() bf(NoArg): 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::NoArg)) 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-6.07.01/documentation/man/syslogstream.yo0000664000175000017500000002633614673353433020663 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(log)(3bobcat), 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-6.07.01/documentation/man/sharedmemory.yo0000664000175000017500000004157214673353433020625 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-6.07.01/documentation/man/localclientsocket.yo0000664000175000017500000001157514673353433021630 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-6.07.01/documentation/man/csv.yo.deprecated0000664000175000017500000002560014673353433021012 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-6.07.01/documentation/man/mstream.yo0000664000175000017500000003330414673353433017570 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)) 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-6.07.01/documentation/man/ifdbuf.yo0000664000175000017500000001267014673353433017362 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 ) (when using bf(FBB::IFdBuf)nl() bf(#include ) (when using bf(FBB::IFdBufS) 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. bf(FBB::IFdBufS) objects operate like bf(FBB::IFdBuf) objects but use bf(FBB::Selector) objects to check whether information on the object's file descriptor is available before reading information from the 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. itb(IFdBufS constructors) Use bf(IFdBufS) constructors corresponding to bf(IFdBuf) constructors to construct the corresponding bf(IFdBufS) objects. ) 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(S)) inherits from this class. itemization( itb(void close()) The file descriptor used by the tt(IFdBuf(S)) is closed, irrespective of the tt(Mode) that was specified when the tt(IFdBuf(S)) object was constructed. Following tt(close) the tt(IFdBuf(S)) 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(S)) 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(S)) object is destroyed. ) manpagesection(EXAMPLE) verbinclude(../../ifdbuf/driver/driver.cc) manpagefiles() em(bobcat/ifdbuf) - defines the bf(FBB::IFdBuf) class interface+nl() em(bobcat/ifdbufs) - defines the bf(FBB::IFdBufS) 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-6.07.01/documentation/man/lm.yo0000664000175000017500000000454414673353433016534 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-6.07.01/documentation/man/sharedpos.yo0000664000175000017500000001327314673353433020113 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-6.07.01/documentation/man/reverse.yo0000664000175000017500000000545514673353433017601 0ustar frankfrankincludefile(include/header) COMMENT(replace 'classname' by the name of the new class) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Reverse)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (for-loop reverse iterators) manpagename(FBB::Reverse)(A class template offering reverse iterators) manpagesynopsis() bf(#include )nl() manpagedescription() Not all data types offering (or implicitly providing) iterators also offer tt(reverse_iterators). Arrays don't, and neither do tt(initalizer_lists). Pointers to array elements can be used instead of iterators, but arrays cannot be used in range-based for-loops. The tt(Ranger) class (cf. bf(ranger)(3bobcat)) can be used for defining tt(begin) and tt(end) members allowing the use of arrays in range-based for-loops. Using bf(Reverse) objects and data structures can be used in range-based for-loops and/or to obtain reverse-iterators to visit data elements in reversed order. The class template tt(Reverse, ReverseArray,) and tt(ReverseSize) are normally not directly used, but are returned by the various tt(reverse) support functions. These three classes offer two members tt(begin), returning a tt(reverse_iterator) to the end of the data range of the object passed to tt(reverse) and tt(end) returning a tt(reverse_iterator) to the beginning of the data range of the object passed to tt(reverse). includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(REVERSE FUNCTIONS) itemization( itb(reverse(Type &object)) returns a tt(Reverse) object offering reverse iterators to the data range of tt(object), which must support tt(begin) and tt(end) members. If tt(Type) is a constant type, then tt(Reverse's begin) and tt(end) members return tt(const_reverse_iterators), otherwise tt(reverse_iterators) are returned; itb(reverse(Type (&array)[size])) returns a tt(Reverse) object offering reverse iterators to the reversed range of elements of tt(array). If tt(Type) is a constant type, then tt(Reverse's begin) and tt(end) members return tt(const_reverse_iterators), otherwise tt(reverse_iterators) are returned; itb(reverse(Type *array, size_t size)) returns a tt(Reverse) object offering reverse iterators to the reversed range of elements of tt(array) to tt(array + size). If tt(Type) is a constant type, then tt(Reverse's begin) and tt(end) members return tt(const_reverse_iterators), otherwise tt(reverse_iterators) are returned. ) manpagesection(EXAMPLE) verbinclude(../../reverse/driver/main.cc) manpagefiles() em(bobcat/reverse) - defines the class interfaces and declares the tt(reverse) functions. manpageseealso() bf(bobcat)(7), bf(ranger)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-6.07.01/documentation/man/digestbuf.yo0000664000175000017500000001102714673353433020072 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 -lcrypto) manpagedescription() bf(FBB::DigestBuf) objects are bf(std::streambuf) objects that can be used to initialize tt(std::ostream) objects with. The message digest of all information inserted into such an tt(std::ostream) is computed. 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 currently supported message digest algorithms are shown by the tt(openssl list -digest-commands). The names of the digest algorithms can be used to select a digest algorithms for the class's constructor, below. COMMENT( 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). END) includefile(include/namespace) manpagesection(INHERITS FROM) bf(std::streambuf) manpagesection(CONSTRUCTORS) itemization( itb(DigestBuf(char const *digestName, 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 size of 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( 1. create a DigestBuf object 2. use it to create a std::ostream object 3. insert information into the ostream object 4. call the DigestBuf object's eoi() member or insert the eoi manipulator into the ostream (see below) 5. 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-6.07.01/documentation/man/serversocket.yo0000664000175000017500000001523014673353433020635 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-6.07.01/documentation/man/bobcat.jpg0000664000175000017500000037125614673353433017516 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-6.07.01/documentation/man/mmapbuf.yo0000664000175000017500000000746714673353433017562 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::MmapBuf)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (std::streambuf using mmap(2)) manpagename(FBB::MmapBuf)(a std::streambuf using mmap(2) for file I/O) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() The bf(mmap)(2) functions map files in the virtual address space of the calling process. Using tt(mmap) in bf(C++) is doable, but complex. The bf(MmapBuf) tt(std::streambuf) class embeds the features of bf(mmap)(2), allowing the use of bf(C++)'s streams instead of using the raw tt(mmap) calls. the bf(FBB::Mmapbase) class defines a tt(std::streambuf) which can be used by tt(istream, ostream,) and tt(iostream) objects. An tt(std::exception) is thrown, and an error message is written to tt(cerr) if the details about the specified filename (cf. section bf(CONSTRUCORS) cannot be determined, or when tt(mmap) or tt(munmap) return errors. includefile(include/namespace) manpagesection(INHERITS FROM) bf(std::streambuf) manpagesection(CONSTRUCTORS) itemization( itb(MmapBuf()) The default constructor merely constructs an empty bf(MmapBuf) object. To change it to a usable object use move assignment; itb(MmapBuf(std::string const &fname, std::ios::openmode openMode, char const *bufSize = 0, mode_t mode = 0644)) The constructor initializes the tt(MmapBuf) object for a file named tt(fname). The tt(openmode) can be any combination of the tt(std::ios::openmode) values. The required values are usually provided when constructing tt(ImapStream, OmapStream,) or tt(IOmapStream) objects (cf. section bf(SEE ALSO) below). The tt(opnemMode) parameter specifies how tt(fname) is used. The standard tt(ios::in, ios::out, ios::trunc, ios::app,) and tt(ios::ate) modes are supported. By default bfMmapBuf) uses a mapping buffer size of 10 times the standard page size, (cf. bf(sysconf)(3), and the member tt(pageSize) below). The size of the mapping buffer can also be specified using the tt(bufSize) parameter. To specify it use a value followed by tt(K, M,) or tt(G), representing, resp. 1024, 1024 * 1024, and 1024 * 1024 * 1024 bytes. The final buffer size is at least equal to the standard page size. When a larger value is specified the used buffer size is set to tt(specified / pageSize * pageSize). The tt(mode) parameter specifies the user/group/other access mode which is used when the file is created by tt(MmapBuf). Its default value specifies read/write access by the user, and read access by others. ) The move constructor and move assignment operator are available.nl() The copy constructor and copy assignment operator are not available. manpagesection(MEMBER FUNCTIONS) All members of bf(std::stringstream) are available, as bf(FBB::MmapBuf) inherits from that class. itemization( itb(size_t bufSize() const) returns the used t(mmap) buffer size; itb(size_t fileSize() const) returns the size of the used file. The size is updated to a larger size when writing beyond the current file size. Once bf(MmapBuf) objects cease to exist the used file's size is modified to the current tt(fileSize) value. The size of a file that can only be read is never altered. itb(size_t pageSize() const) returns the smallest page size used by t(mmap). ) manpagesection(EXAMPLE) An example is provided in bobcat's source archive and gitlab repository at tt(bobcat/mmapbuf/demo). manpagefiles() em(bobcat/mmapbuf) - defines the class interface manpageseealso() bf(bobcat)(7), bf(chmod)(2), bf(immapstream)(3bobcat), bf(iommapstream)(3bobcat), bf(ommapstream)(3bobcat), bf(mmap)(2), bf(sysconf)(3) manpagebugs() None Reported. includefile(include/trailer) bobcat-6.07.01/documentation/man/readlinehistory.yo0000664000175000017500000001675714737536706021351 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: -lbobcat -lreadline 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. When reading the history from a stream it replaces the currently available lines in Gnu's readline history. 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 to become the current history, replacing the existing (Gnu readline) history by the history read from tt(in). The tt(useTimestamp) status determines whether timestams are extracted (if tt(true)) or not (if tt(false)). If extracting the history from tt(in) fails an exception is thrown. itb(std::ostream &operator<<(std::ostream &out, ReadLineHistory &his)) The current history is written to the 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)(3bobcat), bf(readlinestream)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-6.07.01/documentation/man/x2a.yo0000664000175000017500000000762214673353433016616 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-6.07.01/documentation/man/ifilterbuf.yo0000664000175000017500000001536614673353433020263 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. Because tt(IFilterBuf) is a tt(streambuf) its member tt(underflow) is automatically called when reading operations are requested from the tt(stream) object using the tt(IFilterBuf) as its tt(streambuf). If no chars are currently available (i.e., tt(srcBegin == srcEnd), see the description of the tt(filter) member below), then tt(filter) is called, which may store characters in a (local) buffer of at most tt(maxSize) characters (see the description of the tt(IFilterBuf) constructor below). Once this buffer has been filled tt(filter) updates the tt(*srcBegin) and tt(*srcEnd) pointers so that they point to, respectively, the the location of the first character in the local buffer and beyond the location of the last character in the local buffer. 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 put characters back on the internal buffer until the beginning of the buffer has been reached, but may then continue pushing characters on the buffer until the 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-6.07.01/documentation/man/cininserter.yo0000664000175000017500000001376414673353433020455 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 tt(CinInserter) 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-6.07.01/documentation/man/ofoldbuf.yo0000664000175000017500000002042714673353433017722 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-6.07.01/documentation/man/level.yo0000664000175000017500000000460114673353433017225 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-6.07.01/documentation/man/bobcat.yo0000664000175000017500000011326514673353433017357 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::CerrExtractor): Executes child processes not expecting input but maybe writing its standard error stream. nl() Manpage(cerrextractor) 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::CinInserter): Executes child processes expecting input but not producing standard output. nl() Manpage(cininserter) 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::CoutExtractor): Executes child processes not expecting input but maybe producing standard output. nl() Manpage(coutextractor) 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::DiffieHellman): Computing shared keys using the Diffie-Hellman algorithm.nl() Manpage(diffiehellman) bf(FBB::DigestBuf): Computing message digests.nl() Manpage(digestbuf) bf(FBB::ECDH): Computing shared keys using the elliptic curve based Diffie-Hellman algorithm.nl() Manpage(ecdh) 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::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/FBB::IFdStreamS): stream extracting information from a device whose file descriptor is available. nl() Manpage(ifdstream) bf(FBB::IFdBuf/FBB::IFdBufS): 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::ImmapStream): stream extracting information from a file using bf(mmap)(2) to load the file's data into memory. nl() Manpage(immapstream) bf(FBB::IOmmapStream): stream extracting information from and/or writing information to a file using bf(mmap)(2) to load the file's data into memory. nl() Manpage(iommapstream) 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::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::LDC): Large Digital Converter converts (large) values for various radices. nl() Manpage(ldc) 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::MmapBuf): tt(std::streambuf) using bf(mmap)(2) to load the file's data into memory. nl() Manpage(mmapbuf) bf(FBB::OmmapStream): stream writing information to a file using bf(mmap)(2) to load the file's data into memory. nl() Manpage(ommapstream) 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::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::OmmapStream): stream writing information to a file using bf(mmap)(2) to load the file's data into memory. nl() Manpage(ommapstream) bf(FBB::OMutexStream): Mutex protected tt(std::ostream).nl() Manpage(mxstream) 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::OSymCryptStream): stream implementing symmetric encryption and decryption, using a tt(FBB::OSymCryptStreambuf) stream buffer.nl() Manpage(osymcryptstream) bf(FBB::OSymCryptStreambuf): streambuf derived from tt(FBB::EoiBuf) implementing symmetric cryptography.nl() Manpage(osymcryptstreambuf) 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::RandomMt): class template generating random numbers. nl() Manpage(randommt) 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::Reverse): a class template creating a reverse iterator returning values of a specified type.nl() Manpage(reverse) 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::LDC): Large Digital Converter converts (large) values for various radices. nl() Manpage(ldc) 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::DiffieHellman): Computing shared keys using the Diffie-Hellman algorithm.nl() Manpage(diffiehellman) bf(FBB::DigestBuf): Computing message digests.nl() Manpage(digestbuf) bf(FBB::ECDH): Computing shared keys using the elliptic curve based Diffie-Hellman algorithm.nl() Manpage(ecdh) 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) bf(FBB::OSymCryptStream): stream implementing symmetric encryption and decryption, using a tt(FBB::OSymCryptStreambuf) stream buffer.nl() Manpage(osymcryptstream) bf(FBB::OSymCryptStreambuf): streambuf derived from tt(FBB::EoiBuf) implementing symmetric cryptography.nl() Manpage(osymcryptstreambuf) 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/FBB::IFdStreamS): stream extracting information from a device whose file descriptor is available. nl() Manpage(ifdstream) bf(FBB::IFdBuf/FBB::IFdBufS): 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::ImmapStream): stream extracting information from a file using bf(mmap)(2) to load the file's data into memory. nl() Manpage(immapstream) bf(FBB::IOmmapStream): stream extracting information from and/or writing information to a file using bf(mmap)(2) to load the file's data into memory. nl() Manpage(iommapstream) 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::MmapBuf): tt(std::streambuf) using bf(mmap)(2) to load the file's data into memory. nl() Manpage(mmapbuf) 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::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::OmmapStream): stream writing information to a file using bf(mmap)(2) to load the file's data into memory. nl() bf(FBB::OMutexStream): Mutex protected tt(std::ostream).nl() Manpage(mxstream) 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::RandomMt): class template generating random numbers. nl() Manpage(randommt) 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::Reverse): a class template creating a reverse iterator returning values of a specified type.nl() Manpage(reverse) 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(libbobcat6.so)) it is usually sufficient to merely specify tt(-lbobcat). E.g., verb( g++ --std=c++2a main.cc -lbobcat ) Note: 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-6.07.01/documentation/man/randommt.yo0000664000175000017500000000365214673353433017744 0ustar frankfrankincludefile(include/header) COMMENT(replace 'classname' by the name of the new class) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::RandomMT)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Random Generator using std::mt19937) manpagename(FBB::RandomMT)(Class template generating random numbers) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() The class template tt(RandomMT) uses the tt(std::mt19937) Mercenne Twister to produce random numbers. The class template has one template type parameter, which can be any integral or floating point type. By default tt(size_t)-valued random numbers are generated. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(CONSTRUCTORS) itemization( itb(RandomMT::RandomMT(Type minimum, Type maximum, size_t mtSeed)) The tt(Type) template type parameter can be any integral or floating point type. If not specified tt(size_t) is used. The parameters tt(minimum) and tt(maximum) define the range of the generated random values. tt(minimum) must be less or equal to tt(maximum), or an exception is thrown. The tt(mtSeed) parameter is used to initialize (seed) the tt(mt19937) Mercenne Twister. ) The default copy and move constructors and assignment operators are available. manpagesection(OVERLOADED OPERATORS) itemization( itb(Type operator()()) The function call operator returns the next random value. ) manpagesection(EXAMPLE) verbinclude(../../randommt/driver/driver.cc) manpagefiles() em(bobcat/randommt) - defines the class interface manpageseealso() bf(bobcat)(7), bf(irandstream)(3bobcat), bf(rand)(3), bf(randbuf)(3bobcat), bf(srand)(3) manpagebugs() None Reported. includefile(include/trailer) bobcat-6.07.01/documentation/man/argconfig.yo0000664000175000017500000004403614673353433020063 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 bf(Arg) and bf(ConfigFile) classes are also supported 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 bf(Arg) and bf(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 bf(Arg)tt(::option) member having the identical prototype. It does not consider the configuration file but merely considers the command line arguments, returning 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 bf(Arg)tt(::option) member having the identical prototype. It does not consider the configuration file, but merely considers the command line arguments, returning 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 bf(Arg)tt(::option) member having the identical prototype. It does not consider the configuration file, but merely considers the command line arguments, returning 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 bf(Arg)tt(::option) member having the identical prototype. It does not consider the configuration file, but merely considers the command line arguments, returning 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. ) When using the tt(option) members that don't consider configuration files use the tt(beginEndRE) member (cf. bf(configfile)(3obcat)) to retrieve long options that are specified in configuration files. 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-6.07.01/documentation/man/linearmap.yo0000664000175000017500000002271614673353433020075 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(USING SPECIFICATIONS) itemization( itt(using value_type = std::pair); 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-6.07.01/documentation/man/eoibuf.yo0000664000175000017500000001172314673353433017372 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: it contains a (resizable) character buffer, and offers a tt(setp) member as well as a tt(setg) member that can be used to specify the index rage of the buffer from which extractions receive characters. Also, when overriding its base class's tt(eoi_) member it can be used to signal the end of input inserted into tt(std::ostream) classes using tt(EoiBuf) objects as tt(std::streambuf) objects. includefile(include/namespace) manpagesection(INHERITS FROM) tt(FBB::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) The following two functions are defined in the (internally used only) class tt(FBB::OSymCryptBase), which is the base class of bf(osymcryptstreambuf)(3bobcat). itemization( itt(evpUpdate) updates the ongoing encryption or decryption, e.g., using the openssl function tt(EVP_EncryptUpdate), using tt(ucharPtr) to access characters currently in tt(EoiBuf's) buffer: verbinclude(../../osymcryptbase/evpupdate.cc) itt(eoi_) overrides tt(FBB::Eoi::eoi_()) function, preventing new information from being inserted into the tt(FBB::OSymCryptBase) object (and thus from being inserted into its tt(FBB::OSymCryptStreambuf) derived class): verbinclude(../../osymcryptbase/eoi.cc) ) manpagefiles() em(bobcat/eoibuf) - defines the class interface manpageseealso() bf(bobcat)(7), bf(eoi)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-6.07.01/documentation/man/repeat.yo0000664000175000017500000000520014673353433017372 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-6.07.01/documentation/man/coutextractor.yo0000664000175000017500000001061314673353433021024 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 tt(CoutExtractor) 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-6.07.01/documentation/man/localsocketbase.yo0000664000175000017500000000460714673353433021262 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-6.07.01/documentation/man/ecdh.yo0000664000175000017500000003062614673353433017027 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::ECDH)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Elliptic Curve Diffie-Hellman) manpagename(FBB::ECDH)(Elliptic Curve Diffie-Hellman PKI, computing shared keys) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat -lcrypto) manpagedescription() The class bf(FBB::ECDH) computes shared keys (shared secrets) applying elliptic keys to the Diffie-Hellman (1976) algorithm. The Diffie-Hellman algorithm uses public and private information, providing a public key infrastructure (PKI). The public information consists of an elliptic curve specification and a public key, which may be shared over insecure media. The Diffie-Hellman algorithm is commonly used to compute a shared key which is then used to encrypt information sent between two parties. One party, which in this man-page is called the em(initiator), specifies at construction time an elliptic curve, constructs a public and private key, and writes the public key in hexadecimal big-endian form, followed by the name of the used elliptic curve to file. The initiator's private key is separately written to file, as the private key is required for computating the shared key. Encryption may be used when writing the private key to file. Next the initiator passes the file containing the initiator's public key and the name of the used elliptic curve to the other party, which in this man-page is called the tt(peer). The peer, having received the initiator's (public key) file constructs an bf(FBB::ECDH) object. The peer's tt(ECDH) constructor computes the peer's public and private key, writes the peer's public key to file, and constructs the shared key. Once the peer's tt(ECDH) object has been constructed the peer can write the shared key to file. The peer's private key may optionally also be written to file, but that's optional, as the peer's private key is not required for subsequent computations. Encryption may also be used when writing the peer's private key to file. The file containing the peer's public key is then sent to the initator. The initator constructs an tt(ECDH) object specifying the names of the used elliptic curve, of the file containing the initiator's private key, and the name of the file containing the peer's public key. Once this tt(ECDH) object has been constructed the peer may write the shared key to file. The initiator and peer's shared keys are identical and can be used for symmetric encryption of sensitive information shared between the initiator and the peer. tt(FBB::Exception)s are thrown if the tt(ECDH) constructors or members cannot complete their tasks. bf(Perfect Forward Secrecy and Ephemeral Diffie Hellman) The initiator and peer may decide not to save their private information once they have constructed their shared keys, resulting in em(Perfect Forward Secrecy) and em(Ephemeral Diffie Hellman). Here, this 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 procedure described in the previous section, the private keys are not saved on files, and the process constructing the initiator's tt(ECDH) object may not terminate, but must remain active until the peer's public key has been received. Once the initiator's process has constructed the public key that key is encrypted using the common secret, and is then sent to the peer. Alternatively, the initiator's private key may temporarily be stored in shared memory or may temporarily be stored encrypted on file. it() The peer, having received the initiator's public key, constructs the shared secret, encrypts the peer's public key, and sends the encrypted public key to the initiator. it() The initiator upon receipt of the peer's public key, computes the shared key, either by continuing the temporarily suspended construction process or by retrieving the shared key from memory or file, removing the storage (memory or file) thereafter. it() Since the private keys and the public keys are not stored or kept on files the shared keys 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 ) bf(Document encryption using Diffie Hellman) As with PKI in general, the Diffie Hellman key exchange method itself is normally not used for encrypting documents. Instead, it is used to obtain a key that is used for symmetric encryption methods like 3DES or CBC. These symmetric encryption methods are available through, e.g., Bobcats' tt(ISymCryptStream) and tt(OSymCryptStream) classes. includefile(include/namespace) manpagesection(INHERITS FROM) - manpagesection(ENUMERATIONS) The class tt(ECDH) defines two enumerations, each having one defined value. The enumberations are used to select specific overloaded versions of the tt(ECDH) constructors or tt(set) members: itemization( it() The t(enum TheInitiator) has value tt(Initiator) and is used to select overloaded versions meant for the initiator; it() The t(enum ThePeer) has value tt(Peer) and is used to select overloaded versions meant for the peer. ) manpagesection(CONSTRUCTORS) itemization( itb(ECDH()) The default constructor is available merely constructing a valid object. It also prepares a map of all elliptic curves predefined by em(openSSL). As all other constructors use default constructor delegation the map is also available after calling the other constructors; itb(ECDH(TheInitiator init, std::string const &curveName, std::string const &initPubFname)) This constructor initializes the tt(ECDH) object to be used by the initiator, constructing the initiator's private and public keys using the elliptic curve specified by tt(curveName) (e.g., tt(secp384r1), see also tt(operator<<) below). The initiator's public key (in big-endian hexadecimal format) and tt(curveName) are written to tt(initPubFname); This constructor should be called by the initiator to start the Diffie-Hellman shared key computation procedure; itb(ECDH(ThePeer peer, std::string const &initPubFname, std::string const &peerPubFname)) This constructor is used by the peer, having received the initiator's public info on the file tt(initPubFname). It constructs the peer's private and public keys as well as the shared key. The peer's public key (in big-endian hexadecimal format) is written to tt(peerPubFname), which file is then be sent to the initiator; itb(ECDH(std::string const &curveName, std::string const &peerPubFname, std::string const &initSecFname, std::string const passphrase = "")) Once the initiator has received the peer's public key (in the file tt(peerPubFname)) this constructor constructs the initiator's version of the shared key. Here, the initiator has previously saved the initiator's private key to tt(initSecFname), optionally using encryption. If encryption was used then the then used passphrase must also be specified when using this constructor. ) The move constructor (and move assignment operator) is available. manpagesection(MEMBER FUNCTIONS) itemization( itb(std::string const &curve() const) The used elliptic curve is returned; itb(std::string privKey() const) The big-endian hex-formatted private key is returned, prefixed by a line containing tt(hex); itb(void privKey(std::string const &privKeyFname, std::string passphrase) const) The private private key is encrypted using the tt(AES-256-GCM) encryption algorithm, using passphrase tt(passphrase). It is then written to tt(privKeyFname), prefixed by a line containing tt(encrypted). The string tt(passphrase) must consist of at least five characters, and may contain multiple words; itb(std::string const &pubKey() const) The public key is returned as a big-endian hexadecimal string; itb(void set(TheInitiator init, std::string const &curveName, std::string const &initPubFname)) This member should be called by the initiator, constructing the initiator's private and public keys using the elliptic curve specified by tt(curveName). The initiator's public key (in big-endian hexadecimal format) and tt(curveName) are written to tt(initPubFname). This member is automatically called by the constructor having the same parameters, but it may also explicitly called after using the default constructor; itb(void set(ThePeer peer, std::string const &initPubFname, std::string const &peerPubFname)) This member should be called by the peer, having received the initiator's public info on the file tt(initPubFname). It constructs the peer's private and public keys as well as the shared key. The peer's public key (in big-endian hexadecimal format) is written to tt(peerPubFname), which file is then be sent to the initiator. This member is automatically called by the constructor having the same parameters, but it may also explicitly called after using the default constructor; itb(void set(std::string const &curveName, std::string const &peerPubFname, std::string const &initSecFname, std::string const passphrase = "")) This member should be called by the initiator, once the peer's public key (in the file tt(peerPubFname)) has been received. It computes the initiator's version of the shared key. When using this member the initiator has previously saved the initiator's private key to tt(initSecFname), optionally using encryption. If encryption was used then the then used passphrase must also be specified as this member's last argument. itb(std::string const &sharedKey() const) This member returns the computed shared key (in big-endian hexadecimal format); itb(std::string const &sharedKey(std::string const &peerPubFname)) Instead of using the tt(set(std::string const &curveName, ...)) member or the tt(ECDH(std::string const &curveName, ...)) constructor, the initiator may also merely call the tt(set(TheInitiator init, ...)) member or the tt(ECDH(TheInitiator init, ...)) constructor, suspending the process in which they are called until the file containing the peer's public key has been received. Then, this member can be called by the constructed tt(ECDH) object to obtain the initiator's shared key. The advantage of using this member is that the initiator does not have to save the initiator's private key. ) manpagesection(OVERLOADED OPERATOR) itemization( itb(std::ostream &operator<<(ostream &out, ECDH const &ecdh)) The (alphabetically ordered) currently available elliptic curves and their associated comment is written to tt(out), one elliptic curve on a separate line. ) manpagesection(EXAMPLE) Start the program with one of the following arguments: itemization( it() curves: show the available elliptic curves on tt(cout); it() init: compute the initiator's public/secret keys writing them to tt(init.pub) and tt(init.sec); it() peer: compute the peer's public/secret keys writing them to tt(peer.pub) and tt(peer.sec), compute the peer's shared key (tt(peer.shared)); it() priv: compute the initiator's shared key (tt(init.shared)) after making tt(peer.pub) available in a separate process, using a single initiator process. it() shared: compute the initiator's shared key (tt(init.shared)) using a separate initiator process. ) verbinclude(../../ecdh/driver/main.cc) manpagefiles() em(bobcat/ecdh) - defines the class interface manpageseealso() bf(bobcat)(7), bf(bigint)(3bobcat), bf(diffiehellman)(3bobcat), bf(isymcryptstream)(3bobcat), bf(osymcryptstream)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-6.07.01/documentation/man/ranger.yo0000664000175000017500000001043514673353433017376 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Ranger)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (for-loop iterators) 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), bf(reverse)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-6.07.01/documentation/man/omutexstream.yo0000664000175000017500000001075414673353433020661 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-6.07.01/documentation/man/tablelines.yo0000664000175000017500000000243114673353433020237 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 and move constructors and the move assignment operator are available. manpagesection(MEMBER FUNCTIONS) All public members of tt(TableSupport) are available. 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(csvtable)(3bobcat), bf(table)(3bobcat), bf(tablebuf)(3bobcat), bf(tablesupport)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-6.07.01/documentation/man/csv4180.yo0000664000175000017500000002322714746102756017234 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. The values must consist of standard ascii characters (e.g., UTF-8 formatted values are not recognized). 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-6.07.01/documentation/man/ifdstream.yo0000664000175000017500000000503514673353433020076 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 ) (when using bf(FBB::IFdStream)nl() bf(#include ) (when using bf(FBB::IFdStreamS) Linking option: tt(-lbobcat) manpagedescription() bf(FBB::IFdStream) objects are used to extract information from devices whose file descriptors are available. bf(FBB::IFdStreamS) objects operate like bf(FBB::IFdStream) objects but use bf(FBB::Selector) objects to check whether information on the object's file descriptor is available before reading information from the 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. 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.nl() Use bf(IFdStreamS)(int fd, size_t n = 1) to construct an tt(IFdStreamS) object. ) 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(S)) 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 bf(FBB::IFdStream) class interface+nl() em(bobcat/ifdstreams) - defines the bf(FBB::IFdStreamS) class interface manpageseealso() bf(bobcat)(7), bf(ifdbuf)(3bobcat), bf(ofdstream)(3bobcat), bf(selector)(3bobcat) manpagebugs() The tt(IFdStream(S)) object uses an tt(IFdBuf(S)) for its tt(std::streambuf). This buffer is associated with the file descriptor passed to tt(IFdStream(S))'s constructor. When the tt(IFdStream(S)) object goes out of scope the device (file, socket, etc.) to which the file descriptor that was passed to tt(IFdStream(S))'s constructor is em(not) closed. includefile(include/trailer) bobcat-6.07.01/documentation/man/osymcryptstreambuf.yo0000664000175000017500000001416414673353433022105 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::OSymCryptStreambuf)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Symmetric en- and decryption) manpagename(FBB::OSymCryptStreambuf)(std::streambuf performing symmetric en/decryption) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat -lcrypto) manpagedescription() bf(FBB::OSymCryptStreambuf) objects can be used as tt(std::streambuf) objects of tt(std::ostream) objects, and encrypt or decrypt information, that is made available via separate tt(std::istream) streams. The class tt(OSymCryptStreambuf) is a class template, using a tt(FBB::CryptType) template non-type parameter. Objects of the class tt(FBB::OSymCryptStreambuf) encrypt the information they receive, objects of the class tt(FBB::OSymCryptStreambuf) decrypt the information they receive. All symmetric encryption methods defined by the OpenSSL library that can be selected by name may be used to en/decrypt information. To select a particular encryption method an identifier is passed to the constructor. E.g., tt("aes-256-gcm"). For an overview of the currently supported cipher algorithms issue the command verb( openssl list -cipher-algorithms ) tt(OSymCryptStreambuf) objects read the information to en/decrypt from an external source (e.g., from tt(std::istream) objects). The characters that are encrypted or decrypted by tt(OSymCryptStreambuf) objects are written to tt(std::ostream) objects which are at construction-time specified as tt(ostream) references or by filename. includefile(include/namespace) manpagesection(INHERITS FROM) bf(FBB::OSymCryptBase) (public) The class tt(FBB::OSymCryptBase) is an `internal use only' class, derived from tt(std::streambuf), and therefore tt(OSymCryptStreambuf) is a tt(std::streambuf) class. manpagesection(CONSTRUCTORS) itemization( itb(OSymCryptStreambuf(std::ostream &outStreambuf, std::string const &cipherName, std::string const &key, std::string const &iv, size_t inBufSize = 100)) This constructor defines a tt(std::streambuf) encrypting or decrypting the characters it receives. - tt(OSymCryptStreambuf) objects perform encryption;nl() tt(OSymCryptStreambuf) objects perform decryption; - tt(OSymCryptStreambuf) objects write the encrypted or decrypted characters to tt(outStreambuf);nl() - The encryption method to use is specified by the tt(cipherName) parameter. E.g., tt("AES-256-GCM");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::OSymCryptStreambufbuf) internally used buffer will hold tt(inBufSize) characters. The default value is the smallest value that is used. When specifying a smaller tt(bufSize) value the default value is used;nl() itb(OSymCryptStreambuf(std::string const &outStreambufName, std::string const &cipherName, std::string const &key, std::string const &iv, size_t inBufSize = 100)) Same constructor as the previous one, but this constructor's first parameter specifies the name of the file to receive the encrypted or decrypted characters. ) If the construction fails an exception is thrown, mentioning the openssl function that failed to complete (see also tt(errorMsg) below). The move constructor is available, the copy constructor and assignment operators are not available, manpagesection(INHERITED MEMBERS) Since the class is publicly derived from bf(std::ostream), all tt(std::streambuf) members can be used. manpagesection(MEMBER FUNCTIONS) itemization( itb(static std::string errorMsg()) If an openssl function fails an exception is thrown mentioning the name of the failing function. In those cases the function tt(errorMsg) can be called returning a tt(std::string) containing the openssl error code (returned by tt(ERR_get_error)) and its textual representation (returned by tt(ERR_error_string)). If the reported error code is zero, then in fact no error has occurred and the exception was spuriously reported; itb(static size_t keyLength(std::string const &cipherName)) returns the minimum key length required for cipher tt(cipherName); itb(static size_t ivLength(std::sting const &cipherName)) returns the minimum length of the initialization vector that is required for cipher tt(cipherName). ) The latter two functions throw exceptions if tt(cipherName) does not contain the name of a supported cipher algorithm. manpagesection(MANIPULATOR) itemization( itb(std::ostream &FBB::eoi(std::ostream &out)) By inserting the tt(eoi) manipulator into an tt(std::ostream) object that uses a tt(OSymCryptStreambuf) streambuf insertion is considered complete. It completes the insertion of information into the tt(std::ostream) specified at construction time as the tt(OSymCryptStreambuf's) first argument. That way, you don't have to wait until the tt(OSymCryptStreambuf) object's destructor flushes that stream. The example provided at the bf(osymcryptstream)(3bobcat) man-page illustrates the use of the tt(eoi) manipulator. ) manpagesection(EXAMPLE) See the example in the bf(osymcryptstream)(3bobcat) man-page. Instead of defining an tt(OSymCryptStream) an tt(OSymCryptStreamBuf) can be defined, passing its address to a tt(std::ostream) which can then be used as the tt(OSymCryptStream) used in the example. manpagefiles() em(bobcat/osymcryptstreambuf) - defines the class interface manpageseealso() bf(bobcat)(7), bf(isymcryptstream)(3bobcat), bf(isymcryptstreambuf)(3bobcat), bf(osymcryptstream)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-6.07.01/documentation/man/gs.inc0000664000175000017500000000110214673353433016642 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-6.07.01/documentation/man/cmdfinderbase.yo0000664000175000017500000000145314673353433020706 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-6.07.01/documentation/man/semaphore.yo0000664000175000017500000001722714673353433020111 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-6.07.01/documentation/man/localserversocket.yo0000664000175000017500000001711114673353433021650 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-6.07.01/documentation/man/blockciphers0000664000175000017500000000267114673353433020145 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-6.07.01/documentation/man/hostname.yo0000664000175000017500000000366314673353433017743 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-6.07.01/documentation/man/isharedstream.yo0000664000175000017500000002122414673353433020751 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-6.07.01/documentation/man/tablebuf.yo0000664000175000017500000002546714673353433017717 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(csvtable)(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-6.07.01/documentation/man/mlm.yo0000664000175000017500000000515114673353433016704 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-6.07.01/documentation/man/string.yo0000664000175000017500000002730614673353433017433 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(NESTED TYPE) The struct bf(SplitPair) defines a 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-6.07.01/documentation/man/proc.yo0000664000175000017500000005706314673353433017073 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::Proc)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Running Child Processes) manpagename(FBB::Proc)(Runs external programs) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() The bf(FBB::Proc) offers an alternative to the bf(FBB::Process) class. bf(FBB::Proc) 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 communicate with the standard input, output and error streams of child processes. Objects of the tt(class Proc) use standard process-executing functions, like members of the bf(execl)(2) 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(Proc) parent objects. Input expected by child processes can be inserted into tt(Proc) objects. standard output and standard error generated by child processes are inserted into and further handled by tt(std::ostream) objects, by default tt(std::cout) and tt(std::cerr). When using (output) redirection when executing child processes using 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 (cf. section bf(ENUMERATIONS) for a description of the tt(IOMode) enumeration). tt(Proc) objects may repeatedly be used to execute the same or different child processes. Before the next child process is started, the tt(Proc) object ensures that its currently active child process ends. Alternatively, a currently active child process ends if the tt(Proc) object goes out of scope, if the allotted execution time of the child process has passed, if a new process is started using tt(Proc's) assignment operator, or if its tt(stop) member is called. Otherwise child processes continue until completion when calling tt(finish) or, if the child process reads its standard input stream, when the tt(eoi) manipulator is inserted into the tt(Proc) object. Programs called as child processes may be specified when constructing a tt(Proc) object or by using tt(Proc's setCommand) member. tt(Proc) constructors (or tt(Proc's setCommand)-member) don't start child processes. To start child processes the tt(start) members or the assignment operator must be used. Child processes may receive information at their standard input streams through information inserted into tt(Proc) objects. In those cases tt(Proc) objects must inform their child processes that they have received all input. For this the tt(eoi) manipulator can be inserted into tt(Proc) objects, or tt(Proc's finish) member can be called. If information sent to the child is not fully be processedd by the child process then the operating system issues a tt(Broken pipe) message, indicating that information in a pipe was lost, ending the program. The tt(Proc) class's member tt(pipeSignal) can be used to suppress the tt(Broken pipe) message. 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 also be surrounded by backtics (tt(`)-characters). These backtick characters are removed by the tt(Proc) object when the command starts. Child processes may be allotted a limited amount of time (in seconds) to complete. By default no time limit is imposed upon child processes. If a time limit is specified then the child process, if still running after the specified number of seconds, is ended by sending it a tt(SIGTERM) signal, followed by a tt(SIGKILL) signal (cf. bf(signal)(7)). By default the standard input, output and error streams of child processes are handled by their tt(Proc) parent processes: information inserted into the tt(Proc) object is forwarded to the child process's standard input stream, information sent by the child process to its standard output and error streams are either forwarded to the corresponding streams of the parent process, or they can be processed by streams, configured by the tt(Proc) object. Multiple tt(Proc) processes can be combined using the pipe operator (i.e., the | operator). When used, the standard output stream of the left-hand side (lhs) tt(Proc) object is used as the standard input stream of the right-hand side (rhs) tt(Proc) object. Since the tt(Proc) objects start their own child processes, this effectively boils down to the output of the lhs's child process being used as the input of the rhs's child process. The leftmost tt(Proc) object may also read its input (using the pipe operator) from an tt(istream) object or from a file whose name (path) is specified as the most lhs argument of a pipe expression. Likewise, the rightmost tt(Proc) object may pipe its standard output to an existing tt(ostream) object or to a file whose name (path) is specified as the most rhs argument of a pipe expression. tt(Proc) objects use tt(Pipe) objects (cf. bf(pipe)(3bobcat)) for communication with their 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(Proc) 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(std::ostream) manpagesection(ENUMERATIONS) The following enumerations are defined by the tt(Proc) class: bf(enum ProcType):nl() The bf(enum ProcType) defines how a child proc is started or located. Its values are specified at constructor-time or through the tt(setProcType) member. This enumeration defines the following symbolic constants: itemization( itb(NO_PATH) The program specified as child proc 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 proc. itb(USE_SHELL) The program specified as child proc 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 proc's standard streams can be accessed through the tt(Proc) object. Its symbolic constants may be combined using the tt(bit_or) operator. By default tt(CIN | COUT | CERR) is used (see below). tt(IOMode) arguments may be combined using bit-or operators. The following symbolic constants are available: itemization( itb(ALL) Shortcut for bf(CIN | COUT | CERR). itb(CIN) Information inserted into the tt(Proc) object is forwarded to its child proc. 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 made available as tt(Proc's) standard error stream. 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 is made available as tt(Proc's) standard output stream. If this is not required then tt(CERR) should not be specified. itb(IGNORE_CERR) Information written by the child proc to its standard error stream is ignored (i.e., not made available). An tt(std::invalid_argument) exception is thrown if this mode is specified in combination with bf(CERR, MERGE_COUT_CERR,) and/or bf(REPLACE). itb(IGNORE_COUT) Information written by the child proc to its standard output stream is ignored. An tt(std::invalid_argument) exception is thrown if this mode is specified in combination with bf(COUT, MERGE_COUT_CERR) and/or bf(REPLACE). itb(IGNORE_COUT_CERR) Shortcut for tt(IGNORE_CERR | IGNORE_COUT). itb(MERGE_COUT_CERR) Information written by the child process to its standard output and standard error streams is made available at the tt(Proc) object's standard output stream. An tt(std::invalid_argument) exception is thrown if this mode is specified in combination with bf(COUT, CERR, IGNORE_COUT, IGNORE_CERR) or tt(REPLACE). itb(NONE) The tt(Proc) object does not insert information into the standard input streams of its child process and information written by the child process to its standard output or error streams is not forwarded to the tt(Proc) object. Instead, the child process processes its standard streams by itself. When this mode is specified in combination with other tt(IOMode) values it is silently ignored. itb(REPLACE) When starting a child proc (see below at the member tt(start)) the current process (i.e., the program defining the tt(Proc) 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. ) manpagesection(CONSTRUCTOR) Note that child processes are em(not) started automatically following the construction of t(Proc) objects. A tt(start) member or the assignment operator (see below) is used to start child processes. Once a tt(Proc) object has been constructed its parameters can be changed using tt(set)-member functions or tt(start) members. itemization( itb(explicit Proc(std::string const &command = "", IOMode mode = ALL, ProcType type = NO_PATH, size_t bufSize = 200, size_t timeLimit = 0, bool pipeSignal = true)) The parameter tt(bufSize) defines the size of the tt(streambuf) buffers used by the tt(Proc) object. The tt(timeLimit) specifies the maximum execution time of a child process in seconds; when tt(timeLimit == 0) no execution time limit is used. When tt(pipeSignal == true) incomplete processing of information sent to or read from the child process results in a tt(Broken pipe) exception, terminating the program. When specifying tt(false) the tt(Broken pipe) exception is suppressed, and the input and/or output streams do not have to be completely processed (see also tt(pipeSignal's) description). ) Copy and move constructors (and assignment operators) are not available. manpagesection(OVERLOADED OPERATORS) itemization( itb(Proc &operator<<(Type value)) This operator inserts tt(value) into the child's standard input stream. I.e., the child proc 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(Proc) object. Nothing happens if the member is used when the child proc has terminated. Manipulators like tt(std::endl) are also supported. The behavior of this operator is undefined when tt(IOMode CIN) has not been specified. itb(Proc &operator+=(std::string const &)) This operator adds the provided tt(std::string) object to the currently defined command specification of a tt(Proc) 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(Proc) object, and thereupon starts `tt(cmd)' as its child process. 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 ending and restarting another command should be separate actions then use tt(finish) or tt(stop) followed by tt(setCommand), followed by calling an appropriate overloaded version of the member tt(start). itb(Return operator|(Proc &lhs, Proc &rhs)) This operator implements em(piping). Information sent by tt(lhs) to its standard output is used as the standard input of the tt(rhs)'s child process. The tt(Return) value is tt(rhs) if the expression is followed by another pipe-operator or it is tt(void). itb(Return operator|(std::istream &in, Proc &proc)) This operator implements em(piping). Information read from tt(in) is read by tt(proc's) child process. The tt(Return) value is tt(proc) if the expression is followed by another pipe-operator or it is tt(void). itb(Return operator|(std::string const &fname, Proc &proc)) This operator implements em(piping). information in the file whose file (path) name is tt(fname) is read by tt(proc's) child process. The tt(Return) value is tt(proc) if the expression is followed by another pipe-operator or it is tt(void). itb(void operator|(Proc &proc, std::ostream &out)) This operator implements em(piping). Information sent by tt(proc's) child process to its standard output stream is written to tt(out). itb(void operator|(Proc &proc, std::string &fname)) This operator implements em(piping). Information sent by tt(proc's) child process to its standard output stream is written to the file whose file (path) name is tt(fname).) The pipe (|) operator mimics the pipe-operator supported by most command-shell programs and should not be confused with the tt(bit-or) operator. The pipe operator allows constructions like verb( p1 | p2 | p3 // piping 3 Proc objects cin | p1 | p2 | cout // p1 reads cin, p2 writes cout inName | p1 | outName // inName: file name of the file // read by p1, outName: file name // of the file written by p1 ) When using the pipe operator tt(Proc) objects reading input automatically specify their tt(CIN) modes, while tt(Proc) objects writing their standard output automatically specify their tt(COUT) modes. Following the pipe-expression the tt(IOMode) specifications which were specified before the pipe-expression are restored. manpagesection(MEMBERS) itemization( itb(bool active()) If the child proc is currently running tt(true) is returned and and tt(false) if not. itb(void cerrMode(char const *lab) const) The label tt(lab), followed by the a textual representation of the currently configured tt(IOMode) is inserted into tt(std::cerr). itb(void cerrPipes(char const *lab) const) The text tt(Proc), followed by the tt(Proc's) id, followed by label tt(lab), followed by the currently active read and write file descriptors of the pipes currently used by the tt(Proc) object are inserted into tt(std::cerr). itb(std::string const &cmd() const) The currently specified child-process starting command is returned. itb(int exitStatus() const) The last child-process's exit-status is returned. If a child process is currently running or if no child process has yet been started -1 is returned. itb(int finish()) Waits until a currently active child process has ended and returns its exit status. If the child process isn't currently running -1 is returned. itb(IOMode ioMode() const) The tt(IOMode) currently used by the tt(Proc) object is returned. itb(std::string mode() const) The tt(IOMode) currently used by the tt(Proc) object is returned as a text-string. itb(int pid() const) The child process's process-id is returned. The returned value is undefined if no child process has yet been started. If the child process has already completed the last child process's id is returned. itb(void pipeSignal(bool on)) When incompletely forwarding information to a child process or incompletely reading information from a child process a tt(Broken pipe) may result, ending the currently running program. To avoid this, tt(pipeSignal(false)) can be called. To reactivate recognizing broken pipes tt(pipeSignal(true)) can be called. After using tt(pipeSignal(false)) failing insertions into a tt(Proc) object result in its member tt(good) returning tt(false), and its members tt(bad) and tt(fail) returning tt(true). itb(size_t procIdx() const) Every constructed tt(Proc) object receives its own construction-order index. The first tt(Proc) object constructed in a program gets index value 0. itb(ProcType procType() const) The tt(ProcType) used when starting child processes is returned. itb(void setBufSize(size_t bufSize)) The stream buffer size in bytes used by streams communicating with child processes is set to tt(bufSize). A zero byte buffer size is silently changed into one. itb(void setCommand(std::string const &cmd)) The (initial part of a) child process command specification is set to tt(cmd). After calling this member tt(operator+=) can be used to append additional text to the command specification. itb(void setIOMode(IOMode mode)) The tt(IOMode) used when calling child processes is set to tt(mode). Note that pipe-expressions may modify the tt(mode) of tt(Proc) objects while the pipe-expression is executed. For details see the end of the bf(OVERLOADED OPERATORS) section. itb(void setProcType(ProcType type)) The tt(ProcType) used when starting child processes is set to tt(type). itb(void setTimeLimit(size_t timeLimit)) The execution time limit of child processes is set to tt(timeLimit) (in seconds). No time limit is used when tt(timeLimit 0) is specified. The time limit set by tt(setTimeLimit) is used when starting the next child process. When calling tt(setTimeLimit) then tt(pipeSignal(timeLimit == 0)) is automatically called. If that's not intended, then explicitly call tt(pipeSignal) after calling tt(setTimeLimit). itb(void start(size_t timeLimit, IOMode mode = ALL, ProcType type = NO_PATH, size_t bufSize = 200)) The currently specified command is started using the specified tt(timeLimit, IOMode, ProcType) and tt(bufSize) arguments. The tt(start) members do not alter the currently configured default values of their arguments. If a child process is still active when tt(start) is called it first calls tt(stop) to end the currently running child process itb(void start(IOMode mode, ProcType type = NO_PATH, size_t bufSize = 200)) Same as the previous tt(start) member, but using the currently configured tt(timeLimit) and requiring the specification of the tt(IOMode) to use. itb(void start()) Same as the first tt(start) member, but using the currently configured tt(timeLimit, IOMode, ProcType) and tt(bufSize) values. itb(int stop()) A currently active child process is ended by calling tt(Fork::endChild) (see also bf(fork)(3bobcat)). itb(void system(size_t timeLimit, IOMode mode = ALL, size_t bufSize = 200)) The currently stored command is executed as a command of bf(sh)(1), using the specified process-arguments. itb(void system(IOMode mode = ALL, size_t bufSize = 200)) Same as the previous tt(system) command, but using the default tt(timeLimit) specification. itb(size_t timeLimit() const) The currently configured execution time limit of tt(Proc's) child process is returned. The return value zero indicates that no time limit is used. itb(void useErr(std::ostream &out)) The standard error output produced by the child process is sent to tt(out). If the tt(Proc) object had specified tt(IGNORE_CERR) then that tt(IOMode) is unset, and the tt(CERR) mode is set. itb(void useErr(std::string const &fname)) Same as the previous member, but the child's standard error output is written to the file (path) tt(fname). itb(void useMerge(std::ostream &out)) The standard output and standard error output produced by the child process is sent to tt(out). If the tt(Proc) object had specified tt(CERR, COUT, IGNORE_CERR), or tt(IGNORE_COUT) then those tt(IOModes) are unset, and the tt(MERGE_COUT_CERR) mode is set. itb(void useMerge(std::string const &fname)) Same as the previous member, but the child's standard output and standard error output is written to the file (path) tt(fname). itb(void useOut(std::ostream &out)) The standard output produced by the child process is sent to tt(out). If the tt(Proc) object had specified tt(IGNORE_COUT) then that tt(IOMode) is unset, and the tt(COUT) mode is set. itb(void useOut(std::string const &fname)) Same as the previous member, but the child's standard output is written to the file (path) tt(fname). itb(int waitForChild()) This member calls the identically named member from the class tt(FBB::Fork), waiting for a child process to end. When calling tt(finish) or using pipe-expressions tt(waitForChild) is automatically called. ) manpagesection(EXAMPLES) All examples should start with: verb( #include #include using namespace std; using namespace FBB; ) The first example illustrates how a program only producing output can be called. Its child proc simply is tt(/bin/ls): verbinsert(//CODE ../../proc/driver/ls.cc) The next example illustrates a child program that's 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 ../../proc/driver/limit.cc) Piping is illustrated next: information at the program's standard input is piped to a second tt(Proc) object, writing its standard output to the program's standard output stream: verbinsert(//CODE ../../proc/driver/pipe.cc) manpagefiles() em(bobcat/proc) - defines the class interface manpageseealso() bf(bobcat)(7), bf(execle)(3), bf(fork)(3bobcat), bf(process)(3bobcat), bf(ostream)(3fork), bf(sh)(1) manpagebugs() includefile(include/trailer) bobcat-6.07.01/documentation/man/primefactors.yo0000664000175000017500000001415614673353433020622 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() 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-6.07.01/documentation/man/syslogbuf.yo0000664000175000017500000001775614673353433020152 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-6.07.01/documentation/man/gethostent.yo0000664000175000017500000000773014673353433020310 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-6.07.01/documentation/man/onekey.yo0000664000175000017500000000540214673353433017410 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-6.07.01/documentation/man/field.yo0000664000175000017500000001050414673353433017200 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-6.07.01/documentation/man/osymcryptstream.yo0000664000175000017500000001344714673353433021413 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::OSymCryptStream)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Symmetric en- and decryption) manpagename(FBB::OSymCryptStream)(std::ostream performing symmetric en/decryption) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat -lcrypto) manpagedescription() bf(FBB::OSymCryptStream) objects can be used to encrypt or decrypt information, that is available on separate tt(std::istream) streams. The class tt(OSymCryptStream) is a class template, using a tt(FBB::CryptType) template non-type parameter. Objects of the class tt(FBB::OSymCryptStream) encrypt the information they receive, objects of the class tt(FBB::OSymCryptStream) decrypt the information they receive. All symmetric encryption methods defined by the OpenSSL library that can be selected by name may be used to en/decrypt information. To select a particular encryption method an identifier is passed to the constructor. E.g., tt("aes-256-gcm"). For the currently supported cipher algorithms issue the command verb( openssl list -cipher-algorithms ) tt(OSymCryptStream) objects read the information to en/decrypt from an external source (e.g., from tt(std::istream) objects). The characters that are encrypted or decrypted by tt(OSymCryptStream) objects are written to tt(std::ostream) objects which are at construction-time specified as tt(ostream) references or by filename. includefile(include/namespace) manpagesection(INHERITS FROM) bf(FBB::OSymCryptStreambuf) (private), nl() bf(std::istream) manpagesection(CONSTRUCTORS) itemization( itb(OSymCryptStream(std::ostream &outStream, std::string const &cipherName, std::string const &key, std::string const &iv, size_t inBufSize = 100)) This constructor defines a tt(std::streambuf) encrypting or decrypting the characters it receives. - tt(OSymCryptStream) objects perform encryption;nl() tt(OSymCryptStream) objects perform decryption; - tt(OSymCryptStream) objects write the encrypted or decrypted characters to tt(outStream);nl() - The encryption method to use is specified by the tt(cipherName) parameter. E.g., tt("AES-256-GCM");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::OSymCryptStreambuf) internally used buffer will hold tt(inBufSize) characters. The default value is the smallest value that is used. When specifying a smaller tt(bufSize) value the default value is used;nl() itb(OSymCryptStream(std::string const &outStreamName, std::string const &cipherName, std::string const &key, std::string const &iv, size_t inBufSize = 100)) Same constructor as the previous one, but this constructor's first parameter specifies the name of the file to receive the encrypted or decrypted characters. ) If the construction fails an exception is thrown, mentioning the openssl function that failed to complete (see also tt(errorMsg) below). The move constructor is available, the copy constructor and assignment operators are not available, manpagesection(INHERITED MEMBERS) Since the class is publicly derived from bf(std::ostream), all tt(std::ostream) members can be used. manpagesection(MEMBER FUNCTIONS) itemization( itb(static std::string errorMsg()) If an openssl function fails an exception is thrown mentioning the name of the failing function. In those cases the function tt(errorMsg) can be called returning a tt(std::string) containing the openssl error code (returned by tt(ERR_get_error)) and its textual representation (returned by tt(ERR_error_string)). If the reported error code is zero, then in fact no error has occurred and the exception was spuriously reported; itb(static size_t keyLength(std::string const &cipherName)) returns the minimum key length required for cipher tt(cipherName); itb(static size_t ivLength(std::sting const &cipherName)) returns the minimum length of the initialization vector that is required for cipher tt(cipherName). ) The latter two functions throw exceptions if tt(cipherName) does not contain the name of a supported cipher algorithm. manpagesection(MANIPULATOR) itemization( itb(std::ostream &FBB::eoi(std::ostream &out)) By inserting the tt(eoi) manipulator into an tt(OSymCryptStream) object insertion is considered complete. It completes the insertion of information into the tt(std::ostream) specified at construction time as the tt(OSymCryptStream's) first argument. That way, you don't have to wait until the tt(OSymCryptStream) object's destructor flushes that stream. In the following example using the tt(eoi) manipulator is illustrated in the (commented out lines near line 40): verb( //in.seekg(0); // when activated, this won't //enc << in.rdbuf(); // be processed due to '<< eoi' ) Activating those lines will not result in processing the tt(in) stream twice. ) manpagesection(EXAMPLE) verbinsert(-a ../../osymcryptstream/driver/driver.cc) manpagefiles() em(bobcat/osymcryptstream) - defines the class interface manpageseealso() bf(bobcat)(7), bf(isymcryptstream)(3bobcat), bf(isymcryptstreambuf)(3bobcat), bf(osymcryptstreambuf)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-6.07.01/documentation/man/sharedsegment.yo0000664000175000017500000002242014673353433020746 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). To return the shared segment to the operating system tt(deleteSegment) should be used. 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. Note that detaching a memory segment does not destroy it. To return a shared segment to the operating system tt(deleteSegment) should be used. 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-6.07.01/documentation/man/hash.yo0000664000175000017500000000647014673353433017047 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-6.07.01/documentation/man/symcryptciphers0000664000175000017500000001015614673353433020742 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-6.07.01/documentation/man/stat.yo0000664000175000017500000002705714673353433017103 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-6.07.01/documentation/man/configfile.yo0000664000175000017500000003474614673353433020240 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-6.07.01/documentation/man/fork.yo0000664000175000017500000002004514673353433017057 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(int endChild() const) This member may be called by tt(parentProcess) to end the child process. To end the child process a tt(SIGTERM) is sent to the child process, followed by a tt(SIGKILL) (cf. bf(signal)(7)). If the child process has already ended then the child process's exit value is returned, otherwise the child process's end is forced (by calling tt(kill)) and -2 is returned. This member also calls tt(waitForChild) (see below). 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). The tt(pid) member returns -1 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() const) 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(PRIVATE (VIRTUAL) 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. When deriving classes from tt(Fork) their tt(parentProcess) implementation preferably handles all actions to perform by the parent process. If the child process remains active when the parent process decides that the program has performed its duties (e.g., the child process is replaced by a program started by an tt(exec..) function, continuously producing output, interpreted by the parent process) then the parent process can call tt(endChild) to end the child process before ending the tt(parentProcess) function. 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. ) 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)(3), bf(exec)(3bobcat), bf(fork)(2), bf(kill)(2), bf(pipe)(3bobcat), bf(redirector)(3bobcat), bf(stdextractor)(3bobcat), bf(wait)(2), bf(waitpid)(2). manpagebugs() None Reported. includefile(include/trailer) bobcat-6.07.01/documentation/man/typetrait.yo0000664000175000017500000000622014673353433020142 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::TypeTrait)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Type traits) manpagename(FBB::TypeTrait)(Type trait class) 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-6.07.01/documentation/man/selector.yo0000664000175000017500000001332014673353433017734 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-6.07.01/documentation/man/binops.yo0000664000175000017500000001330714673353433017413 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-6.07.01/documentation/man/ibase64buf.yo0000664000175000017500000000670114673353433020053 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-6.07.01/documentation/man/iterator.yo0000664000175000017500000001242614673353433017753 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-6.07.01/documentation/man/bigint.yo0000664000175000017500000010407014673353433017373 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). Note that none of the constructors expecting a tt(BIGNUM) argument modify their argument. If the memory used by the tt(BIGNUM) argument must be returned to the common pool an explicit bf(BN_free)(3ssl) call is required; 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) (having its most significant value at index 0). 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 (most significant byte at index 0). 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 (having its most significant value at index 0). 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); itb(BigInt(size_t length, char const *littleEndian, bool negative = false)) This constructor initializes a tt(BigInt) from tt(length) little-endian encoded bytes stored in tt(littleEndian) (having its least significant value at index 0). This constructor interprets the tt(char) values pointed at by tt(littleEndian) as unsigned values. Use this constructor to reconstruct a tt(BigInt) object from the data made available by the tt(littleEndian) member (most significant byte at index 0). If the number represents a negative value, then provide a third argument tt(true); itb(explicit BigInt(BigInt::Little endian, std::string littleEndian, bool negative = false)) This constructor initializes a tt(BigInt) from the bytes stored in tt(littleEndian), which must be little-endian encoded (having its least significant value at index 0). This constructor interprets the tt(char) values stored in tt(littleEndian) as unsigned values. If the number that is stored in tt(littleEndian) represents a negative value, then provide a third argument tt(true). The consructor's first parameter is used to distinguish this constructor from the constructor expecting a t(string) whose bytes represent a big-endian encoded value, and is not used by this constructor itself. It can be specified as tt(BigInt::Little{}). ) 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 or use the member tt(littleEndian) to receive the representation in 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(char *littleEndian() const) The value represented by the current object is stored in a series of tt(char) typed values in little-endian order. If a value consists of 5 tt(char)s the eight least significant bits will be stored in the tt(char) having index value 0. To receive the bytes in big-endian order the member tt(bigEndian) can be used. The return value consists of a series of tt(sizeInBytes()) (see below) dynamically allocated tt(char) values. The caller of tt(littleEndian) 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 &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; 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++()) Unary prefix increment operator; itb(BigInt operator++(int)) Unary postfix increment operator; itb(BigInt &operator--()) Unary prefix decrement operator; itb(BigInt operator--(int)) Unary postfix decrement operator; itb(BigInt operator-()) Unary negation 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) member; itb(BigInt operator>>=(BigInt const &lhs, size_t nBits)) See also the tt(rshift) member; 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 for real 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 for real 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 merely calls tt(BigInt::rand); itb(BigInt pseudoRandRange(BigInt const &max)) This member merely calls tt(BigInt::randRange). ) 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. This conversion isn't very fast. For faster conversion consider using the LDC class (cf. bf(ldc)(3bobcat)) in statements like verb( BigInt value; // contains a positive value // insert value using decimal digits: std::cout << LDC{ value }; ) 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) verbinclude(../../bigint/driver/example.cc) manpagefiles() em(bobcat/bigint) - defines the class interface manpageseealso() bf(bobcat)(7), bf(diffiehellman)(3bobcat), bf(ldc)(3bobcat), bf(RAND_add)(3ssl), bf(RAND_egd)(3ssl), bf(RAND_load_file)(3ssl), bf(RAND_seed)(3). For tt(BIGNUM):nl() tt(https://www.openssl.org/docs/man1.0.2/man3/bn_sub_words.html) manpagebugs() None Reported. includefile(include/trailer) bobcat-6.07.01/documentation/man/sharedstream.yo0000664000175000017500000002272414673353433020606 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-6.07.01/documentation/man/manipulators.yo0000664000175000017500000000712414673353433020637 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-6.07.01/documentation/man/iostream.yo0000664000175000017500000000607014673353433017743 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-6.07.01/documentation/man/eoi.yo0000664000175000017500000000664214673353433016701 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(MANIPULATOR) itemization( itb(std::ostream &FBB::eoi(std::ostream &out)) The tt(eoi) manipulator can be inserted into the tt(ostream) using a streambuf which is inherited from tt(FBB::EoiBuf) to stop further insertions into the tt(ostream). If it is inserted into a plain tt(std::ostream) nothing happens. tt(eoi) can also be called as a function, receiving the stream that uses an tt(FBB::EoiBuf) as its tt(streambuf). By default the tt(eoi) manipulator performs no actions. To use the manipulator in a class derived from tt(EoiBuf) the following approach can be used: verb( 1. define a tt(bool d_eoi) data member, initialized to tt(false); 2. define a tt(void eoi_() override) member; 3. tt(eoi_) returns if tt(d_eoi == true), otherwise: 4. it sets tt(d_eoi) to tt(true) and performs the actions normally performed by the class's destructor; 5. the class's destructor calls tt(eoi_()). ) ) manpagesection(EXAMPLE) See the example provided in the tt(osymcryptstream)(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-6.07.01/documentation/man/redirector.yo0000664000175000017500000002076414673353433020270 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-6.07.01/documentation/man/filesystem.yo0000664000175000017500000005331214737267135020311 0ustar frankfrankincludefile(include/header) COMMENT(replace 'filesystem' by the name of the new class) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::FileSystem)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Wraps std::filesystem) manpagename(FBB::Filesystem)(class offering std::filesystem facilities) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) This header file also includes the tt(std::chrono) header file. manpagedescription() The Bobcat class bf(FileSystem) is a plain wrapper around the facilities offered by the bf(C++) tt(std::filesystem) namespace. bf(FileSystem) was developed because the use of the tt(std::filesystem) facilities is considered overly complex: too many free functions having signatures resembling bf(C), and therefore not object-based. Its tt(std::filesystem::path) type offers several nice features which are then usable via the tt(path) member functions, but functions manipulating the file system aren't members, but are defined as free functions requiring tt(path) arguments. The class bf(FileSystem) offers almost all tt(std::filesystem) facilities via its member functions. Except for some (static) members all facilities operate on data stored inside bf(FileSystem) objects. The class bf(FileSystem) is an extensive class: over-all it contains about 60 constructors, operators and members. It'll probably take a while before a mental picture of what the class offers has been attained, but at least it embeds all components of the tt(std::filesystem) namespace. Note: itemization( it() The class bf(FileSystem) uses tt(std::chrono::file_clock), which is available since the tt(C++-2a) standard: specify the tt(--std=c++2a) (or more recent) compiler option when using bf(FileSystem). ) includefile(include/namespace) manpagesection(INHERITS FROM) tt(FBB::FS) - internally used only, covered in this man-page manpagesection(TYPEDEFS AND ENUMS) bf(Typedefs:) itemization( it()bf(DirEntry) - tt(std::filesystem::directory_entry) it()bf(DirIter) - tt(std::filesystem::directory_iterator) it()bf(EC) - tt(std::error_code) it()bf(FileClock) - tt(std::chrono::file_clock) it()bf(FileType) - tt(std::filesystem::file_type) it()bf(Path) - tt(std::filesystem::path) it()bf(Perms) - tt(std::filesystem::perms) it()bf(RecursiveIter) - tt(std::filesystem::recursive_directory_iterator) it()bf(FileStatus) - tt(std::filesystem::file_status) it()bf(SystemClock) - tt(std::chrono::system_clock) ) bf(FSOptions:) itemization( itb(enum FSOptions) contains the following values, inherited by tt(FileSystem). Options up to tt(CP_MASK) are primarily used by the tt(copy) member, options beyond tt(CP_MASK) are used by tt(setPermissions): COMMENT( DEFAULT used by default when cally copy or setting permission options to the specified ones ) verb( NEW copy is only performed if the destination doesn't yet exist REPLACE copy is only performed if the destination exists but it is replaced UPDATE copy is only performed if the destination is older than the filesystem entry to copy RECURSIVE directories are recursively copied; can be combined with CP_SYMLINKS, SKIP_SYMLINKS, ONLY_DIRS CP_SYMLINKS symlinks are copied as symlinks SKIP_SYMLINKS symlinks are ignored ONLY_DIRS only the directory structure is copied other entries in directories are ignored SYMLINK with copy: define a symlink to the current entry HARDLINK with copy: define a hard link to the current entry FILE with copy: only files are processed, not directories CP_SYMLINK copies a symlink to a symlink NEW_SYMLINK defines a non-existing (directory) symlink NEW_LINK create_hard-link CP_MASK all the above enum values RESET replace the current permissions ADD add to the current permissions REMOVE remove the specified permissions ) ) All bit-wise operators are available for bf(FSOptions) values. manpagesection(STATIC DATA MEMBER) The class tt(FileSystem) defines one static data member: tt(std::error_code s_errorCode). All tt(FileSystem) objects can use this tt(error_code) object after calling their function call operator. E.g., verb( FileSystem fs; fs(); ) Once tt(fs()) has been called members called by tt(fs) accepting tt(error_code) arguments receive tt(s_error_code) as their argument. It's also possible to use other tt(error_code) objects, or not to use tt(error_code) arguments (which is the default). See also the description of the function call operator below. manpagesection(CONSTRUCTORS) tt(Path) arguments can also be arguments of types from which tt(Path) objects can be constructed (e.g., tt(std::string, char const *), raw string literal). tt(FileSystem) objects contain two data members: a tt(Path) and an tt(EC *). When tt(FileSystem) objects are initialized their tt(EC *) is set to 0. itemization( itb(Filesystem()) The default constructor constructs an empty object, not using the class's static tt(s_errorCode) object; itb(Filesystem(Path const &path, bool useEC = true)) The object is initialized with a copy of tt(path). By default tt(useEC == true), in which case it uses the class's static tt(s_errorCode) object; itb(Filesystem(Path &&path, EC &ec)) The object is initialized with a copy of tt(path), passing tt(ec) to members supporting tt(EC) arguments; itb(Filesystem(Path const &tmp, bool useEC = true)) The object moves tt(tmp) to its internal tt(path). By default tt(useEC == true), in which case it uses the class's static tt(s_errorCode) object; itb(Filesystem(Path &&tmp, EC &ec)) The object moves tt(tmp) to its internal tt(path), passing tt(ec) to members supporting tt(EC) arguments. ) Copy and move constructors (and assignment operators) are available. The newly constructed or assigned object use the same tt(EC) specification as their source (right-hand side) objects. manpagesection(OVERLOADED OPERATORS) tt(Type) arguments can be arguments of type tt(FileSystem, Path) or types from which tt(Path) objects can be constructed (e.g., tt(std::string, char const *), raw string literal). itemization( itb(std::istream &operator>>(std::istream &in, FileSystem &rhs)) extracts a tt(path) specification from tt(in), and initializes tt(rhs) with the extracted path; itb(std::ostream &operator<<(std::ostream &out, FileSystem const &rhs)) inserts the object's tt(path) into tt(out); itb(bool operator==(FileSystem const &lhs, FileSystem const &rhs)) returns tt(true) if tt(lhs) and tt(rhs) refer to the same file system entry. An exception is thrown if at least one argument doesn't refer to an existing file system entry and the tt(lhs) operand hasn't specified an tt(EC) (see tt(operator()()) below). This operator calls the member tt(sameAs) for its tt(lhs) argument; itb(FileSystem &operator/=(Type const &arg)) tt(arg) is appended to the object's tt(path) data member. If the tt(path) data member did not already end in tt('/') then tt(/arg) is appended; itb(FileSystem &operator+=(Type const &arg)) tt(arg) is appended to the object's tt(path) data member; itb(FileSystem [const] &operator()(EC &ec = s_errorCode) [const]) this operator activates passing tt(EC) arguments to member function accepting such arguments. By calling this operator without argument member functions receive tt(FileSystem's s_errorCode). Alternatively another (e.g., local) tt(error_code) object can be specified which will then be passed to members accepting tt(error_code) arguments. Example: verb( std::error_code ec; FileSystem fs; fs(ec); ) Using tt(EC) arguments is configured separately for each tt(FileSystem) object. The member tt(noEC) can be used to suppress passing tt(EC) arguments to tt(std::filesystem) functions; ) manpagesection(MEMBER FUNCTIONS) tt(Type) arguments can be arguments of type tt(FileSystem, Path) or types from which tt(Path) objects can be constructed (e.g., tt(std::string, char const *), raw string literal). All members can use tt(EC) objects to prevent exceptions being thrown when the members cannot perform their tasks. itemization( itb(FileSystem absolute() const) returns a tt(FileSystem) object containing the absolute path of the calling object's tt(Path), which does not have to exist. Relative directory specifications are kept: tt(absolute) simply prefixes the current working directory to the calling object's tt(Path); itb(FileSystem canonical() const) returns a tt(FileSystem) object containing the canonical absolute path of the calling object's tt(Path), from which all relative specifications have been removed. tt(Path) must refer to an existing file system entry; itb(bool copy(Type const &dest, FSOptions cpOptions = DEFAULT)) copies the object's file system entry to tt(dest). It is covered in detail in the section bf(COPYING FILE SYSTEM ENTRIES) below; itb(uintmax_t count() const) returns the number of hard-link counts of the calling tt(FileSystem) object. The file system entry must exist; itb(char const *c_str() const) returns the calling object's tt(PATH) specification as a NTBS; itb(static FileSystem cwd([EC &ec])) this static member returns the current working directory (cwd). If the cwd cannot be determined then an exception is thrown, unless an tt(EC) argument is specified, in which case the tt(EC) argument provides information about the failure; itb(FileSystem destination() const) returns a tt(FileSystem) object containing the (symlink) destination of the calling object, which must refer to a symlink; itb(DirEntry directory() const) returns a tt(DirEntry) for the calling object. The calling object does not have to refer to a directory, and not even to an existing file system entry; itb(Ranger dirRange() const) returns a pair of directory iterators non-recursively visiting all entries referred to by the calling object, which must specify a directory name (see also the member tt(recursiveRange)). Example: verb( for (auto const &entry: fs.dirRange()) cout << entry << '\n'; ) itb(static std::error_code &errorCode()) this static member returns a reference to tt(FileSystem's) static (modifiable) tt(EC) data member. itb(bool exists() const) returns tt(true) if the current object's file system entry exists; itb(static bool exists(FileStatus status)) returns tt(true) if tt(status) indicates that the current file system entry exists (see also the member tt(status) below); itb(std::string extension() const) returns the extension (including the initial dot (.) of the calling object); itb(FileClock::time_point fcModification() const) returns the tt(FileClock::time_point) of the (existing) file system entry represented by the calling object; itb(std::string filename() const) returns the filename (i.e., the path name from which all but the last element has been removed). If the calling object doesn't contain a filename (as with tt(./) or tt(/)) then and empty tt(string) is returned; itb(bool hasExtension() const) returns tt(true) if the calling object's tt(Path) has an extension; itb(bool hasFilename() const) returns tt(true) if the calling object's tt(Path) contains characters after its final tt(/) character; itb(bool isAbsolute() const) returns tt(true) if the calling object's tt(Path) starts with tt(/); itb(bool isRelative() const) returns tt(true) if the calling object's tt(Path) does not start with tt(/); itb(bool knownStatus() const) this member only returns tt(false) for tt(std::filesystem::file_status{}). The member tt(status) is probably more useful: non-existing entries show status values tt(FileType::not_found) or tt(FileType::unknown).nl() To check for specific statuses the functions+nl() tt(bool is_WHATEVER(file_status status)) or+nl() tt(bool is_WHATEVER(path const &entry [, EC &ec]))nl() can also be used; itb(bool mkDir() const) returns tt(true) if the (plain) directory name stored in the calling oblect could be created. This member does not create nested sub-directories, but the directory name specified as the last (tt(/)-separated) component of the calling object's tt(Path) is created if its parent directories already exist; itb(bool mkDir(Type const &reference) const) same as the previous member, but the created directory receives the same attributes (permissions) as tt(reference); itb(bool mkDirs() const) returns true if the last component of the calling object's tt(Path) could be created and its parent components could either be created or already existed as directories. Only the directories are constructed, not their entries. Use the tt(copy) member (see section tt(COPYING FILE SYSTEM ENTRIES) below) to copy directories and their file system entries; itb(SystemClock::time_point modification() const) returns the tt(SystemClock::time_point) of the (existing) file system entry represented by the calling object; itb(FileSystem [const] &noEC() [const]) if the calling object uses an tt(EC), then the tt(EC) won't be used anymore after calling this member; itb(FileSystem parent() const) returns a tt(FileSystem) object initialized with the parent tt(Path) of the calling object. The tt(parent) is equal to the calling object's tt(Path) from which its tt(filename) has been removed (returning an empty object if the calling object merely contains `tt(/)'); itb(Path const &path() const) returns the current object's tt(Path) data member. When inserting tt(path()) into an tt(ostream) tt(Path) is surrounded by double quotes. If that's not required call the tt(string) member; itb(Perms permissions() const) returns the permissions of the calling object, which must refer to an existing file system entry. The returned tt(Perms) value consists of bitwise or-ed values of the tt(std::filesystem::perms enum class), but can be statically cast to tt(mode_t) values which are used as argument to bf(chmod)(2); itb(Ranger<[Const]Iter> range() [const]) returns a pair of iterators visiting all components of the calling object's tt(Path).Example: verb( for (auto const &comp: fs.range()) cout << comp << '\n'; ) itb(FileSystem relative() const) returns a copy of the calling object from which an initial `tt(/)' has been removed; itb(bool remove() const) returns tt(true) if the current object's file system entry has been removed; itb(size_t removeAll() const) returns the number of (recursively) removed file system entries starting at the calling object's tt(Path). The calling object doesn't have to specify a directory; itb(bool rename(Type const &newName) const) returns tt(true) if the current file system entry could be renamed to tt(newName). The calling object's tt(Path) is not altered; itb(bool resize(std::uintmax_t size) const) returns tt(true) if the current file system entry could be resized to tt(size); itb(bool sameAs(Type const &other) const) returns tt(true) if tt(other) refers to the same file system entry as the calling object. It is called by tt(operator==) as its tt(lhs) member; itb(FileSystem &setCwd()) changes the current process's current working directory to the directory specified by the calling object; itb(static FileSystem setCwd(Path const &path [, EC &ec])) this static member changes the current process's current working directory to the directory specified by its tt(Path) argument; itb(FileSystem &setExtension(std::string const &ext)) changes the filename extension of the current object to tt(ext). A dot (tt(.)) is used to separate the current object's tt(stem) (see below) and the extension. The resulting file name only has a single dot; itb(FileSystem &setFilename(std::string const &newName)) changes the current object's file name (including its extension) to tt(newName). If the current object refers to an existing file system entry then that file system entry is kept as-is; itb(bool setModification(FBB::DateTime const &time)) changes the modification time of the current file system entry to the tt(time) time-specification; itb(bool setModification(SystemClock::time_point const &time)) changes the modification time of the current file system entry to the tt(time) time-specification; itb(FileSystem [const] &setPermissions(PermType perms, FSOptions opt = RESET) [const]) changes the permissions of the current file system entry to tt(perms), which must be statically castable to tt(Perms). Example: verb( // change "entry's" permissions to -rw------- FileSystem{ "entry" }.setPermissions(0600); ) itb(bool setType(FileType type, bool destination = true)) it's unclear what this function is used for. It calls tt(filesystem::(symlink_)status), using tt(symlink_status) when called as tt(type(false)). It returns tt(false) if tt(type) doesn't match the current file system entry referred, but the type itself isn't modified; itb(uintmax_t size() const) returns the size in bytes of the current file system entry; itb(FileStatus status(bool destination = true) const) returns the tt(filesystem::status) of the current file system entry. If the current object is a symlink and the symlink's status is requested then call tt(status(false)); itb(FileSystem stem() const) returns the file name of the current object without its extension; itb(std::string string() const) returns the current object's tt(Path) data member as a tt(std::string); itb(static FileSystem tmpDir(Type arg [= true])) this static member returns the file system's directory which is by default used for temporary files. By default tt(tmpDir) uses tt(FileSystem::s_errorCode) objct, when calling tt(tmpDir(false)) no tt(EC) object is used; itb(static FileSystem tmpDir(EC &ec)) this static member returns the file system's directory using the specified tt(EC) object when determining the temporay directory; itb(FileType type(bool destination = true) const) returns the tt(FileType) of the current file system entry. If the current object refers to a symlink call tt(type(false)) to receive the symlink's type. ) manpagesection(COPYING FILE SYSTEM ENTRIES) The member tt(copy(Type const &dest, FSOptions cpOptions = DEFAULT)'s) first argument specifies the name of the copied file or directory. It's second argument specifies the type of the copy-operation. Options can be combined using binary operators (usually tt(bit_or)). The following combinations are valid: itemization( itt(FILE) - unconditionally copies the current entry to tt(dest); itt(FILE | NEW) - the current entry is copied to tt(dest) if tt(dest) does not yet exist; itt(FILE | REPLACE) - the current entry is copied to tt(dest) if tt(dest) already exists; itt(FILE | UPDATE) - the current entry is only copied to tt(dest) if it is younger than tt(dest); itt(CP_SYMLINK) - the current entry must be a symlink, tt(dest) may not yet exist and becomes a symlink to the same destination as the current entry's destination; itt(NEW_LINK) - tt(dest) may not yet exist. It becomes a hard-link to the current entry. The current object must exist; itt(NEW_SYMLINK) - tt(dest) may not yet exist. It becomes a symlink to the current entry. If the current entry is itself a symlink then tt(dest) becomes a symlink to the current entry, and not to the entry the current object refers to. The current object does not have to be an existing file system entry; itt(RECURSIVE) - the current entry is recursively copied to tt(dest). If the current entry isn't a directory then the entry itself is copied as if tt(RECURSIVE) was not specified; itt(RECURSIVE | CP_SYMLINKS) - like using tt(RECURSIVE) but existing symlinks are copied as symlinks; itt(RECURSIVE | ONLY_DIRS) - like using tt(RECURSIVE) but only the directory structure is copied; itt(RECURSIVE | SKIP_SYMLINKS) - like using tt(RECURSIVE) but existing symlinks are not copied; ) manpagesection(EXAMPLE) verbinclude(../../filesystem/driver/main.cc) manpagefiles() em(bobcat/filesystem) - defines the class interface manpageseealso() bf(bobcat)(7), bf(chmod)(2), bf(datetime)(3bobcat), bf(ranger)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-6.07.01/documentation/man/iquotedprintablestream.yo0000664000175000017500000000561514673353433022713 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-6.07.01/documentation/man/clientsocket.yo0000664000175000017500000001127214673353433020607 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-6.07.01/documentation/man/tty.yo0000664000175000017500000000577614673353433016754 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-6.07.01/documentation/man/ptriter.yo0000664000175000017500000000655614673353433017622 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::PtrIter)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Iterator pointing to pointers) 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(USING DECLARATION) The tt(PtrIter) class template defines tt(PtrType): itemization( itb(using PtrType = decltype(&*Iterator())) ) 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-6.07.01/documentation/man/mbuf.yo0000664000175000017500000001644314673353433017056 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-6.07.01/documentation/man/iquotedprintablebuf.yo0000664000175000017500000001152214673353433022166 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-6.07.01/documentation/man/xpointer.yo0000664000175000017500000000462214673353433017771 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-6.07.01/documentation/man/ohexbuf.yo0000664000175000017500000001173714673353433017566 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-6.07.01/documentation/man/immapstream.yo0000664000175000017500000000567614673353433020452 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::ImmapStream)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (std::istream using FBB::MmapBuf as streambuf) manpagename(FBB::ImmapStream)(Input Stream using mmap(2) through FBB::MmapBuf) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() bf(FBB::ImmapStream) objects are used to extract information from files which are made available in the virtual address space of the calling process. Using the virtual address space is handled by the class's privately inherited bf(FBB::MmapBuf) (tt(std::streambuf) class. By mapping files in the process's virtual address space the time required for processing such files is usually dramatically reduced. An tt(std::exception) is thrown, and an error message is written to tt(cerr) if the bf(FBB::MmapBuf) base class cannot determine the size of the specified file, or when the (un)mapping cannot be performed. includefile(include/namespace) manpagesection(INHERITS FROM) bf(std::istream), privately from bf(FBB::MmapBuf). manpagesection(CONSTRUCTORS) itb(ImmapStream()) The default constructor merely constructs an empty bf(ImmapStream) object. To change it to a usable object use move assignment; itb(IOmmapStream(std::string const &fname, char const *bufSize = 0)) The constructor initializes the tt(ImmapStream) object for a file named tt(fname). By default bfImmapStream) uses a mapping buffer size of 10 times the standard page size, (cf. bf(sysconf)(3), and the member tt(pageSize) below). The size of the mapping buffer can also be specified using the tt(bufSize) parameter. To specify it use a value followed by tt(K, M,) or tt(G), representing, resp. 1024, 1024 * 1024, and 1024 * 1024 * 1024 bytes. The final buffer size is at least equal to the standard page size. When a larger value is specified the used buffer size is set to tt(specified / pageSize * pageSize). ) The move constructor and move assignment operator are available.nl() The copy constructor and copy assignment operator are not available. manpagesection(MEMBER FUNCTIONS) All members of bf(std::istream) are available, as bf(FBB::ImmapStream) inherits from that class. itemization( itb(size_t bufSize() const) returns the used t(mmap) buffer size; itb(size_t fileSize() const) returns the size of the specified file. itb(size_t pageSize() const) returns the smallest page size used by t(mmap). ) manpagesection(EXAMPLE) An example is provided in bobcat's source archive and gitlab repository at tt(bobcat/immapstream/demo). manpagefiles() em(bobcat/immapstream) - defines the class interface manpageseealso() bf(bobcat)(7), bf(iommapstream)(3bobcat), bf(ommapstream)(3bobcat), bf(mmap)(2), bf(mmapbuf)(3bobcat) bf(sysconf)(3) manpagebugs() None Reported. includefile(include/trailer) bobcat-6.07.01/documentation/man/user.yo0000664000175000017500000000575614673353433017110 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-6.07.01/documentation/man/ofoldstream.yo0000664000175000017500000001511014673353433020432 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-6.07.01/documentation/man/isymcryptstreambuf.yo0000664000175000017500000001275214673353433022100 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::ISymCryptStreambuf)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (Symmetric en- and decryption) manpagename(FBB::ISymCryptStreambuf) (Streambuf performing symmetric en/decryption) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat -lcrypto) manpagedescription() bf(FBB::ISymCryptStreambuf) objects can be used as tt(std::streambuf) objects of tt(std::istream) objected, and encrypt or decrypt information that is made available via separate tt(std::istream) streams. The class tt(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. All symmetric encryption methods defined by the OpenSSL library that can be selected by name may be used to en/decrypt information. To select a particular encryption method an identifier is passed to the constructor. E.g., tt("aes-256-gcm"). For an overview of the currently supported cipher algorithms issue the command verb( openssl list -cipher-algorithms ) tt(ISymCryptStreambuf) objects read the information to en/decrypt from tt(std::istream) objects, which are at construction-time specified as tt(istream) references or by filename. The characters that are thereupon extracted or read from tt(ISymCryptStream) objects are en/decrypted, and could, e.g., be written to some output stream. includefile(include/namespace) manpagesection(INHERITS FROM) bf(FBB::ISymCryptBase) (public) The class tt(FBB::ISymCryptBase) is an `internal use only' class, derived from tt(std::streambuf), and therefore tt(ISymCryptStreambuf) is a tt(std::streambuf) class. manpagesection(CONSTRUCTORS) itemization( itb(ISymCryptStreambuf(std::istream &inStream, std::string const &cipherName, std::string const &key, std::string const &iv, size_t inBufSize = 100)) This constructor defines a tt(std::streambuf) object encrypting or decrypting the characters which are read from tt(inStream). - tt(ISymCryptStreambuf) objects perform encryption;nl() tt(ISymCryptStreambuf) objects perform decryption; - tt(ISymCryptStreambuf) objects receive the characters to encrypt or decrypt from tt(std::istream &in);nl() - The encryption method to use is specified by the tt(cipherName) parameter. E.g., tt("AES-256-GCM");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::ISymCryptStreambufbuf) internally used buffer will hold tt(inBufSize) characters. The default value is the smallest value that is used. When specifying a smaller tt(bufSize) value than the default value then the default value is used;nl() itb(ISymCryptStreambuf(std::string const &inStreamName, std::string const &cipherName, std::string const &key, std::string const &iv, size_t inBufSize = 100)) Same constructor as the previous one, but this constructor's first parameter specifies the name of the file containing the characters to encrypt or decrypt. ) If the construction fails an exception is thrown, mentioning the openssl function that failed to complete (see also tt(errorMsg) below). The move constructor is available, the copy constructor and assignment operators are not available, manpagesection(INHERITED MEMBERS) Since the class is publicly derived from bf(std::istreambuf), all tt(std::streambuf) members can can be used. manpagesection(MEMBER FUNCTIONS) itemization( itb(static std::string errorMsg()) If an openssl function fails an exception is thrown mentioning the name of the failing function. In those cases the function tt(errorMsg) can be called returning a tt(std::string) containing the openssl error code (returned by tt(ERR_get_error)) and its textual representation (returned by tt(ERR_error_string)). If the reported error code is zero, then in fact no error has occurred and the exception was spuriously reported; itb(static size_t keyLength(std::string const &cipherName)) returns the minimum key length required for cipher tt(cipherName); itb(static size_t ivLength(std::sting const &cipherName)) returns the minimum length of the initialization vector that is required for cipher tt(cipherName). ) The latter two functions throw exceptions if tt(cipherName) does not contain the name of a supported cipher algorithm. manpagesection(EXAMPLE) See the example in the bf(isymcryptstream)(3bobcat) man-page. Instead of defining an tt(ISymCryptStream) an tt(ISymCryptStreamBuf) can be defined, passing its address to a tt(std::istream) which can then be used as the tt(ISymCryptStream) used in the example. manpagefiles() em(bobcat/isymcryptstream) - defines the class interface manpageseealso() bf(bobcat)(7), bf(isymcryptstream)(3bobcat), bf(osymcryptstream)(3bobcat), bf(osymcryptstreambuf)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-6.07.01/documentation/man/sharedreadme.yo0000664000175000017500000001514314673353433020545 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() The following shared memory classes are available: itemization( 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(lock) 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/libbobcat6/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-6.07.01/documentation/man/hostent.yo0000664000175000017500000001065414673353433017607 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-6.07.01/documentation/man/diffiehellman.yo0000664000175000017500000002430314673353433020706 0ustar frankfrankincludefile(include/header) 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, providing a public key infrastructure (PKI). 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(pow(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(pow(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 ) bf(Document encryption using Diffie Hellman) As with PKI in general, the Diffie Hellman key exchange method itself is not normally used for encrypting documents. Instead, it is usually used to exchange the key that is used for symmetric encryption methods like 3DES and CBC. These symmetric encryption methods are available through, e.g., Bobcats' tt(EncryptBuf, DecryptBuf,) and tt(ISymCryptStream) classes. includefile(include/namespace) manpagesection(INHERITS FROM) - 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. The prime length must at least be 1024 or an tt(FBB::Exception) is thrown. 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(FBB::BigInt const &prime, size_t generator = 5, bool progress = false)) Alternatively, this constructor can be used by the initiator after separately having constructed the prime to use. The prime must at least be 1024 bits long. 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)) 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() In addition the private information is written to the file tt('basename'.sec) 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), bf(ecdh)(3bobcat), bf(isymcryptstream)(3bobcat), bf(osymcryptstream)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-6.07.01/documentation/man/glob.yo0000664000175000017500000001326314673353433017045 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-6.07.01/documentation/man/pattern.yo0000664000175000017500000002455714673353433017607 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-6.07.01/documentation/man/isymcryptstream.yo0000664000175000017500000001177414673353433021406 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 en/decryption) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat -lcrypto) manpagedescription() bf(FBB::ISymCryptStream) objects can be used to encrypt or decrypt information that is available on separate tt(std::istream) streams. The class tt(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 to en/decrypt information. To select a particular encryption method an identifier is passed to the constructor. E.g., tt("aes-256-gcm"). For an overview of the currently supported cipher algorithms issue the command verb( openssl list -cipher-algorithms ) tt(ISymCryptStream) objects read the information to en/decrypt from tt(std::istream) objects, which are at construction-time specified as tt(istream) references or by filename. The characters that are thereupon extracted or read from tt(ISymCryptStream) objects are en/decrypted, and could, e.g., be written to some output stream. includefile(include/namespace) manpagesection(INHERITS FROM) bf(FBB::ISymCryptStreambuf) (private), nl() bf(std::istream) manpagesection(CONSTRUCTORS) itemization( itb(ISymCryptStream(std::istream &inStream, std::string const &cipherName, std::string const &key, std::string const &iv, size_t inBufSize = 100)) This constructor defines a tt(std::istream) object encrypting or decrypting the characters which are read from tt(inStream). - tt(ISymCryptStream) objects perform encryption;nl() tt(ISymCryptStream) objects perform decryption; - tt(ISymCryptStream) objects receive the characters to encrypt or decrypt from tt(inStream);nl() - The encryption method to use is specified by the tt(cipherName) parameter. E.g., tt("AES-256-GCM");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 hold tt(inBufSize) characters. The default value is the smallest value that is used. When specifying a smaller tt(bufSize) value than the default value then the default value is used;nl() itb(ISymCryptStream(std::string const &inStreamName, std::string const &cipherName, std::string const &key, std::string const &iv, size_t inBufSize = 100)) Same constructor as the previous one, but this constructor's first parameter specifies the name of the file containing the characters to encrypt or decrypt. ) If the construction fails an exception is thrown, mentioning the openssl function that failed to complete (see also tt(errorMsg) below). The move constructor is available, the copy constructor and assignment operators are not available, manpagesection(INHERITED MEMBERS) Since the class is publicly derived from bf(std::istream), all tt(std::istream) members can be used. manpagesection(MEMBER FUNCTIONS) itemization( itb(static std::string errorMsg()) If an openssl function fails an exception is thrown mentioning the name of the failing function. In those cases the function tt(errorMsg) can be called returning a tt(std::string) containing the openssl error code (returned by tt(ERR_get_error)) and its textual representation (returned by tt(ERR_error_string)). If the reported error code is zero, then in fact no error has occurred and the exception was spuriously reported; itb(static size_t keyLength(std::string const &cipherName)) returns the minimum key length required for cipher tt(cipherName); itb(static size_t ivLength(std::sting const &cipherName)) returns the minimum length of the initialization vector that is required for cipher tt(cipherName). ) The latter two functions throw exceptions if tt(cipherName) does not contain the name of a supported cipher algorithm. manpagesection(EXAMPLE) verbinclude(../../isymcryptstream/driver/driver.cc) manpagefiles() em(bobcat/isymcryptstream) - defines the class interface manpageseealso() bf(bobcat)(7), bf(isymcryptstreambuf)(3bobcat), bf(osymcryptstream)(3bobcat), bf(osymcryptstreambuf)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-6.07.01/documentation/man/cerrextractor.yo0000664000175000017500000001064614673353433021013 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 tt(CerrExtractor) 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-6.07.01/documentation/man/tablesupport.yo0000664000175000017500000003242714673353433020651 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() bf(FBB::TableSupport) is used by tt(FBB::Table) and tt(FBB::TableBuf) objects, handling some of their functionality. Users may derive classes from tt(TableSupport), overriding its virtual members to determine the actual layout of tables. By default the virtual members of tt(TableSupport) 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), offering facilities to separate rows by (partial) horizontal lines (cf. bf(tablelines)(3bobcat) for details). More specialized handling can be realized by deriving new classes from bf(FBB::TableSupport), overriding members so that they implement the programmer's 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 `HLine') 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 tt(TableSupport) object to specify 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 itemization( it() in row 1, it() from column 2 up to (not including) column 5, it() extending the separator to the left by half of 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, in any order, into tt(TableSupport) objecta. When column ranges overlap then their tt(ColumType)s are merged. ) manpagesection(PROTECTED TYPES) itemization( itb(const_iterator) The tt(const_iterator) is defined in the class's protected section. It is an input-iterator returning iterators to tt(struct Field) (see below) objects for table columns and column separators (see below at the tt(begin) and tt(end) members) itb(struct Field) A tt(Field) has two data members: tt(width) and tt(type), representing, respectively, the width and tt(ColumnType) of a column or separating column. The tt(type) values of tt(Field) objects returned by tt(TableSupport) members only contain single values (like tt(SKIP) or tt(LEFT_MID)) (note that column types can be combined when inserted into tt(Table) objects using tt(HLine) objects). ) manpagesection(CONSTRUCTORS) The default, copy and move constructors as well as the copy and move assignment operators are available. manpagesection(OVERLOADED OPERATORS) The following overloaded operators define separators between columns. The first value inserted into a tt(TableSupport) object defines the separator before column 0, the next one defines the separator before column 1, etc, until inserting separator tt(nColumns + 1), defining the separator to the right of the table's last column. Inserting additional separators are ignored. itemization( itb(TableSupport &operator<<(TableSupport &support, size_t width)) This operator defines a column-separator of tt(width) space characters. tt(Width) may be zero, in which case no visible separator is used; itb(TableSupport &operator<<(TableSupport &support, std::string const &text)) This operator defines a separator through text. The length of the tt(text) defines the width of the separator. No separator is used when tt(text) is empty; itb(TableSupport &operator<<(TableSupport &support, HLine const &hsep)) This operator defines how a horizontal separator of a specified row should be displayed (see the above description of tt(HLine)). ) 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 the virtual member tt(v_hline), passing it tt(row). By default tt(v_hline) performs no actions; 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 the virtual member tt(v_hline) without arguments, which by default calls tt(hline(nRows)); itb(void setParam(std::ostream &ostr, size_t nRows, size_t nColumns, std::vector const &align)) This member provides the tt(TableSupport) object with values that are essential for its proper functioning. It is called by the tt(Table) and tt(TableBuf)'s tt(def) member (and manipulator) to configure the tt(TableSupport) with alignment specifications, where+nl() tt(ostr) is a reference to the tt(std::ostream) to receive the table,nl() tt(nRows) specifies the table's number of rows,nl() tt(nColumns) specifies the table's number of columns,nl() tt(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 task is to write a column separator just before the data elements themselves. It calls the virtual member tt(v_vline) passing it its tt(col) parameter. By default tt(v_vline) inserts the column separator of column tt(col); 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 the virtual member tt(v_vline) without arguments, by default calling tt(vline(nColumns)) and inserting a newline into the tt(ostream); itb(size_t width() const) Returns the width of the table in number of characters. It may be called before actually inserting the table into a stream. ) manpagesection(PROTECTED MEMBER FUNCTIONS) The following members are available to classes derived from tt(TableSupport). Except for tt(sep) and tt(sepWidth) their values are only defined after calling tt(setParam) which 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 is returned containing information about the first column element when displaying the horizontal separator before line tt(row). Use argument tt(nRows()) to obtain the information about the separator beyond the last row. The `column elements' of the table consist of its separators and data columns.nl() Dereferencing the returned tt(const_iterator) returns a tt(Field) struct containing information about the width and type 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. Dereferencing the iterator is defined until the iterator has reached 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 table's number of columns is returned; itb(size_t nRows() const) The table's number of rows 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 defined for the table's columns is returned. Element tt(col) refers to the separator to the left of the table's column tt(col), element tt(nColumns()) refers to the separator to the right of the rightmost 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 before row tt(row). By default nothing is inserted. It may insert the horizontal separator 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 made available by dereferencing the iterators. Alternatively, to let tt(v_hline) insert a horizontal line spanning the full width of the table row the following implementation can be used: verb( void Derived::v_hline(size_t row) const { out() << setfill('-') << setw(width()) << "-" << setfill(' '); } ) itb(virtual void v_hline() const) This member is called from tt(hline()). Its task is to write a (partial) horizontal line beyond the table's last line. 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 available (if that separator is not available then no separator is inserted before column tt(col)); itb(virtual void v_vline() const) This member is called from tt(vline()) at the end of each of the table's rows. Its task is to write a column separator, and to terminate the table's line for which it is called. By default it inserts the final column separator (if defined) and a newline (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(csvtable)(3bobcat), bf(table)(3bobcat), bf(tablebuf)(3bobcat), bf(tablelines)(3bobcat) manpagebugs() None Reported. includefile(include/trailer) bobcat-6.07.01/documentation/man/randbuf.yo0000664000175000017500000000344114673353433017540 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(randommt)(3bobcat), bf(std::streambuf) manpagebugs() None Reported. includefile(include/trailer) bobcat-6.07.01/documentation/man/sharedmutex.yo0000664000175000017500000001055614673353433020455 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) verbinclude(../../sharedmutex/driver/driver.cc) 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-6.07.01/documentation/man/iommapstream.yo0000664000175000017500000000720214673353433020614 0ustar frankfrankincludefile(include/header) COMMENT(manpage, section, releasedate, archive, short name) manpage(FBB::IOmmapStream)(3bobcat)(_CurYrs_)(libbobcat-dev__CurVers_) (std::istream using FBB::MmapBuf as streambuf) manpagename(FBB::IOmmapStream)(Input Stream using mmap(2) through FBB::MmapBuf) manpagesynopsis() bf(#include )nl() Linking option: tt(-lbobcat) manpagedescription() bf(FBB::IOmmapStream) objects are used for reading or writing information to files which are made available in the virtual address space of the calling process. Using the virtual address space is handled by the class's privately inherited bf(FBB::MmapBuf) (tt(std::streambuf) class. By mapping files in the process's virtual address space the time required for processing such files is usually dramatically reduced. An tt(std::exception) is thrown, and an error message is written to tt(cerr) if the bf(FBB::MmapBuf) base class cannot determine the size of the specified file, or when the (un)mapping cannot be performed. includefile(include/namespace) manpagesection(INHERITS FROM) bf(std::iostream), privately from bf(FBB::MmapBuf). manpagesection(CONSTRUCTORS) itb(IOmmapStream()) The default constructor merely constructs an empty bf(IOmmapStream) object. To change it to a usable object use move assignment; itb(IOmmapStream(std::string const &fname, char const *bufSize = 0, std::ios::openmode openMode = std::ios::out | std::ios::in, mode_t mode = 0644)) The constructor initializes the tt(IOmmapStream) object for a file named tt(fname). The tt(openMode) parameter specifies how tt(fname) is used. The standard tt(ios::in, ios::out, ios::trunc, ios::app,) and tt(ios::ate) modes are supported. By default bfIOmmapStream) uses a mapping buffer size of 10 times the standard page size, (cf. bf(sysconf)(3), and the member tt(pageSize) below). The size of the mapping buffer can also be specified using the tt(bufSize) parameter. To specify it use a value followed by tt(K, M,) or tt(G), representing, resp. 1024, 1024 * 1024, and 1024 * 1024 * 1024 bytes. The final buffer size is at least equal to the standard page size. When a larger value is specified the used buffer size is set to tt(specified / pageSize * pageSize). The tt(mode) parameter specifies the user/group/other access mode which is used when the file is created by tt(MmapBuf). Its default value specifies read/write access by the user, and read access by others. ) The move constructor and move assignment operator are available.nl() The copy constructor and copy assignment operator are not available. manpagesection(MEMBER FUNCTIONS) All members of bf(std::istream) are available, as bf(FBB::IOmmapStream) inherits from that class. itemization( itb(size_t bufSize() const) returns the used t(mmap) buffer size; itb(size_t fileSize() const) returns the current size of the used file. The size is updated to a larger size when writing beyond the current file size. Once the bf(IOmmapStream) object ceases to exist the used file's size is modified to the current tt(fileSize) value. itb(size_t pageSize() const) returns the smallest page size used by t(mmap). ) manpagesection(EXAMPLE) An example is provided in bobcat's source archive and gitlab repository at tt(bobcat/iommapstream/demo). manpagefiles() em(bobcat/iommapstream) - defines the class interface manpageseealso() bf(bobcat)(7), bf(chmod)(2), bf(immapstream)(3bobcat), bf(mmap)(2), bf(mmapbuf)(3bobcat), bf(ommapstream)(3bobcat), bf(sysconf)(3) manpagebugs() None Reported. includefile(include/trailer) bobcat-6.07.01/documentation/man/inetaddress.yo0000664000175000017500000001142414673353433020424 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-6.07.01/documentation/man/fswap.yo0000664000175000017500000002074014673353433017240 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-6.07.01/documentation/images/0000775000175000017500000000000014673353433016236 5ustar frankfrankbobcat-6.07.01/documentation/images/molds/0000775000175000017500000000000014673353433017354 5ustar frankfrankbobcat-6.07.01/documentation/images/molds/README0000664000175000017500000000044014673353433020232 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/bobcat6/images by 'build install man' bobcat-6.07.01/documentation/images/molds/sharedsegment2.odp0000664000175000017500000004135414673353433023002 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-6.07.01/documentation/images/molds/sharedsegment1.odp0000664000175000017500000004151014673353433022773 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-6.07.01/documentation/images/molds/figure.odp0000664000175000017500000002602214673353433021343 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-6.07.01/documentation/images/sharedsegment1.jpg0000664000175000017500000011232414673353433021655 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-6.07.01/documentation/overrides0000664000175000017500000000054014673353433016715 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-6.07.01/documentation/esr.html0000664000175000017500000036331614673353433016464 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-6.07.01/ecdh/0000775000175000017500000000000014736742656013034 5ustar frankfrankbobcat-6.07.01/ecdh/privatekey.cc0000664000175000017500000000133214673353433015514 0ustar frankfrank//#define XERR #include "ecdh.ih" // static BigInt ECDH::privateKey(string const &initSecFname, string password) { auto in = Exception::factory(initSecFname); string privKey; string type; getline(in, type); // hex or encrypted? if (type == "encrypted") { checkPassword(password); ostringstream out; OSymCryptStream{ out, s_cipherName, password, s_digits } << in.rdbuf() << eoi; privKey = out.str(); } else if (type == "hex") getline(in, privKey); else throw Exception{} << initSecFname << ": corrupted"; return BigInt::fromText(privKey, ios::hex); } bobcat-6.07.01/ecdh/pkeyfromctx.cc0000664000175000017500000000051114673353433015702 0ustar frankfrank #include "ecdh.ih" // static ECDH::ptrEVP_PKEY ECDH::pkeyFromCtx(ptrEVP_PKEY_CTX &ctx, ptrOSSL_PARAM ¶ms, size_t type) { EVP_PKEY *tmp = 0; if (EVP_PKEY_fromdata(ctx.get(), &tmp, type, params.get()) != 1) throw "EVP_PKEY_fromdata"; return { tmp, EVP_PKEY_free }; } bobcat-6.07.01/ecdh/cptevppkeyctx.cc0000664000175000017500000000037114673353433016244 0ustar frankfrank #include "ecdh.ih" // static ECDH::ptrEVP_PKEY_CTX ECDH::cptEvpPkeyCtx() { ptrEVP_PKEY_CTX ret{pkeyCtxFromName(), EVP_PKEY_CTX_free }; if (EVP_PKEY_fromdata_init(ret.get()) != 1) throw "EVP_PKEY_fromdata_init"; return ret; } bobcat-6.07.01/ecdh/cptpubkey.cc0000664000175000017500000000157114673353433015344 0ustar frankfrank #include "ecdh.ih" void ECDH::cptPubKey() try { //ERR_clear_error(); size_t keyLength = 0; if (EVP_PKEY_get_octet_string_param( d_keyPair.get(), "pub", 0, 0, &keyLength) == 0 ) throw "EVP_PKEY_get_octet_string_param"; // Get the key. unique_ptr publicKey{ new uint8_t[keyLength] }; if (EVP_PKEY_get_octet_string_param( d_keyPair.get(), "pub", publicKey.get(), keyLength, &keyLength) == 0 ) throw "EVP_PKEY_get_octet_string_param"; d_pubKey = // public key in hex format toHex({ reinterpret_cast(publicKey.get()), keyLength }); } catch (char const *what) { throw Exception{} << "publicKey: " << what << " failed " << lastErrorString(); } bobcat-6.07.01/ecdh/keygencontext.cc0000664000175000017500000000143014673353433016217 0ustar frankfrank #include "ecdh.ih" // static ECDH::ptrEVP_PKEY_CTX ECDH::keyGenContext() const { ptrEVP_PKEY_CTX ret{ EVP_PKEY_CTX_new_from_name(0, "EC", 0), EVP_PKEY_CTX_free }; if (ret == 0) throw "EVP_PKEY_CTX_new_from_name"; // Initialize the key generation context. if (EVP_PKEY_keygen_init(ret.get()) <= 0) throw "EVP_PKEY_keygen_init"; auto pBuild = cptParamBuild(); // Set the params including the curve name // cptParams() converts OSSL_PARAM_BLD to // OSSL_PARAM. if (not EVP_PKEY_CTX_set_params(ret.get(), cptParams(pBuild).get())) throw "EVP_PKEY_CTX_set_params"; return ret; } bobcat-6.07.01/ecdh/data.cc0000664000175000017500000000023214673353433014240 0ustar frankfrank #include "ecdh.ih" string const ECDH::s_digits{ "0123456789ABCDEF" }; string const ECDH::s_cipherName{ "AES-256-GCM" }; ECDH::CurveMap ECDH::s_curves; bobcat-6.07.01/ecdh/showcurves.cc0000664000175000017500000000071714736466050015547 0ustar frankfrank #include "ecdh.ih" // static ostream &ECDH::showCurves(ostream &out) { TableLines tablelines; tablelines << 0 << " "; Table tab(tablelines, 3, Table::ROWWISE); tab << Align{ 2, std::left} << "curve name" << ' ' << "comment" << Align{ 0, 2, center }; tablelines << TableLines::HLine(1, 0, 3); for (auto const &curve : supportedCurves()) curveInfo(tab, curve.second); out << tab; return out; } bobcat-6.07.01/ecdh/lasterror.cc0000664000175000017500000000047614673353433015356 0ustar frankfrank #include "ecdh.ih" // static std::tuple ECDH::lastError() { unsigned long error = ERR_peek_last_error(); if (error == 0) return { 0, "" }; char errorString[256]; ERR_error_string_n(error, errorString, sizeof(errorString)); return { error, errorString }; } bobcat-6.07.01/ecdh/pkeyinit.cc0000664000175000017500000000033314673353433015165 0ustar frankfrank #include "ecdh.ih" void ECDH::pkeyInit(EVP_PKEY_CTX *ctx) { // Initialize the key generation context. if (EVP_PKEY_keygen_init(ctx) != 1) throw "EVP_PKEY_keygen_init"; } bobcat-6.07.01/ecdh/ecdh4.cc0000664000175000017500000000034014673353433014316 0ustar frankfrank #include "ecdh.ih" ECDH::ECDH(string const &curveName, string const &peerPubFname, string const &initSecFname, string const &password) : ECDH() { set(curveName, peerPubFname, initSecFname, password); } bobcat-6.07.01/ecdh/otherpubkey.cc0000664000175000017500000000162514673353433015677 0ustar frankfrank #include "ecdh.ih" ECDH::ptrEVP_PKEY ECDH::otherPubKey() const try { string peerKey = toData(d_otherPubKey); // cpt an OSSL_PARAM_BLD for the used curve auto paramBuild = cptParamBuild(); // set the peer public key in setPeerPubKey(paramBuild, peerKey); // paramBuild auto params = cptParams(paramBuild); // paramBuild to OSSL_PARAM auto ctx = cptEvpPkeyCtx(); // cpt an EVP_PKEY context. // cpt the peer public key's // EVP_PKEY ptr return pkeyFromCtx(ctx, params, EVP_PKEY_PUBLIC_KEY); } catch (char const *what) { throw Exception{} << "otherPubKey: " << what << " failed: " << lastErrorString(); } bobcat-6.07.01/ecdh/set1.cc0000664000175000017500000000047614673353433014215 0ustar frankfrank #include "ecdh.ih" void ECDH::set([[maybe_unused]] TheInitiator init, string const &curveName, string const &initPubFname) { d_curveName = curveName; cptKeys(); auto out = Exception::factory(initPubFname); out << d_pubKey << '\n' << d_curveName << '\n'; } bobcat-6.07.01/ecdh/cptderivationctx.cc0000664000175000017500000000063214673353433016725 0ustar frankfrank #include "ecdh.ih" ECDH::ptrEVP_PKEY_CTX ECDH::cptDerivationCtx() const { ptrEVP_PKEY_CTX ctx{ EVP_PKEY_CTX_new(d_keyPair.get(), 0), EVP_PKEY_CTX_free }; if (!ctx) throw "EVP_PKEY_CTX_new"; // initialize the derivation context. if (EVP_PKEY_derive_init(ctx.get()) <= 0) throw "EVP_PKEY_derive_init"; return ctx; } bobcat-6.07.01/ecdh/ecdh.f0000664000175000017500000000075714673353433014106 0ustar frankfrankinline std::string const &ECDH::curve() const { return d_curveName; } inline std::string ECDH::privKey() const { return "hex\n" + d_privKey; } inline std::string const &ECDH::pubKey() const { return d_pubKey; } inline std::string const &ECDH::sharedKey() const { return d_sharedKey; } inline std::ostream &operator<<(std::ostream &out, [[maybe_unused]] ECDH const &ecdh) { return ECDH::showCurves(out); } bobcat-6.07.01/ecdh/ecdh3.cc0000664000175000017500000000030314673353433014314 0ustar frankfrank #include "ecdh.ih" ECDH::ECDH(ThePeer peer, string const &initPubFname, string const &peerPubFname) : ECDH() { set(peer, initPubFname, peerPubFname); } bobcat-6.07.01/ecdh/set3.cc0000664000175000017500000000100114673353433014200 0ustar frankfrank #include "ecdh.ih" void ECDH::set(string const &curveName, string const &peerPubFname, string const &initSecFname, string const &password) { { auto in = Exception::factory(peerPubFname); in >> d_otherPubKey; } d_curveName = curveName; auto paramBuild = cptParamBuild(); auto param = setPrivKey(paramBuild, initSecFname, password); auto ctx = cptEvpPkeyCtx(); d_keyPair = pkeyFromCtx(ctx, param, EVP_PKEY_KEYPAIR); cptSharedKey(); } bobcat-6.07.01/ecdh/curveinfo.cc0000664000175000017500000000037514673353433015337 0ustar frankfrank #include "ecdh.ih" // static void ECDH::curveInfo(Table &tab, CurveInfo const &info) { if (info.comment.find("Not suitable for ECDSA") == string::npos) tab << info.name << ' ' << (info.comment.empty() ? " " : info.comment); } bobcat-6.07.01/ecdh/ecdh0000664000175000017500000001420214673353433013650 0ustar frankfrank#ifndef INCLUDED_BOBCAT_ECDH_ #define INCLUDED_BOBCAT_ECDH_ #include #include #include #include #include #include namespace FBB { class BigInt; class Table; class ECDH { friend std::ostream &operator<<(std::ostream &out, ECDH const &ecdh); enum { MIN_PWD_LENGTH = 5 }; using ptrEVP_PKEY = std::unique_ptr; using ptrEVP_PKEY_CTX = std::unique_ptr; using ptrOSSL_PARAM = std::unique_ptr; using ptrOSSL_PARAM_BLD = std::unique_ptr; struct CurveInfo { int internalID = 0; // EC_builtin_curve.nid is an int std::string name; std::string comment; }; using CurveMap = std::map; std::string d_curveName; ptrEVP_PKEY d_keyPair{ 0, EVP_PKEY_free }; std::string d_pubKey; // hex representation std::string d_privKey; // hex representation std::string d_otherPubKey; // hex representation std::string d_sharedKey; // hex representation static CurveMap s_curves; static std::string const s_digits; static std::string const s_cipherName; public: enum TheInitiator { Initiator }; enum ThePeer { Peer }; ECDH(); // 1 ECDH(ECDH &&tmp) = default; ECDH(TheInitiator init, std::string const &curveName, // 2 std::string const &initPubFname); ECDH(ThePeer peer, std::string const &initPubFname, // 3 std::string const &peerPubFname); // called by the initiator after receiving the peer's // public key ECDH(std::string const &curveName, // 4 std::string const &peerPubFname, std::string const &initSecFname, std::string const &password = ""); ECDH &operator=(ECDH &&tmp) = default; std::string const &curve() const; // the used EC // private key: // hex-formatted, // prefixed by std::string privKey() const; // 'hex\n' .f // encrypted, void privKey(std::string const &privKeyFname, // prefixed by std::string passwd) const; // 'encrypted\n' std::string const &pubKey() const; // hex-formatted // .f void set(TheInitiator init, std::string const &curveName, // 1 std::string const &initPubFname); void set(ThePeer peer, std::string const &initPubFname, // 2 std::string const &peerPubFname); // may be called by the initiator after receiving the peer's // public key void set(std::string const &curveName, // 3 std::string const &peerPubFname, std::string const &initSecFname, std::string const &password = ""); std::string const &sharedKey() const; // hex-formatted // .f // idem, but called by the // initiator using // ECDH(TheInitiator) std::string const &sharedKey(std::string const &peerPubFname); // 2 private: static size_t checkHex(char hexDigit); static void checkPassword(std::string &passwd); ptrEVP_PKEY_CTX cptDerivationCtx() const; static ptrEVP_PKEY_CTX cptEvpPkeyCtx(); void cptKeys(); ptrOSSL_PARAM_BLD cptParamBuild() const; static ptrOSSL_PARAM cptParams(ptrOSSL_PARAM_BLD const &pBuild); void cptPrivKey(); // assigns d_privKey void cptSharedKey(); // assigns d_sharedKey void cptPubKey(); // assigns d_pubKey static void curveInfo(Table &table, CurveInfo const &info); ptrEVP_PKEY_CTX keyGenContext() const; static std::tuple lastError(); static std::string lastErrorString(); ptrEVP_PKEY otherPkey() const; ptrEVP_PKEY otherPubKey() const; static ptrEVP_PKEY pkeyFromCtx(ptrEVP_PKEY_CTX &ctx, ptrOSSL_PARAM ¶ms, size_t type); static EVP_PKEY_CTX *pkeyCtxFromName(); static void pkeyInit(EVP_PKEY_CTX *ctx); static EVP_PKEY *pkeyGenerate(EVP_PKEY_CTX *ctx); static BigInt privateKey(std::string const &initSecFname, std::string password); static void setPeerPubKey( ptrOSSL_PARAM_BLD const ¶mBuild, std::string const &otherPubKey); static ptrOSSL_PARAM setPrivKey(ptrOSSL_PARAM_BLD ¶mBuild, std::string const &initSecFname, std::string password); static std::ostream &showCurves(std::ostream &out); static CurveMap const &supportedCurves(); static std::string toData(std::string const &hexStr); static std::string toHex(std::string const &data); }; #include "ecdh.f" } // FBB #endif bobcat-6.07.01/ecdh/set2.cc0000664000175000017500000000056314673353433014213 0ustar frankfrank #include "ecdh.ih" void ECDH::set([[maybe_unused]] ThePeer peer, string const &initPubFname, string const &peerPubFname) { auto in = Exception::factory(initPubFname); in >> d_otherPubKey >> d_curveName; cptKeys(); auto out = Exception::factory(peerPubFname); out << d_pubKey << '\n'; cptSharedKey(); } bobcat-6.07.01/ecdh/ecdh.ih0000664000175000017500000000044214736315237014250 0ustar frankfrank#include "ecdh" #include #include #include #include #include #include #include #include #include using namespace std; using namespace FBB; bobcat-6.07.01/ecdh/setpeerpubkey.cc0000664000175000017500000000055414673353433016225 0ustar frankfrank #include "ecdh.ih" // static void ECDH::setPeerPubKey(ptrOSSL_PARAM_BLD const ¶mBuild, string const &otherPubKey) { if ( OSSL_PARAM_BLD_push_octet_string( paramBuild.get(), "pub", &otherPubKey.front(), otherPubKey.length() ) != 1 ) throw "OSSL_PARAM_BLD_push_octet_string"; } bobcat-6.07.01/ecdh/lasterrorstring.cc0000664000175000017500000000015014673353433016572 0ustar frankfrank #include "ecdh.ih" // static string ECDH::lastErrorString() { return std::get<1>(lastError()); } bobcat-6.07.01/ecdh/setprivkey.cc0000664000175000017500000000065614673353433015546 0ustar frankfrank #include "ecdh.ih" // static ECDH::ptrOSSL_PARAM ECDH::setPrivKey(ptrOSSL_PARAM_BLD ¶mBuild, string const &initSecFname, string password) { BigInt priv = privateKey(initSecFname, password); if (OSSL_PARAM_BLD_push_BN(paramBuild.get(), "priv", &priv.bignum()) != 1) throw "OSSL_PARAM_BLD_push_BN"; return cptParams(paramBuild); } bobcat-6.07.01/ecdh/ecdh2.cc0000664000175000017500000000030114673353433014311 0ustar frankfrank #include "ecdh.ih" ECDH::ECDH(TheInitiator init, string const &curveName, string const &initPubFname) : ECDH() { set(init, curveName, initPubFname); } bobcat-6.07.01/ecdh/pkeyctxfromname.cc0000664000175000017500000000032114673353433016542 0ustar frankfrank #include "ecdh.ih" // static EVP_PKEY_CTX *ECDH::pkeyCtxFromName() { auto ret = EVP_PKEY_CTX_new_from_name(0, "EC", 0); if (ret == 0) throw "EVP_PKEY_CTX_new_from_name"; return ret; } bobcat-6.07.01/ecdh/checkhex.cc0000664000175000017500000000045314673353433015116 0ustar frankfrank #include "ecdh.ih" // static size_t ECDH::checkHex(char hexDigit) { size_t idx = s_digits.find(hexDigit); if (idx == string::npos) throw Exception{} << "checkHex: invalid hex digit `" << hexDigit << '\''; return idx; } bobcat-6.07.01/ecdh/cptprivkey.cc0000664000175000017500000000106414673353433015533 0ustar frankfrank #include "ecdh.ih" // computes secret key as hex-string void ECDH::cptPrivKey() try { // ERR_clear_error(); BIGNUM *privKey = 0; if (EVP_PKEY_get_bn_param(d_keyPair.get(), "priv", &privKey) == 0) throw " EVP_PKEY_get_bn_param"; BigInt key{ privKey }; BN_free(privKey); d_privKey = (ostringstream{} << hex << key).str(); if (d_privKey.empty()) throw "ostringstream{} << hex << key)"; } catch (char const *what) { throw Exception{} << "privKey: " << what << " failed " << lastErrorString(); } bobcat-6.07.01/ecdh/checkpasswd.cc0000664000175000017500000000055314673353433015634 0ustar frankfrank//#define XERR #include "ecdh.ih" // static void ECDH::checkPassword(string &passwd) { if (passwd.size() < MIN_PWD_LENGTH) throw Exception{} << "private key passwordd length must be >= " << MIN_PWD_LENGTH << " chars"; while (passwd.size() < 32) // AES-256-GCM requires pwd len >= 32 passwd += passwd; } bobcat-6.07.01/ecdh/icmconf0000664000175000017500000000007714673353433014370 0ustar frankfrank#define LIBRARY "ecdh" #include "../icmconf.lib" bobcat-6.07.01/ecdh/cptparambuild.cc0000664000175000017500000000117214673353433016162 0ustar frankfrank #include "ecdh.ih" ECDH::ptrOSSL_PARAM_BLD ECDH::cptParamBuild() const { // cpt an OSSL_PARAM_BLD. ptrOSSL_PARAM_BLD paramBuild{ OSSL_PARAM_BLD_new(), OSSL_PARAM_BLD_free }; if (paramBuild == 0) throw "OSSL_PARAM_BLD_new"; // store the curve name in paramBuild if (OSSL_PARAM_BLD_push_utf8_string( paramBuild.get(), "group", // OSSL_PKEY_PARAM_GROUP_NAME &d_curveName.front(), 0) == 0 ) throw "OSSL_PARAM_BLD_push_utf8_string"; return paramBuild; } bobcat-6.07.01/ecdh/todata.cc0000664000175000017500000000061414673353433014607 0ustar frankfrank #include "ecdh.ih" //static string ECDH::toData(string const &hexString) { if (hexString.length() & 1) throw Exception{} << "toData: invalid odd-sized hexString"; string ret; for (auto iter = hexString.begin(), end = hexString.end(); iter != end; ) { size_t hi = checkHex(*iter++); ret.push_back(hi << 4 | checkHex(*iter++)); } return ret; } bobcat-6.07.01/ecdh/sharedkey2.cc0000664000175000017500000000033514673353433015374 0ustar frankfrank#include "ecdh.ih" std::string const &ECDH::sharedKey(std::string const &peerPubFname) { auto in = Exception::factory(peerPubFname); in >> d_otherPubKey; cptSharedKey(); return d_sharedKey; } bobcat-6.07.01/ecdh/otherpkey.cc0000664000175000017500000000147414673353433015352 0ustar frankfrank #include "ecdh.ih" // convert the other pub. key to EVP_PKEY ECDH::ptrEVP_PKEY ECDH::otherPkey() const try { string peerKey = toData(d_otherPubKey); // cpt an OSSL_PARAM_BLD for the used curve auto paramBuild = cptParamBuild(); // set the peer public key in setPeerPubKey(paramBuild, peerKey); // paramBuild auto params = cptParams(paramBuild); // paramBuild to OSSL_PARAM auto ctx = cptEvpPkeyCtx(); // cpt an EVP_PKEY context. return pkeyFromCtx(ctx, params, EVP_PKEY_PUBLIC_KEY); } catch (char const *what) { throw Exception{} << "otherPubKey: " << what << " failed: " << lastErrorString(); } bobcat-6.07.01/ecdh/ecdh1.cc0000664000175000017500000000007614673353433014321 0ustar frankfrank #include "ecdh.ih" ECDH::ECDH() { supportedCurves(); } bobcat-6.07.01/ecdh/cptsharedkey.cc0000664000175000017500000000215714673353433016025 0ustar frankfrank #include "ecdh.ih" void ECDH::cptSharedKey() try { ERR_clear_error(); // the peer public key auto peerKey = otherPubKey(); auto ctx = cptDerivationCtx(); // the derivation context. // store the peer public key if (EVP_PKEY_derive_set_peer(ctx.get(), peerKey.get()) != 1) throw "EVP_PKEY_derive_set_peer"; size_t length = 0; // determine the shared secret's length if (EVP_PKEY_derive(ctx.get(), 0, &length) != 1 or length == 0) throw "EVP_PKEY_derive"; std::string sharedSecret(length, 0); // prepare the shared secret if ( // cpt the shared secret. EVP_PKEY_derive( ctx.get(), reinterpret_cast(&sharedSecret.front()), &length) != 1 ) throw "EVP_PKEY_derive"; d_sharedKey = toHex(sharedSecret); // return the hex shared secret } catch (char const *what) { throw Exception{} << "sharedSecret: " << what << " failed " << lastErrorString(); } bobcat-6.07.01/ecdh/cptkeys.cc0000664000175000017500000000122614673353433015015 0ustar frankfrank #include "ecdh.ih" void ECDH::cptKeys() try { ERR_clear_error(); // cpt the EC key generation context and set auto ctx = keyGenContext(); // the parameters containing the curve name EVP_PKEY *keyPair = 0; // cpt a key pair. if (EVP_PKEY_generate(ctx.get(), &keyPair) != 1) throw "EVP_PKEY_generate"; d_keyPair.reset(keyPair); cptPubKey(); // cpt the public hex-key cptPrivKey(); // cpt the private hex-key } catch (char const *what) { throw Exception{} << "generateKeys: " << what << " failed " << lastErrorString(); } bobcat-6.07.01/ecdh/cptparams.cc0000664000175000017500000000043614673353433015327 0ustar frankfrank #include "ecdh.ih" // static ECDH::ptrOSSL_PARAM ECDH::cptParams(ptrOSSL_PARAM_BLD const &pBuild) { auto ret = ptrOSSL_PARAM{ OSSL_PARAM_BLD_to_param(pBuild.get()), OSSL_PARAM_free }; if (ret == 0) throw "OSSL_PARAM_BLD_to_param"; return ret; } bobcat-6.07.01/ecdh/tohex.cc0000664000175000017500000000042614673353433014463 0ustar frankfrank #include "ecdh.ih" string ECDH::toHex(string const &data) { string ret; for (unsigned char ch: data) { ret.push_back(s_digits[ch >> 4]); // high nibble ret.push_back(s_digits[ch & 0xf]); // low nibble } return ret; } bobcat-6.07.01/ecdh/pkeygenerate.cc0000664000175000017500000000034414673353433016016 0ustar frankfrank #include "ecdh.ih" EVP_PKEY *ECDH::pkeyGenerate(EVP_PKEY_CTX *ctx) { EVP_PKEY *keyPair = 0; // cpt a key pair. if (EVP_PKEY_generate(ctx, &keyPair) != 1) throw "EVP_PKEY_generate"; return keyPair; } bobcat-6.07.01/ecdh/supportedcurves.cc0000664000175000017500000000204014673353433016603 0ustar frankfrank #include "ecdh.ih" // static ECDH::CurveMap const &ECDH::supportedCurves() try { if (s_curves.size() > 0) return s_curves; ERR_clear_error(); size_t count = EC_get_builtin_curves(0, 0); if (count == 0) throw "EC_get_builtin_curves"; auto buffer = make_unique(count); if (EC_get_builtin_curves(buffer.get(), count) != count) throw "EC_get_builtin_curves"; for (size_t idx = 0; idx != count; ++idx) { if (char const *curveName = OBJ_nid2sn(buffer[idx].nid); curveName) { if (string name{ curveName }; name.length() > 0) { char const *comment = buffer[idx].comment; s_curves[name] = CurveInfo{ buffer[idx].nid, name, comment ? comment : "" }; } } } return s_curves; } catch (char const *what) { s_curves = CurveMap{}; throw Exception{} << "supportedCurves: " << what << " failed " << lastErrorString(); } bobcat-6.07.01/ecdh/driver/0000775000175000017500000000000014673353433014316 5ustar frankfrankbobcat-6.07.01/ecdh/driver/build0000775000175000017500000000011614673353433015341 0ustar frankfrank#!/bin/bash g++ -c *.cc g++ -o driver *.o -L../tmp -lecdh -lbobcat -lcrypto bobcat-6.07.01/ecdh/driver/usage.cc0000664000175000017500000000204714673353433015734 0ustar frankfrank// usage.cc #include "main.ih" namespace { char const info[] = R"_( [options] arg Where: [options] - optional arguments (short options between parentheses): --help (-h) - provide this help --version (-v) - show version information and terminate arg: curves: show the available elliptic curves on cout init: compute the initiator's public/secret keys writing them to init.pub and init.sec peer: compute the peer's public/secret keys writing them to peer.pub and peer.sec, compute the peer's shared key (peer.shared) priv: compute the initiator's shared key (init.shared) after making peer.pub available in a separate process, using a single initiator process. shared: compute the initiator's shared key (init.shared) using a separate initiator process )_"; } void usage(std::string const &progname) { cout << "\n" "Usage: " << progname << info; } bobcat-6.07.01/ecdh/driver/main.cc0000664000175000017500000000534214673353433015555 0ustar frankfrank#include "main.ih" int main(int argc, char **argv) try { if (argc == 1) { usage(path{ argv[0] }.filename().string()); return 0; } if ("curves"s == argv[1]) // show supported ECDH curves. cout << ECDH{}; else if ("init"s == argv[1]) // initiator key construction { // write the file containing // the curve + public key ECDH ecdh{ ECDH::Initiator, "secp384r1", "init.pub" }; // save the initiator's // private key ecdh.privKey("init.sec", "use your passphrase"); // not using encryption: // auto initSec = Exception::factory("init.sec"); // initSec << ecdh.privKey() << '\n'; } else if ("priv"s == argv[1]) // initiator key construction { // write the file containing // the curve + public key ECDH ecdh{ ECDH::Initiator, "secp384r1", "init.pub" }; cout << "wait for the peer's public key. " "Press Enter to continue... "; cin.ignore(100, '\n'); // written to file auto initShared = Exception::factory("init.shared"); initShared << ecdh.sharedKey("peer.pub") << '\n'; } else if ("peer"s == argv[1]) // peer's key construction { // write the peer's public key ECDH ecdh{ ECDH::Peer, "init.pub", "peer.pub" }; // save the peer's private // key (although not needed) auto out = Exception::factory("peer.sec"); out << ecdh.privKey() << '\n'; out = Exception::factory("peer.shared"); out << ecdh.sharedKey() << '\n'; } else if ("shared"s == argv[1]) // the initiator's shared key { // construction ECDH ecdh{ "secp384r1", "peer.pub", "init.sec", "use your passphrase" }; auto initShared = Exception::factory("init.shared"); initShared << ecdh.sharedKey() << '\n'; // written to file } else { usage(path{ argv[0] }.filename().string()); return 1; } } catch (exception const &exc) { cerr << "Error: " << exc.what() << '\n'; return 1; } catch (...) // and handle an unexpected exception { cerr << "unexpected exception\n"; return 1; } bobcat-6.07.01/ecdh/driver/main.ih0000664000175000017500000000040314673353433015561 0ustar frankfrank#include #include #include #include #include #include #include "../ecdh" using namespace std; using namespace FBB; using namespace filesystem; void usage(string const &progname); bobcat-6.07.01/ecdh/privkey.cc0000664000175000017500000000142314673353433015023 0ustar frankfrank//#define XERR #include "ecdh.ih" void ECDH::privKey(string const &privKeyFname, string passwd) const { checkPassword(passwd); if (passwd.size() < MIN_PWD_LENGTH) throw Exception{} << "privKey: passwd length must be >= 5 chars"; while (passwd.size() < 32) // AES-256-GCM requires pwd len >= 32 passwd += passwd; // prepare the file to contain the // encrypted key auto out = Exception::factory(privKeyFname); out << "encrypted\n"; // using s_digits as IV OSymCryptStream{ out, s_cipherName, passwd, s_digits } << d_privKey; } bobcat-6.07.01/eoi/0000775000175000017500000000000014736742656012705 5ustar frankfrankbobcat-6.07.01/eoi/eoi2.cc0000664000175000017500000000036714673353433014047 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-6.07.01/eoi/eoi0000664000175000017500000000133714673353433013377 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-6.07.01/eoi/icmconf0000664000175000017500000000007114673353433014233 0ustar frankfrank#define LIBRARY "eoi" #include "../icmconf" bobcat-6.07.01/eoi/eoi1.cc0000664000175000017500000000004714673353433014041 0ustar frankfrank#include "eoi.ih" void Eoi::eoi_() {} bobcat-6.07.01/eoi/eoi.ih0000664000175000017500000000017514736315237013775 0ustar frankfrank#include "eoi" //#include //#define XERR std::cerr << __FILE__": " using namespace std; using namespace FBB; bobcat-6.07.01/eoi/driver/0000775000175000017500000000000014673353433014167 5ustar frankfrankbobcat-6.07.01/eoi/driver/demo.cc0000664000175000017500000000111314673353433015416 0ustar frankfrank#include #include #include // This demo is IUO: it illustrates that when overflow returns EOF the ostream // no longer processes incoming characters using namespace std; struct SB: public streambuf { size_t count = 0; SB() { setp(0, 0); } int overflow(int ch) { if (count == 10) return EOF; cerr.put(ch); ++count; return ch; } }; int main() { SB sb; ostream out{ &sb }; out << "this is a long text, more than 10 chars" << endl; cerr << "done\n"; } bobcat-6.07.01/eoibuf/0000775000175000017500000000000014736742656013402 5ustar frankfrankbobcat-6.07.01/eoibuf/eoibuf0000664000175000017500000000201014673353433014556 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-6.07.01/eoibuf/eoibuf.ih0000664000175000017500000000007714736315237015170 0ustar frankfrank#include "eoibuf" using namespace std; using namespace FBB; bobcat-6.07.01/eoibuf/ucharptr3.f0000664000175000017500000000017614673353433015457 0ustar frankfrank// static inline unsigned char *EoiBuf::ucharPtr(std::string &str) { return reinterpret_cast(&str[0]); } bobcat-6.07.01/eoibuf/setg.cc0000664000175000017500000000024714673353433014645 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-6.07.01/eoibuf/resize.f0000664000175000017500000000010714673353433015037 0ustar frankfrankinline void EoiBuf::resize(size_t size) { d_buffer.resize(size); } bobcat-6.07.01/eoibuf/ucharptr1.f0000664000175000017500000000015114673353433015446 0ustar frankfrankinline unsigned char *EoiBuf::ucharPtr() { return reinterpret_cast(&d_buffer[0]); } bobcat-6.07.01/eoibuf/buffer.f0000664000175000017500000000007614673353433015014 0ustar frankfrankinline std::string &EoiBuf::buffer() { return d_buffer; } bobcat-6.07.01/eoibuf/bufsize.f0000664000175000017500000000011014673353433015177 0ustar frankfrankinline size_t EoiBuf::bufSize() const { return d_buffer.length(); } bobcat-6.07.01/eoibuf/icmconf0000664000175000017500000000007414673353433014733 0ustar frankfrank#define LIBRARY "eoibuf" #include "../icmconf" bobcat-6.07.01/eoibuf/ucharptr4.f0000664000175000017500000000022014673353433015446 0ustar frankfrank// static inline unsigned char const *EoiBuf::ucharPtr(std::string const &str) { return reinterpret_cast(&str[0]); } bobcat-6.07.01/eoibuf/eoibuf2.f0000664000175000017500000000007614673353433015076 0ustar frankfrankinline EoiBuf::EoiBuf(size_t size) : d_buffer(size, 0) {} bobcat-6.07.01/eoibuf/setp.cc0000664000175000017500000000015114673353433014650 0ustar frankfrank#include "eoibuf.ih" void EoiBuf::setp() { streambuf::setp(&*d_buffer.begin(), &*d_buffer.end()); } bobcat-6.07.01/eoibuf/ucharptr2.f0000664000175000017500000000017314673353433015453 0ustar frankfrankinline unsigned char const *EoiBuf::ucharPtr() const { return reinterpret_cast(&d_buffer[0]); } bobcat-6.07.01/exception/0000775000175000017500000000000014736742656014127 5ustar frankfrankbobcat-6.07.01/exception/open3.f0000664000175000017500000000050514673353433015311 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-6.07.01/exception/data.cc0000664000175000017500000000006014673353433015332 0ustar frankfranknamespace FBB { thread_local int g_errno; } bobcat-6.07.01/exception/exception0000664000175000017500000000732714673353433016050 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-6.07.01/exception/errnodescr.cc0000664000175000017500000000070414673353433016574 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-6.07.01/exception/opinsert.f0000664000175000017500000000030614673353433016127 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-6.07.01/exception/open2.f0000664000175000017500000000045414673353433015313 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-6.07.01/exception/exception.f0000664000175000017500000000006314673353433016262 0ustar frankfrankinline Exception::Exception() { g_errno = 0; } bobcat-6.07.01/exception/factory3.f0000664000175000017500000000043014673353433016014 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-6.07.01/exception/factory1.f0000664000175000017500000000033414673353433016015 0ustar frankfranktemplate StreamType Exception::factory(std::string const &name) { StreamType stream{ name }; if (!stream) throw Exception{} << "Can't open `" << name << '\''; return stream; } bobcat-6.07.01/exception/exception.ih0000664000175000017500000000027514736315237016442 0ustar frankfrank#include "exception" #include #include #include #include #include #include using namespace std; using namespace FBB; bobcat-6.07.01/exception/open6.f0000664000175000017500000000072414673353433015317 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-6.07.01/exception/open1.f0000664000175000017500000000037514673353433015314 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-6.07.01/exception/protection.cc0000664000175000017500000000246314673353434016621 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-6.07.01/exception/icmconf0000664000175000017500000000007714673353433015463 0ustar frankfrank#define LIBRARY "exception" #include "../icmconf" bobcat-6.07.01/exception/what.cc0000664000175000017500000000015314673353434015370 0ustar frankfrank#include "exception.ih" char const *Exception::what() const noexcept(true) { return d_what.c_str(); } bobcat-6.07.01/exception/factory2.f0000664000175000017500000000036614673353433016023 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-6.07.01/exception/factory6.f0000664000175000017500000000066614673353433016032 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-6.07.01/exception/open4.f0000664000175000017500000000052014673353433015307 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-6.07.01/exception/open5.f0000664000175000017500000000064514673353433015320 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-6.07.01/exception/destructor.cc0000664000175000017500000000010314673353433016615 0ustar frankfrank#include "exception.ih" Exception::~Exception() noexcept(true) {} bobcat-6.07.01/exception/exception1.cc0000664000175000017500000000014414673353433016503 0ustar frankfrank#include "exception.ih" Exception::Exception(int errnoValue) { g_errno = errno = errnoValue; } bobcat-6.07.01/exception/factory4.f0000664000175000017500000000046214673353433016022 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-6.07.01/exception/driver/0000775000175000017500000000000014737552575015422 5ustar frankfrankbobcat-6.07.01/exception/driver/build0000775000175000017500000000077614673353433016450 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-6.07.01/exception/driver/driver.cc0000664000175000017500000000330014673353433017207 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-6.07.01/exception/factory5.f0000664000175000017500000000063414673353433016024 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-6.07.01/exec/0000775000175000017500000000000014736742656013055 5ustar frankfrankbobcat-6.07.01/exec/exec.ih0000664000175000017500000000020214736315237014304 0ustar frankfrank#include "exec" #include #include #include "../string/string" using namespace std; using namespace FBB; bobcat-6.07.01/exec/childprocess.cc0000664000175000017500000000037114673353434016037 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-6.07.01/exec/execute.cc0000664000175000017500000000016714673353434015022 0ustar frankfrank#include "exec.ih" bool Exec::execute(std::string const &cmd) { d_cmd = cmd; fork(); return d_ret == 0; } bobcat-6.07.01/exec/splitsource.cc0000664000175000017500000000020014673353434015720 0ustar frankfrank#include "exec.ih" vector Exec::splitSource() const { String::Type type; return String::split(&type, d_cmd); } bobcat-6.07.01/exec/icmconf0000664000175000017500000000007214673353434014405 0ustar frankfrank#define LIBRARY "exec" #include "../icmconf" bobcat-6.07.01/exec/exec0000664000175000017500000000163514673353434013721 0ustar frankfrank#ifndef INCLUDED_BOBCAT_EXEC_ #define INCLUDED_BOBCAT_EXEC_ #include #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-6.07.01/exec/driver/0000775000175000017500000000000014737552575014350 5ustar frankfrankbobcat-6.07.01/exec/driver/build0000775000175000017500000000010614673353434015362 0ustar frankfrank#!/bin/bash g++ `cat ../../c++std` -Wall -odriver driver.cc -lbobcat bobcat-6.07.01/exec/driver/driver.cc0000664000175000017500000000072514673353434016146 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-6.07.01/extractorbase/0000775000175000017500000000000014736742656014777 5ustar frankfrankbobcat-6.07.01/extractorbase/extractor.ih.obs0000664000175000017500000000015114673353434020103 0ustar frankfrank#include "extractor" #include #include using namespace std; using namespace FBB; bobcat-6.07.01/extractorbase/execute.cc0000664000175000017500000000020714673353434016737 0ustar frankfrank#include "extractorbase.ih" void ExtractorBase::execute(string const &cmd) { d_iChildOutPipe = Pipe{}; Exec::execute(cmd); } bobcat-6.07.01/extractorbase/extractorbase1.cc0000664000175000017500000000017114673353434020224 0ustar frankfrank#include "extractorbase.ih" ExtractorBase::ExtractorBase(size_t bufSize) : istream(this), d_bufSize(bufSize) {} bobcat-6.07.01/extractorbase/extractor.obs0000664000175000017500000000205514673353434017511 0ustar frankfrank#ifndef INCLUDED_BOBCAT_EXTRACTOR_ #define INCLUDED_BOBCAT_EXTRACTOR_ #include #include #include #include namespace FBB { class ExtractorBase: protected Exec, private IFdBuf { // the child process inserts into the pipe size_t d_bufSize; void (*d_closeFun)(); std::istream &d_in; Pipe d_pipe; // cout/cerr written by the CHILD int d_receiveFd; // chilld's fd output received by the // parent int *d_ret; bool d_stopped; public: ExtractorBase(int *ret, std::istream &in, void (*closeFun)(), size_t bufSize, int receiveFd, std::string const &cmd); ~Extractor() override; using Exec::ret; int stop(); int waitForChild(); private: void v_childRedirections() override; void v_parentRedirections() override; void v_parentProcess() override; }; } // namespace FBB #endif bobcat-6.07.01/extractorbase/extractorbase.ih0000664000175000017500000000016014736315237020153 0ustar frankfrank#include "extractorbase" #include using namespace std; using namespace FBB; using namespace IUO; bobcat-6.07.01/extractorbase/icmconf0000664000175000017500000000010314673353434016322 0ustar frankfrank#define LIBRARY "extractorbase" #include "../icmconf" bobcat-6.07.01/extractorbase/extractorbase0000664000175000017500000000150514673353434017561 0ustar frankfrank#ifndef INCLUDED_BOBCAT_EXTRACTORBASE_ #define INCLUDED_BOBCAT_EXTRACTORBASE_ #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-6.07.01/extractorbase/parentredirections.cc0000664000175000017500000000021614673353434021201 0ustar frankfrank#include "extractorbase.ih" void ExtractorBase::parentRedirections() { reset(d_iChildOutPipe.readOnly(), IFdBuf::CLOSE_FD, d_bufSize); } bobcat-6.07.01/fbb/0000775000175000017500000000000014736520620012643 5ustar frankfrankbobcat-6.07.01/fbb/fbb.ih0000664000175000017500000000007414736315237013725 0ustar frankfrank#include "fbb" using namespace std; using namespace FBB; bobcat-6.07.01/fbb/fbb0000664000175000017500000000025614673353434013331 0ustar frankfrank#ifndef INCLUDED_BOBCAT_FBB_ #define INCLUDED_BOBCAT_FBB_ namespace FBB { enum CryptType { DECRYPT, ENCRYPT, DECODE = DECRYPT, ENCODE }; } // FBB #endif bobcat-6.07.01/field/0000775000175000017500000000000014736520620013175 5ustar frankfrankbobcat-6.07.01/field/field0000664000175000017500000000125714673353434014217 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-6.07.01/field/fieldtype.f0000664000175000017500000000102714673353434015340 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-6.07.01/field/set.f0000664000175000017500000000053214673353434014146 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-6.07.01/field/exp1.f0000664000175000017500000000032614673353434014231 0ustar frankfranktemplate struct exp1 { enum { value = base * exp1::value }; }; template struct exp1 { enum { value = 1 }; }; bobcat-6.07.01/field/exp2.f0000664000175000017500000000026114673353434014230 0ustar frankfranktemplate struct exp2 { enum { value = 1 + exp2::value }; }; template <> struct exp2<1> { enum { value = 0 }; }; bobcat-6.07.01/field/set0.f0000664000175000017500000000114314673353434014225 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-6.07.01/field/get.f0000664000175000017500000000031214673353434014126 0ustar frankfranktemplate inline uint64_t constexpr Field::get(uint64_t value) { return FieldType<((base - 1) & base) == 0, base, end, begin>::get(value); } bobcat-6.07.01/field/field.ih0000664000175000017500000000007714736315237014614 0ustar frankfrank#include "field" using namespace std; using namespace FBB; bobcat-6.07.01/field/get0.f0000664000175000017500000000036714673353434014220 0ustar frankfranktemplate inline uint64_t constexpr FieldType::get(uint64_t value) { return value / exp1::value % exp1::value; } bobcat-6.07.01/field/get1.f0000664000175000017500000000035014673353434014211 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-6.07.01/field/set1.f0000664000175000017500000000223414673353434014230 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-6.07.01/field/driver/0000775000175000017500000000000014673353434014477 5ustar frankfrankbobcat-6.07.01/field/driver/main.cc0000664000175000017500000000136514673353434015737 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-6.07.01/fileclock/0000775000175000017500000000000014737167447014064 5ustar frankfrankbobcat-6.07.01/fileclock/fileclock.ih0000664000175000017500000000002614736315237016326 0ustar frankfrank#include "fileclock" bobcat-6.07.01/fileclock/fileclock0000664000175000017500000000117614737167447015747 0ustar frankfrank#ifndef INCLUDED_BOBCAT_FILECLOCK_ #define INCLUDED_BOBCAT_FILECLOCK_ #include namespace FBB { struct FileClock: public ClockBase { using ChronoClock = std::chrono::file_clock; FileClock(TimePoint const &timePoint = now()); template FileClock(ClockBase const &clock); }; inline FileClock::FileClock(TimePoint const &timePoint) : ClockBase(timePoint) {} template inline FileClock::FileClock(ClockBase const &clock) : ClockBase(toClock(clock)) {} } // FBB #endif bobcat-6.07.01/filesystem/0000775000175000017500000000000014745725615014311 5ustar frankfrankbobcat-6.07.01/filesystem/filesystem.f0000664000175000017500000001552514736462701016646 0ustar frankfrankinline std::ostream &operator<<(std::ostream &out, FileSystem const &rhs) { return out << rhs.d_path.string(); } inline bool operator==(FileSystem const &lhs, FileSystem const &rhs) { return lhs.sameAs(rhs); } template FileSystem &FileSystem::operator/=(Type const &arg) { d_path /= arg; return *this; } inline FileSystem &FileSystem::operator/=(FileSystem const &arg) { return *this /= arg.d_path; } template FileSystem &FileSystem::operator+=(Type const &arg) { d_path += arg; return *this; } inline FileSystem &FileSystem::operator+=(FileSystem const &arg) { return *this += arg.d_path; } inline char const *FileSystem::c_str() const { return d_path.c_str(); } inline std::string FileSystem::extension() const { return d_path.extension(); } inline std::string FileSystem::filename() const { return d_path.filename(); } inline FileSystem::Path const &FileSystem::path() const { return d_path; } inline FileSystem FileSystem::stem() const { return d_path.stem(); } inline std::string FileSystem::string() const { return d_path.string(); } inline bool FileSystem::isAbsolute() const { return d_path.is_absolute(); } inline bool FileSystem::hasExtension() const { return d_path.has_extension(); } inline bool FileSystem::hasFilename() const { return d_path.has_filename(); } inline bool FileSystem::isRelative() const { return d_path.is_relative(); } inline FileSystem FileSystem::parent() const { return d_path.parent_path(); } inline FileSystem FileSystem::relative() const { return d_path.relative_path(); } inline void FileSystem::clear() { d_path.clear(); } inline Ranger FileSystem::range() { return Ranger{ d_path.begin(), d_path.end() }; } inline Ranger FileSystem::range() const { return Ranger{ d_path.begin(), d_path.end() }; } inline FileSystem &FileSystem::operator()(EC &ec) { return set(&ec); } inline FileSystem const &FileSystem::operator()(EC &ec) const { return set(&ec); } inline FileSystem &FileSystem::noEC() { return set(0); } inline FileSystem const &FileSystem::noEC() const { return set(0); } inline FileSystem FileSystem::absolute() const { namespace fs = std::filesystem; return optEC1(fs::absolute, fs::absolute); // return absCan(fs::absolute, fs::absolute); } inline FileSystem FileSystem::canonical() const { namespace fs = std::filesystem; return optEC1(fs::canonical, fs::canonical); // return absCan(fs::canonical, fs::canonical); } inline bool FileSystem::copy(FileSystem const &dest, FSOptions cpOptions) { return copy(dest.d_path, cpOptions); } inline bool FileSystem::mkDir() const { namespace fs = std::filesystem; return optEC1(fs::create_directory, fs::create_directory); } inline bool FileSystem::mkDir(Path const &reference) const { namespace fs = std::filesystem; return optEC2(reference, fs::create_directory, fs::create_directory); } inline bool FileSystem::mkDir(FileSystem const &reference) const { return mkDir(reference.d_path); } inline bool FileSystem::mkDirs() const { namespace fs = std::filesystem; return optEC1(fs::create_directories, fs::create_directories); } // static inline FileSystem FileSystem::cwd() { return std::filesystem::current_path(); } // static inline FileSystem FileSystem::cwd(EC &ec) { return std::filesystem::current_path(ec); } inline bool FileSystem::sameAs(Path const &rhs) const { namespace fs = std::filesystem; return d_ec == 0 ? fs::equivalent(d_path, rhs) : fs::equivalent(d_path, rhs, *d_ec); } inline bool FileSystem::sameAs(FileSystem const &rhs) const { return sameAs(rhs.d_path); } inline bool FileSystem::exists() const { namespace fs = std::filesystem; return optEC1(fs::exists, fs::exists); } // static inline bool FileSystem::exists(FileStatus status) { return std::filesystem::exists(status); } template inline ReturnType FileSystem::optEC1( ReturnType (*fun1)(Path const &), ReturnType (*fun2)(Path const &, EC &)) const { return d_ec == 0 ? fun1(d_path) : fun2(d_path, *d_ec); } inline std::uintmax_t FileSystem::size() const { namespace fs = std::filesystem; return optEC1(fs::file_size, fs::file_size); } inline std::uintmax_t FileSystem::count() const { namespace fs = std::filesystem; return optEC1(fs::hard_link_count, fs::hard_link_count); } inline FileSystem::FileClock::time_point FileSystem::fcModification() const { namespace fs = std::filesystem; return optEC1(fs::last_write_time, fs::last_write_time); } inline FileSystem::SystemClock::time_point FileSystem::modification() const { return FileClock::to_sys(fcModification()); } inline FileSystem FileSystem::destination() const { namespace fs = std::filesystem; return FileSystem{ optEC1(fs::read_symlink, fs::read_symlink) }; } inline bool FileSystem::remove() const { namespace fs = std::filesystem; return optEC1(fs::remove, fs::remove); } inline std::uintmax_t FileSystem::removeAll() const { namespace fs = std::filesystem; return optEC1(fs::remove_all, fs::remove_all); } inline bool FileSystem::rename(Path const &newName) const { namespace fs = std::filesystem; return optEC3(newName, fs::rename, fs::rename); } inline bool FileSystem::rename(FileSystem const &newName) const { return rename(newName.d_path); } // static inline FileSystem FileSystem::tmpDir(EC &ec) { return FileSystem{ std::filesystem::temp_directory_path(ec) }; } inline FileSystem &FileSystem::setExtension(std::string const &ext) { d_path.replace_extension(ext); return *this; } inline FileSystem &FileSystem::setFilename(std::string const &newName) { d_path.replace_filename(newName); return *this; } inline bool FileSystem::knownStatus() const { namespace fs = std::filesystem; return fs::status(d_path, s_errorCode) != fs::file_status{}; } inline FileSystem::FileType FileSystem::type(bool destination) const { return status(destination).type(); } inline FileSystem::Perms FileSystem::permissions() const { return status().permissions(); } inline FileSystem::DirEntry FileSystem::directory() const { namespace fs = std::filesystem; return fs::directory_entry(d_path); } template inline FileSystem const &FileSystem::setPermissions(PermType perms, FSOptions opt) const { return setPerms(static_cast(perms), opt); } template inline FileSystem &FileSystem::setPermissions(PermType perms, FSOptions opt) { return setPerms(static_cast(perms), opt); } // static inline std::error_code &FileSystem::errorCode() { return s_errorCode; } bobcat-6.07.01/filesystem/setcwd1.cc0000664000175000017500000000020114736306357016161 0ustar frankfrank#include "filesystem.ih" FileSystem &FileSystem::setCwd() { optEC1(fs::current_path, fs::current_path); return *this; } bobcat-6.07.01/filesystem/filesystem3.cc0000664000175000017500000000021014736734164017057 0ustar frankfrank#include "filesystem.ih" FileSystem::FileSystem(Path &&tmp, bool useEC) : d_ec(useEC ? &s_errorCode : 0), d_path(move(tmp)) {} bobcat-6.07.01/filesystem/data.cc0000664000175000017500000000007614736306357015532 0ustar frankfrank#include "filesystem.ih" error_code FileSystem::s_errorCode; bobcat-6.07.01/filesystem/setmodification2.cc0000664000175000017500000000024014736306357020055 0ustar frankfrank#include "filesystem.ih" bool FileSystem::setModification(DateTime const &time) { return setModification( SystemClock::from_time_t(time.utcSeconds()) ); } bobcat-6.07.01/filesystem/filesystem0000664000175000017500000002334314745725615016425 0ustar frankfrank#ifndef INCLUDED_BOBCAT_FILESYSTEM_ #define INCLUDED_BOBCAT_FILESYSTEM_ #include #include #include #include #include #include namespace FBB { class DateTime; template class Ranger; struct FileSystem: public FS { // sets d_ec = 0 friend std::istream &operator>>(std::istream &in, // opextract FileSystem &rhs); friend std::ostream &operator<<(std::ostream &out, // .f FileSystem const &rhs); // note: both must exists or an exception is thrown friend bool operator==(FileSystem const &lhs, // .f FileSystem const &rhs); using EC = std::error_code; using FileStatus = std::filesystem::file_status; using Path = std::filesystem::path; using Iter = Path::iterator; using ConstIter = Path::const_iterator; using DirEntry = std::filesystem::directory_entry; using DirIter = std::filesystem::directory_iterator; using RecursiveIter = std::filesystem::recursive_directory_iterator; using CopyOpts = std::filesystem::copy_options; using Perms = std::filesystem::perms; using PermOpts = std::filesystem::perm_options; using FileType = std::filesystem::file_type; using SystemClock = std::chrono::system_clock; using FileClock = std::chrono::file_clock; private: mutable EC *d_ec = 0; // 0 if no EC is used. Path d_path; static EC s_errorCode; public: FileSystem() = default; FileSystem(Path const &path, bool useEC = true); // 1 FileSystem(Path const &path, EC &ec); // 2 FileSystem(Path &&tmp, bool useEC = true); // 3 FileSystem(Path &&tmp, EC &ec); // 4 void swap(FileSystem &other); void clear(); // .f template // .f FileSystem &operator/=(Type const &arg); FileSystem &operator/=(FileSystem const &arg); // .f template // .f FileSystem &operator+=(Type const &arg); FileSystem &operator+=(FileSystem const &arg); // .f // if (not fs().absolute()) // or if (not fs(ec).absolute())... FileSystem &operator()(EC &ec = s_errorCode); // .f FileSystem const &operator()(EC &ec = s_errorCode) const; // .f FileSystem &noEC(); // .f FileSystem const &noEC() const; // .f static std::error_code &errorCode(); // .f char const *c_str() const; // .f Path const &path() const; // .f std::string string() const; // .f std::string extension() const; // .f FileSystem &setExtension(std::string const &ext); // .f bool hasExtension() const; // .f std::string filename() const; // .f FileSystem &setFilename(std::string const &newName); // .f bool hasFilename() const; // .f FileSystem stem() const; // .f FileSystem parent() const; // .f FileSystem relative() const; // drops a starting '/' // .f Ranger range(); // .f Ranger range() const; // .f FileSystem absolute() const; // .f FileSystem canonical() const; // .f bool isAbsolute() const; // .f bool isRelative() const; // .f // .f bool copy(FileSystem const &dest, FSOptions cpOptions = DEFAULT); bool copy(Path const &dest, FSOptions cpOptions = DEFAULT); bool mkDir() const; // the parent must exist // .f bool mkDir(Path const &reference) const; // .f bool mkDir(FileSystem const &reference) const; // .f bool mkDirs() const; // constructs all subdirs // .f static FileSystem cwd(); // .f static FileSystem cwd(EC &ec); // .f FileSystem &setCwd(); // 1 static FileSystem setCwd(Path const &path); // 2 static FileSystem setCwd(Path const &path, EC &ec); // 3 bool sameAs(FileSystem const &other) const; // equivalent // .f bool sameAs(Path const &other) const; // .f bool exists() const; // .f static bool exists(FileStatus status); // .f //throws if not existing uintmax_t size() const; // .f uintmax_t count() const; // # hard link count // .f // last_write_time FileClock::time_point fcModification() const; // .f SystemClock::time_point modification() const; // .f bool setModification(SystemClock::time_point const &time); // 1.cc bool setModification(FBB::DateTime const &time); // 2.cc // the calling object must refer to a simlink FileSystem destination() const; // symlink's destination // .f bool remove() const; // .f std::uintmax_t removeAll() const; // .f bool rename(FileSystem const &newName) const; // .f bool rename(Path const &newName) const; // .f bool resize(std::uintmax_t size) const; // .f static FileSystem tmpDir(bool ec = true); // tmpdir static FileSystem tmpDir(EC &ec); // .f // space, system_complete: maybe? FileType type(bool destination = true) const; // .f // true/false: cf. status() // unclear how this works: returns fallse if the type doesn't // match, but nothing is changed bool setType(FileType type, bool destination = true); FileStatus status(bool destination = true) const; // Only returns false with file_status{}. // More useful: check FileStatus for file_type::not_found or // file_type::unknown bool knownStatus() const; // Koenig: no ns spec needed for is_* // bool is_WHATEVER(file_status status) // bool is_WHATEVER(path const path &entry [, error_code &ec]) // retrieve permissions Perms permissions() const; // .f template FileSystem const &setPermissions(PermType perms, // .f FSOptions opt = RESET) const; template FileSystem &setPermissions(PermType perms, // .f FSOptions opt = RESET); DirEntry directory() const; // .f // returns directory_entry objects, only the current dir Ranger dirRange() const; // 1.cc // returns directory_iterators to all (recursive) entries Ranger recursiveRange() const; // 2.cc private: template Ranger dirRange() const; FileSystem &set(EC *ptr) const; // backdoor (for op()() members) template ReturnType optEC1(ReturnType (*fun1)(Path const &), // .f ReturnType (*fun2)(Path const &, EC &) ) const; bool optEC2(Path const &dest, bool (*fun1)(Path const &, Path const &), // 2.cc bool (*fun2)(Path const &, Path const &, EC &) ) const; bool optEC3(Path const &dest, void (*fun1)(Path const &, Path const &), // 3.cc void (*fun2)(Path const &, Path const &, EC &) ) const; // private backdoor for setPermissions FileSystem &setPerms(Perms perms, FSOptions opt) const; bool hardLink(Path const &dest) const; // .ih bool symLink(Path const &dest) const; // .ih bool cpSymLink(Path const &dest) const; // .ih bool copyFile(Path const &dest, unsigned options) const; bool fsCopy(Path const &dest, unsigned options) const; }; #include "filesystem.f" } // FBB #endif bobcat-6.07.01/filesystem/abscan.cc0000664000175000017500000000003314736306357016041 0ustar frankfrank#include "filesystem.ih" bobcat-6.07.01/filesystem/fscopy.cc0000664000175000017500000000044614736306357016125 0ustar frankfrank#include "filesystem.ih" bool FileSystem::fsCopy(Path const &dest, unsigned options) const { fs::copy_options opts = static_cast(options); if (d_ec == 0) fs::copy(d_path, dest, opts); else fs::copy(d_path, dest, opts, *d_ec); return true; } bobcat-6.07.01/filesystem/status.cc0000664000175000017500000000042114736462514016134 0ustar frankfrank#include "filesystem.ih" FileSystem::FileStatus FileSystem::status(bool destination) const { return destination ? // follow a symlink optEC1(fs::status, fs::status) : optEC1(fs::symlink_status, fs::symlink_status); } bobcat-6.07.01/filesystem/resize.cc0000664000175000017500000000036714736306357016125 0ustar frankfrank#include "filesystem.ih" bool FileSystem::resize(uintmax_t size) const { if (d_ec == 0) { fs::resize_file(d_path, size); return true; } fs::resize_file(d_path, size, *d_ec); return static_cast(*d_ec); } bobcat-6.07.01/filesystem/set.cc0000664000175000017500000000023514736306357015411 0ustar frankfrank#include "filesystem.ih" // private backdoor FileSystem &FileSystem::set(EC *ptr) const { d_ec = ptr; return const_cast(*this); } bobcat-6.07.01/filesystem/setperms.cc0000664000175000017500000000047114736306357016462 0ustar frankfrank#include "filesystem.ih" FileSystem &FileSystem::setPerms(Perms perms, FSOptions opt) const { if (d_ec == 0) fs::permissions(d_path, perms, static_cast(opt)); else fs::permissions(d_path, perms, static_cast(opt), *d_ec); return const_cast(*this); } bobcat-6.07.01/filesystem/filesystem2.cc0000664000175000017500000000016014736734042017055 0ustar frankfrank#include "filesystem.ih" FileSystem::FileSystem(Path const &path, EC &ec) : d_ec(&ec), d_path(path) {} bobcat-6.07.01/filesystem/symlink.cc0000664000175000017500000000054614736306357016311 0ustar frankfrank#include "filesystem.ih" bool FileSystem::symLink(Path const &dest) const { return is_directory(d_path, s_errorCode) ? optEC3(dest, fs::create_directory_symlink, fs::create_directory_symlink) : optEC3(dest, fs::create_symlink, fs::create_symlink); } bobcat-6.07.01/filesystem/ranger1.cc0000664000175000017500000000056314736306357016161 0ustar frankfrank#include "filesystem.ih" Ranger FileSystem::dirRange() const { return d_ec == 0 ? Ranger(fs::directory_iterator{ d_path }, fs::directory_iterator{}) : Ranger(fs::directory_iterator{ d_path, *d_ec }, fs::directory_iterator{}); } bobcat-6.07.01/filesystem/filesystem.ih0000664000175000017500000000134414736315237017014 0ustar frankfrank#include "filesystem" #include #include #include using namespace std; using namespace FBB; using namespace chrono; using namespace filesystem; namespace fs = filesystem; template inline Ranger FileSystem::dirRange() const { auto ret = Ranger { d_ec ? IterType(d_path, *d_ec) : IterType(d_path), IterType{} }; } inline bool FileSystem::hardLink(Path const &dest) const { return optEC3(dest, fs::create_hard_link, fs::create_hard_link); } inline bool FileSystem::cpSymLink(Path const &dest) const { return optEC3(dest, fs::copy_symlink, fs::copy_symlink); } bobcat-6.07.01/filesystem/icmconf0000644000175000017500000000124314736451123015636 0ustar frankfrank// see also ~/.icmake/icmconf.mod for a possible module-using icmconf #define CLS #define LIBRARY "ofiles" #define MULTICOMP "jobs -q" #define SPCH "-u xerr/xerr.ih" //#define USE_ALL "a" #define SOURCES "*.cc" #define OBJ_EXT ".o" #define TMP_DIR "tmp" #define USE_ECHO ON #define IH ".ih" #define CXX "ccache g++" #define CXXFLAGS "-Wall -Werror -O2 -fdiagnostics-color=never" #define REFRESH #define LDFLAGS "-s" #define ADD_LIBRARIES "bobcat" #define ADD_LIBRARY_PATHS "" #define DEFCOM "library" bobcat-6.07.01/filesystem/filesystem1.cc0000664000175000017500000000021114736733632017055 0ustar frankfrank#include "filesystem.ih" FileSystem::FileSystem(Path const &path, bool useEC) : d_ec(useEC ? &s_errorCode : 0), d_path(path) {} bobcat-6.07.01/filesystem/copyfile.cc0000664000175000017500000000051714736306357016433 0ustar frankfrank#include "filesystem.ih" bool FileSystem::copyFile(Path const &dest, unsigned options) const { fs::copy_options opts = static_cast(options &= (FILE - 1)); return d_ec == 0 ? fs::copy_file(d_path, dest, opts) : fs::copy_file(d_path, dest, opts, *d_ec); } bobcat-6.07.01/filesystem/README.copy0000664000175000017500000000075614736306357016150 0ustar frankfrank DIRS_ONLY copy: DEFAULT, NEW, REPLACE, UPDATE, RECURSIVE, CP_SYMLINKS, SKIP_SYMLINKS copy_file: " " " " --- " " FILE copy_symlink: CP_SYMLINK create_directory_symlink of create_symlink: SYMLINK with (dest, link): 'ln -s dest link', link -> dest create_hardlink LINK ---------------------------------------------------------------------- LINK: create_hardlink bobcat-6.07.01/filesystem/setcwd2.cc0000664000175000017500000000024014736306357016165 0ustar frankfrank#include "filesystem.ih" // static FileSystem FileSystem::setCwd(Path const &path) { FileSystem cwd{ path }; fs::current_path(path); return cwd; } bobcat-6.07.01/filesystem/swap.cc0000664000175000017500000000020714736306357015567 0ustar frankfrank#include "filesystem.ih" void FileSystem::swap(FileSystem &other) { std::swap(d_ec, other.d_ec); d_path.swap(other.d_path); } bobcat-6.07.01/filesystem/optec2.cc0000664000175000017500000000052014736306357016007 0ustar frankfrank#include "filesystem.ih" bool FileSystem::optEC2( Path const &dest, bool (*fun1)(Path const &, Path const &), bool (*fun2)(Path const &, Path const &, EC &)) const { return d_ec != 0 ? (*fun2)(d_path, dest, *d_ec) : fun1(d_path, dest); } bobcat-6.07.01/filesystem/setpermissions.cc0000664000175000017500000000000014736306357017673 0ustar frankfrankbobcat-6.07.01/filesystem/filesystem4.cc0000664000175000017500000000015714736734223017066 0ustar frankfrank#include "filesystem.ih" FileSystem::FileSystem(Path &&tmp, EC &ec) : d_ec(&ec), d_path(move(tmp)) {} bobcat-6.07.01/filesystem/opextract.cc0000664000175000017500000000024714736306357016632 0ustar frankfrank#include "filesystem.ih" namespace FBB { istream &operator>>(istream &in, FileSystem &rhs) { rhs.d_ec = 0; return in >> rhs.d_path; } } bobcat-6.07.01/filesystem/setmodification1.cc0000664000175000017500000000054414736306357020063 0ustar frankfrank#include "filesystem.ih" bool FileSystem::setModification(SystemClock::time_point const &time) { FileClock::time_point fileTime = clock_cast(time); if (d_ec == 0) { fs::last_write_time(d_path, fileTime); return true; } fs::last_write_time(d_path, fileTime, *d_ec); return static_cast(*d_ec); } bobcat-6.07.01/filesystem/optec3.cc0000664000175000017500000000056614736306357016022 0ustar frankfrank#include "filesystem.ih" bool FileSystem::optEC3( Path const &dest, void (*fun1)(Path const &, Path const &), void (*fun2)(Path const &, Path const &, EC &)) const { if (d_ec == 0) { fun1(d_path, dest); return true; } (*fun2)(d_path, dest, *d_ec); return static_cast(*d_ec); } bobcat-6.07.01/filesystem/settype.cc0000664000175000017500000000031014736306357016305 0ustar frankfrank#include "filesystem.ih" bool FileSystem::setType(FileType type, bool destination) { status(destination).type(type); return status(destination).type() == type; // check the current status } bobcat-6.07.01/filesystem/ranger2.cc0000664000175000017500000000074714736306357016166 0ustar frankfrank#include "filesystem.ih" Ranger FileSystem::recursiveRange() const { return d_ec == 0 ? Ranger( fs::recursive_directory_iterator{ d_path }, fs::recursive_directory_iterator{} ) : Ranger( fs::recursive_directory_iterator{ d_path, *d_ec }, fs::recursive_directory_iterator{} ); } bobcat-6.07.01/filesystem/tmpdir.cc0000664000175000017500000000034114736306357016113 0ustar frankfrank#include "filesystem.ih" // static FileSystem FileSystem::tmpDir(bool ec) { return ec == true ? tmpDir(s_errorCode) : FileSystem{ std::filesystem::temp_directory_path() }; } bobcat-6.07.01/filesystem/setcwd3.cc0000664000175000017500000000025414736306357016173 0ustar frankfrank#include "filesystem.ih" // static FileSystem FileSystem::setCwd(Path const &path, EC &ec) { FileSystem cwd{ path }; fs::current_path(path, ec); return cwd; } bobcat-6.07.01/filesystem/CLASSES0000664000175000017500000000000014736451145015311 0ustar frankfrankbobcat-6.07.01/filesystem/driver/0000775000175000017500000000000014737223322015571 5ustar frankfrankbobcat-6.07.01/filesystem/driver/build0000775000175000017500000000006514737027560016625 0ustar frankfrank#!/bin/bash g++ --std=c++26 -Wall main.cc -lbobcat; bobcat-6.07.01/filesystem/driver/main.cc0000644000175000017500000000172214737010316017021 0ustar frankfrank#include #include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) { if (argc == 1) { cout << "1st arg: an existing file\n" "2nd arg (optional): a directory owned by the caller\n"; return 1; } FileSystem fs{ argv[1] }; if (not fs.exists()) cout << "No such file " << argv[1] << '\n'; else cout << "last modification date of " << argv[1] << ": " << fs.modification() << '\n'; cout << oct << "Permissions: 0" << static_cast(fs.permissions()) << dec << '\n'; if (argc > 2) { cout << "Entries of " << argv[2] << ":\n"; FileSystem fs2{ argv[2] }; for (auto const &entry: fs2.dirRange()) cout << " " << entry << '\n'; cout << fs2.errorCode().message() << '\n'; } } bobcat-6.07.01/filesystem/copy.cc0000664000175000017500000000250114736306357015566 0ustar frankfrank#include "filesystem.ih" //DEFAULT //NEW, REPLACE, UPDATE - only one //RECURSIVE - not with FILE. Not RECURSIVE then 1 level deep // //CP_SYMLINKS - with copy(): cp symlinks as symlinks //SKIP_SYMLINKS - with copy: skip symlinks //DIRS_ONLY - with copy: only copy the dir. structure // //SYMLINK create_symlink as in 'ln -s d_path dest' // if d_path is a dir: create_directory_symlink // //LINK hard link of src/dest // // FILE calls copy_file // // SYMLINK_CP - calls copy_symlink: both must be symlinks // // //options: // & FILE - copy_file // | DEFAULT NEW, REPLACE, UPDATE // // & CP_SYMLINK - copy_symlink, no further options bool FileSystem::copy(Path const &dest, FSOptions options) { switch (options & (NEW_LINK | NEW_SYMLINK | CP_SYMLINK | FILE)) { case NEW_LINK: return hardLink(dest); case NEW_SYMLINK: return symLink(dest); case CP_SYMLINK: return cpSymLink(dest); case FILE: // only files return copyFile(dest, options); default: // also recursive return fsCopy(dest, options); } } bobcat-6.07.01/fmt/0000775000175000017500000000000014736742656012717 5ustar frankfrankbobcat-6.07.01/fmt/left2.f0000664000175000017500000000022614673353434014072 0ustar frankfrankinline FMT left(std::string const &size, unsigned precision = ~0U) { return { FMT::LEFT, static_cast(size.length()), precision, 1 }; } bobcat-6.07.01/fmt/fmt3.f0000664000175000017500000000010314673353434013721 0ustar frankfrankinline FMT::FMT(unsigned nCols) : FMT(HLINE, 0, ~0U, nCols) {} bobcat-6.07.01/fmt/join1.cc0000664000175000017500000000051014673353434014232 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-6.07.01/fmt/data.cc0000664000175000017500000000040414673353434014125 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-6.07.01/fmt/fmt0000664000175000017500000000712114673353434013421 0ustar frankfrank#ifndef INCLUDED_BOBCAT_FMT_ #define INCLUDED_BOBCAT_FMT_ #include #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, }; using FMTFun = FMT (*)(unsigned, unsigned); using FMTHline = FMT (*)(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-6.07.01/fmt/opinsert.f0000664000175000017500000000014314673353434014717 0ustar frankfrankinline std::ostream &operator<<(std::ostream &out, FMT const &fmt) { return fmt.insert(out); } bobcat-6.07.01/fmt/hline.f0000664000175000017500000000015014673353434014151 0ustar frankfrankinline FMT hline(unsigned nCols = ~0U) { return { FMT::HLINE, 0, ~0U, nCols == 0 ? 1 : nCols }; } bobcat-6.07.01/fmt/lrcfun.cc0000664000175000017500000000040314673353434014504 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-6.07.01/fmt/precision.f0000664000175000017500000000010314673353434015043 0ustar frankfrankinline unsigned FMT::precision() const { return d_precision; } bobcat-6.07.01/fmt/center2.f0000664000175000017500000000026314673353434014421 0ustar frankfrankinline FMT center(std::string const &size, unsigned precision = ~0U) { return { FMT::CENTER, static_cast(size.length()), precision, 1 }; } bobcat-6.07.01/fmt/left1.f0000664000175000017500000000015414673353434014071 0ustar frankfrankinline FMT left(unsigned size, unsigned precision = ~0U) { return { FMT::LEFT, size, precision, 1 }; } bobcat-6.07.01/fmt/align1.f0000664000175000017500000000007514673353434014233 0ustar frankfrankinline FMT::Align FMT::align() const { return d_align; } bobcat-6.07.01/fmt/fmt2.f0000664000175000017500000000016114673353434013724 0ustar frankfrankinline FMT::FMT(unsigned width, unsigned precision, unsigned nCols) : FMT(RIGHT, width, precision, nCols) {} bobcat-6.07.01/fmt/ncols.f0000664000175000017500000000007314673353434014174 0ustar frankfrankinline unsigned FMT::nCols() const { return d_nCols; } bobcat-6.07.01/fmt/fmt1.cc0000664000175000017500000000035214673353434014065 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-6.07.01/fmt/icmconf0000664000175000017500000000007214673353434014247 0ustar frankfrank#define LIBRARY "fmt" #include "../icmconf.lib" bobcat-6.07.01/fmt/fmt.ih0000664000175000017500000000012714736315237014016 0ustar frankfrank#include "fmt" #include "../xerr/xerr.ih" using namespace std; using namespace FBB; bobcat-6.07.01/fmt/align2.f0000664000175000017500000000013114673353434014225 0ustar frankfrank// static inline char const *FMT::align(FMT::Align value) { return s_align[value]; } bobcat-6.07.01/fmt/width2.f0000664000175000017500000000010214673353434014250 0ustar frankfrankinline void FMT::width(unsigned nChars) { d_width = nChars; } bobcat-6.07.01/fmt/width1.f0000664000175000017500000000007314673353434014256 0ustar frankfrankinline unsigned FMT::width() const { return d_width; } bobcat-6.07.01/fmt/insert.f0000664000175000017500000000041214673353434014357 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-6.07.01/fmt/center1.f0000664000175000017500000000016014673353434014414 0ustar frankfrankinline FMT center(unsigned size, unsigned precision = ~0U) { return { FMT::CENTER, size, precision, 1 }; } bobcat-6.07.01/fmt/right2.f0000664000175000017500000000023014673353434014250 0ustar frankfrankinline FMT right(std::string const &size, unsigned precision = ~0U) { return { FMT::RIGHT, static_cast(size.length()), precision, 1 }; } bobcat-6.07.01/fmt/right1.f0000664000175000017500000000015614673353434014256 0ustar frankfrankinline FMT right(unsigned size, unsigned precision = ~0U) { return { FMT::RIGHT, size, precision, 1 }; } bobcat-6.07.01/fmt/join2.f0000664000175000017500000000021314673353434014073 0ustar frankfrank // join all remaining columns inline FMT join(FMT::Align align, unsigned precision = ~0U) { return join(~0U, align, precision); } bobcat-6.07.01/fork/0000775000175000017500000000000014736742656013072 5ustar frankfrankbobcat-6.07.01/fork/preparedaemon2.cc0000664000175000017500000000110414673353434016271 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-6.07.01/fork/fork.ih0000664000175000017500000000031414736315237014342 0ustar frankfrank#include "fork" #include #include #include #include #include #include #include using namespace std; using namespace FBB; bobcat-6.07.01/fork/preparedaemon.cc0000664000175000017500000000103614673353434016213 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-6.07.01/fork/forkfork.cc0000664000175000017500000000064214673353434015216 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-6.07.01/fork/fork0000664000175000017500000000226514673353434013753 0ustar frankfrank#ifndef INCLUDED_BOBCAT_FORK_ #define INCLUDED_BOBCAT_FORK_ #include #include #include namespace FBB { class Fork { pid_t d_pid = -1; public: virtual ~Fork(); void fork(); protected: int endChild() const; // forces the childProcess's end pid_t pid() const; // .f 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 1.cc int waitForChild() const; // for Fork const &obj. 2.f private: virtual void childRedirections(); // do child redirections virtual void childProcess() = 0; // must be implemented static void reopen(std::string const &out, mode_t mode); virtual void parentRedirections(); // do parent redirections virtual void parentProcess() = 0; // must be implemented }; #include "pid.f" #include "waitforchild2.f" } // FBB #endif bobcat-6.07.01/fork/waitforchild1.cc0000664000175000017500000000020214673353434016123 0ustar frankfrank#include "fork.ih" int Fork::waitForChild() { int status; waitpid(d_pid, &status, 0); return WEXITSTATUS(status); } bobcat-6.07.01/fork/childredirections.cc0000664000175000017500000000012214673353434017062 0ustar frankfrank#include "fork.ih" void Fork::childRedirections() // do child redirections {} bobcat-6.07.01/fork/parentredirections.cc0000664000175000017500000000012314673353434017271 0ustar frankfrank#include "fork.ih" void Fork::parentRedirections() // do parent redirections {} bobcat-6.07.01/fork/destructor.cc0000664000175000017500000000004514673353434015566 0ustar frankfrank#include "fork.ih" Fork::~Fork() {} bobcat-6.07.01/fork/reopen.cc0000664000175000017500000000046114673353434014662 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-6.07.01/fork/waitforchild2.f0000664000175000017500000000013714673353434015773 0ustar frankfrankinline int Fork::waitForChild() const { return const_cast(this)->waitForChild(); } bobcat-6.07.01/fork/pid.f0000664000175000017500000000006514673353434014006 0ustar frankfrankinline pid_t Fork::pid() const { return d_pid; } bobcat-6.07.01/fork/endchild.cc0000664000175000017500000000066214673353434015147 0ustar frankfrank#include "fork.ih" int Fork::endChild() const { bool active = false; if (kill(pid(), 0) == 0) // the process is still active { active = true; kill(pid(), SIGTERM); // force its end kill(pid(), SIGKILL); } int ret = waitForChild(); // when active: -1 (forced end) return not active ? ret : -2; // otherwise the child's own exit value } bobcat-6.07.01/fork/driver/0000775000175000017500000000000014737552575014365 5ustar frankfrankbobcat-6.07.01/fork/driver/build0000775000175000017500000000005414673353434015401 0ustar frankfrank#!/bin/sh g++ -o driver driver.cc -lbobcat bobcat-6.07.01/fork/driver/driver.cc0000664000175000017500000000140414673353434016156 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-6.07.01/fork/driver/redirectedchild0000664000175000017500000000340014673353434017413 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-6.07.01/fsoptions/0000775000175000017500000000000014736520620014136 5ustar frankfrankbobcat-6.07.01/fsoptions/fsoptions0000664000175000017500000000622114736306603016111 0ustar frankfrank#ifndef INCLUDED_BOBCAT_FSOPTIONS_ #define INCLUDED_BOBCAT_FSOPTIONS_ #include namespace FBB { class FS { using CopyOpts = std::filesystem::copy_options; using PermOpts = std::filesystem::perm_options; public: enum FSOptions: unsigned { DEFAULT = static_cast(CopyOpts::none), NEW = static_cast(CopyOpts::skip_existing), REPLACE = static_cast(CopyOpts::overwrite_existing), // cp if dest is older UPDATE = static_cast(CopyOpts::update_existing), // RECURSIVE accepts CP_SYMLINKS, SKIP_SYMLINKS, ONLY_DIRS // recursively cp. subdirs RECURSIVE = static_cast(CopyOpts::recursive), // cp symlinks as symlinks CP_SYMLINKS = static_cast(CopyOpts::copy_symlinks), SKIP_SYMLINKS = static_cast(CopyOpts::skip_symlinks), // only cp the dirs ONLY_DIRS = static_cast(CopyOpts::directories_only), // symlinks to d_path SYMLINK = static_cast(CopyOpts::create_symlinks), HARDLINK = static_cast( // 256 CopyOpts::create_hard_links), FILE = 512, // call copy_file instead of copy CP_SYMLINK = 1024, // symlink to symlink NEW_SYMLINK = 2048, // create_(directory_)symlink NEW_LINK = 4096, // create_hardlink CP_MASK = (NEW_LINK << 1) - 1, RESET = static_cast(PermOpts::replace), ADD = static_cast(PermOpts::add), REMOVE = static_cast(PermOpts::remove), NOFOLLOW = static_cast(PermOpts::nofollow), // PERM_MASK = (NEW_LINK << 1) - 1 }; friend CopyOpts cpOpts(FSOptions opts); friend PermOpts permOpts(FSOptions opts); }; inline FS::CopyOpts cpOpts(FS::FSOptions opts) { return static_cast(opts); } inline FS::PermOpts permOpts(FS::FSOptions opts) { return static_cast(opts); } inline FS::FSOptions operator|(FS::FSOptions lhs, FS::FSOptions rhs) { return static_cast( static_cast(lhs) | static_cast(rhs) ); } inline FS::FSOptions operator&(FS::FSOptions lhs, FS::FSOptions rhs) { return static_cast( static_cast(lhs) & static_cast(rhs) ); } inline FS::FSOptions operator^(FS::FSOptions lhs, FS::FSOptions rhs) { return static_cast( static_cast(lhs) ^ static_cast(rhs) ); } inline FS::FSOptions operator!(FS::FSOptions arg) { return operator^(FS::FSOptions::CP_MASK, arg); } } // FBB #endif bobcat-6.07.01/fsoptions/fsoptions.ih0000664000175000017500000000013314736315237016507 0ustar frankfrank#include "fsoptions" #include "../xerr/xerr.ih" using namespace std; using namespace FBB; bobcat-6.07.01/fswap/0000775000175000017500000000000014673353434013241 5ustar frankfrankbobcat-6.07.01/fswap/fswap.decl.f0000664000175000017500000000032214673353434015433 0ustar frankfrank // declaration of the the class FastSwap: elements of SwapModes types // are swapped using an available swap-function. // template class FSwap; bobcat-6.07.01/fswap/fswap.friends.decl.f0000664000175000017500000000022514673353434017066 0ustar frankfrank#include "fswapfun.friends.f" // class FSwap // template friend class FSwap; bobcat-6.07.01/fswap/fswapbase.imp.f0000664000175000017500000000557514673353434016163 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) { using MemberType = typename FSwapMode::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-6.07.01/fswap/fswap.std.f0000664000175000017500000000075314673353434015326 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-6.07.01/fswap/fswappod.imp.f0000664000175000017500000000056214673353434016022 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-6.07.01/fswap/fswap4.f0000664000175000017500000000016014673353434014611 0ustar frankfranktemplate inline void FSwap::Xch::fswap(Tp &lhs, Tp &rhs) { tswap(lhs, rhs); } bobcat-6.07.01/fswap/fswap.std.imp.f0000664000175000017500000000133414673353434016106 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) { using MemberType = typename std::remove_reference::type; 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-6.07.01/fswap/fswap.end.imp.f0000664000175000017500000000063414673353434016064 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-6.07.01/fswap/fswap6.f0000664000175000017500000000023214673353434014613 0ustar frankfrank // overloaded fswap function swapping pointers // template inline void fswap(Type *&lhs, Type *&rhs) { std::swap(lhs, rhs); } bobcat-6.07.01/fswap/fswap.f0000664000175000017500000000016314673353434014530 0ustar frankfranktemplate void fswap(Type &lhs, Type &rhs) { FSwap::Xch::fswap(lhs, rhs); } bobcat-6.07.01/fswap/fswappod.f0000664000175000017500000000101414673353434015227 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-6.07.01/fswap/fswap.std.explicit.f0000664000175000017500000000077414673353434017151 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-6.07.01/fswap/fswap1.f0000664000175000017500000000103014673353434014603 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-6.07.01/fswap/tswap.f0000664000175000017500000000066014673353434014550 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-6.07.01/fswap/fswapfun.friends.f0000664000175000017500000000070014673353434016667 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-6.07.01/fswap/fswap.member.explicit.imp.f0000664000175000017500000000101214673353434020374 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-6.07.01/fswap/swapmode.f0000664000175000017500000000021414673353434015224 0ustar frankfrankstruct SwapMode { enum Enum { STDSWAP, SWAPMEMBER }; }; template struct ModeType {}; bobcat-6.07.01/fswap/fswap2.f0000664000175000017500000000063414673353434014615 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-6.07.01/fswap/fswapswap.f0000664000175000017500000000036014673353434015422 0ustar frankfranktemplate // how to swap this type? class FSwapSwap { Type &d_member; public: using type = Type; FSwapSwap(Type &member); Type &member(); }; FSwapSwap< #include "fswapswapimp.f" bobcat-6.07.01/fswap/fswap.member.explicit.f0000664000175000017500000000077014673353434017622 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-6.07.01/fswap/fswap3.f0000664000175000017500000000044014673353434014611 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-6.07.01/fswap/fswapbase.f0000664000175000017500000000166614673353434015374 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-6.07.01/fswap/fswap.end.f0000664000175000017500000000046414673353434015301 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-6.07.01/fswap/fswapfun.decl.f0000664000175000017500000000062714673353434016154 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-6.07.01/fswap/fswap.member.imp.f0000664000175000017500000000125714673353434016567 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) { using MemberType = typename std::remove_reference::type; 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-6.07.01/fswap/fswap.std.explicit.imp.f0000664000175000017500000000100114673353434017715 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-6.07.01/fswap/fswaptype.imp.f0000664000175000017500000000117414673353434016221 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-6.07.01/fswap/fswap0000664000175000017500000000272714673353434014314 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-6.07.01/fswap/fswap.member.f0000664000175000017500000000074314673353434016002 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-6.07.01/fswap/fswap5.f0000664000175000017500000000016014673353434014612 0ustar frankfranktemplate inline void FSwap::Xch::fswap(Tp &lhs, Tp &rhs) { tswap(lhs, rhs); } bobcat-6.07.01/fswap/fswaptype.f0000664000175000017500000000103514673353434015431 0ustar frankfranktemplate class FSwapMode { SwapMode::Enum d_mode; Type &d_member; public: using MemberType = Type; 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-6.07.01/fswap/driver/0000775000175000017500000000000014737552575014544 5ustar frankfrankbobcat-6.07.01/fswap/driver/driver.cc0000664000175000017500000000652114736770603016343 0ustar frankfrank#include #include 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-6.07.01/gethostent/0000775000175000017500000000000014736742656014315 5ustar frankfrankbobcat-6.07.01/gethostent/gethostent0000664000175000017500000000161314673353434016415 0ustar frankfrank#ifndef INCLUDED_BOBCAT_GETHOSTENT_ #define INCLUDED_BOBCAT_GETHOSTENT_ #include struct hostent; struct in_addr; struct sockaddr_in; #include 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-6.07.01/gethostent/solvename.cc0000664000175000017500000000072514673353434016611 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-6.07.01/gethostent/data.cc0000664000175000017500000000340114673353434015523 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-6.07.01/gethostent/addresstostring.cc0000664000175000017500000000036014673353434020032 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-6.07.01/gethostent/solveaddress.cc0000664000175000017500000000073114673353434017313 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-6.07.01/gethostent/icmconf0000664000175000017500000000010014673353434015635 0ustar frankfrank#define LIBRARY "gethostent" #include "../icmconf" bobcat-6.07.01/gethostent/hosterror.cc0000664000175000017500000000104114673353434016637 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-6.07.01/gethostent/gethostent.cc0000664000175000017500000000074614673353434017007 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-6.07.01/gethostent/gethostent.ih0000664000175000017500000000034314736315237017012 0ustar frankfrank#include "gethostent" #include #include #include #include #include #include #include "../pattern/pattern" using namespace std; using namespace FBB; bobcat-6.07.01/gethostent/driver/0000775000175000017500000000000014737552575015610 5ustar frankfrankbobcat-6.07.01/gethostent/driver/build0000775000175000017500000000014014673353434016620 0ustar frankfrank#!/bin/bash g++ `cat ../../c++std` -Wall -o driver driver.cc -L../tmp -lgethostent -lbobcat -s bobcat-6.07.01/gethostent/driver/driver.cc0000664000175000017500000000170414673353434017404 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-6.07.01/GITNOT/0000775000175000017500000000000014673353433013124 5ustar frankfrankbobcat-6.07.01/GITNOT/dstcorrection1.cc0000664000175000017500000000054414673353433016401 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-6.07.01/GITNOT/setseconds.cc0000664000175000017500000000023714673353433015607 0ustar frankfrank//#include "datetime.ih" // //bool DateTime::setSeconds(int seconds) //{ // TM ts = d_tm; // ts.tm_sec = seconds; // // return updateTime(ts); //} // bobcat-6.07.01/GITNOT/dtm2dtm.cc0000664000175000017500000000047114673353433015010 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-6.07.01/GITNOT/setdisplayzone.cc0000664000175000017500000000023114673353433016504 0ustar frankfrank//#include "datetime.ih" // //void DateTime::setDisplayZone(time_t displayZone) //{ // d_zone = (d_type == UTC) ? 0 : displayZone; //} // // // // // bobcat-6.07.01/GITNOT/utcsec2timestruct.cc0000664000175000017500000000046014673353433017127 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-6.07.01/GITNOT/updatetime.cc0000664000175000017500000000117214673353433015575 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-6.07.01/GITNOT/dtm2timetype.cc0000664000175000017500000000022714673353433016063 0ustar frankfrank//#include "datetime.ih" // //void DateTime::d_tm2timeType() //{ // d_tm.tm_isdst = 0; // d_tm2utcSec(); // // displayShift2d_tm(); // //} // bobcat-6.07.01/GITNOT/displayshift2dtm.cc0000664000175000017500000000055214673353433016727 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-6.07.01/GITNOT/dstcorrection2.cc0000664000175000017500000000052614673353433016402 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-6.07.01/GITNOT/setdst.cc0000664000175000017500000000021214673353433014734 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-6.07.01/GITNOT/parsetime.cc0000664000175000017500000000056714673353433015434 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-6.07.01/GITNOT/setyear.cc0000664000175000017500000000024114673353433015104 0ustar frankfrank//#include "datetime.ih" // //bool DateTime::setYear(size_t year) //{ // TM ts = d_tm; // ts.tm_year = year - 1900; // // return updateTime(ts); //} // bobcat-6.07.01/GITNOT/dtm2utcsec.cc0000664000175000017500000000022514673353433015507 0ustar frankfrank//#include "datetime.ih" // //void DateTime::d_tm2utcSec() //{ // d_time = timeStruct2utcSec(&d_tm); // d_time += defaultDisplayZone(); //} // bobcat-6.07.01/glob/0000775000175000017500000000000014736742656013054 5ustar frankfrankbobcat-6.07.01/glob/mend.f0000664000175000017500000000014414673353434014135 0ustar frankfrankinline char const **FBB::Glob::mend() const { return const_cast(d_share->end); } bobcat-6.07.01/glob/glob1.cc0000664000175000017500000000016514673353434014361 0ustar frankfrank#include "glob.ih" Glob::Glob(string const &pattern, int flags, Dots dots) : Glob(ANY, pattern, flags, dots) {} bobcat-6.07.01/glob/mbegin.f0000664000175000017500000000015014673353434014450 0ustar frankfrankinline char const **FBB::Glob::mbegin() const { return const_cast(d_share->begin); } bobcat-6.07.01/glob/glob5.cc0000664000175000017500000000126614673353434014370 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-6.07.01/glob/glob0000664000175000017500000000411414673353434013712 0ustar frankfrank#ifndef INCLUDED_BOBCAT_GLOB_ #define INCLUDED_BOBCAT_GLOB_ #include #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-6.07.01/glob/accept.cc0000664000175000017500000000135414673353434014615 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-6.07.01/glob/size.cc0000664000175000017500000000011414673353434014321 0ustar frankfrank#include "glob.ih" size_t Glob::size() const { return d_share->size; } bobcat-6.07.01/glob/isdot.cc0000664000175000017500000000024414673353434014475 0ustar frankfrank#include "glob.ih" namespace { string const dot("."); string const dot2(".."); } bool Glob::isDot(char const *cp) { return dot == cp || dot2 == cp; } bobcat-6.07.01/glob/operatorindex.cc0000664000175000017500000000017314673353434016237 0ustar frankfrank#include "glob.ih" char const *Glob::operator[](size_t idx) const { return idx < size() ? d_share->begin[idx] : ""; } bobcat-6.07.01/glob/operatorassign2.cc0000664000175000017500000000013314673353434016472 0ustar frankfrank#include "glob.ih" Glob &Glob::operator=(Glob &&tmp) { swap(tmp); return *this; } bobcat-6.07.01/glob/end.cc0000664000175000017500000000012614673353434014120 0ustar frankfrank#include "glob.ih" char const *const *Glob::end() const { return d_share->end; } bobcat-6.07.01/glob/glob2.cc0000664000175000017500000000021214673353434014353 0ustar frankfrank#include "glob.ih" Glob::Glob(Type type, string const &pattern, int flags, Dots dots) : Glob(fillSet(type), pattern, flags, dots) {} bobcat-6.07.01/glob/begin.cc0000664000175000017500000000013214673353434014433 0ustar frankfrank#include "glob.ih" char const *const *Glob::begin() const { return d_share->begin; } bobcat-6.07.01/glob/icmconf0000664000175000017500000000007214673353434014404 0ustar frankfrank#define LIBRARY "glob" #include "../icmconf" bobcat-6.07.01/glob/glob.ih0000664000175000017500000000057514736315237014317 0ustar frankfrank#include "glob" #include #include #include "../fswap/fswap" #include "../stat/stat" struct FBB::Glob::GlobShare { glob_t globStruct; size_t users; std::unordered_set gsType; char **begin; char **end; size_t size; }; #include "mbegin.f" #include "mend.f" using namespace std; using namespace FBB; bobcat-6.07.01/glob/destructor.cc0000664000175000017500000000036614673353434015556 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-6.07.01/glob/operatorassign.cc0000664000175000017500000000016714673353434016417 0ustar frankfrank#include "glob.ih" Glob &Glob::operator=(Glob const &other) { Glob tmp(other); swap(tmp); return *this; } bobcat-6.07.01/glob/swap.cc0000664000175000017500000000011614673353434014323 0ustar frankfrank#include "glob.ih" void Glob::swap(Glob &other) { fswap(*this, other); } bobcat-6.07.01/glob/fillset.cc0000664000175000017500000000103214673353434015011 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-6.07.01/glob/glob4.cc0000664000175000017500000000015114673353434014357 0ustar frankfrank#include "glob.ih" Glob::Glob(Glob const &other) { d_share = other.d_share; ++d_share->users; } bobcat-6.07.01/glob/glob3.cc0000664000175000017500000000013714673353434014362 0ustar frankfrank#include "glob.ih" Glob::Glob(Glob &&tmp) : d_share(tmp.d_share) { tmp.d_share = 0; } bobcat-6.07.01/glob/driver/0000775000175000017500000000000014737552575014347 5ustar frankfrankbobcat-6.07.01/glob/driver/build0000775000175000017500000000056414673353434015371 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-6.07.01/glob/driver/driver.cc0000664000175000017500000000265614673353434016152 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-6.07.01/glob/driver/main.ln0000777000175000017500000000000014673353434017044 2main.ccustar frankfrankbobcat-6.07.01/glob/driver/buildmain0000775000175000017500000000055314673353434016234 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-6.07.01/glob/driver/main.cc0000664000175000017500000000156414673353434015600 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-6.07.01/gs/0000775000175000017500000000000014673353434012532 5ustar frankfrankbobcat-6.07.01/gs/opbinor.f0000664000175000017500000000027114673353434014351 0ustar frankfrankinline GS__::Type operator|(GS__::Type lhs, GS__::Type rhs) { return static_cast( static_cast(lhs) | static_cast(rhs) ); } bobcat-6.07.01/gs/gs0000664000175000017500000000126414673353434013071 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-6.07.01/hash/0000775000175000017500000000000014673353434013044 5ustar frankfrankbobcat-6.07.01/hash/hashcharptr4.f0000664000175000017500000000026114673353434015605 0ustar frankfranktemplate inline HashCharPtr &HashCharPtr::operator=(HashCharPtr &&tmp) { static_cast(*this) = std::move(tmp); return *this; } bobcat-6.07.01/hash/hashstring1.f0000664000175000017500000000016314673353434015446 0ustar frankfranktemplate inline HashString::HashString(HashString &&tmp) : BaseClass(std::move(tmp)) {} bobcat-6.07.01/hash/opfun4.f0000664000175000017500000000015714673353434014431 0ustar frankfrankinline bool CharPtrEqual::operator()(char const *s1, char const *s2) const { return strcmp(s1, s2) == 0; } bobcat-6.07.01/hash/hashcharcaseptr2.f0000664000175000017500000000026414673353434016442 0ustar frankfranktemplate inline HashCharCasePtr::HashCharCasePtr( std::initializer_list iniValues) : BaseClass(iniValues) {} bobcat-6.07.01/hash/opfun1.f0000664000175000017500000000020014673353434014413 0ustar frankfrankinline size_t CaseHash::operator()(std::string const &key) const { return std::hash()(FBB::String::lc(key)); } bobcat-6.07.01/hash/hashstringcase3.f0000664000175000017500000000034214673353434016303 0ustar frankfranktemplate template inline HashStringCase::HashStringCase(InputIterator first, InputIterator beyond) : BaseClass(first, beyond) {} bobcat-6.07.01/hash/hashstring2.f0000664000175000017500000000031114673353434015442 0ustar frankfranktemplate inline HashString::HashString(std::initializer_list iniValues) : BaseClass(iniValues) {} bobcat-6.07.01/hash/hashstring4.f0000664000175000017500000000025614673353434015454 0ustar frankfranktemplate inline HashString &HashString::operator=(HashString &&tmp) { static_cast(*this) = std::move(tmp); return *this; } bobcat-6.07.01/hash/hashcharptr2.f0000664000175000017500000000031314673353434015601 0ustar frankfranktemplate inline HashCharPtr::HashCharPtr(std::initializer_list iniValues) : BaseClass(iniValues) {} bobcat-6.07.01/hash/opfun2.f0000664000175000017500000000016014673353434014421 0ustar frankfrankinline bool CaseEqual::operator()(char const *s1, char const *s2) const { return strcasecmp(s1, s2) == 0; } bobcat-6.07.01/hash/hashcharcaseptr1.f0000664000175000017500000000020214673353434016431 0ustar frankfranktemplate inline HashCharCasePtr::HashCharCasePtr(HashCharCasePtr &&tmp) : BaseClass(std::move(tmp)) {} bobcat-6.07.01/hash/hash0000664000175000017500000001112514673353434013712 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 > { using BaseClass = std::unordered_map< char const *, Value, std::hash, CharPtrEqual >; public: using value_type = typename BaseClass::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 > { using BaseClass = std::unordered_map; public: using value_type = typename BaseClass::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 { using BaseClass = std::unordered_map; public: using value_type = typename BaseClass::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 > { using BaseClass = std::unordered_map; public: using value_type = typename BaseClass::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-6.07.01/hash/hashstringcase2.f0000664000175000017500000000032114673353434016277 0ustar frankfranktemplate inline HashStringCase::HashStringCase(std::initializer_list iniValues) : BaseClass(iniValues) {} bobcat-6.07.01/hash/hashcharptr1.f0000664000175000017500000000016614673353434015606 0ustar frankfranktemplate inline HashCharPtr::HashCharPtr(HashCharPtr &&tmp) : BaseClass(std::move(tmp)) {} bobcat-6.07.01/hash/hashstring3.f0000664000175000017500000000032214673353434015445 0ustar frankfranktemplate template inline HashString::HashString(InputIterator first, InputIterator beyond) : BaseClass(first, beyond) {} bobcat-6.07.01/hash/hashstringcase4.f0000664000175000017500000000035314673353434016306 0ustar frankfranktemplate inline HashStringCase &HashStringCase::operator=( HashStringCase &&tmp) { static_cast(*this) = std::move(tmp); return *this; } bobcat-6.07.01/hash/opfun3.f0000664000175000017500000000026014673353434014423 0ustar frankfrankinline bool CaseEqual::operator()(std::string const &s1, std::string const &s2) const { return FBB::String::casecmp(s1, s2) == 0; } bobcat-6.07.01/hash/hashcharptr3.f0000664000175000017500000000033614673353434015607 0ustar frankfranktemplate template inline HashCharPtr::HashCharPtr(InputIterator first, InputIterator beyond) : BaseClass(first, beyond) {} bobcat-6.07.01/hash/hashstringcase1.f0000664000175000017500000000017714673353434016307 0ustar frankfranktemplate inline HashStringCase::HashStringCase(HashStringCase &&tmp) : BaseClass(std::move(tmp)) {} bobcat-6.07.01/hash/hashcharcaseptr4.f0000664000175000017500000000035614673353434016446 0ustar frankfranktemplate inline HashCharCasePtr &HashCharCasePtr::operator=( HashCharCasePtr &&tmp) { static_cast(*this) = std::move(tmp); return *this; } bobcat-6.07.01/hash/hashcharcaseptr3.f0000664000175000017500000000034614673353434016444 0ustar frankfranktemplate template inline HashCharCasePtr::HashCharCasePtr(InputIterator first, InputIterator beyond) : BaseClass(first, beyond) {} bobcat-6.07.01/hash/driver/0000775000175000017500000000000014737552575014347 5ustar frankfrankbobcat-6.07.01/hash/driver/driver.cc0000664000175000017500000000070114673353434016137 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-6.07.01/hash/driver/driver2.cc0000664000175000017500000000146614673353434016232 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-6.07.01/highresolutionclock/0000775000175000017500000000000014737167307016203 5ustar frankfrankbobcat-6.07.01/highresolutionclock/highresolutionclock0000664000175000017500000000152414737167307022207 0ustar frankfrank#ifndef INCLUDED_BOBCAT_HIGHRESOLUTIONCLOCK_ #define INCLUDED_BOBCAT_HIGHRESOLUTIONCLOCK_ #include namespace FBB { struct HighResolutionClock: public HighSysClock { using ChronoClock = std::chrono::high_resolution_clock; HighResolutionClock(TimePoint const &timePoint = now()); template HighResolutionClock(ClockBase const &clock); }; inline HighResolutionClock::HighResolutionClock(TimePoint const &timePoint) : HighSysClock(timePoint) {} template inline HighResolutionClock::HighResolutionClock( ClockBase const &clock) : HighSysClock(toClock(clock)) {} } // FBB #endif bobcat-6.07.01/highresolutionclock/highresolutionclock.ih0000664000175000017500000000004014736315237022572 0ustar frankfrank#include "highresolutionclock" bobcat-6.07.01/highsysclock/0000775000175000017500000000000014737165736014622 5ustar frankfrankbobcat-6.07.01/highsysclock/highsysclock0000664000175000017500000000250314737165561017233 0ustar frankfrank#ifndef INCLUDED_BOBCAT_HIGHSYSCLOCK_ #define INCLUDED_BOBCAT_HIGHSYSCLOCK_ #include namespace FBB { template class HighSysClock; template std::ostream &operator<<(std::ostream &out, HighSysClock const &clock); template class HighSysClock: public ClockBase { friend std::ostream &operator<< <>(std::ostream &out, // .f HighSysClock const &clock); mutable char const *d_putTime; // put_time config mutable bool d_localTime; // true: show local time public: using TimePoint = ClockBase::TimePoint; HighSysClock(TimePoint const &timePoint); std::time_t timeT() const; HighSysClock &setTimeT(std::time_t seconds); // .f HighSysClock const &operator()( char const *putTime, bool localTime = true) const; private: std::ostream &insert(std::ostream &out) const; // .f }; #include "highsysclock.f" } // FBB #endif bobcat-6.07.01/highsysclock/highsysclock.ih0000664000175000017500000000015214736315237017624 0ustar frankfrank#include "highsysclock" //#include "../xerr/xerr.ih" // //using namespace std; //using namespace FBB; // bobcat-6.07.01/highsysclock/highsysclock.f0000664000175000017500000000300014737165736017454 0ustar frankfranktemplate inline HighSysClock::HighSysClock(TimePoint const &timePoint) : ClockBase(timePoint), d_putTime(0), d_localTime(true) {} template inline std::time_t HighSysClock::timeT() const { // cf. Annotations 23.1.1 return ChronoClock::to_time_t(this->timePoint()); } template HighSysClock &HighSysClock::setTimeT( std::time_t secs) { ChronoClock::from_time_t(secs); return *this; } template HighSysClock const &HighSysClock::operator()( char const *putTime, bool localTime) const { d_putTime = putTime; d_localTime = localTime; return *this; } template std::ostream &HighSysClock::insert(std::ostream &out) const { if (d_putTime == 0) return out << static_cast>(*this); time_t tt = timeT(); tm *tmPtr = d_localTime ? std::localtime(&tt) : std::gmtime(&tt); out << std::put_time(tmPtr, d_putTime); d_putTime = 0; return out; } template inline std::ostream &operator<<(std::ostream &out, // .f HighSysClock const &clock) { return clock.insert(out); } bobcat-6.07.01/hmacbuf/0000775000175000017500000000000014736742656013536 5ustar frankfrankbobcat-6.07.01/hmacbuf/overflow.cc0000664000175000017500000000040714673353434015701 0ustar frankfrank#include "hmacbuf.ih" // override int HMacBuf::overflow(int ch) { EVP_MAC_update(d_ctx, ucharPtr(), bufSize()); setp(); // FBB::EoiBuf if (ch != EOF) { *pptr() = ch; pbump(1); } return ch; } bobcat-6.07.01/hmacbuf/hmacbuf0000664000175000017500000000254414673353434015063 0ustar frankfrank#ifndef INCLUDED_HMACBUF_ #define INCLUDED_HMACBUF_ #include #include #include #include namespace FBB { class HMacBuf: public EoiBuf { friend std::ostream &operator<<(std::ostream &out, HMacBuf const &hmacbuf); std::string d_key; std::string d_cipher; std::string d_digest; EVP_MAC_CTX *d_ctx = 0; public: HMacBuf() = default; HMacBuf(HMacBuf &&) = default; // uses cipher aes-128-cbc // 16-byte key for aes-128-cbc HMacBuf(std::string const &key, // 1 char const *digest, size_t bufsize = 1024); HMacBuf(std::string const &key, // 2 char const *cipher = "aes-128-cbc", char const *digest = "sha256", size_t bufSize = 1024); HMacBuf &operator=(HMacBuf &&rhs) = default; void reset(); std::string const &hash() const; private: int overflow(int c) override; void eoi_() override; void call(int retValue, char const *fName); // throws on failure }; std::ostream &operator<<(std::ostream &out, HMacBuf const &hmacbuf); } // FBB #endif bobcat-6.07.01/hmacbuf/reset.cc0000664000175000017500000000142714673353434015163 0ustar frankfrank#include "hmacbuf.ih" void HMacBuf::reset() { if (d_ctx != 0 or d_key.empty()) return; // man evp_mac_fetch: // MACs are a bit complex insofar that some of them use other algorithms // for actual computation. HMAC uses a digest, and CMAC uses a cipher. EVP_MAC *mac = EVP_MAC_fetch(0, "cmac", 0); OSSL_PARAM params[] = { OSSL_PARAM_construct_utf8_string("cipher", &d_cipher[0], 0), OSSL_PARAM_construct_utf8_string("digest", &d_digest[0], 0), OSSL_PARAM_construct_end() }; d_ctx = EVP_MAC_CTX_new(mac); call(EVP_MAC_init(d_ctx, reinterpret_cast(d_key.c_str()), d_key.length(), params), "init"); EVP_MAC_free(mac); d_digest.erase(); setp(); } bobcat-6.07.01/hmacbuf/hash.cc0000664000175000017500000000012414673353434014755 0ustar frankfrank#include "hmacbuf.ih" string const &HMacBuf::hash() const { return d_digest; } bobcat-6.07.01/hmacbuf/call.cc0000664000175000017500000000025614673353434014753 0ustar frankfrank#include "hmacbuf.ih" void HMacBuf::call(int retValue, char const *fName) { if (retValue != 1) throw Exception{} << "HMacBuf: EVP_MAC_" << fName << " failed"; } bobcat-6.07.01/hmacbuf/hmacbuf1.cc0000664000175000017500000000023214673353434015520 0ustar frankfrank#include "hmacbuf.ih" HMacBuf::HMacBuf(std::string const &key, char const *digest, size_t bufSize) : HMacBuf(key, "aes-128-cbc", digest, bufSize) {} bobcat-6.07.01/hmacbuf/icmconf0000664000175000017500000000044514673353434015072 0ustar frankfrank#define LIBRARY "hmacbuf" #include "../icmconf" //#undef CXXFLAGS //#define CXXFLAGS "--std=c++2a " ${AUXFLAGS} " -isystem " \ // " -fdiagnostics-color=never "\ // "/home/frank/git/bobcat/src/bobcat/tmp -Wall -O2" bobcat-6.07.01/hmacbuf/hmacbuf2.cc0000664000175000017500000000057114673353434015527 0ustar frankfrank#include "hmacbuf.ih" HMacBuf::HMacBuf(std::string const &key, char const *cipher, char const *digest, size_t bufSize) : EoiBuf(bufSize), d_key(key), d_cipher(cipher), d_digest(digest) { if (key.empty()) throw Exception{} << "HMacBuf non-default constructors require " "non-empty keys"; reset(); } bobcat-6.07.01/hmacbuf/operatorinsert.cc0000664000175000017500000000042314673353434017114 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-6.07.01/hmacbuf/eoi.cc0000664000175000017500000000177314673353434014621 0ustar frankfrank#include "hmacbuf.ih" // int EVP_MAC_final(EVP_MAC_CTX *ctx, // unsigned char *out, size_t *outl, size_t outsize); // EVP_MAC_final() does the final computation and stores the result in the // memory pointed at by out of size outsize, and sets the number of bytes // written in *outl at. If out is NULL or outsize is too small, then no // computation is made. // To figure out what the output length will be and allocate space for it // dynamically, simply call with out being NULL and outl pointing at a valid // location, then allocate space and make a second call with out pointing at // the allocated space. // override void HMacBuf::eoi_() { if (d_ctx == 0) return; call(EVP_MAC_update(d_ctx, ucharPtr(), pptr() - pbase()), "update"); size_t len; EVP_MAC_final(d_ctx, 0, &len, 0); // determine the req. length d_digest.resize(len); call(EVP_MAC_final(d_ctx, ucharPtr(d_digest), &len, len), "final"); EVP_MAC_CTX_free(d_ctx); d_ctx = 0; } bobcat-6.07.01/hmacbuf/hmacbuf.ih0000664000175000017500000000016114736457535015462 0ustar frankfrank#include "hmacbuf" #include #include "../ohexbuf/ohexbuf" using namespace std; using namespace FBB; bobcat-6.07.01/hmacbuf/driver/0000775000175000017500000000000014737552575015031 5ustar frankfrankbobcat-6.07.01/hmacbuf/driver/build0000775000175000017500000000152614673353434016052 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 LIBS=" -lbobcat -lcrypto" sed 's__"../hmacbuf"_' driver.cc > src.cc GPP="g++ `cat ../../c++std`" # Using the standard bobcat library CMD="$GPP -o driver -Wall driver.cc ${LIBS} -s" # Using the library in ../tmp/ CMD="$GPP -o driver -Wall src.cc -L../tmp -lhmacbuf ${LIBS} -s" # Using the library in ../tmp/ and bobcat as /tmp/libbob.a #CMD="$GPP -o driver -Wall src.cc -L../tmp -lhmacbuf -L /tmp -lbob -lcrypto -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 src.cc bobcat-6.07.01/hmacbuf/driver/driver.cc0000664000175000017500000000260414673353434016625 0ustar frankfrank#include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) try { // using the default (sha256) digest algorithm if (argc == 1) throw Exception{} << "Usage: arg1: 16-byte key, arg2: file to process,\n" " arg3 (opt) buf size (default 1024)"; HMacBuf hmacbuf{ argv[1], "aes-128-cbc", "sha256", argc == 3 ? 1024 : stoul(argv[3]) }; HMacBuf empty; // Demo: an empty HMacBuf empty = HMacBuf{ argv[1], "sha256", 100 }; // Demo: move assignmeent ostream out(&hmacbuf); // the ostream receiving the // input to compute the hmac of ifstream in{ argv[2] }; // the file to process out << in.rdbuf() << eoi; // compute the hmac // and show the hmac value cout << " computed hmac value: >" << hmacbuf << "<\n"; in.seekg(0); // to illustrate 'reset': do it hmacbuf.reset(); // again out << in.rdbuf(); eoi(out); // calling eoi as a function cout << "recomputed hmac value: >" << hmacbuf << "<\n"; } catch(exception const &err) { cout << err.what() << endl; return errno; } bobcat-6.07.01/hostent/0000775000175000017500000000000014736742656013615 5ustar frankfrankbobcat-6.07.01/hostent/dotteddecimaladdress.cc0000664000175000017500000000035214673353434020264 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-6.07.01/hostent/hostent.ih0000664000175000017500000000031214736315237015606 0ustar frankfrank#include "hostent" #include #include #include #include #include #include "../fswap/fswap" using namespace std; using namespace FBB; bobcat-6.07.01/hostent/addresslength.f0000664000175000017500000000010614673353434016600 0ustar frankfrankinline size_t Hostent::addressLength() const { return h_length; } bobcat-6.07.01/hostent/hostent0000664000175000017500000000425114673353434015216 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-6.07.01/hostent/countaliases.cc0000664000175000017500000000030014673353434016577 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-6.07.01/hostent/hostent1.f0000664000175000017500000000015214673353434015517 0ustar frankfrankinline Hostent::Hostent(Hostent const &other) { copy(&other, other.d_nAliases, other.d_nAddresses); } bobcat-6.07.01/hostent/naliases.f0000664000175000017500000000010714673353434015551 0ustar frankfrankinline size_t Hostent::nAliases() const { return d_nAliases - 1; } bobcat-6.07.01/hostent/beginalias.f0000664000175000017500000000012114673353434016044 0ustar frankfrankinline char const * const *Hostent::beginAlias() const { return h_aliases; } bobcat-6.07.01/hostent/hostname.f0000664000175000017500000000010414673353434015565 0ustar frankfrankinline char const *Hostent::hostname() const { return h_name; } bobcat-6.07.01/hostent/naddresses.f0000664000175000017500000000011314673353434016102 0ustar frankfrankinline size_t Hostent::nAddresses() const { return d_nAddresses - 1; } bobcat-6.07.01/hostent/xstrdup.cc0000664000175000017500000000025014673353434015622 0ustar frankfrank#include "hostent.ih" char *Hostent::xstrdup(char const *src) { return src ? strcpy(new char[1 + strlen(src)], src) : 0; } bobcat-6.07.01/hostent/icmconf0000664000175000017500000000007514673353434015150 0ustar frankfrank#define LIBRARY "hostent" #include "../icmconf" bobcat-6.07.01/hostent/binaryaddress.f0000664000175000017500000000016414673353434016607 0ustar frankfrankinline char const *Hostent::binaryAddress(size_t nr) const { return nr >= nAddresses() ? 0 : h_addr_list[nr]; } bobcat-6.07.01/hostent/endalias.f0000664000175000017500000000013414673353434015532 0ustar frankfrankinline char const * const *Hostent::endAlias() const { return h_aliases + nAliases(); } bobcat-6.07.01/hostent/hostent2.cc0000664000175000017500000000022514673353434015661 0ustar frankfrank#include "hostent.ih" Hostent::Hostent(Hostent &&tmp) { swap(tmp); tmp.h_name = 0; // prevent tmp's ~Hostent from deleting wild pointers } bobcat-6.07.01/hostent/destructor.f0000664000175000017500000000005614673353434016153 0ustar frankfrankinline Hostent::~Hostent() { destroy(); } bobcat-6.07.01/hostent/hostent3.cc0000664000175000017500000000027014673353434015662 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-6.07.01/hostent/countaddresses.cc0000664000175000017500000000063414673353434017145 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-6.07.01/hostent/operatorassign.cc0000664000175000017500000000020614673353434017152 0ustar frankfrank#include "hostent.ih" Hostent &Hostent::operator=(Hostent const &other) { Hostent tmp(other); swap(tmp); return *this; } bobcat-6.07.01/hostent/swap.cc0000664000175000017500000000012714673353434015066 0ustar frankfrank#include "hostent.ih" void Hostent::swap(Hostent &other) { fswap(*this, other); } bobcat-6.07.01/hostent/opis.f0000664000175000017500000000012714673353434014726 0ustar frankfrankinline Hostent &Hostent::operator=(Hostent &&tmp) { swap(tmp); return *this; } bobcat-6.07.01/hostent/destroy.cc0000664000175000017500000000053114673353434015604 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-6.07.01/hostent/hostent1.cc0000664000175000017500000000026514673353434015664 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-6.07.01/hostent/alias.f0000664000175000017500000000015014673353434015041 0ustar frankfrankinline char const *Hostent::alias(size_t nr) const { return nr >= d_nAliases ? 0 : h_aliases[nr]; } bobcat-6.07.01/hostent/addresstype.f0000664000175000017500000000010614673353434016300 0ustar frankfrankinline size_t Hostent::addressType() const { return h_addrtype; } bobcat-6.07.01/hostent/driver/0000775000175000017500000000000014737552575015110 5ustar frankfrankbobcat-6.07.01/hostent/driver/build0000775000175000017500000000045614673353434016132 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-6.07.01/hostent/driver/driver.cc0000664000175000017500000000130014673353434016674 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-6.07.01/hostent/copy.cc0000664000175000017500000000117214673353434015067 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-6.07.01/hostname/0000775000175000017500000000000014736742656013747 5ustar frankfrankbobcat-6.07.01/hostname/build0000775000175000017500000004241714673353434014774 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-6.07.01/hostname/hostname0000664000175000017500000000075214673353434015504 0ustar frankfrank#ifndef INCLUDED_BOBCAT_HOSTNAME_ #define INCLUDED_BOBCAT_HOSTNAME_ #include #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-6.07.01/hostname/hostname1.cc0000664000175000017500000000023614673353434016146 0ustar frankfrank#include "hostname.ih" Hostname::Hostname(string const &host) : Hostent(GetHostent::gethostent("Hostname::Hostname(std::string)", host)) { init(); } bobcat-6.07.01/hostname/init.cc0000664000175000017500000000026414673353434015213 0ustar frankfrank#include "hostname.ih" void Hostname::init() { if (addressType() != AF_INET) throw Exception{} << "Hostname::init(): no AF_INET address type found"; } bobcat-6.07.01/hostname/icmconf0000664000175000017500000000007614673353434015303 0ustar frankfrank#define LIBRARY "hostname" #include "../icmconf" bobcat-6.07.01/hostname/hostname.ih0000664000175000017500000000023714736315237016100 0ustar frankfrank#include "hostname" #include "../inetaddress/inetaddress" #include "../gethostent/gethostent" #include using namespace std; using namespace FBB; bobcat-6.07.01/hostname/hostname2.cc0000664000175000017500000000137114673353434016150 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-6.07.01/hostname/driver/0000775000175000017500000000000014737552575015242 5ustar frankfrankbobcat-6.07.01/hostname/driver/build0000775000175000017500000000045714673353434016265 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-6.07.01/hostname/driver/driver.cc0000664000175000017500000000166014673353434017037 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-6.07.01/ibase64buf/0000775000175000017500000000000014736520620014044 5ustar frankfrankbobcat-6.07.01/ibase64buf/ibase64buf.ih0000664000175000017500000000013014736315237016320 0ustar frankfrank#include "ibase64buf" using namespace std; using namespace FBB; using namespace IUO; bobcat-6.07.01/ibase64buf/ibase64buf0000664000175000017500000000105414673353434015730 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-6.07.01/ibase64buf/ibase64buf1.f0000664000175000017500000000017714673353434016242 0ustar frankfrankinline IBase64Buf::IBase64Buf(std::istream &in, size_t bufSize) : Base64BufBase(in, bufSize) { doEncrypt(); } bobcat-6.07.01/ibase64buf/ibase64buf2.f0000664000175000017500000000017714673353434016243 0ustar frankfrankinline IBase64Buf::IBase64Buf(std::istream &in, size_t bufSize) : Base64BufBase(in, bufSize) { doDecrypt(); } bobcat-6.07.01/ibase64buf/driver/0000775000175000017500000000000014737552575015356 5ustar frankfrankbobcat-6.07.01/ibase64buf/driver/build0000664000175000017500000000022314673353434016365 0ustar frankfrank#!/bin/bash # For development purposes: g++ `cat ../../c++std` -O2 -Wall -o driver -isystem ../../tmp driver.cc \ -L ../../tmp/lib/ -lbobcat bobcat-6.07.01/ibase64buf/driver/driver.cc0000664000175000017500000000164514673353434017156 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-6.07.01/ibase64stream/0000775000175000017500000000000014736767230014575 5ustar frankfrankbobcat-6.07.01/ibase64stream/ibase64stream.ih0000664000175000017500000000010614736315237017561 0ustar frankfrank#include "ibase64stream" using namespace std; using namespace FBB; bobcat-6.07.01/ibase64stream/ibase64stream0000664000175000017500000000055214736767230017173 0ustar frankfrank#ifndef INCLUDED_BOBCAT_IBASE64STREAM_ #define INCLUDED_BOBCAT_IBASE64STREAM_ #include #include 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-6.07.01/ibase64stream/ibase64stream1.f0000664000175000017500000000023614673353434017474 0ustar frankfranktemplate IBase64Stream::IBase64Stream(std::istream &in, size_t bufSize) : IBase64Buf(in, bufSize), std::istream(this) {} bobcat-6.07.01/ibase64stream/driver/0000775000175000017500000000000014737552575016075 5ustar frankfrankbobcat-6.07.01/ibase64stream/driver/driver.cc0000664000175000017500000000022414736770743017673 0ustar frankfrank#include #include using namespace std; using namespace FBB; int main() { IBase64Stream in(cin); } bobcat-6.07.01/icmake/0000775000175000017500000000000014737302502013341 5ustar frankfrankbobcat-6.07.01/icmake/installer0000775000175000017500000000050614673353434015276 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-6.07.01/icmake/libraries0000664000175000017500000001216214736514056015252 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; for (int idx = 0; idx != listlen(g_classes); ++idx) fprintf << "CLASSES.all" << g_classes[idx] << '\n'; run("icmake --spch -c CLASSES.all -n -l spch"); system("rm CLASSES.all"); run("icmake --spch --precompile=spch -u xerr/xerr.ih tmp/ " "'g++ -c -o $2 '${ICMAKE_CPPSTD}' -Itmp -O2 -x c++-header $1'"); run("icmake --spch -s spch tmp/"); // 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); // at this point the extra classes are // also in g_classes printf << "nclasses: " << g_nClasses << '\n'; md(g_tmpliba + " " + g_tmphdr + " " + g_tmplibso); _cpHeaders(); if (headersOnly) return; _precompileHeaders(); g_copt += " -isystem " + g_cwd + "tmp"; library("oa", staticLib); // compile for static lib. static_library(staticLib); // build static library #ifdef BUILD_SHARED // cf. INSTALL.im 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-6.07.01/icmake/findall0000664000175000017500000000107414673353434014710 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-6.07.01/icmake/log0000775000175000017500000000063014673353434014060 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-6.07.01/icmake/man0000664000175000017500000000275014736775423014062 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); printf << "\n\n"; 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("\n" "Building the man7 man-pages\n"); printf << "\n\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"); printf << "\n\n"; 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-6.07.01/icmake/library0000664000175000017500000001030314736464714014742 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; } void c_compile(string dstDir, int prefix, string srcDir, list cfiles) { fprintf << "tmp/jobs" << ": " << srcDir << ' ' << (srcDir + '/' + dstDir) << ' ' << prefix << '\n'; for (int idx = listlen(cfiles); idx--; ) fprintf << "tmp/jobs" << cfiles[idx] << '\n'; } 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"; if (!exists("tmp/jobs")) { for (int idx = g_nClasses; idx--; ) std_cpp(dstDir, idx, element(idx, g_classes), "../" + libname); } system("icmake -m -q tmp/jobs '" + g_cxx + ' ' + g_copt + " -c -o $2 '${ICMAKE_CPPSTD}' $1'"); } // #ifdef MULTICOMP // void c_compile(string dstDir, int prefix, string srcDir, list cfiles) // { // fprintf << "tmp/jobs" << ": " << srcDir << ' ' << // (srcDir + '/' + dstDir) << ' ' << prefix << '\n'; // // for (int idx = listlen(cfiles); idx--; ) // fprintf << "tmp/jobs" << cfiles[idx] << '\n'; // } // #else // // // 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); // } // } // #endif // // 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"; // // #ifdef MULTICOMP // if (!exists("tmp/jobs")) // #endif // for (int idx = g_nClasses; idx--; ) // std_cpp(dstDir, idx, element(idx, g_classes), "../" + libname); // // #ifdef MULTICOMP // system("icmake -m -q tmp/jobs '" + // g_cxx + ' ' + g_copt + " -c -o $2 '${ICMAKE_CPPSTD}' $1'"); // #endif // } // bobcat-6.07.01/icmake/clean0000664000175000017500000000071514673353434014362 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 spch release.yo */tmp */oa */os */o " "*/*.ih.gch"; } void clean() { setRemovals(); run("rm -rf " + remove1); run("rm -rf " + remove2); exit(0); } bobcat-6.07.01/icmake/uninstall0000664000175000017500000000044714673353434015313 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-6.07.01/icmake/cuteoln0000664000175000017500000000023314673353434014744 0ustar frankfrankstring cutEoln(string text) { int len; len = strlen(text) - 1; if (text[len] == "\n") text = substr(text, 0, len); return text; } bobcat-6.07.01/icmake/run0000664000175000017500000000015014673353434014075 0ustar frankfrankvoid run(string cmd) { if (g_echo == OFF) cmd += "> /dev/null 2>&1"; system(0, cmd); } bobcat-6.07.01/icmake/md0000664000175000017500000000073314673353434013700 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-6.07.01/icmake/gitlab0000664000175000017500000000035414673353434014541 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-6.07.01/icmake/remove0000775000175000017500000000116614673353434014601 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-6.07.01/icmake/backtick0000664000175000017500000000033714673353434015053 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-6.07.01/icmake/man10000664000175000017500000000056514673353434014137 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-6.07.01/icmake/getenv0000664000175000017500000000033314673353434014564 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-6.07.01/icmake/subset.sh0000775000175000017500000000046214673353434015220 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-6.07.01/icmake/addclasses0000664000175000017500000000050314736453043015376 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-6.07.01/icmake/install0000664000175000017500000000603514737302502014736 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"); run("ln -sf systemclock.3.html fileclock.3.html"); run("ln -sf systemclock.3.html highresolutionclock.3.html"); run("ln -sf systemclock.3.html steadyclock.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"); chdir(g_cwd + base + MAN "/man3"); run("ln -sf iterator.3bobcat.gz reverseiterator.3bobcat.gz"); run("ln -sf systemclock.3bobcat.gz fileclock.3bobcat.gz"); run("ln -sf systemclock.3bobcat.gz highresolutionclock.3bobcat.gz"); run("ln -sf systemclock.3bobcat.gz steadyclock.3bobcat.gz"); chdir(g_cwd); 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-6.07.01/icmake/loginstall0000664000175000017500000000155114673353434015447 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-6.07.01/icmake/logrecursive0000664000175000017500000000127314673353434016011 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-6.07.01/icmake/special0000664000175000017500000001425114736452477014727 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-6.07.01/icmake/logzip0000664000175000017500000000165314673353434014606 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-6.07.01/icmconf0000664000175000017500000000143714673353434013467 0ustar frankfrank// see also INSTALL.im for additional #defines #define MULTICOMP "jobs -q" #define USE_ECHO ON #define CLS #ifndef AUXFLAGS #define AUXFLAGS "" #endif #define CXX "g++" // Check INSTALL.im for 'build' compiler options #define CXXFLAGS ${AUXFLAGS} " -Wall -Werror -O2" \ " -fdiagnostics-color=never " // see pf_iterator/icmconf for an example using -system #define SOURCES "*.cc" #define TMP_DIR "tmp" #define OBJ_EXT ".o" #define DEFCOM "library" //////////////////////////////////////////////////////////////////////////// #define ADD_LIBRARIES "" #define ADD_LIBRARY_PATHS "" #define LDFLAGS "" #define MAIN "" bobcat-6.07.01/icmconf.lib0000664000175000017500000000113114736450742014223 0ustar frankfrank#define MULTICOMP "jobs -q" #define SPCH "-a spch tmp/" // #define CLS #define SOURCES "*.cc" #define OBJ_EXT ".o" #define TMP_DIR "tmp" #define USE_ECHO ON #define IH ".ih" #define CXX "ccache g++" #ifndef EXTRAFLAGS #define EXTRAFLAGS "" #endif #define CXXFLAGS " -Wall -Werror -O2 -I../tmp" \ " -fdiagnostics-color=never ${EXTRAFLAGS}" #define ADD_LIBRARIES "bobcat" #define ADD_LIBRARY_PATHS "" #define DEFCOM "library" bobcat-6.07.01/ifdbuf/0000775000175000017500000000000014736742656013370 5ustar frankfrankbobcat-6.07.01/ifdbuf/pxsgetn.f0000664000175000017500000000016514673353434015221 0ustar frankfrankinline std::streamsize IFdBuf::p_xsgetn(char *dest, std::streamsize size) { return IFdBuf::xsgetn(dest, size); } bobcat-6.07.01/ifdbuf/ifdbuf4.cc0000664000175000017500000000017214673353434015212 0ustar frankfrank#include "ifdbuf.ih" IFdBuf::IFdBuf(int fd, Mode mode, size_t size) : d_mode(mode) { reset(fd, KEEP_FD, size); } bobcat-6.07.01/ifdbuf/ifdbuf2.cc0000664000175000017500000000010614673353434015205 0ustar frankfrank#include "ifdbuf.ih" IFdBuf::IFdBuf(Mode mode) : d_mode(mode) {} bobcat-6.07.01/ifdbuf/ifdbuf3.cc0000664000175000017500000000022514673353434015210 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-6.07.01/ifdbuf/reset.cc0000664000175000017500000000025214673353434015010 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-6.07.01/ifdbuf/ifdbuf.ih0000664000175000017500000000027414736315237015143 0ustar frankfrank#include "ifdbuf" //#include //#define CERRX std::cerr << __FILE__": " #include #include #include using namespace FBB; using namespace std; bobcat-6.07.01/ifdbuf/mode.f0000664000175000017500000000010014673353434014442 0ustar frankfrankinline IFdBuf::Mode IFdBuf::mode() const { return d_mode; } bobcat-6.07.01/ifdbuf/xsgetn.cc0000664000175000017500000000136714673353434015206 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-6.07.01/ifdbuf/punderflow.f0000664000175000017500000000010514673353434015710 0ustar frankfrankinline int IFdBuf::p_underflow() { return IFdBuf::underflow(); } bobcat-6.07.01/ifdbuf/close.f0000664000175000017500000000006714673353434014637 0ustar frankfrankinline void IFdBuf::close() { cleanup(CLOSE_FD); } bobcat-6.07.01/ifdbuf/icmconf0000664000175000017500000000007414673353434014722 0ustar frankfrank#define LIBRARY "ifdbuf" #include "../icmconf" bobcat-6.07.01/ifdbuf/setfd.f0000664000175000017500000000006514673353434014635 0ustar frankfrankinline void IFdBuf::setFd(int fd) { d_fd = fd; } bobcat-6.07.01/ifdbuf/ifdbuf1.cc0000664000175000017500000000014414673353434015206 0ustar frankfrank#include "ifdbuf.ih" IFdBuf::IFdBuf() : d_mode(KEEP_FD) // comply with old default {} bobcat-6.07.01/ifdbuf/destructor.cc0000664000175000017500000000010114673353434016055 0ustar frankfrank#include "ifdbuf.ih" IFdBuf::~IFdBuf() { cleanup(d_mode); } bobcat-6.07.01/ifdbuf/fd.f0000664000175000017500000000006314673353434014117 0ustar frankfrankinline int IFdBuf::fd() const { return d_fd; } bobcat-6.07.01/ifdbuf/underflow.cc0000664000175000017500000000066614673353434015704 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-6.07.01/ifdbuf/cleanup.cc0000664000175000017500000000030214673353434015311 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-6.07.01/ifdbuf/reset.f0000664000175000017500000000012014673353434014642 0ustar frankfrankinline void IFdBuf::reset(int fd, size_t size) { reset(fd, d_mode, size); } bobcat-6.07.01/ifdbuf/ifdbuf0000664000175000017500000000403514673353434014544 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, // 0 KEEP_FD, // 1 }; 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 Mode mode() const; // .f protected: void cleanup(Mode mode); void setFd(int fd); // .f int p_underflow(); // .f std::streamsize p_xsgetn(char *dest, std::streamsize n); // .f private: int underflow() override; std::streamsize xsgetn(char *dest, std::streamsize n) override; }; #include "reset.f" #include "close.f" #include "fd.f" #include "mode.f" #include "setfd.f" #include "punderflow.f" #include "pxsgetn.f" } // FBB #endif bobcat-6.07.01/ifdbuf/driver/0000775000175000017500000000000014737552575014663 5ustar frankfrankbobcat-6.07.01/ifdbuf/driver/build0000775000175000017500000000057714673353434015711 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-6.07.01/ifdbuf/driver/driver.cc0000664000175000017500000000054614673353434016462 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-6.07.01/ifdbufs/0000775000175000017500000000000014736742656013553 5ustar frankfrankbobcat-6.07.01/ifdbufs/reset.cc0000664000175000017500000000037614673353434015202 0ustar frankfrank#include "ifdbufs.ih" void IFdBufS::reset(int fd, Mode mode, size_t size) { d_selector.addReadFd(fd); IFdBuf::reset(fd, mode, size); // cleanup(mode); // // d_fd = fd; // // resize(size == 0 ? 1 : size); // // setg(size, size); } bobcat-6.07.01/ifdbufs/ifdbufs0000664000175000017500000000223214673353434015107 0ustar frankfrank#ifndef INCLUDED_BOBCAT_IFDBUFS_ #define INCLUDED_BOBCAT_IFDBUFS_ #include #include namespace FBB { class IFdBufS: public IFdBuf //EoiBuf { Selector d_selector; // to wait for available input public: IFdBufS() = default; // 1 IFdBufS(IFdBufS const &other) = delete; explicit IFdBufS(Mode mode); // 2 explicit IFdBufS(int fd, size_t size = 1); // 3 IFdBufS(int fd, Mode mode, size_t size = 1); // 4 ~IFdBufS() override; // IFdBufS &operator=(IFdBufS 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-6.07.01/ifdbufs/xsgetn.cc0000664000175000017500000000062014673353434015360 0ustar frankfrank#include "ifdbufs.ih" std::streamsize IFdBufS::xsgetn(char *dest, std::streamsize size) { if (size == 0) return 0; d_selector.wait(); return p_xsgetn(dest, size); // // int avail = egptr() - gptr(); // // if (avail > size) // avail = size; // // memcpy(dest, gptr(), avail); // gbump(avail); // // return avail + read(fd(), dest + avail, size - avail); } bobcat-6.07.01/ifdbufs/ifdbufs4.cc0000664000175000017500000000030414673353434015555 0ustar frankfrank#include "ifdbufs.ih" IFdBufS::IFdBufS(int fdarg, Mode mode, size_t size) : IFdBuf(fdarg, mode, size) // d_mode(mode) { d_selector.addReadFd(fd()); //reset(fd, KEEP_FD, size); } bobcat-6.07.01/ifdbufs/close.f0000664000175000017500000000007014673353434015014 0ustar frankfrankinline void IFdBufS::close() { cleanup(CLOSE_FD); } bobcat-6.07.01/ifdbufs/ifdbufs2.cc0000664000175000017500000000013514673353434015555 0ustar frankfrank#include "ifdbufs.ih" IFdBufS::IFdBufS(Mode mode) : IFdBuf(mode) // d_mode(mode) {} bobcat-6.07.01/ifdbufs/ifdbufs3.cc0000664000175000017500000000025514673353434015561 0ustar frankfrank#include "ifdbufs.ih" IFdBufS::IFdBufS(int fd, size_t size) : IFdBuf(fd, size) // d_mode(KEEP_FD) { d_selector.addReadFd(fd); // reset(fd, KEEP_FD, size); } bobcat-6.07.01/ifdbufs/icmconf0000664000175000017500000000007514673353434015106 0ustar frankfrank#define LIBRARY "ifdbufs" #include "../icmconf" bobcat-6.07.01/ifdbufs/ifdbufs1.cc0000664000175000017500000000017414673353434015557 0ustar frankfrank//#include "ifdbufs.ih" // //IFdBufS::IFdBufS() //: // d_mode(KEEP_FD) // comply with old default //{} // // // bobcat-6.07.01/ifdbufs/destructor.cc0000664000175000017500000000010414673353434016243 0ustar frankfrank#include "ifdbufs.ih" IFdBufS::~IFdBufS() { cleanup(mode()); } bobcat-6.07.01/ifdbufs/fd.f0000664000175000017500000000006414673353434014303 0ustar frankfrankinline int IFdBufS::fd() const { return d_fd; } bobcat-6.07.01/ifdbufs/underflow.cc0000664000175000017500000000014614673353434016060 0ustar frankfrank#include "ifdbufs.ih" int IFdBufS::underflow() { d_selector.wait(); return p_underflow(); } bobcat-6.07.01/ifdbufs/cleanup.cc0000664000175000017500000000030014673353434015472 0ustar frankfrank#include "ifdbufs.ih" void IFdBufS::cleanup(Mode mode) { d_selector = Selector{}; if (fd() == -1) return; if (mode == CLOSE_FD) ::close(fd()); setFd(-1); } bobcat-6.07.01/ifdbufs/ifdbufs.ih0000664000175000017500000000027514736315237015512 0ustar frankfrank#include "ifdbufs" //#include //#define CERRX std::cerr << __FILE__": " #include #include #include using namespace FBB; using namespace std; bobcat-6.07.01/ifdbufs/reset.f0000664000175000017500000000012114673353434015026 0ustar frankfrankinline void IFdBufS::reset(int fd, size_t size) { reset(fd, mode(), size); } bobcat-6.07.01/ifdbufs/driver/0000775000175000017500000000000014737552575015046 5ustar frankfrankbobcat-6.07.01/ifdbufs/driver/build0000775000175000017500000000057714673353434016074 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-6.07.01/ifdbufs/driver/driver.cc0000664000175000017500000000054614673353434016645 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-6.07.01/ifdstream/0000775000175000017500000000000014673353434014077 5ustar frankfrankbobcat-6.07.01/ifdstream/ifdstream0000664000175000017500000000046514673353434016005 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-6.07.01/ifdstream/ifdstream1.f0000664000175000017500000000013514673353434016304 0ustar frankfrankinline IFdStream::IFdStream(int fd, size_t n) : IFdBuf(fd, n), std::istream(this) {} bobcat-6.07.01/ifdstreams/0000775000175000017500000000000014673353434014262 5ustar frankfrankbobcat-6.07.01/ifdstreams/ifdstreams0000664000175000017500000000047414673353434016353 0ustar frankfrank#ifndef INCLUDED_BOBCAT_IFDSTREAMS_ #define INCLUDED_BOBCAT_IFDSTREAMS_ #include #include namespace FBB { class IFdStreamS: private IFdBufS, public std::istream { public: explicit IFdStreamS(int fd, size_t n = 1); // 1.f }; #include "ifdstreams1.f" } // FBB #endif bobcat-6.07.01/ifdstreams/ifdstreams1.f0000664000175000017500000000014014673353434016646 0ustar frankfrankinline IFdStreamS::IFdStreamS(int fd, size_t n) : IFdBufS(fd, n), std::istream(this) {} bobcat-6.07.01/ifilterbuf/0000775000175000017500000000000014736742656014264 5ustar frankfrankbobcat-6.07.01/ifilterbuf/showmanyc.cc0000664000175000017500000000017714673353434016600 0ustar frankfrank#include "ifilterbuf.ih" std::streamsize IFilterBuf::showmanyc() { return (d_srcEnd - d_srcBegin) + (egptr() - gptr()); } bobcat-6.07.01/ifilterbuf/ifilterbuf0000664000175000017500000000124714673353434016336 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-6.07.01/ifilterbuf/pbackfail.cc0000664000175000017500000000066614673353434016507 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-6.07.01/ifilterbuf/ifilterbuf1.cc0000664000175000017500000000041114673353434016773 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-6.07.01/ifilterbuf/icmconf0000664000175000017500000000010014673353434015604 0ustar frankfrank#define LIBRARY "ifilterbuf" #include "../icmconf" bobcat-6.07.01/ifilterbuf/setbuffer.f0000664000175000017500000000007114673353434016406 0ustar frankfrankinline void IFilterBuf::setBuffer() { underflow(); } bobcat-6.07.01/ifilterbuf/destructor.cc0000664000175000017500000000006714673353434016764 0ustar frankfrank#include "ifilterbuf.ih" IFilterBuf::~IFilterBuf() {} bobcat-6.07.01/ifilterbuf/underflow.cc0000664000175000017500000000146214673353434016573 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-6.07.01/ifilterbuf/ifilterbuf.ih0000664000175000017500000000015314736315237016727 0ustar frankfrank#include "ifilterbuf" #include #include using namespace std; using namespace FBB; bobcat-6.07.01/ifilterbuf/driver/0000775000175000017500000000000014737552575015557 5ustar frankfrankbobcat-6.07.01/ifilterbuf/driver/build0000775000175000017500000000100414673353434016567 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 LIBS=" -lbobcat" GPP="g++ `cat ../../c++std`" # Using the standard bobcat library CMD="$GPP -o driver -Wall driver.cc ${LIBS} -s" # # 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-6.07.01/ifilterbuf/driver/driver.cc0000664000175000017500000000335414673353434017356 0ustar frankfrank#include #include #include #include #include using namespace std; using namespace FBB; class CharFilterStreambuf: public IFilterBuf { istream &d_in; // stream to read from string d_rmChars; // chars to rm string d_buffer; // locally buffered chars size_t const d_maxSize = 100; public: CharFilterStreambuf(istream &in, string const &rmChars); private: bool filter(char const **srcBegin, char const **srcEnd) override; }; CharFilterStreambuf::CharFilterStreambuf(istream &in, 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) != 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(int argc, char **argv) { if (argc == 1) { cout << "arg[1]: file to process, arg[2]: processed file\n"; return 0; } ifstream in{ argv[1] }; CharFilterStreambuf buf1(in, "1234567890"); istream in1(&buf1); CharFilterStreambuf buf2(in1, "AEIOUaeiou"); istream in2(&buf2); ofstream out{ argv[2] }; out << in2.rdbuf(); } bobcat-6.07.01/immapstream/0000775000175000017500000000000014736742656014450 5ustar frankfrankbobcat-6.07.01/immapstream/immapstream2.cc0000664000175000017500000000024114673353434017345 0ustar frankfrank#include "immapstream.ih" ImmapStream::ImmapStream(std::string const &fname, char const *bufSize) : MmapBuf(fname, bufSize, ios::in), istream(this) {} bobcat-6.07.01/immapstream/immapstream0000664000175000017500000000157014673353434016705 0ustar frankfrank#ifndef INCLUDED_BOBCAT_IMMAPSTREAM_ #define INCLUDED_BOBCAT_IMMAPSTREAM_ #include #include #include "../mmapbuf/mmapbuf" namespace FBB { struct ImmapStream: private MmapBuf, public std::istream { ImmapStream(); // 1 ImmapStream(std::string const &fname, char const *bufSize = 0); // 2 ImmapStream(ImmapStream &&tmp) = default; ImmapStream &operator=(ImmapStream &&tmp) = default; void open(std::string const &fname, char const *bufSize = 0); // 1 size_t bufSize() const; size_t fileSize() const; }; inline size_t ImmapStream::bufSize() const { return static_cast(*this).bufSize(); } inline size_t ImmapStream::fileSize() const { return static_cast(*this).fileSize(); } } // FBB #endif bobcat-6.07.01/immapstream/demo/0000775000175000017500000000000014673353434015364 5ustar frankfrankbobcat-6.07.01/immapstream/demo/build0000775000175000017500000000064614673353434016417 0ustar frankfrank#!/bin/bash # rm main.o if [ "main.cc" -nt "main.o" ] ; then g++ ${ICMAKE_CPPSTD} -c -Wall -fdiagnostics-color=never main.cc || exit 1 fi CMD="g++ ${ICMAKE_CPPSTD} -Wall -fdiagnostics-color=never main.o \ -L../tmp -L../../mmapbuf/tmp -limmapstream -lmmapbuf -lbobcat -s" # CMD="g++ ${ICMAKE_CPPSTD} -Wall main.cc ../*.o -lbobcat -s" # CMD="g++ ${ICMAKE_CPPSTD} -Wall main.cc -lbobcat -s" echo $CMD $CMD bobcat-6.07.01/immapstream/demo/in20000664000175000017500000000032214673353434015774 0ustar frankfrankl 1 o 5000 l 1 o 10000 l 1 o 0 l 1 o 11000 b q use with cat main.cc main.cc main.cc main.cc > big a.out big 1K < in2 | diff - out2 which should show no output and $? == 0 valgrind reports no errors bobcat-6.07.01/immapstream/demo/out20000664000175000017500000000167514673353434016211 0ustar frankfrank b - cp the file's rdbuf to cout c - clear the file f - file size g - get a single character fm the file, writing to cout l nr - insert nr lines from the file into cout o offset - seekg offset q - quit r nr - read nr chars from the file, writing them to cout t - tellg bufSize: 4096 fileSize: 11148 1? #include inserted 1 lines in OK: 1, at offset 19 2? in OK: 1, at offset 5000 3? value = in.gcount(); inserted 1 lines in OK: 1, at offset 5030 4? in OK: 1, at offset 10000 5? break; inserted 1 lines in OK: 1, at offset 10012 6? in OK: 1, at offset 0 7? #include inserted 1 lines in OK: 1, at offset 19 8? in OK: 1, at offset 11000 9? "in OK: " << in.good() << ", at offset " << value << '\n'; } } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } in OK: 1, at offset 11148 10? bobcat-6.07.01/immapstream/demo/main.cc0000664000175000017500000000534314673353434016624 0ustar frankfrank#include #include #include #include #include #include "../immapstream" using namespace std; namespace fs = filesystem; using namespace FBB; char usage[] = R"( b - cp the file's rdbuf to cout c - clear the file f - file size g - get a single character fm the file, writing to cout l nr - insert nr lines from the file into cout o offset - seekg offset q - quit r nr - read nr chars from the file, writing them to cout t - tellg )"; int main(int argc, char **argv) try { if (argc == 1) { cout << "1st argument: input file, 2nd arg (opt) mmap buf size\n"; return 1; } ImmapStream in(argv[1], argv[2]); cout << usage << "\n" "bufSize: " << in.bufSize() << "\n" "fileSize: " << in.fileSize() << '\n'; string line; size_t lineNr = 0; size_t value; while (true) { cout << '\n' << ++lineNr << "? "; getline(cin, line); switch (line.front()) { case 'b': cout << in.rdbuf(); break; case 'c': in.clear(); break; case 'g': cout << static_cast(in.get()) << '\n'; break; case 'l': { line.front() = ' '; size_t idx; for (idx = 0, value = stoul(line); idx != value; ++idx) { if (not getline(in, line)) break; cout << line << '\n'; } cout << "inserted " << idx << " lines\n"; } break; case 'o': line.front() = ' '; value = stoul(line); in.seekg(value); break; case 'q': cout.put('\n'); return 0; case 'r': line.front() = ' '; value = stoul(line); line.resize(value); in.read(&line.front(), value); value = in.gcount(); cout.write(&line.front(), value); cout << "\ngot " << value << " chars from " << argv[1] << '\n'; break; case 't': break; default: cout << "undefined input: `" << line << "'\n"; break; } value = in.tellg(); cout.clear(); cout << "in OK: " << in.good() << ", at offset " << value << '\n'; } } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } bobcat-6.07.01/immapstream/open2.cc0000664000175000017500000000021314673353434015766 0ustar frankfrank#include "immapstream.ih" void ImmapStream::open(string const &fname, char const *bufSize) { *this = ImmapStream{ fname, bufSize }; } bobcat-6.07.01/immapstream/icmconf0000664000175000017500000000010514673353434015775 0ustar frankfrank#define LIBRARY "immapstream" #include "../icmconf.lib" bobcat-6.07.01/immapstream/immapstream1.cc0000664000175000017500000000013414673353434017345 0ustar frankfrank#include "immapstream.ih" ImmapStream::ImmapStream() : MmapBuf(), istream(this) {} bobcat-6.07.01/immapstream/immapstream.ih0000664000175000017500000000010414736315237017273 0ustar frankfrank#include "immapstream" using namespace std; using namespace FBB; bobcat-6.07.01/indent/0000775000175000017500000000000014736742656013412 5ustar frankfrankbobcat-6.07.01/indent/dec.cc0000664000175000017500000000032314673353434014442 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-6.07.01/indent/data.cc0000664000175000017500000000011414673353434014616 0ustar frankfrank#include "indent.ih" size_t Indent::s_width = 0; size_t Indent::s_inc = 4; bobcat-6.07.01/indent/clear.f0000664000175000017500000000006114673353434014634 0ustar frankfrankinline void Indent::clear() { s_width = 0; } bobcat-6.07.01/indent/setwidth.f0000664000175000017500000000010414673353434015377 0ustar frankfrankinline void Indent::setWidth(size_t width) { s_width = width; } bobcat-6.07.01/indent/indent.cc0000664000175000017500000000022414673353434015170 0ustar frankfrank#include "indent.ih" ostream &FBB::indent(ostream &out) { if (Indent::s_width) out << setw(Indent::s_width) << ' '; return out; } bobcat-6.07.01/indent/inc.f0000664000175000017500000000006414673353434014322 0ustar frankfrankinline void Indent::inc() { s_width += s_inc; } bobcat-6.07.01/indent/decindent.cc0000664000175000017500000000015514673353434015647 0ustar frankfrank#include "indent.ih" ostream &FBB::decindent(ostream &out) { Indent::dec(); return out << indent; } bobcat-6.07.01/indent/indentdec.cc0000664000175000017500000000016714673353434015652 0ustar frankfrank#include "indent.ih" ostream &FBB::indentdec(ostream &out) { out << indent; Indent::dec(); return out; } bobcat-6.07.01/indent/nlindent.cc0000664000175000017500000000013414673353434015522 0ustar frankfrank#include "indent.ih" ostream &nlindent(ostream &out) { return out << '\n' << indent; } bobcat-6.07.01/indent/nlindent.f0000664000175000017500000000012714673353434015364 0ustar frankfrankinline std::ostream &nlindent(std::ostream &out) { return out << '\n' << indent; } bobcat-6.07.01/indent/setinc.f0000664000175000017500000000007414673353434015037 0ustar frankfrankinline void Indent::setInc(size_t inc) { s_inc = inc; } bobcat-6.07.01/indent/indentinc.cc0000664000175000017500000000016614673353434015667 0ustar frankfrank#include "indent.ih" ostream &FBB::indentinc(ostream &out) { out << indent; Indent::inc(); return out; } bobcat-6.07.01/indent/indent.ih0000664000175000017500000000012314736315237015200 0ustar frankfrank#include "indent" #include using namespace std; using namespace FBB; bobcat-6.07.01/indent/incindent.cc0000664000175000017500000000016714673353434015670 0ustar frankfrank#include "indent.ih" std::ostream &FBB::incindent(std::ostream &out) { Indent::inc(); return out << indent; } bobcat-6.07.01/indent/indent0000664000175000017500000000157014673353434014611 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-6.07.01/inetaddress/0000775000175000017500000000000014736742656014436 5ustar frankfrankbobcat-6.07.01/inetaddress/inetaddress2.f0000664000175000017500000000013014673353434017156 0ustar frankfrankinline InetAddress::InetAddress(sockaddr_in const &address) : d_address(address) {} bobcat-6.07.01/inetaddress/dotteddecimaladdress.cc0000664000175000017500000000027714673353434021113 0ustar frankfrank#include "inetaddress.ih" std::string InetAddress::dottedDecimalAddress() const { return GetHostent::addressToString("InetAddress::getAddress()", &d_address.sin_addr); } bobcat-6.07.01/inetaddress/sockaddrptr2.f0000664000175000017500000000014514673353434017177 0ustar frankfrankinline sockaddr *InetAddress::sockaddrPtr() { return reinterpret_cast(&d_address); } bobcat-6.07.01/inetaddress/inetaddress0000664000175000017500000000274514673353434016666 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-6.07.01/inetaddress/sockaddrptr1.f0000664000175000017500000000016714673353434017202 0ustar frankfrankinline sockaddr const *InetAddress::sockaddrPtr() const { return reinterpret_cast(&d_address); } bobcat-6.07.01/inetaddress/init.cc0000664000175000017500000000033514673353434015701 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-6.07.01/inetaddress/port.f0000664000175000017500000000012414673353434015556 0ustar frankfrankinline uint16_t InetAddress::port() const { return ntohs(d_address.sin_port); } bobcat-6.07.01/inetaddress/inetaddress.ih0000664000175000017500000000017414736315237017256 0ustar frankfrank#include "inetaddress" #include #include "../gethostent/gethostent" using namespace std; using namespace FBB; bobcat-6.07.01/inetaddress/inetaddress1.f0000664000175000017500000000011714673353434017162 0ustar frankfrankinline InetAddress::InetAddress(uint16_t port) { init(INADDR_ANY, port); } bobcat-6.07.01/inetaddress/sockaddrinptr1.f0000664000175000017500000000013114673353434017520 0ustar frankfrankinline sockaddr_in const *InetAddress::sockaddr_inPtr() const { return &d_address; } bobcat-6.07.01/inetaddress/size.f0000664000175000017500000000011214673353434015541 0ustar frankfrankinline size_t InetAddress::size() const { return sizeof(d_address); } bobcat-6.07.01/inetaddress/inetaddress1.cc0000664000175000017500000000041514673353434017323 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-6.07.01/inetaddress/sockaddrinptr2.f0000664000175000017500000000011514673353434017523 0ustar frankfrankinline sockaddr_in *InetAddress::sockaddr_inPtr() { return &d_address; } bobcat-6.07.01/inetaddress/driver/0000775000175000017500000000000014737552575015731 5ustar frankfrankbobcat-6.07.01/inetaddress/driver/build0000775000175000017500000000005414673353434016745 0ustar frankfrank#!/bin/sh g++ -o driver driver.cc -lbobcat bobcat-6.07.01/inetaddress/driver/driver.cc0000664000175000017500000000120114673353434017515 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-6.07.01/INSTALL0000664000175000017500000001205614673353433013155 0ustar frankfrankTo Install the bobcat library by hand instead of using the binary distribution perform the following steps: 0. To install bobcat icmake >= 12.01.00 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-6.07.01/INSTALL.im0000664000175000017500000000604714736472763013574 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 "-O2 -Wall -Werror -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/libbobcat6-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-6.07.01/iobuf/0000775000175000017500000000000014736742656013235 5ustar frankfrankbobcat-6.07.01/iobuf/pseekoff.cc0000664000175000017500000000067714673353434015350 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-6.07.01/iobuf/xsputn.cc0000664000175000017500000000020514673353434015072 0ustar frankfrank#include "iobuf.ih" std::streamsize IOBuf::xsputn(char const *buffer, streamsize n) { return d_out->write(buffer, n) ? n : 0; } bobcat-6.07.01/iobuf/overflow.cc0000664000175000017500000000021414673353434015374 0ustar frankfrank#include "iobuf.ih" int IOBuf::overflow(int c) { if (c == EOF) d_out->flush(); else d_out->put(c); return c; } bobcat-6.07.01/iobuf/iobuf0000664000175000017500000000302714673353434014256 0ustar frankfrank#ifndef INCLUDED_BOBCAT_IOBUF_ #define INCLUDED_BOBCAT_IOBUF_ #include #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-6.07.01/iobuf/iobuf.ih0000664000175000017500000000007614736315237014655 0ustar frankfrank#include "iobuf" using namespace std; using namespace FBB; bobcat-6.07.01/iobuf/reset.cc0000664000175000017500000000027414673353434014661 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-6.07.01/iobuf/iobuf2.f0000664000175000017500000000012114673353434014554 0ustar frankfrankinline IOBuf::IOBuf(std::istream &in, std::ostream &out) { reset(in, out); } bobcat-6.07.01/iobuf/pseekpos.f0000664000175000017500000000023714673353434015227 0ustar frankfrankinline IOBuf::pos_type IOBuf::pSeekpos(pos_type offset, std::ios::openmode mode) { return seekoff(offset, std::ios::beg, mode); } bobcat-6.07.01/iobuf/icmconf0000664000175000017500000000007314673353434014566 0ustar frankfrank#define LIBRARY "iobuf" #include "../icmconf" bobcat-6.07.01/iobuf/sync.cc0000664000175000017500000000013514673353434014507 0ustar frankfrank#include "iobuf.ih" int IOBuf::sync() { d_out->flush(); return not d_out->good(); } bobcat-6.07.01/iobuf/destructor.cc0000664000175000017500000000011014673353434015722 0ustar frankfrank#include "iobuf.ih" IOBuf::~IOBuf() { if (d_out) sync(); } bobcat-6.07.01/iobuf/seekoff.cc0000664000175000017500000000027714673353434015164 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-6.07.01/iobuf/iobuf1.f0000664000175000017500000000006514673353434014562 0ustar frankfrankinline IOBuf::IOBuf() : d_in(0), d_out(0) {} bobcat-6.07.01/iobuf/underflow.cc0000664000175000017500000000036214673353434015542 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-6.07.01/iobuf/seekpos.cc0000664000175000017500000000025314673353434015205 0ustar frankfrank#include "iobuf.ih" IOBuf::pos_type IOBuf::seekpos(pos_type offset, ios::openmode mode) { return pSeekpos(offset, mode); } bobcat-6.07.01/iomapbuf/0000775000175000017500000000000014736315237013722 5ustar frankfrankbobcat-6.07.01/iomapbuf/iomapbuf2.cc0000664000175000017500000000034014673353434016113 0ustar frankfrank#include "iomapbuf.ih" IOmapbuf::IOmapbuf(string const &fname, ios::openmode iosMode, char const *bufSize, mode_t mode) : MapBase(fname, iosMode, bufSize, mode) { setp(0, 0); setg(0, 0, 0); } bobcat-6.07.01/iomapbuf/opmvassign.cc0000664000175000017500000000026714673353434016425 0ustar frankfrank#include "iomapbuf.ih" IOmapbuf &IOmapbuf::operator=(IOmapbuf &&tmp) { moveAssign(move(tmp)); if (Omapbuf::load()) setg(begin(), next(), end()); return *this; } bobcat-6.07.01/iomapbuf/iomapbuf.ih0000664000175000017500000000013314736315237016043 0ustar frankfrank#include "../xerr/xerr.ih" #include "iomapbuf" using namespace std; using namespace FBB; bobcat-6.07.01/iomapbuf/demo/0000775000175000017500000000000014736311023014633 5ustar frankfrankbobcat-6.07.01/iomapbuf/demo/build0000775000175000017500000000031514673353434015673 0ustar frankfrank#!/bin/bash cd ../../mapbase icmbuild || exit 1 echo 1 cd ../imapbuf icmbuild || exit 1 echo 2 cd ../omapbuf icmbuild || exit 1 echo 3 cd ../iomapbuf icmbuild || exit 1 echo 4 cd demo icmbuild echo 5 bobcat-6.07.01/iomapbuf/demo/in0000664000175000017500000017771014673353434015215 0ustar frankfrank//#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } //#define XERR #include "main.ih" int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], ios::in | ios::out);//, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; xerr("START"); // io << "hello world" << endl; xerr("MID"); // io.seekg(0); // cout << io.tellg() << '\n'; xerr("END"); // out.seekp(20); string line; // getline(io, line); // cout << io.good() << ' ' << io.tellg() << '\n'; // cout << line << '\n'; // out << line << '\n'; //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': io << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; io.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } io.flush(); io.seekg(0); cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } bobcat-6.07.01/iomapbuf/demo/out0000664000175000017500000000003714673353434015401 0ustar frankfrank//#define XERR bobcat-6.07.01/iomapbuf/demo/icmconf0000664000175000017500000000173014736311023016175 0ustar frankfrank// see also ~/.icmake/icmconf.mod for a possible module-using icmconf // #define CLS #define MULTICOMP "jobs -q" //#define SPCH "-u xerr/xerr.ih" //#define USE_ALL "a" #define MAIN "main.cc" #define SOURCES "*.cc" #define OBJ_EXT ".o" #define TMP_DIR "tmp" #define USE_ECHO ON #define IH ".ih" #define CXX "g++" #define CXXFLAGS "-Wall -Werror -O2 -fdiagnostics-color=never" #define REFRESH #define LDFLAGS "-s" //#define ADD_LIBRARIES "omapbuf mapbase bobcat" //#define ADD_LIBRARY_PATHS "../../../mapbase/tmp " \ // " ../../../omapbuf/tmp" #define ADD_LIBRARIES "iomapbuf imapbuf omapbuf mapbase bobcat" #define ADD_LIBRARY_PATHS "../../tmp ../../../mapbase/tmp " \ "../../../imapbuf/tmp ../../../omapbuf/tmp" #define DEFCOM "program" bobcat-6.07.01/iomapbuf/demo/main.cc0000664000175000017500000001005514673353434016103 0ustar frankfrank#define XERR #include "main.ih" // arg 1: existing (input) file // arg 2: output file (maybe existing, if not existing: created) // actions: // b - write the input file using its rdbuf() member // c - clear the stream status // f - flush the buffer // l nr - write lines from the input file using << // o offset - to position offset // q - quit // r nr - read nr lines from the output file, writing to cout // w nr - write lines from the input file using write int main(int argc, char **argv) try { xerr("MAIN"); ifstream in{ argv[1] }; // Omapbuf buffer(argv[2], ios::in | ios::out); IOmapbuf buffer(argv[2], fs::exists(argv[2]) ? ios::in | ios::out : ios::in | ios::out | ios::trunc, "1K"); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file // ostream io{ &buffer }; iostream io{ &buffer }; string line; size_t value; while (true) { cout << "? "; getline(cin, line); switch (line.front()) { case 'b': io << in.rdbuf(); // block-wise insertion break; case 'c': io.clear(); break; case 'f': io << flush; break; case 'l': while (getline(in, line)) // line-wise insertion io << line << '\n'; break; case 'o': line.front() = ' '; value = stoul(line); io.seekp(value); //xerr("calling io.tellp"); cout << "at: " << io.tellp() << '\n'; //xerr("done calling io.tellp"); break; case 'q': return 0; case 'r': line.front() = ' '; for (value = stoul(line); value--; ) { if (not getline(io, line)) break; cout << line << '\n'; } break; case 'w': in.seekg(0); line.front() = ' '; for (value = stoul(line); value--; ) { if (not getline(in, line)) break; io << line << '\n'; } break; default: cout << "undefined: " << line << '\n'; break; } cout << io.good() << '\n'; } //return 0; // //xerr("START"); // //// io << "hello world" << endl; // //xerr("MID"); // //// io.seekg(0); //// cout << io.tellg() << '\n'; // //xerr("END"); // // //// out.seekp(20); // // string line; // //// getline(io, line); //// cout << io.good() << ' ' << io.tellg() << '\n'; // //// cout << line << '\n'; // // //// out << line << '\n'; // ////return 0; // // // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) // switch (argc == 4 ? *argv[3] : 'r') // { // case 'r': // io << in.rdbuf(); // block-wise insertion // break; // // case 'l': // while (getline(in, line)) // line-wise insertion // io << line << '\n'; // break; // // case 'w': // while (getline(in, line)) // raw writes // { // line += '\n'; // io.write(line.c_str(), line.length()); // } // break; // // default: // cout << "in out [l(ine), r(rdbuf), w(write)]\n"; // break; // } // // io.flush(); // // io.seekg(0); // cout << io.rdbuf(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } bobcat-6.07.01/iomapbuf/demo/main.ih0000664000175000017500000000032014673353434016110 0ustar frankfrank#include "../../xerr/xerr.ih" #include #include #include #include #include "../iomapbuf" using namespace std; using namespace FBB; namespace fs = filesystem; bobcat-6.07.01/iomapbuf/icmconf0000664000175000017500000000010214673353434015255 0ustar frankfrank#define LIBRARY "iomapbuf" #include "../icmconf.lib" bobcat-6.07.01/iomapbuf/destructor.cc0000664000175000017500000000007614673353434016433 0ustar frankfrank#include "iomapbuf.ih" // overrides IOmapbuf::~IOmapbuf() {} bobcat-6.07.01/iomapbuf/seekoff.cc0000664000175000017500000000145214673353434015656 0ustar frankfrank#define XERR #include "iomapbuf.ih" ios::pos_type IOmapbuf::seekoff(ios::off_type pos, ios::seekdir where, ios::openmode mode) { pos = Omapbuf::seekoff(pos, where, mode); //xerr("IOMapBuf " << pos); if (pos == -1 or pbase() == 0) // invalid pos or no buffer { //xerr("seekoff returns: " << pos); return pos; // then simply return pos } //xerr("Next: " << (void *)pbase()); size_t newPos = pos; gbump( // abspos is outside of the buffer ? newPos < offset() or offset() + mapLength() <= newPos ? egptr() - gptr() // then the buffer is exhausted : // or reset gptr() newPos - offset() - (gptr() - eback()) ); return pos; } bobcat-6.07.01/iomapbuf/iomapbuf0000664000175000017500000000171714673353434015456 0ustar frankfrank#ifndef INCLUDED_BOBCAT_IOMAPBUF_ #define INCLUDED_BOBCAT_IOMAPBUF_ #include "../imapbuf/imapbuf" #include "../omapbuf/omapbuf" namespace FBB { class IOmapbuf: public Imapbuf, public Omapbuf { public: IOmapbuf() = default; IOmapbuf(std::string const &fname, // 2.cc IOS::openmode iosMode = IOS::out, char const *bufSize = 0, mode_t mode = 0644); ~IOmapbuf() override; IOmapbuf &operator=(IOmapbuf &&tmp); protected: IOS::pos_type seekpos(IOS::pos_type offset, IOS::openmode mode = IOS::in | IOS::out) override; IOS::pos_type seekoff(IOS::off_type pos, IOS::seekdir where, IOS::openmode mode = IOS::in | IOS::out) override; }; } // FBB #endif bobcat-6.07.01/iomapbuf/seekpos.cc0000664000175000017500000000022714673353434015704 0ustar frankfrank#include "iomapbuf.ih" std::ios::pos_type IOmapbuf::seekpos(ios::pos_type offset, ios::openmode mode) { return seekoff(offset, ios::beg, mode); } bobcat-6.07.01/iommapstream/0000775000175000017500000000000014736767370014627 5ustar frankfrankbobcat-6.07.01/iommapstream/iommapstream0000664000175000017500000000210314736767370017244 0ustar frankfrank#ifndef INCLUDED_BOBCAT_IOMMAPSTREAM_ #define INCLUDED_BOBCAT_IOMMAPSTREAM_ #include #include #include namespace FBB { struct IOmmapStream: private MmapBuf, public std::iostream { IOmmapStream(); // 1 IOmmapStream(std::string const &fname, char const *bufSize = 0, // 2 IOS::openmode openMode = IOS::in | IOS::out, mode_t mode = 0644); IOmmapStream(IOmmapStream &&tmp) = default; IOmmapStream &operator=(IOmmapStream &&tmp) = default; void open(std::string const &fname, char const *bufSize = 0, // 1 IOS::openmode openMode = IOS::in | IOS::out, mode_t mode = 0644); size_t bufSize() const; size_t fileSize() const; }; inline size_t IOmmapStream::bufSize() const { return static_cast(*this).bufSize(); } inline size_t IOmmapStream::fileSize() const { return static_cast(*this).fileSize(); } } // FBB #endif bobcat-6.07.01/iommapstream/iommapstream1.cc0000664000175000017500000000014014673353434017700 0ustar frankfrank#include "iommapstream.ih" IOmmapStream::IOmmapStream() : MmapBuf(), iostream(this) {} bobcat-6.07.01/iommapstream/iommapstream.ih0000664000175000017500000000010514736315237017632 0ustar frankfrank#include "iommapstream" using namespace std; using namespace FBB; bobcat-6.07.01/iommapstream/demo/0000775000175000017500000000000014673353434015543 5ustar frankfrankbobcat-6.07.01/iommapstream/demo/build0000775000175000017500000000064714673353434016577 0ustar frankfrank#!/bin/bash # rm main.o if [ "main.cc" -nt "main.o" ] ; then g++ ${ICMAKE_CPPSTD} -c -Wall -fdiagnostics-color=never main.cc || exit 1 fi CMD="g++ ${ICMAKE_CPPSTD} -Wall -fdiagnostics-color=never main.o \ -L../tmp -L../../mmapbuf/tmp -liommapstream -lmmapbuf -lbobcat -s" # CMD="g++ ${ICMAKE_CPPSTD} -Wall main.cc ../*.o -lbobcat -s" # CMD="g++ ${ICMAKE_CPPSTD} -Wall main.cc -lbobcat -s" echo $CMD $CMD bobcat-6.07.01/iommapstream/demo/main.cc0000664000175000017500000000764714673353434017014 0ustar frankfrank#define XERR #include #include #include #include #include #include "../iommapstream" using namespace std; namespace fs = filesystem; using namespace FBB; char usage[] = R"( 1 offset - seekg offset on the 1st file 2 offset - seekp/seekg offset on the 2nd file b - insert the 1st file's rdbuf into the 2nd file c - clear the files e nr - extract nr lines from the 2nd file into cout f - 2nd file's size l nr - insert nr lines from the 1st file into the 2nd file p - put a single character fm the 1st file into the 2nd file q - quit s - sync the 2nd file t - 2nd file's tellp w nr - write nr chars from the 1st file to the 2nd file )"; int main(int argc, char **argv) try { if (argc == 1) { cout << "1st argument: input file, 2nd arg: output file, " "3rd opt. arg: buf size\n"; return 1; } ifstream in(argv[1]); IOmmapStream out{ argv[2], argv[3], fs::exists(argv[2]) ? ios::in | ios::out : ios::out }; // if (argc <= 3) // cout << usage << "\n" cout << "bufSize: " << out.bufSize() << "\n" "fileSize: " << out.fileSize() << '\n'; string line; size_t lineNr = 0; size_t value = 0; while (true) { cout << '\n' << ++lineNr << "? "; getline(cin, line); switch (line.front()) { case 'b': out << in.rdbuf(); break; case 'c': in.clear(); out.clear(); break; case 'e': { line.front() = ' '; size_t idx; for (idx = 0, value = stoul(line); idx != value; ++idx) { if (not getline(out, line)) break; cout << line << '\n'; } cout << "\nextracted " << idx << " lines\n"; } break; case 'f': cout << out.fileSize() << '\n'; break; case 'l': { line.front() = ' '; size_t idx; for (idx = 0, value = stoul(line); idx != value; ++idx) { if (not getline(in, line)) break; out << line << '\n'; } cout << "inserted " << idx << " lines\n"; } break; case '1': line.front() = ' '; value = stoul(line); in.seekg(value); break; case '2': line.front() = ' '; value = stoul(line); out.seekp(value); break; case 'p': out << static_cast(in.get()); break; case 'q': cout.put('\n'); return 0; case 's': out.flush(); break; case 't': break; case 'w': line.front() = ' '; value = stoul(line); line.resize(value); in.read(&line.front(), value); value = in.gcount(); out.write(&line.front(), value); cout << "\nwrote " << value << " chars from " << argv[1] << " to " << argv[2] << '\n'; break; default: cout << "undefined input: `" << line << "'\n"; break; } value = out.tellp(); cout << "in OK: " << in.good() << ", out OK: " << out.good() << ", at " << value << '\n'; } } catch (exception const &exc) { cout << exc.what() << '\n'; return 1; } bobcat-6.07.01/iommapstream/open2.cc0000664000175000017500000000033214673353434016147 0ustar frankfrank#include "iommapstream.ih" void IOmmapStream::open(string const &fname, char const *bufSize, IOS::openmode openMode, mode_t mode) { *this = IOmmapStream{ fname, bufSize, openMode, mode }; } bobcat-6.07.01/iommapstream/icmconf0000664000175000017500000000010614673353434016155 0ustar frankfrank#define LIBRARY "iommapstream" #include "../icmconf.lib" bobcat-6.07.01/iommapstream/iommapstream2.cc0000664000175000017500000000034514673353434017710 0ustar frankfrank#include "iommapstream.ih" IOmmapStream::IOmmapStream(string const &fname, char const *bufSize, IOS::openmode openMode, mode_t mode) : MmapBuf(fname, bufSize, openMode, mode), iostream(this) {} bobcat-6.07.01/iostream/0000775000175000017500000000000014736742656013754 5ustar frankfrankbobcat-6.07.01/iostream/iostream2.f0000664000175000017500000000020714673353434016017 0ustar frankfrankinline IOStream::IOStream(std::istream &in, std::ostream &out) : std::istream(this), std::ostream(this) { open(in, out); } bobcat-6.07.01/iostream/clear1.cc0000664000175000017500000000013714673353434015423 0ustar frankfrank#include "iostream.ih" void IOStream::clear() { istream::clear(); ostream::clear(); } bobcat-6.07.01/iostream/iostream.ih0000664000175000017500000000010114736315237016100 0ustar frankfrank#include "iostream" using namespace std; using namespace FBB; bobcat-6.07.01/iostream/iostream1.f0000664000175000017500000000012014673353434016010 0ustar frankfrankinline IOStream::IOStream() : std::istream(this), std::ostream(this) {} bobcat-6.07.01/iostream/icmconf0000664000175000017500000000013314673353434015302 0ustar frankfrank#define LIBRARY "iostream" #define AUXFLAGS "-I../tmp" #include "../icmconf" bobcat-6.07.01/iostream/open.f0000664000175000017500000000013714673353434015055 0ustar frankfrankinline void IOStream::open(std::istream &in, std::ostream &out) { IOBuf::reset(in, out); } bobcat-6.07.01/iostream/iostream0000664000175000017500000000100414673353434015505 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-6.07.01/iquotedprintablebuf/0000775000175000017500000000000014736520620016162 5ustar frankfrankbobcat-6.07.01/iquotedprintablebuf/iquotedprintablebuf0000664000175000017500000000170014673353434022162 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-6.07.01/iquotedprintablebuf/iquotedprintablebuf1.f0000664000175000017500000000023114673353434022465 0ustar frankfrankinline IQuotedPrintableBuf::IQuotedPrintableBuf( std::istream &in, size_t bufSize) : QPBufBase(in, bufSize) { doEncode(); } bobcat-6.07.01/iquotedprintablebuf/iquotedprintablebuf2.f0000664000175000017500000000023114673353434022466 0ustar frankfrankinline IQuotedPrintableBuf::IQuotedPrintableBuf( std::istream &in, size_t bufSize) : QPBufBase(in, bufSize) { doDecode(); } bobcat-6.07.01/iquotedprintablebuf/iquotedprintablebuf.ih0000664000175000017500000000014114736315237022556 0ustar frankfrank#include "iquotedprintablebuf" using namespace std; using namespace FBB; using namespace IUO; bobcat-6.07.01/iquotedprintablebuf/driver/0000775000175000017500000000000014737552575017474 5ustar frankfrankbobcat-6.07.01/iquotedprintablebuf/driver/build0000775000175000017500000000106714673353434020515 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-6.07.01/iquotedprintablebuf/driver/driver.cc0000664000175000017500000000174514673353434021275 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-6.07.01/iquotedprintablebuf/driver/bobcat/0000775000175000017500000000000014673353434020716 5ustar frankfrankbobcat-6.07.01/iquotedprintablebuf/driver/bobcat/qpstreambufbase0000777000175000017500000000000014673353434033154 2../../../qpstreambufbase/qpstreambufbaseustar frankfrankbobcat-6.07.01/iquotedprintablebuf/driver/bobcat/iquotedprintablestreambuf1.f0000777000175000017500000000000014673353434034567 2../../iquotedprintablestreambuf1.fustar frankfrankbobcat-6.07.01/iquotedprintablebuf/driver/bobcat/iquotedprintablestreambuf0000777000175000017500000000000014673353434033755 2../../iquotedprintablestreambufustar frankfrankbobcat-6.07.01/iquotedprintablebuf/driver/bobcat/iquotedprintablestreambuf2.f0000777000175000017500000000000014673353434034571 2../../iquotedprintablestreambuf2.fustar frankfrankbobcat-6.07.01/iquotedprintablestream/0000775000175000017500000000000014736520620016701 5ustar frankfrankbobcat-6.07.01/iquotedprintablestream/iquotedprintablestream1.f0000664000175000017500000000035614673353434023733 0ustar frankfranktemplate IQuotedPrintableStream::IQuotedPrintableStream(std::istream &in, size_t bufSize) : IQuotedPrintableBuf(in, bufSize), std::istream(this) {} bobcat-6.07.01/iquotedprintablestream/iquotedprintablestream0000664000175000017500000000070714673353434023426 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-6.07.01/iquotedprintablestream/iquotedprintablestream.ih0000664000175000017500000000011714736315237024017 0ustar frankfrank#include "iquotedprintablestream" using namespace std; using namespace FBB; bobcat-6.07.01/iquotedprintablestream/driver/0000775000175000017500000000000014737552575020213 5ustar frankfrankbobcat-6.07.01/iquotedprintablestream/driver/driver.cc0000664000175000017500000000042414673353434022005 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-6.07.01/irandstream/0000775000175000017500000000000014673353434014432 5ustar frankfrankbobcat-6.07.01/irandstream/irandstream1.f0000664000175000017500000000013514673353434017172 0ustar frankfrankinline IRandStream::IRandStream(int max) : RandBuf(1, max, 1), std::istream(this) {} bobcat-6.07.01/irandstream/irandstream3.f0000664000175000017500000000017014673353434017173 0ustar frankfrankinline IRandStream::IRandStream(int min, int max, size_t seed) : RandBuf(min, max, seed), std::istream(this) {} bobcat-6.07.01/irandstream/irandstream2.f0000664000175000017500000000015014673353434017170 0ustar frankfrankinline IRandStream::IRandStream(int min, int max) : RandBuf(min, max, 1), std::istream(this) {} bobcat-6.07.01/irandstream/irandstream0000664000175000017500000000067214673353434016673 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-6.07.01/irandstream/driver/0000775000175000017500000000000014737552575015735 5ustar frankfrankbobcat-6.07.01/irandstream/driver/build0000775000175000017500000000043314673353434016752 0ustar frankfrank#!/bin/bash GCC="g++ `cat ../../c++std` -o driver" # # Using the standard bobcat library # ${GCC} driver.cc -lbobcat # Using the randbuf library, and bobcat echo ${GCC} driver.cc -L../../randbuf/tmp -lrandbuf -lbobcat -s ${GCC} driver.cc -L../../randbuf/tmp -lrandbuf -lbobcat -s bobcat-6.07.01/irandstream/driver/driver.cc0000664000175000017500000000117514673353434017533 0ustar frankfrank#include #include using namespace std; using namespace FBB; int main(int argc, char **argv) { if (argc == 1) cout << "\n" "Showing one random value between 1 and 1000 (inclusive).\n" "If you want more values specify the requested number of\n" "values as the program's first argument\n" "On repeated calls the same numbers are generated\n\n"; IRandStream in(1000); for (size_t count = argc == 1? 1 : stoul(argv[1]); count--; ) { size_t random; in >> random; cout << random << endl; } } bobcat-6.07.01/isharedstream/0000775000175000017500000000000014736742656014764 5ustar frankfrankbobcat-6.07.01/isharedstream/isharedstream0000664000175000017500000000211214673353434017526 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-6.07.01/isharedstream/truncate.f0000664000175000017500000000015414673353434016750 0ustar frankfrankinline bool ISharedStream::truncate(std::streamsize offset) { return sharedMemory().truncate(offset); } bobcat-6.07.01/isharedstream/isharedstream.ih0000664000175000017500000000010614736315237020125 0ustar frankfrank#include "isharedstream" using namespace std; using namespace FBB; bobcat-6.07.01/isharedstream/open2.cc0000664000175000017500000000025014673353434016303 0ustar frankfrank#include "isharedstream.ih" void ISharedStream::open(int id, std::ios::openmode openMode) { setMemory(SharedMemory(id)); setOpenMode(openMode); clear(); } bobcat-6.07.01/isharedstream/isharedstream1.cc0000664000175000017500000000012314673353434020173 0ustar frankfrank#include "isharedstream.ih" ISharedStream::ISharedStream() : istream(this) {} bobcat-6.07.01/isharedstream/icmconf0000664000175000017500000000010314673353434016307 0ustar frankfrank#define LIBRARY "sharedsegment" #include "../icmconf" bobcat-6.07.01/isharedstream/open1.cc0000664000175000017500000000041214673353434016302 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-6.07.01/isharedstream/isharedstream3.cc0000664000175000017500000000022614673353434020201 0ustar frankfrank#include "isharedstream.ih" ISharedStream::ISharedStream(size_t id, std::ios::openmode openMode) : SharedBuf(id, openMode), istream(this) {} bobcat-6.07.01/isharedstream/isharedstream2.cc0000664000175000017500000000040314673353434020175 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-6.07.01/isharedstream/meminfo.cc0000664000175000017500000000025714673353434016721 0ustar frankfrank#include "isharedstream.ih" void ISharedStream::memInfo(std::ostream &out, char const *end) const { static_cast(this)->memInfo(out); out << end; } bobcat-6.07.01/isymcryptbase/0000775000175000017500000000000014736742656015027 5ustar frankfrankbobcat-6.07.01/isymcryptbase/evpupdate.cc0000664000175000017500000000077714673353434017336 0ustar frankfrank#include "isymcryptbase.ih" bool ISymCryptBase::evpUpdate(size_t inBufRead) { checkOutBufSize(inBufRead); int nOutputChars; if (not ((*d_evpUpdate)( // en/decrypt the bytes in d_inBuf ctx(), uOutBuf(), &nOutputChars, reinterpret_cast(d_inBuf.get()), inBufRead )) ) throw Exception{} << "EVP_{En,De}cryptUpdate failed"; setg(outBuf(), outBuf(), outBuf() + nOutputChars); return nOutputChars != 0; } bobcat-6.07.01/isymcryptbase/isymcryptbase.ih0000664000175000017500000000015514736315237020237 0ustar frankfrank#include "isymcryptbase" #include using namespace std; using namespace FBB; using namespace IUO; bobcat-6.07.01/isymcryptbase/isymcryptbase1.cc0000664000175000017500000000161214673353434020305 0ustar frankfrank#include "isymcryptbase.ih" ISymCryptBase::ISymCryptBase( istream &inStream, string const &cipherName, string const &key, string const &iv, size_t inBufSize, OSSL_PARAM const *params, int (*evpInit)(EVP_CIPHER_CTX *, EVP_CIPHER const *, unsigned char const *key, unsigned char const *iv, OSSL_PARAM const *param), int (*evpUpdate)(EVP_CIPHER_CTX *, unsigned char *out, int *outl, unsigned char const *in, int inl), int (*evpFinal)(EVP_CIPHER_CTX *, unsigned char *out, int *outl) ) : SymCryptBase(cipherName, key, iv, params, evpInit), d_inStream(inStream), d_inBufSize(inBufSize < 100 ? 100 : inBufSize), d_inBuf(new char[d_inBufSize]), d_evpUpdate(evpUpdate), d_evpFinal(evpFinal) {} bobcat-6.07.01/isymcryptbase/evpfinal.cc0000664000175000017500000000067314673353434017140 0ustar frankfrank#include "isymcryptbase.ih" bool ISymCryptBase::evpFinal() { checkOutBufSize(blockSize()); int nOutputChars; if (not ((*d_evpFinal)( // finalize en/decryption ctx(), uOutBuf(), &nOutputChars )) ) // { // checkEVPerror(); throw Exception{} << "EVP_{En,De}cryptFinal failed"; // } setg(outBuf(), outBuf(), outBuf() + nOutputChars); return nOutputChars != 0; } bobcat-6.07.01/isymcryptbase/icmconf0000664000175000017500000000010714673353434016356 0ustar frankfrank#define LIBRARY "isymcryptbase" #include "../icmconf.lib" bobcat-6.07.01/isymcryptbase/destructor.cc0000664000175000017500000000014314673353434017522 0ustar frankfrank#include "isymcryptbase.ih" ISymCryptBase::~ISymCryptBase() { // EVP_CIPHER_CTX_free(d_ctx); } bobcat-6.07.01/isymcryptbase/isymcryptbase2.cc0000664000175000017500000000177314673353434020316 0ustar frankfrank#include "isymcryptbase.ih" ISymCryptBase::ISymCryptBase( std::string const &inStreamName, string const &cipherName, string const &key, string const &iv, size_t inBufSize, OSSL_PARAM const *params, int (*evpInit)(EVP_CIPHER_CTX *, EVP_CIPHER const *, unsigned char const *key, unsigned char const *iv, OSSL_PARAM const *param), int (*evpUpdate)(EVP_CIPHER_CTX *, unsigned char *out, int *outl, unsigned char const *in, int inl), int (*evpFinal)(EVP_CIPHER_CTX *, unsigned char *out, int *outl) ) : SymCryptBase(cipherName, key, iv, params, evpInit), d_ifStream( new ifstream{ Exception::factory(inStreamName) } ), d_inStream(*d_ifStream.get()), d_inBufSize(inBufSize < 100 ? 100 : inBufSize), d_inBuf(new char[d_inBufSize]), d_evpUpdate(evpUpdate), d_evpFinal(evpFinal) {} bobcat-6.07.01/isymcryptbase/underflow.cc0000664000175000017500000000105514673353434017334 0ustar frankfrank#include "isymcryptbase.ih" int ISymCryptBase::underflow() { d_inStream.read(d_inBuf.get(), d_inBufSize); // read d_inStream size_t nRead = d_inStream.gcount(); // # chars read if (nRead == 0) { if (evpUpdate(0)) return static_cast(*gptr()); if (evpFinal()) return static_cast(*gptr()); return EOF; } //setg(d_inBuf.get(), d_inBuf.get(), d_inBuf.get() + nRead); evpUpdate(nRead); return static_cast(*gptr()); } bobcat-6.07.01/isymcryptbase/isymcryptbase0000664000175000017500000000513314673353434017642 0ustar frankfrank#ifndef INCLUDED_BOBCAT_ISYMCRYPTBASE_ #define INCLUDED_BOBCAT_ISYMCRYPTBASE_ #include #include #include #include namespace FBB { namespace IUO // the facilities defined here are not further documented { // elsewhere. The ISymCryptBase class defined below // should only be used by IISymCrypt. class ISymCryptBase: private SymCryptBase, public std::streambuf { std::unique_ptr d_ifStream; // used by the 2nd constructor std::istream &d_inStream; // source stream to process size_t d_inBufSize; std::unique_ptr d_inBuf; // buffer receiving chars from // d_instream int (*d_evpUpdate)(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, unsigned char const *in, int inl); int (*d_evpFinal)(EVP_CIPHER_CTX *, unsigned char *out, int *outl); public: ISymCryptBase( std::istream &inStream, std::string const &cipherName, std::string const &key, std::string const &iv, size_t inBufSize, OSSL_PARAM const *params, int (*evpInit)(EVP_CIPHER_CTX *ctx, EVP_CIPHER const *type, unsigned char const *key, unsigned char const *iv, OSSL_PARAM const *params), 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) ); ISymCryptBase( std::string const &inStreamName, std::string const &cipherName, std::string const &key, std::string const &iv, size_t inBufSize, OSSL_PARAM const *params, int (*evpInit)(EVP_CIPHER_CTX *ctx, EVP_CIPHER const *type, unsigned char const *key, unsigned char const *iv, OSSL_PARAM const *params), 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) ); ~ISymCryptBase() override; using SymCryptBase::errorMsg; // static members using SymCryptBase::ivLength; using SymCryptBase::keyLength; private: bool evpFinal(); bool evpUpdate(size_t inBufRead); int underflow() override; }; } // IUO } // FBB #endif bobcat-6.07.01/isymcryptstream/0000775000175000017500000000000014673353434015400 5ustar frankfrankbobcat-6.07.01/isymcryptstream/isymcryptstream2.f0000664000175000017500000000102314673353434021104 0ustar frankfranktemplate ISymCryptStream::ISymCryptStream( std::istream &&inStream, std::string const &cipherName, std::string const &key, std::string const &iv, size_t inBufSize ) : ISymCryptStreambuf( // std::move(inStream), inStream, cipherName, key, iv, inBufSize ), std::istream(this) { std::string line; std::getline(inStream, line); std::cerr << "instream: " << inStream.good() << ": " << line << '\n'; } bobcat-6.07.01/isymcryptstream/isymcryptstream1.f0000664000175000017500000000062114673353434021106 0ustar frankfranktemplate template ISymCryptStream::ISymCryptStream( StreamSpec &streamSpec, std::string const &cipherName, std::string const &key, std::string const &iv, size_t inBufSize ) : ISymCryptStreambuf( streamSpec, cipherName, key, iv, inBufSize ), std::istream(this) {} bobcat-6.07.01/isymcryptstream/isymcryptstream0000664000175000017500000000132414673353434020602 0ustar frankfrank#ifndef INCLUDED_BOBCAT_ISYMCRYPTSTREAM_ #define INCLUDED_BOBCAT_ISYMCRYPTSTREAM_ #include namespace FBB { template struct ISymCryptStream: private ISymCryptStreambuf, public std::istream { template ISymCryptStream( // 1.f StreamSpec &streamSpec, std::string const &cipherName, std::string const &key, std::string const &iv, size_t inBufSize = 100 ); using ISymCryptStreambuf::keyLength; using ISymCryptStreambuf::ivLength; }; #include "isymcryptstream1.f" } // namespace FBB #endif bobcat-6.07.01/isymcryptstream/driver/0000775000175000017500000000000014737552575016703 5ustar frankfrankbobcat-6.07.01/isymcryptstream/driver/build0000775000175000017500000000074714673353434017730 0ustar frankfrank#!/bin/bash # # using libbobcat: # g++ `cat ../../c++std` -O2 -Wall -o driver driver.cc -lbobcat -lcrypto # using local libraries and libbobcat for other requirements: g++ `cat ../../c++std` -O2 -Wall -o driver driver.cc \ -L../../symcryptbase/tmp/ \ -L../../isymcryptbase/tmp/ \ -lisymcryptbase -lsymcryptbase -lbobcat -lcrypto # g++ `cat ../../c++std` -O2 -Wall -o driver -isystem ../../tmp driver.cc \ # -L ../../tmp/lib/ -lbobcat -lcrypto bobcat-6.07.01/isymcryptstream/driver/driver.cc0000664000175000017500000000302514673353434020475 0ustar frankfrank#include #include #include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) try { if (argc == 1) { cout << "arg[1]: e - encrypt, d - decrypt,\n" "arg[2]: file to process, arg[3]: processed file\n"; return 0; } string key = "0123456789abcdef0123456789abcdef"; string iv = " 0123456789ab" "456"; char cipherName[] = "AES-256-GCM" //"AES-256-CBC" ; ifstream in = Exception::factory(argv[2]); ofstream out{ argv[3] }; ISymCryptStreambuf encbuf{ in, cipherName, key, iv, 100 }; if (*argv[1] == 'e') { ISymCryptStream enc{ in, cipherName, key, iv, 100 }; // comment out the previous line and uncomment the next // to use the constructor expecting a string as 1st arg: // ISymCryptStream enc{ argv[2], cipherName, key, // iv, 100}; out << enc.rdbuf(); } else { ISymCryptStream decrypt{ in, cipherName, key, iv, 100 }; // comment out the previous line and uncomment the next // to use the constructor expecting a string as 1st arg: // ISymCryptStream decrypt{ argv[2], cipherName, key, // iv, 100 }; out << decrypt.rdbuf(); } } catch (exception const &exc) { cerr << exc.what() << '\n'; } bobcat-6.07.01/isymcryptstreambuf/0000775000175000017500000000000014673353434016075 5ustar frankfrankbobcat-6.07.01/isymcryptstreambuf/isymcryptstreambuf1.f0000664000175000017500000000100114673353434022271 0ustar frankfranktemplate inline ISymCryptStreambuf::ISymCryptStreambuf( StreamSpec &streamSpec, std::string const &cipherName, std::string const &key, std::string const &iv, size_t inBufSize ) : ISymCryptBase( streamSpec, cipherName, key, iv, inBufSize, 0, &EVP_EncryptInit_ex2, &EVP_EncryptUpdate, &EVP_EncryptFinal_ex ) {} bobcat-6.07.01/isymcryptstreambuf/isymcryptstreambuf2.f0000664000175000017500000000100014673353434022271 0ustar frankfranktemplate inline ISymCryptStreambuf::ISymCryptStreambuf( StreamSpec &streamSpec, std::string const &cipherName, std::string const &key, std::string const &iv, size_t inBufSize ) : ISymCryptBase( streamSpec, cipherName, key, iv, inBufSize, 0, &EVP_DecryptInit_ex2, &EVP_DecryptUpdate, &EVP_DecryptFinal_ex ) {} bobcat-6.07.01/isymcryptstreambuf/isymcryptstreambuf0000664000175000017500000000246114673353434021777 0ustar frankfrank#ifndef INCLUDED_BOBCAT_ISYMCRYPTSTREAMBUF_ #define INCLUDED_BOBCAT_ISYMCRYPTSTREAMBUF_ #include #include namespace FBB { // generic class name, only 2 specializations exist: ENCRYPT and DECRYPT // defined in FBB::CryptType template class ISymCryptStreambuf; template <> class ISymCryptStreambuf: public IUO::ISymCryptBase { public: template ISymCryptStreambuf( // 1.f StreamSpec &streamSpec, std::string const &cipherName, std::string const &key, std::string const &iv, size_t bufSize = 100 ); // inherits static size_t keyLength(char const *cipherName) and // size_t ivLength(char const *cipherName) }; template <> class ISymCryptStreambuf: public IUO::ISymCryptBase { public: template ISymCryptStreambuf( // 2.f StreamSpec &streamSpec, std::string const &cipherName, std::string const &key, std::string const &iv, size_t bufSize = 100 ); }; #include "isymcryptstreambuf1.f" #include "isymcryptstreambuf2.f" } // namespace FBB #endif bobcat-6.07.01/iterator/0000775000175000017500000000000014673353434013752 5ustar frankfrankbobcat-6.07.01/iterator/operatorinc.f0000664000175000017500000000016214673353434016445 0ustar frankfranktemplate inline Iterator &Iterator::operator++() { ++d_value; return *this; } bobcat-6.07.01/iterator/max.f0000664000175000017500000000020614673353434014704 0ustar frankfranktemplate inline Iterator Iterator::max() { return Iterator(std::numeric_limits::max()); } bobcat-6.07.01/iterator/last.f0000664000175000017500000000017014673353434015062 0ustar frankfranktemplate inline Iterator Iterator::last(Type value) { return Iterator(++value); } bobcat-6.07.01/iterator/operatorequal.f0000664000175000017500000000022114673353434016777 0ustar frankfranktemplate inline bool operator==(Iterator const &lhs, Iterator const &rhs) { return lhs.d_value == rhs.d_value; } bobcat-6.07.01/iterator/min.f0000664000175000017500000000020614673353434014702 0ustar frankfranktemplate inline Iterator Iterator::min() { return Iterator(std::numeric_limits::min()); } bobcat-6.07.01/iterator/operatorpostdec.f0000664000175000017500000000020614673353434017334 0ustar frankfranktemplate inline Iterator Iterator::operator--(int) { Iterator tmp(d_value--); return tmp; } bobcat-6.07.01/iterator/iterator0000664000175000017500000000353114673353434015530 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 struct Iterator { friend bool operator==<>(Iterator const &lhs, Iterator const &rhs); using iterator_category = std::input_iterator_tag; using difference_type = std::ptrdiff_t; using value_type = Type const; using pointer = value_type *; using reference = value_type &; private: 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-6.07.01/iterator/iterator1.f0000664000175000017500000000017214673353434016033 0ustar frankfranktemplate inline Iterator::Iterator(Type const &value) : d_value(value), d_type(new Type) {} bobcat-6.07.01/iterator/operatordec.f0000664000175000017500000000016214673353434016427 0ustar frankfranktemplate inline Iterator &Iterator::operator--() { --d_value; return *this; } bobcat-6.07.01/iterator/reverseiterator2.f0000664000175000017500000000021514673353434017426 0ustar frankfranktemplate ReverseIterator::ReverseIterator(Iterator const &vi) : std::reverse_iterator>(vi) {} bobcat-6.07.01/iterator/operatorunequal.f0000664000175000017500000000020714673353434017346 0ustar frankfranktemplate inline bool operator!=(Iterator const &lhs, Iterator const &rhs) { return not (lhs == rhs); } bobcat-6.07.01/iterator/operatorpostinc.f0000664000175000017500000000020614673353434017352 0ustar frankfranktemplate inline Iterator Iterator::operator++(int) { Iterator tmp(d_value++); return tmp; } bobcat-6.07.01/iterator/reverseiterator1.f0000664000175000017500000000023114673353434017423 0ustar frankfranktemplate ReverseIterator::ReverseIterator(Type const &value) : std::reverse_iterator>(Iterator(value)) {} bobcat-6.07.01/iterator/reverseiteratorlast.f0000664000175000017500000000025014673353434020227 0ustar frankfranktemplate inline ReverseIterator ReverseIterator::last(Type const &value) { return ReverseIterator(Iterator::last(value)); } bobcat-6.07.01/iterator/operatorstarconst.f0000664000175000017500000000023014673353434017710 0ustar frankfranktemplate inline Type const &Iterator::operator*() const { return d_value; // // *d_type = d_value; // return *d_type; } bobcat-6.07.01/iterator/driver/0000775000175000017500000000000014737552575015255 5ustar frankfrankbobcat-6.07.01/iterator/driver/build0000775000175000017500000000010514673353434016266 0ustar frankfrank#!/bin/bash g++ `cat ../../c++std` -Wall -o driver -I. driver.cc -s bobcat-6.07.01/iterator/driver/driver.cc0000664000175000017500000000201614673353434017046 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-6.07.01/iterator/driver/bobcat0000777000175000017500000000000014673353434016553 2..ustar frankfrankbobcat-6.07.01/iuo/0000775000175000017500000000000014736745340012716 5ustar frankfrankbobcat-6.07.01/iuo/iuo0000664000175000017500000000066214673353434013440 0ustar frankfrank#ifndef INCLUDED_BOBCAT_IUO_ #define INCLUDED_BOBCAT_IUO_ #include #include namespace FBB { void deprecated__(bool &called, char const *msg); class OptStructArray { using OptStruct = struct option; size_t d_n; OptStruct *d_opt; public: OptStructArray(size_t n); ~OptStructArray(); OptStruct *get(); }; #include "destructor.f" #include "get.f" } // FBB #endif bobcat-6.07.01/iuo/opstructarray1.cc0000664000175000017500000000021514673353434016225 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-6.07.01/iuo/deprecated.cc0000664000175000017500000000046214673353434015326 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-6.07.01/iuo/get.f0000664000175000017500000000011614673353434013641 0ustar frankfrankinline OptStructArray::OptStruct *OptStructArray::get() { return d_opt; } bobcat-6.07.01/iuo/icmconf0000664000175000017500000000007114673353434014254 0ustar frankfrank#define LIBRARY "iuo" #include "../icmconf" bobcat-6.07.01/iuo/destructor.f0000664000175000017500000000010214673353434015253 0ustar frankfrankinline OptStructArray::~OptStructArray() { delete [] d_opt; } bobcat-6.07.01/iuo/iuo.ih0000664000175000017500000000012114736315237014024 0ustar frankfrank#include "iuo" #include using namespace std; using namespace FBB; bobcat-6.07.01/ldc/0000775000175000017500000000000014736742656012673 5ustar frankfrankbobcat-6.07.01/ldc/set4.cc0000664000175000017500000000022214673353434014045 0ustar frankfrank#include "ldc.ih" void LDC::set(size_t nBytes, char const *bytes, string const &digits) { LDC tmp{ nBytes, bytes, digits }; swap(tmp); } bobcat-6.07.01/ldc/compress.cc0000664000175000017500000000163514673353434015032 0ustar frankfrank#include "ldc.ih" // 4 0 // indices in hexNr // 1 2 3 4 5 // digits in hexNr // // converted into buffer: // // high idx low idx // extra 0-bytes nexNr's digits // 00 00 00 00 00 01 23 45 // ^ ^ // end begin // // Ptr's value contains: 0x12345 void LDC::compress(string const &hexNr) { d_size = hexNr.length(); // prefix an initial 0-byte // to simulate a div10-result d_size = d_size / 2 + (d_size & 1) + SIZE; // always at least VALUE // 0-bytes available at the upper end prepareBuffers(); compressDigits(hexNr); // compress hexNr's digits guardBegin(); setDivPtrs(); } bobcat-6.07.01/ldc/operatoris3.cc0000664000175000017500000000015114673353434015441 0ustar frankfrank#include "ldc.ih" LDC &LDC::operator=(std::string const &hexStr) { set(hexStr); return *this; } bobcat-6.07.01/ldc/ldc7.cc0000664000175000017500000000032114673353434014017 0ustar frankfrank#include "ldc.ih" LDC::LDC(BigInt const &bigInt, string const &digits) : LDC() { auto [nBytes, bytes] = bigIntBytes(bigInt); LDC tmp{ nBytes, bytes, digits }; delete[] bytes; swap(tmp); } bobcat-6.07.01/ldc/setradix1.cc0000664000175000017500000000041214673353434015073 0ustar frankfrank#include "ldc.ih" namespace { string digits{ "0123456789abcdefghijklmnopqrstuvwxyz" }; } void LDC::setRadix(size_t radix) { if (radix < 2 or radix > 36) throw Exception{} << "radix must be >= 2 and <= 36"; setRadix(digits.substr(0, radix)); } bobcat-6.07.01/ldc/ldc.ih0000664000175000017500000000047014736315237013747 0ustar frankfrank#include "ldc" #include #include #include #include #include "../fswap/fswap" #include "../bigint/bigint" #include "../string/string" using namespace std; using namespace FBB; inline int LDC::idx(CHAR *ptr, bool bufIdx) const { return ptr - d_buffer[bufIdx]; } bobcat-6.07.01/ldc/ldc2.cc0000664000175000017500000000020714673353434014015 0ustar frankfrank#include "ldc.ih" LDC::LDC(string const &hexStr, size_t radix) // e.g., deadbeef, no 0x { setRadix(radix); init(hexStr); } bobcat-6.07.01/ldc/convert.cc0000664000175000017500000000177014673353434014657 0ustar frankfrank#include "ldc.ih" void LDC::convert() { if (size_t length = d_end - d_begin.ptr; // no length or merely a 0-value? length == 0 // then convert to a value 0 or (length == 1 and *d_begin.valuePtr == 0) ) { d_converted.push_back('0'); return; } while (*d_begin.valuePtr >= d_radix) // reducible values are available { reduce(); // reduce d_begin till all the // value's bytes were processed swap(); // continue with the div 10 value } if (*d_begin.valuePtr != 0) // add the remaining != 0 quotient d_converted += d_digits[*d_begin.ptr]; // as the final (MS) digit // the MSD is not at idx 0 and is // therefore first displayed. reverse(d_converted.begin(), d_converted.end()); } bobcat-6.07.01/ldc/ldc4.cc0000664000175000017500000000031014673353434014012 0ustar frankfrank#include "ldc.ih" LDC::LDC(BigInt const &bigInt, size_t radix) : LDC() { auto [nBytes, bytes] = bigIntBytes(bigInt); LDC tmp{ nBytes, bytes, radix }; delete[] bytes; swap(tmp); } bobcat-6.07.01/ldc/opfunction.cc0000664000175000017500000000067014673353434015361 0ustar frankfrank#include "ldc.ih" #include string LDC::operator()(size_t power, char sep) const { string ret; if (power <= 1) return ret = d_converted; size_t end = d_converted.length(); size_t begin = end % power; if (begin == 0) begin += power; ret += d_converted.substr(0, begin); for (; begin != end; begin += power) ret += sep + d_converted.substr(begin, power); return ret; } bobcat-6.07.01/ldc/installdiv.cc0000664000175000017500000000115614673353434015346 0ustar frankfrank#include "ldc.ih" void LDC::installDiv(VALUE div10Value) { size_t nBytes = d_end - d_begin.ptr; // # bytes in th current value Cpt div10{ .value = div10Value }; // obtain div10Value's bytes d_divBegin -= nBytes; // begin of the div10Value: if (div10.bytes[nBytes - 1] == 0) // if div10's MSB == 0 { // then ignore the MSB --nBytes; ++d_divBegin; } // cp div10Value to the the div-buffer copy(div10.bytes, div10.bytes + nBytes, d_divBegin); } bobcat-6.07.01/ldc/setdivptrs.cc0000664000175000017500000000067314673353434015407 0ustar frankfrank#include "ldc.ih" void LDC::setDivPtrs() { // beyond the last byte of the quotient: // same length as buffer[0]'s value d_divEnd = d_buffer[1] + (d_end - d_buffer[0]); d_divBegin = d_divEnd; // so far no div10 value: new bytes are // stored before d_divBegin, first the // MSB. } bobcat-6.07.01/ldc/reduce.cc0000664000175000017500000000202114673353434014434 0ustar frankfrank#include "ldc.ih" void LDC::reduce() { while (true) { // store value / 10 at d_divEnd installDiv(*d_begin.valuePtr / d_radix); *d_begin.valuePtr %= d_radix; // compute the radix value if (d_begin.ptr == d_lsb) // all digits were processed break; // not all digits were processed // the next value ends at (beyond) // the byte holding the remainder d_end = d_begin.ptr + 1; // (% 10) of the current value // ensure that d_begin.ptr points guardBegin(); // at or beyond the value's LSB } // remainder: always < d_modulo: // add the remainder as the next d_converted += d_digits[*d_begin.ptr]; // digit to 'd_converted' } bobcat-6.07.01/ldc/operatoris2.cc0000664000175000017500000000012714673353434015443 0ustar frankfrank#include "ldc.ih" LDC &LDC::operator=(LDC &&tmp) { swap(tmp); return *this; } bobcat-6.07.01/ldc/README0000664000175000017500000001052014673353434013541 0ustar frankfrankHerer are some examples, conversions with 0-digits, to decimal: Start (decimal): 167772160 (hex): 0x0a.00.00.00 Each hex digit is stored in a nibble. There are 2 nibbles in a byte. In the illustrations below the bytes are visually separated by .-characters. The dividend is split up in blocks of 2 bytes. So 0a.00 and 00.00. The procedure also works for larger and smaller numbers, and also for uint64_t (8 bytes). When dividing by 10 (0xa) (example below) the 'rest' will be the beginning of the next dividend; 'quot' is the beginning of the divident of the next division. The mask ----- marks the two bytes targeted by the operation: dividend: rest quot 0a.00.00.00 0 01.00 ----- 0 if 'rest' == 0 then 0-bytes are added up to the first byte != 0 (or until the final bytes has been reached). At that point that byte's value is assigned to 'rest', here resulting in: dividend: rest quot 0a.00.00.00 0 01.00 00.00 0 01.00.00.00 added2 bytes ----- ~ 0 The next dividend concatenates quotients: here it's 1 quotient: 01.00.00.00 (01000000 * a = 0a000000) Next round: dividend: rest quot 01.00.00.00 6 19 ----- 06.00 6 99 ----- 06.00 6 99 last byte (LB) was processed ~ Next: dividend: rest quot 19.99.99 3 28f ----- 03.99 1 5c LB ~ Next: dividend: rest quot 02.8f.5c 5 41 ----- 05.5c 2 89 LB ~ Next: dividend: rest quot 41.89 7 06.8d LB ~ Next: dividend: rest quot 06.8d 7 a7 LB ~ Next: dividend: rest quot 00.a7 7 10 LB ~ Next: dividend: rest quot 00.10 6 1 LB ~ Next: dividend: rest quot 00.01 1 0 LB, done ~ Number decimal: 167772160 Decimal starting value: 167772160 Match. -------------------------------------------------------------------------- Another one, having repeated series of 0s: hex: 0x 64.00.00.08.ff dec: 429496731903 dividend: rest quot 64.00.00.08.ff 0 [0a.00] ----- 00.08 8 0a.00.00.00 added 2 0-bytes for 00 en 08 ----- 08.ff 3 e6 LB ----- ~ dividend: rest quot 0a.00.00.00.e6 0 [01.00] ----- 00.00.e6 01.00.00.00.00 added 3 0-bytes, for 00, 00 en e6 -------- e6 0 17 LB ~ dividend: rest quot 01.00.00.00.17 6 19 ----- 06.00 6 99 ----- 06.00 6 99 ----- 06.17 9 9b LB ~ dividend: rest quot 19.99.99.9b 3 28f ----- 03.99 1 5c ----- 1.9b 1 29 LB ~ dividend: rest quot 02.8f.5c.29 5 41 ----- 05.5c 2 89 ----- 02.29 3 37 LB ~ dividend: rest quot 41.89.37 7 68d ----- 07.37 7 b8 LB ~ dividend: rest quot 06.8d.b8 7 a7 ----- 07.b8 6 c5 LB ~ dividend: rest quot a7.c5 9 10c6 LB ~ dividend: rest quot 10.c6 4 0x1ad LB ~ dividend: rest quot 01.ad 9 2a LB ~ dividend: rest quot 00.2a 2 4 LB ~ 429496731903: correct. bobcat-6.07.01/ldc/swap1.cc0000664000175000017500000000014214673353434014222 0ustar frankfrank#include "ldc.ih" void LDC::swap(LDC &other) { fswap(*this, other, d_converted, d_digits); } bobcat-6.07.01/ldc/set1.cc0000664000175000017500000000022014673353434014040 0ustar frankfrank#include "ldc.ih" void LDC::set(string const &hexNr, size_t radix) // e.g., deadbeef, no 0x { LDC tmp{ hexNr, radix }; swap(tmp); } bobcat-6.07.01/ldc/init1.cc0000664000175000017500000000106114673353434014214 0ustar frankfrank#include "ldc.ih" // called by LDC(string const &hexStr, ...) void LDC::init(string const &hexStr) { if (hexStr.empty()) throw Exception{} << "'LDC(string const &hexStr ...': hexStr may not be empty"; string hexNr{ String::lc(hexStr) }; bytes2hex(hexNr); // hexNr's elements now contain hex digit // values // at least SIZE bytes, 1 extra byte for odd- compress(hexNr); // sized digits -> room for the final digit convert(); } bobcat-6.07.01/ldc/set3.cc0000664000175000017500000000017614673353434014054 0ustar frankfrank#include "ldc.ih" void LDC::set(string const &hexNr, string const &digits) { LDC tmp{ hexNr, digits }; swap(tmp); } bobcat-6.07.01/ldc/operatoris1.cc0000664000175000017500000000013214673353434015436 0ustar frankfrank#include "ldc.ih" LDC &LDC::operator=(LDC const &rhs) { return *this = LDC{ rhs }; } bobcat-6.07.01/ldc/ldc1.cc0000664000175000017500000000011414673353434014011 0ustar frankfrank#include "ldc.ih" LDC::LDC() { d_buffer[0] = 0; d_buffer[1] = 0; } bobcat-6.07.01/ldc/bytes2hex.cc0000664000175000017500000000141514673353434015110 0ustar frankfrank#include "ldc.ih" // static void LDC::bytes2hex(string &arg) { // ignore initial 0-characters // (non-essential cosmetics) if (size_t idx = arg.find_first_not_of('0', 0); idx != string::npos) arg.erase(0, idx); // keep a single 0-byte else { arg = string(1, 0); // mere zeroes require no further return; // modifications } for (char &byte: arg) // convert to binary hex bytes byte = isdigit(byte) ? byte - '0' : byte - 'a' + 10; reverse(arg.begin(), arg.end()); // least significant digit as binary // value is now at arg[0]. } bobcat-6.07.01/ldc/set2.cc0000664000175000017500000000021214673353434014042 0ustar frankfrank#include "ldc.ih" void LDC::set(size_t nBytes, char const *bytes, size_t radix) { LDC tmp{ nBytes, bytes, radix }; swap(tmp); } bobcat-6.07.01/ldc/preparebuffers.cc0000664000175000017500000000032514673353434016205 0ustar frankfrank#include "ldc.ih" void LDC::prepareBuffers() { for (size_t idx = 0; idx != 2; ++idx) d_buffer[idx] = new CHAR[d_size](); d_lsb = d_buffer[0]; // begin location of hexNr's compressed } bobcat-6.07.01/ldc/compressdigits.cc0000664000175000017500000000121414673353434016227 0ustar frankfrank#include "ldc.ih" void LDC::compressDigits(string const &hexNr) { d_end = d_lsb; // append bytes at d_end size_t value = 0; // stores 2 nibbles // 1, 2, 3, 4, ...: // 1 in lowest nibble, 2 in highest size_t nibble = 0; for (char const &ch: hexNr) // ch values are hexNr's characters { value = (ch << nibble) | value; nibble += 4; if (nibble == 8) { nibble = 0; *d_end++ = value; value = 0; } } if (value != 0) *d_end++ = value; } bobcat-6.07.01/ldc/show.cc0000664000175000017500000000034114673353434014150 0ustar frankfrank#include "ldc.ih" // static ostream &LDC::show(ostream &out, string const &arg) { out << "Lowest idx first: " << hex; for (char const &byte: arg) out << static_cast(byte); return out << dec; } bobcat-6.07.01/ldc/indices.cc0000664000175000017500000000054514673353434014614 0ustar frankfrank#include "ldc.ih" ostream &LDC::indices(ostream &out) const { return out << " lsb: " << idx(d_lsb, d_cb) << ", begin: " << idx(d_begin.ptr, d_cb) << ", end: " << idx(d_end, d_cb) << "\n" " divBegin: " << idx(d_divBegin, not d_cb) << ", divEnd: " << idx(d_divEnd, not d_cb); } bobcat-6.07.01/ldc/ldc9.cc0000664000175000017500000000020214673353434014017 0ustar frankfrank#include "ldc.ih" #include LDC::LDC(LDC &&tmp) { swap(tmp); tmp.d_buffer[0] = 0; tmp.d_buffer[1] = 0; } bobcat-6.07.01/ldc/showdiv.cc0000664000175000017500000000042614673353434014657 0ustar frankfrank#include "ldc.ih" ostream &LDC::showDiv(ostream &out) const { out.fill('0'); out << hex; for (CHAR *end = d_divEnd, *begin = d_divBegin; end-- != begin; ) out << setw(2) << static_cast(*end) << ' '; out.fill(' '); return out << dec; } bobcat-6.07.01/ldc/icmconf0000664000175000017500000000007114673353434014222 0ustar frankfrank#define LIBRARY "ldc" #include "../icmconf" bobcat-6.07.01/ldc/ldc5.cc0000664000175000017500000000021514673353434014017 0ustar frankfrank#include "ldc.ih" LDC::LDC(string const &hexStr, string const &digits) // e.g., deadbeef, no 0x { setRadix(digits); init(hexStr); } bobcat-6.07.01/ldc/swap2.cc0000664000175000017500000000034314673353434014226 0ustar frankfrank#include "ldc.ih" void LDC::swap() { d_lsb = d_divBegin; d_begin.ptr = d_lsb; d_end = d_divEnd; guardBegin(); d_divEnd = d_buffer[d_cb] + d_size - SIZE; d_divBegin = d_divEnd; d_cb = not d_cb; } bobcat-6.07.01/ldc/showcb.cc0000664000175000017500000000106414673353434014460 0ustar frankfrank#include "ldc.ih" ostream &LDC::showCb(ostream &out) const { out.fill('0'); out << hex; for (CHAR *end = d_end, *begin = d_begin.ptr; end-- != begin; ) out << setw(2) << static_cast(*end); out << '\n'; for (CHAR *end = d_end, *begin = d_begin.ptr; end-- != begin; ) out << setw(2) << static_cast(*end) << ' '; out << "| "; for (CHAR *end = d_begin.ptr, *begin = d_lsb; end-- != begin; ) out << setw(2) << static_cast(*end) << ' '; out.fill(' '); return out << dec; } bobcat-6.07.01/ldc/init2.cc0000664000175000017500000000135714673353434014225 0ustar frankfrank#include "ldc.ih" // called by LDC(size_t nBytes, char const *bytes, ...) void LDC::init(size_t nBytes, char const *bytes) { if (nBytes == 0) throw Exception{} << "'LDC(size_t nBytes, char const *bytes ...': nBytes must be >= 1"; d_size = nBytes + SIZE; // always at least VALUE bytes prepareBuffers(); reverse_copy(bytes, bytes + nBytes, d_lsb); d_end = d_lsb + nBytes; // beyond the last byte to convert // the first div value is stored before // d_end: there must always be enough // bytes to handle the value as VALUE guardBegin(); setDivPtrs(); convert(); } bobcat-6.07.01/ldc/destructor.cc0000664000175000017500000000015514673353434015371 0ustar frankfrank#include "ldc.ih" LDC::~LDC() { for (size_t idx = 0; idx != 2; ++idx) delete[] d_buffer[idx]; } bobcat-6.07.01/ldc/ldc6.cc0000664000175000017500000000020714673353434014021 0ustar frankfrank#include "ldc.ih" LDC::LDC(size_t nBytes, char const *bytes, string const &digits) { setRadix(digits); init(nBytes, bytes); } bobcat-6.07.01/ldc/bigintbytes.cc0000664000175000017500000000045314673353434015517 0ustar frankfrank#include "ldc.ih" // static pair LDC::bigIntBytes(BigInt const &bigInt) { size_t size = bigInt.sizeInBytes(); return (size == 0) ? pair{ 1, new char[1]{ 0 } } : pair{ size, bigInt.bigEndian() }; } bobcat-6.07.01/ldc/ldc3.cc0000664000175000017500000000017614673353434014023 0ustar frankfrank#include "ldc.ih" LDC::LDC(size_t nBytes, char const *bytes, size_t radix) { setRadix(radix); init(nBytes, bytes); } bobcat-6.07.01/ldc/ldc8.cc0000664000175000017500000000106214673353434014023 0ustar frankfrank#include "ldc.ih" LDC::LDC(LDC const &other) : d_size(other.d_size), d_radix(other.d_radix), d_cb(other.d_cb), d_converted(other.d_converted) { prepareBuffers(); d_lsb = d_buffer[d_cb]; d_end = d_lsb + (other.d_end - other.d_buffer[d_cb]); d_begin.ptr = d_lsb + (other.d_begin.ptr - other.d_buffer[d_cb]); d_lsb += other.d_lsb - other.d_buffer[d_cb]; d_divEnd = d_buffer[not d_cb]; d_divBegin = d_divEnd + (other.d_divBegin - other.d_buffer[not d_cb]); d_divEnd += other.d_divEnd - other.d_buffer[not d_cb]; } bobcat-6.07.01/ldc/ldc0000664000175000017500000001360114673353434013351 0ustar frankfrank#ifndef INCLUDED_LDC_ #define INCLUDED_LDC_ #include #include #include // in the sources: MSB means most significant byte // LSB: least significant byte. namespace FBB { class BigInt; class LDC { using CHAR = unsigned char; using VALUE = size_t; // usually sizeof(size_t) >= // sizeof(uint64_t) enum { SIZE = sizeof(VALUE) }; union Ptrs { CHAR *ptr; VALUE *valuePtr; // interpret byte sequence as VALUE }; union Cpt { VALUE value; CHAR bytes[SIZE]; }; size_t d_size; // size of the buffers size_t d_radix; bool d_cb = false; // index of the d_buffer element // containing the cpv bytes Ptrs d_begin; // address and value of the currently // processed value (cpv) CHAR *d_lsb; // location of the full value's LSB CHAR *d_end; // beyond the cpv CHAR *d_divEnd; // beyond the bytes of the div10 value CHAR *d_divBegin; // the first byte of the div10 value // beyond the quotient's bytes pointed at by d_divEnd there are SIZE // bytes so when a small value is stored in the buffer the value at // d_divBegin always points to a VALUE value CHAR *d_buffer[2]; // buffers containing the cpb ([0]) // and cpb / 10 ([1]) + SIZE / 2 // spare bytes at the end so at least // VALUE values fit. std::string d_converted; std::string d_digits; public: LDC(); // 1 LDC(std::string const &hexNr, // input is a hex number in a 2 size_t radix = 10); // string e.g., deadbeef // (no 0x prefix) // bytes contains the // binary big endian representation of // the number using nBytes LDC(size_t nBytes, char const *bytes, size_t radix = 10); // 3 LDC(BigInt const &bigInt, size_t radix = 10); // 4 LDC(std::string const &hexNr, // input is a hex number in a 5 std::string const &digits); // string e.g., deadbeef // (no 0x prefix) // bytes contains the // binary big endian representation of // the number using nBytes LDC(size_t nBytes, char const *bytes, // 6 std::string const &digits); LDC(BigInt const &bigInt, std::string const &digits); // 7 LDC(LDC const &other); // 8 LDC(LDC &&tmp); // 9 ~LDC(); LDC &operator=(LDC const &rhs); // 1 LDC &operator=(LDC &&tmp); // 2 LDC &operator=(std::string const &hexNr); // uses radix 10 3 std::string operator()(size_t power, char sep = '\'') const; void set(std::string const &hexNr, size_t radix = 10); // 1 void set(size_t nBytes, char const *bytes, size_t radix = 10); // 2 void set(std::string const &hexNr, std::string const &digits); // 3 void set(size_t nBytes, char const *bytes, // 4 std::string const &digits); std::string const &str() const; // .f void swap(LDC &other); // 1 private: static std::pair bigIntBytes(BigInt const &bigInt); static void bytes2hex(std::string &arg); void compress(std::string const &hexNr); void compressDigits(std::string const &hexNr); void convert(); // convert to d_radix void guardBegin(); // ensure d_begin.ptr >= d_lsb int idx(CHAR *ptr, bool bufIdx) const; // inserts current and next // buffer indices into out std::ostream &indices(std::ostream &out) const; // called by LDC(string const &hexStr, ...) void init(std::string const &hexStr); // 1 // called by LDC(size_t nBytes, char const *bytes, ...) void init(size_t nBytes, char const *bytes); // 2 // install div_10 in void installDiv(VALUE div10Value); // d_begin[not d_cpt] void prepareBuffers(); void reduce(); // reduced digits to d_ret void setDivPtrs(); // initialize the div-ptrs void setRadix(size_t radix); // 1 void setRadix(std::string const &digits); // 2 static std::ostream &show(std::ostream &out, std::string const &digits); std::ostream &showCb(std::ostream &out) const; std::ostream &showDiv(std::ostream &out) const; void swap(); // swap begin/end with 2 // nextBegin/nextEnd }; #include "ldc.f" } // namespace FBB #endif bobcat-6.07.01/ldc/guardbegin.cc0000664000175000017500000000025414673353434015302 0ustar frankfrank#include "ldc.ih" void LDC::guardBegin() { d_begin.ptr = d_end - SIZE; if (d_begin.ptr < d_lsb) // reset for smaller values d_begin.ptr = d_lsb; } bobcat-6.07.01/ldc/ldc.f0000664000175000017500000000025414673353434013575 0ustar frankfrankinline std::string const &LDC::str() const { return d_converted; } inline std::ostream &operator<<(std::ostream &out, LDC const &ldc) { return out << ldc.str(); } bobcat-6.07.01/ldc/setradix2.cc0000664000175000017500000000033214673353434015075 0ustar frankfrank#include "ldc.ih" void LDC::setRadix(string const &digits) { if (digits.length() < 2) throw Exception{} << "at least 2 digits must be specified"; d_digits = digits; d_radix = d_digits.length(); } bobcat-6.07.01/ldc/driver/0000775000175000017500000000000014737552575014166 5ustar frankfrankbobcat-6.07.01/ldc/driver/build0000775000175000017500000000106314673353434015203 0ustar frankfrank#!/bin/bash tput clear LIBS=" -lbobcat -lcrypto" GPP="g++ `cat ../../c++std`" # link against ../tmp/libldc.a CMD="$GPP -o driver -Wall -I../ driver.cc -L../tmp -lldc ${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-6.07.01/ldc/driver/driver.cc0000664000175000017500000000456514673353434015772 0ustar frankfrank#include #include #include #include #include #include #include "../ldc" using namespace std; using namespace FBB; int main(int argc, char **argv) try { if (argc == 1) { cout << "\n" "args: optional hex number without initial 0x\n" " by default 1122334455667788aabbcc\n" "optional 2nd arg: radix (2 <= radix <= 36)\n" " or ':<#iterations>' for arg[2] BigInt and " "LDC conversions\n" " (#iterations are multiplied by 1'000)\n" "\n"; } string value = "1122334455667788aabbcc"; if (argc > 1) value = argv[1]; size_t radix = 10; size_t iterations = 0; if (argc > 2) { if (argv[2][0] != ':') // non-default radix radix = stoul(argv[2]); else iterations = stoull(argv[2] + 1); } LDC digits{ value, "0123456789ABCDEF" }; LDC ldc{ value, radix }; cout << "radix = " << radix << "\n" "value = " << value << "\n" "digits: " << digits << "\n" " LDC: " << ldc << "\n" " " << ldc(3, '.') << '\n'; BigInt bigInt = BigInt::fromText(value, ios::hex); cout << "BigInt: " << bigInt << '\n'; char *bytes = bigInt.bigEndian(); LDC ldc2(bigInt.sizeInBytes(), bytes); delete[] bytes; cout << " LDC2: " << ldc2 << '\n'; LDC ldc3(bigInt); cout << " LDC3: " << ldc2 << '\n'; if (iterations == 0) // no timing return 0; ostream dummy(0); // dummy ostream to insert BigInts in dummy.setstate(ios::badbit); // for comparison also used with LDC cout << "requested 1000 * " << iterations << " iterations\n"; iterations *= 1000; size_t now = time(0); for (size_t begin = 0; begin != iterations; ++begin) dummy << bigInt; size_t done = time(0); cout << "BigInt conversion: " << (done - now) << " seconds\n"; now = time(0); for (size_t begin = 0; begin != iterations; ++begin) dummy << ldc; done = time(0); cout << "LDC conversion: " << (done - now) << " seconds\n"; } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } bobcat-6.07.01/ldc/driver/buildex0000775000175000017500000000006714673353434015543 0ustar frankfrank#!/bin/bash g++ -I. example.cc -L../tmp -lldc -lbobcat bobcat-6.07.01/ldc/driver/bobcat0000777000175000017500000000000014673353434015464 2..ustar frankfrankbobcat-6.07.01/ldc/driver/example.cc0000664000175000017500000000124014673353434016115 0ustar frankfrank#include #include using namespace std; using namespace FBB; int main(int argc, char **argv) { string value = "1122334455667788aabbcc"; size_t radix = 10; LDC digits{ value, "0123456789ABCDEF" }; LDC ldc{ value, radix }; cout << "radix = " << radix << "\n" "value = " << value << "\n" "digits: " << digits << "\n" " LDC: " << ldc << "\n" " " << ldc(3, '.') << '\n'; } // shows: // radix = 10 // value = 1122334455667788aabbcc // digits: 1122334455667788AABBCC // LDC: 20713245101768454273940428 // 20.713.245.101.768.454.273.940.428 bobcat-6.07.01/level/0000775000175000017500000000000014736742656013240 5ustar frankfrankbobcat-6.07.01/level/level.ih0000664000175000017500000000012514736315237014656 0ustar frankfrank#include "level" #include "../log/log" using namespace std; using namespace FBB; bobcat-6.07.01/level/level.f0000664000175000017500000000006614673353434014510 0ustar frankfrankinline level::level(size_t lev) : d_level(lev) {} bobcat-6.07.01/level/insertinto.cc0000664000175000017500000000022214673353434015731 0ustar frankfrank#include "level.ih" std::ostream &level::insertInto(Log &lp) const { return lp.level(d_level); // otherwise set the level. } bobcat-6.07.01/level/level0000664000175000017500000000060114673353434014257 0ustar frankfrank#ifndef INCLUDED_BOBCAT_LEVEL_ #define INCLUDED_BOBCAT_LEVEL_ #include namespace FBB { class Log; 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-6.07.01/level/icmconf0000664000175000017500000000007314673353434014571 0ustar frankfrank#define LIBRARY "level" #include "../icmconf" bobcat-6.07.01/level/operatorinsert.cc0000664000175000017500000000052414673353434016620 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-6.07.01/level/driver/0000775000175000017500000000000014737552575014533 5ustar frankfrankbobcat-6.07.01/level/driver/build0000775000175000017500000000005614673353434015551 0ustar frankfrank#!/bin/bash g++ -o driver driver.cc -lbobcat bobcat-6.07.01/level/driver/driver.cc0000664000175000017500000000151014736771656016334 0ustar frankfrank#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-6.07.01/LICENSE0000644000175000017500000010472014746121445013124 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-6.07.01/linearmap/0000775000175000017500000000000014673353434014071 5ustar frankfrankbobcat-6.07.01/linearmap/erase1.f0000664000175000017500000000035214673353434015420 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-6.07.01/linearmap/operatorindex.f0000664000175000017500000000046114673353434017124 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-6.07.01/linearmap/find2.f0000664000175000017500000000036314673353434015244 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-6.07.01/linearmap/equalrange2.f0000664000175000017500000000050414673353434016445 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-6.07.01/linearmap/insert3.f0000664000175000017500000000041314673353434015625 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-6.07.01/linearmap/lowerbound1.f0000664000175000017500000000034414673353434016502 0ustar frankfrank// iterator lower_bound(Key const &key) template inline typename LinearMap::iterator LinearMap:: lower_bound(Key const &key) { return iterator(findPtr(key)); } bobcat-6.07.01/linearmap/insert2.f0000664000175000017500000000061614673353434015631 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-6.07.01/linearmap/upperbound2.f0000664000175000017500000000040114673353434016500 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-6.07.01/linearmap/equalrange1.f0000664000175000017500000000043414673353434016446 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-6.07.01/linearmap/linearmap0000664000175000017500000000610214673353434015763 0ustar frankfrank#ifndef INCLUDED_BOBCAT_LINEARMAP_ #define INCLUDED_BOBCAT_LINEARMAP_ #include #include #include #include namespace FBB { template class LinearMap: private std::vector> { using Base = std::vector>; using LinMap = LinearMap; using ConstIterPair = std::pair< typename LinearMap::const_iterator, typename LinearMap::const_iterator >; using IterPair = std::pair< typename LinearMap::iterator, typename LinearMap::iterator >; public: using value_type = std::pair; using iterator = typename Base::iterator; using const_iterator = typename Base::const_iterator; using reverse_iterator = typename Base::reverse_iterator; using const_reverse_iterator = typename Base::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-6.07.01/linearmap/count.f0000664000175000017500000000026314673353434015371 0ustar frankfrank// size_t count(Key const &key) const template inline size_t LinearMap::count(Key const &key) const { return find(key) != end(); } bobcat-6.07.01/linearmap/insert1.f0000664000175000017500000000077714673353434015640 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-6.07.01/linearmap/at.f0000664000175000017500000000040214673353434014640 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-6.07.01/linearmap/erase2.f0000664000175000017500000000022514673353434015420 0ustar frankfrank// bool erase(Key const &key) // template void LinearMap::erase(iterator iter) { Base::erase(iter); } bobcat-6.07.01/linearmap/findptr.f0000664000175000017500000000063214673353434015707 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-6.07.01/linearmap/linearmap1.f0000664000175000017500000000033014673353434016265 0ustar frankfrank// LinearMap(Iterator begin, Iterator end) template template inline LinearMap:: LinearMap(Iterator begin, Iterator end) { insert(begin, end); } bobcat-6.07.01/linearmap/erase3.f0000664000175000017500000000025214673353434015421 0ustar frankfrank// bool erase(Key const &key) // template void LinearMap::erase(iterator begin, iterator end) { Base::erase(begin, end); } bobcat-6.07.01/linearmap/upperbound1.f0000664000175000017500000000034414673353434016505 0ustar frankfrank// iterator upper_bound(Key const &key) template inline typename LinearMap::iterator LinearMap:: upper_bound(Key const &key) { return iterator(findPtr(key)); } bobcat-6.07.01/linearmap/linearmap2.f0000664000175000017500000000035614673353434016276 0ustar frankfrank// LinearMap(initializer_list initial) template inline LinearMap:: LinearMap(std::initializer_list initial) { for (auto &value: initial) insert(value); } bobcat-6.07.01/linearmap/lowerbound2.f0000664000175000017500000000040114673353434016475 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-6.07.01/linearmap/find1.f0000664000175000017500000000032614673353434015242 0ustar frankfrank// iterator find(Key const &key) template inline typename LinearMap::iterator LinearMap:: find(Key const &key) { return iterator(findPtr(key)); } bobcat-6.07.01/linearmap/driver/0000775000175000017500000000000014737552575015374 5ustar frankfrankbobcat-6.07.01/linearmap/driver/build0000775000175000017500000000015414673353434016411 0ustar frankfrank#!/bin/bash g++-8 --std=c++17 -Wall -fdiagnostics-color=never -o driver -I. driver.cc \ -lbobcat -s bobcat-6.07.01/linearmap/driver/driver.cc0000664000175000017500000000170614673353434017172 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-6.07.01/linearmap/driver/bobcat0000777000175000017500000000000014673353434016672 2..ustar frankfrankbobcat-6.07.01/localclientsocket/0000775000175000017500000000000014736742656015633 5ustar frankfrankbobcat-6.07.01/localclientsocket/localclientsocket0000664000175000017500000000146014673353434021251 0ustar frankfrank#ifndef INCLUDED_BOBCAT_LOCALCLIENTSOCKET_ #define INCLUDED_BOBCAT_LOCALCLIENTSOCKET_ #include #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-6.07.01/localclientsocket/localclientsocket.ih0000664000175000017500000000021114736315237021640 0ustar frankfrank#include "localclientsocket" #include #include #include using namespace std; using namespace FBB; bobcat-6.07.01/localclientsocket/connect.cc0000664000175000017500000000034114673353434017561 0ustar frankfrank#include "localclientsocket.ih" int LocalClientSocket::connect() { if (::connect(socket(), sockaddrPtr(), size()) < 0) throw Exception{} << "LocalClientSocket::connect(): " << errnodescr; return socket(); } bobcat-6.07.01/localclientsocket/driver/0000775000175000017500000000000014673353434017116 5ustar frankfrankbobcat-6.07.01/localclientsocket/driver/build0000775000175000017500000000025114673353434020141 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-6.07.01/localclientsocket/driver/client.cc0000664000175000017500000000233014673353434020701 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-6.07.01/localserversocket/0000775000175000017500000000000014736742656015663 5ustar frankfrankbobcat-6.07.01/localserversocket/localserversocket.ih0000664000175000017500000000024114736315237021723 0ustar frankfrank#include "localserversocket" #include #include #include #include using namespace std; using namespace FBB; bobcat-6.07.01/localserversocket/accept.cc0000664000175000017500000000064514673353434017426 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-6.07.01/localserversocket/localserversocket0000664000175000017500000000156014673353434021332 0ustar frankfrank#ifndef INCLUDED_BOBCAT_LOCALSERVERSOCKET_ #define INCLUDED_BOBCAT_LOCALSERVERSOCKET_ #include #include #include namespace FBB { class LocalServerSocket: public LocalSocketBase { bool d_unlink = false; 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-6.07.01/localserversocket/open.cc0000664000175000017500000000060214673353434017121 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-6.07.01/localserversocket/localserversocket1.f0000664000175000017500000000023314673353434021633 0ustar frankfrankinline LocalServerSocket::LocalServerSocket(std::string const &name, Socket action) { open(name, action); } bobcat-6.07.01/localserversocket/destructor.cc0000664000175000017500000000017714673353434020365 0ustar frankfrank#include "localserversocket.ih" LocalServerSocket::~LocalServerSocket() { if (d_unlink) unlink(d_name.c_str()); } bobcat-6.07.01/localserversocket/listen.cc0000664000175000017500000000103714673353434017461 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-6.07.01/localserversocket/driver/0000775000175000017500000000000014673353434017146 5ustar frankfrankbobcat-6.07.01/localserversocket/driver/build0000775000175000017500000000025114673353434020171 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-6.07.01/localserversocket/driver/server.cc0000664000175000017500000000257614673353434020775 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-6.07.01/localsocketbase/0000775000175000017500000000000014736742656015267 5ustar frankfrankbobcat-6.07.01/localsocketbase/sockaddrptr.f0000664000175000017500000000017314673353434017747 0ustar frankfrankinline sockaddr const *LocalSocketBase::sockaddrPtr() const { return reinterpret_cast(&d_address); } bobcat-6.07.01/localsocketbase/localsocketbase1.f0000664000175000017500000000012514673353434020643 0ustar frankfrankinline LocalSocketBase::LocalSocketBase(std::string const &name) { open(name); } bobcat-6.07.01/localsocketbase/socket.f0000664000175000017500000000010414673353434016711 0ustar frankfrankinline int LocalSocketBase::socket() const { return d_socket; } bobcat-6.07.01/localsocketbase/open.cc0000664000175000017500000000125014673353434016525 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-6.07.01/localsocketbase/size.f0000664000175000017500000000010514673353434016374 0ustar frankfrankinline size_t LocalSocketBase::size() const { return d_length; } bobcat-6.07.01/localsocketbase/localsocketbase.ih0000664000175000017500000000016414736315237020737 0ustar frankfrank#include "localsocketbase" #include #include using namespace std; using namespace FBB; bobcat-6.07.01/localsocketbase/localsocketbase1.cc0000664000175000017500000000024114673353434021002 0ustar frankfrank#include "localsocketbase.ih" LocalSocketBase::LocalSocketBase() : d_length(0), d_socket(-1) { memset(&d_address, 0, sizeof(struct sockaddr_un)); } bobcat-6.07.01/localsocketbase/localsocketbase0000664000175000017500000000151614673353434020343 0ustar frankfrank#ifndef INCLUDED_BOBCAT_LOCALSOCKETBASE_ #define INCLUDED_BOBCAT_LOCALSOCKETBASE_ #include #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-6.07.01/log/0000775000175000017500000000000014736742656012712 5ustar frankfrankbobcat-6.07.01/log/opfun.cc0000664000175000017500000000041714673353434014342 0ustar frankfrank#include "log.ih" Log &Log::operator()(char accept) { d_active->levelOK = false; d_active->opfunOK = d_active->accept.find(accept) != string::npos; setActive(d_active->opfunOK); d_level = ~0UL; // stop level insertions return *this; } bobcat-6.07.01/log/instance.cc0000664000175000017500000000025214673353434015014 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-6.07.01/log/data.cc0000664000175000017500000000006214673353434014120 0ustar frankfrank#include "log.ih" unique_ptr Log::s_stream; bobcat-6.07.01/log/log0000664000175000017500000000551014673353434013407 0ustar frankfrank#ifndef INCLUDED_BOBCAT_LOG_ #define INCLUDED_BOBCAT_LOG_ #include #include #include #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 { // opins: friend Log &operator<<(Log &log, LogManipulator manip); // 2.cc friend Log &operator<<(Log &log, // 3.cc std::ostream &(*fun)(std::ostream &str)); friend Log &operator<<(Log &log, // 4.cc std::ios_base &(*fun)(std::ios_base &base)); template friend Log &operator<<(Log &log, Type const &type); // .f std::ofstream d_stream; size_t d_level; // defined by setLevel: the minimum level // messages must have to be inserted struct Active { bool levelOK; bool opfunOK; // WHAT'S opfun? // log characters accepted by opfun.cc (?) std::string accept; // accepted log characters for opfun.cc }; std::unique_ptr d_active; // Log object used by static std::unique_ptr s_stream; // initialize() and instance() 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); Log &operator()(char accept); void str(std::string const &str); std::string const &str() const; private: void init(); }; #include "log.f" //std::ostream &operator<<(std::ostream &str, LogManipulator); // opins1.cc } // FBB std::ostream &operator<<(std::ostream &str, FBB::LogManipulator); // opins1.cc #endif bobcat-6.07.01/log/README0000664000175000017500000000712014673254453013563 0ustar frankfrankenum 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 { // opins: friend Log &operator<<(Log &log, LogManipulator manip); // 2.cc friend Log &operator<<(Log &log, // 3.cc std::ostream &(*fun)(std::ostream &str)); friend Log &operator<<(Log &log, // 4.cc std::ios_base &(*fun)(std::ios_base &base)); template friend Log &operator<<(Log &log, Type const &type); // .f std::ofstream d_stream; size_t d_level; // defined by setLevel: the minimum level // messages must have to be inserted: if d_level // <= the actually specified msg level the message // is inserted struct Active { bool levelOK; // if 'true' next inserted message are logged bool opfunOK; // log characters accepted by opfun.cc (?) std::string accept; // accepted log characters for opfun.cc }; std::unique_ptr d_active; // Log object used by static std::unique_ptr s_stream; // initialize() and instance() public: // initializes s_stream, returns its Log object static Log &initialize(std::string const &filename, std::ios::openmode = std::ios::out | std::ios::app, char const *delim = " "); // returns s_stream's Log object static Log &instance(); // defines the base class objects, calls init() Log(); // 1.cc // defines the base class objects, calls init() Log(std::ostream &out, char const *delim = " "); // 2.cc // forwards to open(), also called by initialize() Log(std::string const &filename, // 3.cc std::ios::openmode = std::ios::out | std::ios::app, char const *delim = " "); // redefines LogBuf, calls init() void open(std::string const &filename, std::ios::openmode = std::ios::out | std::ios::app, char const *delim = " "); // returns the current message level (i.e., d_level) size_t level() const; // .f // updates d_active's levelOK, opfunOK to false // messages are logged if levelOK is true // WIP std::ostream &level(size_t useLevel); // .cc // d_level = newLevel, activates msg logging at 'newLevel' void setLevel(size_t newLevel); using LogBuf::setTimeStamp; // OBS void setTimestamp(TimeStamps timeStamp, char const *delim = " "); // logging completely off/on, but on() can specify a level nr. void off(); // .f void on(size_t logLevel = 0); Log &operator()(char accept); void str(std::string const &str); std::string const &str() const; private: void init(); }; // Not in FBB, but overloading the std operator<<(ostream &) function: std::ostream &operator<<(std::ostream &str, FBB::LogManipulator); // opins1.cc #endif bobcat-6.07.01/log/open.cc0000664000175000017500000000113214673353434014147 0ustar frankfrank#include "log.ih" void Log::open(string const &filename, ios::openmode mode, char const *delim) { if (filename.empty() || filename == "&1") setStream(cout); // merely set LogBuf's d_stream to &cout else if (filename == "&2") setStream(cerr); else { d_stream.open(filename.c_str(), mode); if (not d_stream) throw Exception{} << "Log::Log(string, ...): can't write `" << filename << '\''; setStream(d_stream); } settimestamp(TIMESTAMPS, delim); init(); } bobcat-6.07.01/log/setlevel.cc0000664000175000017500000000023714673353434015036 0ustar frankfrank#include "log.ih" void Log::setLevel(size_t logLevel) { d_level = logLevel; level(~0U); // calls the ostream &level() manipulator (.cc) } bobcat-6.07.01/log/log.ih0000664000175000017500000000014414736315237014003 0ustar frankfrank#include "log" #include #include using namespace std; using namespace FBB; bobcat-6.07.01/log/log3.cc0000664000175000017500000000022414673353434014053 0ustar frankfrank#include "log.ih" Log::Log(string const &filename, ios::openmode mode, char const *delim) : ostream(this) { open(filename, mode, delim); } bobcat-6.07.01/log/init.cc0000664000175000017500000000020314673353434014147 0ustar frankfrank#include "log.ih" void Log::init() { d_active.reset(new Active{ false, false }); // d_msgLevel = ~0U; setLevel(0); } bobcat-6.07.01/log/log2.cc0000664000175000017500000000021314673353434014050 0ustar frankfrank#include "log.ih" Log::Log(ostream &out, char const *delim) : LogBuf(out, TIMESTAMPS, true, delim), ostream(this) { init(); } bobcat-6.07.01/log/opins3.cc0000664000175000017500000000142014673353434014421 0ustar frankfrank#include "log.ih" namespace FBB { Log &operator<<(Log &log, ostream &(*fun)(ostream &)) { if (log.d_active->levelOK or log.d_active->opfunOK) static_cast(log) << fun; if (static_cast(&std::endl) == fun) log.d_active->opfunOK = false; return log; } // if (log.d_active->opfunOK) // { // // cerr << __FILE__ " active\n"; // // static_cast(log) << fun; // // if (static_cast(&std::endl) == fun) // { // // cerr << __FILE__ " active ends\n"; // log.d_active->opfunOK = false; // } // } // return log; // } } bobcat-6.07.01/log/icmconf0000664000175000017500000000013314673353434014240 0ustar frankfrank#define LIBRARY "log" #define IH ".ih" #include "../icmconf" bobcat-6.07.01/log/opins4.cc0000664000175000017500000000037114673353434014426 0ustar frankfrank#include "log.ih" namespace FBB { Log &operator<<(Log &log, ios_base &(*fun)(ios_base &base)) { if (log.d_active->levelOK or log.d_active->opfunOK) static_cast(log) << fun; return log; } } bobcat-6.07.01/log/log.f0000664000175000017500000000110414673353434013626 0ustar frankfrankinline size_t Log::level() const { return d_level; } inline void Log::off() { setActive(OFF); } inline void Log::str(std::string const &accept) { d_active->accept = accept; } inline std::string const &Log::str() const { return d_active->accept; } template Log &operator<<(Log &log, Type const &type) { if (log.d_active->levelOK or log.d_active->opfunOK) reinterpret_cast(log) << type; return log; } inline Log &operator<<(Log &str, level lvl) { dynamic_cast(str) << lvl; return str; } bobcat-6.07.01/log/on.cc0000664000175000017500000000014614673353434013626 0ustar frankfrank#include "log.ih" void Log::on(size_t logLevel) { setActive(ACTIVE); setLevel(logLevel); } bobcat-6.07.01/log/log1.cc0000664000175000017500000000014614673353434014054 0ustar frankfrank#include "log.ih" Log::Log() : LogBuf(TIMESTAMPS, false, " "), ostream(this) { init(); } bobcat-6.07.01/log/initialize.cc0000664000175000017500000000076314673353434015360 0ustar frankfrank#include "log.ih" Log &Log::initialize(std::string const &filename, std::ios::openmode mode, char const *delim) { if (s_stream.get()) // multiple initializations are not allowed throw Exception{} << "Log::initialize: FBB::Log already initialized"; // initialize the static s_stream s_stream.reset(new Log(filename, mode, delim)); return *s_stream.get(); // and return the initialized Log object } bobcat-6.07.01/log/opins1.cc0000664000175000017500000000027414673353434014425 0ustar frankfrank#include "log.ih" ostream &operator<<(ostream &str, FBB::LogManipulator manip) { if (FBB::Log *ptr = dynamic_cast(&str); ptr != 0) *ptr << manip; return str; } bobcat-6.07.01/log/settimestamp.cc0000664000175000017500000000016214673353434015727 0ustar frankfrank#include "log.ih" void Log::setTimestamp(TimeStamps type, char const *delim) { settimestamp(type, delim); } bobcat-6.07.01/log/opins2.cc0000664000175000017500000000156114673353434014426 0ustar frankfrank#include "log.ih" namespace FBB { Log &operator<<(Log &log, LogManipulator manip) { if ( bool opfunOK = log.d_active->opfunOK; opfunOK || log.d_active->levelOK ) { switch (manip) { case FATAL: log.flush(); throw Exception{1} << "LogManipulator::FATAL"; case nl: // 0-char is interpreted by log << static_cast(0); // LogBuf as '\n', without break; // writing a timestamp case fnl: log << static_cast(1); break; } if (opfunOK and manip != nl) log.d_active->opfunOK = false; } return log; } } bobcat-6.07.01/log/level.cc0000664000175000017500000000062514673353434014323 0ustar frankfrank#include "log.ih" ostream &Log::level(size_t msgLevel) { // levelOK opfunOK *d_active = { d_level <= msgLevel, false }; // d_active->levelOK = d_level <= msgLevel; // d_active->opfunOK = false; // LogBuf's member: maybe activates setActive(d_active->levelOK); // logging return *this; } bobcat-6.07.01/log/driver/0000775000175000017500000000000014737552575014205 5ustar frankfrankbobcat-6.07.01/log/driver/build0000775000175000017500000000041114673353434015216 0ustar frankfrank#!/bin/bash # g++ driver.cc -lbobcat #g++ driver.cc -L../tmp -L../../logbuf/tmp -L../../level/tmp \ # -llog -llevel -llogbuf -lbobcat #g++ driver.cc -L../tmp -L../../logbuf/tmp -llog -llogbuf -lbobcat g++ driver.o -L../tmp -llog -lbobcat bobcat-6.07.01/log/driver/driver.cc0000664000175000017500000000235214736772032016000 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"; log.str("ab"); log('a') << "hello a!" << endl; log('b') << "hello b!" << nl << setw(16) << ' ' << "so far, so good" << endl; log << "not shown" << endl; log('c') << "not shown\n"; log << "not shown\n"; log.setLevel(2); log << level(2) << "in business again\n"; } bobcat-6.07.01/logbuf/0000775000175000017500000000000014736742656013407 5ustar frankfrankbobcat-6.07.01/logbuf/logbuf0000664000175000017500000000372514673353434014607 0ustar frankfrank#ifndef INCLUDED_BOBCAT_LOGBUF_ #define INCLUDED_BOBCAT_LOGBUF_ #include #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 "logbuf.f" } // FBB #endif bobcat-6.07.01/logbuf/xsputn.cc0000664000175000017500000000152314673353434015250 0ustar frankfrank#include "logbuf.ih" streamsize LogBuf::xsputn(char const *buffer, streamsize n) { //cerr<<__FILE__" active = " << (d_active == ACTIVE) << '\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-6.07.01/logbuf/overflow.cc0000664000175000017500000000202414673353434015547 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-6.07.01/logbuf/logbuf.ih0000664000175000017500000000023714736315237015200 0ustar frankfrank#include "logbuf" #include #include #include #include #include using namespace std; using namespace FBB; bobcat-6.07.01/logbuf/checktimestamp.cc0000664000175000017500000000041714673353434016711 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-6.07.01/logbuf/logbuf.f0000664000175000017500000000073014673353434015024 0ustar frankfrankinline bool LogBuf::empty() const { return d_empty; } inline void LogBuf::setActive(bool active) { if (d_active != OFF) d_active = active ? ACTIVE : NOT_ACTIVE; } inline void LogBuf::setActive(Active active) { d_active = active; } inline bool LogBuf::active() const { return d_active == ACTIVE; } inline void LogBuf::setEmpty(bool empty) { d_empty = empty; } inline void LogBuf::setStream(std::ostream &stream) { d_stream = &stream; } bobcat-6.07.01/logbuf/logbuf1.cc0000664000175000017500000000100314673353434015237 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-6.07.01/logbuf/newline.cc0000664000175000017500000000044314673353434015350 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-6.07.01/logbuf/icmconf0000664000175000017500000000007414673353434014741 0ustar frankfrank#define LIBRARY "logbuf" #include "../icmconf" bobcat-6.07.01/logbuf/inserttimestamp.cc0000664000175000017500000000053214673353434017136 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-6.07.01/logbuf/sync.cc0000664000175000017500000000012214673353434014655 0ustar frankfrank#include "logbuf.ih" int LogBuf::sync() { d_stream->flush(); return 0; } bobcat-6.07.01/logbuf/settimestamp.cc0000664000175000017500000000027314673353434016427 0ustar frankfrank#include "logbuf.ih" void LogBuf::settimestamp(TimeStamps timestamps, char const *delim) { if ( (d_timestamps = timestamps) != NOTIMESTAMPS) d_delim = !delim ? "" : delim; } bobcat-6.07.01/logbuf/logbuf2.cc0000664000175000017500000000102614673353434015245 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-6.07.01/logbuf/driver/0000775000175000017500000000000014737552575014702 5ustar frankfrankbobcat-6.07.01/logbuf/driver/build0000775000175000017500000000014314673353434015715 0ustar frankfrank#!/bin/bash #g++ -o driver driver.cc -lbobcat g++ -o driver driver.cc -L../tmp -llogbuf -lbobcat bobcat-6.07.01/logbuf/driver/driver.cc0000664000175000017500000000104014673353434016467 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-6.07.01/mailheaders/0000775000175000017500000000000014736742656014407 5ustar frankfrankbobcat-6.07.01/mailheaders/initial.f0000664000175000017500000000031314673353434016174 0ustar frankfrankinline bool FBB::MailHeaders::const_hdr_iterator::initial( std::string const &hdr, std::string const &key) { return hdr.substr(0, hdr.find(':')).find(key) == 0; } bobcat-6.07.01/mailheaders/caseinitial.f0000664000175000017500000000033314673353434017032 0ustar frankfrankinline bool FBB::MailHeaders::const_hdr_iterator::caseInitial( std::string const &hdr, std::string const &key) { return String::lc(hdr.substr(0, hdr.find(':'))).find(key) == 0; } bobcat-6.07.01/mailheaders/data.cc0000664000175000017500000000033714673353434015622 0ustar frankfrank#include "mailheaders.ih" MailHeaders::const_hdr_iterator::Comparator MailHeaders::const_hdr_iterator::s_comparator[] = { fail, initial, partial, full, caseInitial, casePartial, caseFull }; bobcat-6.07.01/mailheaders/oppostinc.f0000664000175000017500000000023014673353434016557 0ustar frankfrankinline FBB::MailHeaders::const_hdr_iterator FBB::MailHeaders::const_hdr_iterator::operator++(int) { return const_hdr_iterator(d_mh, d_current++); } bobcat-6.07.01/mailheaders/opindex.f0000664000175000017500000000014614673353434016215 0ustar frankfrankinline std::string const &FBB::MailHeaders::operator[](size_t idx) const { return d_lines[idx]; } bobcat-6.07.01/mailheaders/lookup.cc0000664000175000017500000000065714673353434016227 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-6.07.01/mailheaders/read.cc0000664000175000017500000000210114673353434015613 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-6.07.01/mailheaders/mailheaders1.cc0000664000175000017500000000023014673353434017240 0ustar frankfrank#include "mailheaders.ih" MailHeaders::MailHeaders(istream &in, Mode mode) : d_in(in), d_match(FAIL) { if (mode == READ) read(); } bobcat-6.07.01/mailheaders/begin.f0000664000175000017500000000015014673353434015626 0ustar frankfrankinline FBB::MailHeaders::const_iterator FBB::MailHeaders::begin() const { return d_lines.begin(); } bobcat-6.07.01/mailheaders/iteratorclass.demo0000664000175000017500000000261114673353434020124 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-6.07.01/mailheaders/opstar.f0000664000175000017500000000015514673353434016057 0ustar frankfrankinline std::string const &FBB::MailHeaders::const_hdr_iterator::operator*() const { return *d_current; } bobcat-6.07.01/mailheaders/opinc.f0000664000175000017500000000023314673353434015654 0ustar frankfrankinline FBB::MailHeaders::const_hdr_iterator &FBB::MailHeaders::const_hdr_iterator::operator++() { d_current = lookup(++d_current); return *this; } bobcat-6.07.01/mailheaders/mailheaders2.cc0000664000175000017500000000027114673353434017246 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-6.07.01/mailheaders/lookdown.cc0000664000175000017500000000103114673353434016535 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-6.07.01/mailheaders/consthdropdec.cc0000664000175000017500000000034714673353434017551 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-6.07.01/mailheaders/consthdriterator1.cc0000664000175000017500000000065314673353434020371 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-6.07.01/mailheaders/end.f0000664000175000017500000000014414673353434015313 0ustar frankfrankinline FBB::MailHeaders::const_iterator FBB::MailHeaders::end() const { return d_lines.end(); } bobcat-6.07.01/mailheaders/rbeginh.f0000664000175000017500000000021114673353434016156 0ustar frankfrankinline FBB::MailHeaders::const_reverse_hdr_iterator FBB::MailHeaders::rbeginh() const { return const_reverse_hdr_iterator(endh()); } bobcat-6.07.01/mailheaders/fail.f0000664000175000017500000000040014673353434015453 0ustar frankfrankinline bool FBB::MailHeaders::const_hdr_iterator::fail( std::string const &hdr, std::string const &key) { throw Exception(1) << "MailHeaders: setHeaderIterator() not called"; return false; // not reached } bobcat-6.07.01/mailheaders/icmconf0000664000175000017500000000010114673353434015730 0ustar frankfrank#define LIBRARY "mailheaders" #include "../icmconf" bobcat-6.07.01/mailheaders/casefull.f0000664000175000017500000000032014673353434016337 0ustar frankfrankinline bool FBB::MailHeaders::const_hdr_iterator::caseFull( std::string const &hdr, std::string const &key) { return String::lc(hdr.substr(0, hdr.find(':'))) == key; } bobcat-6.07.01/mailheaders/rend.f0000664000175000017500000000015614673353434015500 0ustar frankfrankinline FBB::MailHeaders::const_reverse_iterator FBB::MailHeaders::rend() const { return d_lines.rend(); } bobcat-6.07.01/mailheaders/size.f0000664000175000017500000000011414673353434015514 0ustar frankfrankinline size_t FBB::MailHeaders::size() const { return d_lines.size(); } bobcat-6.07.01/mailheaders/full.f0000664000175000017500000000030014673353434015501 0ustar frankfrankinline bool FBB::MailHeaders::const_hdr_iterator::full( std::string const &hdr, std::string const &key) { return hdr.substr(0, hdr.find(':')) == key; } bobcat-6.07.01/mailheaders/casepartial.f0000664000175000017500000000035314673353434017037 0ustar frankfrankinline bool FBB::MailHeaders::const_hdr_iterator::casePartial( std::string const &hdr, std::string const &key) { return String::lc(hdr.substr(0, hdr.find(':'))).find(key) != std::string::npos; } bobcat-6.07.01/mailheaders/operatorassign.cc0000664000175000017500000000020614673353434017744 0ustar frankfrank#include "mailheaders.ih" MailHeaders &MailHeaders::operator=(MailHeaders &&tmp) { fswap(*this, tmp, d_hdr); return *this; } bobcat-6.07.01/mailheaders/mailheaders0000664000175000017500000001214714673353434016605 0ustar frankfrank#ifndef INCLUDED_BOBCAT_MAILHEADERS_ #define INCLUDED_BOBCAT_MAILHEADERS_ #include #include #include #include #include namespace FBB { class MailHeaders { public: using const_iterator = std::vector::const_iterator; using const_reverse_iterator = std::vector::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: struct const_hdr_iterator { using iterator_category = std::input_iterator_tag; using difference_type = std::ptrdiff_t; using value_type = std::string const; using pointer = value_type *; using reference = value_type &; friend MailHeaders; using Comparator = bool(*)(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 }; using const_reverse_hdr_iterator = std::reverse_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-6.07.01/mailheaders/rbegin.f0000664000175000017500000000016214673353434016013 0ustar frankfrankinline FBB::MailHeaders::const_reverse_iterator FBB::MailHeaders::rbegin() const { return d_lines.rbegin(); } bobcat-6.07.01/mailheaders/oparrow.f0000664000175000017500000000015714673353434016242 0ustar frankfrankinline std::string const *FBB::MailHeaders::const_hdr_iterator::operator->() const { return &*d_current; } bobcat-6.07.01/mailheaders/beginh.f0000664000175000017500000000043214673353434016001 0ustar frankfrankinline FBB::MailHeaders::const_hdr_iterator FBB::MailHeaders::beginh() const { return const_hdr_iterator(this, begin()); // returns iterator over all headers // matching d_hdr by the d_match type } bobcat-6.07.01/mailheaders/opneq.f0000664000175000017500000000026614673353434015674 0ustar frankfrankinline bool FBB::MailHeaders::const_hdr_iterator::operator!=( const_hdr_iterator const &other) const { return d_current != other.d_current; } bobcat-6.07.01/mailheaders/rendh.f0000664000175000017500000000021114673353434015640 0ustar frankfrankinline FBB::MailHeaders::const_reverse_hdr_iterator FBB::MailHeaders::rendh() const { return const_reverse_hdr_iterator(beginh()); } bobcat-6.07.01/mailheaders/partial.f0000664000175000017500000000033314673353434016201 0ustar frankfrankinline bool FBB::MailHeaders::const_hdr_iterator::partial( std::string const &hdr, std::string const &key) { return hdr.substr(0, hdr.find(':')).find(key) != std::string::npos; } bobcat-6.07.01/mailheaders/opeq.f0000664000175000017500000000026614673353434015516 0ustar frankfrankinline bool FBB::MailHeaders::const_hdr_iterator::operator==( const_hdr_iterator const &other) const { return d_current == other.d_current; } bobcat-6.07.01/mailheaders/setheaderiterator.f0000664000175000017500000000017614673353434020270 0ustar frankfrankinline void FBB::MailHeaders::setHeaderIterator(char const *header, Match match) { d_hdr = header; d_match = match; } bobcat-6.07.01/mailheaders/endh.f0000664000175000017500000000030614673353434015463 0ustar frankfrankinline FBB::MailHeaders::const_hdr_iterator FBB::MailHeaders::endh() const { // returns address of the sentinel return const_hdr_iterator(this, end()); } bobcat-6.07.01/mailheaders/opdec.f0000664000175000017500000000023314673353434015636 0ustar frankfrankinline FBB::MailHeaders::const_hdr_iterator &FBB::MailHeaders::const_hdr_iterator::operator--() { d_current = lookdown(d_current); return *this; } bobcat-6.07.01/mailheaders/mailheaders.ih0000664000175000017500000000041414736315237017175 0ustar frankfrank#include "mailheaders" #include #include "../fswap/fswap" #include "casefull.f" #include "caseinitial.f" #include "casepartial.f" #include "fail.f" #include "full.f" #include "initial.f" #include "partial.f" using namespace std; using namespace FBB; bobcat-6.07.01/mailheaders/driver/0000775000175000017500000000000014737552575015702 5ustar frankfrankbobcat-6.07.01/mailheaders/driver/build0000775000175000017500000000005614673353434016720 0ustar frankfrank#!/bin/bash g++ -o driver driver.cc -lbobcat bobcat-6.07.01/mailheaders/driver/driver.cc0000664000175000017500000000227414673353434017501 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-6.07.01/mailheaders/driver/driver.h0000664000175000017500000000017014673353434017334 0ustar frankfrank#ifndef INCLUDED_DRIVER_H_ #define INCLUDED_DRIVER_H_ #include #include namespace FBB { } #endif bobcat-6.07.01/mailheaders/driver/spam10000664000175000017500000000644214673353434016644 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-6.07.01/mailheaders/driver/spam20000664000175000017500000000431414673353434016641 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-6.07.01/mailheaders/driver/mail.hein0000664000175000017500000001317114673353434017464 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-6.07.01/mailheaders/driver/driver.ih0000664000175000017500000000014614673353434017510 0ustar frankfrank#include "driver.h" #include #include using namespace std; using namespace FBB; bobcat-6.07.01/mailheaders/driver/mail0000664000175000017500000001337514673353434016550 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-6.07.01/mapbase/0000775000175000017500000000000014736315237013530 5ustar frankfrankbobcat-6.07.01/mapbase/data.cc0000664000175000017500000000011514673353434014746 0ustar frankfrank#include "mapbase.ih" size_t MapBase::s_pageSize = sysconf(_SC_PAGE_SIZE); bobcat-6.07.01/mapbase/readingmaplength.cc0000664000175000017500000000051314673353434017350 0ustar frankfrank#include "mapbase.ih" bool MapBase::readingMapLength() { if (d_offset >= d_orgSize) return false; // no chars for the reading mmap // otherwise use a full/partial buffer d_mapLength = min(d_orgSize, d_offset + d_bufferSize) - d_offset; return true; } bobcat-6.07.01/mapbase/setabspos.cc0000664000175000017500000000215014673353434016041 0ustar frankfrank#define XERR #include "mapbase.ih" ios::off_type MapBase::setAbsPos(ios::off_type pos, ios::seekdir where) { d_absolute = true; switch (where) { case ios::beg: d_absPos = pos; break; // if there's no buffer yet then d_offset == 0, // pptr() == 0, and eback() == 0. In that case use // d_absPos as current position. // but what happens if there is a buffer and d_absPos is set? // then the current position isn't important anymore and so once // d_absPos is explicitly set d_absPos should be used as // reference. case ios::cur: if (d_absolute) d_absPos += pos; else { d_absPos = pos + d_offset + (gptr() - eback()); d_absolute = false; } break; case ios::end: d_absPos = pos + d_fileSize; break; } //xerr("absPos: " << d_absPos); return d_absPos; // may be < 0, handled by seek{pos,off} } bobcat-6.07.01/mapbase/moveassign.cc0000664000175000017500000000121414673353434016211 0ustar frankfrank#include "mapbase.ih" void MapBase::moveAssign(MapBase &&tmp) { unmap(); // osync for writing modes? d_writing = tmp.d_writing; d_mMapped = tmp.d_mMapped; d_fname = std::move(tmp.d_fname); d_mode = tmp.d_mode; d_offset = tmp.d_offset; d_absPos = tmp.d_absPos; d_absolute = tmp.d_absolute; d_cp = tmp.d_cp; d_fileSize = tmp.d_fileSize; d_orgSize = tmp.d_orgSize; d_enlargedSize = tmp.d_enlargedSize; d_bufferSize = tmp.d_bufferSize; d_mapLength = d_bufferSize; tmp.d_mMapped = false; // prevent actions by tmp's destructor tmp.d_orgSize = 0; tmp.d_fileSize = 0; } bobcat-6.07.01/mapbase/mapbase0000664000175000017500000000643014673353434015067 0ustar frankfrank#ifndef INCLUDED_BOBCAT_MAPBASE_ #define INCLUDED_BOBCAT_MAPBASE_ #include #include #include // d_absPos holds the current absolute position. It is used when seek // operations specify ios::cur, and updated when xs{get,put} // namespace FBB { class MapBase: public std::streambuf { bool d_writing; // writing is OK bool d_mMapped; std::string d_fname; std::ios::openmode d_mode; size_t d_fileSize; // filesize (may be enlarged when // writing) size_t d_orgSize; // original fileSize size_t d_enlargedSize; // enlarged fileSize size_t d_bufferSize; // configured buffer size size_t d_mapLength; // length of the mmap buffer size_t d_offset; // always x * s_pageSize size_t d_absPos; // the abs. pos bool d_absolute; // if true: use d_absPos with // relative position computations char *d_cp; // begin of the mmap area static size_t s_pageSize; protected: using IOS = std::ios; MapBase(); // only used when moving // 1. // bufSize 0 means: the file's size // used for create() // append K, M or G for KB, MB // or GB. BufSize is at least // 10 * s_pageSize // mode is only used for create(): for non-existing // writable files MapBase(std::string const &fname, IOS::openmode iosMode, // 2. char const *bufSize, mode_t mode = 0); ~MapBase(); void moveAssign(MapBase &&tmp); IOS::off_type setAbsPos(IOS::off_type pos, IOS::seekdir where); bool readingMapLength(); void writingMapLength(); void setpBuf(); // calls setp() when writing bool map(int protection); // PROT_READ, PROT_WRITE or both size_t absPos() const; // .f bool append() const; // .f std::string const &fname() const; // .f size_t fileSize() const; // .f size_t offset() const; // .f size_t mapLength() const; // .f IOS::openmode mode() const; // .f size_t realSize() const; // .f char *begin(); // .f char *next(); // .f char *end(); // .f void osync(); private: void unmap(); void setFileSize(mode_t mode); // mode: used with creat() void setBufLength(char const *bufSize); }; #include "mapbase.f" // bool nextOffset(); // void setPos(size_t pos); // .f } // FBB #endif bobcat-6.07.01/mapbase/osync.cc0000664000175000017500000000133014673353434015170 0ustar frankfrank#define XERR #include "mapbase.ih" void MapBase::osync() { if (not d_mMapped) return; size_t nWritten = pptr() - d_cp ; // #bytes written into the buffer //xerr("file size " << d_fileSize << ", offset: " << d_offset << \X======== //", nWritten: " << nWritten); if (nWritten > 0) // some bytes were written { if (msync(d_cp, nWritten, MS_SYNC) != 0) cerr << "msync " << d_fname << ": from " << d_offset << ", nBytes = " << nWritten << " failed\n"; if (size_t size = d_offset + nWritten; d_fileSize < size) {//xerr("enlarging file size from " << d_fileSize << " to " << size); d_fileSize = size; } } unmap(); } bobcat-6.07.01/mapbase/setbuflength.cc0000664000175000017500000000174114673353434016535 0ustar frankfrank#include "mapbase.ih" void MapBase::setBufLength(char const *bufSize) { if (bufSize == 0) d_bufferSize = 0; else { string spec{ bufSize }; d_bufferSize = stoul(spec); switch (spec.back()) // extend by K,M,G suffixes { case 'K': d_bufferSize *= 1024; break; case 'M': d_bufferSize *= 1024 * 1024; break; case 'G': d_bufferSize *= 1024 * 1024 * 1024; break; } } if (d_bufferSize < 10 * s_pageSize) // the buffer is at least d_bufferSize = 10 * s_pageSize; // 10 * page size // for reading: bufLength is at // most equal to the file size if (not d_writing and d_bufferSize > d_orgSize) d_bufferSize = d_orgSize; // then use the file size } bobcat-6.07.01/mapbase/resize.cc0000664000175000017500000000010614673353434015336 0ustar frankfrank//#include "mapbase.ih" // //void MapBase::resize() //{ // //} // bobcat-6.07.01/mapbase/test/0000775000175000017500000000000014673353434014510 5ustar frankfrankbobcat-6.07.01/mapbase/test/get.cc0000664000175000017500000000033214673353434015574 0ustar frankfrank#include "main.ih" bool get(size_t &var, char const *prompt) { string pos; cout << prompt << ": "; cin >> pos; if (pos.front() == '-') return false; var = stoul(pos); return true; } bobcat-6.07.01/mapbase/test/data.cc0000664000175000017500000000045314673353434015732 0ustar frankfrank#include "main.ih" size_t bufSize = 10; bool read = false; size_t fileSize = 0; size_t offset = 0; size_t currentPos = 0; size_t realSize = 0; size_t nToDo; char const *what; char const *fromTo; char const *seek; void (*file)(); void (*setRW)(); //bool void (*eofCheck)(); bool (*checkFit)(); bobcat-6.07.01/mapbase/test/writefit.cc0000664000175000017500000000047114673353434016656 0ustar frankfrank#include "main.ih" bool writeFit() { if (bufSize < nToDo) // characters don't fit return false; cout << " fits: writing " << nToDo << " to " << currentPos << '\n'; currentPos += nToDo; if (realSize < currentPos) realSize = currentPos; return true; } bobcat-6.07.01/mapbase/test/prepare.cc0000664000175000017500000000104514673353434016455 0ustar frankfrank#include "main.ih" void prepare(int argc, char **argv) { if (argc == 2 and *argv[1] == 'r') // reading { read = true; what = "read"; seek = "seekg"; file = nop; eofCheck = atEOF; setRW = setRead; fromTo = " from "; checkFit = readFit; } else { what = "write"; seek = "seekp"; file = setWrite; // eofCheck = boolNop; eofCheck = nop; setRW = setWrite; fromTo = " to "; checkFit = writeFit; } } bobcat-6.07.01/mapbase/test/readfit.cc0000664000175000017500000000040314673353434016432 0ustar frankfrank#include "main.ih" bool readFit() { if (offset + bufSize < currentPos + nToDo) // characters don't fit return false; cout << " fits: reading " << nToDo << " from " << currentPos << '\n'; currentPos += nToDo; return true; } bobcat-6.07.01/mapbase/test/run.cc0000664000175000017500000000106314673353434015623 0ustar frankfrank#include "main.ih" void run() { if (not read) realSize = fileSize; while (get(currentPos, seek)) { (*eofCheck)(); // for reading, no further action try { while (get(nToDo, "nToDo")) { (*setRW)(); // setRead or setWrite process(); } } catch (...) { break; } // cout << "mmap buffer from " << offset << " to " << // (offset + bufSize) << '\n'; } } bobcat-6.07.01/mapbase/test/ateof.cc0000664000175000017500000000025014673353434016112 0ustar frankfrank#include "main.ih" //bool void atEOF() { if (not read or currentPos < fileSize) return;// false; cout << "seekg beyond EOF\n"; // return true; } bobcat-6.07.01/mapbase/test/checkresize.cc0000664000175000017500000000033014673353434017312 0ustar frankfrank#include "main.ih" void checkResize() { if (read) return; cout << "\nfinal file size: " << fileSize; if (realSize < fileSize) cout << ", truncated (resized) to " << realSize << '\n'; } bobcat-6.07.01/mapbase/test/setread.cc0000664000175000017500000000063714673353434016454 0ustar frankfrank#include "main.ih" void setRead() { if (currentPos + nToDo > fileSize) { size_t nAvail = fileSize - currentPos; if (nAvail == 0) { cout << "at EOF: can't read " << nToDo << " bytes\n"; throw false; } cout << "available till EOF: " << nAvail << ": reducing N to read to " << nAvail << '\n'; nToDo = nAvail; } } bobcat-6.07.01/mapbase/test/nop.cc0000664000175000017500000000011114673353434015604 0ustar frankfrank#include "main.ih" void nop() {} bool boolNop() { return false; } bobcat-6.07.01/mapbase/test/icmconf0000664000175000017500000000112014673353434016043 0ustar frankfrank// see also ~/.icmake/icmconf.mod for a possible module-using icmconf //#define CLS #define MULTICOMP "jobs -q" #define MAIN "main.cc" #define SOURCES "*.cc" #define OBJ_EXT ".o" #define TMP_DIR "tmp" #define USE_ECHO ON #define IH ".ih" #define CXX "ccache g++" #define CXXFLAGS "-Wall -Werror -O2 -fdiagnostics-color=never" #define REFRESH #define LDFLAGS "-s" #define ADD_LIBRARIES "" #define ADD_LIBRARY_PATHS "" #define DEFCOM "program" bobcat-6.07.01/mapbase/test/main.cc0000664000175000017500000000044114673353434015742 0ustar frankfrank#include "main.ih" // argc == 2 and *argv[1] == 'r' then reading int main(int argc, char **argv) { prepare(argc, argv); while (get(fileSize, "file size")) { run(); checkResize(); // when writing cout << '\n'; } } bobcat-6.07.01/mapbase/test/process.cc0000664000175000017500000000122514673353434016475 0ustar frankfrank#include "main.ih" void process() { while (true) { map(); if ((*checkFit)()) { nToDo = 0; break; } size_t nAvail = offset + bufSize - currentPos; nToDo -= nAvail; cout << " " << what << ' ' << nAvail << fromTo << currentPos << '\n'; currentPos = offset + bufSize; } cout << " next offset at " << currentPos << '\n'; } // // cout << "next [Yn]? "; // string line; // getline(cin, line); // if (not line.length() or line.front() != 'y') // break; bobcat-6.07.01/mapbase/test/map.cc0000664000175000017500000000023314673353434015572 0ustar frankfrank#include "main.ih" void map() { offset = currentPos / bufSize * bufSize; cout << "map: at offset " << offset << ": " << bufSize << " bytes\n"; } bobcat-6.07.01/mapbase/test/main.ih0000664000175000017500000000125514673353434015761 0ustar frankfrank#include #include using namespace std; extern bool read; extern size_t fileSize; extern size_t bufSize; extern size_t offset; extern size_t currentPos; extern size_t realSize; extern size_t nToDo; extern size_t realSize; extern char const *what; extern char const *fromTo; extern char const *seek; extern void (*file)(); extern void (*eofCheck)(); void nop(); bool boolNop(); void prepare(int argc, char **argv); bool get(size_t &var, char const *prompt); void map(); extern bool (*checkFit)(); bool readFit(); bool writeFit(); void process(); extern void (*setRW)(); void setRead(); void setWrite(); void checkResize(); void atEOF(); void run(); bobcat-6.07.01/mapbase/test/flow.txt0000664000175000017500000000205214673353434016217 0ustar frankfrankcurrentpos initially 0 READ WRITE ----------------------------------------------------------------- get filesize set realSize seekg: seekp: (reducelength()?) reduce nTodo (pos) to pos > fileSize -> # bytes to fileSize enlarge fileSize (setwrite) -> EOF if nTdoDo (setRead) map: fd = open cpt offet, bufSize bufPos = pos - offset d_cp = mmap(bufSize, offset) imapbuf: omapbuf: setg... setp... maybe enlarge realSize at destruction: resize file to realSize bobcat-6.07.01/mapbase/test/setwrite.cc0000664000175000017500000000035514673353434016670 0ustar frankfrank#include "main.ih" void setWrite() // writing { if (currentPos + nToDo > fileSize) { fileSize = (currentPos + nToDo + bufSize) / bufSize * bufSize; cout << "\nnew file size: " << fileSize << '\n'; } } bobcat-6.07.01/mapbase/icmconf0000664000175000017500000000010114673353434015062 0ustar frankfrank#define LIBRARY "mapbase" #include "../icmconf.lib" bobcat-6.07.01/mapbase/mapbase2.cc0000664000175000017500000000107414673353434015534 0ustar frankfrank#define XERR #include "mapbase.ih" MapBase::MapBase(std::string const &name, ios::openmode iosMode, char const *bufSize, mode_t mode) : d_writing((iosMode & (ios::out | ios::app)) != 0), d_mMapped(false), d_fname(name), d_mode(iosMode), d_offset(0), d_absPos(0), d_absolute(true), d_cp(0) { setFileSize(mode); d_fileSize = d_orgSize; d_enlargedSize = d_orgSize; setBufLength(bufSize); d_mapLength = d_bufferSize; if ((iosMode & ios::ate) or (iosMode & ios::app)) d_absPos = d_fileSize; } bobcat-6.07.01/mapbase/setpbuf.cc0000664000175000017500000000031614673353434015510 0ustar frankfrank#define XERR #include "mapbase.ih" void MapBase::setpBuf() { setp(d_cp, d_cp + d_mapLength); pbump(d_absPos - d_offset); //xerr("MapBase " << d_absPos << " pbump to " << (d_absPos - d_offset)); } bobcat-6.07.01/mapbase/unmap.cc0000664000175000017500000000032214673353434015155 0ustar frankfrank#include "mapbase.ih" void MapBase::unmap() { if (not d_mMapped) return; if (munmap(d_cp, d_mapLength) != 0) cerr << "munmap for " << fname() << " failed\n"; d_mMapped = false; } bobcat-6.07.01/mapbase/destructor.cc0000664000175000017500000000022314673353434016233 0ustar frankfrank#include "mapbase.ih" MapBase::~MapBase() { unmap(); if (d_orgSize < d_fileSize) fs::resize_file(d_fname, d_fileSize); } bobcat-6.07.01/mapbase/map.cc0000664000175000017500000000265114673353434014621 0ustar frankfrank#define XERR #include "mapbase.ih" bool MapBase::map(int protection) // PROT_READ, PROT_WRITE or both { if (not d_writing and d_absPos >= d_orgSize) // nothing to map at EOF return false; // when reading unmap(); // WIP: if (not d_absolute) d_absPos = d_offset + pptr() - pbase(); d_offset = d_absPos / s_pageSize * s_pageSize; // d_offset <= d_absPos if (d_writing) writingMapLength(); else if (not readingMapLength()) // set the reading mapLength return true; // no length: don't mmap //xerr("absPos = " << d_absPos << ", offset " << d_offset <<\X========= //", length: " << d_mapLength << ", enlarged size: " << d_enlargedSize); int fd = open(d_fname.c_str(), protection == PROT_READ ? O_RDONLY : O_RDWR); if (fd == -1) // file can't be opened throw Exception{} << "can't open " << d_fname; // d_mapLength may exceed the file's size d_cp = static_cast( // mmap the required buffer mmap(0, d_mapLength, protection, MAP_SHARED, fd, d_offset) ); close(fd); if (d_cp == MAP_FAILED) // mapping failed throw Exception{} << "mmap for " << d_fname << " failed"; d_mMapped = true; // no set{pg} because they're called by {io}mapbuf return true; } bobcat-6.07.01/mapbase/mapbase.ih0000664000175000017500000000042214736315237015460 0ustar frankfrank#include "../xerr/xerr.ih" #include "mapbase" #include #include #include #include #include #include #include using namespace std; using namespace FBB; namespace fs = filesystem; bobcat-6.07.01/mapbase/mapbase1.cc0000664000175000017500000000006214673353434015527 0ustar frankfrank#include "mapbase.ih" MapBase::MapBase() //: { } bobcat-6.07.01/mapbase/mapbase.f0000664000175000017500000000146714673353434015320 0ustar frankfrank//inline void MapBase::setPos(size_t pos) //{ // d_absPos = pos; //} // inline size_t MapBase::absPos() const { return d_absPos; } inline std::string const &MapBase::fname() const { return d_fname; } inline std::ios::openmode MapBase::mode() const { return d_mode; } inline size_t MapBase::fileSize() const { return d_fileSize; } inline size_t MapBase::realSize() const { return d_fileSize; } inline size_t MapBase::offset() const { return d_offset; } inline size_t MapBase::mapLength() const { return d_mapLength; } inline char *MapBase::begin() { return d_cp; } inline char *MapBase::next() { return d_cp + d_absPos - d_offset; } inline char *MapBase::end() { return d_cp + d_mapLength; } inline bool MapBase::append() const { return (d_mode & IOS::app) != 0; } bobcat-6.07.01/mapbase/writingmaplength.cc0000664000175000017500000000042614673353434017425 0ustar frankfrank#include "mapbase.ih" void MapBase::writingMapLength() { d_mapLength = d_bufferSize; if (d_offset + d_bufferSize > d_enlargedSize) { d_enlargedSize = d_offset + d_bufferSize; // enlarge the file fs::resize_file(d_fname, d_enlargedSize); } } bobcat-6.07.01/mapbase/setfilesize.cc0000664000175000017500000000166414673353434016375 0ustar frankfrank#define XERR #include "mapbase.ih" void MapBase::setFileSize(mode_t mode) try { // ios:: // in the file must exist // out recreates unless also in // ate start initially at the end. Needs in to prevent rewriting // trunc truncates, with in|out reading also OK // app when writing always reposition to the end if (d_mode & ios::app) d_mode |= ios::out; if ( (d_mode & ios::trunc) // truncate or or // out-mode w/o in-mode ((d_mode & ios::out) and (d_mode & ios::in) == 0) ) { if (creat(d_fname.c_str(), mode) == -1) throw -1; d_orgSize = 0; return; } Stat stat{ d_fname }; // obtain the file's info if (not stat) throw -1; d_orgSize = stat.size(); } catch (...) { throw Exception{} << "can't open " << d_fname; } bobcat-6.07.01/mbuf/0000775000175000017500000000000014736742656013062 5ustar frankfrankbobcat-6.07.01/mbuf/xsputn.cc0000664000175000017500000000030114673353434014714 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-6.07.01/mbuf/showlinenr.cc0000664000175000017500000000016314673353434015551 0ustar frankfrank#include "mbuf.ih" inline void Mbuf::setLineNr(size_t lineNr) { d_showLineNr = true; d_lineNr = lineNr; } bobcat-6.07.01/mbuf/overflow.cc0000664000175000017500000000014614673353434015225 0ustar frankfrank#include "mbuf.ih" int Mbuf::overflow(int c) { atFirstChar(); d_ostr.put(c); return c; } bobcat-6.07.01/mbuf/setcount.f0000664000175000017500000000010214673353434015056 0ustar frankfrankinline void Mbuf::setCount(size_t count) { d_count = count; } bobcat-6.07.01/mbuf/reset1.cc0000664000175000017500000000070514673353434014566 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-6.07.01/mbuf/reset3.cc0000664000175000017500000000070414673353434014567 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-6.07.01/mbuf/reset2.cc0000664000175000017500000000055714673353434014574 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-6.07.01/mbuf/mbuf1.cc0000664000175000017500000000040614673353434014373 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-6.07.01/mbuf/inspectofstr.cc0000664000175000017500000000024614673353434016106 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-6.07.01/mbuf/atfirstchar.cc0000664000175000017500000000103214673353434015667 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-6.07.01/mbuf/throwing.f0000664000175000017500000000010214673353434015053 0ustar frankfrankinline void Mbuf::throwing(bool ifTrue) { d_throw = ifTrue; } bobcat-6.07.01/mbuf/maxcount.f0000664000175000017500000000010014673353434015046 0ustar frankfrankinline size_t Mbuf::maxCount() const { return d_maxCount; } bobcat-6.07.01/mbuf/lineexcess.f0000664000175000017500000000010214673353434015354 0ustar frankfrankinline bool Mbuf::lineExcess() const { return d_lineExcess; } bobcat-6.07.01/mbuf/mbuf.cc0000664000175000017500000000002314673353434014305 0ustar frankfrank#include "mbuf.ih" bobcat-6.07.01/mbuf/count.f0000664000175000017500000000007214673353434014350 0ustar frankfrankinline size_t Mbuf::count() const { return d_count; } bobcat-6.07.01/mbuf/linetag.f0000664000175000017500000000011214673353434014636 0ustar frankfrankinline std::string const &Mbuf::lineTag() const { return d_lineTag; } bobcat-6.07.01/mbuf/mbuf3.cc0000664000175000017500000000127414673353434014401 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-6.07.01/mbuf/throws.f0000664000175000017500000000007114673353434014545 0ustar frankfrankinline bool Mbuf::throws() const { return d_throw; } bobcat-6.07.01/mbuf/showtag.cc0000664000175000017500000000037314673353434015040 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-6.07.01/mbuf/sync.cc0000664000175000017500000000014414673353434014334 0ustar frankfrank#include "mbuf.ih" int Mbuf::sync() { d_ostr.flush(); d_firstChar = true; return 0; } bobcat-6.07.01/mbuf/setlinenr.cc0000664000175000017500000000015414673353434015364 0ustar frankfrank#include "mbuf.ih" void Mbuf::setLineNr(size_t lineNr) { d_lineNr = lineNr; d_showLineNr = true; } bobcat-6.07.01/mbuf/settag.cc0000664000175000017500000000020414673353434014644 0ustar frankfrank#include "mbuf.ih" void Mbuf::setTag(string const &tag) { d_tag = not tag.empty() && (tag.front() != '[') ? '[' + tag : tag; } bobcat-6.07.01/mbuf/nolinenr.f0000664000175000017500000000007314673353434015045 0ustar frankfrankinline void Mbuf::noLineNr() { d_showLineNr = false; } bobcat-6.07.01/mbuf/setmaxcount.f0000664000175000017500000000011614673353434015571 0ustar frankfrankinline void Mbuf::setMaxCount(size_t maxCount) { d_maxCount = maxCount; } bobcat-6.07.01/mbuf/mbuf0000664000175000017500000000610614673353434013731 0ustar frankfrank#ifndef INCLUDED_BOBCAT_MBUF_ #define INCLUDED_BOBCAT_MBUF_ #include #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-6.07.01/mbuf/mbuf2.cc0000664000175000017500000000054214673353434014375 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-6.07.01/mbuf/setlinetag.f0000664000175000017500000000012614673353434015357 0ustar frankfrankinline void Mbuf::setLineTag(std::string const &lineTag) { d_lineTag = lineTag; } bobcat-6.07.01/mbuf/tag.f0000664000175000017500000000010214673353434013765 0ustar frankfrankinline std::string const &Mbuf::tag() const { return d_tag; } bobcat-6.07.01/mbuf/mbuf.ih0000664000175000017500000000016714736315237014330 0ustar frankfrank#include "mbuf" #include #include #include using namespace std; using namespace FBB; bobcat-6.07.01/mbuf/driver/0000775000175000017500000000000014737552575014355 5ustar frankfrankbobcat-6.07.01/mbuf/driver/build0000775000175000017500000000050614673353434015373 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-6.07.01/mbuf/driver/driver.cc0000664000175000017500000000127414673353434016153 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-6.07.01/milter/0000775000175000017500000000000014736742656013425 5ustar frankfrankbobcat-6.07.01/milter/body.cc0000664000175000017500000000015114673353434014656 0ustar frankfrank#include "milter.ih" sfsistat Milter::body(unsigned char *text, size_t length) { return CONTINUE; } bobcat-6.07.01/milter/milter.f0000664000175000017500000001205514673353434015063 0ustar frankfrankinline bool Milter::start() { return smfi_main() == MI_SUCCESS; } inline void Milter::stop() { smfi_stop(); } inline std::string const &Milter::name() { return s_name; } // protected: inline bool Milter::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. inline bool Milter::addRecipient(std::string const &rcptName) { return smfi_addrcpt(d_ctx, const_cast(rcptName.c_str())) == SUCCESS; } inline bool Milter::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; } // NEW: // envelope is the plain envelope address like who@domain // smfi_chgfrom's 3rd arg not used (ESMTP arguments) // this function must be called from inline int Milter::changeEnvelope(std::string const &envelope) { return smfi_chgfrom(d_ctx, const_cast(envelope.c_str()), 0); // return chgfrom(d_ctx, const_cast(envelope.c_str())) // == SUCCESS; } inline bool Milter::deleteRecipient(std::string const &rcptName) { return smfi_delrcpt(d_ctx, const_cast(rcptName.c_str())) == SUCCESS; } inline SMFICTX *Milter::id() const { return d_ctx; } inline bool Milter::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())); } inline bool Milter::openSocket(bool removeIfTrue) { return smfi_opensocket(removeIfTrue) == SUCCESS; } inline bool Milter::quarantine(std::string const &reason) { return smfi_quarantine(d_ctx, const_cast(reason.c_str())) == SUCCESS; } inline bool Milter::replaceBody(std::string const &body) { return smfi_replacebody(d_ctx, reinterpret_cast ( const_cast(body.c_str()) ), body.length()) == SUCCESS; } inline bool Milter::setBacklog(size_t backlog) { return smfi_setbacklog(backlog) == SUCCESS; } inline void Milter::setConnection(std::string const &socketName) { smfi_setconn(const_cast(socketName.c_str())); } inline bool Milter::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, ...) inline void Milter::setTimeout(size_t seconds) { smfi_settimeout(seconds); } inline char const *Milter::symval(std::string const &name) const { return smfi_getsymval(d_ctx, const_cast(name.c_str())); } inline bool Milter::wait() // from eom() only { return smfi_progress(d_ctx) == SUCCESS; } bobcat-6.07.01/milter/data.cc0000664000175000017500000000016614673353434014640 0ustar frankfrank#include "milter.ih" string Milter::s_name; Milter *Milter::s_mp; unordered_map Milter::s_map; bobcat-6.07.01/milter/eom.cc0000664000175000017500000000010614673353434014501 0ustar frankfrank#include "milter.ih" sfsistat Milter::eom() { return CONTINUE; } bobcat-6.07.01/milter/mclose.cc0000664000175000017500000000056114673353434015210 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. { ret = it->second->close(); delete it->second; // delete this Milter s_map.erase(it); // and erase from the map } return ret; } bobcat-6.07.01/milter/sender.cc0000664000175000017500000000012414673353434015201 0ustar frankfrank#include "milter.ih" sfsistat Milter::sender(char **argv) { return CONTINUE; } bobcat-6.07.01/milter/recipient.cc0000664000175000017500000000012714673353434015706 0ustar frankfrank#include "milter.ih" sfsistat Milter::recipient(char **argv) { return CONTINUE; } bobcat-6.07.01/milter/eoh.cc0000664000175000017500000000010614673353434014474 0ustar frankfrank#include "milter.ih" sfsistat Milter::eoh() { return CONTINUE; } bobcat-6.07.01/milter/install.cc0000664000175000017500000000055414673353434015376 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-6.07.01/milter/icmconf0000664000175000017500000000010214637221551014741 0ustar frankfrank#define LIBRARY "bcmilter" #include "../icmconf.lib" bobcat-6.07.01/milter/milter0000664000175000017500000001504314673353434014637 0ustar frankfrank#ifndef INCLUDED_BOBCAT_MILTER_ #define INCLUDED_BOBCAT_MILTER_ #include #include #include #include #include #include namespace FBB { class Milter { static std::string s_name; static Milter *s_mp; static bool s_callClose; using iterator = std::unordered_map::iterator; static std::unordered_map s_map; SMFICTX *d_ctx; // for local use only public: virtual ~Milter(); // empty using callback_set = size_t; enum CallBack // using exp(2) to select the callbacks { // to use in initialize.cc 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 }; using flag_set = unsigned long; 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 // NEW: CHANGE_ENVELOPE = SMFIF_CHGFROM, // filter may change 'From ' // (envelope sender) DELETE_RECIPIENTS = SMFIF_DELRCPT, // filter may delete recipients QUARANTINE = SMFIF_QUARANTINE, // filter may quarantine // envelope // CHG: ALL_FLAGS = ADD_HEADERS | ADD_RECIPIENTS | CHANGE_BODY | CHANGE_HEADERS | CHANGE_ENVELOPE | 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(); // .f static void stop(); // .f static std::string const &name(); // .f protected: Milter() = default; Milter(Milter const &other) = delete; bool addHeader(std::string const &hdrName, // .f std::string const &hdrValue); // from eom() only // hdr-name: without : // hdr-value: \n and \t ok. bool addRecipient(std::string const &rcptName); // .f bool changeHeader(std::string const &hdrName, // .f unsigned headerNr, std::string const &hdrValue); int changeEnvelope(std::string const &envelope); // .f bool deleteRecipient(std::string const &rcptName); // .f SMFICTX *id() const; // .f bool insertHeader(size_t hdrIdx, std::string const &hdrName, // .f std::string const &hdrValue); static bool openSocket(bool removeIfTrue = true); // .f bool quarantine(std::string const &reason); // .f bool replaceBody(std::string const &body); // .f static bool setBacklog(size_t backlog = 5); // .f static void setConnection(std::string const &socketName); // .f // .d bool setReply(std::string const &rcode, std::string const &xcode = "", std::string const &msg = ""); // can't do smfi_setmlreply(ctx, ...) // since there is no smfi_Vsetmlreply(ctx, ...) static void setTimeout(size_t seconds = 7210); // .f char const *symval(std::string const &name) const; // .f #if SMFI_VERSION > 2 virtual sfsistat unknown(char const *ptr); #endif bool wait(); // from eom() only // .f private: // // tmp // virtual int chgfrom(SMFICTX *, char *) = 0; virtual sfsistat abort(); virtual sfsistat body(unsigned char *text, size_t length); 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 virtual sfsistat eoh(); virtual sfsistat eom(); virtual sfsistat header(char *headerf, char *headerv); virtual sfsistat helo(char *helohost); virtual sfsistat recipient(char **argv); virtual sfsistat sender(char **argv); static Milter *install(SMFICTX *ctx); static sfsistat mConnect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr); static sfsistat mAbort(SMFICTX *ctx); static sfsistat mBody(SMFICTX *ctx, unsigned char *body, size_t len); static sfsistat mSender(SMFICTX *ctx, char **argv); static sfsistat mRecipient(SMFICTX *ctx, char **argv); static sfsistat mEoh(SMFICTX *ctx); static sfsistat mEom(SMFICTX *ctx); static sfsistat mHeader(SMFICTX *ctx, char *headerf, char *headerv); static sfsistat mHelo(SMFICTX *ctx, char *helohost); static sfsistat mClose(SMFICTX *ctx); #if SMFI_VERSION > 2 static sfsistat mUnknown(SMFICTX *ctx, char const *ptr); #endif /* SMFI_VERSION > 2 */ #if SMFI_VERSION > 3 static sfsistat mData(SMFICTX *ctx); #endif /* SMFI_VERSION > 3 */ }; #include "milter.f" } #endif bobcat-6.07.01/milter/close.cc0000664000175000017500000000020714673353434015030 0ustar frankfrank#include "milter.ih" sfsistat Milter::close() { smfi_setpriv(d_ctx, 0); // delete this d_ctx data return CONTINUE; } bobcat-6.07.01/milter/helo.cc0000664000175000017500000000012514673353434014651 0ustar frankfrank#include "milter.ih" sfsistat Milter::helo(char *helohost) { return CONTINUE; } bobcat-6.07.01/milter/destructor.cc0000664000175000017500000000005314673353434016120 0ustar frankfrank#include "milter.ih" Milter::~Milter() {} bobcat-6.07.01/milter/abort.cc0000664000175000017500000000011014673353434015023 0ustar frankfrank#include "milter.ih" sfsistat Milter::abort() { return CONTINUE; } bobcat-6.07.01/milter/header.cc0000664000175000017500000000014514673353434015154 0ustar frankfrank#include "milter.ih" sfsistat Milter::header(char *headerf, char *headerv) { return CONTINUE; } bobcat-6.07.01/milter/unknown.cc0000664000175000017500000000016714673353434015427 0ustar frankfrank#include "milter.ih" #if SMFI_VERSION > 2 sfsistat Milter::unknown(char const *ptr) { return CONTINUE; } #endif bobcat-6.07.01/milter/initialize.cc0000664000175000017500000000507114673353434016070 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; callbacks |= CLOSE; // always call mClose() // see the 'connection info filter names in libmilter/mfapi.h: for (size_t callback = 1; callback & ALL_CALLBACKS; callback <<= 1) { switch (callback & callbacks) { case CONNECT: descr.xxfi_connect = &mConnect; // called virtual connect() break; // same for other members 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-6.07.01/milter/milter.ih0000664000175000017500000000253714736315237015241 0ustar frankfrank#include "milter" using namespace FBB; inline sfsistat Milter::mConnect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr) { return install(ctx)->connect(hostname, hostaddr); } inline sfsistat Milter::mAbort(SMFICTX *ctx) { return install(ctx)->abort(); } inline sfsistat Milter::mBody(SMFICTX *ctx, unsigned char *body, size_t len) { return Milter::install(ctx)->body(body, len); } inline sfsistat Milter::mSender(SMFICTX *ctx, char **argv) { return install(ctx)->sender(argv); } inline sfsistat Milter::mRecipient(SMFICTX *ctx, char **argv) { return install(ctx)->recipient(argv); } inline sfsistat Milter::mEoh(SMFICTX *ctx) { return install(ctx)->eoh(); } inline sfsistat Milter::mEom(SMFICTX *ctx) { return install(ctx)->eom(); } inline sfsistat Milter::mHeader(SMFICTX *ctx, char *headerf, char *headerv) { return install(ctx)->header(headerf, headerv); } inline sfsistat Milter::mHelo(SMFICTX *ctx, char *helohost) { return install(ctx)->helo(helohost); } #if SMFI_VERSION > 2 inline sfsistat Milter::mUnknown(SMFICTX *ctx, char const *ptr) { return install(ctx)->unknown(ptr); } #endif /* SMFI_VERSION > 2 */ #if SMFI_VERSION > 3 inline sfsistat Milter::mData(SMFICTX *ctx) { return install(ctx)->data(); } #endif /* SMFI_VERSION > 3 */ using namespace std; using namespace FBB; bobcat-6.07.01/milter/connect.cc0000664000175000017500000000015614673353434015357 0ustar frankfrank#include "milter.ih" sfsistat Milter::connect(char *hostname, _SOCK_ADDR *hostaddr) { return CONTINUE; } bobcat-6.07.01/milter/datamember.cc0000664000175000017500000000014514673353434016025 0ustar frankfrank#include "milter.ih" #if SMFI_VERSION > 3 sfsistat Milter::data() { return CONTINUE; } #endif bobcat-6.07.01/mmapbuf/0000775000175000017500000000000014736742656013560 5ustar frankfrankbobcat-6.07.01/mmapbuf/sflush.cc0000664000175000017500000000044314673353434015364 0ustar frankfrank#define XERR #include "mmapbuf.ih" void MmapBuf::sflush() { size_t nChars = max(pptr(), d_maxPtr) - d_buffer; // enlarge the fileSize if needed if (nChars != 0 and d_fileSize < d_offset + nChars) d_fileSize = d_offset + nChars; } bobcat-6.07.01/mmapbuf/xsputn.cc0000664000175000017500000000113014673353434015413 0ustar frankfrank#define XERR #include "mmapbuf.ih" std::streamsize MmapBuf::xsputn(char const *buffer, std::streamsize request) { if (request <= 0) return 0; size_t pending = request; size_t nWritten = 0; while (pending) { size_t nAvail = epptr() - pptr(); if (nAvail == 0) { overflow(*buffer++); ++nWritten; --pending; } else { size_t wrote = writen(&buffer, min(pending, nAvail)); nWritten += wrote; pending -= wrote; } } return nWritten; } bobcat-6.07.01/mmapbuf/showmanyc.cc0000664000175000017500000000016214673353434016066 0ustar frankfrank#define XERR #include "mmapbuf.ih" // overrides streamsize MmapBuf::showmanyc() { return egptr() - gptr(); } bobcat-6.07.01/mmapbuf/seek.cc0000664000175000017500000000246514673353434015015 0ustar frankfrank#define XERR #include "mmapbuf.ih" std::ios::pos_type MmapBuf::seek(IOS::off_type pos, IOS::seekdir where) { switch (where) { case ios::beg: d_pos = pos; break; case ios::end: d_pos = d_fileSize + pos; break; case ios::cur: { if (not d_activeBuffer) { d_pos += pos; break; } // d_buffer has a value so over/underflow has set buffer ptrs size_t pPos = 0; // needed when only writing if (pbase() != 0) // get the current write-position { pPos = d_offset + (pptr() - pbase()); d_maxPtr = max(d_maxPtr, pptr()); // check/update maxPtr } size_t gPos = 0; // needed when reading if (eback() != 0) // get the current read position gPos = d_offset + (gptr() - eback()); // use the farthest position = the position after the most // recent read or write d_pos = max(pPos, gPos) + pos; } break; } setp(0, 0); // forcing under/overflow setg(0, 0, 0); d_activeBuffer = false; return d_pos; } bobcat-6.07.01/mmapbuf/mmapbuf3.cc0000664000175000017500000000113314673353434015567 0ustar frankfrank#define XERR #include "mmapbuf.ih" MmapBuf::MmapBuf(MmapBuf &&tmp) : streambuf(static_cast(tmp)) { if (not d_fname.empty()) { if (writable()) sync(); else unmap(); } d_fname = move(tmp.d_fname); d_openMode = tmp.d_openMode; d_buffer = tmp.d_buffer; d_bufSize = tmp.d_bufSize; d_fileSize = tmp.d_fileSize; d_enlargedSize = tmp.d_enlargedSize; d_activeBuffer = tmp.d_activeBuffer; d_pos = tmp.d_pos; d_offset = tmp.d_offset; d_maxPtr = tmp.d_maxPtr; d_sync = tmp.d_sync; } bobcat-6.07.01/mmapbuf/overflow.cc0000664000175000017500000000155114673353434015724 0ustar frankfrank#define XERR #include "mmapbuf.ih" // override int MmapBuf::overflow(int ch) { // SF: setp(d_buffer, d_buffer + d_bufSize); // when appending set d_pos to the last written position or // to the current fileSize. Not completely sure if this is // all it takes... if (d_openMode & ios::app) d_pos = max(d_fileSize, d_offset + (d_maxPtr - d_buffer)); else if (d_activeBuffer) d_pos = d_offset + d_bufSize; // set d_pos beyond the buffer // else: no active buffer -> d_pos was explicitly set // check if an mmapped buffer exists and d_pos is // within the buffer-area: then use the new put-position else if (d_buffer != 0 and withinBuffer(d_bufSize)) return resetWriteBuffer(ch); // no active buffer, OR pptr() is not inside the d_buffer area sync(); return writeBuffer(ch); } bobcat-6.07.01/mmapbuf/writen.cc0000664000175000017500000000032414673353434015366 0ustar frankfrank#define XERR #include "mmapbuf.ih" size_t MmapBuf::writen(char const **bufferPtr, size_t toWrite) { memcpy(pptr(), *bufferPtr, toWrite); *bufferPtr += toWrite; pbump(toWrite); return toWrite; } bobcat-6.07.01/mmapbuf/data.cc0000664000175000017500000000013114673353434014763 0ustar frankfrank#define XERR #include "mmapbuf.ih" size_t MmapBuf::s_pageSize = sysconf(_SC_PAGE_SIZE); bobcat-6.07.01/mmapbuf/readbuffer.cc0000664000175000017500000000050614673353434016165 0ustar frankfrank#define XERR #include "mmapbuf.ih" int MmapBuf::readBuffer() { unmap(); if (d_pos >= d_fileSize) return EOF; d_offset = d_pos / d_bufSize * d_bufSize; d_readBufSize = min(d_fileSize - d_offset, d_bufSize); map(writable() ? PROT_READ | PROT_WRITE : PROT_READ); return resetReadBuffer(); } bobcat-6.07.01/mmapbuf/writebuffer.cc0000664000175000017500000000027314673353434016405 0ustar frankfrank#define XERR #include "mmapbuf.ih" int MmapBuf::writeBuffer(int ch) { d_offset = d_pos / d_bufSize * d_bufSize; map(PROT_READ | PROT_WRITE); return resetWriteBuffer(ch); } bobcat-6.07.01/mmapbuf/mmapbuf2.cc0000664000175000017500000000064114673353434015571 0ustar frankfrank#define XERR #include "mmapbuf.ih" MmapBuf::MmapBuf(string const &fname, char const *bufSize, ios::openmode openMode, mode_t mode) : d_fname(fname), d_openMode(openMode), d_buffer(0), d_activeBuffer(false), d_pos(0), d_sync(false) { setFileSize(mode); d_enlargedSize = d_fileSize; setBufSize(bufSize); if (openMode & ios::ate) d_pos = d_fileSize; } bobcat-6.07.01/mmapbuf/moveassign.cc0000664000175000017500000000024214673353434016230 0ustar frankfrank#define XERR #include #include "mmapbuf.ih" MmapBuf &MmapBuf::operator=(MmapBuf &&tmp) { fswap(&d_openMode, *this, tmp); return *this; } bobcat-6.07.01/mmapbuf/README0000664000175000017500000001214314673353434014431 0ustar frankfrankMmapBuf implements a streambuf using the mmap function for for its file I/O. Data members are string d_fname - the name of the used file std::ios:openmode d_openMode - mode flags like ios::in, ios::out, but also, e.g, ios::ate and ios::app char *d_buffer - the memory buffer returned by mmap size_t d_bufSize - the size of the buffer returned by mmap size_t d_readBufSize - the maybe reduced buffer size when reading size_t d_enlargedSize - when writing is allowed: the largest used offset + bufSize value size_t d_fileSize - original file size, increased when writing to positions beyond d_fileSize. The Mapbase object's destructor resizes the file to d_fileSize. size_t d_pos - the current offset within the file (returned by tellp/tellg) bool d_activeBuffer - true: under/overflow has set a buffer with setp/setg size_t d_offset - the current offset used by mmap (cf. underflow.cc) char *d_maxPtr - the maximum pptr() value used in the current buffer. bool d_sync - used by IOmmapStream: true when sync is required when reading information after writing static size_t s_pageSize; - the page size returned by sysconf(_SC_PAGE_SIZE) (e.g., 4096). This variable defines the smallest size of the buffer used by mmap. Flow used by seek: The data member d_activeBuffer keeps track of whether or not an active mmap buffer exists. When seeking with ios::beg or ios::end d_pos is set according to the specified argument. When seeking with ios::cur, no active buffer: the pos paramater is added to d_pos. active buffer: when writing was used (pbase() != 0) the offset after the last writing action is determined. (if that position exceeds the last used position in the mmap buffer then d_maxPtr is updated, so when the buffer is flushed the file size can be updated) when reading was used (eback() != 0) the offset after the last reading action is determined. next d_pos is updated to the max(writePos, readPos) + pos Next the read/write buffers are reset to 0, forcing over/underflow at the next read/write request. At that point d_activeBuffer is set to false (as there's no active buffer anymore) and d_pos, the new current position in the file is returned. Flow used by overflow: if there's an active buffer, then it was completely filled, and the next d_pos is the beginning of a new buffer. otherwise there's no active buffer: maybe d_buffer exists (i.e., d_activeBuffer = true), resulting from the last mmap call. If d_pos is located inside the current buffer then the overflowing char is written into that position. otherwise the current buffer is sync-ed (unmapped) to file and a new mmap buffer is loaded. d_pos is then located inside the new buffer and the overflowing char is written into that position. When writing the overflowing char d_sync is set to true, allowing read-operations to sync the last written buffer, possibly enlarging the file's size. Flow used by underflow: When underflow is called and IOmmapStream is used information may have been written to file by a previous write action (in which case d_sync is true). If so the currernt mmapped buffer is written to file, possibly updating the file's size so reading can cover the fully updated file. If d_activeBuffer is true, then reading exhausted the current buffer and d_pos is set to just beyond the current buffer. otherwise there's no active buffer: maybe d_buffer exists, resulting from the last mmap call. If d_pos is located inside the current buffer then there is an active buffer, buffer's gptr() location is updated and the char. at that position is returned. otherwise a possibly existing mmapped buffer is unmapped, the parameters of the next buffer are determined, and the character at position d_pos in that buffer is returned When mapping for reading the maximum position in the mapped buffer cannot exceed the file's size. The max. usable position is stored in d_readBufSize by the function readBuffer. If d_pos exceeds the current file size EOF is returned. Note that the offset plus the size of the buffer that's passed to mmap can exceed the current file's size. bobcat-6.07.01/mmapbuf/failure.cc0000664000175000017500000000016714673353434015512 0ustar frankfrank#define XERR #include "mmapbuf.ih" void MmapBuf::failure(string msg) { xerr(msg); throw Exception{} << msg; } bobcat-6.07.01/mmapbuf/xsgetn.cc0000664000175000017500000000106514673353434015371 0ustar frankfrank#define XERR #include "mmapbuf.ih" // override std::streamsize MmapBuf::xsgetn(char *dest, std::streamsize req) { if (req <= 0) return 0; size_t request = req; size_t nRead = 0; while (request) { size_t nAvail = showmanyc(); if (nAvail == 0) { if (underflow() == EOF) break; } else { size_t nObtained = readn(&dest, min(request , nAvail)); nRead += nObtained; request -= nObtained; } } return nRead; } bobcat-6.07.01/mmapbuf/mmapbuf1.cc0000664000175000017500000000040214673353434015563 0ustar frankfrank#define XERR #include "mmapbuf.ih" MmapBuf::MmapBuf() : d_openMode(static_cast(0)), d_buffer(0), d_bufSize(0), d_fileSize(0), d_enlargedSize(0), d_activeBuffer(false), d_pos(0), d_offset(0), d_maxPtr(0) {} bobcat-6.07.01/mmapbuf/mmapbuf0000664000175000017500000000673614673353434015136 0ustar frankfrank#ifndef INCLUDED_BOBCAT_MMAPBUF_ #define INCLUDED_BOBCAT_MMAPBUF_ #include #include #include namespace FBB { class MmapBuf: public std::streambuf { protected: using IOS = std::ios; private: std::string d_fname; IOS::openmode d_openMode; char *d_buffer; size_t d_bufSize; size_t d_readBufSize; size_t d_fileSize; // original file size, increased when writing // beyond size_t d_enlargedSize; // the largest used offset + bufSize value, // used when mapping beyond the current file // size (in map.cc) to resize the file // accordingly bool d_activeBuffer; // under/overflow defined the buffer w. setg/p size_t d_pos; size_t d_offset; char *d_maxPtr; // used when writing: the max. index used // when writing a buffer, allowing d_fileSize // to be enlarges when unmapping a buffer bool d_sync; // with ios::in | ios::out: sync at underflow static size_t s_pageSize; public: MmapBuf(); // 1 MmapBuf(std::string const &fname, // 2 char const *bufSize = 0, IOS::openmode openMode = IOS::out, mode_t mode = 0644); ~MmapBuf() override; size_t bufSize() const; size_t fileSize() const; size_t pageSize() const; protected: MmapBuf(MmapBuf &&tmp); // 3 MmapBuf &operator=(MmapBuf &&tmp); private: std::streamsize showmanyc() override; int overflow(int ch) override; int underflow() override; int sync() override; std::streamsize xsgetn(char *dest, std::streamsize request) override; std::streamsize xsputn(char const *buffer, std::streamsize nChars) override; IOS::pos_type seekpos(IOS::pos_type pos, IOS::openmode mode = IOS::in | IOS::out) override; IOS::pos_type seekoff(IOS::off_type pos, IOS::seekdir where, IOS::openmode mode = IOS::in | IOS::out) override; void setFileSize(mode_t mode); void setBufSize(char const *bufSize); IOS::pos_type seek(IOS::off_type pos, IOS::seekdir where); void sflush(); bool withinBuffer(size_t bufSize) const; void map(int protection); // PROT_READ or PROT_READ | PROT_WRITE void unmap(); // calls mmap's munmap function void mapBuffer(int protection); // see plainimap/imapbuf static void failure(std::string msg); int readBuffer(); int writeBuffer(int ch); size_t readn(char **dest, size_t toRead); size_t writen(char const **bufferPtr, size_t toWrite); int resetReadBuffer(); int resetWriteBuffer(int ch); bool writable() const; // .ih }; inline size_t MmapBuf::bufSize() const { return d_bufSize; } inline size_t MmapBuf::fileSize() const { return d_fileSize; } } // FBB #endif bobcat-6.07.01/mmapbuf/demo/0000775000175000017500000000000014673353434014474 5ustar frankfrankbobcat-6.07.01/mmapbuf/demo/build0000775000175000017500000000041114673353434015515 0ustar frankfrank#!/bin/bash CMD="g++ ${ICMAKE_CPPSTD} -Wall main.cc -L../tmp \ -lmmapbuf -lbobcat -s" # CMD="g++ ${ICMAKE_CPPSTD} -Wall main.cc ../*.o -lbobcat -s" # CMD="g++ ${ICMAKE_CPPSTD} -Wall main.cc -lbobcat -s" echo $CMD $CMD bobcat-6.07.01/mmapbuf/demo/in20000664000175000017500000000003114673353434015101 0ustar frankfrank2 4096 e 1 2 0 1 0 e 1 q bobcat-6.07.01/mmapbuf/demo/cmp0000775000175000017500000000024314673353434015200 0ustar frankfrank#!/bin/bash if [ $# -eq 0 ] ; then echo test file nr arg needed exit 0 fi a.out main.cc out x < in$1 | diff - out$1 [ $? -eq 0 ] && echo no differences bobcat-6.07.01/mmapbuf/demo/in30000664000175000017500000000003214673353434015103 0ustar frankfranki 5 2 0 1 0 i 1 1 0 i 1 q bobcat-6.07.01/mmapbuf/demo/in10000664000175000017500000000005014673353434015101 0ustar frankfrank2 4096 i 1 1 0 2 0 2 4096 i 1 2 0 i 1 q bobcat-6.07.01/mmapbuf/demo/in40000664000175000017500000000005414673353434015110 0ustar frankfrank2 4100 i 5 2 100 i 2 2 4100 e 5 2 100 e 2 q bobcat-6.07.01/mmapbuf/demo/main.cc0000664000175000017500000001075314673353434015735 0ustar frankfrank#include #include #include #include #include #include "../mmapbuf" using namespace std; namespace fs = filesystem; using namespace FBB; char usage[] = R"( 1 offset - seekg offset on the 1st file 2 offset - seekp (= seekg) offset on the 2nd file b - insert the 1st file's rdbuf to the 2nd file c - clear the files f - 2nd file's size g - get a single character fm the 2nd file, writing to cout i nr - insert nr lines from the 1st file into the 2nd file e nr - extract nr lines from the 2nd file into cout p - put a single character fm the 1st file to the 2nd file q - quit s - sync the 2nd file t - 2nd file's tellp (= tellg) r nr - read nr chars from the 2nd file, writing them to cout w nr - write nr chars from the 1st file to the 2nd file )"; int main(int argc, char **argv) try { if (argc == 1) { cout << "1st argument: input file, 2nd arg: input/output file\n"; return 1; } ifstream in(argv[1]); MmapBuf buf(argv[2], 0, fs::exists(argv[2]) ? ios::in | ios::out : ios::out); iostream out(&buf); if (argc == 3) cout << usage << "\n" "bufSize: " << buf.bufSize() << "\n" "fileSize: " << buf.fileSize() << '\n'; string line; size_t lineNr = 0; size_t value; while (true) { cout << '\n' << ++lineNr << "? "; getline(cin, line); switch (line.front()) { case 'b': out << in.rdbuf(); break; case 'c': in.clear(); out.clear(); break; case 'f': cout << buf.fileSize() << '\n'; break; case '1': line.front() = ' '; value = stoul(line); in.seekg(value); break; case 'e': { line.front() = ' '; size_t idx; for (idx = 0, value = stoul(line); idx != value; ++idx) { if (not getline(out, line)) break; cout << line << '\n'; } cout << "extracted " << idx << " lines\n"; } break; case 'i': { line.front() = ' '; size_t idx; for (idx = 0, value = stoul(line); idx != value; ++idx) { if (not getline(in, line)) break; out << line << '\n'; } cout << "inserted " << idx << " lines\n"; } break; case '2': line.front() = ' '; value = stoul(line); out.seekp(value); break; case 'g': cout << static_cast(out.get()) << '\n'; break; case 'p': out << static_cast(in.get()); break; case 'q': cout.put('\n'); return 0; case 's': out.flush(); break; case 't': break; case 'w': line.front() = ' '; value = stoul(line); line.resize(value); in.read(&line.front(), value); value = in.gcount(); out.write(&line.front(), value); cout << "\nwrote " << value << " chars from " << argv[1] << " to " << argv[2] << '\n'; break; case 'r': line.front() = ' '; value = stoul(line); line.resize(value); out.read(&line.front(), value); value = out.gcount(); cout.write(&line.front(), value); cout << "\ngot " << value << " chars from " << argv[2] << '\n'; break; default: cout << "undefined input: `" << line << "'\n"; break; } value = out.tellp(); cout << "in OK: " << in.good() << ", out OK: " << out.good() << ", at " << value << '\n'; } } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } bobcat-6.07.01/mmapbuf/demo/in50000664000175000017500000000006414673353434015112 0ustar frankfranke 1 2 4100 2 13 r 10 q reactivating a saved buffer bobcat-6.07.01/mmapbuf/resetwritebuffer.cc0000664000175000017500000000040414673353434017444 0ustar frankfrank#define XERR #include "mmapbuf.ih" int MmapBuf::resetWriteBuffer(int ch) { d_activeBuffer = true; setp(d_buffer, d_buffer + d_bufSize); pbump(d_pos - d_offset); *pptr() = ch; pbump(1); ++d_pos; d_sync = true; return ch; } bobcat-6.07.01/mmapbuf/icmconf0000664000175000017500000000010114673353434015101 0ustar frankfrank#define LIBRARY "mmapbuf" #include "../icmconf.lib" bobcat-6.07.01/mmapbuf/resetreadbuffer.cc0000664000175000017500000000035114673353434017226 0ustar frankfrank#define XERR #include "mmapbuf.ih" int MmapBuf::resetReadBuffer() { setg(d_buffer, d_buffer, d_buffer + d_readBufSize); gbump(d_pos - d_offset); d_activeBuffer = true; return static_cast(*gptr()); } bobcat-6.07.01/mmapbuf/unmap.cc0000664000175000017500000000052014673353434015174 0ustar frankfrank#define XERR #include "mmapbuf.ih" void MmapBuf::unmap() { if (d_buffer == 0) return; // mmap and munmap accept buffers for reading exceeding the file size if (munmap(d_buffer, d_bufSize) != 0) failure("munmap for " + d_fname + " failed"); d_buffer = 0; // no buffer available anymore } bobcat-6.07.01/mmapbuf/sync.cc0000664000175000017500000000034714673353434015037 0ustar frankfrank#define XERR #include "mmapbuf.ih" // override int MmapBuf::sync() { if (d_buffer != 0) // sync only needed when there's a buffer { sflush(); unmap(); } d_sync = false; return 0; } bobcat-6.07.01/mmapbuf/destructor.cc0000664000175000017500000000030514673353434016253 0ustar frankfrank#define XERR #include "mmapbuf.ih" // overrides MmapBuf::~MmapBuf() { if (not writable()) unmap(); else { sync(); fs::resize_file(d_fname, d_fileSize); } } bobcat-6.07.01/mmapbuf/map.cc0000664000175000017500000000074514673353434014642 0ustar frankfrank#define XERR #include "mmapbuf.ih" void MmapBuf::map(int protection) // PROT_READ or PROT_READ | PROT_WRITE { // note: when reading d_data,bufSize may exceed the file's size if (writable()) { if (d_offset + d_bufSize > d_enlargedSize) { d_enlargedSize = d_offset + d_bufSize; fs::resize_file(d_fname, d_enlargedSize); } } mapBuffer(protection); // mmap the buffer, set d_buffer } bobcat-6.07.01/mmapbuf/seekoff.cc0000664000175000017500000000036714673353434015507 0ustar frankfrank#define XERR #include "mmapbuf.ih" // called by seekp()/tellp() (tellp using 0, ios::cur) ios::pos_type MmapBuf::seekoff(ios::off_type pos, ios::seekdir where, ios::openmode mode) { return seek(pos, where); } bobcat-6.07.01/mmapbuf/setbufsize.cc0000664000175000017500000000124114673353434016240 0ustar frankfrank#define XERR #include "mmapbuf.ih" void MmapBuf::setBufSize(char const *bufSize) { if (bufSize == 0) { d_bufSize = 10 * s_pageSize; return; } string spec{ bufSize }; d_bufSize = stoul(spec); switch (spec.back()) // extend by K,M,G suffixes { case 'K': d_bufSize *= 1024; break; case 'M': d_bufSize *= 1024 * 1024; break; case 'G': d_bufSize *= 1024 * 1024 * 1024; break; } // at least s_pageSize d_bufSize = max(s_pageSize, d_bufSize / s_pageSize * s_pageSize); } bobcat-6.07.01/mmapbuf/mapbuffer.cc0000664000175000017500000000131214673353434016023 0ustar frankfrank#define XERR #include "mmapbuf.ih" void MmapBuf::mapBuffer(int protection) { int fd = open(d_fname.c_str(), protection == PROT_READ ? O_RDONLY : O_RDWR ); if (fd == -1) // file can't be opened failure("can't open " + d_fname); // mmap and munmap accept buffers for reading exceeding the file size d_buffer = static_cast( // mmap the required buffer mmap(0, d_bufSize, protection, MAP_SHARED, fd, d_offset) ); close(fd); if (d_buffer == MAP_FAILED) // mapping failed failure("mmap for " + d_fname + " failed"); d_maxPtr = d_buffer; } bobcat-6.07.01/mmapbuf/underflow.cc0000664000175000017500000000124714673353434016070 0ustar frankfrank#define XERR #include "mmapbuf.ih" // override int MmapBuf::underflow() { if (d_sync) sync(); // active buffer and underflow: if (d_activeBuffer) // the buffer is exhausted d_pos = d_offset + d_bufSize; // set d_pos beyond the buffer // else: no active buffer anymore -> d_pos was explicitly set // check if an mmapped buffer exists and d_pos is // within the buffer-area: then use the new get-position return (d_buffer != 0 and withinBuffer(d_readBufSize)) ? resetReadBuffer() : readBuffer(); } bobcat-6.07.01/mmapbuf/readn.cc0000664000175000017500000000027114673353434015150 0ustar frankfrank#define XERR #include "mmapbuf.ih" size_t MmapBuf::readn(char **dest, size_t toRead) { memcpy(*dest, gptr(), toRead); *dest += toRead; gbump(toRead); return toRead; } bobcat-6.07.01/mmapbuf/seekpos.cc0000664000175000017500000000031314673353434015525 0ustar frankfrank#define XERR #include "mmapbuf.ih" // not called by tellp // overrides std::ios::pos_type MmapBuf::seekpos(ios::pos_type offset, ios::openmode mode) { return seekoff(offset, ios::beg, mode); } bobcat-6.07.01/mmapbuf/mmapbuf.ih0000664000175000017500000000072714736315237015526 0ustar frankfrank#include "../xerr/xerr.ih" #include "mmapbuf" #include #include #include #include #include #include #include #include #include inline bool FBB::MmapBuf::writable() const { return (d_openMode & IOS::out) != 0; } inline size_t st(char const *cp) { return (size_t)cp; } using namespace std; namespace fs = filesystem; using namespace FBB; bobcat-6.07.01/mmapbuf/setfilesize.cc0000664000175000017500000000224614673353434016411 0ustar frankfrank#define XERR #include "mmapbuf.ih" // 'mode' defines the access permissions of the file when it's creaed. // by default rw-r--r-- (0644) and is passed to MmapBuf via the [IO]mapbuf // derived class void MmapBuf::setFileSize(mode_t mode) { // ios:: // in the file must exist // out recreates unless also in // ate start initially at the end. Needs in to prevent rewriting // trunc truncates, with in|out reading also OK // app when writing always reposition to the end if (d_openMode & ios::app) d_openMode |= ios::out; if ( // create the file if (d_openMode & ios::trunc) // truncate or or // out-mode w/o in-mode ((d_openMode & ios::out) and (d_openMode & ios::in) == 0) ) { if (creat(d_fname.c_str(), mode) == -1) failure("can't create " + d_fname); d_fileSize = 0; return; } Stat stat{ d_fname }; // obtain the file's info if (not stat) failure("can't stat " + d_fname); d_fileSize = stat.size(); } bobcat-6.07.01/mmapbuf/withinbuffer.cc0000664000175000017500000000023314673353434016551 0ustar frankfrank#define XERR #include "mmapbuf.ih" bool MmapBuf::withinBuffer(size_t bufSize) const { return d_offset <= d_pos and d_pos < d_offset + bufSize; } bobcat-6.07.01/mstream/0000775000175000017500000000000014736742656013601 5ustar frankfrankbobcat-6.07.01/mstream/noid.cc0000664000175000017500000000065514673353434015037 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-6.07.01/mstream/reset3.f0000664000175000017500000000014714673353434015147 0ustar frankfrankinline void Mstream::reset(std::streambuf *buf) { Mbuf::reset(buf, maxCount(), tag(), throws()); } bobcat-6.07.01/mstream/mstream3.f0000664000175000017500000000030614673353434015472 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-6.07.01/mstream/reset6.f0000664000175000017500000000026614673353434015154 0ustar frankfrankinline void Mstream::reset(std::streambuf *buf, size_t maxCount, std::string const &tag, bool throwing) { Mbuf::reset(buf, maxCount, tag, throwing); } bobcat-6.07.01/mstream/fmsg.cc0000664000175000017500000000017214673353434015034 0ustar frankfrank#include "mstream.ih" namespace FBB { Mstream fmsg(std::cout, numeric_limits::max(), "Fatal", true); } bobcat-6.07.01/mstream/off.f0000664000175000017500000000007714673353434014516 0ustar frankfrankinline void Mstream::off() { setstate(std::ios::badbit); } bobcat-6.07.01/mstream/reset4.f0000664000175000017500000000027614673353434015153 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-6.07.01/mstream/reset.cc0000664000175000017500000000034014673353434015217 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-6.07.01/mstream/mstream4.f0000664000175000017500000000031314673353434015471 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-6.07.01/mstream/setactive.cc0000664000175000017500000000021214673353434016062 0ustar frankfrank#include "mstream.ih" bool Mstream::setActive(bool ifTrue) { if (ifTrue) on(); else off(); return ifTrue; } bobcat-6.07.01/mstream/isactive.f0000664000175000017500000000007514673353434015551 0ustar frankfrankinline bool Mstream::isActive() const { return good(); } bobcat-6.07.01/mstream/mstream0000664000175000017500000001136114673353434015166 0ustar frankfrank#ifndef INCLUDED_BOBCAT_MSTREAM_ #define INCLUDED_BOBCAT_MSTREAM_ #include #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-6.07.01/mstream/mstream2.f0000664000175000017500000000031614673353434015472 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-6.07.01/mstream/noidl.cc0000664000175000017500000000020014673353434015175 0ustar frankfrank#include "mstream.ih" namespace FBB { std::ostream &noidl(std::ostream &os) { return FBB::noid(os.put('\n')); } } // FBB bobcat-6.07.01/mstream/flush.cc0000664000175000017500000000073614673353434015227 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-6.07.01/mstream/on.f0000664000175000017500000000005314673353434014352 0ustar frankfrankinline void Mstream::on() { clear(); } bobcat-6.07.01/mstream/mstream.ih0000664000175000017500000000014714736315237015564 0ustar frankfrank#include "mstream" #include #include using namespace std; using namespace FBB; bobcat-6.07.01/mstream/imsg.cc0000664000175000017500000000014514673353434015037 0ustar frankfrank#include "mstream.ih" namespace FBB { Mstream imsg(std::cout, numeric_limits::max()); } bobcat-6.07.01/mstream/mstream1.f0000664000175000017500000000006614673353434015473 0ustar frankfrankinline Mstream::Mstream() : std::ostream(this) {} bobcat-6.07.01/mstream/wmsg.cc0000664000175000017500000000016614673353434015060 0ustar frankfrank#include "mstream.ih" namespace FBB { Mstream wmsg(std::cout, numeric_limits::max(), "Warning"); } bobcat-6.07.01/mstream/endl.cc0000664000175000017500000000020014673353434015012 0ustar frankfrank#include "mstream.ih" namespace FBB { std::ostream &endl(std::ostream &os) { return FBB::flush(os.put('\n')); } } // FBB bobcat-6.07.01/mstream/emsg.cc0000664000175000017500000000016414673353434015034 0ustar frankfrank#include "mstream.ih" namespace FBB { Mstream emsg(std::cout, numeric_limits::max() - 1, "Error"); } bobcat-6.07.01/mstream/reset5.f0000664000175000017500000000027314673353434015151 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-6.07.01/mstream/reset1.f0000664000175000017500000000015714673353434015146 0ustar frankfrankinline void Mstream::reset(std::ostream &ostr) { Mbuf::reset(ostr.rdbuf(), maxCount(), tag(), throws()); } bobcat-6.07.01/mstream/id.f0000664000175000017500000000011514673353434014331 0ustar frankfrankinline long Mstream::id() const { return reinterpret_cast(this); } bobcat-6.07.01/mstream/driver/0000775000175000017500000000000014737552575015074 5ustar frankfrankbobcat-6.07.01/mstream/driver/build0000775000175000017500000000026114673353434016110 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-6.07.01/mstream/driver/driver.cc0000664000175000017500000000355314673353434016674 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-6.07.01/mstream/reset2.f0000664000175000017500000000015414673353434015144 0ustar frankfrankinline void Mstream::reset(std::string const &name) { Mbuf::reset(name, maxCount(), tag(), throws()); } bobcat-6.07.01/multibuf/0000775000175000017500000000000014736742656013760 5ustar frankfrankbobcat-6.07.01/multibuf/stream1.f0000664000175000017500000000014214673353434015470 0ustar frankfrankinline MultiBuf::stream::stream(std::ostream &os, Mode mode) : d_os(&os), d_mode(mode) {} bobcat-6.07.01/multibuf/xsputn.cc0000664000175000017500000000022214673353434015614 0ustar frankfrank#include "multibuf.ih" std::streamsize MultiBuf::xsputn(char const *buffer, std::streamsize n) { d_buffer.append(buffer, n); return n; } bobcat-6.07.01/multibuf/multibuf1.f0000664000175000017500000000012114673353434016021 0ustar frankfrankinline MultiBuf::MultiBuf(std::ostream &os, Mode mode) { insert(os, mode); } bobcat-6.07.01/multibuf/overflow.cc0000664000175000017500000000021314673353434016116 0ustar frankfrank#include "multibuf.ih" int MultiBuf::overflow(int c) { if (c == EOF) sync(); else d_buffer += c; return c; } bobcat-6.07.01/multibuf/multibuf2.f0000664000175000017500000000013114673353434016023 0ustar frankfrankinline MultiBuf::MultiBuf(std::vector const &osvector) { insert(osvector); } bobcat-6.07.01/multibuf/mode.f0000664000175000017500000000011414673353434015037 0ustar frankfrankinline MultiBuf::Mode MultiBuf::stream::mode() const { return d_mode; } bobcat-6.07.01/multibuf/insert2.f0000664000175000017500000000016314673353434015505 0ustar frankfrankinline void MultiBuf::insert(std::vector const &os) { d_os.insert(d_os.end(), os.begin(), os.end()); } bobcat-6.07.01/multibuf/begin1.f0000664000175000017500000000011114673353434015255 0ustar frankfrankinline MultiBuf::iterator MultiBuf::begin() { return d_os.begin(); } bobcat-6.07.01/multibuf/end1.f0000664000175000017500000000010514673353434014742 0ustar frankfrankinline MultiBuf::iterator MultiBuf::end() { return d_os.end(); } bobcat-6.07.01/multibuf/multibuf.ih0000664000175000017500000000024014736315237016114 0ustar frankfrank#include "multibuf" #include struct FBB::MultiBuf::Insert { std::string &buffer; bool ok; }; using namespace std; using namespace FBB; bobcat-6.07.01/multibuf/icmconf0000664000175000017500000000007614673353434015314 0ustar frankfrank#define LIBRARY "multibuf" #include "../icmconf" bobcat-6.07.01/multibuf/setonce.f0000664000175000017500000000015414673353434015557 0ustar frankfrankinline void MultiBuf::stream::setOnce(stream &os) { if (os.d_mode == RESET) os.d_mode = ONCE; } bobcat-6.07.01/multibuf/size.f0000664000175000017500000000010114673353434015061 0ustar frankfrankinline size_t MultiBuf::size() const { return d_os.size(); } bobcat-6.07.01/multibuf/insert1.f0000664000175000017500000000014414673353434015503 0ustar frankfrankinline void MultiBuf::insert(std::ostream &os, Mode mode) { d_os.push_back(stream(os, mode)); } bobcat-6.07.01/multibuf/sync.cc0000664000175000017500000000037214673353434015235 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-6.07.01/multibuf/insertstruct.cc0000664000175000017500000000066214673353434017034 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-6.07.01/multibuf/setmode.f0000664000175000017500000000011014673353434015547 0ustar frankfrankinline void MultiBuf::stream::setMode(Mode mode) { d_mode = mode; } bobcat-6.07.01/multibuf/multibuf0000664000175000017500000000544514673353434015532 0ustar frankfrank#ifndef INCLUDED_BOBCAT_MULTIBUF_ #define INCLUDED_BOBCAT_MULTIBUF_ #include #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 }; using iterator = std::vector::iterator; using const_iterator = std::vector::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-6.07.01/multibuf/ostream.f0000664000175000017500000000010714673353434015567 0ustar frankfrankinline std::ostream &MultiBuf::stream::ostream() { return *d_os; } bobcat-6.07.01/multibuf/setonce.cc0000664000175000017500000000015314673353434015716 0ustar frankfrank#include "multibuf.ih" void MultiBuf::setOnce() { for (auto &os: d_os) stream::setOnce(os); } bobcat-6.07.01/multibuf/remove.cc0000664000175000017500000000117614673353434015561 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-6.07.01/multibuf/end2.f0000664000175000017500000000012114673353434014741 0ustar frankfrankinline MultiBuf::const_iterator MultiBuf::end() const { return d_os.end(); } bobcat-6.07.01/multibuf/begin2.f0000664000175000017500000000012514673353434015263 0ustar frankfrankinline MultiBuf::const_iterator MultiBuf::begin() const { return d_os.begin(); } bobcat-6.07.01/multibuf/driver/0000775000175000017500000000000014737552575015253 5ustar frankfrankbobcat-6.07.01/multibuf/driver/build0000775000175000017500000000026114673353434016267 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-6.07.01/multibuf/driver/driver.cc0000664000175000017500000000100214673353434017036 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-6.07.01/npipe/0000775000175000017500000000000014736742656013244 5ustar frankfrankbobcat-6.07.01/npipe/setdefault.cc0000664000175000017500000000012014673353434015674 0ustar frankfrank#include "npipe.ih" void NPipe::setDefault() { NPipe tmp; swap(tmp); } bobcat-6.07.01/npipe/reset1.cc0000664000175000017500000000011514673353434014743 0ustar frankfrank#include "npipe.ih" void NPipe::reset() { close(); setDefault(); } bobcat-6.07.01/npipe/swap.f0000664000175000017500000000011014673353434014345 0ustar frankfrankinline void NPipe::swap(NPipe &other) { FBB::fswap(*this, other); } bobcat-6.07.01/npipe/reset2.cc0000664000175000017500000000015514673353434014750 0ustar frankfrank#include "npipe.ih" void NPipe::reset(int const *fds) { close(); NPipe tmp{ fds }; swap(tmp); } bobcat-6.07.01/npipe/npipe2.f0000664000175000017500000000007714673353434014604 0ustar frankfrankinline NPipe::NPipe(NPipe &&tmp) : Pipe(std::move(tmp)) {} bobcat-6.07.01/npipe/npipe0000664000175000017500000000367714673353434014307 0ustar frankfrank#ifndef INCLUDED_BOBCAT_NPIPE_ #define INCLUDED_BOBCAT_NPIPE_ #include namespace FBB { struct NPipe: public Pipe { NPipe() = default; NPipe(NPipe const &other) = delete; NPipe(NPipe &&tmp); // 2.f explicit NPipe(int const *fd); // fd: must be 2 FDs 3.f explicit NPipe(bool initialize); // 4.cc // void close(); // Pipe // void closeReadFd(); // Pipe // void closeWriteFd(); // Pipe // int readFd() const; // Pipe // void readFrom(int filedescriptor); // Pipe // void readFrom(int const *filedescriptor, size_t nSwallow); // Pipe // int readOnly(); // Pipe // int readOnlyFd(); // Pipe // closes the npipes void reset(); // and reopens them 1.cc // closes the npipes and reopens // them with the provided 2 void reset(int const *fds); // read/write file descr. 2.cc void swap(NPipe &other); // .f // int writeFd() const; // Pipe // void writtenBy(int filedescriptor); // Pipe // void writtenBy(int const *filedescr, size_t nSwallow = 2); // Pipe // int writeOnly(); // Pipe // int writeOnlyFd(); // Pipe private: void setDefault(); }; #include "npipe2.f" #include "npipe3.f" #include "swap.f" } // FBB #endif bobcat-6.07.01/npipe/icmconf0000664000175000017500000000015614673353434014577 0ustar frankfrank#define LIBRARY "npipe" #define AUXFLAGS "-I../tmp -pthread" #include "../icmconf" bobcat-6.07.01/npipe/npipe.ih0000664000175000017500000000023214736315237014665 0ustar frankfrank#include "npipe" #include #include "../exception/exception" #include "../redirector/redirector" using namespace std; using namespace FBB; bobcat-6.07.01/npipe/npipe3.f0000664000175000017500000000006514673353434014602 0ustar frankfrankinline NPipe::NPipe(int const *fd) : Pipe(fd) {} bobcat-6.07.01/npipe/npipe4.cc0000664000175000017500000000023214673353434014737 0ustar frankfrank#include "npipe.ih" NPipe::NPipe(bool initialize) : Pipe(false) // initialize fds to -1 { if (initialize) reset(); } bobcat-6.07.01/ofdbuf/0000775000175000017500000000000014736742656013376 5ustar frankfrankbobcat-6.07.01/ofdbuf/xsputn.cc0000664000175000017500000000100614673353434015233 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-6.07.01/ofdbuf/warn.cc0000664000175000017500000000031414673353434014642 0ustar frankfrank#define XERR #include "ofdbuf.ih" void OFdBuf::warn(bool on) { unsigned value = d_mode; if (on) value |= WARN; else value &= ~WARN; d_mode = static_cast(value); } bobcat-6.07.01/ofdbuf/overflow.cc0000664000175000017500000000023114673353434015534 0ustar frankfrank#include "ofdbuf.ih" int OFdBuf::overflow(int ch) { sync(); if (ch != EOF) { *pptr() = ch; pbump(1); } return ch; } bobcat-6.07.01/ofdbuf/reset.cc0000664000175000017500000000023714673353434015021 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-6.07.01/ofdbuf/ofdbuf3.cc0000664000175000017500000000021714673353434015225 0ustar frankfrank#include "ofdbuf.ih" #include OFdBuf::OFdBuf(int fd, size_t bufSize) : d_mode(CLOSE_FD) { reset(fd, CLOSE_FD, bufSize); } bobcat-6.07.01/ofdbuf/ofdbuf2.cc0000664000175000017500000000010614673353434015221 0ustar frankfrank#include "ofdbuf.ih" OFdBuf::OFdBuf(Mode mode) : d_mode(mode) {} bobcat-6.07.01/ofdbuf/ofdbuf.ih0000664000175000017500000000023014736315237015147 0ustar frankfrank#include "ofdbuf" #include "../xerr/xerr.ih" #include #include #include using namespace FBB; using namespace std; bobcat-6.07.01/ofdbuf/icmconf0000664000175000017500000000007414673353434014730 0ustar frankfrank#define LIBRARY "ofdbuf" #include "../icmconf" bobcat-6.07.01/ofdbuf/eoi.f0000664000175000017500000000005214673353434014306 0ustar frankfrankinline void OFdBuf::eoi() { eoi_(); } bobcat-6.07.01/ofdbuf/ofdbuf0000664000175000017500000000375314673353434014566 0ustar frankfrank#ifndef INCLUDED_BOBCAT_OFDBUF_ #define INCLUDED_BOBCAT_OFDBUF_ #include #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, // 0 KEEP_FD, // 1 WARN, // 2 }; 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 void warn(bool on); // .cc 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-6.07.01/ofdbuf/sync.cc0000664000175000017500000000114514673353434014652 0ustar frankfrank#include "ofdbuf.ih" int OFdBuf::sync() { int ret = 0; if (pptr() > pbase()) // if there are chars in the buffer { // then write them to the device if (write(d_fd, ucharPtr(), pptr() - pbase()) < 0) { ret = -1; if ((d_mode & WARN) == WARN) std::cerr << "[Warning] OFdBuf::sync could not " "write to FD " << d_fd << '\n'; } setp(); // and reset the stream pointers } return ret; // return OK. } bobcat-6.07.01/ofdbuf/destructor.cc0000664000175000017500000000010114673353434016063 0ustar frankfrank#include "ofdbuf.ih" OFdBuf::~OFdBuf() { cleanup(d_mode); } bobcat-6.07.01/ofdbuf/ofdbuf4.cc0000664000175000017500000000017314673353434015227 0ustar frankfrank#include "ofdbuf.ih" OFdBuf::OFdBuf(int fd, Mode mode, size_t size) : d_mode(mode) { reset(fd, CLOSE_FD, size); } bobcat-6.07.01/ofdbuf/eoi.cc0000664000175000017500000000010514673353434014445 0ustar frankfrank#include "ofdbuf.ih" void OFdBuf::eoi_() { cleanup(CLOSE_FD); } bobcat-6.07.01/ofdbuf/fd.f0000664000175000017500000000006314673353434014125 0ustar frankfrankinline int OFdBuf::fd() const { return d_fd; } bobcat-6.07.01/ofdbuf/cleanup.cc0000664000175000017500000000027114673353434015324 0ustar frankfrank#include "ofdbuf.ih" void OFdBuf::cleanup(Mode mode) { if (d_fd == -1) return; sync(); if ((d_mode & KEEP_FD) == CLOSE_FD) close(d_fd); d_fd = -1; } bobcat-6.07.01/ofdbuf/ofdbuf1.cc0000664000175000017500000000014614673353434015224 0ustar frankfrank#include "ofdbuf.ih" OFdBuf::OFdBuf() : d_mode(CLOSE_FD) // comply with old default {} bobcat-6.07.01/ofdbuf/reset.f0000664000175000017500000000012614673353434014656 0ustar frankfrankinline void OFdBuf::reset(int fd, size_t bufSize) { reset(fd, d_mode, bufSize); } bobcat-6.07.01/ofdbuf/driver/0000775000175000017500000000000014737552575014671 5ustar frankfrankbobcat-6.07.01/ofdbuf/driver/build0000775000175000017500000000066714673353434015717 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-6.07.01/ofdbuf/driver/driver.cc0000664000175000017500000000105414736771017016464 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 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-6.07.01/ofdstream/0000775000175000017500000000000014673353434014105 5ustar frankfrankbobcat-6.07.01/ofdstream/ofdstream0000664000175000017500000000045014673353434016013 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-6.07.01/ofdstream/ofdstream1.f0000664000175000017500000000013514673353434016320 0ustar frankfrankinline OFdStream::OFdStream(int fd, size_t n) : OFdBuf(fd, n), std::ostream(this) {} bobcat-6.07.01/ofilterbuf/0000775000175000017500000000000014736742656014272 5ustar frankfrankbobcat-6.07.01/ofilterbuf/reset1.cc0000664000175000017500000000027114673353434015774 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-6.07.01/ofilterbuf/ofilterbuf3.f0000664000175000017500000000010614673353434016652 0ustar frankfrankinline OFilterBuf::OFilterBuf(std::ostream &out) : d_out(&out) {} bobcat-6.07.01/ofilterbuf/ofilterbuf0000664000175000017500000000151614673353434016351 0ustar frankfrank#ifndef _INCLUDED_OFILTERBUF_ #define _INCLUDED_OFILTERBUF_ #include #include namespace FBB { class OFilterBuf: public Eoi { using openmode = std::ios::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-6.07.01/ofilterbuf/reset2.cc0000664000175000017500000000020214673353434015767 0ustar frankfrank#include "ofilterbuf.ih" void OFilterBuf::reset(std::ostream &out) { d_out->flush(); d_dest.close(); d_out = &out; } bobcat-6.07.01/ofilterbuf/ofilterbuf2.cc0000664000175000017500000000021314673353434017010 0ustar frankfrank#include "ofilterbuf.ih" OFilterBuf::OFilterBuf(std::string const &fname, openmode mode) : d_dest(fname, mode), d_out(&d_dest) {} bobcat-6.07.01/ofilterbuf/out.f0000664000175000017500000000010414673353434015233 0ustar frankfrankinline std::ostream &OFilterBuf::out() const { return *d_out; } bobcat-6.07.01/ofilterbuf/ofilterbuf1.f0000664000175000017500000000007014673353434016650 0ustar frankfrankinline OFilterBuf::OFilterBuf() : d_out(&d_dest) {} bobcat-6.07.01/ofilterbuf/icmconf0000664000175000017500000000010014673353434015612 0ustar frankfrank#define LIBRARY "ofilterbuf" #include "../icmconf" bobcat-6.07.01/ofilterbuf/ofilterbuf.ih0000664000175000017500000000010314736315237016736 0ustar frankfrank#include "ofilterbuf" using namespace std; using namespace FBB; bobcat-6.07.01/ofoldbuf/0000775000175000017500000000000014736742656013731 5ustar frankfrankbobcat-6.07.01/ofoldbuf/iniblankstabs.cc0000664000175000017500000000022214673353434017050 0ustar frankfrank#include "ofoldbuf.ih" void OFoldBuf::iniBlankTabs(TabsOrBlanks tob) { if (tob == BLANKS) useBlanks(); else useTabs(); } bobcat-6.07.01/ofoldbuf/modify1.f0000664000175000017500000000021414673353434015435 0ustar frankfrankinline std::ostream &lm::modify(std::ostream &out) const { dynamic_cast(*out.rdbuf()).setIndent(d_value); return out; } bobcat-6.07.01/ofoldbuf/overflow.cc0000664000175000017500000000052214673353434016072 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-6.07.01/ofoldbuf/ofoldbuf3.cc0000664000175000017500000000070614673353434016116 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-6.07.01/ofoldbuf/data.cc0000664000175000017500000000010714673353434015137 0ustar frankfrank#include "ofoldbuf.ih" vector OFoldBuf::s2_buffers; bobcat-6.07.01/ofoldbuf/lm1.f0000664000175000017500000000010614673353434014556 0ustar frankfrankinline FBB::lm::lm(int value) : d_value(value < 0 ? 0 : value) {} bobcat-6.07.01/ofoldbuf/addnonws.f0000664000175000017500000000010114673353434015675 0ustar frankfrankinline void FBB::OFoldBuf::addNonWs(int c) { d_nonWs += c; } bobcat-6.07.01/ofoldbuf/ofoldbuf2.cc0000664000175000017500000000070714673353434016116 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-6.07.01/ofoldbuf/put.f0000664000175000017500000000010414673353434014673 0ustar frankfrankinline void FBB::OFoldBuf::put(int ch) const { out().put(ch); } bobcat-6.07.01/ofoldbuf/findofoldstreambuf.cc0000664000175000017500000000053514673353434020110 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-6.07.01/ofoldbuf/ofoldbuf.ih0000664000175000017500000000027614736315237016047 0ustar frankfrank#include "ofoldbuf" #include #include #include "addnonws.f" #include "writews.f" #include "writenonws.f" #include "put.f" using namespace std; using namespace FBB; bobcat-6.07.01/ofoldbuf/indent.cc0000664000175000017500000000056514673353434015517 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-6.07.01/ofoldbuf/writenonws.f0000664000175000017500000000014514673353434016307 0ustar frankfrankinline void FBB::OFoldBuf::writeNonWs() const { out().write(d_nonWs.data(), d_nonWs.length()); } bobcat-6.07.01/ofoldbuf/ws.cc0000664000175000017500000000041714673353434014663 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-6.07.01/ofoldbuf/mlm1.f0000664000175000017500000000007014673353434014733 0ustar frankfrankinline FBB::mlm::mlm(int value) : d_value(value) {} bobcat-6.07.01/ofoldbuf/writews.f0000664000175000017500000000013414673353434015572 0ustar frankfrankinline void FBB::OFoldBuf::writeWs() const { out().write(d_ws.data(), d_ws.length()); } bobcat-6.07.01/ofoldbuf/settrailingblanks.f0000664000175000017500000000020114673353434017601 0ustar frankfrankinline void FBB::OFoldBuf::setTrailingBlanks(TrailingBlanks tb) { d_handleTrailingBlanks = tb == HANDLE_TRAILING_BLANKS; } bobcat-6.07.01/ofoldbuf/opinsert2.f0000664000175000017500000000015014673353434016011 0ustar frankfrankinline std::ostream &operator<<(std::ostream &out, FBB::mlm const &idt) { return idt.modify(out); } bobcat-6.07.01/ofoldbuf/ofoldbuf1.cc0000664000175000017500000000063414673353434016114 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-6.07.01/ofoldbuf/newline.cc0000664000175000017500000000016014673353434015666 0ustar frankfrank#include "ofoldbuf.ih" void OFoldBuf::newline() { //cerr << "NEWLINE\n"; put('\n'); d_next = 0; } bobcat-6.07.01/ofoldbuf/setmargins.cc0000664000175000017500000000023114673353434016400 0ustar frankfrank#include "ofoldbuf.ih" void OFoldBuf::setMargins(size_t leftMargin, size_t rightMargin) { d_rightMargin = rightMargin; d_indent = leftMargin; } bobcat-6.07.01/ofoldbuf/nonws.cc0000664000175000017500000000043514673353434015376 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-6.07.01/ofoldbuf/icmconf0000664000175000017500000000013614673353434015262 0ustar frankfrank#define LIBRARY "ofoldbuf" #define AUXFLAGS "-I../../tmp" #include "../icmconf" bobcat-6.07.01/ofoldbuf/ofoldbuf0000664000175000017500000000745514673353434015457 0ustar frankfrank#ifndef INCLUDED_BOBCAT_OFOLDBUF_ #define INCLUDED_BOBCAT_OFOLDBUF_ #include #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; using BufIt = std::vector::iterator; 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-6.07.01/ofoldbuf/flush.cc0000664000175000017500000000121314673353434015346 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-6.07.01/ofoldbuf/clearws.cc0000664000175000017500000000013314673353434015665 0ustar frankfrank#include "ofoldbuf.ih" void OFoldBuf::clearWs() { d_ws.clear(); d_wsLength = 0; } bobcat-6.07.01/ofoldbuf/rightmargin.f0000664000175000017500000000017614673353434016407 0ustar frankfrankinline size_t FBB::OFoldBuf::rightMargin(std::streambuf const *buffer) { return (*findOFoldBuf(buffer))->d_rightMargin; } bobcat-6.07.01/ofoldbuf/length.cc0000664000175000017500000000015714673353434015514 0ustar frankfrank#include "ofoldbuf.ih" size_t OFoldBuf::length() const { return d_next + d_wsLength + d_nonWs.length(); } bobcat-6.07.01/ofoldbuf/sync.cc0000664000175000017500000000021114673353434015176 0ustar frankfrank#include "ofoldbuf.ih" int OFoldBuf::sync() { if (d_mode == NON_WS) flush(); out().rdbuf()->pubsync(); return 0; } bobcat-6.07.01/ofoldbuf/destructor.cc0000664000175000017500000000056714673353434016436 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-6.07.01/ofoldbuf/indent2.cc0000664000175000017500000000017414673353434015575 0ustar frankfrank#include "ofoldbuf.ih" void OFoldBuf::indent() { for (size_t nr = 0; nr < d_indent; ++nr) put(d_indentChar); } bobcat-6.07.01/ofoldbuf/opinsert1.f0000664000175000017500000000014714673353434016016 0ustar frankfrankinline std::ostream &operator<<(std::ostream &out, FBB::lm const &idt) { return idt.modify(out); } bobcat-6.07.01/ofoldbuf/modifyindent.cc0000664000175000017500000000023014673353434016714 0ustar frankfrank#include "ofoldbuf.ih" void OFoldBuf::modifyIndent(int delta) { d_indent += delta; if (static_cast(d_indent) < 0) d_indent = 0; } bobcat-6.07.01/ofoldbuf/setindent.f0000664000175000017500000000011214673353434016057 0ustar frankfrankinline void FBB::OFoldBuf::setIndent(int value) { d_indent = value; } bobcat-6.07.01/ofoldbuf/modify2.f0000664000175000017500000000022014673353434015433 0ustar frankfrankinline std::ostream &mlm::modify(std::ostream &out) const { dynamic_cast(*out.rdbuf()).modifyIndent(d_value); return out; } bobcat-6.07.01/ofoldbuf/useblanks.f0000664000175000017500000000013214673353434016053 0ustar frankfrankinline void FBB::OFoldBuf::useBlanks() { d_indentChar = ' '; d_indentWidth = 1; } bobcat-6.07.01/ofoldbuf/leftmargin.f0000664000175000017500000000017014673353434016216 0ustar frankfrankinline size_t FBB::OFoldBuf::leftMargin(std::streambuf const *buffer) { return (*findOFoldBuf(buffer))->d_indent; } bobcat-6.07.01/ofoldbuf/addws.cc0000664000175000017500000000034214673353434015331 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-6.07.01/ofoldbuf/driver/0000775000175000017500000000000014737552575015224 5ustar frankfrankbobcat-6.07.01/ofoldbuf/driver/build0000775000175000017500000000106014673353434016236 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-6.07.01/ofoldbuf/driver/driver.cc0000664000175000017500000000125714673353434017023 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-6.07.01/ofoldbuf/usetabs.f0000664000175000017500000000015714673353434015541 0ustar frankfrankinline void FBB::OFoldBuf::useTabs(size_t tabWidth) { d_indentChar = '\t'; d_indentWidth = tabWidth; } bobcat-6.07.01/ofoldstream/0000775000175000017500000000000014736742656014450 5ustar frankfrankbobcat-6.07.01/ofoldstream/reset1.cc0000664000175000017500000000043214673353434016151 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-6.07.01/ofoldstream/reset2.cc0000664000175000017500000000041514673353434016153 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-6.07.01/ofoldstream/ofoldstream1.f0000664000175000017500000000040114673353434017202 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-6.07.01/ofoldstream/ofoldstream2.f0000664000175000017500000000037014673353434017210 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-6.07.01/ofoldstream/settrailingblanks.f0000664000175000017500000000014714673353434020331 0ustar frankfrankinline void OFoldStream::setTrailingBlanks(TrailingBlanks tb) { OFoldBuf::setTrailingBlanks(tb); } bobcat-6.07.01/ofoldstream/setmargins.f0000664000175000017500000000014014673353434016756 0ustar frankfrankinline void OFoldStream::setMargins(size_t lm, size_t rm) { OFoldBuf::setMargins(lm, rm); } bobcat-6.07.01/ofoldstream/ofoldstream0000664000175000017500000000406314673353434016705 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-6.07.01/ofoldstream/ofoldstream.ih0000664000175000017500000000010414736315237017273 0ustar frankfrank#include "ofoldstream" using namespace std; using namespace FBB; bobcat-6.07.01/ofoldstream/icmconf0000664000175000017500000000013614673353434016001 0ustar frankfrank#define LIBRARY "ofoldstream" #define AUXFLAGS "-I../tmp" #include "../icmconf" bobcat-6.07.01/ofoldstream/rightmargin.f0000664000175000017500000000016114673353434017120 0ustar frankfrankinline size_t OFoldStream::rightMargin(std::ostream const &os) { return OFoldBuf::rightMargin(os.rdbuf()); } bobcat-6.07.01/ofoldstream/useblanks.f0000664000175000017500000000010414673353434016571 0ustar frankfrankinline void OFoldStream::useBlanks() { OFoldBuf::useBlanks(); } bobcat-6.07.01/ofoldstream/leftmargin.f0000664000175000017500000000015714673353434016742 0ustar frankfrankinline size_t OFoldStream::leftMargin(std::ostream const &os) { return OFoldBuf::leftMargin(os.rdbuf()); } bobcat-6.07.01/ofoldstream/driver/0000775000175000017500000000000014737552575015743 5ustar frankfrankbobcat-6.07.01/ofoldstream/driver/build0000775000175000017500000000007614673353434016763 0ustar frankfrank#!/bin/sh g++ -I../../tmp driver.cc -L../../tmp/lib -lbobcat bobcat-6.07.01/ofoldstream/driver/driver.cc0000664000175000017500000000063414673353434017540 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-6.07.01/ofoldstream/usetabs.f0000664000175000017500000000012714673353434016255 0ustar frankfrankinline void OFoldStream::useTabs(size_t tabWidth) { OFoldBuf::useTabs(tabWidth); } bobcat-6.07.01/ohexbuf/0000775000175000017500000000000014736742656013571 5ustar frankfrankbobcat-6.07.01/ohexbuf/separator1.cc0000664000175000017500000000016414673353434016152 0ustar frankfrank#include "ohexbuf.ih" void OHexBuf::separator(bool reset) { d_separated = &OHexBuf::plain; clear(reset); } bobcat-6.07.01/ohexbuf/overflow.cc0000664000175000017500000000022314673353434015730 0ustar frankfrank#include "ohexbuf.ih" // overrides int OHexBuf::overflow(int ch) { (this->*d_separated)(ch); (this->*d_widthHandler)(); return ch; } bobcat-6.07.01/ohexbuf/setwidth.cc0000664000175000017500000000035214673353434015723 0ustar frankfrank#include "ohexbuf.ih" void OHexBuf::setWidth(size_t width) { d_width = width; d_widthHandler = d_width == 0 ? &OHexBuf::noWidth : &OHexBuf::widthHandler; } bobcat-6.07.01/ohexbuf/widthhandler.cc0000664000175000017500000000026614673353434016551 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-6.07.01/ohexbuf/ohexbuf.ih0000664000175000017500000000012414736315237015537 0ustar frankfrank#include "ohexbuf" #include using namespace std; using namespace FBB; bobcat-6.07.01/ohexbuf/separated.cc0000664000175000017500000000014614673353434016041 0ustar frankfrank#include "ohexbuf.ih" void OHexBuf::separated(int ch) { out() << setw(2) << ch << d_separator; } bobcat-6.07.01/ohexbuf/nowidth.cc0000664000175000017500000000006214673353434015542 0ustar frankfrank#include "ohexbuf.ih" void OHexBuf::noWidth() {} bobcat-6.07.01/ohexbuf/separator2.cc0000664000175000017500000000024214673353434016150 0ustar frankfrank#include "ohexbuf.ih" void OHexBuf::separator(string const &sep, bool reset) { d_separator = sep; d_separated = &OHexBuf::separated; clear(reset); } bobcat-6.07.01/ohexbuf/ohexbuf0000664000175000017500000000267514673353434015156 0ustar frankfrank#ifndef INCLUDED_BOBCAT_OHEXBUF_ #define INCLUDED_BOBCAT_OHEXBUF_ #include #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-6.07.01/ohexbuf/text2bin.cc0000664000175000017500000000033214673353434015625 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-6.07.01/ohexbuf/plain.cc0000664000175000017500000000012314673353434015167 0ustar frankfrank#include "ohexbuf.ih" void OHexBuf::plain(int ch) { out() << setw(2) << ch; } bobcat-6.07.01/ohexbuf/clear.cc0000664000175000017500000000021514673353434015154 0ustar frankfrank#include "ohexbuf.ih" void FBB::OHexBuf::clear(bool reset) { if (reset) { d_separator.clear(); d_count = 0; } } bobcat-6.07.01/ohexbuf/icmconf0000664000175000017500000000007514673353434015124 0ustar frankfrank#define LIBRARY "ohexbuf" #include "../icmconf" bobcat-6.07.01/ohexbuf/size.f0000664000175000017500000000007414673353434014703 0ustar frankfrankinline size_t OHexBuf::size() const { return d_count; } bobcat-6.07.01/ohexbuf/eoi.f0000664000175000017500000000004614673353434014504 0ustar frankfrankinline OHexBuf::eoi() { eoi_(); } bobcat-6.07.01/ohexbuf/sync.cc0000664000175000017500000000012114673353434015036 0ustar frankfrank#include "ohexbuf.ih" int OHexBuf::sync() { out() << flush; return 0; } bobcat-6.07.01/ohexbuf/destructor.cc0000664000175000017500000000016214673353434016265 0ustar frankfrank#include "ohexbuf.ih" OHexBuf::~OHexBuf() { eoi_(); out().fill(d_padding); out().flags(d_current); } bobcat-6.07.01/ohexbuf/eoi.cc0000664000175000017500000000016314673353434014644 0ustar frankfrank#include "ohexbuf.ih" #include void OHexBuf::eoi_() { sync(); separator(); setWidth(0); } bobcat-6.07.01/ohexbuf/ohexbuf1.cc0000664000175000017500000000065714673353434015621 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-6.07.01/ohexbuf/driver/0000775000175000017500000000000014737552575015064 5ustar frankfrankbobcat-6.07.01/ohexbuf/driver/build0000775000175000017500000000066214673353434016105 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-6.07.01/ohexbuf/driver/driver.cc0000664000175000017500000000061114673353434016654 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-6.07.01/omapbuf/0000775000175000017500000000000014736315237013551 5ustar frankfrankbobcat-6.07.01/omapbuf/omapbuf2.cc0000664000175000017500000000060514673353434015575 0ustar frankfrank#include "omapbuf.ih" // the file is created (to size 0) if not existing and create was // specified and the write-flag(s) of mode are set. Omapbuf::Omapbuf(string const &fname, ios::openmode iosMode, char const *bufSize, mode_t mode) : MapBase(fname, iosMode | ios::out, bufSize, mode) { setp(0, 0); // start w/o an mmapped buffer } bobcat-6.07.01/omapbuf/xsputn.cc0000664000175000017500000000137014673353434015423 0ustar frankfrank#define XERR #include "omapbuf.ih" // overrides streamsize Omapbuf::xsputn(char const *buffer, streamsize nChars) { streamsize nWritten = 0; if (append()) setAbsPos(fileSize(), ios::beg); while (nWritten != nChars) { streamsize avail = epptr() - pptr(); if (avail == 0) // buffer full / not yet set { overflow(*buffer); // reload the buffer ++nWritten; // one char written by overfl. continue; } streamsize toWrite = min(avail, nChars - nWritten); memmove(pptr(), buffer + nWritten, toWrite); pbump(toWrite); nWritten += toWrite; } return nChars; } bobcat-6.07.01/omapbuf/omapbuf0000664000175000017500000000236014673353434015127 0ustar frankfrank#ifndef INCLUDED_BOBCAT_OMAPBUF_ #define INCLUDED_BOBCAT_OMAPBUF_ #include "../mapbase/mapbase" // char *pbase(): // char *pptr(): // char *epptr(): // void pbump(int n): // setp(char *beg, char *beyond): namespace FBB { struct Omapbuf: virtual public MapBase { Omapbuf() = default; Omapbuf(std::string const &fname, IOS::openmode iosMode = IOS::out, char const *bufSize = 0, mode_t mode = 0644); ~Omapbuf() override; Omapbuf &operator=(Omapbuf &&tmp); protected: bool load(); // load the current file's mmap int overflow(int ch) override; int sync() override; std::streamsize xsputn(char const *buffer, std::streamsize nChars) override; // -1 on error, seekoff: in MapBase IOS::pos_type seekpos(IOS::pos_type offset, IOS::openmode mode = IOS::in | IOS::out) override; IOS::pos_type seekoff(IOS::off_type pos, IOS::seekdir where, IOS::openmode mode = IOS::in | IOS::out) override; }; } // FBB #endif bobcat-6.07.01/omapbuf/overflow.cc0000664000175000017500000000065114673353434015726 0ustar frankfrank#define XERR #include "omapbuf.ih" // overrides int Omapbuf::overflow(int ch) { //xerr("OMapbuf: " << absPos()); sync(); // write the current mmap buffer to file //xerr("OMapbuf (2):" << absPos()); if (not (load())) return EOF; *pptr() = static_cast(ch); // put it into the buffer pbump(1); // advance the buffer's pointer return ch; } bobcat-6.07.01/omapbuf/opmvassign.cc0000664000175000017500000000021414673353434016244 0ustar frankfrank#define XERR #include "omapbuf.ih" Omapbuf &Omapbuf::operator=(Omapbuf &&tmp) { moveAssign(move(tmp)); load(); return *this; } bobcat-6.07.01/omapbuf/demo/0000775000175000017500000000000014736311021014460 5ustar frankfrankbobcat-6.07.01/omapbuf/demo/build0000775000175000017500000000014514673353434015523 0ustar frankfrank#!/bin/bash cd ../../mapbase icmbuild || exit 1 cd ../omapbuf icmbuild || exit 1 cd demo icmbuild bobcat-6.07.01/omapbuf/demo/icmconf0000664000175000017500000000131714736311021016023 0ustar frankfrank// see also ~/.icmake/icmconf.mod for a possible module-using icmconf #define CLS #define MULTICOMP "jobs -q" //#define SPCH "-u xerr/xerr.ih" //#define USE_ALL "a" #define MAIN "main.cc" #define SOURCES "*.cc" #define OBJ_EXT ".o" #define TMP_DIR "tmp" #define USE_ECHO ON #define IH ".ih" #define CXX "g++" #define CXXFLAGS "-Wall -Werror -O2 -fdiagnostics-color=never" #define REFRESH #define LDFLAGS "-s" #define ADD_LIBRARIES "omapbuf mapbase bobcat" #define ADD_LIBRARY_PATHS "../../tmp ../../../mapbase/tmp" #define DEFCOM "program" bobcat-6.07.01/omapbuf/demo/main.cc0000664000175000017500000000246314673353434015736 0ustar frankfrank#define XERR #include "main.ih" int main(int argc, char **argv) try { string line; ifstream in{ argv[1] }; Omapbuf buffer(argv[2], ios::in | ios::out); // Omapbuf buffer(argv[2], ios::in | ios::out | ios::app); // ios::in | (fs::exists(argv[2]) ? ios::app : ios::trunc) // ); // append to existing file ostream out{ &buffer }; // file to write // out << "hello world" << endl; //return 0; // out.seekp(20); // // getline(in, line); // out << line << '\n'; // //return 0; // arg 4: 'l' - write lines, 'w' - raw writes, 'r' (default: rdbuf) switch (argc == 4 ? *argv[3] : 'r') { case 'r': out << in.rdbuf(); // block-wise insertion break; case 'l': while (getline(in, line)) // line-wise insertion out << line << '\n'; break; case 'w': while (getline(in, line)) // raw writes { line += '\n'; out.write(line.c_str(), line.length()); } break; default: cout << "in out [l(ine), r(rdbuf), w(write)]\n"; break; } xerr("DONE"); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } bobcat-6.07.01/omapbuf/demo/main.ih0000664000175000017500000000031414673353434015742 0ustar frankfrank#include "../../xerr/xerr.ih" #include #include #include #include #include #include "../omapbuf" using namespace std; namespace fs = filesystem; bobcat-6.07.01/omapbuf/icmconf0000664000175000017500000000010114673353434015103 0ustar frankfrank#define LIBRARY "omapbuf" #include "../icmconf.lib" bobcat-6.07.01/omapbuf/sync.cc0000664000175000017500000000012614673353434015034 0ustar frankfrank #include "omapbuf.ih" //override int Omapbuf::sync() { osync(); return 0; } bobcat-6.07.01/omapbuf/destructor.cc0000664000175000017500000000016314673353434016257 0ustar frankfrank #include "omapbuf.ih" // overrides Omapbuf::~Omapbuf() { sync(); fs::resize_file(fname(), realSize()); } bobcat-6.07.01/omapbuf/seekoff.cc0000664000175000017500000000157314673353434015511 0ustar frankfrank#define XERR #include "omapbuf.ih" // called by seekg()/tellg() (tellg using 0, ios::cur) ios::pos_type Omapbuf::seekoff(ios::off_type pos, ios::seekdir where, ios::openmode mode) { //xerr("pos = " << pos << ", where = " << where); pos = setAbsPos(pos, where) < 0 ? -1 : absPos(); //xerr("OmapBuf absPos set to " << pos); if (pos == -1 or pbase() == 0) // invalid pos or no buffer return pos; // then simply return pos size_t newPos = pos; pbump( // abspos is outside of the buffer ? newPos < offset() or offset() + mapLength() <= newPos ? epptr() - pptr() // then the buffer is exhausted : // or reset gptr() newPos - offset() - (pptr() - pbase()) ); return pos; } bobcat-6.07.01/omapbuf/omapbuf.ih0000664000175000017500000000031314736315237015521 0ustar frankfrank#include "../xerr/xerr.ih" #include "omapbuf" #include #include #include #include using namespace std; using namespace FBB; namespace fs = filesystem; bobcat-6.07.01/omapbuf/seekpos.cc0000664000175000017500000000112014673353434015524 0ustar frankfrank#define XERR #include "omapbuf.ih" std::ios::pos_type Omapbuf::seekpos(ios::pos_type offset, ios::openmode mode) { return seekoff(offset, ios::beg, mode); // // absPos in the current buffer? // if (offset() <= absPos() and absPos() <= offset() + length()) // { // setp(begin(), begin() + length()); // pbump(absPos() - offset()); // go to the next write position // } // else // if not in the current buffer // map(PROT_READ | PROT|WRITE); // then mmap } bobcat-6.07.01/omapbuf/load.cc0000664000175000017500000000033114673353434014775 0ustar frankfrank#define XERR #include "omapbuf.ih" bool Omapbuf::load() { if (append()) setAbsPos(fileSize(), ios::beg); if (not map(PROT_READ | PROT_WRITE)) return false; setpBuf(); return true; } bobcat-6.07.01/ommapstream/0000775000175000017500000000000014736767322014453 5ustar frankfrankbobcat-6.07.01/ommapstream/ommapstream2.cc0000664000175000017500000000034114673353434017362 0ustar frankfrank#include "ommapstream.ih" OmmapStream::OmmapStream(string const &fname, char const *bufSize, IOS::openmode openMode, mode_t mode) : MmapBuf(fname, bufSize, openMode, mode), ostream(this) {} bobcat-6.07.01/ommapstream/demo/0000775000175000017500000000000014673353434015372 5ustar frankfrankbobcat-6.07.01/ommapstream/demo/build0000775000175000017500000000064614673353434016425 0ustar frankfrank#!/bin/bash # rm main.o if [ "main.cc" -nt "main.o" ] ; then g++ ${ICMAKE_CPPSTD} -c -Wall -fdiagnostics-color=never main.cc || exit 1 fi CMD="g++ ${ICMAKE_CPPSTD} -Wall -fdiagnostics-color=never main.o \ -L../tmp -L../../mmapbuf/tmp -lommapstream -lmmapbuf -lbobcat -s" # CMD="g++ ${ICMAKE_CPPSTD} -Wall main.cc ../*.o -lbobcat -s" # CMD="g++ ${ICMAKE_CPPSTD} -Wall main.cc -lbobcat -s" echo $CMD $CMD bobcat-6.07.01/ommapstream/demo/main.cc0000664000175000017500000000744714673353434016641 0ustar frankfrank#define XERR #include #include #include #include #include #include "../ommapstream" using namespace std; namespace fs = filesystem; using namespace FBB; char usage[] = R"( 1 offset - seekg offset on the 1st file 2 offset - seekp offset on the 2nd file b - insert the 1st file's rdbuf into the 2nd file c - clear the files f - 2nd file's size l nr - insert nr lines from the 1st file into the 2nd file p - put a single character fm the 1st file into the 2nd file q - quit s - sync the 2nd file t - 2nd file's tellp w nr - write nr chars from the 1st file to the 2nd file )"; int main(int argc, char **argv) try { if (argc == 1) { cout << "1st argument: input file, 2nd arg: output file, " "3rd opt. arg: buf size,\n" "4th opt. arg: 1: ios::ate, 2: ios::app, 3: both\n"; return 1; } ifstream in(argv[1]); ios::openmode mode = fs::exists(argv[2]) ? ios::in | ios::out : ios::out; if (argc > 4) { char ch = *argv[4]; mode |= ch == '1' ? ios::ate : ch == '2' ? ios::app : ch == '3' ? ios::ate | ios::app : ios::out; // by default, no further action } OmmapStream out{ argv[2], argv[3], mode }; // if (argc <= 3) // cout << usage << "\n" cout << "bufSize: " << out.bufSize() << "\n" "fileSize: " << out.fileSize() << '\n'; string line; size_t lineNr = 0; size_t value = 0; while (true) { cout << '\n' << ++lineNr << "? "; getline(cin, line); switch (line.front()) { case 'b': out << in.rdbuf(); break; case 'c': in.clear(); out.clear(); break; case 'f': cout << out.fileSize() << '\n'; break; case 'l': { line.front() = ' '; size_t idx; for (idx = 0, value = stoul(line); idx != value; ++idx) { if (not getline(in, line)) break; out << line << '\n'; } cout << "inserted " << idx << " lines\n"; } break; case '1': line.front() = ' '; value = stoul(line); in.seekg(value); break; case '2': line.front() = ' '; value = stoul(line); out.seekp(value); break; case 'p': out << static_cast(in.get()); break; case 'q': cout.put('\n'); return 0; case 's': out.flush(); break; case 't': break; case 'w': line.front() = ' '; value = stoul(line); line.resize(value); in.read(&line.front(), value); value = in.gcount(); out.write(&line.front(), value); cout << "\nwrote " << value << " chars from " << argv[1] << " to " << argv[2] << '\n'; break; default: cout << "undefined input: `" << line << "'\n"; break; } value = out.tellp(); cout << "in OK: " << in.good() << ", out OK: " << out.good() << ", at " << value << '\n'; } } catch (exception const &exc) { cout << exc.what() << '\n'; return 1; } bobcat-6.07.01/ommapstream/demo/inout.tgz0000664000175000017500000000046414673353434017262 0ustar frankfrank‹íØ»NÃ0`Ï~Š#••ÖvnCÛ01±ub‡X$NÉ…ðøØA@.K©*þOŠŽtìÈ–­±±ìä„Ç¡¯2‰Ä²Î”Œ˜ c%B$B2!E(Fâô[cl쇬#be—ÙÇoæý4~¡EîxMWôVŸ8çc¯i2CEœœ®¡ë’ÚqØR¶v…šÌØužûÉ;Ú‘±”Ò¦ÐÏ;Öõ– SÎ?øOñ©2yE}ÕŽuáËD¶õ#G7!³]ÝÐ~ïV?÷aüCþ~N½Æœÿð«üKGò#ÿR%>ÿq ÿael^…¦iû¡ÓY“òÏžëû°ìè—\ÓÚiø­U¡Kc5Ýß|ñÞV¾?Ê{ƒpÑ^ÕÚÙT(bobcat-6.07.01/ommapstream/ommapstream1.cc0000664000175000017500000000013414673353434017361 0ustar frankfrank#include "ommapstream.ih" OmmapStream::OmmapStream() : MmapBuf(), ostream(this) {} bobcat-6.07.01/ommapstream/open2.cc0000664000175000017500000000032714673353434016002 0ustar frankfrank#include "ommapstream.ih" void OmmapStream::open(string const &fname, char const *bufSize, IOS::openmode openMode, mode_t mode) { *this = OmmapStream{ fname, bufSize, openMode, mode }; } bobcat-6.07.01/ommapstream/ommapstream.ih0000664000175000017500000000010414736315237017307 0ustar frankfrank#include "ommapstream" using namespace std; using namespace FBB; bobcat-6.07.01/ommapstream/icmconf0000664000175000017500000000010514673353434016003 0ustar frankfrank#define LIBRARY "ommapstream" #include "../icmconf.lib" bobcat-6.07.01/ommapstream/ommapstream0000664000175000017500000000177614736767322016736 0ustar frankfrank#ifndef INCLUDED_BOBCAT_OMMAPSTREAM_ #define INCLUDED_BOBCAT_OMMAPSTREAM_ #include #include #include namespace FBB { struct OmmapStream: private MmapBuf, public std::ostream { OmmapStream(); // 1 OmmapStream(std::string const &fname, char const *bufSize = 0, IOS::openmode openMode = IOS::out, mode_t mode = 0644); // 2 OmmapStream(OmmapStream &&tmp) = default; OmmapStream &operator=(OmmapStream &&tmp) = default; void open(std::string const &fname, char const *bufSize = 0, // 1 IOS::openmode openMode = IOS::out, mode_t mode = 0644); size_t bufSize() const; size_t fileSize() const; }; inline size_t OmmapStream::bufSize() const { return static_cast(*this).bufSize(); } inline size_t OmmapStream::fileSize() const { return static_cast(*this).fileSize(); } } // FBB #endif bobcat-6.07.01/omutexstream/0000775000175000017500000000000014736742656014666 5ustar frankfrankbobcat-6.07.01/omutexstream/data.cc0000664000175000017500000000011014673353434016066 0ustar frankfrank#include "omutexstream.ih" recursive_mutex OMutexStream::Out::s_mutex; bobcat-6.07.01/omutexstream/out1.cc0000664000175000017500000000021414673353434016052 0ustar frankfrank#include "omutexstream.ih" OMutexStream::Out::Out(OMutexStream const &mstr) : std::ostream(mstr.d_out.rdbuf()) { s_mutex.lock(); } bobcat-6.07.01/omutexstream/omutexstream.ih0000664000175000017500000000020614736315237017732 0ustar frankfrank#include "omutexstream" //#include //#define XERR std::cerr << __FILE__": " using namespace std; using namespace FBB; bobcat-6.07.01/omutexstream/operatorinsert1.f0000664000175000017500000000025714673353434020172 0ustar frankfranktemplate OMutexStream::Out operator<<(OMutexStream const &mstr, Tp &&tp) { OMutexStream::Out out{ mstr }; out << std::forward(tp); return out; } bobcat-6.07.01/omutexstream/omutexstream1.f0000664000175000017500000000011114673353434017634 0ustar frankfrankinline OMutexStream::OMutexStream(std::ostream &out) : d_out(out) {} bobcat-6.07.01/omutexstream/out2.f0000664000175000017500000000011414673353434015712 0ustar frankfrankinline OMutexStream::Out::Out(Out &&tmp) : std::ostream(tmp.rdbuf()) {} bobcat-6.07.01/omutexstream/operatorinsert2.f0000664000175000017500000000026014673353434020165 0ustar frankfranktemplate OMutexStream::Out operator<<(OMutexStream const &mstr, Ret &(*manip)(Ret &os)) { OMutexStream::Out out{ mstr }; out << manip; return out; } bobcat-6.07.01/omutexstream/icmconf0000664000175000017500000000010214673353434016210 0ustar frankfrank#define LIBRARY "omutexstream" #include "../icmconf" bobcat-6.07.01/omutexstream/destructor.cc0000664000175000017500000000012014673353434017354 0ustar frankfrank#include "omutexstream.ih" OMutexStream::Out::~Out() { s_mutex.unlock(); } bobcat-6.07.01/omutexstream/omutexstream0000664000175000017500000000175114673353434017342 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-6.07.01/omutexstream/ostream.f0000664000175000017500000000014214673353434016474 0ustar frankfrankinline OMutexStream::Out OMutexStream::ostream() const { return OMutexStream::Out{ *this }; } bobcat-6.07.01/omutexstream/driver/0000775000175000017500000000000014737552575016161 5ustar frankfrankbobcat-6.07.01/omutexstream/driver/build0000775000175000017500000000035614673353434017202 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-6.07.01/omutexstream/driver/driver.cc0000664000175000017500000000165214673353434017757 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-6.07.01/onekey/0000775000175000017500000000000014736742656013423 5ustar frankfrankbobcat-6.07.01/onekey/get.cc0000664000175000017500000000026514673353434014504 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-6.07.01/onekey/setecho.f0000664000175000017500000000011314673353434015207 0ustar frankfrankinline void OneKey::setEcho(Mode state) { d_useEcho = (state == ON); } bobcat-6.07.01/onekey/onekey0000664000175000017500000000124414673353434014631 0ustar frankfrank#ifndef INCLUDED_BOBCAT_ONEKEY_ #define INCLUDED_BOBCAT_ONEKEY_ #include #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-6.07.01/onekey/onekey.cc0000664000175000017500000000133314673353434015214 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-6.07.01/onekey/onekey.ih0000664000175000017500000000015014736315237015222 0ustar frankfrank#include "onekey" #include #include using namespace std; using namespace FBB; bobcat-6.07.01/onekey/destructor.cc0000664000175000017500000000013414673353434016116 0ustar frankfrank#include "onekey.ih" OneKey::~OneKey() { tcsetattr(STDIN_FILENO, TCSANOW, &d_saved); } bobcat-6.07.01/onekey/driver/0000775000175000017500000000000014737552575014716 5ustar frankfrankbobcat-6.07.01/onekey/driver/build0000775000175000017500000000023314673353434015731 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-6.07.01/onekey/driver/driver.cc0000664000175000017500000000152314673353434016511 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-6.07.01/osharedstream/0000775000175000017500000000000014736742656014772 5ustar frankfrankbobcat-6.07.01/osharedstream/osharedstream3.cc0000664000175000017500000000023314673353434020213 0ustar frankfrank#include "osharedstream.ih" OSharedStream::OSharedStream(size_t id, std::ios::openmode openMode) : SharedBuf(id, openMode), std::ostream(this) {} bobcat-6.07.01/osharedstream/osharedstream0000664000175000017500000000223414673353434017547 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-6.07.01/osharedstream/truncate.f0000664000175000017500000000015414673353434016756 0ustar frankfrankinline bool OSharedStream::truncate(std::streamsize offset) { return sharedMemory().truncate(offset); } bobcat-6.07.01/osharedstream/osharedstream1.cc0000664000175000017500000000012314673353434020207 0ustar frankfrank#include "osharedstream.ih" OSharedStream::OSharedStream() : ostream(this) {} bobcat-6.07.01/osharedstream/osharedstream.ih0000664000175000017500000000010614736315237020141 0ustar frankfrank#include "osharedstream" using namespace std; using namespace FBB; bobcat-6.07.01/osharedstream/open2.cc0000664000175000017500000000025014673353434016311 0ustar frankfrank#include "osharedstream.ih" void OSharedStream::open(int id, std::ios::openmode openMode) { setMemory(SharedMemory(id)); setOpenMode(openMode); clear(); } bobcat-6.07.01/osharedstream/icmconf0000664000175000017500000000010314673353434016315 0ustar frankfrank#define LIBRARY "sharedsegment" #include "../icmconf" bobcat-6.07.01/osharedstream/open1.cc0000664000175000017500000000041214673353434016310 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-6.07.01/osharedstream/meminfo.cc0000664000175000017500000000025714673353434016727 0ustar frankfrank#include "osharedstream.ih" void OSharedStream::memInfo(std::ostream &out, char const *end) const { static_cast(this)->memInfo(out); out << end; } bobcat-6.07.01/osharedstream/osharedstream2.cc0000664000175000017500000000041014673353434020207 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-6.07.01/osymcryptbase/0000775000175000017500000000000014736742656015035 5ustar frankfrankbobcat-6.07.01/osymcryptbase/overflow.cc0000664000175000017500000000075114673353434017202 0ustar frankfrank#include "osymcryptbase.ih" int OSymCryptBase::overflow(int ch) { if (d_eoi) return EOF; evpUpdate(); // process the so far received chars // prepare EoiBuf for the next input if (ch != EOF) // write a character? { *pptr() = static_cast(ch); // put it into the buffer pbump(1); // advance the buffer's pointer } return ch; } bobcat-6.07.01/osymcryptbase/osymcryptbase0000664000175000017500000000504314673353434017656 0ustar frankfrank#ifndef INCLUDED_BOBCAT_OSYMCRYPTBASE_ #define INCLUDED_BOBCAT_OSYMCRYPTBASE_ #include #include #include #include #include #include #include namespace FBB { namespace IUO // the facilities defined here are not further documented { // elsewhere. The OSymCryptBase class defined below // should only be used by ISymCryptStreambuf. class OSymCryptBase: private SymCryptBase, public EoiBuf { std::unique_ptr d_ofStream; // used by the 2nd constructor std::ostream &d_outStream; // destination stream to write bool d_eoi = false; int (*d_evpUpdate)(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, unsigned char const *in, int inl); int (*d_evpFinal)(EVP_CIPHER_CTX *, unsigned char *out, int *outl); public: OSymCryptBase( std::ostream &outStream, std::string const &cipherName, std::string const &key, std::string const &iv, size_t inBufSize, OSSL_PARAM const *params, int (*evpInit)(EVP_CIPHER_CTX *ctx, EVP_CIPHER const *type, unsigned char const *key, unsigned char const *iv, OSSL_PARAM const *params), 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) ); OSymCryptBase( std::string const &outStreamName, std::string const &cipherName, std::string const &key, std::string const &iv, size_t inBufSize, OSSL_PARAM const *params, int (*evpInit)(EVP_CIPHER_CTX *ctx, EVP_CIPHER const *type, unsigned char const *key, unsigned char const *iv, OSSL_PARAM const *params), 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) ); ~OSymCryptBase() override; using SymCryptBase::keyLength; using SymCryptBase::ivLength; private: void eoi_() override; void evpFinal(); void evpUpdate(); int overflow(int ch) override; int sync() override; }; } // IUO } // FBB #endif bobcat-6.07.01/osymcryptbase/evpupdate.cc0000664000175000017500000000112314673353434017326 0ustar frankfrank#include "osymcryptbase.ih" void OSymCryptBase::evpUpdate() { size_t inBufRead = pptr() - pbase(); // # read chars checkOutBufSize(inBufRead); int nOutputChars; if (not ((*d_evpUpdate)( // en/decrypt the bytes in d_inBuf ctx(), uOutBuf(), &nOutputChars, ucharPtr(), inBufRead )) ) throw Exception{} << "EVP_{En,De}cryptUpdate failed"; d_outStream.write(outBuf(), nOutputChars); // write the processed // chars to d_outSteam setp(); } bobcat-6.07.01/osymcryptbase/evpfinal.cc0000664000175000017500000000054314673353434017142 0ustar frankfrank#include "osymcryptbase.ih" void OSymCryptBase::evpFinal() { int outBufSize; checkOutBufSize(blockSize()); if (not ((*d_evpFinal)( // finalize en/decryption ctx(), uOutBuf(), &outBufSize )) ) throw Exception{} << "EVP_{En,De}cryptFinal failed"; d_outStream.write(outBuf(), outBufSize); } bobcat-6.07.01/osymcryptbase/icmconf0000664000175000017500000000010714673353434016364 0ustar frankfrank#define LIBRARY "osymcryptbase" #include "../icmconf.lib" bobcat-6.07.01/osymcryptbase/osymcryptbase.ih0000664000175000017500000000015514736315237020253 0ustar frankfrank#include "osymcryptbase" #include using namespace std; using namespace FBB; using namespace IUO; bobcat-6.07.01/osymcryptbase/osymcryptbase2.cc0000664000175000017500000000173414673353434020327 0ustar frankfrank#include "osymcryptbase.ih" OSymCryptBase::OSymCryptBase( string const &outStreamName, string const &cipherName, string const &key, string const &iv, size_t inBufSize, OSSL_PARAM const *params, int (*evpInit)(EVP_CIPHER_CTX *, EVP_CIPHER const *, unsigned char const *key, unsigned char const *iv, OSSL_PARAM const *param), int (*evpUpdate)(EVP_CIPHER_CTX *, unsigned char *out, int *outl, unsigned char const *in, int inl), int (*evpFinal)(EVP_CIPHER_CTX *, unsigned char *out, int *outl) ) : SymCryptBase(cipherName, key, iv, params, evpInit), EoiBuf(inBufSize < 100 ? 100 : inBufSize), d_ofStream( new ofstream{ Exception::factory(outStreamName) } ), d_outStream(*d_ofStream.get()), d_evpUpdate(evpUpdate), d_evpFinal(evpFinal) { setp(); } bobcat-6.07.01/osymcryptbase/sync.cc0000664000175000017500000000016314673353434016310 0ustar frankfrank#include "osymcryptbase.ih" int OSymCryptBase::sync() { evpUpdate(); d_outStream.flush(); return 0; } bobcat-6.07.01/osymcryptbase/destructor.cc0000664000175000017500000000015714673353434017535 0ustar frankfrank#include "osymcryptbase.ih" OSymCryptBase::~OSymCryptBase() { eoi_(); // EVP_CIPHER_CTX_free(d_ctx); } bobcat-6.07.01/osymcryptbase/eoi.cc0000664000175000017500000000045314673353434016112 0ustar frankfrank#include "osymcryptbase.ih" void OSymCryptBase::eoi_() { if (d_eoi) return; evpUpdate(); // process available chars in the input d_eoi = true; resize(0); // clear the input buffer evpUpdate(); // update an empty buffer } bobcat-6.07.01/osymcryptbase/osymcryptbase1.cc0000664000175000017500000000156214673353434020325 0ustar frankfrank#include "osymcryptbase.ih" OSymCryptBase::OSymCryptBase( ostream &outStream, string const &cipherName, string const &key, string const &iv, size_t inBufSize, OSSL_PARAM const *params, int (*evpInit)(EVP_CIPHER_CTX *, EVP_CIPHER const *, unsigned char const *key, unsigned char const *iv, OSSL_PARAM const *param), int (*evpUpdate)(EVP_CIPHER_CTX *, unsigned char *out, int *outl, unsigned char const *in, int inl), int (*evpFinal)(EVP_CIPHER_CTX *, unsigned char *out, int *outl) ) : SymCryptBase(cipherName, key, iv, params, evpInit), EoiBuf(inBufSize < 100 ? 100 : inBufSize), d_outStream(outStream), d_evpUpdate(evpUpdate), d_evpFinal(evpFinal) { setp(); } bobcat-6.07.01/osymcryptstream/0000775000175000017500000000000014673353434015406 5ustar frankfrankbobcat-6.07.01/osymcryptstream/osymcryptstream0000664000175000017500000000132314673353434020615 0ustar frankfrank#ifndef INCLUDED_BOBCAT_OSYMCRYPTSTREAM_ #define INCLUDED_BOBCAT_OSYMCRYPTSTREAM_ #include namespace FBB { template struct OSymCryptStream: private OSymCryptStreambuf, public std::ostream { template OSymCryptStream( // 1.f StreamSpec &streamSpec, std::string const &cipherName, std::string const &key, std::string const &iv, size_t inBufSize = 100 ); using OSymCryptStreambuf::keyLength; using OSymCryptStreambuf::ivLength; }; #include "osymcryptstream1.f" } // namespace FBB #endif bobcat-6.07.01/osymcryptstream/osymcryptstream1.f0000664000175000017500000000062114673353434021122 0ustar frankfranktemplate template OSymCryptStream::OSymCryptStream( StreamSpec &streamSpec, std::string const &cipherName, std::string const &key, std::string const &iv, size_t inBufSize ) : OSymCryptStreambuf( streamSpec, cipherName, key, iv, inBufSize ), std::ostream(this) {} bobcat-6.07.01/osymcryptstream/driver/0000775000175000017500000000000014737552575016711 5ustar frankfrankbobcat-6.07.01/osymcryptstream/driver/build0000775000175000017500000000075314673353434017733 0ustar frankfrank#!/bin/bash # # using libbobcat: g++ `cat ../../c++std` -O2 -Wall -o driver driver.cc -lbobcat -lcrypto exit 0 # using local libraries and libbobcat for other requirements: g++ `cat ../../c++std` -O2 -Wall -o driver driver.cc \ -L../../symcryptbase/tmp/ \ -L../../osymcryptbase/tmp/ \ -losymcryptbase -lsymcryptbase -lbobcat -lcrypto # g++ `cat ../../c++std` -O2 -Wall -o driver -isystem ../../tmp driver.cc \ # -L ../../tmp/lib/ -lbobcat -lcrypto bobcat-6.07.01/osymcryptstream/driver/driver.cc0000664000175000017500000000327514673353434020512 0ustar frankfrank#include #include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) try { if (argc == 1) { cout << "arg[1]: e - encrypt, d - decrypt,\n" "arg[2]: file to process, arg[3]: processed file\n"; return 0; } string key = "0123456789abcdef0123456789abcdef"; cout << "encryption key ? "; cin >> key; while (key.size() < 32) key += key; string iv = " 0123456789ab" "456"; char cipherName[] = "AES-256-GCM" //"AES-256-CBC" ; ifstream in{ argv[2] }; ofstream out{ argv[3] }; if (*argv[1] == 'e') { OSymCryptStream enc{ out, cipherName, key, iv, 100 }; // comment out the above statement and uncomment the next // to use the constructor expecting a string as 1st arg: // OSymCryptStream enc{ argv[3], cipherName, key, // iv, 100 }; enc << in.rdbuf() << eoi; //in.seekg(0); // when activated, this won't //enc << in.rdbuf(); // be processed due to '<< eoi' } else { OSymCryptStream decrypt{ out, cipherName, key, iv, 100 }; // comment out the above statement and uncomment the next // to use the constructor expecting a string as 1st arg: // OSymCryptStream decrypt{ argv[3], cipherName, key, // iv, 100 }; decrypt << in.rdbuf() << eoi; } } catch (exception const &exc) { cerr << exc.what() << '\n'; } bobcat-6.07.01/osymcryptstreambuf/0000775000175000017500000000000014673353434016103 5ustar frankfrankbobcat-6.07.01/osymcryptstreambuf/osymcryptstreambuf1.f0000664000175000017500000000100114673353434022305 0ustar frankfranktemplate inline OSymCryptStreambuf::OSymCryptStreambuf( StreamSpec &streamSpec, std::string const &cipherName, std::string const &key, std::string const &iv, size_t inBufSize ) : OSymCryptBase( streamSpec, cipherName, key, iv, inBufSize, 0, &EVP_EncryptInit_ex2, &EVP_EncryptUpdate, &EVP_EncryptFinal_ex ) {} bobcat-6.07.01/osymcryptstreambuf/osymcryptstreambuf2.f0000664000175000017500000000100014673353434022305 0ustar frankfranktemplate inline OSymCryptStreambuf::OSymCryptStreambuf( StreamSpec &streamSpec, std::string const &cipherName, std::string const &key, std::string const &iv, size_t inBufSize ) : OSymCryptBase( streamSpec, cipherName, key, iv, inBufSize, 0, &EVP_DecryptInit_ex2, &EVP_DecryptUpdate, &EVP_DecryptFinal_ex ) {} bobcat-6.07.01/osymcryptstreambuf/osymcryptstreambuf0000664000175000017500000000246514673353434022017 0ustar frankfrank#ifndef INCLUDED_BOBCAT_OSYMCRYPTSTREAMBUF_ #define INCLUDED_BOBCAT_OSYMCRYPTSTREAMBUF_ #include #include namespace FBB { // generic class name, only 2 specializations exist: ENCRYPT and DECRYPT // defined in FBB::CryptType template class OSymCryptStreambuf; template <> class OSymCryptStreambuf: public IUO::OSymCryptBase { public: template OSymCryptStreambuf( // 1.f StreamSpec &streamSpec, std::string const &cipherName, std::string const &key, std::string const &iv, size_t inBufSize = 100 ); // inherits static size_t keyLength(char const *cipherName) and // size_t ivLength(char const *cipherName) }; template <> class OSymCryptStreambuf: public IUO::OSymCryptBase { public: template OSymCryptStreambuf( // 2.f StreamSpec &streamSpec, std::string const &cipherName, std::string const &key, std::string const &iv, size_t inBufSize = 100 ); }; #include "osymcryptstreambuf1.f" #include "osymcryptstreambuf2.f" } // namespace FBB #endif bobcat-6.07.01/pattern/0000775000175000017500000000000014736742656013606 5ustar frankfrankbobcat-6.07.01/pattern/pattern0000664000175000017500000001361514673353434015204 0ustar frankfrank#ifndef INCLUDED_BOBCAT_PATTERN_ #define INCLUDED_BOBCAT_PATTERN_ #include #include // for pair<> #include #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 { using conversion = std::pair; 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: using Position = std::pair; // 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-6.07.01/pattern/pattern.ih0000664000175000017500000000540414736315237015577 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" 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 { std::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 using StatePair = std::pair; static std::vector s_transition; std::string d_target; std::string::iterator d_next; public: //static void setup(); PerlSetFSA(); void convert(std::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 std; using namespace FBB; bobcat-6.07.01/pattern/position.cc0000664000175000017500000000053514673353434015754 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-6.07.01/pattern/before.cc0000664000175000017500000000016114673353434015345 0ustar frankfrank#include "pattern.ih" string Pattern::before() const { return d_text.substr(0, d_subExpression[0].rm_so); } bobcat-6.07.01/pattern/validatorobject.cc0000664000175000017500000000142214673353434017260 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-6.07.01/pattern/convert.cc0000664000175000017500000000265514673353434015575 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-6.07.01/pattern/data.cc0000664000175000017500000000434514673353434015024 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-6.07.01/pattern/regex.cc0000664000175000017500000000120114673353434015211 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-6.07.01/pattern/beyond.cc0000664000175000017500000000025014673353434015362 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-6.07.01/pattern/operatorindex.cc0000664000175000017500000000050014673353434016763 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-6.07.01/pattern/operatorassign2.cc0000664000175000017500000000014714673353434017231 0ustar frankfrank#include "pattern.ih" Pattern &Pattern::operator=(Pattern &&tmp) { swap(tmp); return *this; } bobcat-6.07.01/pattern/operatorlshift2.cc0000664000175000017500000000032514673353434017234 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-6.07.01/pattern/actions.cc0000664000175000017500000000125514673353434015550 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-6.07.01/pattern/fsadriver/0000775000175000017500000000000014673353434015563 5ustar frankfrankbobcat-6.07.01/pattern/fsadriver/build0000775000175000017500000004035614673353434016620 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-6.07.01/pattern/fsadriver/fsadriver.h0000664000175000017500000000017614673353434017725 0ustar frankfrank#ifndef INCLUDED_FSADRIVER_H_ #define INCLUDED_FSADRIVER_H_ #include #include namespace FBB { } #endif bobcat-6.07.01/pattern/fsadriver/fsadriver.cc0000664000175000017500000000107714673353434020064 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-6.07.01/pattern/pattern3.cc0000664000175000017500000000045614673353434015652 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-6.07.01/pattern/pattern4.cc0000664000175000017500000000042114673353434015643 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-6.07.01/pattern/pattern2.f0000664000175000017500000000010314673353434015476 0ustar frankfrankinline Pattern::Pattern(Pattern const &other) { copy(other); } bobcat-6.07.01/pattern/end.f0000664000175000017500000000010014673353434014502 0ustar frankfrankinline size_t Pattern::end() const { return d_beyondLast; } bobcat-6.07.01/pattern/icmconf0000664000175000017500000000007514673353434015141 0ustar frankfrank#define LIBRARY "pattern" #include "../icmconf" bobcat-6.07.01/pattern/matched.f0000664000175000017500000000010714673353434015350 0ustar frankfrankinline std::string Pattern::matched() const { return (*this)[0]; } bobcat-6.07.01/pattern/operatorlshift1.cc0000664000175000017500000000017714673353434017240 0ustar frankfrank#include "pattern.ih" Pattern &Pattern::operator<<(int matchOptions) { d_matchOptions = matchOptions; return *this; } bobcat-6.07.01/pattern/destructor.f0000664000175000017500000000007314673353434016143 0ustar frankfrankinline Pattern::Regex::~Regex() { regfree(&d_regex); } bobcat-6.07.01/pattern/destructor.cc0000664000175000017500000000012314673353434016277 0ustar frankfrank#include "pattern.ih" Pattern::~Pattern() { if (d_regex) destroy(); } bobcat-6.07.01/pattern/operatorassign.cc0000664000175000017500000000020614673353434017143 0ustar frankfrank#include "pattern.ih" Pattern &Pattern::operator=(Pattern const &other) { Pattern tmp(other); swap(tmp); return *this; } bobcat-6.07.01/pattern/swap.cc0000664000175000017500000000013714673353434015060 0ustar frankfrank#include "pattern.ih" void Pattern::swap(Pattern &other) { fswap(*this, other, d_text); } bobcat-6.07.01/pattern/match.cc0000664000175000017500000000074514673353434015207 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-6.07.01/pattern/newregex.f0000664000175000017500000000016614673353434015574 0ustar frankfrankinline void Pattern::newRegex(std::string const &pattern, int options) { d_regex = new Regex(pattern, options); } bobcat-6.07.01/pattern/pattern.f0000664000175000017500000000012614673353434015421 0ustar frankfrankinline std::string const &Pattern::pattern() const { return Regex::s_converted; } bobcat-6.07.01/pattern/destroy.cc0000664000175000017500000000027414673353434015601 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-6.07.01/pattern/perlsetfsa.cc0000664000175000017500000000310514673353434016254 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-6.07.01/pattern/pattern1.cc0000664000175000017500000000035614673353434015647 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-6.07.01/pattern/driver/0000775000175000017500000000000014737552575015101 5ustar frankfrankbobcat-6.07.01/pattern/driver/build0000775000175000017500000000065714673353434016126 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-6.07.01/pattern/driver/driver.cc0000664000175000017500000000366714673353434016707 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-6.07.01/pattern/driver/driver.h0000664000175000017500000000017014673353434016533 0ustar frankfrank#ifndef INCLUDED_DRIVER_H_ #define INCLUDED_DRIVER_H_ #include #include namespace FBB { } #endif bobcat-6.07.01/pattern/driver/main.notused0000664000175000017500000000076414673353434017427 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-6.07.01/pattern/copy.cc0000664000175000017500000000056214673353434015062 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-6.07.01/pattern/setpattern.cc0000664000175000017500000000064514673353434016303 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-6.07.01/pf_iterator/0000775000175000017500000000000014736742656014447 5ustar frankfrankbobcat-6.07.01/pf_iterator/iterator1.cc0000664000175000017500000000014614673353434016661 0ustar frankfrank#include "../primefactors/primefactors.ih" PrimeFactors::iterator::iterator() : d_sentinel(1) {} bobcat-6.07.01/pf_iterator/checkinitialprimes.cc0000664000175000017500000000046514673353434020622 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-6.07.01/pf_iterator/next.cc0000664000175000017500000000036614673353434015731 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-6.07.01/pf_iterator/operatorpreinc.cc0000664000175000017500000000063714673353434020010 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-6.07.01/pf_iterator/icmconf0000664000175000017500000000034614673353434016003 0ustar frankfrank#define LIBRARY "pf_iterator" #include "../icmconf" #undef CXXFLAGS #define CXXFLAGS "--std=c++2a " ${AUXFLAGS} " -isystem " \ "/home/frank/git/bobcat/src/bobcat/tmp -Wall -O2" bobcat-6.07.01/pf_iterator/destructor.cc0000664000175000017500000000012314673353434017140 0ustar frankfrank#include "../primefactors/primefactors.ih" PrimeFactors::iterator::~iterator() {} bobcat-6.07.01/pf_iterator/iscomposite.cc0000664000175000017500000000052014673353434017301 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-6.07.01/pf_iterator/iterator2.cc0000664000175000017500000000044614673353434016665 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-6.07.01/pf_iteratorstream/0000775000175000017500000000000014736742656015663 5ustar frankfrankbobcat-6.07.01/pf_iteratorstream/writenewprimes.cc0000664000175000017500000000045714673353434021254 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-6.07.01/pf_iteratorstream/openstream.cc0000664000175000017500000000056714673353434020347 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-6.07.01/pf_iteratorstream/next.cc0000664000175000017500000000054014673353434017137 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-6.07.01/pf_iteratorstream/operatorpreinc.cc0000664000175000017500000000134514673353434021221 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-6.07.01/pf_iteratorstream/icmconf0000664000175000017500000000035414673353434017216 0ustar frankfrank#define LIBRARY "pf_iteratorstream" #include "../icmconf" #undef CXXFLAGS #define CXXFLAGS "--std=c++2a " ${AUXFLAGS} " -isystem " \ "/home/frank/git/bobcat/src/bobcat/tmp -Wall -O2" bobcat-6.07.01/pf_iteratorstream/newprimes.OBS0000664000175000017500000000045314673353434020233 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-6.07.01/pf_iteratorstream/destructor.cc0000664000175000017500000000016614673353434020363 0ustar frankfrank#include "../primefactors/primefactors.ih" PrimeFactors::iteratorStream::~iteratorStream() { writeNewPrimes(); } bobcat-6.07.01/pf_iteratorstream/readprimes.cc0000664000175000017500000000065614673353434020324 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-6.07.01/pf_iteratorstream/resetprimes.cc0000664000175000017500000000065614673353434020533 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-6.07.01/pf_iteratorstream/iteratorstream1.cc0000664000175000017500000000050714673353434021312 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-6.07.01/pipe/0000775000175000017500000000000014736742656013066 5ustar frankfrankbobcat-6.07.01/pipe/closereadfd.f0000664000175000017500000000006514673353434015501 0ustar frankfrankinline void Pipe::closeReadFd() { close(READ); } bobcat-6.07.01/pipe/writefd.f0000664000175000017500000000007514673353434014673 0ustar frankfrankinline int Pipe::writeFd() const { return d_fd[WRITE]; } bobcat-6.07.01/pipe/writeonlyfd.cc0000664000175000017500000000016114673353434015731 0ustar frankfrank#include "pipe.ih" int Pipe::writeOnlyFd() { int ret = writeOnly(); d_fd[WRITE] = -1; return ret; } bobcat-6.07.01/pipe/reset1.cc0000664000175000017500000000012714673353434014570 0ustar frankfrank#include "pipe.ih" void Pipe::reset() { close(); Pipe tmp; swap(tmp); } bobcat-6.07.01/pipe/pipe1.cc0000664000175000017500000000016614673353434014406 0ustar frankfrank#include "pipe.ih" Pipe::Pipe() { if (pipe(d_fd)) throw Exception{} << "Pipe::Pipe(): " << errnodescr; } bobcat-6.07.01/pipe/pipe3.cc0000664000175000017500000000013114673353434014400 0ustar frankfrank#include "pipe.ih" Pipe::Pipe(int const *fd) { memcpy(d_fd, fd, 2 * sizeof(int)); } bobcat-6.07.01/pipe/swap.f0000664000175000017500000000010614673353434014174 0ustar frankfrankinline void Pipe::swap(Pipe &other) { FBB::fswap(*this, other); } bobcat-6.07.01/pipe/reset2.cc0000664000175000017500000000015214673353434014567 0ustar frankfrank#include "pipe.ih" void Pipe::reset(int const *fds) { close(); Pipe tmp{ fds }; swap(tmp); } bobcat-6.07.01/pipe/pipe2.cc0000664000175000017500000000012214673353434014377 0ustar frankfrank#include "pipe.ih" Pipe::Pipe(Pipe &&tmp) : d_fd{ -1, -1} { swap(tmp); } bobcat-6.07.01/pipe/closewritefd.f0000664000175000017500000000006714673353434015722 0ustar frankfrankinline void Pipe::closeWriteFd() { close(WRITE); } bobcat-6.07.01/pipe/readonlyfd.cc0000664000175000017500000000015614673353434015516 0ustar frankfrank#include "pipe.ih" int Pipe::readOnlyFd() { int ret = readOnly(); d_fd[READ] = -1; return ret; } bobcat-6.07.01/pipe/pipe0000664000175000017500000000443414673353434013743 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(); // 1.cc Pipe(Pipe &&tmp); // 2.cc explicit Pipe(int const *fd); // fd: must be 2 FDs 3.cc explicit Pipe(bool initialize); // 4.cc // ~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 close(); // close the fds 1.cc void closeReadFd(); // .f void closeWriteFd(); // .f int readFd() const; // .f void readFrom(int filedescriptor); void readFrom(int const *filedescriptor, size_t nSwallow); int readOnly(); // closes the write FD // closes the FDs, sets read FD int readOnlyFd(); // to -1, returns the original FD // closes the npipes void reset(); // and reopens them 1.cc // closes the npipes and reopens // them with the provided 2 void reset(int const *fds); // read/write file descr. 2.cc void swap(Pipe &other); int writeFd() const; // .f int writeOnly(); // closes the read FD int writeOnlyFd(); // as readOnlyFd, using the write FD void writtenBy(int filedescriptor); void writtenBy(int const *filedescr, size_t nSwallow = 2); protected: void close(RW rw); // 2.cc }; #include "closereadfd.f" #include "closewritefd.f" #include "readfd.f" #include "swap.f" #include "writefd.f" } // FBB #endif bobcat-6.07.01/pipe/pipe.ih0000664000175000017500000000014114736315237014330 0ustar frankfrank#include "pipe" #include #include "../redirector/redirector" using namespace FBB; bobcat-6.07.01/pipe/close1.cc0000664000175000017500000000011614673353434014551 0ustar frankfrank#include "pipe.ih" void Pipe::close() { close(READ); close(WRITE); } bobcat-6.07.01/pipe/icmconf0000664000175000017500000000015514673353434014420 0ustar frankfrank#define LIBRARY "pipe" #define AUXFLAGS "-I../tmp -pthread" #include "../icmconf" bobcat-6.07.01/pipe/readfrom.cc0000664000175000017500000000063614673353434015171 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-6.07.01/pipe/readonly.cc0000664000175000017500000000012614673353434015201 0ustar frankfrank#include "pipe.ih" int Pipe::readOnly() { close(WRITE); return d_fd[READ]; } bobcat-6.07.01/pipe/writeonly.cc0000664000175000017500000000012714673353434015421 0ustar frankfrank#include "pipe.ih" int Pipe::writeOnly() { close(READ); return d_fd[WRITE]; } bobcat-6.07.01/pipe/pipe4.cc0000664000175000017500000000025114673353434014404 0ustar frankfrank#include "pipe.ih" Pipe::Pipe(bool initialize) { if (initialize) *this = Pipe{}; else { d_fd[READ] = -1; d_fd[WRITE] = -1; } } bobcat-6.07.01/pipe/readfrom2.cc0000664000175000017500000000040014673353434015240 0ustar frankfrank#include "pipe.ih" void Pipe::readFrom(int const *fd, size_t nSwallow) { close(WRITE); for (size_t idx = 0; idx != nSwallow; ++idx) { Redirector redirector{ d_fd[READ] }; redirector.swallow(fd[idx]); } close(READ); } bobcat-6.07.01/pipe/operatorassign.cc0000664000175000017500000000015114673353434016422 0ustar frankfrank#include "pipe.ih" Pipe &Pipe::operator=(Pipe &&tmp) { close(); swap(tmp); return *this; } bobcat-6.07.01/pipe/writtenby2.cc0000664000175000017500000000040214673353434015472 0ustar frankfrank#include "pipe.ih" void Pipe::writtenBy(int const *fd, size_t nSwallow) { close(READ); for (size_t idx = 0; idx != nSwallow; ++idx) { Redirector redirector{ d_fd[WRITE] }; redirector.swallow(fd[idx]); } close(WRITE); } bobcat-6.07.01/pipe/writtenby.cc0000664000175000017500000000064114673353434015415 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-6.07.01/pipe/close2.cc0000664000175000017500000000020314673353434014547 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-6.07.01/pipe/readfd.f0000664000175000017500000000007314673353434014452 0ustar frankfrankinline int Pipe::readFd() const { return d_fd[READ]; } bobcat-6.07.01/pipe/driver/0000775000175000017500000000000014737552575014361 5ustar frankfrankbobcat-6.07.01/pipe/driver/build0000775000175000017500000000023314673353434015374 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-6.07.01/pipe/driver/driver.cc0000664000175000017500000000177614673353434016166 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-6.07.01/primefactors/0000775000175000017500000000000014736742656014627 5ustar frankfrankbobcat-6.07.01/primefactors/primefactors.ih0000664000175000017500000000152014736315237017634 0ustar frankfrank#include "primefactors" #include #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-6.07.01/primefactors/addprimes.cc0000664000175000017500000000057114673353434017101 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-6.07.01/primefactors/reduce.cc0000664000175000017500000000055314673353434016400 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-6.07.01/primefactors/setsentinel.f0000664000175000017500000000015114673353434017320 0ustar frankfrankinline void FBB::PrimeFactors::iterator::setSentinel(BigInt const &value) { d_sentinel[0] = value; } bobcat-6.07.01/primefactors/atsentinel.f0000664000175000017500000000015514673353434017135 0ustar frankfrankinline bool FBB::PrimeFactors::iterator::atSentinel() const { return d_iterator == d_sentinel.begin(); } bobcat-6.07.01/primefactors/primefactors1.cc0000664000175000017500000000016714673353434017711 0ustar frankfrank#include "primefactors.ih" PrimeFactors::PrimeFactors(BigIntVector &primes) : d_iterator(new iterator(primes)) {} bobcat-6.07.01/primefactors/opstar.f0000664000175000017500000000014514673353434016276 0ustar frankfrankinline FBB::BigInt const &FBB::PrimeFactors::iterator::operator*() const { return *d_iterator; } bobcat-6.07.01/primefactors/opinc.f0000664000175000017500000000015714673353434016101 0ustar frankfrankinline FBB::PrimeFactors::iterator &FBB::PrimeFactors::iterator::operator++() { return operatorPreInc(); } bobcat-6.07.01/primefactors/factorize.cc0000664000175000017500000000050114673353434017110 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-6.07.01/primefactors/lastprime.f0000664000175000017500000000014514673353434016766 0ustar frankfrankinline FBB::BigInt const &FBB::PrimeFactors::iterator::lastPrime() const { return d_lastPrime; } bobcat-6.07.01/primefactors/icmconf0000664000175000017500000000034714673353434016164 0ustar frankfrank#define LIBRARY "primefactors" #include "../icmconf" #undef CXXFLAGS #define CXXFLAGS "--std=c++2a " ${AUXFLAGS} " -isystem " \ "/home/frank/git/bobcat/src/bobcat/tmp -Wall -O2" bobcat-6.07.01/primefactors/availableprimes.cc0000664000175000017500000000104714673353434020270 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-6.07.01/primefactors/primefactors2.cc0000664000175000017500000000022614673353434017706 0ustar frankfrank#include "primefactors.ih" PrimeFactors::PrimeFactors(string const &name, size_t blockSize) : d_iterator(new iteratorStream(name, blockSize)) {} bobcat-6.07.01/primefactors/primefactors0000664000175000017500000000433114673353434017241 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; }; using Factors = std::vector; private: using BigIntVector = std::vector; using ConstIterator = BigIntVector::const_iterator; 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-6.07.01/primefactors/driver/0000775000175000017500000000000014737552575016122 5ustar frankfrankbobcat-6.07.01/primefactors/driver/build0000775000175000017500000000102714673353434017137 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-6.07.01/primefactors/driver/driver.cc0000664000175000017500000000137114673353434017716 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-6.07.01/primefactors/nextprime.f0000664000175000017500000000010514673353434016775 0ustar frankfrankinline void FBB::PrimeFactors::iterator::nextPrime() { next(); } bobcat-6.07.01/proc/0000775000175000017500000000000014736742656013074 5ustar frankfrankbobcat-6.07.01/proc/activatordemo/0000775000175000017500000000000014673353434015725 5ustar frankfrankbobcat-6.07.01/proc/activatordemo/demo.cc0000664000175000017500000000274214673353434017165 0ustar frankfrank#include #include #include using namespace std; using namespace FBB; int pCount = 0; struct P { vector *d_i = 0; int d_id; struct A { std::vector

d_p; std::vector *d_i = 0; // pipes passed to Proc objects A(P &p, int val) { if (d_i == 0) d_i = new vector{ val }; else d_i->push_back(val); p.d_i = d_i; d_p.push_back(&p); } A(A &&tmp, P &p) { fswap(*this, tmp); d_i->push_back(10 * p.d_id); p.d_i = d_i; d_p.push_back(&p); } A(A &&tmp) // gebruikt door op| { fswap(*this, tmp); } ~A() { if (d_p.size() != 0) { for (P *p: d_p) p->out(); delete d_i; } } }; P() : d_id(++pCount) {} void out() { cout << "P " << d_id << ": "; if (d_i == 0) cout << "no entries"; else { for (int val: *d_i) cout << val << ' '; } cout << "\n\n"; } }; P::A operator|(int val, P &p) { return P::A{p, val}; } P::A operator|(P::A &&tmp, P &p) { return P::A{move(tmp), p}; } int main() { P p1; P p2; P p3; 4 | p1 | p2 | p3; } bobcat-6.07.01/proc/exitstatus.f0000664000175000017500000000010014673353434015437 0ustar frankfrankinline int Proc::exitStatus() const { return d_child.ret; } bobcat-6.07.01/proc/toout.cc0000664000175000017500000000043214673353434014544 0ustar frankfrank//#define XERR #include "proc.ih" void Proc::toOut() { if (d_writeOut != d_pipesPtr->size() - 1) return; IFdBufS buf{ (*d_pipesPtr)[d_writeOut].readOnlyFd(), d_bufSize }; d_out() << &buf; d_out().clear(); // clear because '<< &buf' may return EOF } bobcat-6.07.01/proc/parentprocess.cc0000664000175000017500000000010014673353434016252 0ustar frankfrank#include "proc.ih" // overrides void Proc::parentProcess() {} bobcat-6.07.01/proc/cerradmin.cc0000664000175000017500000000106014673353434015334 0ustar frankfrank#include "proc.ih" void Proc::cerrAdmin(char const *lab) const { std::cerr << lab << " Admin: "; if (d_admin == 0) std::cerr << "empty"; if (d_admin & ACTIVE) std::cerr << "ACTIVE "; if (d_admin & LOCAL_PIPES) std::cerr << "LOCAL_PIPES "; if (d_admin & USE_OUT) std::cerr << "USE_OUT "; if (d_admin & USE_ERR) std::cerr << "USE_ERR "; if (d_admin & THREAD_OUT) std::cerr << "THREAD_OUT "; if (d_admin & THREAD_ERR) std::cerr << "THREAD_ERR "; std::cerr << '\n'; } bobcat-6.07.01/proc/activator2.cc0000664000175000017500000000016014673353434015446 0ustar frankfrank#include "proc.ih" Proc::Activator::Activator(Activator &&tmp) : d_pipesPtr(0) { fswap(*this, tmp); } bobcat-6.07.01/proc/cerrmode.cc0000664000175000017500000000114014673353434015167 0ustar frankfrank#include "proc.ih" void Proc::cerrMode(char const *lab) const { std::cerr << lab << " 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 & REPLACE) std::cerr << "REPLACE "; std::cerr << '\n'; } bobcat-6.07.01/proc/useerr2.f0000664000175000017500000000012314673353434014616 0ustar frankfrankinline void Proc::useErr(std::string const &fname) { useStream(fname, CERR); } bobcat-6.07.01/proc/toerr.cc0000664000175000017500000000035414673353434014530 0ustar frankfrank//#define XERR #include "proc.ih" void Proc::toErr() { int fd = (*d_pipesPtr)[d_writeErr].readOnlyFd(); IFdBufS buf{ fd, d_bufSize }; d_err() << &buf; d_err().clear(); // clear because '<< &buf' may return EOF } bobcat-6.07.01/proc/prefork.cc0000664000175000017500000000121414673353434015041 0ustar frankfrank#define XERR #include "proc.ih" void Proc::preFork(IOMode mode, ProcType type, size_t bufSize, size_t timeLimit) { d_child = RetPid{}; // no child return value yet available d_timeLimit = timeLimit; rmBackticks(); // rm backticks from d_command // save the default data in d_forkData d_forkData = { setBufSize(bufSize), setIOMode(mode), setProcType(type), (d_admin & PIPE_SIGNAL) != 0 }; //xerr((d_forkData.pipeSignal ? "SIG_DFL" : "SIG_IGN")); signal(SIGPIPE, d_forkData.pipeSignal ? SIG_DFL : SIG_IGN); } bobcat-6.07.01/proc/proc1.cc0000664000175000017500000000101114673353434014410 0ustar frankfrank#include "proc.ih" Proc::Proc(string const &cmd, IOMode mode, ProcType type, size_t bufSize, size_t timeLimit, bool pipeSig) : d_ptr(0), // for now: unused. d_admin(LOCAL_PIPES), d_cmd(cmd), d_err(&cerr), d_in(0), d_out(&cout), d_pipesPtr(0), //new vector(3)), d_timeLimit(timeLimit), d_timerSem(0), d_id(++s_id) { pipeSignal(pipeSig); setBufSize(bufSize); setProcType(type); setIOMode(mode); rdbuf(&d_oBuf); } bobcat-6.07.01/proc/data.cc0000664000175000017500000000010514673353434014300 0ustar frankfrank#include "proc.ih" ofstream Proc::s_ignored; size_t Proc::s_id = 0; bobcat-6.07.01/proc/checkerrthread.cc0000664000175000017500000000020414673353434016345 0ustar frankfrank#include "proc.ih" void Proc::checkErrThread() { if (d_admin & THREAD_ERR) d_errThread.join(); endTimerThread(); } bobcat-6.07.01/proc/procidx.f0000664000175000017500000000010014673353434014672 0ustar frankfrankinline size_t Proc::procIdx() const { return d_child.pid; } bobcat-6.07.01/proc/useerr1.f0000664000175000017500000000011214673353434014613 0ustar frankfrankinline void Proc::useErr(std::ostream &err) { useStream(err, CERR); } bobcat-6.07.01/proc/outopfun.cc0000664000175000017500000000011714673353434015251 0ustar frankfrank#include "proc.ih" ostream &Proc::Out::operator()() { return *d_stream; } bobcat-6.07.01/proc/opactfname.cc0000664000175000017500000000056414673353434015515 0ustar frankfrank#include "proc.ih" namespace FBB { void operator|(Proc::Activator &&act, string const &fname) { Proc &proc = *act.d_procPtr.back(); proc.useOut(fname); proc.d_mode |= Proc::COUT; proc.d_mode &= ~Proc::IGNORE_COUT; // see the proc header file // proc.showMode(__FILE__); // proc.d_mode &= ~(Proc::IGNORE_COUT | Proc::CERR | } } // FBB bobcat-6.07.01/proc/pipes.cc0000664000175000017500000000031314673353434014510 0ustar frankfrank//#define XERR #include "proc.ih" // see also activator1.cc void Proc::pipes(vector *pipes, size_t nPipes) { d_pipesPtr = pipes; d_admin &= ~LOCAL_PIPES; d_read = nPipes - 3; } bobcat-6.07.01/proc/output.cc0000664000175000017500000000451114673353434014734 0ustar frankfrank#include "proc.ih" void Proc::output(Out &out) { struct Variables { IOMode useBits; unsigned threadBit; size_t pipeIdx; // read or write pipe idx IOMode ignoreBit; // if set, info goes to s_ignored unsigned setBit; // d_admin's bit to check ostream &stdOut; // default ostream to use thread &thr; // thread running threadFun void (Proc::*threadFun)(); // thread fun handling the output }; Variables vars = &out == &d_out ? Variables{ COUT | MERGE_COUT_CERR | IGNORE_COUT, // useBits THREAD_OUT, // threadBit d_writeOut, // pipeIdx IGNORE_COUT, // ignoreBit USE_OUT, // setBit cout, // stdOut d_outThread, // thr &Proc::toOut } // threadFun : Variables{ CERR | IGNORE_CERR, // useBits THREAD_ERR, // threadBit d_writeErr, // pipeIdx IGNORE_CERR, // ignoreBit USE_ERR, // setBit cerr, // stdOut d_errThread, // thr &Proc::toErr }; // threadFun if (not (d_mode & vars.useBits)) { d_admin &= ~vars.threadBit; closePipe(vars.pipeIdx); return; } d_admin |= vars.threadBit; // cout is used, so start its thread if (d_mode & vars.ignoreBit) // when ignored: output to s_ignore out = Out{ &s_ignored }; else if (not (d_admin & vars.setBit)) // or use the default, unless out = Out{ &vars.stdOut }; // already specified vars.thr = thread{ vars.threadFun, this }; } bobcat-6.07.01/proc/iomode.f0000664000175000017500000000010014673353434014476 0ustar frankfrankinline Proc::IOMode Proc::ioMode() const { return d_mode; } bobcat-6.07.01/proc/proc.ih0000664000175000017500000000123614736315237014352 0ustar frankfrank#include "proc" #include "../xerr/xerr.ih" #include #include #include #include #include struct FBB::Proc::ExecContext { size_t argc; // must eventually be at least 1 char const **argv; // 0-terminated array of pointers to the // arguments }; inline FBB::Proc::RetPid::RetPid(int rt, pid_t pd) : ret(rt), pid(pd) {} inline void FBB::Proc::closePipe(size_t idx) { (*d_pipesPtr)[idx].close(); } inline bool FBB::Proc::localPipes() const { return d_admin & LOCAL_PIPES; } using namespace std; using namespace FBB; bobcat-6.07.01/proc/out1.cc0000664000175000017500000000015514673353434014264 0ustar frankfrank#include "proc.ih" Proc::Out::Out(std::ostream *str, bool alloc) : d_stream(str), d_alloc(alloc) {} bobcat-6.07.01/proc/usestream1.cc0000664000175000017500000000025714673353434015470 0ustar frankfrank#include "proc.ih" // bit is set in d_mode void Proc::useStream(std::ostream &str, IOMode bit) { use(bit) = Out{ &str }; } bobcat-6.07.01/proc/childprocess.cc0000664000175000017500000000165114673353434016060 0ustar frankfrank#include "proc.ih" // overrides void Proc::childProcess() { ExecContext ec; if (d_procType != USE_SHELL) ec = analyzeCmd(); // No system, so run execl() or execle() else { ec.argv = new char const *[4]; ec.argv[d_writeOut] = "/bin/sh"; ec.argv[1] = "-c"; ec.argv[2] = d_cmd.c_str(); ec.argv[3] = 0; } (*(d_procType == USE_PATH ? execvp : execv)) (ec.argv[0], const_cast(ec.argv)); throw Exception{} << "Proc: cannot execv[p] " << d_cmd; } // char buffer[100]; // int nRead; // //// int fd = (*d_pipesPtr)[d_read].readFd(); // // while (true) // { // cin.read(buffer, 100); // nRead = cin.gcount(); // // //nRead = read(fd, buffer, d_bufSize); // // if (nRead == 0) // break; // // cout.write(buffer, nRead); // } // // cerr << "END\n"; // // throw 0; bobcat-6.07.01/proc/endtimerthread.cc0000664000175000017500000000024214673353434016370 0ustar frankfrank#define XERR #include "proc.ih" void Proc::endTimerThread() { if (d_timeLimit == 0) return; d_timerSem.notify(); d_timerThread.join(); } bobcat-6.07.01/proc/getpipes.cc0000664000175000017500000000041014673353434015206 0ustar frankfrank#include "proc.ih" void Proc::getPipes() // called by start, when (d_admin & LOCAL_PIPES) { delete d_pipesPtr; d_pipesPtr = new vector(3); // see activator1.cc d_read = 0; // pipe to read, sending to the child } bobcat-6.07.01/proc/opactostr.cc0000664000175000017500000000055314673353434015414 0ustar frankfrank#include "proc.ih" namespace FBB { void operator|(Proc::Activator &&act, ostream &out) { Proc &proc = *act.d_procPtr.back(); proc.useOut(out); proc.d_mode |= Proc::COUT; proc.d_mode &= ~Proc::IGNORE_COUT; // see the proc header file // proc.showMode(__FILE__); // proc.d_mode &= ~(Proc::IGNORE_COUT | Proc::CERR | } } // FBB bobcat-6.07.01/proc/settimelimit.cc0000664000175000017500000000027714673353434016112 0ustar frankfrank//#define XERR #include "proc.ih" size_t Proc::setTimeLimit(size_t timeLimit) { size_t ret = d_timeLimit; d_timeLimit = timeLimit; pipeSignal(timeLimit == 0); return ret; } bobcat-6.07.01/proc/useout2.f0000664000175000017500000000012314673353434014635 0ustar frankfrankinline void Proc::useOut(std::string const &fname) { useStream(fname, COUT); } bobcat-6.07.01/proc/activatordestr.cc0000664000175000017500000000303014673353434016425 0ustar frankfrank#include "proc.ih" Proc::Activator::~Activator() { // a previously constructed Activator if (d_procPtr.empty()) // in a pipe-sequence, whose vectors were return; // already moved to the next Activator for (Proc *ptr: d_procPtr) // start the child processes ptr->start(); // back() writes to cout thread resultThread{ &Proc::toOut, d_procPtr.back() }; d_procPtr.front()->readCin(); // read the input // close all Out/In pipes. Pipe 0 is for // readCin, Err pipes are handled next, // the last Out pipe is for resultThread for (size_t idx = 2, end = d_pipesPtr->size() - 1; idx != end; idx += 2) (*d_pipesPtr)[idx].close(); for (Proc *ptr: d_procPtr) // join the errThreads if active ptr->checkErrThread(); resultThread.join(); pid_t procIdx = 0; int procRet = 0; for (size_t idx = 0, end = d_procPtr.size(); idx != end; ++idx) { Proc *ptr = d_procPtr[idx]; // return the first failing Proc's // error code int ret = ptr->waitForChild(); if (idx == 1 or (ret != 0 and procRet == 0)) { procIdx = idx; procRet = ret; } } d_procPtr.back()->d_child = { procRet, procIdx }; delete d_pipesPtr; } bobcat-6.07.01/proc/activator1.cc0000664000175000017500000000263614673353434015457 0ustar frankfrank#include "proc.ih" // the first pipe is used by the first object forwarding its input // stream to its child. // the last pipe but one collects a child's cout info // the last pipe collects a child's cerr info // with multiple piped processes the last pipe is forwarded to the next // child's input stream // | pipe[0] - external info, read by the 1st child's CIN // | pipe[1] - the 1st child's CERR // | | pipe[2] - the 1st child's COUT, 2nd child's CIN // | +-------- - pipe frame used by the 1st child // | pipe[5] - the 2nd child's CERR // | pipe[4] - the 2nd child's COUT, the 3rd child's CIN // | +-------- - pipe frame used by the 2nd child // ... // | | pipe[#-3] - the last but one's child's COUT, the last child's CIN // | +-------- - pipe frame used by the 1st child // | pipe[#-2] - the last child's CERR // | pipe[#-1] - the last child's COUT // | +-------- - pipe frame used by the last child // Each process uses three pipes, each new process adds two new pipes. // After defining the new pipes: // read = size() - 3, // writeErr = size() - 2, // writeOut = size() - 1 Proc::Activator::Activator(Proc &proc) : d_pipesPtr(new vector(1)) // define one pipe { add(proc); // add proc to d_procPtr } bobcat-6.07.01/proc/setcommand.f0000664000175000017500000000011214673353434015357 0ustar frankfrankinline void Proc::setCommand(std::string const &cmd) { d_cmd = cmd; } bobcat-6.07.01/proc/setiomode.cc0000664000175000017500000000172114673353434015364 0ustar frankfrank#include "proc.ih" Proc::IOMode Proc::setIOMode(IOMode mode) { if (mode & ~IOMODES) throw invalid_argument("Undefined IOMode"); if ((mode & REPLACE) && (mode & ~REPLACE)) throw invalid_argument("IOModes cannot be combined with REPLACE"); 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"); IOMode ret = d_mode; d_mode = mode; return ret; } bobcat-6.07.01/proc/analyzecmd.cc0000664000175000017500000000137014673353434015523 0ustar frankfrank#include "proc.ih" Proc::ExecContext Proc::analyzeCmd() const { // split the elements in d_cmd String::Type type; vector elements(String::split(&type, d_cmd)); if (type != String::NORMAL) throw Exception{} << "Proc: " << d_cmd << ": 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 // proc. ec.argv[ec.argc] = 0; // terminate in a null ptr return ec; } bobcat-6.07.01/proc/cmd.f0000664000175000017500000000010214673353434013767 0ustar frankfrankinline std::string const &Proc::cmd() const { return d_cmd; } bobcat-6.07.01/proc/timerthread.cc0000664000175000017500000000052114673353434015701 0ustar frankfrank#include "proc.ih" void Proc::timerThread() { // wait until the semaphore's notification // or the end of the waiting time d_timerSem.wait_for(chrono::seconds{ d_timeLimit }); endChild(); // Fork::endChild ends the child process } bobcat-6.07.01/proc/setin.cc0000664000175000017500000000041514673353434014515 0ustar frankfrank#include "proc.ih" Proc &Proc::setIn(string const &fname) { // access the fname file d_in = new ifstream{ Exception::factory(fname) }; d_mode |= Proc::CIN; d_admin |= DELETE_D_IN; return *this; } bobcat-6.07.01/proc/start1.cc0000664000175000017500000000211614673353434014611 0ustar frankfrank#include "proc.ih" void Proc::start(size_t timeLimit, IOMode mode, ProcType type, size_t bufferSize) { if (active()) stop(); d_admin |= ACTIVE; // set/save the actual/current data preFork(mode, type, bufferSize, timeLimit); if (localPipes()) // local I/O pipes are used getPipes(); // d_read set to 0; // otherwise: d_read is set by pipes() d_writeErr = d_read + 1; d_writeOut = d_writeErr + 1; if (d_mode == REPLACE) childProcess(); // update: no redirections else fork(); beginTimerThread(); // (maybe) begin the timer thread output(d_err); // (maybe) start the d_err thread if (not localPipes()) // piping forwards Pi's OUT to Pj's IN return; output(d_out); // (maybe) start the d_out thread if (mode & CIN) readCin(); else closePipe(d_read); } bobcat-6.07.01/proc/useout1.f0000664000175000017500000000011214673353434014632 0ustar frankfrankinline void Proc::useOut(std::ostream &out) { useStream(out, COUT); } bobcat-6.07.01/proc/usemerge2.f0000664000175000017500000000014014673353434015124 0ustar frankfrankinline void Proc::useMerge(std::string const &fname) { useStream(fname, MERGE_COUT_CERR); } bobcat-6.07.01/proc/mode.cc0000664000175000017500000000106414673353434014320 0ustar frankfrank#include "proc.ih" std::string Proc::mode() const { string ret; if (d_mode == NONE) return ret = "NONE"; if (d_mode & REPLACE) return ret += "REPLACE"; if (d_mode & CIN) ret += "CIN "; if (d_mode & COUT) ret += "COUT "; if (d_mode & CERR) ret += "CERR "; if (d_mode & IGNORE_COUT) ret += "IGNORE_COUT "; if (d_mode & IGNORE_CERR) ret += "IGNORE_CERR "; if (d_mode & MERGE_COUT_CERR) ret += "MERGE_COUT_CERR "; ret.pop_back(); return ret; } bobcat-6.07.01/proc/opistrproc.cc0000664000175000017500000000053114673353434015576 0ustar frankfrank#include "proc.ih" namespace FBB { Proc::Activator operator|(istream &in, Proc &proc) { proc.d_in = ∈ proc.d_mode |= Proc::CIN; // see the proc header file // use the default ERR stream // proc.d_mode & ~(Proc::CERR | Proc::IGNORE_CERR); return { proc }; } } // FBB bobcat-6.07.01/proc/proctype.f0000664000175000017500000000011014673353434015070 0ustar frankfrankinline Proc::ProcType Proc::procType() const { return d_procType; } bobcat-6.07.01/proc/icmconf0000664000175000017500000000013614673353434014425 0ustar frankfrank#define LIBRARY "proc" #define AUXFLAGS "-isystem ../tmp" #include "../icmconf" bobcat-6.07.01/proc/devnull.cc0000664000175000017500000000025214673353434015043 0ustar frankfrank//#include "proc.ih" // //// static //void Proc::devNull() //{ // if (s_ignored.rdbuf() == 0) // s_ignored = Exception::factory("/dev/null"); //} // bobcat-6.07.01/proc/finish1.cc0000664000175000017500000000134514673353434014737 0ustar frankfrank#define XERR #include "proc.ih" int Proc::finish(bool endChild) { if (not (d_admin & ACTIVE) or not localPipes()) return -1; if (d_mode & CIN) d_oBuf.eoi(); // end the child process if endTimerThread(); // d_timeLimit != 0 if (d_admin & THREAD_OUT) d_outThread.join(); if (d_admin & THREAD_ERR) d_errThread.join(); if (endChild) d_child.ret = Fork::endChild(); else waitForChild(); d_bufSize = d_forkData.bufSize; // reset saved data members d_mode = d_forkData.mode; d_procType = d_forkData.type; pipeSignal(d_forkData.pipeSignal); return exitStatus(); } bobcat-6.07.01/proc/start3.f0000664000175000017500000000017414673353434014455 0ustar frankfrankinline void Proc::start(IOMode mode, ProcType type, size_t bufferSize) { start(d_timeLimit, mode, type, bufferSize); } bobcat-6.07.01/proc/waitforchild.cc0000664000175000017500000000054714673353434016060 0ustar frankfrank#include "proc.ih" int Proc::waitForChild() { d_child = { Fork::waitForChild(), pid() }; // process ends, reset admin to the // default: not active, no local pipes, d_admin = LOCAL_PIPES; // no threads active d_pipesPtr = 0; return exitStatus(); } bobcat-6.07.01/proc/childredirections.cc0000664000175000017500000000136514673353434017076 0ustar frankfrank#include "proc.ih" // overrides void Proc::childRedirections() { // all pipes before d_read are not used by this process and // can be closed for (size_t idx = 0; idx != d_read; ++idx) (*d_pipesPtr)[idx].close(); if (d_mode & CIN) (*d_pipesPtr)[d_read].readFrom(STDIN_FILENO); if (d_mode & MERGE_COUT_CERR) // cout/cerr to 1 pipe { int fd[] = { STDOUT_FILENO, STDERR_FILENO }; (*d_pipesPtr)[d_writeOut].writtenBy(fd, 2); } else { if (d_mode & (COUT | IGNORE_COUT)) (*d_pipesPtr)[d_writeOut].writtenBy(STDOUT_FILENO); if (d_mode & (CERR | IGNORE_CERR)) (*d_pipesPtr)[d_writeErr].writtenBy(STDERR_FILENO); } } bobcat-6.07.01/proc/pipesignal.cc0000664000175000017500000000031114673353434015521 0ustar frankfrank#define XERR #include "proc.ih" void Proc::pipeSignal(bool on) // true: SIG_DFL { d_oBuf.warn(on); if (on) d_admin |= PIPE_SIGNAL; else d_admin &= ~PIPE_SIGNAL; } bobcat-6.07.01/proc/destructor.cc0000664000175000017500000000024114673353434015566 0ustar frankfrank#include "proc.ih" // overrides Proc::~Proc() { stop(); if (localPipes()) // local pipes were closed by finish delete d_pipesPtr; } bobcat-6.07.01/proc/opis.cc0000664000175000017500000000041314673353434014343 0ustar frankfrank#include "proc.ih" int Proc::operator=(std::string const &cmd) { int ret = stop(); // stop a currently running cmd setCommand(cmd); // set the next cmd start(); // start the command return ret; } bobcat-6.07.01/proc/opstrproc.f0000664000175000017500000000015514673353434015267 0ustar frankfrankinline Proc::Activator operator|(std::string const &fname, Proc &proc) { return { proc.setIn(fname) }; } bobcat-6.07.01/proc/usestream2.cc0000664000175000017500000000025614673353434015470 0ustar frankfrank#include "proc.ih" void Proc::useStream(std::string const &fname, IOMode bit) { use(bit) = Out{ new ofstream{ Exception::factory(fname) }, true }; } bobcat-6.07.01/proc/setbufsize.cc0000664000175000017500000000025014673353434015553 0ustar frankfrank//#define XERR #include "proc.ih" size_t Proc::setBufSize(size_t bufSize) { size_t ret = d_bufSize; d_bufSize = bufSize == 0 ? 1 : bufSize; return ret; } bobcat-6.07.01/proc/cerrpipes.cc0000664000175000017500000000064014673353434015367 0ustar frankfrank#include "proc.ih" void Proc::cerrPipe(size_t idx) const { cerr << " Pipe " << idx << ": read = " << (*d_pipesPtr)[idx].readFd() << ", write = " << (*d_pipesPtr)[idx].writeFd() << '\n'; } void Proc::cerrPipes(char const *lab) const { cerr << "Proc " << d_id << ". " << lab << '\n'; for (size_t idx = 0, end = d_pipesPtr->size(); idx != end; ++idx) cerrPipe(idx); } bobcat-6.07.01/proc/opaddis.f0000664000175000017500000000013614673353434014656 0ustar frankfrankinline Proc &Proc::operator+=(std::string const &txt) { d_cmd += txt; return *this; } bobcat-6.07.01/proc/begintimerthread.cc0000664000175000017500000000046514673353434016715 0ustar frankfrank#define XERR #include "proc.ih" void Proc::beginTimerThread() { if (d_timeLimit == 0) return; d_timerSem.set(0); // semaphore: end thread waits // and start the thread d_timerThread = thread{ &Proc::timerThread, this }; } bobcat-6.07.01/proc/iomodeoperators.f0000664000175000017500000000146414673353434016453 0ustar frankfrankinline Proc::IOMode operator|(Proc::IOMode lhs, Proc::IOMode rhs) { return static_cast( static_cast(lhs) | static_cast(rhs)); } inline Proc::IOMode &operator|=(Proc::IOMode &lhs, Proc::IOMode rhs) { reinterpret_cast(lhs) |= static_cast(rhs); return lhs; } inline Proc::IOMode operator&(Proc::IOMode lhs, Proc::IOMode rhs) { return static_cast( static_cast(lhs) & static_cast(rhs)); } inline Proc::IOMode &operator&=(Proc::IOMode &lhs, Proc::IOMode rhs) { reinterpret_cast(lhs) &= static_cast(rhs); return lhs; } inline Proc::IOMode operator~(Proc::IOMode mode) { return static_cast( ~static_cast(mode) & Proc::IOMODES); } bobcat-6.07.01/proc/usemerge1.f0000664000175000017500000000012714673353434015130 0ustar frankfrankinline void Proc::useMerge(std::ostream &out) { useStream(out, MERGE_COUT_CERR); } bobcat-6.07.01/proc/start2.f0000664000175000017500000000012614673353434014451 0ustar frankfrankinline void Proc::start() { start(d_timeLimit, d_mode, d_procType, d_bufSize); } bobcat-6.07.01/proc/setproctype.cc0000664000175000017500000000023514673353434015754 0ustar frankfrank//#define XERR #include "proc.ih" Proc::ProcType Proc::setProcType(ProcType type) { ProcType ret = d_procType; d_procType = type; return ret; } bobcat-6.07.01/proc/outdestructor.cc0000664000175000017500000000023614673353434016322 0ustar frankfrank#include "proc.ih" Proc::Out::~Out() { if (d_alloc) delete d_stream; // flushes the stream else d_stream->flush(); } bobcat-6.07.01/proc/system.f0000664000175000017500000000032514673353434014557 0ustar frankfrankinline void Proc::system(IOMode mode, size_t bufSize) { system(0, mode, bufSize); } inline void Proc::system(size_t timeLimit, IOMode mode, size_t bufSize) { start(timeLimit, mode, USE_SHELL, bufSize); } bobcat-6.07.01/proc/finish2.f0000664000175000017500000000014414673353434014574 0ustar frankfrankinline int Proc::finish() { return finish(false); // false: don't force the child's end } bobcat-6.07.01/proc/stop.f0000664000175000017500000000007114673353434014216 0ustar frankfrankinline int Proc::stop() { return finish(active()); } bobcat-6.07.01/proc/opprocostr.f0000664000175000017500000000014614673353434015446 0ustar frankfrankinline void operator|(Proc &proc, std::ostream &out) { operator|(Proc::Activator{ proc }, out); } bobcat-6.07.01/proc/opactproc.cc0000664000175000017500000000022714673353434015366 0ustar frankfrank#include "proc.ih" namespace FBB { Proc::Activator operator|(Proc::Activator &&lhs, Proc &rhs) { lhs.add(rhs); return move(lhs); } } // FBB bobcat-6.07.01/proc/active.f0000664000175000017500000000010514673353434014502 0ustar frankfrankinline bool Proc::active() const { return kill(pid(), 0) == 0; } bobcat-6.07.01/proc/outopis.cc0000664000175000017500000000015414673353434015075 0ustar frankfrank#include "proc.ih" Proc::Out &Proc::Out::operator=(Out &&tmp) { fswap(*this, tmp); return *this; } bobcat-6.07.01/proc/rmbackticks.cc0000664000175000017500000000041114673353434015664 0ustar frankfrank#include "proc.ih" void Proc::rmBackticks() { if (d_cmd.front() == '`' && d_cmd.back() == '`') // rm backticks { d_cmd.resize(d_cmd.length() - 1); // rm last backtick d_cmd.erase(0, 1); // rm front backtick } } bobcat-6.07.01/proc/add.cc0000664000175000017500000000212714673353434014125 0ustar frankfrank#include "proc.ih" void Proc::Activator::add(Proc &proc) { if (not d_procPtr.empty()) { if ( find(d_procPtr.begin(), d_procPtr.end(), &proc) != d_procPtr.end() ) throw Exception{} << "All Proc objects in 'proc1 | proc2' must be different"; if ( not (d_procPtr.back()->d_mode & (COUT | MERGE_COUT_CERR)) or not (proc.d_mode & CIN) ) throw Exception{} << "At 'proc1 | proc2' COUT is required for proc1 and CIN for proc2"; Proc &back = *d_procPtr.back(); // see the proc header file back.d_mode |= COUT; // back.d_mode &= ~(IGNORE_COUT | CERR | IGNORE_CERR | MERGE_COUT_CERR); } // proc.d_mode &= ~(IGNORE_COUT | CERR | IGNORE_CERR | MERGE_COUT_CERR); d_procPtr.push_back(&proc); // store the Proc objects in sequence size_t nPipes = d_pipesPtr->size() + 2; d_pipesPtr->resize(nPipes); // add two new pipes proc.pipes(d_pipesPtr, nPipes); // set proc's pipes } bobcat-6.07.01/proc/use.cc0000664000175000017500000000213114673353434014164 0ustar frankfrank#include "proc.ih" // bit == COUT: if d_mode & MERGE_COUT_CERR, MERGE_COUT_CERR is kept // bit == CERR: if d_mode & MERGE_COUT_CERR, MERGE_COUT_CERR is replaced // by CERR | COUT: COUT keeps its own Out stream, CERR // gets the use-specified stream Proc::Out &Proc::use(IOMode bit) // bit to be set in d_mode { d_mode |= bit; switch (bit) { case COUT: if (d_mode & MERGE_COUT_CERR) d_mode |= CERR; // d_mode &= ~(MERGE_COUT_CERR | IGNORE_COUT | IGNORE_CERR); d_admin |= USE_OUT; return d_out; case CERR: if (d_mode & MERGE_COUT_CERR) d_mode |= COUT; // d_mode &= ~(MERGE_COUT_CERR | IGNORE_COUT | IGNORE_CERR); d_admin |= USE_ERR; return d_err; default: // = case MERGE_COUT_CERR: use is only called with // arguments COUT, CERR or MERGE_COUT_CERR d_mode &= ~(COUT | CERR | IGNORE_COUT | IGNORE_CERR); d_admin |= USE_OUT; return d_out; } } bobcat-6.07.01/proc/proc0000664000175000017500000003173514673353434013763 0ustar frankfrank#ifndef INCLUDED_BOBCAT_PROC_ #define INCLUDED_BOBCAT_PROC_ #include #include #include #include #include #include #include #include #include #include #include // 0: not specified // i: IGNORE_ // +: specified // d: default (use cout/cerr) // f: forwards to parent // O: thread to toOut // OI: thread to toOut, ignore // E: thread to toErr // EI: thread to toErr, ignore // u: unused (no thread) // // ------------------------------------------------------------- // d_mode action child // --------------------- ------------- --------------------- // COUT CERR MERGE d_out d_err cout cerr // ------------------------------------------------------------- // 0 0 + O u f f (->STDOUT) // 0 0 0 u u d d // ------------------------------------------------------------- // i 0 0 OI u f d // i i 0 OI EI f f // i + 0 OI E f f // ------------------------------------------------------------- // 0 0 0 u u d d // 0 i 0 u EI d f // 0 + 0 u E d f // ------------------------------------------------------------- // + 0 0 O u f d // + i 0 O EI f f // + + 0 O E f f // ------------------------------------------------------------- // // Piping: // --------------------------------------- // x | y in | x x | out // ------------- ------- ------- // in ? + + ? // out + ? ? + // err d d d d // --------------------------------------- namespace FBB { class Proc: private Fork, public std::ostream { struct Activator { std::vector d_procPtr; // sequence of piped Proc objects std::vector *d_pipesPtr; // pipes passed to Proc objects Activator(Proc &proc); // activator1.cc Activator(Activator &&tmp); // .ih ~Activator(); // activatordestr.cc void add(Proc &proc); //void setOut(std::ostream &out); // actsetout.f }; // opistrproc.cc friend Activator operator|(std::istream &in, Proc &proc); // opstrproc.f friend Activator operator|(std::string const &fname, Proc &proc); friend Activator operator|(Proc &lhs, Proc &rhs); // opprocproc.f friend Activator operator|(Activator &&lhs, Proc &rhs); // opactproc.cc friend void operator|(Proc &proc, std::ostream &out); // opprocostr.f // opactcostr.cc friend void operator|(Activator &&lhs, std::ostream &out); // opactfname.cc friend void operator|(Activator &&lhs, std::string const &fname); enum Admin { BUFSIZE = 200, ACTIVE = 1 << 0, LOCAL_PIPES = 1 << 1, // Proc is used stand-alone, no operator| used USE_OUT = 1 << 2, // d_out has been set by a use... member USE_ERR = 1 << 3, // d_err has been set by a use... member THREAD_OUT = 1 << 4, // d_outThread is active THREAD_ERR = 1 << 5, // d_errThread is active DELETE_D_IN = 1 << 6, // when using 'fname | proc' PIPE_SIGNAL = 1 << 7, // when set, broken CIN pipe breaks (default) }; struct ExecContext; class Out { std::ostream *d_stream; bool d_alloc; public: Out(std::ostream *str, bool alloc = false); // 1.cc ~Out(); // outdestructor.cc Out &operator=(Out &&tmp); // outopis.cc std::ostream &operator()(); // outopfun.cc }; struct RetPid { int ret; pid_t pid; RetPid(int ret = -1, pid_t pid = 0); // .ih }; public: enum ProcType { NO_PATH, USE_PATH, USE_SHELL }; enum IOMode: size_t { NONE = 0, // no piping/redirection CIN = 1 << 0, // all inserted info goes to the // child's std input 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, REPLACE = 1 << 6, IOMODES = (1 << 7) - 1, }; private: struct ForkData { size_t bufSize; IOMode mode; ProcType type; bool pipeSignal; }; void *d_ptr; // unused, but defined for future // extra (bridging) members // LOCAL_PIPES when defining a unsigned d_admin; // stand-alone process. size_t d_bufSize; RetPid d_child; std::thread d_errThread; // receives cerr from the child std::thread d_outThread; // receives cout from the child std::string d_cmd; Out d_err; // CERR output produced by Proc ForkData d_forkData; // by default: ->cin, or set by // 'istr | proc'. When using // 'name | proc' d_in is deleted std::istream *d_in; // after use (Admin::DELETE_D_IN) IOMode d_mode; OFdBuf d_oBuf; // info into the pipe to the child Out d_out; // COUT output produced by Proc // When LOCAL_PIPES: pipes defined by // start. When piping (no LOCAL_PIPES) std::vector *d_pipesPtr; // pipes received by pipe() ProcType d_procType; // d_read, d_writeErr and d_writeOut // are set by start1.cc size_t d_read; // idx of the pipe read by the child size_t d_timeLimit; // seconds allowed to child-proc Semaphore d_timerSem; // ends the child process at notify std::thread d_timerThread; // handles the child's time-limit size_t d_writeErr; // cerr pipe idx written by the child size_t d_writeOut; // cout pipe idx written by the child // handles output with IGNORE_COUT static std::ofstream s_ignored; // and IGNORE_CERR // data.cc static size_t s_id; size_t d_id; public: explicit Proc(std::string const &command = "", // 1.cc IOMode mode = ALL, ProcType type = NO_PATH, size_t bufSize = BUFSIZE, size_t timeLimit = 0, bool pipeSignal = true); Proc(Proc const &other) = delete; ~Proc() override; // stop()s any ongoing proc bool active() const; // child process is active .f std::string const &cmd() const; // returns d_cmd .f int exitStatus() const; // .f int finish(); // ends an active child (cf. stop) 2.f std::string mode() const; IOMode ioMode() const; int operator=(std::string const &cmd); // set & start a cmd opis.cc // adds to d_cmd Proc &operator+=(std::string const &text); // opaddis.f using Fork::pid; void pipeSignal(bool on); // true: SIG_DFL size_t procIdx() const; // .f ProcType procType() const; // .f // set members returning values the previous values // values set are used at the next run: size_t setBufSize(size_t bufSize); void setCommand(std::string const &cmd); // .f IOMode setIOMode(IOMode ioMode); ProcType setProcType(ProcType type); size_t setTimeLimit(size_t timeLimit = 0); // 0 means: no time monitor void start(size_t timeLimit, IOMode mode = ALL, // 1.cc ProcType type = NO_PATH, size_t bufSize = BUFSIZE); void start(); // uses the current defaults // 2.f void start(IOMode mode, ProcType type = NO_PATH, // 3.f size_t bufSize = BUFSIZE); int stop(); // forces a child process's end 1.f void system(IOMode mode = ALL, size_t bufSize = BUFSIZE); // .f void system(size_t timeLimit, IOMode mode = ALL, // .f size_t bufSize = BUFSIZE); size_t timeLimit() const; // .f // By specifying useX(...) the associated IOMode flag (COUT/CERR) // is set and the IGNORE_... flag is unset. void useErr(std::ostream &out); // 1.f void useErr(std::string const &fname); // 2.f void useMerge(std::ostream &out); // 1.f void useMerge(std::string const &fname); // 2.f void useOut(std::ostream &out); // 1.f void useOut(std::string const &fname); // 2.f int waitForChild(); void cerrAdmin(char const *lab = "") const; void cerrMode(char const *lab = "") const; void cerrPipe(size_t idx) const; void cerrPipes(char const *lab = "") const; private: ExecContext analyzeCmd() const; void beginTimerThread(); // begins the timer thread in start void checkErrThread(); // join d_errThread if active void closePipe(size_t idx); // .ih int finish(bool endChild); // true: uses Fork::endChild 1.cc void getPipes(); // get pipes with ourPipes void endTimerThread(); // ends the timer thread in finish bool localPipes() const; // .ih // set 'out' depending on d_mode's void output(Out &out); // use or IGNORE_ bits void pipes(std::vector *pipes, size_t read); void preFork(IOMode mode, ProcType type, size_t bufSize, size_t timeLimit); void readCin(); // reads cin at start3 void rmBackticks(); Proc &setIn(std::string const &fname); // used by 'fname | proc' // ends the child process after void timerThread(); // d_timeLimit seconds void toOut(); // called by d_outThread void toErr(); // called by d_errThread Out &use(IOMode bit); // bit is set in d_mode void useStream(std::ostream &str, IOMode bit); // 1.cc void useStream(std::string const &fname, IOMode bit); // 2.cc void childProcess() override; void childRedirections() override; void parentProcess() override; // no actions }; #include "active.f" #include "cmd.f" #include "exitstatus.f" #include "finish2.f" #include "iomode.f" #include "iomodeoperators.f" #include "opaddis.f" #include "opprocostr.f" #include "opprocproc.f" #include "opstrproc.f" #include "procidx.f" #include "proctype.f" #include "setcommand.f" #include "start2.f" #include "start3.f" #include "stop.f" #include "system.f" #include "useerr1.f" #include "useerr2.f" #include "usemerge1.f" #include "usemerge2.f" #include "useout1.f" #include "useout2.f" } // FBB #endif bobcat-6.07.01/proc/readcin.cc0000664000175000017500000000247414673353434015007 0ustar frankfrank#include "proc.ih" void Proc::readCin() { // closes the d_read fd int fd = (*d_pipesPtr)[d_read].writeOnlyFd(); d_oBuf.reset(fd, d_bufSize); // OK, insertions into *this if (d_in != 0) { *this << d_in->rdbuf(); if (d_admin & DELETE_D_IN) { delete d_in; d_admin &= ~DELETE_D_IN; } d_in = 0; } if (not localPipes()) *this << eoi; } // OFdStream out{ fd, d_bufSize }; // OK, // out << cin.rdbuf() << std::flush; // cerr< #include #include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) try { // [[maybe_unused]] char const prog[] = "./cincoutcerr"; [[maybe_unused]] char const prog[] = "/bin/cat"; Proc proc{ argc == 1 ? "/bin/ls" : argv[1] //, Proc::NONE //, Proc::CIN //, Proc::MERGE_COUT_CERR //, Proc::CIN | Proc::MERGE_COUT_CERR //, Proc::CIN | Proc::COUT | Proc::IGNORE_CERR //, Proc::CIN | Proc::COUT //, Proc::CIN | Proc::CERR //, Proc::CIN | Proc::IGNORE_COUT | Proc::IGNORE_CERR //, Proc::CIN | Proc::IGNORE_COUT | Proc::CERR }; // proc.pipeSignal(false); proc.setCommand(prog); [[maybe_unused]] Proc proc2{ "/bin/cat" //, Proc::CIN | Proc::COUT | Proc::IGNORE_CERR //, Proc::CIN | Proc::COUT | Proc::CERR }; [[maybe_unused]] Proc proc3{ "/bin/cat" //, Proc::CIN | Proc::IGNORE_COUT | Proc::IGNORE_CERR }; // https://stackoverflow.com/questions/16219912/how-to-avoid-a-broken-pipe // signal(SIGPIPE, SIG_IGN); // proc.pipeSignal(false); // ifstream in{"cin"}; // reading twice via piping ifstream in{"xref"}; // reading twice via piping // ofstream out{ "/tmp/out" }; // proc.setTimeLimit(1); // also with setTimeLimit: proc.start(); // piping after start()-finish() is OK proc << in.rdbuf(); // proc << cin.rdbuf(); proc.finish(); in.seekg(0); //return 0; cout << "\n2 --------------\n\n"; // // "main.ih" | proc | "/tmp/out"; // "main.ih" | proc | cout; // in | proc | cout; // in | proc | proc2 | cout; // proc.showMode("1"); // proc2.showMode("2"); // proc3.showMode("3"); in | proc | proc2 | proc3 | cout; // cerr << proc3.exitStatus() << ' ' << proc3.procIdx() << '\n'; //return 0; cout << "\n3 --------------\n\n"; in.seekg(0); proc.start(); proc << in.rdbuf(); proc.finish(); return 0; // proc.useOut("/tmp/out"); // proc.useMerge(cout); // proc.start(Proc::IGNORE_COUT | Proc::CIN); // proc.start(); // proc.start(Proc::CIN | Proc::MERGE_COUT_CERR); // proc << cin.rdbuf(); // in | proc; // (use a.out /bin/cat) // in.seekg(0); // in | proc; // in | proc | out; // in | proc | cout; return 0; proc.start(); // proc << in.rdbuf(); // proc << cin.rdbuf(); proc.finish(); return 0; //proc.stop(); // proc = "/bin/cat"; // set and start proc.setCommand("/bin/cat"); // starting again using /bin/cat //proc.showMode("before useOut"); // proc.useOut(cout); //proc.showMode("after useOut"); proc.start(); proc << "hello world\n"; proc.finish(); } catch (int x) { if (x != 0) cerr << x << " exception\n"; } catch (exception const &exc) { cerr << exc.what() << '\n'; } catch (...) { cerr << "Exception caught\n"; } bobcat-6.07.01/proc/driver/b0000775000175000017500000000025614673353434014531 0ustar frankfrank#!/bin/bash if [ $# -eq 0 ] ; then echo Provide 1st argument: ls.cc, limit.cc exit 0; fi g++ `cat ../../c++std` -Wall $1 -lbobcat -s | exit 1 echo a.out available bobcat-6.07.01/proc/driver/ls.cc0000664000175000017500000000026014673353434015302 0ustar frankfrank#include #include using namespace std; using namespace FBB; //CODE int main() { Proc proc("/bin/ls -Fla", Proc::COUT); proc.start(); } //= bobcat-6.07.01/proc/driver/pipe.cc0000664000175000017500000000050614673353434015624 0ustar frankfrank#include #include using namespace std; using namespace FBB; //CODE int main() { Proc proc1{ "/bin/cat" }; Proc proc2{ "/bin/cat" }; cin | proc1 | proc2; // By default piping to cout. To do that // explicitly use '... | proc2 | cout' } //= bobcat-6.07.01/proc/driver/limit.cc0000664000175000017500000000112414673353434016002 0ustar frankfrank#include #include using namespace std; using namespace FBB; //CODE int main() { Proc proc("/bin/cat", Proc::CIN | Proc::COUT); proc.setTimeLimit(5); proc.start(); while (true) { cout << "? "; string line; if (not getline(cin, line)) return 0; proc << line << endl; // to /bin/cat if (not proc.good()) { cout << "child time limit exceeded\n"; break; } } cout << "/bin/cat time limit of 5 seconds reached: child proc ended\n"; } //= bobcat-6.07.01/proc/opprocproc.f0000664000175000017500000000015614673353434015423 0ustar frankfrankinline Proc::Activator operator|(Proc &lhs, Proc &rhs) { return operator|(Proc::Activator{ lhs }, rhs); } bobcat-6.07.01/process/0000775000175000017500000000000014736742656013607 5ustar frankfrankbobcat-6.07.01/process/process1.cc0000664000175000017500000000016414673353434015646 0ustar frankfrank#include "process.ih" Process::Process(std::string const &command) : Process(ALL, NO_PATH, 0, 200, command) {} bobcat-6.07.01/process/childerrstream.cc0000664000175000017500000000015114673353434017113 0ustar frankfrank#include "process.ih" std::istream &Process::childErrStream() { active(); return d_iChildErr; } bobcat-6.07.01/process/exitstatus.f0000664000175000017500000000010414673353434016156 0ustar frankfrankinline int Process::exitStatus() const { return d_exitStatus; } bobcat-6.07.01/process/newpipe.cc0000664000175000017500000000014214673353434015552 0ustar frankfrank#include "process.ih" void Process::newPipe(Pipe &pipe) { pipe.close(); pipe = Pipe{}; } bobcat-6.07.01/process/forking.cc0000664000175000017500000000022614673353434015545 0ustar frankfrank#include "process.ih" void Process::forking() { newPipes(); if (d_mode == IOMode::DIRECT) childProcess(); fork(); } bobcat-6.07.01/process/parentprocess.cc0000664000175000017500000000014114673353434016772 0ustar frankfrank#include "process.ih" void Process::parentProcess() // overrides { d_child.pid = pid(); } bobcat-6.07.01/process/dquotedstring.x0000664000175000017500000000243714673353434016672 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-6.07.01/process/operatorfun1.cc0000664000175000017500000000024214673353434016531 0ustar frankfrank#include "process.ih" Process &Process::operator()(IOMode mode, ProcessType type, size_t timeLimit) { return operator()(mode, type, timeLimit, bufSize()); } bobcat-6.07.01/process/whichstream.cc0000664000175000017500000000120714673353434016424 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-6.07.01/process/stop.cc0000664000175000017500000000047314673353434015077 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-6.07.01/process/operatorpipe.cc0000664000175000017500000000371214673353434016622 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-6.07.01/process/closepipes.cc0000664000175000017500000000021414673353434016251 0ustar frankfrank#include "process.ih" void Process::closePipes() { d_oChildInPipe.close(); d_iChildOutPipe.close(); d_iChildErrPipe.close(); } bobcat-6.07.01/process/opinsert.f0000664000175000017500000000025014673353434015606 0ustar frankfranktemplate Process &Process::operator<<(Type const &value) { if (active()) dynamic_cast(*this) << value; return *this; } bobcat-6.07.01/process/opfun1.f0000664000175000017500000000016414673353434015157 0ustar frankfrankinline Process &Process::operator()(IOMode mode) { return operator()(mode, d_setProcessType, d_setTimeLimit); } bobcat-6.07.01/process/iomode.f0000664000175000017500000000015614673353434015224 0ustar frankfrankinline Process::IOMode Process::ioMode() const { return d_mode & ~(IN_PIPE | OUT_PIPE | CLOSE_ON_EXEC); } bobcat-6.07.01/process/eoi2.cc0000664000175000017500000000020614673353434014742 0ustar frankfrank#include "process.ih" void Process::eoi_() { if (active()) { close(); d_exitStatus = waitForChild(); } } bobcat-6.07.01/process/showmode.cc0000664000175000017500000000211214673353434015727 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-6.07.01/process/process3.cc0000664000175000017500000000022114673353434015642 0ustar frankfrank#include "process.ih" Process::Process(IOMode mode, ProcessType type, std::string const &command) : Process(mode, type, 0, 200, command) {} bobcat-6.07.01/process/vparentredirections.cc0000664000175000017500000000377114673353434020210 0ustar frankfrank//#include "process.ih" // //void Process::v_parentRedirections() //{ // d_selector = Selector{}; // multiple file IO/alarm handling // // if (d_setMode & CLOSE_ON_EXEC) // closeChildInputOnExec(); // // if (d_mode & CIN) // parent's ostream writes to // { // the child's cin stream: the // // parent writes, the child reads // int fd = d_childIn_paWritePipe.writeOnly(); // // if (not (d_setMode & IN_PIPE)) // { // d_toChildCinBuf.reset(fd, 200); // streambuf to write to the child // d_oChild.rdbuf(&d_toChildCinBuf); // activate the stream to the // // child process // } // } // // if ((d_mode & (COUT | MERGE_COUT_CERR)) == NONE) // d_paIn_childCoutPipe.closeWriteFd(); // else // at COUT // { // int fd = d_paIn_childCoutPipe.readOnly(); // read the child's cout // // if (not (d_setMode & OUT_PIPE)) // { // d_fmChildCoutBuf.reset(fd, 200); // streambuf reading the // // child's cout // d_iChildCout.rdbuf(&d_fmChildCoutBuf); // active reading the // // child's cout stream // d_selector.addReadFd(fd); // react on incoming info // } // } // // if (d_mode & CERR) // if CERR is used // { // int fd = d_paIn_childCerrPipe.readOnly(); // read the child's cerr // d_fmChildCerrBuf.reset(fd, 200); // activate the buffer // d_iChildCerr.rdbuf(&d_fmChildCerrBuf); // read the child's cerr // d_selector.addReadFd(fd); // react on incoming info // } // // clear(); // clears IOStream's streams //} // // // bobcat-6.07.01/process/retpid1.f0000664000175000017500000000010214673353434015307 0ustar frankfrankinline FBB::Process::RetPid::RetPid() : ret(0), pid(0) {} bobcat-6.07.01/process/childprocess.cc0000664000175000017500000000150514673353434016571 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-6.07.01/process/system4.f0000664000175000017500000000017714673353434015363 0ustar frankfrankinline void Process::system(IOMode mode, size_t timeLimit, size_t bufSize) { start(mode, USE_SHELL, timeLimit, bufSize); } bobcat-6.07.01/process/process4.cc0000664000175000017500000000030514673353434015646 0ustar frankfrank#include "process.ih" Process::Process(IOMode mode, ProcessType processType, size_t timeLimit, string const &command) : Process(mode, processType, timeLimit, 200, command) {} bobcat-6.07.01/process/newpipes.cc0000664000175000017500000000043014673353434015735 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-6.07.01/process/start1.f0000664000175000017500000000013114673353434015157 0ustar frankfrankinline void Process::start() { start(d_setMode, d_setProcessType, d_setTimeLimit); } bobcat-6.07.01/process/discontinue.cc0000664000175000017500000000047514673353434016440 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-6.07.01/process/setiomode.f0000664000175000017500000000012614673353434015735 0ustar frankfrankinline void Process::setIOMode(IOMode mode) { d_setMode = sanitizeIOMode(mode); } bobcat-6.07.01/process/timelimit.f0000664000175000017500000000011014673353434015733 0ustar frankfrankinline size_t Process::timeLimit() const { return d_setTimeLimit; } bobcat-6.07.01/process/setcommand.f0000664000175000017500000000013114673353434016073 0ustar frankfrankinline void Process::setCommand(std::string const &command) { d_command = command; } bobcat-6.07.01/process/opfun2.f0000664000175000017500000000032614673353434015160 0ustar frankfrankinline Process &Process::operator()(IOMode mode, ProcessType type) { return operator()(mode & ~(IN_PIPE | OUT_PIPE | CLOSE_ON_EXEC), type, d_setTimeLimit); } bobcat-6.07.01/process/childoutstream.f0000664000175000017500000000014214673353434016772 0ustar frankfrankinline std::istream &Process::childOutStream() { return static_cast(*this); } bobcat-6.07.01/process/limiter.cc0000664000175000017500000000221214673353434015550 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-6.07.01/process/escapedstring.x0000664000175000017500000000205614673353434016626 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-6.07.01/process/start1.cc0000664000175000017500000000022514673353434015323 0ustar frankfrank#include "process.ih" void Process::start(size_t mode, ProcessType type, size_t timeLimit) { start(iomode(mode), type, timeLimit, bufSize()); } bobcat-6.07.01/process/process.ih0000664000175000017500000000074314736315237015602 0ustar frankfrank#include "process" #include #include #include #include #include #include #include #include "../redirector/redirector" struct FBB::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" using namespace std; using namespace FBB; bobcat-6.07.01/process/system1.f0000664000175000017500000000013014673353434015345 0ustar frankfrankinline void Process::system() { start(d_mode, USE_SHELL, d_timeLimit, bufSize()); } bobcat-6.07.01/process/available.cc0000664000175000017500000000015514673353434016027 0ustar frankfrank#include "process.ih" size_t Process::available() { d_selector.setAlarm(0); return whichStream(); } bobcat-6.07.01/process/str.f0000664000175000017500000000011114673353434014547 0ustar frankfrankinline std::string const &Process::str() const { return d_command; } bobcat-6.07.01/process/bufsize.f0000664000175000017500000000010114673353434015405 0ustar frankfrankinline size_t Process::bufSize() const { return d_bufSize; } bobcat-6.07.01/process/setbufsize.f0000664000175000017500000000014214673353434016126 0ustar frankfrankinline void Process::setBufSize(size_t bufSize) { d_bufSize = bufSize == 0 ? 1 : bufSize; } bobcat-6.07.01/process/icmconf0000664000175000017500000000016014673353434015135 0ustar frankfrank#define LIBRARY "process" #define AUXFLAGS "-I../tmp -pthread" #include "../icmconf" bobcat-6.07.01/process/close.cc0000664000175000017500000000034114673353434015211 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-6.07.01/process/operatorfun2.cc0000664000175000017500000000042314673353434016533 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-6.07.01/process/opextract.f0000664000175000017500000000030014673353434015750 0ustar frankfranktemplate Process &Process::operator>>(Type &value) { if ((available() & CHILD_COUT) || active()) dynamic_cast(*this) >> value; return *this; } bobcat-6.07.01/process/vchildredirections.cc0000664000175000017500000000254414673353434017777 0ustar frankfrank//#include "process.ih" // //void Process::v_childRedirections() //{ // if (d_mode & CIN) // CHILD PROCESS: reads // d_childIn_paWritePipe.readFrom(STDIN_FILENO); // cin from the pipe // // if (d_mode & MERGE_COUT_CERR) // cout/cerr to 1 pipe // { // int fd[] = { STDOUT_FILENO, STDERR_FILENO }; // d_paIn_childCoutPipe.writtenBy(fd, 2); // } // else // { // if (d_mode & COUT) // cout writes to a pipe // d_paIn_childCoutPipe.writtenBy(STDOUT_FILENO); // // if (d_mode & CERR) // cerr: to another pipe // d_paIn_childCerrPipe.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-6.07.01/process/start3.f0000664000175000017500000000021514673353434015164 0ustar frankfrankinline void Process::start(IOMode mode, ProcessType type) { start(mode & ~(IN_PIPE | OUT_PIPE | CLOSE_ON_EXEC), type, d_setTimeLimit); } bobcat-6.07.01/process/waitforchild.cc0000664000175000017500000000017514673353434016570 0ustar frankfrank#include "process.ih" int Process::waitForChild() { int ret = Fork::waitForChild(); closePipes(); return ret; } bobcat-6.07.01/process/system2.f0000664000175000017500000000014114673353434015350 0ustar frankfrankinline void Process::system(IOMode mode) { start(mode, USE_SHELL, d_timeLimit, bufSize()); } bobcat-6.07.01/process/childredirections.cc0000664000175000017500000000240114673353434017601 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-6.07.01/process/parentredirections.cc0000664000175000017500000000173014673353434020013 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-6.07.01/process/operatorinsert.cc0000664000175000017500000000026414673353434017170 0ustar frankfrank#include "process.ih" Process &Process::operator<<(std::ostream &(*pf)(std::ostream &)) { if (active()) static_cast(*this) << pf; return *this; } bobcat-6.07.01/process/settimelimit.f0000664000175000017500000000014614673353434016460 0ustar frankfrankinline void Process::setTimeLimit(size_t timeLimit) { d_setTimeLimit = d_timeLimit = timeLimit; } bobcat-6.07.01/process/destructor.cc0000664000175000017500000000015314673353434016303 0ustar frankfrank#include "process.ih" Process::~Process() { stop(); Signal::instance().remove(SIGCHLD, *this); } bobcat-6.07.01/process/operatorassign.cc0000664000175000017500000000031114673353434017141 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-6.07.01/process/quotedstring.x0000664000175000017500000000145714673353434016527 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-6.07.01/process/signalhandler.cc0000664000175000017500000000026414673353434016723 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-6.07.01/process/sanitizeiomode.cc0000664000175000017500000000167214673353434017137 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-6.07.01/process/setprocesstype.f0000664000175000017500000000014714673353434017044 0ustar frankfrankinline void Process::setProcessType(ProcessType type) { d_setProcessType = d_processType = type; } bobcat-6.07.01/process/opaddis.f0000664000175000017500000000016014673353434015366 0ustar frankfrankinline Process &Process::operator+=(std::string const &command) { d_command += command; return *this; } bobcat-6.07.01/process/start2.f0000664000175000017500000000025714673353434015171 0ustar frankfrankinline void Process::start(IOMode mode) { start(mode & ~(IN_PIPE | OUT_PIPE | CLOSE_ON_EXEC), d_setProcessType, d_setTimeLimit); } bobcat-6.07.01/process/process0000664000175000017500000002073614673353434015210 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 #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(); using ConstIter = std::string::const_iterator; 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-6.07.01/process/eoi1.cc0000664000175000017500000000017514673353434014746 0ustar frankfrank#include "process.ih" int Process::eoi() { eoi_(); // *this << FBB::eoi; return exitStatus(); } bobcat-6.07.01/process/active.cc0000664000175000017500000000043314673353434015361 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-6.07.01/process/process5.cc0000664000175000017500000000151014673353434015646 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-6.07.01/process/split.x0000664000175000017500000000241214673353434015122 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-6.07.01/process/processtype.f0000664000175000017500000000013214673353434016322 0ustar frankfrankinline Process::ProcessType Process::processType() const { return d_setProcessType; } bobcat-6.07.01/process/close2.cc0000664000175000017500000000013614673353434015275 0ustar frankfrank#include "process.ih" void Process::close(int fd) { if (fd != -1) ::close(fd); } bobcat-6.07.01/process/rmbackticks.cc0000664000175000017500000000044314673353434016404 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-6.07.01/process/start2.cc0000664000175000017500000000162314673353434015327 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-6.07.01/process/system3.f0000664000175000017500000000016114673353434015353 0ustar frankfrankinline void Process::system(IOMode mode, size_t timeLimit) { start(mode, USE_SHELL, timeLimit, bufSize()); } bobcat-6.07.01/process/process2.cc0000664000175000017500000000020214673353434015640 0ustar frankfrank#include "process.ih" Process::Process(IOMode mode, std::string const &command) : Process(mode, NO_PATH, 0, 200, command) {} bobcat-6.07.01/process/analyzecommand.cc0000664000175000017500000000140614673353434017111 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-6.07.01/process/driver/0000775000175000017500000000000014737552575015102 5ustar frankfrankbobcat-6.07.01/process/driver/build0000775000175000017500000000325414673353434016123 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-6.07.01/process/driver/driver.cc0000664000175000017500000000641314673353434016700 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-6.07.01/process/driver/gpg.cc0000664000175000017500000000063614673353434016163 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-6.07.01/process/driver/spawn/0000775000175000017500000000000014673353434016222 5ustar frankfrankbobcat-6.07.01/process/driver/spawn/parentprocess.cc0000664000175000017500000000012514673353434021417 0ustar frankfrank#include "spawn.ih" void Spawn::parentProcess() { d_insertPipe.writeOnly(); } bobcat-6.07.01/process/driver/spawn/childprocess.cc0000664000175000017500000000053314673353434021214 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-6.07.01/process/driver/spawn/end.cc0000664000175000017500000000016314673353434017277 0ustar frankfrank#include "spawn.ih" void Spawn::end() { flush(); ::close(d_insertPipe.writeFd()); waitForChild(); } bobcat-6.07.01/process/driver/spawn/spawn.ih0000664000175000017500000000030014673353434017665 0ustar frankfrank#include "spawn.h" #include #include #include #include #include #include using namespace std; using namespace FBB; bobcat-6.07.01/process/driver/spawn/spawn1.cc0000664000175000017500000000056714673353434017752 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-6.07.01/process/driver/spawn/main.cc0000664000175000017500000000034614673353434017460 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-6.07.01/process/driver/spawn/spawn.h0000664000175000017500000000135514673353434017527 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-6.07.01/process/driver/spawn/childredirections.cc0000664000175000017500000000027214673353434022230 0ustar frankfrank#include "spawn.ih" void Spawn::childRedirections() { d_insertPipe.readFrom(STDIN_FILENO); // d_extractPipe.writtenBy(STDOUT_FILENO); // d_errPipe.writtenBy(STDERR_FILENO); } bobcat-6.07.01/process/driver/sha1sum.cc0000664000175000017500000000103014673353434016754 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-6.07.01/process/driver/sort.cc0000664000175000017500000000101014673353434016360 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-6.07.01/process/driver/ls.cc0000664000175000017500000000050214673353434016014 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-6.07.01/process/driver/thread.cc0000664000175000017500000000101014673353434016640 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-6.07.01/process/driver/all.cc0000664000175000017500000000122114673353434016145 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-6.07.01/process/driver/pipe.cc0000664000175000017500000000060614673353434016340 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-6.07.01/process/driver/cincoutcerr.cc0000664000175000017500000000060314673353434017720 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-6.07.01/process/driver/discontinue/0000775000175000017500000000000014673353434017416 5ustar frankfrankbobcat-6.07.01/process/driver/discontinue/build0000775000175000017500000000005214673353434020440 0ustar frankfrank#!/bin/sh g++ -o driver *.cc -lbobcat -s bobcat-6.07.01/process/driver/discontinue/demo.cc0000664000175000017500000000457614673353434020665 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-6.07.01/process/driver/discontinue/discontinue.cc0000664000175000017500000000076614673353434022262 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-6.07.01/process/driver/manual/0000775000175000017500000000000014673353434016347 5ustar frankfrankbobcat-6.07.01/process/driver/manual/newpipe.cc0000664000175000017500000000007514673353434020327 0ustar frankfrank#include "main.ih" Pipe *newPipe() { return new Pipe; } bobcat-6.07.01/process/driver/manual/data.cc0000664000175000017500000000066514673353434017576 0ustar frankfrank#include "main.ih" unique_ptr d_child_inp; // cin read by the CHILD unique_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-6.07.01/process/driver/manual/childls.cc0000664000175000017500000000024114673353434020275 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-6.07.01/process/driver/manual/parentcat.cc0000664000175000017500000000073014673353434020637 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-6.07.01/process/driver/manual/newpipes.cc0000664000175000017500000000035414673353434020512 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-6.07.01/process/driver/manual/childsha1.cc0000664000175000017500000000025514673353434020520 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-6.07.01/process/driver/manual/parentredirs.cc0000664000175000017500000000054314673353434021362 0ustar frankfrank#include "main.ih" void parentRedirections() { d_childCinbuf.reset(p1 = d_child_inp->writeOnly()); d_childCin.rdbuf(&d_childCinbuf); d_childCoutbuf.reset(p2 = d_child_outp->readOnly()); d_childCout.rdbuf(&d_childCoutbuf); if (oldIn != -1) ::close(oldIn); if (oldOut != -1) ::close(oldOut); io.clear(); } bobcat-6.07.01/process/driver/manual/icmconf0000664000175000017500000000071714673353434017715 0ustar frankfrank#define CLS #define USE_ECHO ON #define BINARY "binary" #define MAIN "main.cc" #define COMPILER "g++" #define COMPILER_OPTIONS "-g -Wall -O2" #define SOURCES "*.cc" #define LINKER_OPTIONS "-s" #define ADD_LIBRARIES "bobcat" #define ADD_LIBRARY_PATHS "" #define TMP_DIR "tmp" #define LIBRARY "modules" #define OBJ_EXT ".o" #define DEFCOM "program" bobcat-6.07.01/process/driver/manual/close.cc0000664000175000017500000000021314673353434017757 0ustar frankfrank#include "main.ih" void close() { ::close(d_child_inp->writeFd()); d_child_inp.reset(newPipe()); d_child_inp->writeOnly(); } bobcat-6.07.01/process/driver/manual/redirchild.cc0000664000175000017500000000022714673353434020770 0ustar frankfrank#include "main.ih" void redirectChild() { d_child_inp->readFrom(STDIN_FILENO); // set up the pipes d_child_outp->writtenBy(STDOUT_FILENO); } bobcat-6.07.01/process/driver/manual/main.cc0000664000175000017500000000263114673353434017604 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-6.07.01/process/driver/manual/parentout.cc0000664000175000017500000000021614673353434020676 0ustar frankfrank#include "main.ih" void parentOut() { size_t count = 0; while (getline(io, line)) cout << ++count<< ": " << line << endl; } bobcat-6.07.01/process/driver/manual/main.ih0000664000175000017500000000210514673353434017613 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::unique_ptr d_child_inp; // cin read by the CHILD extern std::unique_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-6.07.01/process/driver/manual/childechoes.cc0000664000175000017500000000027114673353434021130 0ustar frankfrank#include "main.ih" void childEchoes() { while (getline(cin, line)) { cerr << "Child receives: " << line << endl; cout << "Child saw: " << line << endl; } } bobcat-6.07.01/process/driver/manual/parentclosein.cc0000664000175000017500000000023214673353434021521 0ustar frankfrank#include "main.ih" void parentCloseIn() { io << "Hello world" << endl; close(); while (getline(io, line)) cout << line << endl; } bobcat-6.07.01/process/driver/manual/finalization.cc0000664000175000017500000000030714673353434021345 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-6.07.01/process/driver/pipes/0000775000175000017500000000000014673353434016212 5ustar frankfrankbobcat-6.07.01/process/driver/pipes/demo.cc0000664000175000017500000000166014673353434017450 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-6.07.01/process/driver/limit.cc0000664000175000017500000000126114673353434016517 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-6.07.01/process/closechildinputonexec.cc0000664000175000017500000000102614673353434020500 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-6.07.01/process/chgnames0000775000175000017500000000060714673353434015315 0ustar frankfrank#!/bin/bash cd ~/src/bobcat/process || exit 1 sed -i -e " s/d_oChildInPipe/d_childIn_paWritePipe/g s/d_iChildOutPipe/d_paIn_childCoutPipe/g s/d_iChildErrPipe/d_paIn_childCerrPipe/g s/d_oChildInbuf/d_toChildCinBuf/g s/d_iChildOutbuf/d_fmChildCoutBuf/g s/d_iChildErrbuf/d_fmChildCerrBuf/g s/d_oChildIn/d_oChild/g s/d_iChildOut/d_iChildCout/g s/d_iChildErr/d_iChildCerr/g " *.cc process* bobcat-6.07.01/processenums/0000775000175000017500000000000014673353434014647 5ustar frankfrankbobcat-6.07.01/processenums/processenums0000664000175000017500000000702014673353434017317 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-6.07.01/process-pipe.odp0000664000175000017500000004230114673353434015236 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-6.07.01/process-pipe.pdf0000664000175000017500000100750714673353434015237 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-6.07.01/ptriter/0000775000175000017500000000000014673353434013612 5ustar frankfrankbobcat-6.07.01/ptriter/ptriter1.f0000664000175000017500000000014414673353434015532 0ustar frankfranktemplate PtrIter::PtrIter(Iterator const &iter) : d_iter(iter) {} bobcat-6.07.01/ptriter/ptriter0000664000175000017500000000221114673353434015222 0ustar frankfrank#ifndef INCLUDED_BOBCAT_PTRITER_ #define INCLUDED_BOBCAT_PTRITER_ #include namespace FBB { template struct PtrIter { using iterator_category = std::input_iterator_tag; using difference_type = std::ptrdiff_t; using value_type = decltype(&*Iterator()); using pointer = value_type *; using reference = value_type &; private: Iterator d_iter; public: using PtrType = decltype(&*Iterator()); 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-6.07.01/ptriter/opstar.f0000664000175000017500000000017714673353434015276 0ustar frankfranktemplate typename PtrIter::PtrType PtrIter::operator*() const { return &*d_iter; } bobcat-6.07.01/ptriter/opinc.f0000664000175000017500000000016414673353434015072 0ustar frankfranktemplate PtrIter &PtrIter::operator++() { ++d_iter; return *this; } bobcat-6.07.01/ptriter/ptriter.f0000664000175000017500000000016414673353434015453 0ustar frankfranktemplate PtrIter ptrIter(Iterator const &iter) { return PtrIter(iter); } bobcat-6.07.01/ptriter/opneq.f0000664000175000017500000000020314673353434015076 0ustar frankfranktemplate bool PtrIter::operator!=(PtrIter const &other) const { return d_iter != other.d_iter; } bobcat-6.07.01/ptriter/opeq.f0000664000175000017500000000020314673353434014720 0ustar frankfranktemplate bool PtrIter::operator==(PtrIter const &other) const { return d_iter == other.d_iter; } bobcat-6.07.01/ptriter/driver/0000775000175000017500000000000014737552575015115 5ustar frankfrankbobcat-6.07.01/ptriter/driver/driver.cc0000664000175000017500000000213514673353434016710 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-6.07.01/qpbufbase/0000775000175000017500000000000014736742656014101 5ustar frankfrankbobcat-6.07.01/qpbufbase/text.cc0000664000175000017500000000012714673353434015364 0ustar frankfrank#include "qpbufbase.ih" void QPBufBase::text() { flush(); d_buffer += '\n'; } bobcat-6.07.01/qpbufbase/dodecode.cc0000664000175000017500000000015614673353434016150 0ustar frankfrank#include "qpbufbase.ih" void QPBufBase::doDecode() { d_action = &QPBufBase::decode; // setBuffer(); } bobcat-6.07.01/qpbufbase/escape.cc0000664000175000017500000000030114673353434015632 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-6.07.01/qpbufbase/insert.cc0000664000175000017500000000022414673353434015702 0ustar frankfrank#include "qpbufbase.ih" void QPBufBase::insert(int ch) { if (isprint(ch) && ch != '=') d_pending += ch; else escape(ch); } bobcat-6.07.01/qpbufbase/data.cc0000664000175000017500000000026414673353434015313 0ustar frankfrank#include "qpbufbase.ih" string const QPBufBase::s_hexChars { "0123456789ABCDEF" }; void (QPBufBase::*QPBufBase::s_encode[])() = { &QPBufBase::text, &QPBufBase::binary }; bobcat-6.07.01/qpbufbase/qpbufbase0000664000175000017500000000315714673353434015772 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 #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-6.07.01/qpbufbase/decode.cc0000664000175000017500000000231714673353434015626 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-6.07.01/qpbufbase/icmconf0000664000175000017500000000007314673353434015432 0ustar frankfrank#define LIBRARY "qpsbb" #include "../icmconf" bobcat-6.07.01/qpbufbase/binary.cc0000664000175000017500000000012514673353434015662 0ustar frankfrank#include "qpbufbase.ih" void QPBufBase::binary() { escape('\n'); flush(); } bobcat-6.07.01/qpbufbase/doencode.cc0000664000175000017500000000024414673353434016160 0ustar frankfrank#include "qpbufbase.ih" void QPBufBase::doEncode(bool binary) { d_encode = binary? &QPBufBase::binary : &QPBufBase::text; d_action = &QPBufBase::encode; } bobcat-6.07.01/qpbufbase/qpbufbase.ih0000664000175000017500000000012714736315237016362 0ustar frankfrank#include "qpbufbase" using namespace std; using namespace FBB; using namespace IUO; bobcat-6.07.01/qpbufbase/flush.cc0000664000175000017500000000200014673353434015511 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-6.07.01/qpbufbase/filter.cc0000664000175000017500000000101014673353434015655 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-6.07.01/qpbufbase/qpbufbase1.cc0000664000175000017500000000017314673353434016432 0ustar frankfrank#include "qpbufbase.ih" QPBufBase::QPBufBase(std::istream &in, size_t bufSize) : IFilterBuf(bufSize), d_in(in) {} bobcat-6.07.01/qpbufbase/encode.cc0000664000175000017500000000060714673353434015640 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-6.07.01/randbuf/0000775000175000017500000000000014736742656013552 5ustar frankfrankbobcat-6.07.01/randbuf/randbuf0000664000175000017500000000056114673353434015110 0ustar frankfrank#ifndef INCLUDED_BOBCAT_RANDBUF_ #define INCLUDED_BOBCAT_RANDBUF_ #include #include #include namespace FBB { class RandBuf: public std::streambuf { RandomMT d_randomMT; std::string d_buffer; public: RandBuf(int min, int max, size_t seed); private: int underflow() override; }; } #endif bobcat-6.07.01/randbuf/randbuf.ih0000664000175000017500000000021714736315237015504 0ustar frankfrank#include "randbuf" #include #include #include #include using namespace std; using namespace FBB; bobcat-6.07.01/randbuf/randbuf1.cc0000664000175000017500000000025314673353434015553 0ustar frankfrank#include "randbuf.ih" RandBuf::RandBuf(int minimum, int maximum, size_t seed) : d_randomMT(min(minimum, maximum), max(minimum, maximum), seed) { setg(0, 0, 0); } bobcat-6.07.01/randbuf/icmconf0000664000175000017500000000010114673353434015073 0ustar frankfrank#define LIBRARY "randbuf" #include "../icmconf.lib" bobcat-6.07.01/randbuf/underflow.cc0000664000175000017500000000043414673353434016057 0ustar frankfrank#include "randbuf.ih" int RandBuf::underflow() { ostringstream ostr; d_buffer = to_string(d_randomMT()) + ' '; setg( &d_buffer.front(), &d_buffer.front(), &d_buffer.front() + d_buffer.length() ); return static_cast(*gptr()); } bobcat-6.07.01/randbuf/driver/0000775000175000017500000000000014737552575015045 5ustar frankfrankbobcat-6.07.01/randbuf/driver/build0000775000175000017500000000056114673353434016064 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-6.07.01/randbuf/driver/driver.cc0000664000175000017500000000137614736770154016650 0ustar frankfrank#include #include #include 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-6.07.01/randbuf/driver/driver.h0000664000175000017500000000076314673353434016507 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-6.07.01/randommt/0000775000175000017500000000000014673353434013742 5ustar frankfrankbobcat-6.07.01/randommt/randommt0000664000175000017500000000212414673353434015505 0ustar frankfrank#ifndef INCLUDED_BOBCAT_RANDOMMT_ #define INCLUDED_BOBCAT_RANDOMMT_ #include #include #include namespace FBB { template class RandomMT { using Distribution = typename std::conditional::value, std::uniform_int_distribution, std::uniform_real_distribution >::type; std::mt19937 d_engine; Distribution d_dist; public: RandomMT(Type minimum, Type maximum, size_t mtSeed); Type operator()(); // returns the next random value }; template RandomMT::RandomMT(Type minimum, Type maximum, size_t mtSeed) : d_engine(mtSeed) { if (maximum < minimum) throw Exception{} << "RandomMt{ minimum, maximum ... } " " requires minimum <= maximum"; d_dist.param(typename Distribution::param_type{ minimum, maximum } ); } template inline Type RandomMT::operator()() { return d_dist(d_engine); } } // FBB #endif bobcat-6.07.01/randommt/driver/0000775000175000017500000000000014737552575015245 5ustar frankfrankbobcat-6.07.01/randommt/driver/build0000775000175000017500000000011314673353434016255 0ustar frankfrank#!/bin/bash g++ `cat ../../c++std` -O2 -Wall -o driver driver.cc -lbobcat bobcat-6.07.01/randommt/driver/driver.cc0000664000175000017500000000125014673353434017035 0ustar frankfrank#include #include using namespace std; using namespace FBB; int main(int argc, char **argv) try { if (argc == 1) { cout << "arg[1]: minimum value, arg[2]: maximum value,\n" "arg[3]: (optional) seed (or time(0))\n"; return 0; } // specify, e.g., RandomMt to generate random double values RandomMT<> rmt( stoull(argv[1]), stoull(argv[2]), argc >= 4 ? stoull(argv[3]) : time(0) ); while (true) { cout << rmt() << "\n" "Enter: next"; cin.ignore(1000, '\n'); } } catch (exception const &exc) { cerr << exc.what() << '\n'; } bobcat-6.07.01/ranger/0000775000175000017500000000000014673353434013377 5ustar frankfrankbobcat-6.07.01/ranger/ranger.f0000664000175000017500000000017214673353434015024 0ustar frankfranktemplate Ranger::Ranger(Iter const &begin, Iter const &end) : d_begin(begin), d_end(end) {} bobcat-6.07.01/ranger/ranger4.f0000664000175000017500000000017714673353434015115 0ustar frankfranktemplate Ranger ranger(Data *begin, size_t count) { return Ranger(begin, begin + count); } bobcat-6.07.01/ranger/ranger3.f0000664000175000017500000000017414673353434015111 0ustar frankfranktemplate Ranger ranger(Iter &&begin, size_t count) { return Ranger(begin, begin + count); } bobcat-6.07.01/ranger/begin.f0000664000175000017500000000013514673353434014631 0ustar frankfrank template Iter const &Ranger::begin() const { return d_begin; } bobcat-6.07.01/ranger/end.f0000664000175000017500000000012514673353434014312 0ustar frankfranktemplate Iter const &Ranger::end() const { return d_end; } bobcat-6.07.01/ranger/ranger0000664000175000017500000000131414673353434014577 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-6.07.01/ranger/ranger1.f0000664000175000017500000000016014673353434015102 0ustar frankfranktemplate Ranger ranger(Iter &&begin, Iter &&end) { return Ranger(begin, end); } bobcat-6.07.01/ranger/ranger2.f0000664000175000017500000000016214673353434015105 0ustar frankfranktemplate Ranger ranger(Data *begin, Data *end) { return Ranger(begin, end); } bobcat-6.07.01/ranger/driver/0000775000175000017500000000000014737552575014702 5ustar frankfrankbobcat-6.07.01/ranger/driver/driver.cc0000664000175000017500000000273614673353434016504 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-6.07.01/READLINE0000664000175000017500000000012614673353433013225 0ustar frankfrank# This file is read from icmake/special readlinebuf readlinehistory readlinestream bobcat-6.07.01/readlinebuf/0000775000175000017500000000000014736742656014411 5ustar frankfrankbobcat-6.07.01/readlinebuf/readlinebuf2.cc0000664000175000017500000000130414673353434017250 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-6.07.01/readlinebuf/readline.cc0000664000175000017500000000040314673353434016470 0ustar frankfrank#include "readlinebuf.ih" size_t ReadLineBuf::readLine() { ofstream out{"/tmp/log", ios::app}; out << "called" << endl; char *buf = readline(d_prompt.c_str()); // readline(3) if (buf == 0) return 0; return nextLine(buf); } bobcat-6.07.01/readlinebuf/instance.cc0000664000175000017500000000030014673353434016505 0ustar frankfrank#include "readlinebuf.ih" ReadLineBuf &ReadLineBuf::instance() { if (s_readLineBuf.get() == 0) throw logic_error("ReadLineBuf not yet initialized"); return *s_readLineBuf; } bobcat-6.07.01/readlinebuf/data.cc0000664000175000017500000000012414673353434015616 0ustar frankfrank#include "readlinebuf.ih" std::unique_ptr ReadLineBuf::s_readLineBuf; bobcat-6.07.01/readlinebuf/initialize2.cc0000664000175000017500000000053714673353434017140 0ustar frankfrank#include "readlinebuf.ih" ReadLineBuf &ReadLineBuf::initialize(std::string const &prompt, size_t historySize, Type type) { if (s_readLineBuf != 0) throw logic_error("ReadLineBuf already initialized"); s_readLineBuf.reset(new ReadLineBuf(prompt, historySize, type)); return *s_readLineBuf; } bobcat-6.07.01/readlinebuf/nextline.cc0000664000175000017500000000106214673353434016535 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-6.07.01/readlinebuf/expansionerror.f0000664000175000017500000000013714673353434017627 0ustar frankfrankinline std::string const &ReadLineBuf::expansionError() const { return d_expansionError; } bobcat-6.07.01/readlinebuf/expansion.f0000664000175000017500000000013114673353434016547 0ustar frankfrankinline ReadLineBuf::Expansion ReadLineBuf::expansion() const { return d_expansion; } bobcat-6.07.01/readlinebuf/initialize1.cc0000664000175000017500000000043714673353434017136 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-6.07.01/readlinebuf/readlinebuf1.cc0000664000175000017500000000047714673353434017261 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-6.07.01/readlinebuf/icmconf0000664000175000017500000000010114673353434015732 0ustar frankfrank#define LIBRARY "readlinebuf" #include "../icmconf" bobcat-6.07.01/readlinebuf/setprompt.f0000664000175000017500000000013114673353434016600 0ustar frankfrankinline void ReadLineBuf::setPrompt(std::string const &prompt) { d_prompt = prompt; } bobcat-6.07.01/readlinebuf/destructor.cc0000664000175000017500000000014714673353434017110 0ustar frankfrank#include "readlinebuf.ih" ReadLineBuf::~ReadLineBuf() { if (d_history) clear_history(); } bobcat-6.07.01/readlinebuf/setexpansion.cc0000664000175000017500000000043214673353434017427 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-6.07.01/readlinebuf/expandline.cc0000664000175000017500000000111614673353434017036 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-6.07.01/readlinebuf/underflow.cc0000664000175000017500000000060014673353434016711 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-6.07.01/readlinebuf/readlinebuf0000664000175000017500000000432314673353434016606 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); size_t readLine(); // reads a line, adds it to the history 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-6.07.01/readlinebuf/driver/0000775000175000017500000000000014737720247015675 5ustar frankfrankbobcat-6.07.01/readlinebuf/driver/build0000775000175000017500000000066314673353434016726 0ustar frankfrank#!/bin/bash LIB="-lreadline -lbobcat -s" LIB="-L../tmp -lreadlinebuf -lbobcat -lreadline -s" # 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" CMD="$GPP -o driver -Wall driver.cc $LIB" # -I../../tmp driver.cc \ # -L../tmp -lreadlinebuf \ # -lreadline -lbobcat -s" echo $CMD $CMD bobcat-6.07.01/readlinebuf/driver/driver.cc0000664000175000017500000000232714736770267017511 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-6.07.01/readlinebuf/usetimestamps.cc0000664000175000017500000000025714673353434017617 0ustar frankfrank#include "readlinebuf.ih" bool ReadLineBuf::useTimestamps(string (*timestamp)()) { if (!d_history) return false; d_timestamp = timestamp; return true; } bobcat-6.07.01/readlinebuf/readlinebuf.ih0000664000175000017500000000052214736315237017201 0ustar frankfrank#include "readlinebuf" #include // TMP #include // TMP #include // TMP #include #include #include #include #include #include using namespace std; using namespace FBB; bobcat-6.07.01/readlinehistory/0000775000175000017500000000000014736742656015336 5ustar frankfrankbobcat-6.07.01/readlinehistory/instance.cc0000664000175000017500000000035314673353434017442 0ustar frankfrank#include "readlinehistory.ih" ReadLineHistory &ReadLineHistory::instance(bool useTimestamps) { s_readLineHistory.reset(new ReadLineHistory); s_readLineHistory->setTimestampsIO(useTimestamps); return *s_readLineHistory; } bobcat-6.07.01/readlinehistory/readlinehistory0000664000175000017500000001034714673353434020463 0ustar frankfrank#ifndef INCLUDED_BOBCAT_READLINEHISTORY_ #define INCLUDED_BOBCAT_READLINEHISTORY_ #include #include #include #include #include namespace FBB { struct ReadLineHistory { friend std::ostream &operator<<(std::ostream &out, ReadLineHistory const &history); friend std::istream &operator>>(std::istream &out, ReadLineHistory &history); class HistoryElement // stores the pointers to the { // relevant elements in HIST_ENTRY friend struct ReadLineHistory; // elements char const *d_line; char const *d_timestamp; public: char const *line() const; // .f char const *timestamp() const; // .f private: HistoryElement() = default; HistoryElement &operator=(HIST_ENTRY const *element); }; using ElementsPtr = HistoryElement *; using ElementsConstPtr = HistoryElement const *; struct const_iterator { using iterator_category = std::input_iterator_tag; using difference_type = std::ptrdiff_t; using value_type = HistoryElement const; using pointer = value_type *; using reference = value_type &; private: friend ReadLineHistory; friend std::reverse_iterator; size_t d_idx; // idx of a history element ElementsConstPtr d_elements; public: const_iterator &operator++(); // .f const_iterator operator++(int); // .f bool operator==(const_iterator const &rhs) const; // .f bool operator!=(const_iterator const &rhs) const; // .f HistoryElement const &operator*() const; HistoryElement const *operator->() const; // .f private: const_iterator(HistoryElement const *vect); // last element .f const_iterator(HistoryElement const *vect, size_t idx); // .f // for the reverse iter. const_iterator &operator--(); // .f const_iterator operator--(int); // .f }; using const_reverse_iterator = std::reverse_iterator; private: bool d_timestamps; // store time stamps or not ElementsPtr d_elements; // ptr to the HistoryElements // singleton static std::unique_ptr s_readLineHistory; public: ReadLineHistory(ReadLineHistory const &other) = delete; ~ReadLineHistory(); static ReadLineHistory &instance(bool useTimestamps = false); 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 // write/read the timestamps at // insertions/extractions ReadLineHistory &setTimestampsIO(bool useTimestamps); // .f size_t size() const; // .f size_t maxSize() const; // .f bool timestamps() const; // .f private: ReadLineHistory(); void destroy(); std::istream &extract(std::istream &in); void setElements(); 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 "readlinehistory.f" } // FBB #endif bobcat-6.07.01/readlinehistory/data.cc0000664000175000017500000000013714673353434016547 0ustar frankfrank#include "readlinehistory.ih" unique_ptr ReadLineHistory::s_readLineHistory; bobcat-6.07.01/readlinehistory/extractlines.cc0000664000175000017500000000027114673353434020342 0ustar frankfrank#include "readlinehistory.ih" istream &ReadLineHistory::extractLines(istream &in) { string line; while (getline(in, line)) add_history(line.c_str()); return in; } bobcat-6.07.01/readlinehistory/inserthistoryelement.cc0000664000175000017500000000034714673353434022141 0ustar frankfrank#include "readlinehistory.ih" void ReadLineHistory::insertHistoryElement(HistoryElement const &he, std::ostream &out) { out << he.line() << '\n' << he.timestamp() << '\n'; } bobcat-6.07.01/readlinehistory/readlinehistory.ih0000664000175000017500000000052314736315237021054 0ustar frankfrank#include "readlinehistory" #include // TMP #include #include using namespace std; using namespace FBB; //#include "opdec.f" //#include "opdecpost.f" inline ReadLineHistory::const_iterator ReadLineHistory::const_iterator::operator--(int) { return const_iterator(d_elements, d_idx--); } bobcat-6.07.01/readlinehistory/extracttimestamps.cc0000664000175000017500000000044714673353434021423 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-6.07.01/readlinehistory/icmconf0000664000175000017500000000010514673353434016663 0ustar frankfrank#define LIBRARY "readlinehistory" #include "../icmconf" bobcat-6.07.01/readlinehistory/extract.cc0000664000175000017500000000041114673353434017303 0ustar frankfrank#include "readlinehistory.ih" istream &ReadLineHistory::extract(istream &in) { if (!in) return in; clear_history(); if (d_timestamps) extractTimestamps(in); else extractLines(in); setElements(); return in; } bobcat-6.07.01/readlinehistory/operatorinsert.cc0000664000175000017500000000073114673353434020716 0ustar frankfrank#include "readlinehistory.ih" namespace FBB { std::ostream &operator<<(std::ostream &out, ReadLineHistory const &history) { void (*insert)(ReadLineHistory::HistoryElement const &he, ostream &out) = history.d_timestamps ? &ReadLineHistory::insertHistoryElement : &ReadLineHistory::insertLine; for (auto &he: history) (*insert)(he, out); return out; } } // FBB bobcat-6.07.01/readlinehistory/destructor.cc0000664000175000017500000000014014673353434020026 0ustar frankfrank#include "readlinehistory.ih" ReadLineHistory::~ReadLineHistory() { delete[] d_elements; } bobcat-6.07.01/readlinehistory/operatorassign.cc0000664000175000017500000000035014673353434020673 0ustar frankfrank#include "readlinehistory.ih" ReadLineHistory::HistoryElement &ReadLineHistory::HistoryElement::operator=(HIST_ENTRY const *element) { d_line = element->line; d_timestamp = element->timestamp; return *this; } bobcat-6.07.01/readlinehistory/insertline.cc0000664000175000017500000000021714673353434020011 0ustar frankfrank#include "readlinehistory.ih" void ReadLineHistory::insertLine(HistoryElement const &he, std::ostream &out) { out << he.line() << '\n'; } bobcat-6.07.01/readlinehistory/operatorderef.cc0000664000175000017500000000023714673353434020500 0ustar frankfrank#include "readlinehistory.ih" ReadLineHistory::HistoryElement const &ReadLineHistory::const_iterator::operator*() const { return d_elements[d_idx]; } bobcat-6.07.01/readlinehistory/setelements.cc0000664000175000017500000000041014673353434020160 0ustar frankfrank#include "readlinehistory.ih" void ReadLineHistory::setElements() { delete[] d_elements; d_elements = new HistoryElement[history_length]; for (size_t idx = 0, end = history_length; idx != end; ++idx) d_elements[idx] = history_list()[idx]; } bobcat-6.07.01/readlinehistory/readlinehistory.f0000664000175000017500000000504214673353434020703 0ustar frankfrank// free functions: // =============== inline std::istream &operator>>(std::istream &in, ReadLineHistory &history) { return history.extract(in); } // ReadLineHistory: // ================ inline ReadLineHistory::const_iterator ReadLineHistory::begin() const { return const_iterator(d_elements, 0); } inline ReadLineHistory::const_iterator ReadLineHistory::end() const { return const_iterator(d_elements); } inline size_t ReadLineHistory::maxSize() const { return history_max_entries; } inline ReadLineHistory::const_reverse_iterator ReadLineHistory::rbegin() const { return const_reverse_iterator(end()); } inline ReadLineHistory::const_reverse_iterator ReadLineHistory::rend() const { return const_reverse_iterator(begin()); } inline ReadLineHistory &ReadLineHistory::setTimestampsIO(bool useTimestamps) { d_timestamps = useTimestamps; return *this; } inline size_t ReadLineHistory::size() const { return history_length; } inline bool ReadLineHistory::timestamps() const { return d_timestamps; } // HistoryElement: // =============== inline char const *ReadLineHistory::HistoryElement::line() const { return d_line; } inline char const *ReadLineHistory::HistoryElement::timestamp() const { return d_timestamp; } // const_iterator: // =============== inline ReadLineHistory::const_iterator::const_iterator( ElementsConstPtr elements, size_t idx) : d_idx(idx), d_elements(elements) {} inline ReadLineHistory::const_iterator::const_iterator( ElementsConstPtr elements) : d_idx(history_length), d_elements(elements) {} inline ReadLineHistory::HistoryElement const *ReadLineHistory::const_iterator::operator->() const { return &operator*(); } inline bool ReadLineHistory::const_iterator::operator==( const_iterator const &rhs) const { return d_idx == rhs.d_idx; } inline ReadLineHistory::const_iterator &ReadLineHistory::const_iterator::operator++() { ++d_idx; return *this; } inline ReadLineHistory::const_iterator ReadLineHistory::const_iterator::operator++(int) { return const_iterator(d_elements, d_idx++); } inline ReadLineHistory::const_iterator &ReadLineHistory::const_iterator::operator--() { --d_idx; return *this; } inline bool ReadLineHistory::const_iterator::operator!=( const_iterator const &rhs) const { return not (*this == rhs); } bobcat-6.07.01/readlinehistory/readlinehistory1.cc0000664000175000017500000000032014673353434021116 0ustar frankfrank#include "readlinehistory.ih" ReadLineHistory::ReadLineHistory() : d_timestamps(false), // maybe reset by instance() d_elements(0) // new HistoryElement[history_length]) { setElements(); } bobcat-6.07.01/readlinehistory/driver/0000775000175000017500000000000014740155324016612 5ustar frankfrankbobcat-6.07.01/readlinehistory/driver/build0000775000175000017500000000061114737551253017644 0ustar frankfrank#!/bin/bash LIBS="-lbobcat -lreadline" #LIBS="-L../tmp -lreadlinehistory -lbobcat -lreadline" #LIBS="-L../../readlinebuf/tmp -lreadlinebuf -lbobcat -lreadline" #CMD="g++ `cat ../../c++std` -o driver -Wall -I../../tmp driver.cc -L../../tmp/lib \ # ${LIBS} -s" CMD="g++ ${ICMAKE_CPPSTD} -o driver -Wall driver.cc ${LIBS} -s" echo $CMD $CMD bobcat-6.07.01/readlinehistory/driver/driver.cc0000664000175000017500000000323214736771506020427 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" "Again: 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); cout << "\n" "All lines, from the last to the first:\n"; for_each(history.rbegin(), history.rend(), showHis); } bobcat-6.07.01/readlinestream/0000775000175000017500000000000014736520620015111 5ustar frankfrankbobcat-6.07.01/readlinestream/readlinestream1.f0000664000175000017500000000026614673353434020353 0ustar frankfrankinline ReadLineStream::ReadLineStream(std::string const &prompt, Type type) : std::istream(&ReadLineBuf::initialize(prompt, type)), d_readLineBuf(ReadLineBuf::instance()) {} bobcat-6.07.01/readlinestream/readlinestream2.f0000664000175000017500000000037514673353434020355 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-6.07.01/readlinestream/expansionerror.f0000664000175000017500000000016014673353434020342 0ustar frankfrankinline std::string const &ReadLineStream::expansionError() const { return d_readLineBuf.expansionError(); } bobcat-6.07.01/readlinestream/expansion.f0000664000175000017500000000015514673353434017274 0ustar frankfrankinline ReadLineStream::Expansion ReadLineStream::expansion() const { return d_readLineBuf.expansion(); } bobcat-6.07.01/readlinestream/readlinestream.ih0000664000175000017500000000010514736315237020434 0ustar frankfrank#include "readlinestream" using namespace std; using namespace FBB; bobcat-6.07.01/readlinestream/setprompt.f0000664000175000017500000000015214673353434017322 0ustar frankfrankinline void ReadLineStream::setPrompt(std::string const &prompt) { d_readLineBuf.setPrompt(prompt); } bobcat-6.07.01/readlinestream/readlinestream0000664000175000017500000000226314673353434020045 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-6.07.01/readlinestream/usetimestamps.f0000664000175000017500000000017514673353434020175 0ustar frankfrankinline bool ReadLineStream::useTimestamps(std::string (*timestamp)()) { return d_readLineBuf.useTimestamps(timestamp); } bobcat-6.07.01/readlinestream/driver/0000775000175000017500000000000014737553033016411 5ustar frankfrankbobcat-6.07.01/readlinestream/driver/build0000775000175000017500000000037414737553033017442 0ustar frankfrank#!/bin/bash CMD="g++ ${ICMAKE_CPPSTD} -o driver -Wall -I../../tmp driver.cc -L../../tmp/lib \ -lreadline -lbobcat -s" CMD="g++ ${ICMAKE_CPPSTD} -o driver -Wall driver.cc -lbobcat -s" echo $CMD $CMD bobcat-6.07.01/readlinestream/driver/driver.cc0000664000175000017500000000216214673353434020216 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-6.07.01/readlinestream/setexpansion.f0000664000175000017500000000014514673353434020007 0ustar frankfrankinline bool ReadLineStream::setExpansion(Type type) { return d_readLineBuf.setExpansion(type); } bobcat-6.07.01/README0000664000175000017500000000276214673353433013007 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-6.07.01/README.class-setup0000664000175000017500000002245414673353433015251 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-6.07.01/README.fnwrap0000664000175000017500000003273714673353433014310 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 { using ReturnType = Ret; }; 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: using NotUsed = Dissect *; The second support struct is: template struct At { using Type = typename std::tuple_element::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 { using RetType = typename Dissect::ReturnType; 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 ...> { using first_argument_type = typename TypeTrait::Plain; using second_argument_type = typename TypeTrait::Plain; using LastType = typename At::Type; 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-6.07.01/README.immovable0000664000175000017500000000300114673353433014744 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-6.07.01/README.milter0000664000175000017500000000253014673353433014273 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-6.07.01/README.optimization0000664000175000017500000000752214673353433015533 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-6.07.01/README.process-pipe0000664000175000017500000000632614673353433015417 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-6.07.01/README.X110000664000175000017500000000272414673353433013355 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-6.07.01/redirector/0000775000175000017500000000000014736742656014273 5ustar frankfrankbobcat-6.07.01/redirector/redirector1.f0000664000175000017500000000007014673353434016652 0ustar frankfrankinline Redirector::Redirector(int fd) : d_fd(fd) {} bobcat-6.07.01/redirector/swallow.cc0000664000175000017500000000027114673353434016262 0ustar frankfrank#include "redirector.ih" void Redirector::swallow(int alternateFd) const { if (dup2(d_fd, alternateFd) < 0) throw Exception{} << "Redirector::swallow(): " << errnodescr; } bobcat-6.07.01/redirector/accessvia.f0000664000175000017500000000012714673353434016373 0ustar frankfrankinline void Redirector::accessVia(int alternateFd) const { swallow(alternateFd); } bobcat-6.07.01/redirector/through.cc0000664000175000017500000000031514673353434016251 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-6.07.01/redirector/redirector0000664000175000017500000000110414673353434016344 0ustar frankfrank#ifndef INCLUDED_BOBCAT_REDIRECTOR_ #define INCLUDED_BOBCAT_REDIRECTOR_ #include 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-6.07.01/redirector/redirector.ih0000664000175000017500000000010314736315237016740 0ustar frankfrank#include "redirector" #include using namespace FBB; bobcat-6.07.01/redirector/driver/0000775000175000017500000000000014737552575015566 5ustar frankfrankbobcat-6.07.01/redirector/driver/build0000775000175000017500000002642414673353434016613 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-6.07.01/redirector/driver/driver.cc0000664000175000017500000000062014673353434017356 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-6.07.01/repeat/0000775000175000017500000000000014673353434013401 5ustar frankfrankbobcat-6.07.01/repeat/repeat0000664000175000017500000000172214673353434014606 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-6.07.01/repeat/call1.f0000664000175000017500000000023114673353434014540 0ustar frankfranktemplate inline void Repeat__::call(Fun fun, Params &&...params) { fun(std::forward(params)...); } bobcat-6.07.01/repeat/call2.f0000664000175000017500000000037314673353434014550 0ustar frankfranktemplate inline void Repeat__::call(Class &obj, Member member, Params &&...params) { (obj.*member)(std::forward(params)...); } bobcat-6.07.01/repeat/call3.f0000664000175000017500000000040514673353434014545 0ustar frankfranktemplate inline void Repeat__::call(Class const &obj, Member member, Params &&...params) { (obj.*member)(std::forward(params)...); } bobcat-6.07.01/repeat/repeat.f0000664000175000017500000000052414673353434015031 0ustar frankfranktemplate void repeat(Counter counter, First &&first, Params &&...params) { for (; counter; --counter) Repeat__::isClass>::call( std::forward(first), std::forward(params)...); } bobcat-6.07.01/repeat/driver/0000775000175000017500000000000014737552575014704 5ustar frankfrankbobcat-6.07.01/repeat/driver/build0000775000175000017500000000007014673353434015716 0ustar frankfrank#!/bin/bash g++ `cat ../../c++std` -o driver driver.cc bobcat-6.07.01/repeat/driver/driver.cc0000664000175000017500000000240514736770650016502 0ustar frankfrank#include #include #include #include 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-6.07.01/required0000664000175000017500000000117714673353434013672 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-6.07.01/reverse/0000775000175000017500000000000014673353434013574 5ustar frankfrankbobcat-6.07.01/reverse/reverse.f0000664000175000017500000000247614673353434015427 0ustar frankfranktemplate inline Reverse::Reverse(Type &type) : d_type(type) {} template inline Reverse::reverse_iter Reverse::begin() const { return reverse_iter{ d_type.end() }; } template inline Reverse::reverse_iter Reverse::end() const { return reverse_iter{ d_type.begin() }; } template inline auto reverse(Type &type) { return Reverse{ type }; } template inline auto reverse(Type const &type) { return Reverse{ type }; } template inline auto reverse(Type &&type) { return Reverse{ type }; } template inline ReverseArray::ReverseArray(Type (&type)[size]) : d_type(type) {} template inline auto reverse(Type (&type)[size]) { return ReverseArray{ type }; } template inline ReverseSize::ReverseSize(Type *type, size_t size) : d_type(type), d_size(size) {} template inline auto reverse(Type *type, size_t size) { return ReverseSize{ type, size }; } bobcat-6.07.01/reverse/reverse0000664000175000017500000000272414673353434015177 0ustar frankfrank#ifndef INCLUDED_BOBCAT_REVERSE_ #define INCLUDED_BOBCAT_REVERSE_ #include #include namespace FBB { template class Reverse { Type &d_type; using reverse_iter = std::reverse_iterator< typename std::conditional< isConst, typename Type::const_iterator, typename Type::iterator >::type >; public: Reverse(Type &type); reverse_iter begin() const; reverse_iter end() const; }; template class ReverseArray { Type (&d_type)[size]; public: ReverseArray(Type (&type)[size]); std::reverse_iterator begin() const { return std::reverse_iterator{ d_type + size }; } std::reverse_iterator end() const { return std::reverse_iterator{ d_type }; } }; template class ReverseSize { Type *d_type; size_t d_size; public: ReverseSize(Type *type, size_t size); std::reverse_iterator begin() const { return std::reverse_iterator{ d_type + d_size }; } std::reverse_iterator end() const { return std::reverse_iterator{ d_type }; } }; #include "reverse.f" } // FBB #endif bobcat-6.07.01/reverse/driver/0000775000175000017500000000000014673353434015067 5ustar frankfrankbobcat-6.07.01/reverse/driver/main.cc0000664000175000017500000000272414673353434016327 0ustar frankfrank#include #include #include using namespace std; using namespace FBB; int main() { int intArr[] = { 1, 2, 3, 4, 5}; // arrays of known sizes for (int value: reverse(intArr)) cout << value << ' '; cout << '\n'; for (int value: reverse(intArr, 5)) // using specified sizes cout << value << ' '; cout << '\n'; int const constArr[] = { 1, 2, 3, 4, 5};// arrays with const elements for (int value: reverse(constArr)) cout << value << ' '; cout << '\n'; for (int value: reverse(constArr, 5)) // using specified sizes cout << value << ' '; cout << '\n'; for (int value: reverse(intArr, 5)) // arrays of specified sizes cout << value << ' '; cout << '\n'; vector vi{ 1, 2, 3, 4, 5 }; // handle non-const objects for (int value: reverse(vi)) cout << value << ' '; cout << '\n'; vector const cvi{ 1, 2, 3, 4, 5 }; // handle const objects for (int value: reverse(cvi)) cout << value << ' '; cout << '\n'; // handle lvalues for (int value: reverse(initializer_list{ 1, 2, 4, 8 })) cout << value << ' '; cout.put('\n'); // named constant objects auto ilist = initializer_list{ 1, 2, 4, 8 }; for (int value: reverse(ilist)) cout << value << ' '; cout.put('\n'); } bobcat-6.07.01/scripts/0000775000175000017500000000000014673353434013610 5ustar frankfrankbobcat-6.07.01/scripts/check1.20.00000775000175000017500000000103214673353434015246 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-6.07.01/selector/0000775000175000017500000000000014736742656013751 5ustar frankfrankbobcat-6.07.01/selector/rmwritefd.f0000664000175000017500000000010614673353434016110 0ustar frankfrankinline void Selector::rmWriteFd(int fd) { FD_CLR(fd, &d_write); } bobcat-6.07.01/selector/writefd.f0000664000175000017500000000012214673353434015547 0ustar frankfrankinline int Selector::writeFd() { return checkSet(&d_writeidx, d_ret_write); } bobcat-6.07.01/selector/addwritefd.f0000664000175000017500000000010614673353434016222 0ustar frankfrankinline void Selector::addWriteFd(int fd) { addFd(&d_write, fd); } bobcat-6.07.01/selector/setalarm.cc0000664000175000017500000000046114673353434016061 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-6.07.01/selector/nready.f0000664000175000017500000000006414673353434015372 0ustar frankfrankinline int Selector::nReady() { return d_ret; } bobcat-6.07.01/selector/addfd.cc0000664000175000017500000000021014673353434015303 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-6.07.01/selector/noalarm.f0000664000175000017500000000011714673353434015540 0ustar frankfrankinline void Selector::noAlarm() { d_alarm.tv_sec = d_alarm.tv_usec = -1; } bobcat-6.07.01/selector/exceptfd.f0000664000175000017500000000012514673353434015710 0ustar frankfrankinline int Selector::exceptFd() { return checkSet(&d_exceptidx, d_ret_except); } bobcat-6.07.01/selector/wait.cc0000664000175000017500000000131114673353434015210 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-6.07.01/selector/checkset.cc0000664000175000017500000000032014673353434016034 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-6.07.01/selector/isempty.cc0000664000175000017500000000023714673353434015744 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-6.07.01/selector/icmconf0000664000175000017500000000007614673353434015305 0ustar frankfrank#define LIBRARY "selector" #include "../icmconf" bobcat-6.07.01/selector/selector.ih0000664000175000017500000000014714736315237016104 0ustar frankfrank#include "selector" #include #include using namespace std; using namespace FBB; bobcat-6.07.01/selector/rmexceptfd.f0000664000175000017500000000011014673353434016241 0ustar frankfrankinline void Selector::rmExceptFd(int fd) { FD_CLR(fd, &d_except); } bobcat-6.07.01/selector/addexceptfd.f0000664000175000017500000000011014673353434016353 0ustar frankfrankinline void Selector::addExceptFd(int fd) { addFd(&d_except, fd); } bobcat-6.07.01/selector/selector1.cc0000664000175000017500000000030714673353434016151 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-6.07.01/selector/selector0000664000175000017500000000435214673353434015510 0ustar frankfrank#ifndef INCLUDED_BOBCAT_SELECTOR_ #define INCLUDED_BOBCAT_SELECTOR_ #include #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-6.07.01/selector/rmreadfd.f0000664000175000017500000000010414673353434015667 0ustar frankfrankinline void Selector::rmReadFd(int fd) { FD_CLR(fd, &d_read); } bobcat-6.07.01/selector/readfd.f0000664000175000017500000000011714673353434015334 0ustar frankfrankinline int Selector::readFd() { return checkSet(&d_readidx, d_ret_read); } bobcat-6.07.01/selector/driver/0000775000175000017500000000000014737552575015244 5ustar frankfrankbobcat-6.07.01/selector/driver/build0000775000175000017500000000005614673353434016262 0ustar frankfrank#!/bin/bash g++ -o driver driver.cc -lbobcat bobcat-6.07.01/selector/driver/driver.cc0000664000175000017500000000133614673353434017041 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-6.07.01/selector/driver/testempty.cc0000664000175000017500000000074614673353434017610 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-6.07.01/selector/addreadfd.f0000664000175000017500000000010414673353434016001 0ustar frankfrankinline void Selector::addReadFd(int fd) { addFd(&d_read, fd); } bobcat-6.07.01/semaphore/0000775000175000017500000000000014736742656014114 5ustar frankfrankbobcat-6.07.01/semaphore/wait2.f0000664000175000017500000000072314673353434015303 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-6.07.01/semaphore/notify.cc0000664000175000017500000000040114673353434015716 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-6.07.01/semaphore/notifyall.cc0000664000175000017500000000040514673353434016413 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-6.07.01/semaphore/wait.cc0000664000175000017500000000055414673353434015363 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-6.07.01/semaphore/waituntil.f0000664000175000017500000000073714673353434016302 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-6.07.01/semaphore/waitfun.f0000664000175000017500000000073414673353434015734 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-6.07.01/semaphore/waitfor.f0000664000175000017500000000065414673353434015733 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-6.07.01/semaphore/set.cc0000664000175000017500000000020414673353434015202 0ustar frankfrank#include "semaphore.ih" void Semaphore::set(size_t available) { lock_guard lk(d_mutex); d_nAvailable = available; } bobcat-6.07.01/semaphore/semaphore0000664000175000017500000000250514673353434016014 0ustar frankfrank#ifndef INCLUDED_BOBCAT_SEMAPHORE_ #define INCLUDED_BOBCAT_SEMAPHORE_ #include #include #include namespace FBB { class Semaphore { 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-6.07.01/semaphore/icmconf0000664000175000017500000000007714673353434015451 0ustar frankfrank#define LIBRARY "semaphore" #include "../icmconf" bobcat-6.07.01/semaphore/semaphore1.cc0000664000175000017500000000014314673353434016455 0ustar frankfrank#include "semaphore.ih" Semaphore::Semaphore(size_t nAvailable) : d_nAvailable(nAvailable) {} bobcat-6.07.01/semaphore/size.f0000664000175000017500000000010414673353434015220 0ustar frankfrankinline size_t Semaphore::size() const { return d_nAvailable; } bobcat-6.07.01/semaphore/semaphore.ih0000664000175000017500000000010214736315237016401 0ustar frankfrank#include "semaphore" using namespace std; using namespace FBB; bobcat-6.07.01/sep/0000775000175000017500000000000014673353434012710 5ustar frankfrankbobcat-6.07.01/sep/sep0000664000175000017500000000044614673353434013426 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-6.07.01/serversocket/0000775000175000017500000000000014736742656014650 5ustar frankfrankbobcat-6.07.01/serversocket/serversocket.ih0000664000175000017500000000023414736315237017677 0ustar frankfrank#include "serversocket" #include #include #include #include using namespace std; using namespace FBB; bobcat-6.07.01/serversocket/serversocket1.cc0000664000175000017500000000101514673353434017744 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-6.07.01/serversocket/accept.cc0000664000175000017500000000065614673353434016415 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-6.07.01/serversocket/serversocket0000664000175000017500000000064214673353434017304 0ustar frankfrank#ifndef INCLUDED_BOBCAT_SERVERSOCKET_ #define INCLUDED_BOBCAT_SERVERSOCKET_ #include #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-6.07.01/serversocket/icmconf0000664000175000017500000000014214673353434016176 0ustar frankfrank#define LIBRARY "serversocket" #define AUXFLAGS "-I../tmp" #include "../icmconf" bobcat-6.07.01/serversocket/listen.cc0000664000175000017500000000106214673353434016444 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-6.07.01/serversocket/driver/0000775000175000017500000000000014673353434016133 5ustar frankfrankbobcat-6.07.01/serversocket/driver/build0000775000175000017500000000017114673353434017157 0ustar frankfrank#!/bin/bash tput clear GPP="g++ `cat ../../c++std`" CMD="$GPP -o server -Wall server.cc -lbobcat -s" echo $CMD $CMD bobcat-6.07.01/serversocket/driver/server.cc0000664000175000017500000000577714673353434017770 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-6.07.01/sharedblock/0000775000175000017500000000000014736520620014373 5ustar frankfrankbobcat-6.07.01/sharedblock/sharedblock.ih0000664000175000017500000000010414736315237017177 0ustar frankfrank#include "sharedblock" using namespace std; using namespace FBB; bobcat-6.07.01/sharedblock/sharedblock0000664000175000017500000000061614673353434016611 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-6.07.01/sharedblock/lock.f0000664000175000017500000000007014673353434015476 0ustar frankfrankinline void SharedBlock::lock() { d_mutex.lock(); } bobcat-6.07.01/sharedblock/unlock.f0000664000175000017500000000007414673353434016045 0ustar frankfrankinline void SharedBlock::unlock() { d_mutex.unlock(); } bobcat-6.07.01/sharedblock/setid.f0000664000175000017500000000007214673353434015660 0ustar frankfrankinline void SharedBlock::setID(int id) { d_id = id; } bobcat-6.07.01/sharedblock/id.f0000664000175000017500000000007014673353434015142 0ustar frankfrankinline int SharedBlock::id() const { return d_id; } bobcat-6.07.01/sharedbuf/0000775000175000017500000000000014736742656014074 5ustar frankfrankbobcat-6.07.01/sharedbuf/xsputn.cc0000664000175000017500000000024114673353434015731 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-6.07.01/sharedbuf/showmanyc.cc0000664000175000017500000000014014673353434016376 0ustar frankfrank#include "sharedbuf.ih" streamsize SharedBuf::showmanyc() { return d_memory.showmanyc(); } bobcat-6.07.01/sharedbuf/overflow.cc0000664000175000017500000000016114673353434016234 0ustar frankfrank#include "sharedbuf.ih" int SharedBuf::overflow(int ch) { return mode(ios::out) ? d_memory.put(ch) : EOF; } bobcat-6.07.01/sharedbuf/sharedbuf1.cc0000664000175000017500000000024614673353434016421 0ustar frankfrank#include "sharedbuf.ih" SharedBuf::SharedBuf() : d_openMode(static_cast(0)), d_currentMode(d_openMode) { setg(0, 0, 0); setp(0, 0); } bobcat-6.07.01/sharedbuf/clear.f0000664000175000017500000000007114673353434015317 0ustar frankfrankinline void SharedBuf::clear() { d_memory.clear(); } bobcat-6.07.01/sharedbuf/pbackfail.cc0000664000175000017500000000034414673353434016310 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-6.07.01/sharedbuf/remove.f0000664000175000017500000000007314673353434015530 0ustar frankfrankinline void SharedBuf::remove() { d_memory.remove(); } bobcat-6.07.01/sharedbuf/xsgetn.cc0000664000175000017500000000022114673353434015676 0ustar frankfrank#include "sharedbuf.ih" streamsize SharedBuf::xsgetn(char *data, streamsize len) { return mode(ios::in) ? d_memory.read(data, len) : EOF; } bobcat-6.07.01/sharedbuf/kill.f0000664000175000017500000000006714673353434015171 0ustar frankfrankinline void SharedBuf::kill() { d_memory.kill(); } bobcat-6.07.01/sharedbuf/createsharedcondition.cc0000664000175000017500000000035114673353434020733 0ustar frankfrank#include "sharedbuf.ih" SharedCondition SharedBuf::createSharedCondition() { auto sharedCondition(SharedCondition::create(d_memory)); seekoff(sharedCondition.offset() + sharedCondition.size()); return sharedCondition; } bobcat-6.07.01/sharedbuf/meminfo.f0000664000175000017500000000012114673353434015657 0ustar frankfrankinline void SharedBuf::memInfo(std::ostream &out) const { out << d_memory; } bobcat-6.07.01/sharedbuf/setmemory.f0000664000175000017500000000013014673353434016251 0ustar frankfrankinline void SharedBuf::setMemory(SharedMemory &&tmp) { d_memory = std::move(tmp); } bobcat-6.07.01/sharedbuf/sharedbuf.ih0000664000175000017500000000010214736315237016341 0ustar frankfrank#include "sharedbuf" using namespace std; using namespace FBB; bobcat-6.07.01/sharedbuf/mode.cc0000664000175000017500000000025414673353434015320 0ustar frankfrank#include "sharedbuf.ih" bool SharedBuf::mode(ios::openmode flag) { if (not (d_currentMode & flag)) return false; d_currentMode = flag; return true; } bobcat-6.07.01/sharedbuf/icmconf0000664000175000017500000000007714673353434015431 0ustar frankfrank#define LIBRARY "sharedbuf" #include "../icmconf" bobcat-6.07.01/sharedbuf/setopenmode.f0000664000175000017500000000017514673353434016560 0ustar frankfrankinline void SharedBuf::setOpenMode(std::ios::openmode openMode) { d_openMode = openMode; d_currentMode = openMode; } bobcat-6.07.01/sharedbuf/seekoff.cc0000664000175000017500000000041414673353434016014 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-6.07.01/sharedbuf/sharedbuf0000664000175000017500000000536314673353434015761 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-6.07.01/sharedbuf/sharedbuf3.cc0000664000175000017500000000055514673353434016426 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-6.07.01/sharedbuf/attachsharedcondition.cc0000664000175000017500000000056714673353434020745 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-6.07.01/sharedbuf/sharedbuf2.cc0000664000175000017500000000051314673353434016417 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-6.07.01/sharedbuf/underflow.cc0000664000175000017500000000035314673353434016401 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-6.07.01/sharedbuf/seekpos.cc0000664000175000017500000000027314673353434016046 0ustar frankfrank#include "sharedbuf.ih" ios::pos_type SharedBuf::seekpos(ios::pos_type offset, ios::openmode mode) { return seekoff(offset, ios::beg, mode); } bobcat-6.07.01/sharedbuf/sharedmemory.f0000664000175000017500000000011014673353434016722 0ustar frankfrankinline SharedMemory &SharedBuf::sharedMemory() { return d_memory; } bobcat-6.07.01/sharedbuf/id.f0000664000175000017500000000007714673353434014633 0ustar frankfrankinline int SharedBuf::id() const { return d_memory.id(); } bobcat-6.07.01/sharedbuf/driver/0000775000175000017500000000000014737552575015367 5ustar frankfrankbobcat-6.07.01/sharedbuf/driver/build0000775000175000017500000000013314673353434016401 0ustar frankfrank#!/bin/bash g++ `cat ../../c++std` -o driver -I.. driver.cc -L../tmp -lsharedbuf -lbobcat bobcat-6.07.01/sharedbuf/driver/driver.cc0000664000175000017500000000505514673353434017166 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-6.07.01/sharedbuf/driver/bobcat0000777000175000017500000000000014673353434016665 2..ustar frankfrankbobcat-6.07.01/sharedcondition/0000775000175000017500000000000014736742656015306 5ustar frankfrankbobcat-6.07.01/sharedcondition/wait2.f0000664000175000017500000000041314673353434016471 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-6.07.01/sharedcondition/notify.cc0000664000175000017500000000027214673353434017116 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-6.07.01/sharedcondition/waitfor2.f0000664000175000017500000000041414673353434017201 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-6.07.01/sharedcondition/condition1.cc0000664000175000017500000000040614673353434017654 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-6.07.01/sharedcondition/prepare.cc0000664000175000017500000000051014673353434017237 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-6.07.01/sharedcondition/notifyall.cc0000664000175000017500000000027614673353434017613 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-6.07.01/sharedcondition/wait.cc0000664000175000017500000000031114673353434016544 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-6.07.01/sharedcondition/offset.f0000664000175000017500000000012014673353434016724 0ustar frankfrankinline std::streamsize SharedCondition::offset() const { return d_offset; } bobcat-6.07.01/sharedcondition/sharedcondition.ih0000664000175000017500000000011014736315237020764 0ustar frankfrank#include "sharedcondition" using namespace std; using namespace FBB; bobcat-6.07.01/sharedcondition/readattach.cc0000664000175000017500000000000014673353434017673 0ustar frankfrankbobcat-6.07.01/sharedcondition/lock.cc0000664000175000017500000000023014673353434016530 0ustar frankfrank#include "sharedcondition.ih" void SharedCondition::lock() { Data data = prepare(); data.condition->lock(); d_shmem->seek(data.offset); } bobcat-6.07.01/sharedcondition/icmconf0000664000175000017500000000016214673353434016636 0ustar frankfrank#define LIBRARY "sharedcondition" #define AUXFLAGS "-pthread -I." #include "../icmconf" bobcat-6.07.01/sharedcondition/unlock.cc0000664000175000017500000000023414673353434017077 0ustar frankfrank#include "sharedcondition.ih" void SharedCondition::unlock() { Data data = prepare(); data.condition->unlock(); d_shmem->seek(data.offset); } bobcat-6.07.01/sharedcondition/size.f0000664000175000017500000000011314673353434016412 0ustar frankfrankconstexpr size_t SharedCondition::size() { return sizeof(Condition); } bobcat-6.07.01/sharedcondition/destructor.cc0000664000175000017500000000015214673353434020001 0ustar frankfrank#include "sharedcondition.ih" SharedCondition::~SharedCondition() { if (d_shmem) unlock(); } bobcat-6.07.01/sharedcondition/sharedcondition0000664000175000017500000000477314673353434020411 0ustar frankfrank#ifndef INCLUDED_BOBCAT_SHAREDCONDITION_ #define INCLUDED_BOBCAT_SHAREDCONDITION_ #include #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-6.07.01/sharedcondition/create.cc0000664000175000017500000000051714673353434017053 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-6.07.01/sharedcondition/waiter.cc0000664000175000017500000000065114673353434017102 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-6.07.01/sharedcondition/sharedcondition2.cc0000664000175000017500000000023414673353434021043 0ustar frankfrank#include "sharedcondition.ih" SharedCondition::SharedCondition(SharedMemory &shmem, std::streamsize offset) : d_shmem(&shmem), d_offset(offset) {} bobcat-6.07.01/sharedcondition/waituntil1.f0000664000175000017500000000046114673353434017547 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-6.07.01/sharedcondition/waitfor1.f0000664000175000017500000000034014673353434017176 0ustar frankfranktemplate inline std::cv_status SharedCondition::wait_for( std::chrono::duration const &relTime) { return wait_until(std::chrono::system_clock::now() + relTime); } bobcat-6.07.01/sharedcondition/waituntil2.f0000664000175000017500000000076314673353434017555 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-6.07.01/sharedcondition/attach.cc0000664000175000017500000000060414673353434017051 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-6.07.01/sharedcondition/sharedcondition1.cc0000664000175000017500000000014714673353434021045 0ustar frankfrank#include "sharedcondition.ih" SharedCondition::SharedCondition() : d_shmem(0), d_offset(0) {} bobcat-6.07.01/sharedcondition/driver/0000775000175000017500000000000014737552575016601 5ustar frankfrankbobcat-6.07.01/sharedcondition/driver/build0000775000175000017500000000024114673353434017613 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-6.07.01/sharedcondition/driver/driver.cc0000664000175000017500000000545214673353434020401 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-6.07.01/sharedmemory/0000775000175000017500000000000014736742656014630 5ustar frankfrankbobcat-6.07.01/sharedmemory/put.cc0000664000175000017500000000052014673353434015734 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-6.07.01/sharedmemory/lockall.cc0000664000175000017500000000053414673353434016552 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-6.07.01/sharedmemory/showmanyc.cc0000664000175000017500000000016514673353434017141 0ustar frankfrank#include "sharedmemory.ih" streamsize SharedMemory::showmanyc() { return d_pos.eof() ? 0 : d_pos.showmanyc(); } bobcat-6.07.01/sharedmemory/get.cc0000664000175000017500000000047614673353434015715 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-6.07.01/sharedmemory/seek.cc0000664000175000017500000000021514673353434016054 0ustar frankfrank#include "sharedmemory.ih" ios::pos_type SharedMemory::seek(ios::off_type offset, ios::seekdir way) { return d_pos.seek(offset, way); } bobcat-6.07.01/sharedmemory/insert.cc0000664000175000017500000000105314673353434016432 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-6.07.01/sharedmemory/operatorassign.f0000664000175000017500000000014614673353434020030 0ustar frankfrankinline SharedMemory &SharedMemory::operator=(SharedMemory &&tmp) { swap(tmp); return *this; } bobcat-6.07.01/sharedmemory/sharedmemory0000664000175000017500000001343614673353434017251 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-6.07.01/sharedmemory/datasegmentsize.f0000664000175000017500000000017114673353434020155 0ustar frankfrankinline size_t SharedMemory::dataSegmentSize() const { return d_sharedSegment ? d_sharedSegment->segmentSize() : 0; } bobcat-6.07.01/sharedmemory/install.f0000664000175000017500000000231014673353434016431 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-6.07.01/sharedmemory/write1.f0000664000175000017500000000022614673353434016202 0ustar frankfranktemplate inline int SharedMemory::write(Type const *value) { return write(reinterpret_cast(value), sizeof(Type)); } bobcat-6.07.01/sharedmemory/swap.f0000664000175000017500000000012614673353434015740 0ustar frankfrankinline void SharedMemory::swap(SharedMemory &other) { FBB::fswap(*this, other); } bobcat-6.07.01/sharedmemory/read.cc0000664000175000017500000000113614673353434016043 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-6.07.01/sharedmemory/sharedmemory2.cc0000664000175000017500000000051514673353434017711 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-6.07.01/sharedmemory/readblock.cc0000664000175000017500000000153014673353434017054 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-6.07.01/sharedmemory/ptr.cc0000664000175000017500000000035414673353434015736 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-6.07.01/sharedmemory/computesegmentsize.cc0000664000175000017500000000304614673353434021064 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) { using Entry = SharedBlock; 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-6.07.01/sharedmemory/read2.f0000664000175000017500000000053614673353434015770 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-6.07.01/sharedmemory/map1.cc0000664000175000017500000000033414673353434015765 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-6.07.01/sharedmemory/kill.cc0000664000175000017500000000034614673353434016065 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-6.07.01/sharedmemory/offset.f0000664000175000017500000000012314673353434016251 0ustar frankfrankinline std::streamsize SharedMemory::offset() const { return d_pos.offset(); } bobcat-6.07.01/sharedmemory/remove1.cc0000664000175000017500000000015014673353434016501 0ustar frankfrank#include "sharedmemory.ih" void SharedMemory::remove() { validate(); lockAll(); kill(); } bobcat-6.07.01/sharedmemory/truncate.cc0000664000175000017500000000032714673353434016756 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-6.07.01/sharedmemory/lock.cc0000664000175000017500000000032314673353434016055 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-6.07.01/sharedmemory/clear.cc0000664000175000017500000000017314673353434016216 0ustar frankfrank#include "sharedmemory.ih" void SharedMemory::clear() { validate(); lockAll(); clearAll(); unlockAll(); } bobcat-6.07.01/sharedmemory/icmconf0000664000175000017500000000010214673353434016152 0ustar frankfrank#define LIBRARY "sharedmemory" #include "../icmconf" bobcat-6.07.01/sharedmemory/read1.f0000664000175000017500000000021014673353434015754 0ustar frankfranktemplate inline int SharedMemory::read(Type *value) { return read(reinterpret_cast(value), sizeof(Type)); } bobcat-6.07.01/sharedmemory/sharedmemory.ih0000664000175000017500000000012714736315237017640 0ustar frankfrank#include "sharedmemory" #include using namespace std; using namespace FBB; bobcat-6.07.01/sharedmemory/unlock.cc0000664000175000017500000000032614673353434016423 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-6.07.01/sharedmemory/validate.cc0000664000175000017500000000023514673353434016720 0ustar frankfrank#include "sharedmemory.ih" void SharedMemory::validate() const { if (d_sharedSegment == 0) throw Exception{} << "SharedMemory not available"; } bobcat-6.07.01/sharedmemory/nreadable.f0000664000175000017500000000017214673353434016704 0ustar frankfrankinline std::streamsize SharedMemory::nReadable() const { return d_sharedSegment ? d_sharedSegment->nReadable() : 0; } bobcat-6.07.01/sharedmemory/sharedmemory3.cc0000664000175000017500000000030214673353434017704 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-6.07.01/sharedmemory/writeblock.cc0000664000175000017500000000102314673353434017270 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-6.07.01/sharedmemory/operatorinsert.f0000664000175000017500000000015414673353434020047 0ustar frankfrankinline std::ostream &operator<<(std::ostream &out, SharedMemory const &mem) { return mem.insert(out); } bobcat-6.07.01/sharedmemory/destructor.cc0000664000175000017500000000023314673353434017323 0ustar frankfrank#include "sharedmemory.ih" SharedMemory::~SharedMemory() { SharedSegment::detach(d_data, false); SharedSegment::detach(d_sharedSegment, false); } bobcat-6.07.01/sharedmemory/blockoffset.f0000664000175000017500000000013514673353434017267 0ustar frankfrankinline std::streamsize SharedMemory::blockOffset() const { return d_pos.blockOffset(); } bobcat-6.07.01/sharedmemory/map2.cc0000664000175000017500000000072614673353434015773 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-6.07.01/sharedmemory/unlockall.cc0000664000175000017500000000047314673353434017117 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-6.07.01/sharedmemory/maxoffset.f0000664000175000017500000000013114673353434016756 0ustar frankfrankinline std::streamsize SharedMemory::maxOffset() const { return d_pos.maxOffset(); } bobcat-6.07.01/sharedmemory/write.cc0000664000175000017500000000150214673353434016257 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-6.07.01/sharedmemory/clearall.cc0000664000175000017500000000030014673353434016677 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-6.07.01/sharedmemory/blockavailable.cc0000664000175000017500000000063714673353434020070 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-6.07.01/sharedmemory/id.f0000664000175000017500000000007114673353434015361 0ustar frankfrankinline int SharedMemory::id() const { return d_id; } bobcat-6.07.01/sharedmemory/write2.f0000664000175000017500000000054614673353434016210 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-6.07.01/sharedmutex/0000775000175000017500000000000014736742656014462 5ustar frankfrankbobcat-6.07.01/sharedmutex/sharedmutex0000664000175000017500000000106714673353434016732 0ustar frankfrank#ifndef INCLUDED_BOBCAT_SHAREDMUTEX_ #define INCLUDED_BOBCAT_SHAREDMUTEX_ #include #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-6.07.01/sharedmutex/sharedmutex1.cc0000664000175000017500000000051214673353434017371 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-6.07.01/sharedmutex/sharedmutex.ih0000664000175000017500000000010414736315237017317 0ustar frankfrank#include "sharedmutex" using namespace std; using namespace FBB; bobcat-6.07.01/sharedmutex/unlock.f0000664000175000017500000000011214673353434016106 0ustar frankfrankinline void SharedMutex::unlock() { pthread_mutex_unlock(&d_mutex); } bobcat-6.07.01/sharedmutex/mutexptr.f0000664000175000017500000000011114673353434016502 0ustar frankfrankinline pthread_mutex_t *SharedMutex::mutexPtr() { return &d_mutex; } bobcat-6.07.01/sharedmutex/lock.cc0000664000175000017500000000026114673353434015710 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-6.07.01/sharedmutex/icmconf0000664000175000017500000000010114673353434016003 0ustar frankfrank#define LIBRARY "sharedmutex" #include "../icmconf" bobcat-6.07.01/sharedmutex/destructor.cc0000664000175000017500000000011114673353434017150 0ustar frankfrank#include "sharedmutex.ih" SharedMutex::~SharedMutex() { unlock(); } bobcat-6.07.01/sharedmutex/driver/0000775000175000017500000000000014737552575015755 5ustar frankfrankbobcat-6.07.01/sharedmutex/driver/build0000775000175000017500000000006414673353434016772 0ustar frankfrank#!/bin/bash g++ -Wall driver.cc -lpthread -lbobcat bobcat-6.07.01/sharedmutex/driver/driver.cc0000664000175000017500000000264714673353434017560 0ustar frankfrank#include #include #include #include #include #include #include #include #include using namespace std; using namespace FBB; class Wait: public Fork { SharedSegment *d_shared; int d_id; SharedMutex *d_mutex; public: Wait(); ~Wait(); void childProcess() override; void parentProcess() override; }; Wait::Wait() : d_shared(SharedSegment::create(&d_id, 1, 100, 0700)), d_mutex(new (d_shared) SharedMutex) { cout << "shared memory ID = " << d_id << '\n'; } Wait::~Wait() { d_mutex->~SharedMutex(); SharedSegment::deleteSegment(d_id); cout << "deleted the shared memory\n"; } void Wait::childProcess() { Semaphore waiter{0}; while (true) { waiter.wait_for(chrono::seconds(2)); d_mutex->lock(); cout << "child hello\n"; d_mutex->unlock(); } } void Wait::parentProcess() { string line; do { cout << "press enter to allow the parent to locck\n"; cin.ignore(100, '\n'); d_mutex->lock(); cout << "parent has the lock, press enter to continue " "(to end: some input)\n"; getline(cin, line); d_mutex->unlock(); } while (line.empty()); kill(pid(), SIGTERM); } int main() { Wait waiter; waiter.fork(); } bobcat-6.07.01/sharedpos/0000775000175000017500000000000014736742656014121 5ustar frankfrankbobcat-6.07.01/sharedpos/showmanyc.cc0000664000175000017500000000051714673353434016433 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-6.07.01/sharedpos/seek.cc0000664000175000017500000000055714673353434015356 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-6.07.01/sharedpos/insert.cc0000664000175000017500000000046614673353434015732 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-6.07.01/sharedpos/reset.cc0000664000175000017500000000044514673353434015545 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-6.07.01/sharedpos/update.cc0000664000175000017500000000073414673353434015706 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-6.07.01/sharedpos/segmentsize.f0000664000175000017500000000013114673353434016610 0ustar frankfrankinline size_t SharedPos::segmentSize() const { return d_sharedData->segmentSize(); } bobcat-6.07.01/sharedpos/eof.f0000664000175000017500000000013114673353434015024 0ustar frankfrankinline bool SharedPos::eof() const { return d_offset >= d_sharedData->nReadable(); } bobcat-6.07.01/sharedpos/offset.f0000664000175000017500000000011214673353434015540 0ustar frankfrankinline std::streamsize SharedPos::offset() const { return d_offset; } bobcat-6.07.01/sharedpos/blockidx.f0000664000175000017500000000010514673353434016053 0ustar frankfrankinline size_t SharedPos::blockIdx() const { return d_blockIdx; } bobcat-6.07.01/sharedpos/icmconf0000664000175000017500000000010314673353434015444 0ustar frankfrank#define LIBRARY "sharedsegment" #include "../icmconf" bobcat-6.07.01/sharedpos/operatorplusis.cc0000664000175000017500000000014714673353434017515 0ustar frankfrank#include "sharedpos.ih" void SharedPos::operator+=(size_t len) { d_offset += len; update(); } bobcat-6.07.01/sharedpos/nreadable.f0000664000175000017500000000013614673353434016175 0ustar frankfrankinline std::streamsize SharedPos::nReadable() const { return d_sharedData->nReadable(); } bobcat-6.07.01/sharedpos/operatorinsert.f0000664000175000017500000000016514673353434017342 0ustar frankfrankinline std::ostream &operator<<(std::ostream &out, SharedPos const &sharedPos) { return sharedPos.insert(out); } bobcat-6.07.01/sharedpos/sharedpos.ih0000664000175000017500000000010214736315237016413 0ustar frankfrank#include "sharedpos" using namespace std; using namespace FBB; bobcat-6.07.01/sharedpos/blockoffset.f0000664000175000017500000000011314673353434016554 0ustar frankfrankinline size_t SharedPos::blockOffset() const { return d_blockOffset; } bobcat-6.07.01/sharedpos/atmaxoffset.f0000664000175000017500000000012314673353434016575 0ustar frankfrankinline bool SharedPos::atMaxOffset() const { return d_offset == d_maxOffset; } bobcat-6.07.01/sharedpos/operatorplusplus.cc0000664000175000017500000000013114673353434020056 0ustar frankfrank#include "sharedpos.ih" void SharedPos::operator++() { ++d_offset; update(); } bobcat-6.07.01/sharedpos/eos.f0000664000175000017500000000017314673353434015047 0ustar frankfrankinline std::streamsize SharedPos::eos() const { return static_cast(blockIdx() + 1) * segmentSize(); } bobcat-6.07.01/sharedpos/maxoffset.f0000664000175000017500000000012014673353434016245 0ustar frankfrankinline std::streamsize SharedPos::maxOffset() const { return d_maxOffset; } bobcat-6.07.01/sharedpos/sharedpos0000664000175000017500000000413614673353434016030 0ustar frankfrank#ifndef INCLUDED_BOBCAT_SHAREDPOS_ #define INCLUDED_BOBCAT_SHAREDPOS_ #include #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-6.07.01/sharedsegment/0000775000175000017500000000000014736742656014762 5ustar frankfrankbobcat-6.07.01/sharedsegment/updatenreadable.cc0000664000175000017500000000033014673353434020375 0ustar frankfrank#include "sharedsegment.ih" void SharedSegment::updateNreadable(streamsize offset) { d_nReadableMutex.lock(); if (offset > d_nReadable) d_nReadable = offset; d_nReadableMutex.unlock(); } bobcat-6.07.01/sharedsegment/sharedsegment.ih0000664000175000017500000000022014736315237020116 0ustar frankfrank#include "sharedsegment" #include #include #include "../ranger/ranger" using namespace std; using namespace FBB; bobcat-6.07.01/sharedsegment/nblocks.f0000664000175000017500000000010714673353434016552 0ustar frankfrankinline size_t SharedSegment::nBlocks() const { return d_nBlocks; } bobcat-6.07.01/sharedsegment/rawdetach.cc0000664000175000017500000000036514673353434017227 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-6.07.01/sharedsegment/operatorindex.f0000664000175000017500000000012714673353434020004 0ustar frankfrankinline SharedBlock &SharedSegment::operator[](size_t idx) { return d_block[idx]; } bobcat-6.07.01/sharedsegment/deletesegment.cc0000664000175000017500000000032614673353434020107 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-6.07.01/sharedsegment/insert.cc0000664000175000017500000000162214673353434016566 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-6.07.01/sharedsegment/size.cc0000664000175000017500000000044414673353434016235 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-6.07.01/sharedsegment/newsegment.cc0000664000175000017500000000105414673353434017435 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-6.07.01/sharedsegment/segmentsize.f0000664000175000017500000000011714673353434017455 0ustar frankfrankinline size_t SharedSegment::segmentSize() const { return d_segmentSize; } bobcat-6.07.01/sharedsegment/nreadableunlock.f0000664000175000017500000000012014673353434020243 0ustar frankfrankinline void SharedSegment::nReadableUnlock() { d_nReadableMutex.unlock(); } bobcat-6.07.01/sharedsegment/lock.f0000664000175000017500000000011114673353434016042 0ustar frankfrankinline void SharedSegment::lock(size_t idx) { d_block[idx].lock(); } bobcat-6.07.01/sharedsegment/unlock.f0000664000175000017500000000011514673353434016411 0ustar frankfrankinline void SharedSegment::unlock(size_t idx) { d_block[idx].unlock(); } bobcat-6.07.01/sharedsegment/nreadablelock.f0000664000175000017500000000011414673353434017703 0ustar frankfrankinline void SharedSegment::nReadableLock() { d_nReadableMutex.lock(); } bobcat-6.07.01/sharedsegment/truncate.cc0000664000175000017500000000041414673353434017105 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-6.07.01/sharedsegment/clear.cc0000664000175000017500000000043714673353434016353 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-6.07.01/sharedsegment/icmconf0000664000175000017500000000010314673353434016305 0ustar frankfrank#define LIBRARY "sharedsegment" #include "../icmconf" bobcat-6.07.01/sharedsegment/detach.f0000664000175000017500000000021514673353434016347 0ustar frankfranktemplate Type *SharedSegment::detach(Type *sharedPtr, bool requireOK) { rawDetach(sharedPtr, requireOK); return 0; } bobcat-6.07.01/sharedsegment/nreadable.f0000664000175000017500000000012414673353434017033 0ustar frankfrankinline std::streamsize SharedSegment::nReadable() const { return d_nReadable; } bobcat-6.07.01/sharedsegment/operatorinsert.f0000664000175000017500000000023314673353434020177 0ustar frankfrankinline std::ostream &operator<<(std::ostream &out, SharedSegment const &sharedData) { return sharedData.insert(out); } bobcat-6.07.01/sharedsegment/sharedsegment0000664000175000017500000000632414673353434017533 0ustar frankfrank#ifndef INCLUDED_BOBCAT_SHAREDSEGMENT_ #define INCLUDED_BOBCAT_SHAREDSEGMENT_ #include #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-6.07.01/sharedsegment/create.cc0000664000175000017500000000063614673353434016531 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-6.07.01/sharedsegment/sharedsegment1.cc0000664000175000017500000000102214673353434020166 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-6.07.01/sharedsegment/access.f0000664000175000017500000000010514673353434016356 0ustar frankfrankinline size_t SharedSegment::access() const { return d_access; } bobcat-6.07.01/sharedsegment/attach.cc0000664000175000017500000000036014673353434016524 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-6.07.01/sharedsegment/newdata.cc0000664000175000017500000000024714673353434016707 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-6.07.01/sharedsegment/driver/0000775000175000017500000000000014737552575016255 5ustar frankfrankbobcat-6.07.01/sharedsegment/driver/build0000775000175000017500000000011214673353434017264 0ustar frankfrank#!/bin/bash g++ `cat ../../c++std` -pthread -o driver driver.cc -lbobcat bobcat-6.07.01/sharedsegment/driver/driver.cc0000664000175000017500000001202214673353434020044 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-6.07.01/sharedstream/0000775000175000017500000000000014736742656014613 5ustar frankfrankbobcat-6.07.01/sharedstream/sharedstream.ih0000664000175000017500000000010514736315237017602 0ustar frankfrank#include "sharedstream" using namespace std; using namespace FBB; bobcat-6.07.01/sharedstream/clear.f0000664000175000017500000000013414673353434016036 0ustar frankfrankinline void SharedStream::clear() { std::istream::clear(); std::ostream::clear(); } bobcat-6.07.01/sharedstream/truncate.f0000664000175000017500000000015314673353434016576 0ustar frankfrankinline bool SharedStream::truncate(std::streamsize offset) { return sharedMemory().truncate(offset); } bobcat-6.07.01/sharedstream/sharedstream0000664000175000017500000000252014673353434017207 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-6.07.01/sharedstream/sharedstream1.cc0000664000175000017500000000014314673353434017653 0ustar frankfrank#include "sharedstream.ih" SharedStream::SharedStream() : istream(this), ostream(this) {} bobcat-6.07.01/sharedstream/open2.cc0000664000175000017500000000024614673353434016137 0ustar frankfrank#include "sharedstream.ih" void SharedStream::open(int id, std::ios::openmode openMode) { setMemory(SharedMemory(id)); setOpenMode(openMode); clear(); } bobcat-6.07.01/sharedstream/sharedstream2.cc0000664000175000017500000000043514673353434017660 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-6.07.01/sharedstream/icmconf0000664000175000017500000000010314673353434016136 0ustar frankfrank#define LIBRARY "sharedsegment" #include "../icmconf" bobcat-6.07.01/sharedstream/sharedstream3.cc0000664000175000017500000000025514673353434017661 0ustar frankfrank#include "sharedstream.ih" SharedStream::SharedStream(int id, std::ios::openmode openMode) : SharedBuf(id, openMode), std::istream(this), std::ostream(this) {} bobcat-6.07.01/sharedstream/open1.cc0000664000175000017500000000041014673353434016127 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-6.07.01/sharedstream/meminfo.cc0000664000175000017500000000025514673353434016546 0ustar frankfrank#include "sharedstream.ih" void SharedStream::memInfo(std::ostream &out, char const *end) const { static_cast(this)->memInfo(out); out << end; } bobcat-6.07.01/sharedstream/driver/0000775000175000017500000000000014737552575016106 5ustar frankfrankbobcat-6.07.01/sharedstream/driver/build0000775000175000017500000000026114673353434017122 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-6.07.01/sharedstream/driver/driver.cc0000664000175000017500000002166114673353434017706 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-6.07.01/signal/0000775000175000017500000000000014736742656013406 5ustar frankfrankbobcat-6.07.01/signal/signal0000664000175000017500000000233314673353434014577 0ustar frankfrank#ifndef INCLUDED_BOBCAT_SIGNAL_ #define INCLUDED_BOBCAT_SIGNAL_ #include #include #include #include namespace FBB { class SignalHandler { friend class Signal; public: virtual ~SignalHandler(); private: virtual void signalHandler(size_t signum) = 0; }; class Signal { using SignalHandlerVector = std::vector; 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 std::unique_ptr s_signal; public: Signal(Signal const &) = delete; static Signal &instance(); 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-6.07.01/signal/instance.cc0000664000175000017500000000025514673353434015513 0ustar frankfrank#include "signal.ih" unique_ptr Signal::s_signal; Signal &Signal::instance() { if (s_signal == 0) s_signal.reset(new Signal); return *s_signal; } bobcat-6.07.01/signal/signal.ih0000664000175000017500000000012514736315237015172 0ustar frankfrank#include "signal" #include using namespace std; using namespace FBB; bobcat-6.07.01/signal/reset.cc0000664000175000017500000000023714673353434015031 0ustar frankfrank#include "signal.ih" void Signal::reset(size_t signum) { verify(signum, "Signal::reset"); signal(signum, SIG_DFL); d_signals[signum].clear(); } bobcat-6.07.01/signal/signal.cc0000664000175000017500000000216214673353434015163 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-6.07.01/signal/handler.cc0000664000175000017500000000022014673353434015314 0ustar frankfrank#include "signal.ih" void Signal::handler(int signum) { for (auto &obj: s_signal->d_signals[signum]) obj->signalHandler(signum); } bobcat-6.07.01/signal/icmconf0000664000175000017500000000007414673353434014740 0ustar frankfrank#define LIBRARY "signal" #include "../icmconf" bobcat-6.07.01/signal/destructor.cc0000664000175000017500000000007114673353434016101 0ustar frankfrank#include "signal.ih" SignalHandler::~SignalHandler() {} bobcat-6.07.01/signal/ignore.cc0000664000175000017500000000024114673353434015165 0ustar frankfrank#include "signal.ih" void Signal::ignore(size_t signum) { verify(signum, "Signal::ignore"); signal(signum, SIG_IGN); d_signals[signum].clear(); } bobcat-6.07.01/signal/add.cc0000664000175000017500000000041014673353434014430 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-6.07.01/signal/verify.cc0000664000175000017500000000064614673353434015217 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-6.07.01/signal/signal1.cc0000664000175000017500000000005214673353434015240 0ustar frankfrank#include "signal.ih" Signal::Signal() {} bobcat-6.07.01/signal/remove.cc0000664000175000017500000000121614673353434015202 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-6.07.01/signal/driver/0000775000175000017500000000000014737552575014701 5ustar frankfrankbobcat-6.07.01/signal/driver/build0000775000175000017500000000055614673353434015724 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-6.07.01/signal/driver/driver.cc0000664000175000017500000000226714736771550016505 0ustar frankfrank#include #include #include #include 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-6.07.01/socketbase/0000775000175000017500000000000014736742656014254 5ustar frankfrankbobcat-6.07.01/socketbase/socketbase.ih0000664000175000017500000000013414736315237016706 0ustar frankfrank#include "socketbase" #include using namespace std; using namespace FBB; bobcat-6.07.01/socketbase/makebase.f0000664000175000017500000000017514673353434016166 0ustar frankfrankinline SocketBase SocketBase::makeBase(int socket, sockaddr_in const &address) { return SocketBase{ socket, address }; } bobcat-6.07.01/socketbase/socketbase2.cc0000664000175000017500000000055314673353434016763 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-6.07.01/socketbase/setbooloption.cc0000664000175000017500000000045714673353434017461 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-6.07.01/socketbase/socketbase1.cc0000664000175000017500000000041414673353434016756 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-6.07.01/socketbase/socketbase0000664000175000017500000000270414673353434016315 0ustar frankfrank#ifndef INCLUDED_BOBCAT_SOCKETBASE_ #define INCLUDED_BOBCAT_SOCKETBASE_ #include #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-6.07.01/socketbase/socket.f0000664000175000017500000000007514673353434015705 0ustar frankfrankinline int SocketBase::socket() const { return d_sock; } bobcat-6.07.01/socketbase/debug.f0000664000175000017500000000011314673353434015474 0ustar frankfrankinline bool SocketBase::debug() const { return boolOption(SO_DEBUG); } bobcat-6.07.01/socketbase/setdebug.f0000664000175000017500000000014214673353434016212 0ustar frankfrankinline bool SocketBase::setDebug(bool trueIsOn) { return setBoolOption(SO_DEBUG, trueIsOn); } bobcat-6.07.01/socketbase/booloption.cc0000664000175000017500000000046714673353434016746 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-6.07.01/socketbase/icmconf0000664000175000017500000000010014673353434015574 0ustar frankfrank#define LIBRARY "socketbase" #include "../icmconf" bobcat-6.07.01/socketbase/setreuse.f0000664000175000017500000000014614673353434016253 0ustar frankfrankinline bool SocketBase::setReuse(bool trueIsOn) { return setBoolOption(SO_REUSEADDR, trueIsOn); } bobcat-6.07.01/socketbase/reuse.f0000664000175000017500000000011714673353434015535 0ustar frankfrankinline bool SocketBase::reuse() const { return boolOption(SO_REUSEADDR); } bobcat-6.07.01/socketbase/socketbase1.f0000664000175000017500000000017014673353434016615 0ustar frankfrankinline SocketBase::SocketBase(int socket, sockaddr_in const &address) : InetAddress(address), d_sock(socket) {} bobcat-6.07.01/SSLCLASSES0000664000175000017500000000036414736743116013526 0ustar frankfrank# This file is read from icmake/special bigint diffiehellman digestbuf ecdh hmacbuf isymcryptbase isymcryptstream isymcryptstreambuf ldc osymcryptbase osymcryptstream osymcryptstreambuf pf_iterator pf_iteratorstream primefactors symcryptbase bobcat-6.07.01/stat/0000775000175000017500000000000014736742656013104 5ustar frankfrankbobcat-6.07.01/stat/inode.f0000664000175000017500000000010014673353434014330 0ustar frankfrankinline size_t Stat::inode() const { return d_stat.st_ino; } bobcat-6.07.01/stat/stat3.cc0000664000175000017500000000013414673353434014437 0ustar frankfrank#include "stat.ih" Stat::Stat(string const &name) : d_name(name) { init(::stat); } bobcat-6.07.01/stat/modestr.cc0000664000175000017500000000075714673353434015071 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-6.07.01/stat/name.f0000664000175000017500000000007614673353434014166 0ustar frankfrankinline std::string const &Stat::name() { return d_name; } bobcat-6.07.01/stat/nblocks.f0000664000175000017500000000010514673353434014672 0ustar frankfrankinline size_t Stat::nBlocks() const { return d_stat.st_blocks; } bobcat-6.07.01/stat/stat.ih0000664000175000017500000000033114736315237014365 0ustar frankfrank#include "stat" #include #include #include #include #include "../string/string" #include "../user/user" #include "../fswap/fswap" using namespace std; using namespace FBB; bobcat-6.07.01/stat/lastchange.f0000664000175000017500000000014214673353434015351 0ustar frankfrankinline DateTime Stat::lastChange() const { return DateTime(d_stat.st_ctime, DateTime::UTC); } bobcat-6.07.01/stat/stat1.cc0000664000175000017500000000007114673353434014435 0ustar frankfrank#include "stat.ih" Stat::Stat() : d_errno(false) {} bobcat-6.07.01/stat/istype.f0000664000175000017500000000010514673353434014554 0ustar frankfrankinline bool Stat::isType(Type probe) { return type() == probe; } bobcat-6.07.01/stat/gid.f0000664000175000017500000000007614673353434014011 0ustar frankfrankinline size_t Stat::gid() const { return d_stat.st_gid; } bobcat-6.07.01/stat/error.f0000664000175000017500000000007214673353434014373 0ustar frankfrankinline size_t Stat::error() const { return d_errno; } bobcat-6.07.01/stat/set1.cc0000664000175000017500000000013114673353434014252 0ustar frankfrank#include "stat.ih" bool Stat::set(string const &name) { return set(::stat, name); } bobcat-6.07.01/stat/nlinks.f0000664000175000017500000000010314673353434014533 0ustar frankfrankinline size_t Stat::nLinks() const { return d_stat.st_nlink; } bobcat-6.07.01/stat/mode.f0000664000175000017500000000010614673353434014164 0ustar frankfrankinline size_t Stat::mode() const { return d_stat.st_mode & RWX; } bobcat-6.07.01/stat/device.f0000664000175000017500000000010114673353434014472 0ustar frankfrankinline size_t Stat::device() const { return d_stat.st_dev; } bobcat-6.07.01/stat/stat0000664000175000017500000001120314673353434013767 0ustar frankfrank#ifndef INCLUDED_BOBCAT_STAT_ #define INCLUDED_BOBCAT_STAT_ #include #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: using stat = struct 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-6.07.01/stat/set3.cc0000664000175000017500000000017714673353434014266 0ustar frankfrank#include "stat.ih" bool Stat::set(string const &name, string const &pathList) { return setPath(::stat, name, pathList); } bobcat-6.07.01/stat/stat4.f0000664000175000017500000000013214673353434014276 0ustar frankfrankinline Stat::Stat(Lstat, std::string const &name) : d_name(name) { init(lstat); } bobcat-6.07.01/stat/uid.f0000664000175000017500000000007614673353434014027 0ustar frankfrankinline size_t Stat::uid() const { return d_stat.st_uid; } bobcat-6.07.01/stat/typestr.cc0000664000175000017500000000127014673353434015115 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-6.07.01/stat/init.cc0000664000175000017500000000030514673353434014344 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-6.07.01/stat/setpath.cc0000664000175000017500000000077214673353434015061 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-6.07.01/stat/set2.f0000664000175000017500000000012714673353434014120 0ustar frankfrankinline bool Stat::set(Lstat, std::string const &name) { return set(lstat, name); } bobcat-6.07.01/stat/specialmode.cc0000664000175000017500000000060514673353434015671 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-6.07.01/stat/mode.cc0000664000175000017500000000056014673353434014330 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-6.07.01/stat/lastaccess.f0000664000175000017500000000014214673353434015365 0ustar frankfrankinline DateTime Stat::lastAccess() const { return DateTime(d_stat.st_atime, DateTime::UTC); } bobcat-6.07.01/stat/icmconf0000664000175000017500000000007214673353434014434 0ustar frankfrank#define LIBRARY "stat" #include "../icmconf" bobcat-6.07.01/stat/stat2.cc0000664000175000017500000000020214673353434014432 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-6.07.01/stat/size.f0000664000175000017500000000007714673353434014221 0ustar frankfrankinline off_t Stat::size() const { return d_stat.st_size; } bobcat-6.07.01/stat/access.cc0000664000175000017500000000203214673353434014641 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-6.07.01/stat/set5.cc0000664000175000017500000000023414673353434014262 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-6.07.01/stat/stat6.f0000664000175000017500000000016714673353434014310 0ustar frankfrankinline Stat::Stat(Lstat, std::string const &name, std::string const &pathlist) { setPath(lstat, name, pathlist); } bobcat-6.07.01/stat/operatorassign.cc0000664000175000017500000000015314673353434016442 0ustar frankfrank#include "stat.ih" Stat &Stat::operator=(Stat &&tmp) { fswap(*this, tmp, d_name); return *this; } bobcat-6.07.01/stat/lastmodification.f0000664000175000017500000000015014673353434016570 0ustar frankfrankinline DateTime Stat::lastModification() const { return DateTime(d_stat.st_mtime, DateTime::UTC); } bobcat-6.07.01/stat/set4.f0000664000175000017500000000023014673353434014115 0ustar frankfrankinline bool Stat::set(Lstat, std::string const &name, std::string const &pathList) { return setPath(lstat, name, pathList); } bobcat-6.07.01/stat/opbool.f0000664000175000017500000000010014673353434014524 0ustar frankfrankinline Stat::operator bool() const { return d_errno == 0; } bobcat-6.07.01/stat/stat5.f0000664000175000017500000000016114673353434014301 0ustar frankfrankinline Stat::Stat(std::string const &name, std::string const &pathlist) { setPath(::stat, name, pathlist); } bobcat-6.07.01/stat/devicetype.f0000664000175000017500000000010614673353434015401 0ustar frankfrankinline size_t Stat::deviceType() const { return d_stat.st_rdev; } bobcat-6.07.01/stat/path.cc0000664000175000017500000000061014673353434014334 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-6.07.01/stat/type.f0000664000175000017500000000014014673353434014217 0ustar frankfrankinline Stat::Type Stat::type() const { return static_cast(d_stat.st_mode & S_IFMT); } bobcat-6.07.01/stat/blocksize.f0000664000175000017500000000011014673353434015220 0ustar frankfrankinline size_t Stat::blockSize() const { return d_stat.st_blksize; } bobcat-6.07.01/stat/driver/0000775000175000017500000000000014737552575014377 5ustar frankfrankbobcat-6.07.01/stat/driver/build0000775000175000017500000000054714673353434015422 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-6.07.01/stat/driver/driver.cc0000664000175000017500000000230214736772213016166 0ustar frankfrank#include #include #include #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-6.07.01/stat/driver/driver.ln0000777000175000017500000000000014673353434020012 2driver.ccustar frankfrankbobcat-6.07.01/stat/statstruct.f0000664000175000017500000000011114673353434015454 0ustar frankfrankinline Stat::stat const &Stat::statStruct() const { return d_stat; } bobcat-6.07.01/stdextractor/0000775000175000017500000000000014736742656014657 5ustar frankfrankbobcat-6.07.01/stdextractor/stdextractor2.cc0000664000175000017500000000022014673353434017760 0ustar frankfrank#include "stdextractor.ih" StdExtractor::StdExtractor(StdMode mode, size_t bufSize) : IUO::ExtractorBase(bufSize), d_modeFun(close) {} bobcat-6.07.01/stdextractor/stdextractor0000664000175000017500000000066014673353434017322 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-6.07.01/stdextractor/icmconf0000664000175000017500000000010214673353434016201 0ustar frankfrank#define LIBRARY "stdextractor" #include "../icmconf" bobcat-6.07.01/stdextractor/close.cc0000664000175000017500000000023614673353434016264 0ustar frankfrank#include "stdextractor.ih" void StdExtractor::close() // static { ::close(STDIN_FILENO); // close and reopen stdin ::open("/dev/null", O_RDONLY); } bobcat-6.07.01/stdextractor/childredirections.cc0000664000175000017500000000040714673353434020655 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-6.07.01/stdextractor/stdextractor1.cc0000664000175000017500000000020414673353434017761 0ustar frankfrank#include "stdextractor.ih" StdExtractor::StdExtractor(size_t bufSize) : IUO::ExtractorBase(bufSize), d_modeFun(noClose) {} bobcat-6.07.01/stdextractor/stdextractor.ih0000664000175000017500000000015514736315237017717 0ustar frankfrank#include "stdextractor" #include #include using namespace std; using namespace FBB; bobcat-6.07.01/stdextractor/driver/0000775000175000017500000000000014737552575016152 5ustar frankfrankbobcat-6.07.01/stdextractor/driver/build0000775000175000017500000000017314673353434017170 0ustar frankfrank#!/bin/bash g++ -Wall -odriver driver.cc -L../../extractorbase/tmp -lextractorbase \ -L../tmp -lstdextractor -lbobcat bobcat-6.07.01/stdextractor/driver/driver.cc0000664000175000017500000000071114673353434017743 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-6.07.01/steadyclock/0000775000175000017500000000000014737223252014421 5ustar frankfrankbobcat-6.07.01/steadyclock/steadyclock.ih0000664000175000017500000000003014736315237017245 0ustar frankfrank#include "steadyclock" bobcat-6.07.01/steadyclock/steadyclock.f0000664000175000017500000000115114737223124017071 0ustar frankfrankinline SteadyClock::SteadyClock(TimePoint const &timePoint) : ClockBase(timePoint) {} inline SteadyClock &SteadyClock::operator-=(SteadyClock const &rhs) { return *this = SteadyClock{ timePoint() - rhs.elapsed() }; } inline SteadyClock operator-(SteadyClock const &lhs, SteadyClock const &rhs) { return SteadyClock{ lhs } -= rhs; } inline SteadyClock::Duration since(SteadyClock const &time0) { return ClockTypes::elapsed((SteadyClock{} - time0).timePoint()); } inline size_t countSince(SteadyClock const &time0) { return ClockTypes::count((SteadyClock{} - time0).timePoint()); } bobcat-6.07.01/steadyclock/steadyclock0000664000175000017500000000062014737223252016647 0ustar frankfrank#ifndef INCLUDED_BOBCAT_STEADYCLOCK_ #define INCLUDED_BOBCAT_STEADYCLOCK_ #include namespace FBB { struct SteadyClock: public ClockBase { using ChronoClock = std::chrono::steady_clock; SteadyClock(TimePoint const &timePoint = now()); SteadyClock &operator-=(SteadyClock const &rhs); }; #include "steadyclock.f" } // FBB #endif bobcat-6.07.01/string/0000775000175000017500000000000014736742656013437 5ustar frankfrankbobcat-6.07.01/string/splitpair2.f0000664000175000017500000000017514673353434015672 0ustar frankfrankinline FBB::String::SplitPair::SplitPair(char ch, Type type) : std::pair(std::string(1, ch), type) {} bobcat-6.07.01/string/escape1.cc0000664000175000017500000000107214673353434015257 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-6.07.01/string/string.ih0000664000175000017500000000035314736315237015257 0ustar frankfrank#include "string" #include #include #include #include #include "tolower.f" #include "toupper.f" #include "splitpair1.f" #include "splitpair2.f" using namespace std; using namespace FBB; bobcat-6.07.01/string/join1.cc0000664000175000017500000000046714673353434014765 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-6.07.01/string/sqin.cc0000664000175000017500000000023114673353434014704 0ustar frankfrank#include "string.ih" bool String::sqIn(FSAData &data) { ++data.begin; data.entry.second = SQUOTE; data.state = SQSTRING; return true; } bobcat-6.07.01/string/data.cc0000664000175000017500000000126614673353434014654 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-6.07.01/string/urlencode.cc0000664000175000017500000000134114673353434015715 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-6.07.01/string/argv.cc0000664000175000017500000000040714673353434014676 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-6.07.01/string/tok.cc0000664000175000017500000000056114673353434014535 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-6.07.01/string/split8.cc0000664000175000017500000000037414673353434015165 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-6.07.01/string/string0000664000175000017500000001402714673353434014664 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: using SplitPairVector = std::vector; using ConstIter = std::string::const_iterator; 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-6.07.01/string/split4.cc0000664000175000017500000000036014673353434015154 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-6.07.01/string/split1.cc0000664000175000017500000000035214673353434015152 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-6.07.01/string/unescape2.cc0000664000175000017500000000326514673353434015631 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-6.07.01/string/split2.cc0000664000175000017500000000035514673353434015156 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-6.07.01/string/lc1.cc0000664000175000017500000000022314673353434014412 0ustar frankfrank#include "string.ih" string String::lc(string const &str) { string ret(str); for (auto &ch: ret) tolower(ch); return ret; } bobcat-6.07.01/string/split6.cc0000664000175000017500000000041114673353434015153 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-6.07.01/string/join2.cc0000664000175000017500000000032414673353434014756 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-6.07.01/string/casecmp.f0000664000175000017500000000020014673353434015201 0ustar frankfrankinline int String::casecmp(std::string const &lhs, std::string const &rhs) { return strcasecmp(lhs.c_str(), rhs.c_str()); } bobcat-6.07.01/string/eosdq.cc0000664000175000017500000000024414673353434015051 0ustar frankfrank#include "string.ih" bool String::eosDq(FSAData &data) { data.entry.second = DQUOTE_UNTERMINATED; data.entries->push_back(data.entry); return false; } bobcat-6.07.01/string/split5.cc0000664000175000017500000000104314673353434015154 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-6.07.01/string/unescape1.cc0000664000175000017500000000630114673353434015622 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-6.07.01/string/tolower.f0000664000175000017500000000011214673353434015263 0ustar frankfrankinline void FBB::String::tolower(char &chr) { chr = ::tolower(chr); } bobcat-6.07.01/string/split3.cc0000664000175000017500000000043014673353434015151 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-6.07.01/string/sepin.cc0000664000175000017500000000053214673353434015054 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-6.07.01/string/peek.cc0000664000175000017500000000067514673353434014672 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-6.07.01/string/chin.cc0000664000175000017500000000021514673353434014655 0ustar frankfrank#include "string.ih" bool String::chIn(FSAData &data) { data.entry.first += *data.begin++; // store the character return true; } bobcat-6.07.01/string/icmconf0000664000175000017500000000007414673353434014771 0ustar frankfrank#define LIBRARY "string" #include "../icmconf" bobcat-6.07.01/string/toksep.cc0000664000175000017500000000077014673353434015247 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-6.07.01/string/joinall.cc0000664000175000017500000000044114673353434015365 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-6.07.01/string/uc1.cc0000664000175000017500000000022314673353434014423 0ustar frankfrank#include "string.ih" string String::uc(string const &lhs) { string ret(lhs); for (auto &ch: ret) toupper(ch); return ret; } bobcat-6.07.01/string/split7.cc0000664000175000017500000000032714673353434015162 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-6.07.01/string/process.cc0000664000175000017500000000065614673353434015423 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-6.07.01/string/joinignoreseparator.cc0000664000175000017500000000105114673353434020017 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-6.07.01/string/dqin.cc0000664000175000017500000000023114673353434014665 0ustar frankfrank#include "string.ih" bool String::dqIn(FSAData &data) { ++data.begin; data.entry.second = DQUOTE; data.state = DQSTRING; return true; } bobcat-6.07.01/string/urldecode.cc0000664000175000017500000000062414673353434015706 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-6.07.01/string/eossq.cc0000664000175000017500000000024414673353434015070 0ustar frankfrank#include "string.ih" bool String::eosSq(FSAData &data) { data.entry.second = SQUOTE_UNTERMINATED; data.entries->push_back(data.entry); return false; } bobcat-6.07.01/string/str.cc0000664000175000017500000000053214673353434014546 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-6.07.01/string/escin.cc0000664000175000017500000000075114673353434015042 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-6.07.01/string/qend.cc0000664000175000017500000000032114673353434014661 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-6.07.01/string/trim1.cc0000664000175000017500000000047414673353434014777 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-6.07.01/string/splitpair1.f0000664000175000017500000000013514673353434015665 0ustar frankfrankinline FBB::String::SplitPair::SplitPair() : std::pair("", NORMAL) {} bobcat-6.07.01/string/toupper.f0000664000175000017500000000011214673353434015266 0ustar frankfrankinline void FBB::String::toupper(char &chr) { chr = ::toupper(chr); } bobcat-6.07.01/string/driver/0000775000175000017500000000000014737552575014732 5ustar frankfrankbobcat-6.07.01/string/driver/build0000775000175000017500000000107114673353434015746 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-6.07.01/string/driver/driver.cc0000664000175000017500000000401214673353434016521 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-6.07.01/string/driver/splitdriver.cc0000664000175000017500000000477614673353434017616 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-6.07.01/string/driver/bobcat/0000775000175000017500000000000014673353434016154 5ustar frankfrankbobcat-6.07.01/string/driver/bobcat/splitpair2.f0000777000175000017500000000000014673353434023275 2../../splitpair2.fustar frankfrankbobcat-6.07.01/string/driver/bobcat/split1.f0000777000175000017500000000000014673353434021543 2../../split1.fustar frankfrankbobcat-6.07.01/string/driver/bobcat/split4.f0000777000175000017500000000000014673353434021551 2../../split4.fustar frankfrankbobcat-6.07.01/string/driver/bobcat/string0000777000175000017500000000000014673353434021257 2../../stringustar frankfrankbobcat-6.07.01/string/driver/bobcat/split3.f0000777000175000017500000000000014673353434021547 2../../split3.fustar frankfrankbobcat-6.07.01/string/driver/bobcat/casecmp.f0000777000175000017500000000000014673353434022141 2../../casecmp.fustar frankfrankbobcat-6.07.01/string/driver/bobcat/tolower.f0000777000175000017500000000000014673353434022301 2../../tolower.fustar frankfrankbobcat-6.07.01/string/driver/bobcat/split2.f0000777000175000017500000000000014673353434021545 2../../split2.fustar frankfrankbobcat-6.07.01/string/driver/bobcat/splitpair1.f0000777000175000017500000000000014673353434023273 2../../splitpair1.fustar frankfrankbobcat-6.07.01/string/driver/bobcat/toupper.f0000777000175000017500000000000014673353434022307 2../../toupper.fustar frankfrankbobcat-6.07.01/string/eosin.cc0000664000175000017500000000016714673353434015057 0ustar frankfrank#include "string.ih" bool String::eosIn(FSAData &data) { data.entries->push_back(data.entry); return false; } bobcat-6.07.01/stringline/0000775000175000017500000000000014736520620014270 5ustar frankfrankbobcat-6.07.01/stringline/stringline.ih0000664000175000017500000000010314736315237016770 0ustar frankfrank#include "stringline" using namespace std; using namespace FBB; bobcat-6.07.01/stringline/opextract.f0000664000175000017500000000014414673353434016456 0ustar frankfrankinline std::istream &operator>>(std::istream &in, StringLine &str) { return getline(in, str); } bobcat-6.07.01/stringline/stringline0000664000175000017500000000035614673353434016404 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-6.07.01/symcryptbase/0000775000175000017500000000000014736742656014656 5ustar frankfrankbobcat-6.07.01/symcryptbase/symcryptbase.ih0000664000175000017500000000016214736315237017713 0ustar frankfrank#include "symcryptbase" #include using namespace std; using namespace FBB; using namespace IUO; bobcat-6.07.01/symcryptbase/uoutbuf.f0000664000175000017500000000016014673353434016503 0ustar frankfrankinline unsigned char *SymCryptBase::uOutBuf() { return reinterpret_cast(d_outBuf.get()); } bobcat-6.07.01/symcryptbase/errormsg.cc0000664000175000017500000000051714673353434017020 0ustar frankfrank#include "symcryptbase.ih" // static string SymCryptBase::errorMsg() { char buf[256]; // see 'man err_error_string' auto eCode = ERR_get_error(); ostringstream out; out << "openssl error code: " << eCode << ". openssl error string: " << ERR_error_string(eCode, buf); return out.str(); } bobcat-6.07.01/symcryptbase/cipherof.cc0000664000175000017500000000044414673353434016756 0ustar frankfrank#include "symcryptbase.ih" // static EVP_CIPHER *SymCryptBase::cipherOf(string const &cipherName) { EVP_CIPHER *cipher = EVP_CIPHER_fetch(0, &cipherName.front(), 0); if (cipher == 0) throw Exception{} << "EVP_CIPHER_fetch " << cipherName << " failed"; return cipher; } bobcat-6.07.01/symcryptbase/checkoutbufsize.cc0000664000175000017500000000051114673353434020347 0ustar frankfrank#include "symcryptbase.ih" void SymCryptBase::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-6.07.01/symcryptbase/keylength.f0000664000175000017500000000020514673353434017004 0ustar frankfrankinline size_t SymCryptBase::keyLength(std::string const &cipherName) { return lengthOf(EVP_CIPHER_get_key_length, cipherName); } bobcat-6.07.01/symcryptbase/ctx.f0000664000175000017500000000010114673353434015603 0ustar frankfrankinline EVP_CIPHER_CTX *SymCryptBase::ctx() { return d_ctx; } bobcat-6.07.01/symcryptbase/outbuf.f0000664000175000017500000000010314673353434016313 0ustar frankfrankinline char *SymCryptBase::outBuf() { return d_outBuf.get(); } bobcat-6.07.01/symcryptbase/icmconf0000664000175000017500000000010614673353434016204 0ustar frankfrank#define LIBRARY "symcryptbase" #include "../icmconf.lib" bobcat-6.07.01/symcryptbase/lengthof.cc0000664000175000017500000000063614673353434016770 0ustar frankfrank#include "symcryptbase.ih" // static size_t SymCryptBase::lengthOf(int (*getLength)(EVP_CIPHER const *), string const &cipherName) { auto *cipher = cipherOf(cipherName); size_t length = (*getLength)(cipher); // EVP_CIPHER_get_key_length or // EVP_CIPHER_get_iv_length EVP_CIPHER_free(cipher); return length; } bobcat-6.07.01/symcryptbase/symcryptbase0000664000175000017500000000416214673353434017321 0ustar frankfrank#ifndef INCLUDED_BOBCAT_SYMCRYPTBASE_ #define INCLUDED_BOBCAT_SYMCRYPTBASE_ #include #include #include #include #include namespace FBB { namespace IUO // the facilities defined here are not further documented { // elsewhere. The SymCryptBase class defined below // should only be used by ISymCryptBase and OSymCryptBase. class SymCryptBase { std::string d_cipherName; size_t d_outBufSize = 0; std::unique_ptr d_outBuf; // buffer receiving processed chars: // size determined by checkOutBufSize EVP_CIPHER_CTX *d_ctx; size_t d_blockSize; public: SymCryptBase( std::string const &cipherName, std::string const &key, std::string const &iv, OSSL_PARAM const *params, int (*evpInit)(EVP_CIPHER_CTX *ctx, EVP_CIPHER const *type, unsigned char const *key, unsigned char const *iv, OSSL_PARAM const *params) ); ~SymCryptBase(); static std::string errorMsg(); static size_t ivLength(std::string const &cipherName); static size_t keyLength(std::string const &cipherName); protected: EVP_CIPHER_CTX *ctx(); // .f size_t blockSize() const; // .f void checkOutBufSize(size_t inputSize); static EVP_CIPHER *cipherOf(std::string const &cipherName); void lengthCheck(char const *what, size_t required, size_t actual) const; static size_t lengthOf(int (*getLength)(EVP_CIPHER const *), std::string const &cipherName); char *outBuf(); // .f unsigned char *uOutBuf(); // .f }; #include "blocksize.f" #include "ctx.f" #include "ivlength.f" #include "keylength.f" #include "outbuf.f" #include "uoutbuf.f" } // IUO } // FBB #endif bobcat-6.07.01/symcryptbase/ivlength.f0000664000175000017500000000020314673353434016630 0ustar frankfrankinline size_t SymCryptBase::ivLength(std::string const &cipherName) { return lengthOf(EVP_CIPHER_get_iv_length, cipherName); } bobcat-6.07.01/symcryptbase/destructor.cc0000664000175000017500000000013614673353434017353 0ustar frankfrank#include "symcryptbase.ih" SymCryptBase::~SymCryptBase() { EVP_CIPHER_CTX_free(d_ctx); } bobcat-6.07.01/symcryptbase/lengthcheck.cc0000664000175000017500000000050714673353434017436 0ustar frankfrank#include "symcryptbase.ih" void SymCryptBase::lengthCheck(char const *what, size_t required, size_t actual) const { if (actual < required) throw Exception{} << d_cipherName << " needs " << what << " length " << required << ", got: " << actual; } bobcat-6.07.01/symcryptbase/blocksize.f0000664000175000017500000000011214673353434016774 0ustar frankfrankinline size_t SymCryptBase::blockSize() const { return d_blockSize; } bobcat-6.07.01/symcryptbase/symcryptbase1.cc0000664000175000017500000000212414673353434017762 0ustar frankfrank#include "symcryptbase.ih" SymCryptBase::SymCryptBase( string const &cipherName, string const &key, string const &iv, OSSL_PARAM const *params, int (*evpInit)(EVP_CIPHER_CTX *, EVP_CIPHER const *, unsigned char const *key, unsigned char const *iv, OSSL_PARAM const *param) ) : d_cipherName(cipherName) { EVP_CIPHER *cipher = cipherOf(&cipherName.front()); lengthCheck("key", EVP_CIPHER_get_key_length(cipher), key.length()); lengthCheck("iv", EVP_CIPHER_get_iv_length(cipher), iv.length()); if ((d_ctx = EVP_CIPHER_CTX_new()) == 0) throw Exception{} << "EVP_CIPHER_CTX_new failed"; if (not ((*evpInit)(d_ctx, cipher, reinterpret_cast(key.data()), reinterpret_cast(iv.data()), params))) { EVP_CIPHER_CTX_free(d_ctx); throw Exception{} << "EVP_{En,De}cryptInit_ex2 failed"; } d_blockSize = EVP_CIPHER_CTX_block_size(d_ctx); EVP_CIPHER_free(cipher); } bobcat-6.07.01/syslogbuf/0000775000175000017500000000000014736742656014146 5ustar frankfrankbobcat-6.07.01/syslogbuf/xsputn.cc0000664000175000017500000000024014673353434016002 0ustar frankfrank#include "syslogbuf.ih" // override streamsize SyslogBuf::xsputn(char const *buf, streamsize nChars) { buffer().append(buf, nChars); return nChars; } bobcat-6.07.01/syslogbuf/overflow.cc0000664000175000017500000000022114673353434016303 0ustar frankfrank#include "syslogbuf.ih" int SyslogBuf::overflow(int ch) { if (ch != EOF) buffer() += ch; else sync(); return ch; } bobcat-6.07.01/syslogbuf/reset1.cc0000664000175000017500000000035714673353434015655 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-6.07.01/syslogbuf/reset2.cc0000664000175000017500000000025414673353434015652 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-6.07.01/syslogbuf/defaultpriority.f0000664000175000017500000000012314673353434017527 0ustar frankfrankinline Priority SyslogBuf::defaultPriority() const { return d_orgPriority; } bobcat-6.07.01/syslogbuf/setpriority.cc0000664000175000017500000000023214673353434017037 0ustar frankfrank#include "syslogbuf.ih" Priority SyslogBuf::setPriority(Priority priority) { Priority old = d_priority; d_priority = priority; return old; } bobcat-6.07.01/syslogbuf/priority.f0000664000175000017500000000011114673353434016157 0ustar frankfrankinline Priority SyslogBuf::priority() const { return d_priority; } bobcat-6.07.01/syslogbuf/syslogbuf1.cc0000664000175000017500000000045014673353434016542 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-6.07.01/syslogbuf/icmconf0000664000175000017500000000007714673353434015503 0ustar frankfrank#define LIBRARY "syslogbuf" #include "../icmconf" bobcat-6.07.01/syslogbuf/eoi.f0000664000175000017500000000005514673353434015061 0ustar frankfrankinline void SyslogBuf::eoi() { eoi_(); } bobcat-6.07.01/syslogbuf/setdefaultpriority.cc0000664000175000017500000000024714673353434020412 0ustar frankfrank#include "syslogbuf.ih" Priority SyslogBuf::setDefaultPriority(Priority priority) { Priority old = d_orgPriority; d_orgPriority = priority; return old; } bobcat-6.07.01/syslogbuf/sync.cc0000664000175000017500000000033014673353434015415 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-6.07.01/syslogbuf/destructor.cc0000664000175000017500000000010214673353434016634 0ustar frankfrank#include "syslogbuf.ih" SyslogBuf::~SyslogBuf() { // eoi(); } bobcat-6.07.01/syslogbuf/syslogbuf.ih0000664000175000017500000000010214736315237016465 0ustar frankfrank#include "syslogbuf" using namespace std; using namespace FBB; bobcat-6.07.01/syslogbuf/eoi.cc0000664000175000017500000000016014673353434015216 0ustar frankfrank#include "syslogbuf.ih" void SyslogBuf::eoi_() { sync(); closelog(); // syslog.h } bobcat-6.07.01/syslogbuf/syslogbuf0000664000175000017500000001007214673353434016076 0ustar frankfrank#ifndef INCLUDED_BOBCAT_SYSLOGBUF_ #define INCLUDED_BOBCAT_SYSLOGBUF_ // see below for the options/facility/level overview #include #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-6.07.01/syslogbuf/driver/0000775000175000017500000000000014737552575015441 5ustar frankfrankbobcat-6.07.01/syslogbuf/driver/build0000775000175000017500000000040614673353434016456 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-6.07.01/syslogbuf/driver/driver.cc0000664000175000017500000000046614673353434017241 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-6.07.01/syslogstream/0000775000175000017500000000000014736742656014665 5ustar frankfrankbobcat-6.07.01/syslogstream/alert.f0000664000175000017500000000014414673353434016132 0ustar frankfrankinline std::ostream &SyslogStream::alert(std::ostream &str) { return setPriority(str, ALERT); } bobcat-6.07.01/syslogstream/emerg.f0000664000175000017500000000014414673353434016122 0ustar frankfrankinline std::ostream &SyslogStream::emerg(std::ostream &str) { return setPriority(str, EMERG); } bobcat-6.07.01/syslogstream/setdefaultpriority.f0000664000175000017500000000017414673353434020770 0ustar frankfrankinline Priority SyslogStream::setDefaultPriority(Priority priority) { return SyslogBuf::setDefaultPriority(priority); } bobcat-6.07.01/syslogstream/maskvalue2.f0000664000175000017500000000022414673353434017074 0ustar frankfranktemplate inline int SyslogStream::maskValue(Priority p1, Priorities ...ps) { return ((1 << p1) | maskValue(ps ...)); } bobcat-6.07.01/syslogstream/strerrno.cc0000664000175000017500000000016114673353434017040 0ustar frankfrank#include "syslogstream.ih" ostream &SyslogStream::strerrno(ostream &str) { return str << strerror(errno); } bobcat-6.07.01/syslogstream/syslogstream.ih0000664000175000017500000000025014736315237017727 0ustar frankfrank#include "syslogstream" #include // strerror #include #include "../string/string" using namespace std; using namespace FBB; bobcat-6.07.01/syslogstream/setmask1.f0000664000175000017500000000015614673353434016556 0ustar frankfrankinline int SyslogStream::setMask(Priority p1, PriorityType upTo) { return setMask(maskValue(p1), upTo); } bobcat-6.07.01/syslogstream/stop.cc0000664000175000017500000000106414673353434016152 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-6.07.01/syslogstream/defaultpriority.f0000664000175000017500000000014514673353434020252 0ustar frankfrankinline Priority SyslogStream::defaultPriority() const { return SyslogBuf::defaultPriority(); } bobcat-6.07.01/syslogstream/debug.f0000664000175000017500000000014414673353434016111 0ustar frankfrankinline std::ostream &SyslogStream::debug(std::ostream &str) { return setPriority(str, DEBUG); } bobcat-6.07.01/syslogstream/syslogstream1.cc0000664000175000017500000000035014673353434017777 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-6.07.01/syslogstream/err.f0000664000175000017500000000014014673353434015607 0ustar frankfrankinline std::ostream &SyslogStream::err(std::ostream &str) { return setPriority(str, ERR); } bobcat-6.07.01/syslogstream/warning.f0000664000175000017500000000015014673353434016465 0ustar frankfrankinline std::ostream &SyslogStream::warning(std::ostream &str) { return setPriority(str, WARNING); } bobcat-6.07.01/syslogstream/maskvalue1.f0000664000175000017500000000011014673353434017065 0ustar frankfrankinline int SyslogStream::maskValue(Priority p1) { return 1 << p1; } bobcat-6.07.01/syslogstream/priority.f0000664000175000017500000000012714673353434016705 0ustar frankfrankinline Priority SyslogStream::priority() const { return SyslogBuf::priority(); } bobcat-6.07.01/syslogstream/close.f0000664000175000017500000000006114673353434016126 0ustar frankfrankinline void SyslogStream::close() { eoi(); } bobcat-6.07.01/syslogstream/notice.f0000664000175000017500000000014614673353434016306 0ustar frankfrankinline std::ostream &SyslogStream::notice(std::ostream &str) { return setPriority(str, NOTICE); } bobcat-6.07.01/syslogstream/icmconf0000664000175000017500000000013714673353434016217 0ustar frankfrank#define LIBRARY "syslogstream" #define AUXFLAGS "-I../tmp" #include "../icmconf" bobcat-6.07.01/syslogstream/open.f0000664000175000017500000000027414673353434015770 0ustar frankfrankinline void SyslogStream::open(std::string const &ident, Priority priority, Facility facility, int option) { reset(ident, priority, facility, option); } bobcat-6.07.01/syslogstream/info.f0000664000175000017500000000014214673353434015754 0ustar frankfrankinline std::ostream &SyslogStream::info(std::ostream &str) { return setPriority(str, INFO); } bobcat-6.07.01/syslogstream/setmask4.f0000664000175000017500000000037714673353434016566 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-6.07.01/syslogstream/syslogstream0000664000175000017500000001153714673353434017343 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-6.07.01/syslogstream/setpriority2.cc0000664000175000017500000000033314673353434017642 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-6.07.01/syslogstream/crit.f0000664000175000017500000000014214673353434015762 0ustar frankfrankinline std::ostream &SyslogStream::crit(std::ostream &str) { return setPriority(str, CRIT); } bobcat-6.07.01/syslogstream/setmask3.f0000664000175000017500000000023114673353434016552 0ustar frankfranktemplate inline int SyslogStream::setMask(Priority p1, Priorities ...ps) { return setMask(maskValue(p1, ps ...), SINGLE); } bobcat-6.07.01/syslogstream/stof.cc0000664000175000017500000000165014673353434016141 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-6.07.01/syslogstream/setmask2.f0000664000175000017500000000013514673353434016554 0ustar frankfrankinline int SyslogStream::setMask(Priority p1) { return setMask(maskValue(p1), SINGLE); } bobcat-6.07.01/syslogstream/setpriority.f0000664000175000017500000000015614673353434017423 0ustar frankfrankinline Priority SyslogStream::setPriority(Priority priority) { return SyslogBuf::setPriority(priority); } bobcat-6.07.01/syslogstream/driver/0000775000175000017500000000000014737552575016160 5ustar frankfrankbobcat-6.07.01/syslogstream/driver/build0000775000175000017500000000045414673353434017200 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-6.07.01/syslogstream/driver/driver.cc0000664000175000017500000000055714673353434017761 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-6.07.01/systemclock/0000775000175000017500000000000014737164502014456 5ustar frankfrankbobcat-6.07.01/systemclock/systemclock.ih0000664000175000017500000000003014736315237017333 0ustar frankfrank#include "systemclock" bobcat-6.07.01/systemclock/systemclock0000664000175000017500000000146414737157322016750 0ustar frankfrank#ifndef INCLUDED_BOBCAT_SYSTEMCLOCK_ #define INCLUDED_BOBCAT_SYSTEMCLOCK_ #include namespace FBB { struct SystemClock: public HighSysClock { using ChronoClock = std::chrono::system_clock; SystemClock(TimePoint const &timePoint = now()); // constructor accepting template // ClockBase: any clock SystemClock(ClockBase const &clock); // derived fm ClockBase }; inline SystemClock::SystemClock(TimePoint const &timePoint) : HighSysClock(timePoint) {} template inline SystemClock::SystemClock(ClockBase const &clock) : HighSysClock(toClock(clock)) {} } // FBB #endif bobcat-6.07.01/systemclock/driver/0000775000175000017500000000000014737304036015747 5ustar frankfrankbobcat-6.07.01/systemclock/driver/build0000775000175000017500000000011714737160526016777 0ustar frankfrank#!/bin/bash g++ --std=c++26 -Wall -fdiagnostics-color=never main.cc -lbobcat; bobcat-6.07.01/systemclock/driver/main.cc0000644000175000017500000000303314737303751017202 0ustar frankfrank#include #include #include #include #include #include #include using namespace std; using namespace FBB; int main() { SystemClock sysNow{ }; cout << "system clock at " << sysNow << "\n" "elapsed: " << sysNow.elapsed() << "\n\n"; // same timespec, elapsed ns. FileClock fileNow{ sysNow }; // is clock-specific cout << "file clock at " << fileNow << "\n" "elapsed: " << fileNow.elapsed() << "\n\n"; SystemClock sysNow2{ fileNow }; cout << "system clock at " << sysNow2 << "\n" "elapsed: " << sysNow2.elapsed() << "\n\n"; cout << sysNow2("%Y %b %d, %H:%M:%S") << "\n" "\n" "minimum time: " << sysNow2.min() << "\n" "maximum time: " << SystemClock::max() << "\n\n"; // conversion to less precise time specification: cout << "100 minutes is " << toDouble(100min) << " hours\n\n"; HighResolutionClock hrc{ fileNow }; cout << "high resolution clock at " << hrc << "\n\n"; SteadyClock sc0; // computing 'since' itself takes several auto passed = since(sc0); // (variable) hundred nano seconds cout << "sc0 since: " << passed << '\n'; SteadyClock sc; this_thread::sleep_for(1s); cout << "ELAPSED: " << since(sc) << '\n' << "(small delay...)\n" "as count: " << countSince(sc) << "\n\n"; } bobcat-6.07.01/table/0000775000175000017500000000000014736742656013220 5ustar frankfrankbobcat-6.07.01/table/opinsert3.f0000664000175000017500000000032614673353434015306 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-6.07.01/table/clearstr.f0000664000175000017500000000010314673353434015170 0ustar frankfrankinline void Table::clearStr() { std::ostringstream::clear(); } bobcat-6.07.01/table/fill.f0000664000175000017500000000032014673353434014300 0ustar frankfranktemplate void Table::fill(Iter it, Iter end) { TableBase::clear(); while (it != end) { std::ostringstream str; str << *it++; push_back(str.str()); } } bobcat-6.07.01/table/append.cc0000664000175000017500000000044314673353434014767 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-6.07.01/table/table.ih0000664000175000017500000000015614736315237014622 0ustar frankfrank#include "table" #include #include "../string/string" using namespace std; using namespace FBB; bobcat-6.07.01/table/setalign.f0000664000175000017500000000015014673353434015161 0ustar frankfrankinline Table &Table::setAlign(Align const &align) { TableBase::setAlign(align); return *this; } bobcat-6.07.01/table/opinsert2.f0000664000175000017500000000013514673353434015303 0ustar frankfrankinline Table &operator<<(Table &table, Table &(*fun)(Table &)) { return (*fun)(table); } bobcat-6.07.01/table/table1.cc0000664000175000017500000000031214673353434014663 0ustar frankfrank#include "table.ih" Table::Table(TableSupport &tableSupport, size_t nColumns, FillDirection direction, WidthType widthType) : TableBase(tableSupport, nColumns, direction, widthType) {} bobcat-6.07.01/table/icmconf0000664000175000017500000000007314673353434014551 0ustar frankfrank#define LIBRARY "table" #include "../icmconf" bobcat-6.07.01/table/def2.f0000664000175000017500000000007414673353434014200 0ustar frankfrankinline Table &def(Table &table) { return table.def(); } bobcat-6.07.01/table/pushback.f0000664000175000017500000000016314673353434015157 0ustar frankfrankinline void Table::push_back(Element const &element) { d_tabulated = false; d_string.push_back(element); } bobcat-6.07.01/table/flush.cc0000664000175000017500000000014414673353434014637 0ustar frankfrank#include "table.ih" Table &Table::flush() { push_back(str()); str(""); return *this; } bobcat-6.07.01/table/table0.cc0000664000175000017500000000022414673353434014664 0ustar frankfrank#include "table.ih" Table::Table(size_t nColumns, FillDirection direction, WidthType widthType) : TableBase(nColumns, direction, widthType) {} bobcat-6.07.01/table/def1.f0000664000175000017500000000010714673353434014174 0ustar frankfrankinline Table &Table::def() { TableBase::def(); return *this; } bobcat-6.07.01/table/opinsert1.f0000664000175000017500000000013514673353434015302 0ustar frankfrankinline Table &operator<<(Table &tab, Align const &align) { return tab.setAlign(align); } bobcat-6.07.01/table/table0000664000175000017500000000462414673353434014230 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: // required for push_back() using value_type = std::string; using const_reference = Element const &; 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-6.07.01/table/driver/0000775000175000017500000000000014737552575014513 5ustar frankfrankbobcat-6.07.01/table/driver/build0000775000175000017500000000011014673353434015520 0ustar frankfrank#!/bin/bash g++ -O2 `cat ../../c++std` -o driver driver.cc -lbobcat -s bobcat-6.07.01/table/driver/driver.cc0000664000175000017500000000163014673353434016305 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-6.07.01/tablebase/0000775000175000017500000000000014736742656014053 5ustar frankfrankbobcat-6.07.01/tablebase/vindex.f0000664000175000017500000000017514673353434015512 0ustar frankfrankinline FBB::TableBase::Element &FBB::TableBase::vIndex(size_t row, size_t col) { return d_string[col * d_nRows + row]; } bobcat-6.07.01/tablebase/nrows.f0000664000175000017500000000010414673353434015355 0ustar frankfrankinline size_t FBB::TableBase::nRows() const { return d_nRows; } bobcat-6.07.01/tablebase/tablebase1.cc0000664000175000017500000000066614673353434016365 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-6.07.01/tablebase/insert.cc0000664000175000017500000000245014673353434015657 0ustar frankfrank#include "tablebase.ih" std::ios_base &(*ctr)(std::ios_base &stream) = FBB::center; 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) if (manip != ctr) 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-6.07.01/tablebase/clear.f0000664000175000017500000000012714673353434015300 0ustar frankfrankinline void FBB::TableBase::clear() { d_tabulated = false; d_string.clear(); } bobcat-6.07.01/tablebase/columnwidth.f0000664000175000017500000000013114673353434016542 0ustar frankfrankinline size_t FBB::TableBase::columnWidth(size_t col) const { return d_align[col]; } bobcat-6.07.01/tablebase/elementat.f0000664000175000017500000000020014673353434016160 0ustar frankfrankinline FBB::TableBase::Element &FBB::TableBase::elementAt(size_t row, size_t col) { return (this->*d_indexFun)(row, col); } bobcat-6.07.01/tablebase/element1.f0000664000175000017500000000026114673353434015723 0ustar frankfrankinline FBB::TableBase::Element::Element(std::string text, std::ios_base &(*manip)(std::ios_base &)) : d_text(text), d_manip(manip) {} bobcat-6.07.01/tablebase/hindex.f0000664000175000017500000000020014673353434015461 0ustar frankfrankinline FBB::TableBase::Element &FBB::TableBase::hIndex(size_t row, size_t col) { return d_string[row * d_nColumns + col]; } bobcat-6.07.01/tablebase/icmconf0000664000175000017500000000007714673353434015410 0ustar frankfrank#define LIBRARY "tablebase" #include "../icmconf" bobcat-6.07.01/tablebase/def.cc0000664000175000017500000000231014673353434015104 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-6.07.01/tablebase/setalign.cc0000664000175000017500000000040014673353434016152 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-6.07.01/tablebase/tablebase0.cc0000664000175000017500000000072114673353434016354 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-6.07.01/tablebase/destructor.cc0000664000175000017500000000010714673353434016546 0ustar frankfrank#include "tablebase.ih" TableBase::~TableBase() { delete d_ptr; } bobcat-6.07.01/tablebase/tablebase.ih0000664000175000017500000000015614736315237016310 0ustar frankfrank#include "tablebase" #include #include "elementat.f" using namespace std; using namespace FBB; bobcat-6.07.01/tablebase/opinsert1.f0000664000175000017500000000015414673353434016136 0ustar frankfrankinline std::ostream &operator<<(std::ostream &str, FBB::TableBase &table) { return table.insert(str); } bobcat-6.07.01/tablebase/tablebase0000664000175000017500000000577614673353434015727 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-6.07.01/tablebase/columnmanip.f0000664000175000017500000000023214673353434016531 0ustar frankfrankinline Manipulator FBB::TableBase::columnManip(size_t col) const { Manipulator manip = d_align[col].manip(); return manip ? manip : std::right; } bobcat-6.07.01/tablebase/length.f0000664000175000017500000000012614673353434015472 0ustar frankfrankinline size_t FBB::TableBase::Element::length() const { return d_text.length(); } bobcat-6.07.01/tablebuf/0000775000175000017500000000000014736742656013715 5ustar frankfrankbobcat-6.07.01/tablebuf/fs.cc0000664000175000017500000000027214673353434014625 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-6.07.01/tablebuf/overflow.cc0000664000175000017500000000047214673353434016062 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-6.07.01/tablebuf/setrowseparator2.f0000664000175000017500000000010214673353434017373 0ustar frankfrankinline void TableBuf::setRowSeparator(char rs) { d_rs = rs; } bobcat-6.07.01/tablebuf/setrowseparator1.f0000664000175000017500000000007314673353434017401 0ustar frankfrankinline void TableBuf::setRowSeparator() { d_rs = -1; } bobcat-6.07.01/tablebuf/setfieldseparator2.f0000664000175000017500000000010414673353434017651 0ustar frankfrankinline void TableBuf::setFieldSeparator(char fs) { d_fs = fs; } bobcat-6.07.01/tablebuf/setfieldseparator1.f0000664000175000017500000000007514673353434017657 0ustar frankfrankinline void TableBuf::setFieldSeparator() { d_fs = -1; } bobcat-6.07.01/tablebuf/setalign.f0000664000175000017500000000015614673353434015664 0ustar frankfrankinline TableBuf &TableBuf::setAlign(Align const &align) { TableBase::setAlign(align); return *this; } bobcat-6.07.01/tablebuf/endrow.cc0000664000175000017500000000034414673353434015513 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-6.07.01/tablebuf/opinsert2.f0000664000175000017500000000014314673353434015777 0ustar frankfrankinline TableBuf &operator<<(TableBuf &tab, Align const &align) { return tab.setAlign(align); } bobcat-6.07.01/tablebuf/tablebuf0000664000175000017500000000355714673353434015426 0ustar frankfrank#ifndef INCLUDED_BOBCAT_TABLEBUF_ #define INCLUDED_BOBCAT_TABLEBUF_ #include #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-6.07.01/tablebuf/tablebuf.ih0000664000175000017500000000010114736315237016002 0ustar frankfrank#include "tablebuf" using namespace std; using namespace FBB; bobcat-6.07.01/tablebuf/nextfield.cc0000664000175000017500000000023314673353434016174 0ustar frankfrank#include "tablebuf.ih" void TableBuf::nextField() { d_tabulated = false; d_string.push_back(d_str); d_str.erase(); d_buffered = false; } bobcat-6.07.01/tablebuf/tablebuf1.cc0000664000175000017500000000044714673353434016066 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-6.07.01/tablebuf/icmconf0000664000175000017500000000007614673353434015251 0ustar frankfrank#define LIBRARY "tablebuf" #include "../icmconf" bobcat-6.07.01/tablebuf/def2.f0000664000175000017500000000010214673353434014665 0ustar frankfrankinline TableBuf &def(TableBuf &table) { return table.def(); } bobcat-6.07.01/tablebuf/operatorinsert.cc0000664000175000017500000000034414673353434017275 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-6.07.01/tablebuf/sync.cc0000664000175000017500000000015114673353434015165 0ustar frankfrank#include "tablebuf.ih" int TableBuf::sync() { if (d_buffered) nextField(); return 0; } bobcat-6.07.01/tablebuf/def1.f0000664000175000017500000000011514673353434014670 0ustar frankfrankinline TableBuf &TableBuf::def() { TableBase::def(); return *this; } bobcat-6.07.01/tablebuf/rs.cc0000664000175000017500000000027214673353434014641 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-6.07.01/tablebuf/tablebuf0.cc0000664000175000017500000000045114673353434016060 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-6.07.01/tablebuf/driver/0000775000175000017500000000000014737552575015210 5ustar frankfrankbobcat-6.07.01/tablebuf/driver/build0000775000175000017500000000026414673353434016227 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-6.07.01/tablebuf/driver/driver.cc0000664000175000017500000000117014673353434017001 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-6.07.01/tablelines/0000775000175000017500000000000014736742656014253 5ustar frankfrankbobcat-6.07.01/tablelines/outline.cc0000664000175000017500000000127214673353434016233 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-6.07.01/tablelines/tablelines1.f0000664000175000017500000000012614673353434016614 0ustar frankfrankinline TableLines::TableLines(TableLines &&tmp) : TableSupport(std::move(tmp)) {} bobcat-6.07.01/tablelines/vhline.cc0000664000175000017500000000066514673353434016046 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-6.07.01/tablelines/tablelines.ih0000664000175000017500000000020714736315237016705 0ustar frankfrank#include "tablelines" #include #include #include "../ranger/ranger" using namespace std; using namespace FBB; bobcat-6.07.01/tablelines/icmconf0000664000175000017500000000010014673353434015573 0ustar frankfrank#define LIBRARY "tablelines" #include "../icmconf" bobcat-6.07.01/tablelines/opassign.f0000664000175000017500000000015514673353434016236 0ustar frankfrankinline TableLines &TableLines::operator=(TableLines &&tmp) { *this = std::move(tmp); return *this; } bobcat-6.07.01/tablelines/tablelines0000664000175000017500000000103614673353434016310 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-6.07.01/tablesupport/0000775000175000017500000000000014736742656014655 5ustar frankfrankbobcat-6.07.01/tablesupport/nrows.f0000664000175000017500000000010714673353434016162 0ustar frankfrankinline size_t FBB::TableSupport::nRows() const { return d_nRows; } bobcat-6.07.01/tablesupport/hline2.f0000664000175000017500000000011514673353434016172 0ustar frankfrankinline void FBB::TableSupport::hline(size_t row) const { v_hline(row); } bobcat-6.07.01/tablesupport/sep.f0000664000175000017500000000013414673353434015601 0ustar frankfrankinline std::vector const &FBB::TableSupport::sep() const { return d_sep; } bobcat-6.07.01/tablesupport/hline1.f0000664000175000017500000000010014673353434016163 0ustar frankfrankinline void FBB::TableSupport::hline() const { v_hline(); } bobcat-6.07.01/tablesupport/ncolumns.f0000664000175000017500000000011514673353434016647 0ustar frankfrankinline size_t FBB::TableSupport::nColumns() const { return d_nColumns; } bobcat-6.07.01/tablesupport/sepwidth.f0000664000175000017500000000017114673353434016642 0ustar frankfrankinline size_t FBB::TableSupport::sepWidth(size_t col) const { return col < d_sep.size() ? d_sep[col].length() : 0; } bobcat-6.07.01/tablesupport/operatorinsizet.cc0000664000175000017500000000033014673353434020411 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-6.07.01/tablesupport/data.cc0000664000175000017500000000012214673353434016060 0ustar frankfrank#include "tablesupport.ih" vector TableSupport::const_iterator::s_empty; bobcat-6.07.01/tablesupport/hline0.cc0000664000175000017500000000052114673353434016331 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-6.07.01/tablesupport/hline1.cc0000664000175000017500000000024714673353434016337 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-6.07.01/tablesupport/vline2.f0000664000175000017500000000011514673353434016210 0ustar frankfrankinline void FBB::TableSupport::vline(size_t col) const { v_vline(col); } bobcat-6.07.01/tablesupport/colwidth.f0000664000175000017500000000017614673353434016635 0ustar frankfrankinline size_t FBB::TableSupport::colWidth(size_t col) const { return col < d_align->size() ? (*d_align)[col].col() : 0; } bobcat-6.07.01/tablesupport/operatorinhline.cc0000664000175000017500000000146114673353434020360 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-6.07.01/tablesupport/element.f0000664000175000017500000000012714673353434016445 0ustar frankfrankinline size_t FBB::TableSupport::element(size_t column) { return column * 2 + 1; } bobcat-6.07.01/tablesupport/tablesupport.ih0000664000175000017500000000036014736315237017711 0ustar frankfrank#include "tablesupport" #include #include "../fswap/fswap" #include "leftseparator.f" #include "rightseparator.f" #include "element.f" #include "lefttype.f" #include "righttype.f" using namespace std; using namespace FBB; bobcat-6.07.01/tablesupport/operatorinstring.cc0000664000175000017500000000031614673353434020565 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-6.07.01/tablesupport/out.f0000664000175000017500000000012114673353434015615 0ustar frankfrankinline std::ostream &FBB::TableSupport::out() const { return *d_streamPtr; } bobcat-6.07.01/tablesupport/tablesupport2.cc0000664000175000017500000000043214673353434017761 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-6.07.01/tablesupport/vhline.cc0000664000175000017500000000011414673353434016435 0ustar frankfrank#include "tablesupport.ih" void TableSupport::v_hline(size_t row) const {} bobcat-6.07.01/tablesupport/constiterator1.cc0000664000175000017500000000070514673353434020137 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-6.07.01/tablesupport/align.f0000664000175000017500000000013314673353434016103 0ustar frankfrankinline std::vector const &FBB::TableSupport::align() const { return *d_align; } bobcat-6.07.01/tablesupport/vline1.f0000664000175000017500000000010014673353434016201 0ustar frankfrankinline void FBB::TableSupport::vline() const { v_vline(); } bobcat-6.07.01/tablesupport/begin.f0000664000175000017500000000022214673353434016074 0ustar frankfrankinline FBB::TableSupport::const_iterator FBB::TableSupport::begin(size_t row) const { const_iterator ret(*this, row, true); return ret; } bobcat-6.07.01/tablesupport/opstar.f0000664000175000017500000000022614673353434016324 0ustar frankfrankinline FBB::TableSupport::Field const &FBB::TableSupport::const_iterator::operator*() const { return *operator->(); } bobcat-6.07.01/tablesupport/opinc.f0000664000175000017500000000017614673353434016130 0ustar frankfrankinline FBB::TableSupport::const_iterator &FBB::TableSupport::const_iterator::operator++() { ++d_iter; return *this; } bobcat-6.07.01/tablesupport/opbitor.f0000664000175000017500000000043614673353434016475 0ustar frankfrankinline FBB::TableSupport::ColumnType operator|(FBB::TableSupport::ColumnType lhs, FBB::TableSupport::ColumnType rhs) { return static_cast( static_cast(lhs) | static_cast(rhs)); } bobcat-6.07.01/tablesupport/end.f0000664000175000017500000000022114673353434015555 0ustar frankfrankinline FBB::TableSupport::const_iterator FBB::TableSupport::end(size_t row) const { const_iterator ret(*this, row, false); return ret; } bobcat-6.07.01/tablesupport/rightseparator.f0000664000175000017500000000013614673353434020052 0ustar frankfrankinline size_t FBB::TableSupport::rightSeparator(size_t column) { return column * 2 + 2; } bobcat-6.07.01/tablesupport/icmconf0000664000175000017500000000010214673353434016177 0ustar frankfrank#define LIBRARY "tablesupport" #include "../icmconf" bobcat-6.07.01/tablesupport/width.f0000664000175000017500000000011414673353434016127 0ustar frankfrankinline size_t FBB::TableSupport::width() const { return d_tableWidth; } bobcat-6.07.01/tablesupport/tablesupport1.cc0000664000175000017500000000023114673353434017755 0ustar frankfrank#include "tablesupport.ih" TableSupport::TableSupport() : d_streamPtr(0), d_nRows(0), d_nColumns(0), d_align(0), d_tableWidth(0) {} bobcat-6.07.01/tablesupport/righttype.f0000664000175000017500000000032414673353434017032 0ustar frankfrankinline void FBB::TableSupport::rightType(size_t *target, size_t type) { *target = *target != SKIP || (type & (USE | RIGHT_FULL)) ? USE : RIGHT_MID; } bobcat-6.07.01/tablesupport/leftseparator.f0000664000175000017500000000013114673353434017662 0ustar frankfrankinline size_t FBB::TableSupport::leftSeparator(size_t column) { return column * 2; } bobcat-6.07.01/tablesupport/vhline2.cc0000664000175000017500000000012714673353434016523 0ustar frankfrank#include "tablesupport.ih" void TableSupport::v_hline() const { hline(d_nRows); } bobcat-6.07.01/tablesupport/destructor.cc0000664000175000017500000000007514673353434017354 0ustar frankfrank#include "tablesupport.ih" TableSupport::~TableSupport() {} bobcat-6.07.01/tablesupport/operatorassign.cc0000664000175000017500000000021714673353434020214 0ustar frankfrank#include "tablesupport.ih" TableSupport &TableSupport::operator=(TableSupport &&tmp) { fswap(*this, tmp, d_elements); return *this; } bobcat-6.07.01/tablesupport/width.cc0000664000175000017500000000023714673353434016275 0ustar frankfrank#include "tablesupport.ih" #include size_t TableSupport::width(size_t idx) const { return idx & 1 ? colWidth(idx >> 1) : sepWidth(idx >> 1); } bobcat-6.07.01/tablesupport/vvline1.cc0000664000175000017500000000015514673353434016541 0ustar frankfrank#include "tablesupport.ih" void TableSupport::v_vline() const { vline(d_nColumns); out() << '\n'; } bobcat-6.07.01/tablesupport/vvline0.cc0000664000175000017500000000020614673353434016535 0ustar frankfrank#include "tablesupport.ih" void TableSupport::v_vline(size_t col) const { if (col < d_sep.size()) out() << d_sep[col]; } bobcat-6.07.01/tablesupport/opneq.f0000664000175000017500000000023214673353434016133 0ustar frankfrankinline bool FBB::TableSupport::const_iterator::operator!=( FBB::TableSupport::const_iterator const &other) const { return not (*this == other); } bobcat-6.07.01/tablesupport/tablesupport0000664000175000017500000001551014673353434017316 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); }; struct const_iterator { using iterator_category = std::input_iterator_tag; using difference_type = std::ptrdiff_t; using value_type = Field; using pointer = value_type *; using reference = value_type &; private: 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 using UMsizeVector = std::unordered_map>; using UMValue = UMsizeVector::value_type; using UMIter = UMsizeVector::const_iterator; 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-6.07.01/tablesupport/opeq.f0000664000175000017500000000024014673353434015754 0ustar frankfrankinline bool FBB::TableSupport::const_iterator::operator==( FBB::TableSupport::const_iterator const &other) const { return d_iter == other.d_iter; } bobcat-6.07.01/tablesupport/setparam.cc0000664000175000017500000000076014673353434016773 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-6.07.01/tablesupport/lefttype.f0000664000175000017500000000032114673353434016644 0ustar frankfrankinline void FBB::TableSupport::leftType(size_t *target, size_t type) { *target = *target != SKIP || (type & (USE | LEFT_FULL)) ? USE : LEFT_MID; } bobcat-6.07.01/tablesupport/operatorarrow.cc0000664000175000017500000000031714673353434020063 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-6.07.01/tempstream/0000775000175000017500000000000014736742656014312 5ustar frankfrankbobcat-6.07.01/tempstream/tempstream1.cc0000664000175000017500000000064014673353434017053 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-6.07.01/tempstream/tempstream0000664000175000017500000000066614673353434016416 0ustar frankfrank#ifndef INCLUDED_TEMPSTREAM_ #define INCLUDED_TEMPSTREAM_ #include #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-6.07.01/tempstream/destructor.cc0000664000175000017500000000013014673353434017001 0ustar frankfrank#include "tempstream.ih" TempStream::~TempStream() { unlink(d_fileName.c_str()); } bobcat-6.07.01/tempstream/filename.f0000664000175000017500000000012214673353434016224 0ustar frankfrankinline std::string const &TempStream::fileName() const { return d_fileName; } bobcat-6.07.01/tempstream/tempstream.ih0000664000175000017500000000017614736315237017010 0ustar frankfrank#include "tempstream" #include #include #include using namespace std; using namespace FBB; bobcat-6.07.01/tempstream/driver/0000775000175000017500000000000014737552575015605 5ustar frankfrankbobcat-6.07.01/tempstream/driver/driver.cc0000664000175000017500000000043214673353434017376 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-6.07.01/TODO0000664000175000017500000000035014673353433012606 0ustar frankfrankFuture release: remove CryptBuf, EncryptBuf, DecryptBuf Provide examples in the following man-pages: milter.yo >>> to be used by other build scripts: >>> hmacbuf/driver/build converts driver.cc to src.cc for local library use bobcat-6.07.01/tty/0000775000175000017500000000000014736742656012751 5ustar frankfrankbobcat-6.07.01/tty/tty.ih0000664000175000017500000000022214736315237014076 0ustar frankfrank#include "tty" #include #include #include #include using namespace std; using namespace FBB; bobcat-6.07.01/tty/tty1.cc0000664000175000017500000000046714673353434014160 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-6.07.01/tty/icmconf0000664000175000017500000000007114673353434014300 0ustar frankfrank#define LIBRARY "tty" #include "../icmconf" bobcat-6.07.01/tty/tty2.cc0000664000175000017500000000011314673353434014145 0ustar frankfrank#include "tty.ih" Tty::Tty(EchoType type) : Tty() { echo(type); } bobcat-6.07.01/tty/echo.cc0000664000175000017500000000051314673353434014165 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-6.07.01/tty/destructor.cc0000664000175000017500000000006414673353434015446 0ustar frankfrank#include "tty.ih" Tty::~Tty() { close(d_fd); } bobcat-6.07.01/tty/tty0000664000175000017500000000114114673353434013501 0ustar frankfrank#ifndef INCLUDED_BOBCAT_TTY_ #define INCLUDED_BOBCAT_TTY_ #include #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-6.07.01/tty/driver/0000775000175000017500000000000014737552575014244 5ustar frankfrankbobcat-6.07.01/tty/driver/build0000775000175000017500000000012014673353434015252 0ustar frankfrank#!/bin/bash g++ `cat ../../c++std` -o driver driver.cc -L../tmp -ltty -lbobcat bobcat-6.07.01/tty/driver/driver.cc0000664000175000017500000000064214673353434016040 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-6.07.01/typetrait/0000775000175000017500000000000014673353434014146 5ustar frankfrankbobcat-6.07.01/typetrait/typetrait0000664000175000017500000000643014673353434016121 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 }; using Plain = U; }; template struct Type { enum { isClass = sizeof(fun(0)) == sizeof(double) }; enum { isPointer = false }; enum { isConst = true }; enum { isRef = false }; enum { isR_Ref = false }; using Plain = U; }; template struct Type { enum { isClass = false }; enum { isPointer = true }; enum { isConst = false }; enum { isRef = false }; enum { isR_Ref = false }; using Plain = U; }; template struct Type { enum { isClass = false }; enum { isPointer = true }; enum { isConst = true }; enum { isRef = false }; enum { isR_Ref = false }; using Plain = U; }; template struct Type { enum { isClass = sizeof(fun(0)) == sizeof(double) }; enum { isPointer = false }; enum { isConst = false }; enum { isRef = true }; enum { isR_Ref = false }; using Plain = U; }; template struct Type { enum { isClass = sizeof(fun(0)) == sizeof(double) }; enum { isPointer = false }; enum { isConst = true }; enum { isRef = true }; enum { isR_Ref = false }; using Plain = U; }; template struct Type { enum { isClass = sizeof(fun(0)) == sizeof(double) }; enum { isPointer = false }; enum { isConst = false }; enum { isRef = false }; enum { isR_Ref = true }; using Plain = U; }; template struct Type { enum { isClass = sizeof(fun(0)) == sizeof(double) }; enum { isPointer = false }; enum { isConst = true }; enum { isRef = false }; enum { isR_Ref = true }; using Plain = U; }; public: enum { isClass = Type::isClass }; enum { isPointer = Type::isPointer }; enum { isConst = Type::isConst }; enum { isRef = Type::isRef }; enum { isR_Ref = Type::isR_Ref }; using Plain = typename Type::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 { using type = typename std::conditional< LpromotesR::yes, LHS, RHS>::type; }; } // FBB #endif bobcat-6.07.01/typetrait/driver/0000775000175000017500000000000014737552575015451 5ustar frankfrankbobcat-6.07.01/typetrait/driver/build0000775000175000017500000000010114673353434016456 0ustar frankfrank#!/bin/bash g++ `cat ../../c++std` -Wall -o driver driver.cc -s bobcat-6.07.01/typetrait/driver/driver.cc0000664000175000017500000000271114673353434017244 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-6.07.01/user/0000775000175000017500000000000014736742656013107 5ustar frankfrankbobcat-6.07.01/user/egroupid.cc0000664000175000017500000000011414673353434015220 0ustar frankfrank#include "user.ih" size_t User::eGroupid() const { return getegid(); } bobcat-6.07.01/user/shell.f0000664000175000017500000000010614673353434014352 0ustar frankfrankinline std::string const &User::shell() const { return d_shell; } bobcat-6.07.01/user/name.f0000664000175000017500000000010414673353434014161 0ustar frankfrankinline std::string const &User::name() const { return d_name; } bobcat-6.07.01/user/realname.f0000664000175000017500000000011414673353434015026 0ustar frankfrankinline std::string const &User::realname() const { return d_realname; } bobcat-6.07.01/user/user0000664000175000017500000000345614673353434014010 0ustar frankfrank#ifndef INCLUDED_BOBCAT_USER #define INCLUDED_BOBCAT_USER #include #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-6.07.01/user/failure.cc0000664000175000017500000000023314673353434015033 0ustar frankfrank#include "user.ih" // static void User::failure() { throw Exception{1} << "Unable to determine actual user information from `/etc/passwd'"; } bobcat-6.07.01/user/userid.f0000664000175000017500000000007114673353434014537 0ustar frankfrankinline size_t User::userid() const { return d_uid; } bobcat-6.07.01/user/homedir.f0000664000175000017500000000011214673353434014667 0ustar frankfrankinline std::string const &User::homedir() const { return d_homedir; } bobcat-6.07.01/user/user4.cc0000664000175000017500000000042414673353434014450 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-6.07.01/user/euserid.cc0000664000175000017500000000011314673353434015041 0ustar frankfrank#include "user.ih" size_t User::eUserid() const { return geteuid(); } bobcat-6.07.01/user/ingroup.cc0000664000175000017500000000062114673353434015070 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-6.07.01/user/password.f0000664000175000017500000000011414673353434015104 0ustar frankfrankinline std::string const &User::password() const { return d_password; } bobcat-6.07.01/user/icmconf0000664000175000017500000000007214673353434014437 0ustar frankfrank#define LIBRARY "user" #include "../icmconf" bobcat-6.07.01/user/user1.cc0000664000175000017500000000007114673353434014443 0ustar frankfrank#include "user.ih" User::User() : User(getuid()) {} bobcat-6.07.01/user/assign.cc0000664000175000017500000000062614673353434014676 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-6.07.01/user/user3.cc0000664000175000017500000000041514673353434014447 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-6.07.01/user/operatorassign.cc0000664000175000017500000000022714673353434016447 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-6.07.01/user/groupid.f0000664000175000017500000000007214673353434014716 0ustar frankfrankinline size_t User::groupid() const { return d_gid; } bobcat-6.07.01/user/user2.cc0000664000175000017500000000036314673353434014450 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-6.07.01/user/user.ih0000664000175000017500000000025314736315237014376 0ustar frankfrank#include "user" #include #include #include #include #include "../fswap/fswap" using namespace FBB; using namespace std; bobcat-6.07.01/user/verify.cc0000664000175000017500000000006114673353434014707 0ustar frankfrank#include "user.ih" void User::verify() const {} bobcat-6.07.01/user/driver/0000775000175000017500000000000014737552575014402 5ustar frankfrankbobcat-6.07.01/user/driver/build0000775000175000017500000000023314673353434015415 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-6.07.01/user/driver/driver.cc0000664000175000017500000000101714673353434016173 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-6.07.01/VERSION0000664000175000017500000000004014746103001013143 0ustar frankfrankVERSION=6.07.01 YEARS=2005-2025 bobcat-6.07.01/x2a/0000775000175000017500000000000014736742656012623 5ustar frankfrankbobcat-6.07.01/x2a/data.cc0000664000175000017500000000006114673353434014030 0ustar frankfrank#include "x2a.ih" bool X2a::s_lastFail = false; bobcat-6.07.01/x2a/x2a1.f0000664000175000017500000000024214673353434013533 0ustar frankfranktemplate // initialize from inline X2a::X2a(T const &x) // (insertable) type { s_lastFail = (*this << x).fail(); } bobcat-6.07.01/x2a/x2a.ih0000664000175000017500000000021214736315237013621 0ustar frankfrank#include "x2a" #include #include #include #include using namespace std; using namespace FBB; bobcat-6.07.01/x2a/opinsert.f0000664000175000017500000000014614673353434014626 0ustar frankfrankinline std::ostream &operator<<(std::ostream &ostr, X2a const &x2a) { return ostr << x2a.str(); } bobcat-6.07.01/x2a/x2a0000664000175000017500000000165414673353434013236 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-6.07.01/x2a/lastfail.f0000664000175000017500000000006714673353434014564 0ustar frankfrankinline bool X2a::lastFail() { return s_lastFail; } bobcat-6.07.01/x2a/icmconf0000664000175000017500000000007114673353434014152 0ustar frankfrank#define LIBRARY "x2a" #include "../icmconf" bobcat-6.07.01/x2a/opassign.f0000664000175000017500000000012514673353434014603 0ustar frankfrankinline X2a &X2a::operator=(X2a const &rhs) { str(rhs.str()); return *this; } bobcat-6.07.01/x2a/opstring.f0000664000175000017500000000010514673353434014623 0ustar frankfrankinline X2a::operator std::string const() const { return str(); } bobcat-6.07.01/x2a/x2a2.f0000664000175000017500000000011314673353434013531 0ustar frankfrankinline X2a::X2a(X2a const &other) : std::ostringstream(other.str()) {} bobcat-6.07.01/x2a/x2a1.cc0000664000175000017500000000056014673353434013676 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-6.07.01/x2a/x2a2.cc0000664000175000017500000000020214673353434013670 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-6.07.01/x2a/driver/0000775000175000017500000000000014737552575014116 5ustar frankfrankbobcat-6.07.01/x2a/driver/build0000775000175000017500000000006114673353434015130 0ustar frankfrank#!/bin/sh g++ -I.. -o driver driver.cc -lbobcat bobcat-6.07.01/x2a/driver/driver.cc0000664000175000017500000000151614673353434015713 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-6.07.01/xerr/0000775000175000017500000000000014736315237013100 5ustar frankfrankbobcat-6.07.01/xerr/xerr.ih0000664000175000017500000000132114736315237014377 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-6.07.01/xpointer/0000775000175000017500000000000014736742656014001 5ustar frankfrankbobcat-6.07.01/xpointer/get.cc0000664000175000017500000000052114673353434015055 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-6.07.01/xpointer/data.cc0000664000175000017500000000013114673353434015204 0ustar frankfrank#include "xpointer.ih" size_t Xpointer::s_counter = 0; Display *Xpointer::s_theDisplay; bobcat-6.07.01/xpointer/xpointer.ih0000664000175000017500000000007714736315237016166 0ustar frankfrank#include "xpointer" using namespace std; using namespace FBB; bobcat-6.07.01/xpointer/set.cc0000664000175000017500000000076614673353434015104 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-6.07.01/xpointer/icmconf0000664000175000017500000000007614673353434015335 0ustar frankfrank#define LIBRARY "xpointer" #include "../icmconf" bobcat-6.07.01/xpointer/xpointer.cc0000664000175000017500000000034614673353434016153 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-6.07.01/xpointer/xpointer0000664000175000017500000000104214673353434015561 0ustar frankfrank#ifndef INCLUDED_BOBCAT_XPOINTER_ #define INCLUDED_BOBCAT_XPOINTER_ #include #include #include namespace FBB { class Xpointer { using DeleterType = void (*)(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-6.07.01/xpointer/destructor.cc0000664000175000017500000000023114673353434016472 0ustar frankfrank#include "xpointer.ih" Xpointer::~Xpointer() { if (!--s_counter) // No more Xpointer objects ? XCloseDisplay(s_theDisplay); } bobcat-6.07.01/xpointer/deleter.f0000664000175000017500000000013114673353434015557 0ustar frankfrankinline void Xpointer::deleter(Display *dsp) { if (dsp) XCloseDisplay(dsp); } bobcat-6.07.01/xpointer/driver/0000775000175000017500000000000014737552575015274 5ustar frankfrankbobcat-6.07.01/xpointer/driver/build0000775000175000017500000000012114673353434016303 0ustar frankfrank#!/bin/bash g++ `cat ../../c++std` -c -Wall -o driver driver.cc -lbobcat -lX11 bobcat-6.07.01/xpointer/driver/driver.cc0000664000175000017500000000125114673353434017065 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; }