<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-14240039</id><updated>2012-02-17T03:20:48.475+02:00</updated><category term='linux'/><category term='думи'/><category term='daily'/><category term='emacs'/><category term='javascript'/><category term='java'/><category term='sql'/><category term='programming'/><category term='source control'/><category term='freebsd'/><category term='Lisp'/><category term='c++'/><category term='misc'/><title type='text'>От дума на дума</title><subtitle type='html'>за нещата, които ме вълнуват</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://zlatozar.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://zlatozar.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Zlatozar</name><uri>http://www.blogger.com/profile/16257250071061885492</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/17/6760/640/RabotnotoMqsto.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>42</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-14240039.post-5499687535657157194</id><published>2011-08-11T16:38:00.002+03:00</published><updated>2011-08-18T16:46:14.018+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>C++ classes rules</title><content type='html'>&lt;pre style="color: #111111; font-size: 10pt;"&gt;#_______________________________________________________________________________&lt;br /&gt;#&lt;br /&gt;#   &lt;b&gt;C++&lt;/b&gt; notes during coding&lt;br /&gt;#_______________________________________________________________________________&lt;br /&gt;#&lt;br /&gt;&lt;br /&gt;1. Basics&lt;br /&gt;    &lt;br /&gt;    * Do not write using declarations in header files.&lt;br /&gt;    * Use delete for simple variables and delete[] for arrays.&lt;br /&gt;    * Global variables are implicitly initialized to zero; the programmer must initialize all other variables.&lt;br /&gt;      Compiler does not detect uninitialized local variables.&lt;br /&gt;&lt;br /&gt;    * Use reference as auxiliary variables:&lt;br /&gt;&lt;pre class="brush: cpp"&gt;    for(int i = 0; i &lt; SIZE; ++i) {&lt;br /&gt;        int&amp; p = a[i];            // very efficient when 'p' has to be referred many times &lt;br /&gt;        if(p == 0) {&lt;br /&gt;           p = 1;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;* function declaration = function signature      function definition = function implementation    * A function can return a reference type, and if it does, it can be called on either side of an assignment      or in an I/O statement.    * Enumerations do not have to be named if the name of the enumerator is sufficient    * An array of objects requires a no-argument constructor because there is no way to specify the actual parameter of       constructor, which is called for all of the array elements when the array is created.    * Static objects are destroyed (their destructors are executed) when the entire program terminates.    * &lt;i&gt;static&lt;/i&gt; keywordEach name in a C++ source file, including functions and global variables, has a linkage that is either internal or external.External linkage means that the name is available from other source files. Internal linkage (also called static linkage)means that it is not. By default, functions and global variables have external linkage.Initialization order of nonlocal variables in different source files is undefined.    * namespacesThink of scopes more like directories and "using" statements more like path variables - kind of like&lt;b&gt;"I won't remember the exact name of xxxxx.cpp but I will remember it's in my 'project_subdir' directory for example".&lt;/b&gt;There's nothing wrong, per-se, with deeply nested namespaces in C++, except that they're not normally necessary as there'sno module system behind them, and the extra layers just add noise so avoid them.&lt;b&gt;Watch out for ADL(argument-dependent-lookup) when using namespaces!&lt;/b&gt;The basic idea is what when the compiler finds a non-fully-qualified identifier it will try to match itstarting in the current namespace, and if not found it will try the enclosing namespace... allthe way to the root.    * Anything which can appear on the left of = (that is, anything that can represent an address) is called an &lt;i&gt;Lvalue&lt;/i&gt;.      Anything which can appear on the right of = (that is, anything that can yield a value) is called an &lt;i&gt;Rvalue&lt;/i&gt;.    * What is a handle?Sometimes libraries require client code to keep information returned from one interface in order to passit to another. This information is sometimes called a handle and is often used to keep track of specificinstances that require state to be remembered between calls. The term "handle" is sometimes used to describea pointer to a pointer to some memory(a pointer to some other C++ object). In some applications,handles areused because they allow the underlying software to move memory around as necessary. Summarizing: accessingsomething via a level of indirection. If the abstract model specifies that one object "contains" another,your implementation does not have to make the contained object a data member of the containing object. Instead,the containing object ca have a handle to the representation of the contained object. It is a good ideato use smart pointers for all handles!     * Libraries  &lt;b&gt;Static:&lt;/b&gt;A static library contains object code that is linked with an end-user application and then becomespart of that executable. A static library is sometimes called an archive because it is essentially just a packageof compiled object files. These libraries normally have a file extension of .a on UNIX and Mac OS X machinesor .lib on Windows, for example, libjpeg.a or jpeg.lib.&lt;pre class="brush: plain"&gt;g++ -c file1.cpp&lt;br /&gt;   g++ -c file2.cpp&lt;br /&gt;   g++ -c file3.cpp&lt;br /&gt;   ar -crs libmyapi.a file1.o file2.o file3.o&lt;br /&gt;&lt;/pre&gt;The &lt;i&gt;-c&lt;/i&gt; option to g++ tells the compiler to produce a .o file from the input .cpp file. The options to&lt;b&gt;ar&lt;/b&gt; are &lt;i&gt;-c&lt;/i&gt; creates an archive, &lt;i&gt;-r&lt;/i&gt; inserts the supplied .o files into that archive, and &lt;i&gt;-s&lt;/i&gt; creates an indexfor the archive.Your users can then link against your library using the &lt;i&gt;-l&lt;/i&gt; option to ld or g++. This specifies thename of the library to link against. The -L linker option can also be used to specify the directorywhere your library can be found. For example,&lt;pre class="brush: plain"&gt;g++ usercode.cpp -o userapp -L. -lmyapi&lt;br /&gt;&lt;/pre&gt;In this example, the end-user application userapp is created by compiling &lt;b&gt;usercode.cpp&lt;/b&gt; and linkingagainst the libmyapi.a static library in the same directory.The order of archives on this command line is significant. For each archive that the linker findson the command line, it looks to see if that archive defines any symbols that were referenced fromany object files specified earlier on the command line. If it does define any needed symbols, theobject files with those symbols are copied into the executable. It is therefore best practice to specifylibraries at the end of the command line.While I am discussing the creation of static libraries, it is worth noting proper usage ofthe &lt;i&gt;-static&lt;/i&gt; compiler option. This flag is used for the creation of executables, not libraries. It istherefore applicable to users of your API, but not to the building of your API itself. This flaginstructs the compiler to prefer linking the static versions of all dependent libraries into the executableso that it depends on no dynamic libraries at run time.  &lt;b&gt;Dynamic:&lt;/b&gt;Dynamic libraries are files linked against at compile time to resolve undefined references and thendistributed with the end-user application so that the application can load the library code at run timeThis normally requires use of a dynamic linker on the end user’s machine to determine and load all dynamiclibrary dependencies at run time, perform the necessary symbol relocations, and then pass control to the application.For example, the Linux dynamic linker is called ld.so and on the Mac it is called dyld.Often, the dynamic linker supports a number of environment variables to modify or debug its behavior.Dynamic libraries are sometimes called shared libraries because they can be shared by multiple programs.On UNIX machines they can be called Dynamic Shared Objects, and on Windows they are referred to as Dynamic Link Libraries.They have a .so file extension on UNIX platforms, .dll on Windows, and .dylib on Mac OS X,for example, libjpeg.so or jpeg.dll.Creating a dynamic library on Linux is a very similar process to creating a static library. Using theGNU C++ compiler, you can simply use the -shared linker option to generate a .so file instead ofan executable.On platforms where it is not the default behavior, you should also specify either the -fpic or the&lt;i&gt;-fPIC&lt;/i&gt; command line option to instruct the compiler to emit &lt;i&gt;position-independent&lt;/i&gt; code (PIC). This isneeded because the code in a shared library may be loaded into a different memory location for differentexecutables. It’s therefore important to generate PIC code for shared libraries so that user codedoes not depend on the absolute memory address of symbols. The following example illustrates howto compile three source files into a dynamic library.&lt;pre class="brush: plain"&gt;g++ -c -fPIC file1.c&lt;br /&gt;   g++ -c -fPIC file2.c&lt;br /&gt;   g++ -c -fPIC file3.c&lt;br /&gt;   g++ -shared -o libmyapi.so -fPIC file1.o file2.o file3.o&lt;br /&gt;&lt;/pre&gt;Users can then link your dynamic library into their code using the same compile line shown earlierfor the static library case, that is,&lt;pre class="brush: plain"&gt;g++ usercode.cpp -o userapp -L. -lmyapi&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;NOTE:&lt;/b&gt; If you have both a static library and a dynamic library with the same base name in the same directory,that is, libmyapi.a and libmyapi.so, the compiler will use the dynamic library (unless you usethe &lt;i&gt;-static&lt;/i&gt; library option to require only static libraries to be used). To favor use of a static libraryover a dynamic library with the same base name, you could place the static library in a differentdirectory and ensure that this directory appears earlier in the library search path (using the -L linkeroption).Note also that in a dynamic library, all code is essentially flattened into a single object file. This is incontrast to static libraries that are represented as a collection of object files that can be copied individuallyinto an executable as needed (i.e., object files in a static archive that are not needed are notcopied into the executable image). As a result, loading a dynamic library will involve loading all thecode defined in that .so file.On Linux platforms, you can use the dlopen() function call to load a .so file into the current process.Then you can use the dlsym() function to access symbols within that library. This lets you createplugin interfaces, as described earlier. For example, consider the following very simple plugininterface:&lt;pre class="brush: cpp"&gt;#ifndef PLUGIN_H&lt;br /&gt;        #define PLUGIN_H&lt;br /&gt;        #include &amp;lt;string&amp;gt;&lt;br /&gt;            extern "C"&lt;br /&gt;            void DoSomething(const std::string &amp;name);&lt;br /&gt;        #endif&lt;br /&gt;&lt;/pre&gt;You can build a dynamic library for this API, such as libplugin.so. Then the following codedemonstrates how to load this library and call the DoSomething() function within that .so file:&lt;pre class="brush: cpp"&gt;typedef void(*FuncPtrT)(const std::string &amp;);&lt;br /&gt;        const char *error;&lt;br /&gt;&lt;br /&gt;        // open the dynamic library&lt;br /&gt;        void *handle = dlopen("libplugin.so", RTLD_LOCAL | RTLD_LAZY);&lt;br /&gt;        if (! handle) {&lt;br /&gt;          std::cout &lt;&lt; "Cannot load plugin!" &lt;&lt; std::endl;&lt;br /&gt;          exit(1);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        dlerror();&lt;br /&gt;&lt;br /&gt;        // get the DoSomething() function from the plugin&lt;br /&gt;        FuncPtrT fptr = (FuncPtrT) dlsym(handle, "DoSomething");&lt;br /&gt;&lt;br /&gt;        if ((error = dlerror())) {&lt;br /&gt;           std::cout &lt;&lt; "Cannot find function in plugin: " &lt;&lt; error;&lt;br /&gt;           std::cout &lt;&lt; std::endl;&lt;br /&gt;           &lt;br /&gt;           dlclose(handle);&lt;br /&gt;           exit(1);&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        // call the DoSomething() function&lt;br /&gt;        (*fptr)("Hello There!");&lt;br /&gt;        &lt;br /&gt;        // close the shared library&lt;br /&gt;        dlclose(handle);&lt;br /&gt;&lt;/pre&gt;* AssertionsThe behavior of assert depends on the NDEBUG preprocessor symbol: if the symbol is not defined, theassertion takes place, otherwise it is ignored. Compilers often define this symbol when compiling "debug"builds. If you want to leave asserts in run time code, you must specify your compiler settings, or writeyour own version of assert that isn't affected by the value of &lt;b&gt;NDEBUG&lt;/b&gt;.     * Use 0 for integers, 0.0 for reals, NULL for pointers, and '\0' for chars.      * Make crash course:&lt;pre class="brush: plain"&gt;target : depends&lt;br /&gt;           rule&lt;br /&gt;  &lt;br /&gt;        target  - the parameter given to make. I.e. what to build&lt;br /&gt;        depends - file or other targets target depends on&lt;br /&gt;        rule    - how to create target (note that rule is preceeded by a TAB char)&lt;br /&gt;&lt;br /&gt;        $(VAR)  - environment variable or variable defined above&lt;br /&gt;        $@      - current target&lt;br /&gt;        $*      - current target without extension &lt;br /&gt;                  (the bit which matches the % wildcard in the rule definition)&lt;br /&gt;        $&lt;      - current dependency&lt;br /&gt;        $^      - the names of all the dependencies space separated&lt;br /&gt;&lt;/pre&gt;* Doxygen crash course&lt;pre class="brush: plain"&gt;- \file [&amp;lt;filename&amp;gt;]&lt;br /&gt;       - \class &amp;lt;class name&amp;gt; [&amp;lt;header-file&amp;gt;] [&amp;lt;header-name&amp;gt;]&lt;br /&gt;       - \brief &amp;lt;short summary&amp;gt;&lt;br /&gt;       - \author &amp;lt;list of authors&amp;gt;&lt;br /&gt;       - \date &amp;lt;date description&amp;gt;&lt;br /&gt;       - \param &amp;lt;parameter name&amp;gt; &amp;lt;description&amp;gt;&lt;br /&gt;       - \param[in] &amp;lt;input parameter name&amp;gt; &amp;lt;description&amp;gt;&lt;br /&gt;       - \param[out] &amp;lt;output parameter name&amp;gt; &amp;lt;description&amp;gt;&lt;br /&gt;       - \param[in,out] &amp;lt;input/output parameter name&amp;gt; &amp;lt;description&amp;gt;&lt;br /&gt;       - \return &amp;lt;description of the return result&amp;gt;&lt;br /&gt;       - \code &amp;lt;block of code&amp;gt; \endcode&lt;br /&gt;       - \verbatim &amp;lt;verbatim text block&amp;gt; \endverbatim&lt;br /&gt;       - \exception &amp;lt;exception-object&amp;gt; &amp;lt;description&amp;gt;&lt;br /&gt;       - \deprecated &amp;lt;explanation and alternatives&amp;gt;&lt;br /&gt;       - \attention &amp;lt;message that needs attention&amp;gt;&lt;br /&gt;       - \warning &amp;lt;warning message&amp;gt;&lt;br /&gt;       - \since &amp;lt;API version or date when the entity was added&amp;gt;&lt;br /&gt;       - \version &amp;lt;version string&amp;gt;&lt;br /&gt;       - \bug &amp;lt;description of bug&amp;gt;&lt;br /&gt;       - \see &amp;lt;cross-references to other methods or classes&amp;gt;&lt;br /&gt;&lt;br /&gt;       - \a &amp;lt;word&amp;gt;   Mark next word as a reference to a parameter.&lt;br /&gt;       - \e &amp;lt;word&amp;gt;   Use italic font for the next word.&lt;br /&gt;       - \b &amp;lt;word&amp;gt;   Use bold font for the next word.&lt;br /&gt;       - \c &amp;lt;word&amp;gt;   Use typewriter font for the next word.&lt;br /&gt;       - \sa &amp;lt;references&amp;gt;   Adds a section with cross references.&lt;br /&gt;       - \bug &amp;lt;text&amp;gt;   Describe a known bug.&lt;br /&gt;       - \todo &amp;lt;text&amp;gt;   Add a todo list.&lt;br /&gt;       - \attention &amp;lt;text&amp;gt;   Add a section for something that needs attention.&lt;br /&gt;       - \warning &amp;lt;text&amp;gt;   Add a section for a warning.&lt;br /&gt;       - \anchor &amp;lt;refname&amp;gt;   Set an invisible anchor which can be used to create a link with \ref.&lt;br /&gt;       - \ref &amp;lt;refname&amp;gt; [&amp;lt;text&amp;gt;]   Add a link to &amp;lt;refname&amp;gt;.&lt;br /&gt;&lt;/pre&gt;In addition to these commands, Doxygen supports various formatting2. Object-oriented programming    * Typical class structure:&lt;pre class="brush: cpp"&gt;// Foo.h&lt;br /&gt;#ifndef _FOO_H_&lt;br /&gt;#define _FOO_H_&lt;br /&gt;&lt;br /&gt;// _____________________________________________________________________________&lt;br /&gt;//                                                                     Includes&lt;br /&gt;&lt;br /&gt;// Headers&lt;br /&gt;#include "Bar.h"&lt;br /&gt;&lt;br /&gt;// Forward declarations&lt;br /&gt;class Joe;&lt;br /&gt;&lt;br /&gt;// DO NOT USE: using namespace std;&lt;br /&gt;/**&lt;br /&gt; * @ingroup &lt;br /&gt; * @class Foo&lt;br /&gt; * @brief &lt;br /&gt; *&lt;br /&gt; * @author&lt;br /&gt; * @version 1.0.0&lt;br /&gt; */&lt;br /&gt;class Foo&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;// Public Types&lt;br /&gt;public:&lt;br /&gt;    typedef int FooValType;&lt;br /&gt;    enum FooItemType  {&lt;br /&gt;        FOO_ITEM_0,&lt;br /&gt;        // ...&lt;br /&gt;    };&lt;br /&gt;&lt;br /&gt;// Private Members&lt;br /&gt;private:&lt;br /&gt;    FooValType _val;&lt;br /&gt;&lt;br /&gt;// Public Methods&lt;br /&gt;public:&lt;br /&gt;    // Constructors&lt;br /&gt;    Foo();&lt;br /&gt;    virtual ~Foo();&lt;br /&gt;&lt;br /&gt;    // Other methods&lt;br /&gt;    void process(const Joe&amp; aJoe);&lt;br /&gt;&lt;br /&gt;    // getters/setters&lt;br /&gt;    FooValType getVal() const;&lt;br /&gt;&lt;br /&gt;    // toString&lt;br /&gt;    friend std::ostream&amp; operator&lt;&lt;(std::ostream&amp; ostr, const Foo&amp; inFoo);&lt;br /&gt;&lt;br /&gt;// Private Methods&lt;br /&gt;private:&lt;br /&gt;    DISALLOW_COPY_AND_ASSIGN(Foo);&lt;br /&gt;    void _process() const;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;// _____________________________________________________________________________&lt;br /&gt;//                                                               Inline methods&lt;br /&gt;&lt;br /&gt;// Small and fast methods that change the object state&lt;br /&gt;&lt;br /&gt;// _____________________________________________________________________________&lt;br /&gt;//                                                               Static methods&lt;br /&gt;&lt;br /&gt;// Static method from class interface&lt;br /&gt;&lt;br /&gt;#endif /* _FOO_H_ */&lt;br /&gt;&lt;/pre&gt;* The relative order of initialization of non-local static objects in different translation units is      undefined    * In the C++ object model, protection is applied at the class level and      not at the object level. An object "beta" of class X can access everything inside another       object - "alpha", of class X without any restrictions. For example in copy constructors      you can use private data of source object.    * Every class presents two interfaces: one to the users, another to the derived classes    * Implicitly declared constructors are publicinlinemembers of their class    * Initialization order is declared in the class itself, not in the constructor!        * Don’t attempt to call one constructor of a class from another.    * The assignment operator should check for self-assignment and return a reference to "this".    * When creating an object on the stack, omit parenthesis for the default constructor.    * Pass objects by const reference instead of by value.    * Returning a reference to a data member is risky because the reference is valid only as long as the object is "alive"    * = does not always mean assignment! It can also be shorthand for copy construction      when used on the same line as the variable declaration:&lt;pre class="brush: cpp"&gt;SpreadsheetCell aThirdCell = myCell;   // aThirdCell is constructed with the copy constructor&lt;br /&gt;      anotherCell = myCell;                  // Calls operator= for anotherCell.&lt;br /&gt;&lt;/pre&gt;* Don't use "extern" declarations    * The virtual keyword has a few subtleties and is often cited as a poorly designed part of the language.      There is a lot of problems associated with omission of the virtual keyword. So to avoid problems:As a rule of thumb, make all your methods virtual (including the destructor, but notconstructors) to avoid problems associated with omission of the virtual keyword.Attempting to override a non-virtual method will "hide" the superclass definitionand will only be used in the context of the subclass.Constructors cannot and need not be virtual because you always specify the exact class being constructed when creating an object.    * When upcasting, use a pointer or reference to the superclass to avoid slicing.    * Use downcasting only when necessary and be sure to use a dynamic cast.    * Uses multiple inheritance only for the implementation of mix-in classesA mix-in class adds new capabilities to other classes. They represent static relationship and usually theyare pure virtual classes so no one creates an instance of a mix-in class. It does not make any senseto create an instance of mix-in class because the mix-in class adds flavor to some other class - it is to bemixed in with another class. A mix-in class answers the question "What else is this class able to do?" and theanswer often ends with "-able." Naming convention is mix-in class to end with "-able" e.g. Callable.    * When you override a method, you are implicitly hiding any other versions of the method!      It makes sense if you think about it — why would you want to change some versions of a method and not others?To avoid obscure bugs, you should override all versions of an overloaded method,either explicitly or with the "using" keyword.&lt;pre class="brush: cpp"&gt;class Foo {&lt;br /&gt;        public:&lt;br /&gt;          virtual void overload() { cout &lt;&lt; "Foo's overload()" &lt;&lt; endl; }&lt;br /&gt;          virtual void overload(int i) { cout &lt;&lt; "Foo's overload(int i)" &lt;&lt; endl; }&lt;br /&gt;      };&lt;br /&gt;      class Bar : public Foo {&lt;br /&gt;        public:&lt;br /&gt;          using Foo::overload;&lt;br /&gt;          virtual void overload() { cout &lt;&lt; "Bar’s overload()" &lt;&lt; endl; }&lt;br /&gt;      }&lt;br /&gt;&lt;/pre&gt;If your API does not call a particular method internally, then that method probably should not be virtual.You should also only allow subclassing in situations where it makes sense: where the potential subclasses form an &lt;i&gt;"is-a"&lt;/i&gt;relationship with the base class.   * Overloading works only within the scope of a single class!   * Don't change the default parameters of the inherited functions you override.     When overriding a method that has a default argument, you should provide a default argument as well,     and it should probably be the same value.      * The only truly useful way to change a method’s access level is by providing a less     restrictive accessor to a protected method.   * If your subclass does not specify its own copy constructor or operator=, the parent     functionality continues to work. If the subclass does provide its own copy constructor     or operator=, it needs to explicitly reference the parent versions.   * Note that the runtime-type information is stored in the vtable of the object. Therefore, in order to use     dynamic_cast, your classes must have at least one virtual function. Use &lt;b&gt;dynamic_cast&lt;&gt;&lt;/b&gt; to restore     lost type information   * Do not mix and match malloc() and free() with new and delete. Use only new and delete.     As a rule of thumb, every line of code that allocates memory with new should correspond     to another line of code that releases the same memory with delete.   * Calling "delete" twice is incorrect and leads to undefined behavior   * Do not throw exceptions from destructor   * Member initialization list: variables of primitive data types are initialized through assignments,     while variables of class types are initialized by calling copy constructor.   * Always List any Superclass Constructors in the Initializer List of a Subclass Constructor   * When object that contains nested classes goes out of scope, the destructors for nested objects are called     (in revert order of construction)   * The definitions of static members occur outside the class in the implementation file   * Constant static attributes can be initialized within the class definition if they are of an integral type, and     the initialization expression must be constant.   * An operation in a class "C" that returns a new object should have a return type "C" and should allocate this     object on the stack&lt;pre class="brush: cpp"&gt;Integer Integer::clone() const {&lt;br /&gt;       Interger res(_value);&lt;br /&gt;       return res;&lt;br /&gt;     }&lt;br /&gt;&lt;/pre&gt;* Use &lt;b&gt;"new"&lt;/b&gt; when you don't know exact type until runtime. In other words when you expect to use polymorphism (late binding)     Operations with a late binding mus be invoked through a pointer or a reference.   * Covariant return types! If a virtual operation in the base class returns a class type, a reference to a class type,     or a pointer to class type, the same virtual operation in a derived class can return a class(or a reference or a pointer)      that is publicly derived from the base class. That is, the return types in the base class and in the derived class do not     have to be strictly identical.   * To provide a default implementation that must be redefined in a derived class, use pure virtual operations and provide     there implementation   * Avoid calling virtual functions in constructors and destructors   * When we have a pure virtual function in any class then it prevent us to create any instance of that class.     That is we cannot make the object of that class. Now if you want to prevent a class from being instantiated     but at the same time you don't want to declare any pure virtual method inside it, then there is no way except that     you make your destructor as pure virtual. You cannot make your constructor as pure virtual and you don't have any other     method to make pure virtual then in that case you are left with only one alternative of making your innocent destructor     as pure virtual to avoid your class to be instantiated.   * A fiend function is not implemented inside the class granting friendship (unless it is an inline declaration and      definition for the friend function which is rare). A friend function lives in another class or it could be a     free function not attached to any class. A function(or class) can not proclaim itself to be a friend of another class.      * Friend mechanism is can not be transitive - friend of a friend is NOT friend      * Friendship is not inherited3. ReferencesYou can think of references as just another name for the original variable!Taking the address of a reference gives the same result as taking the address of the variable towhich the reference refers. References are const by default, in that you can’t change to what they refer.So, C++ does not allow you to mark a reference variable explicitly const!&lt;pre class="brush: cpp"&gt;int x = 3;&lt;br /&gt;      int&amp; xRef = x;&lt;br /&gt;      int* xPtr = &amp;xRef; // Address of a reference is pointer to value&lt;br /&gt;      *xPtr = 100;       // x will be changed&lt;br /&gt;&lt;/pre&gt;You must always initialize a reference when it is allocated. Usually, references areallocated when they are declared, but reference data members can be initialized inthe initializer list for the containing class.You cannot change the variable to which a reference refers after it is initialized; youcan only change the value of that variable.You cannot declare a reference to a reference or a pointer to a reference. You must initialize reference data members in the constructor initializationlist, not in the body of the constructorA common quandary arises when you have a pointer to something that you need to pass to a function ormethod that takes a reference. You can "convert" a pointer to a reference in this case simply bydereferencing the pointer.&lt;pre class="brush: plain"&gt;void swap(int&amp; first, int&amp; second);&lt;br /&gt;      ........&lt;br /&gt;      int x = 5, y = 6;&lt;br /&gt;      int *xp = &amp;x, *yp = &amp;y;&lt;br /&gt;      swap(*xp, *yp);&lt;br /&gt;&lt;/pre&gt;You can't pass constants as arguments to functions that employ pass-by-reference:&lt;pre class="brush: plain"&gt;swap(3, 4); // DOES NOT COMPILE&lt;br /&gt;&lt;/pre&gt;You can also return a reference from a function or method. The main reason to do so is efficiency.But be careful - never return a reference to a variable, such as an automatically allocated variable onthe stack, that will be destroyed when the function ends. A second reason to return a reference is if youwant to be able to assign to the return value directly as an lvalue. For example, several overloaded operatorscommonly return references.Almost everything you can do with references, you can accomplish with pointers.If the code receiving the variable is responsible for releasing the memory associated with an object,it must receive a pointer to the object. If the code receiving the variable should not free the memory,it should receive a reference! The only case in which you need to use a pointer instead of referenceis when you need to change the location to which it points.Because return references do not invoke copy constructors, they may be more efficient than functionsthat return objects.When you have class methods that change object state (e.g set/add) it is good practice to return reference type not void and terminate with a statement of the form:&lt;pre class="brush: plain"&gt;.........&lt;br /&gt;      return &amp;this;&lt;br /&gt;&lt;/pre&gt;In this way you can chain e.g. if we have "add" method then&lt;pre class="brush: plain"&gt;i.add(5).add(7);&lt;br /&gt;&lt;/pre&gt;But do not return a reference to attributes of a class(common error).         * A function should not return a reference to a heap-based object that was allocated in the function.Reference and pointer attributes have the values referenced by them changed instead of their own values,and so the do not have to be specified as mutable.     4. Be const correctGeneral rule for const pointers: const applies to the level of indirection directly to its left!There is alternative syntax but I use this one.&lt;pre class="brush: plain"&gt;const int my_constant = 10&lt;br /&gt;    An int which can't change value. Similar to #define in C but better.&lt;br /&gt;&lt;br /&gt;int const* my_constant&lt;br /&gt;    Variable pointer to a constant integer.&lt;br /&gt;const int* my_constant&lt;br /&gt;    Alternative syntax, the same as above.&lt;br /&gt;&lt;br /&gt;int* const my_constant&lt;br /&gt;    Constant pointer to a variable integer.&lt;br /&gt;&lt;br /&gt;int const* const my_constant&lt;br /&gt;    Constant pointer to a constant integer.&lt;br /&gt;const int* const my_constant&lt;br /&gt;    Alternative syntax, the same as above.&lt;br /&gt;&lt;br /&gt;void my_method(QString const&amp; my_paramater)&lt;br /&gt;    my_paramater will not be altered by the method.&lt;br /&gt;    '&amp;' means it can be altered but here we just want it to be used because it saves taking a copy.&lt;br /&gt;&lt;/pre&gt;&lt;pre class="brush: cpp"&gt;class MyClass {&lt;br /&gt;      void my_method() const;&lt;br /&gt;      int my_variable;&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;my_method() will not alter any member variable (my_variable), this means you can call the method from a const variable.&lt;pre class="brush: cpp"&gt;int const* const my_method(const int* const&amp;) const&lt;br /&gt;&lt;/pre&gt;It will return a pointer which is constant and points to a constant integer,    the method doesn't alter either the variable pointed to by the parameter    or the pointer itself and it doesn't alter any of the member variables of the object the method is it. The const-ness of parameter can be used to define an overloaded function but only if this parameter is passedby reference.&lt;b&gt;How to read const?&lt;/b&gt;&lt;b&gt;Rule a: If a const and/or volatile is next to a type specifier (int, long, etc.) it applies to that specifier.&lt;/b&gt;&lt;b&gt;Rule b: if a const and/or volatile is not next to a type then it applies to the pointer asterisk on its immediate left.&lt;/b&gt;    5. Arrays    * The advantage of putting an array on the heap is that you can use dynamic memory to define its size at run time.&lt;pre class="brush: cpp"&gt;int numDocs = askUserForNumberOfDocuments();&lt;br /&gt;       Document* docArray = new Document[numDocs];    // dynamic size&lt;br /&gt;&lt;/pre&gt;* If you have an array of pointers, you will still need to delete each element individually just as you      allocated each element individually and after that to delete array itself.    * If you need to determine the dimensions of a multidimensional array at run time, you can use a heapbased array but:&lt;pre class="brush: cpp"&gt;char** board = new char[i][j]; // DOES NOT COMPILE!&lt;br /&gt;&lt;/pre&gt;You can allocate the first dimension array just like a single-dimensional heap-based array, but the individual subarrays must be explicitly allocated.6. Pointers Pointers are something like that: &lt;i&gt;A pointer is simply a level of indirection that says to the program "Hey! Look over there.".&lt;/i&gt; When you take the address of a variable, using the &amp; operator, you are adding a level of indirection in memory. In the address-based view, the program is simply noting the numerical address of the variable, which can be stored in a pointer variable. In the graphical view, the &amp; operator creates a new arrow whose point ends at the variable.    * You can assign a string to a char* without const, and the program will work fine unless you attempt to change the string.      A much safer way to code is to use a pointer to const characters when referring to string literals.&lt;pre class="brush: cpp"&gt;const char* ptr = "hello"; // Assign the string literal to a variable.&lt;br /&gt;       ptr[1] = 'a';              // BUG! Compiler will catch it.&lt;br /&gt;&lt;/pre&gt;* For compatibility, you can convert a C++ string into a C-style string by using the      &lt;b&gt;c_str()&lt;/b&gt; method. You should call the method just before using the result so that it      accurately reflects the current contents of the string.    * Each function actually lives at a particular address. In C++, you can use functions as data.Function pointers are typed according to the parameter types and return type of compatible functions!The easiest way to work with function pointers is to use the typedef mechanism to assign a type nameto the family of functions that have the given characteristics.&lt;pre class="brush: cpp"&gt;// type called YesNoFunc that pointer to any function that has two int parameters and returns a bool.&lt;br /&gt;        typedef bool(*YesNoFunc)(int, int); &lt;br /&gt;&lt;/pre&gt;Any function that return bool and accepts parameters two integer could be represented by this type.    * Nested objects and shared pointers&lt;pre class="brush: cpp"&gt;class Example {&lt;br /&gt;        public: &lt;br /&gt;        // ...&lt;br /&gt;        private:&lt;br /&gt;          boost::scoped_ptr&amp;lt;Owned&amp;gt; data;&lt;br /&gt;       };&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;scoped_ptr&lt;/b&gt; is very good for this purpose. But one has to understand its semantics. You can group smart pointers using two major properties:     - Copyable: A smart pointer can be copied: The copy and the original share ownership.     - Movable: A smart pointer can be moved: The move-result will have ownership, the original won't own anymore.That's rather common terminology. For smart pointers, there is a specific terminology which better marks those properties:     - Transfer of Ownership: A smart pointer is Movable     - Share of Ownership: A smart pointer is copyable. If a smart pointer is already copyable, it's easy to support       transfer-of-ownership semantic. That then is just an atomic copy &amp; reset-of-original operation, restricting that to smart       pointers of certain kinds(e.g only temporary smart pointers).Let's group the available smart pointers, using (C)opyable, and (M)ovable, (N)either:     1. boost::scoped_ptr: N     2. std::auto_ptr: M     3. boost::shared_ptr: C&lt;b&gt;auto_ptr&lt;/b&gt; has one big problem, in that it realizes the Movable concept using a copy constructor.&lt;pre class="brush: cpp"&gt;auto_ptr&amp;lt;int&amp;gt; a(new int), b;&lt;br /&gt;       // oops, after this, a is reset. But a copy was desired!&lt;br /&gt;       // it does the copy&amp;reset-of-original, but it's not restricted to only temporary&lt;br /&gt;       // auto_ptrs (so, not to ones that are returned from functions, for example).&lt;br /&gt;       b = a;&lt;br /&gt;&lt;/pre&gt;NOTE: See also boost::weak_ptr&lt;b&gt;TIP:&lt;/b&gt; Always prefer passing a non-mutable object as a const reference rather than passing it by value. This will avoid     the memory and performance costs to create and destroy a temporary copy of the object and all of its member and     inherited objects.    * OwnershipBe careful with code like this&lt;pre class="brush: cpp"&gt;void doSomething(Simple*&amp; outSimplePtr) {&lt;br /&gt;      outSimplePtr = new Simple(); // BUG! Doesn't delete the original.&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;Valgrind&lt;/b&gt; catch the problem. Learn how to read Valgrind messages!7. I/O       goodbit   The stream is in a "good" state — nothing’s wrong    eofbit    The stream is positioned at end-of-file — no more data can be read    failbit   An operation failed but recovery is possible    badbit    The stream has “lost integrity” and cannot be used any more    * Every input stream has an associated source. Every output stream has an associated      destination.    * Not all output streams are buffered. The cerr stream, for example, does not buffer      its output.    * By default, the input stream will tokenize values according to white space.    * The methods that read in data from a stream(take iostream as a parameter) will change the actual      stream (most notably, its position), so they are not const methods. Thus, you can’t call them  on a const reference.    * String streams provide a way to use stream semantics with strings. In this way, you can have an inmemory      stream that represents textual data. There are useful for parsing text, because streams have built-in      tokenizing functionality. The main advantage of a string stream over a standard C++ string is that, in addition to data,      the object knows about its current position.    * Stream linking is accomplished with the tie() method. To tie an output stream to an input stream, call      tie() on the input stream, and pass the address of the output stream. To break the link, pass NULL.    * The fstream class provides a bidirectional file stream. fstream is ideal for applications that need to      replace data within a file because you can read until you find the correct position, then immediately      switch to writing. But be careful:   Bidirectional streams have separate pointers for the read position and the write position.When switching between reading and writing, you will need to seek to theappropriate position.    * A locale is a collection of settings about a particular location. An individual      setting is called a facet (e.g format used to display a date). Most operating systems have a mechanism to determine      the locale as defined by the user.      In C++, you can pass an empty string to the locale object constructor to create a locale from the user’s environment.    8. Exceptions    * The dark side of C++ exceptions:&lt;pre class="brush: cpp"&gt;void g() {&lt;br /&gt;        throw std::exception();&lt;br /&gt;      }&lt;br /&gt;      void f() {&lt;br /&gt;        int *i = new int(2);&lt;br /&gt;        *i = 3;&lt;br /&gt;        g();&lt;br /&gt;        // Oops, if an exception is thrown, i is never deleted&lt;br /&gt;        // and we have a memory leak&lt;br /&gt;        delete i;&lt;br /&gt;      }&lt;br /&gt;      int main() {&lt;br /&gt;        try {&lt;br /&gt;          f();&lt;br /&gt;        }&lt;br /&gt;        catch(...) { }&lt;br /&gt;        return (0);&lt;br /&gt;      }    &lt;br /&gt;&lt;/pre&gt;* In C++ a function that does not specify a list of exceptions can throw any exception it wants! A function without      a throw list can throw exceptions of any type. A function with an empty throw list shouldn’t throw any exception.      Unfortunately, the throw list is not enforced at compile time in C++.    * Your programs can catch exceptions by value, reference, const reference, or pointer.&lt;pre class="brush: cpp"&gt;} catch (const char* e) {       // when you throw error message  &lt;br /&gt;          } catch (const exception&amp; e) {&lt;br /&gt;&lt;/pre&gt;But generally catch exceptions with const to document that you are not modifying them.    * The keyword throw by itself simply rethrows whatever exception was caught most recently.&lt;pre class="brush: cpp"&gt;} catch (...) {&lt;br /&gt;            delete str;&lt;br /&gt;            throw;         // Rethrow the exception.&lt;br /&gt;          }&lt;br /&gt;&lt;/pre&gt;* Use auto_ptr to write exception save code:&lt;pre class="brush: cpp"&gt;void myFunction() {&lt;br /&gt;	auto_ptr ptr( new T ); &lt;br /&gt;	/*... code that throws exception...*/ &lt;br /&gt;&lt;br /&gt;	// ptr’s destructor gets called as the function’s stack unwinds here &amp; the object &lt;br /&gt;	// gets deleted automatically&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;* It’s important to know about &lt;b&gt;set_terminate()&lt;/b&gt;, it’s not a very effective exception-handling      approach. We recommend trying to catch and handle each exception individually in order to provide      more precise error handling.    * Unlike const, the exception specification is not part of the function or method signature. You cannot      overload a function based solely on different exceptions in the throw list.    * Throw lists don’t prevent functions from throwing unlisted exception types, but      they prevent the exception from leaving the function.        * The &lt;b&gt;unexpected()&lt;/b&gt; function applies program-wide, not just to this function, so you should reset the handler       when you are done with the code that needed your special handler.    * If you change throw lists when you override methods, remember that any code that      called the superclass version of the method must be able to call the subclass version.      Thus, you can’t add exceptions.    * When you catch exceptions polymorphically, make sure to catch them by reference.      If you catch exceptions by value, you can encounter slicing, in which case you lose      information from the object.    * Objects thrown as exceptions are always copied by value at least once. Thus,      if you write a class whose objects will be thrown as exceptions, you must make those objects copyable.      This means that if you have dynamically allocated memory, you must write a destructor, copy constructor,      and assignment operator. Catch exception objects by reference to avoid unnecessary copying.When a piece of code throws an exception, control jumps immediately to the exception handler thatcatches the exception. This exception handler could lie one or more function calls up the stack of execution.As the control jumps up in the stack in a process called stack unwinding, all code remaining in eachfunction past the current point of execution is skipped. However, local objects and variables in eachfunction that is unwound are destroyed as if the code finished the function normally. However, in stack unwinding,pointer variables are not freed, and other cleanup is not performed.    * Smart pointers allow you to write code that automatically prevents memory leaks with exception handling    * C++ guarantees that it will run the destructor for any fully constructed "subobjects"    * &lt;b&gt;RAII programming idiom&lt;/b&gt;The idea is to wrap the resource release operation in a destructor of an object in the scope. Language guaranteesthat the destructor will always be invoked (of a successfully constructed object) when control flow leaves the scopebecause of a return statement or an exception.&lt;b&gt;NOTE:&lt;/b&gt; Prefer to think of it as Stack-Based Resource Management because it tells a little more about what is goingon and what the goal is.The thing that gives destructors more expressiveness for dealing with cleanup is that they only executefor the objects that have been initialized. This means that if control exits a block after only half of the stack-localobjects have been constructed, only those half of the objects have their destructors invoked.With finally, all that bookkeeping is the responsibility of the programmer.9. Overloading C++ OperatorsThe general guiding principle is to make your classes behave like built-in types. The second reason to overload operatorsis to gain greater control over behavior in your program. It’s important to emphasize that operator overloading doesn'tnecessarily make things easier for you as the class developer; its main purpose is to make things easier for clients of the class.When the operator is a method of a class, the left-hand-side of the operator expression mustalways be an object of that class. If you write a global function, the left-hand-side can be an object of a differenttype.    * Operators that must be methods: When the operator is a method of a class, the left-hand-side of the operator expression must      always be an object of that class.    * Operators that must be global functions: Whenever you need to allow the left-hand side of the      operator to be a variable of a different type from your class, you must make the operator a global      function.    * Operators that can be either methods or global functions: Make every operator a method unless you      must make it a global function as described previously. One major advantage to this rule is that      methods can be virtual, but friend functions cannot. Therefore, when you plan to write overloaded      operators in an inheritance tree, you should make them methods if possible.    * &lt;b&gt;Choosing Argument Types: The choice of value vs. reference is easy: you should take every parameter by reference.&lt;/b&gt;    * The const decision is also trivial: Mark every parameter const unless you actually modify it.      A return value that can be modified as an lvalue (the left-hand-side of an assignment expression) must be      non-const. Otherwise, it should be const.    * C++ doesn’t determine overload resolution based on return type. Thus, you can specify any return type you want      when you write overloaded operators. However, you should write your overloaded operators such that they return      the same types as the operators do for the built-in types. The general rule for value or reference is to return      a reference if you can; otherwise, return a value.An &lt;i&gt;l-value&lt;/i&gt; operator(operators that are invoked on existing objects) can return a reference to the object on the LHS,the target of the operator call. This is safe, efficient and the correct way to implement an &lt;i&gt;l-value&lt;/i&gt; operator.Commutative operators (+, -, etc.) that compute the result from their operands, cannot return a reference or apointer. Naturally such operators return the result by value.    * Operators You Shouldn’t Overload: operator&amp;&amp; operator|| operator, and operator&amp;    * &lt;b&gt;(C++ hack)The prefix versions of operator++ and operator-- take no arguments,      while the postfix versions take one unused argument of type int&lt;/b&gt;    * postfix operation e.g. operation++(int) returns old value for the use in the rest of expression      prefix operation e.g. operation++ returns new value    * The C++ standard specifies that the prefix versions of increment and decrement return an lvalue, so      they can’t return a const value.    * The operator[] can replace both setElementAt() and getElementAt() because it returns a reference to the element at location x.    * You cannot overload the subscripting operator(operator[]) to take more than one parameter. If      you want to provide subscripting on more than one index, you can use the function      call operator.    * C++ allows you to overload the function call operator, written as operator(). If you write an operator()      for your class, you can use objects of that class as if they were function pointers. You can only overload this      operator as a non-static method in a class.    * An object of a class with a function call operator (operator()) is called a function object, or functor for short.      The advantage of function objects over standard methods of objects is simple: these objects can sometimes      masquerade as function pointers. You can pass function objects as callback functions to routines that expect function pointers,      as long as the function pointer types are templatized. This is a function with state - closure.    * You can overload the dereferencing operators for your classes in order to make objects of the classes      behave like pointers. In this way you can implement smart pointers.    * There are two differences between the prefix and postfix increments: their return type and their arguments.      The prefix version returns the modified object. It may seem odd that the postfix version of ++ returns a new object,      rather than a modified object.    * It is quite common to implement operator== as a virtual member function. However, it's counterpart, operator!= need      not to be a virtual function because it is implemented in terms of operator==&lt;pre class="brush: cpp"&gt;class X {&lt;br /&gt;  public:&lt;br /&gt;    virtual bool operator==(const X&amp; rhs) const { /* code is here */}&lt;br /&gt;    bool operator!=(const X&amp; rhs) const { return !(*this == rhs); }&lt;br /&gt;} &lt;br /&gt;&lt;/pre&gt;* Any operation that does NOT REQUIRE an l-value and is commutative is better implemented as a non-member function(+, - etc.).      This allows the compiler to applay a conversion in case of argument mismatch for the first argument.    * Any operation that REQUIRE an l-value is better implemented as a member function. This clearly shows that it can be invoked      on existing, modifiable objects.&lt;b&gt;Implementing operator-&gt; is tricky!&lt;/b&gt;The result of applying the arrow operator should be a member or method of an object.However, in order to implement it like that, you would have to be able to implement the equivalent of operator* followed by operator.. C++ doesn’t allow you to overload operator. for good reason: it’s impossible to write a single prototype that allows you to capture any possible member or method selection. Similarly, you couldn't writean operator-&gt; with such semantics. Therefore, C++ treats operator-&gt; as a special case.Consider this line:&lt;pre class="brush: cpp"&gt;smartCell-&gt;set(5);&lt;br /&gt;&lt;/pre&gt;C++ translates the preceding to:&lt;pre class="brush: cpp"&gt;(smartCell.operator-&gt;())-&gt;set(5);&lt;br /&gt;&lt;/pre&gt;As you can see, C++ applies another operator-&gt; to whatever you return from your overloaded operator-&gt;Conversions for Boolean ExpressionsIt is handy to use pointers in conditional statements like this:&lt;pre class="brush: plain"&gt;if (classPtr != NULL) {&lt;br /&gt;           // Perform some dereferencing action.&lt;br /&gt;        }&lt;br /&gt;&lt;/pre&gt;To do that you have to overload operator void*() (see type conversion operator T())    * You can predefine only operator&lt;, then&lt;pre class="brush: plain"&gt; &lt;br /&gt;      x &gt; y can be expressed as y &lt; x&lt;br /&gt;      x &gt;= y can be expressed as !(x &lt; y)&lt;br /&gt;      x &lt;= y can be expressed as !(y &lt; x) &lt;br /&gt;&lt;/pre&gt;10. Tests  &lt;pre class="brush: plain"&gt;1. What are the things that this piece of code was written to do?&lt;br /&gt;     2. What are the typical ways each method would be called?&lt;br /&gt;     3. What preconditions of the methods could be violated by the caller?&lt;br /&gt;     4. How could each method be misused?&lt;br /&gt;     5. What kinds of data are you expecting as input?&lt;br /&gt;     6. What kinds of data are you not expecting as input?&lt;br /&gt;     7. What are the edge cases or exceptional conditions?&lt;br /&gt;  &lt;/pre&gt;Once you have generated ideas for some of the tests you would like to use, consider how you mightorganize them into categories and the breakdown of tests will fall into place.     1. Basic tests     2. Error tests     3. Internationalization tests     4. Bad input tests     5. Complicated testsImportant: Decide on the correct output for your test before you ever run the test.Write the Tests Guideline:&lt;pre class="brush: plain"&gt;1. Make sure that you’re only testing one thing in each test. That way, if a test fails, it will point to&lt;br /&gt;        a specific piece of functionality.&lt;br /&gt;     2. Be specific inside the test. Did the test fail because an exception was thrown or because the&lt;br /&gt;        wrong value was returned?&lt;br /&gt;     3. Use logging extensively inside of test code. If the test fails some day, you will have some insight&lt;br /&gt;        into what happened.&lt;br /&gt;     4. Avoid tests that depend on earlier tests or are otherwise interrelated. Tests should be as atomic&lt;br /&gt;        and isolated as possible.&lt;br /&gt;     5. If the test requires the use of other subsystems, consider writing stub versions of those subsystems&lt;br /&gt;        that simulate the modules’ behavior so that changes in loosely related code don’t cause the&lt;br /&gt;        test to fail.&lt;br /&gt;     6. Ask your code reviewers to look at your unit tests as well. When you do a code review, tell the&lt;br /&gt;        other engineer where you think additional tests could be added.&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;NOTE:&lt;/b&gt; A fixture is simply a logical group of testsAn integration test covers areas where components meet. Unlike a unit test, which generally acts on thelevel of a single class, an integration test usually involves two or more classes. Integration tests excel attesting interactions between two components, often written by two different programmers. In fact, theprocess of writing an integration test often reveals important incongruities in designs.System tests operate at an even higher level than integration tests. These tests examine the program as awhole. System tests often make use of a virtual user that simulates a human being working with the program.Of course, the virtual user must be programmed with a script of actions to perform. Other systemtests rely on scripts or a fixed set of inputs and expected outputs.Regression testing is more of a testing concept than a specific type of test. The idea is that once a featureworks, developers tend to put it aside and assume that it will continue to work. Unfortunately, new featuresand other code changes often conspire to break previously working functionality. Regression testsare often put in place as a sanity check for features that are, more or less, complete and working. If theregression test is well written, it will cease to pass when a change is introduced that breaks the feature.  &lt;b&gt;What to Test?&lt;/b&gt;- Condition testing. When writing unit tests, you should use your knowledge of the code undertest to exercise all combinations of any if/else, for, while, and switch expressions within theunit.- Equivalence classes. An equivalence class is a set of test inputs that all have the same expectedbehavior. The technique of equivalence class partitioning therefore attempts to find test inputsthat exercise difference classes of behavior.- Boundary conditions. Most errors occur around the boundary of expected values. How manytimes have you inadvertently written code with an "off-by-one" error?- Parameter testing. A test for a given API call should vary all parameters to the function to verifythe full range of functionality.- Return value assertion. This form of testing ensures that a function returns correct results fordifferent combinations of its input parameters.- Operation order. Varying the sequence of operations to perform the same test (where this is possible)can help uncover any order of execution assumptions and non-orthogonal behavior.- Negative testing. This testing technique constructs or forces error conditions to see how the codereacts to unexpected situations.- Buffer overruns. A buffer overrun, or overflow, is when memory is written past the end of anallocated buffer.- Memory ownership. Memory errors are a common cause of crashes in C++ programs. Any APIcalls that return dynamically allocated memory should document whether the API owns the memoryor if the client is responsible for freeing it. These specifications should be tested to ensure thatthey are correct. For example, if the client is responsible for freeing the memory, a test couldrequest the dynamic object twice and assert that the two pointers are different. A further testcould free the memory and then rerequest the object from the API multiple times to ensure thatno memory corruption or crashes occur.- NULL input. Another common source of crashes in C++ is passing a NULL pointer to a functionthat then immediately attempts to dereference the pointer without checking for NULL. Youshould therefore test all functions that accept a pointer parameter to ensure that they behavegracefully when passed a NULL pointer.#_______________________________________________________________________________#                                                            Articles and linkshttp://www.gotw.ca/gotw/index.htmhttp://strlen.com/rants/javaclassesincpp.html     http://make.paulandlesley.org/autodep.htmlhttp://www.newty.de/fpt/http://www.mactech.com/articles/mactech/Vol.16/16.07/UsingFlexandBison/http://gnuu.org/2009/09/18/writing-your-own-toy-compiler/#_______________________________________________________________________________#                                                                         BooksC/C++ listmania:   http://www.amazon.com/Destination-C-C/lm/1RXP5YEYOG4HX/ref=cm_lm_byauthor_title_fullIt is not a book but it is very useful resource:   http://www.parashift.com/c++-faq-lite/&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14240039-5499687535657157194?l=zlatozar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zlatozar.blogspot.com/feeds/5499687535657157194/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14240039&amp;postID=5499687535657157194' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/5499687535657157194'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/5499687535657157194'/><link rel='alternate' type='text/html' href='http://zlatozar.blogspot.com/2011/08/c-classes-rules.html' title='C++ classes rules'/><author><name>Zlatozar</name><uri>http://www.blogger.com/profile/16257250071061885492</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/17/6760/640/RabotnotoMqsto.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14240039.post-5274137755592707529</id><published>2011-04-18T13:41:00.002+03:00</published><updated>2011-12-01T16:09:45.139+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><title type='text'>SQL crash course</title><content type='html'>&lt;pre style="color: #111111; font-size: 10pt;"&gt;&lt;br/&gt;&lt;br /&gt;1 Database&lt;br /&gt;~~~~~~~~~~~~~~~~~~~~~~~&lt;br /&gt;&lt;br /&gt;Before you start to create database you're going to need to have better idea of&lt;br /&gt;  what kinds of data you're going to want to store and some ways to categorizing it.&lt;br /&gt;&lt;br /&gt;  &lt;b&gt;Database is a container that holds tables and other SQL structures related to&lt;br /&gt;  those tables.&lt;/b&gt; Tables are connected in some way.&lt;br /&gt;&lt;br /&gt;2  Tables&lt;br /&gt;~~~~~~~~~~~~~~~~~~~~~~~&lt;br /&gt;&lt;i&gt;What is a table anyway?&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;A column is a piece of data stored by your table. A row is a single set of columns that describe attributes of single thing.&lt;/i&gt;&lt;br /&gt;Columns and rows together make up a table.&lt;br /&gt; &lt;br /&gt;  You can identify categories for the type of data you're collecting. Your categories then become your&lt;br /&gt;  columns. Type could be person, employer etc. Type is your row.&lt;br /&gt;&lt;br /&gt;  You need a database for your tables:&lt;br /&gt;&lt;pre class="brush: sql"&gt;CREATE DATABASE zlatozar_test;&lt;br /&gt;&lt;/pre&gt;You have to tell RDBMS which database you are going to use:&lt;pre class="brush: sql"&gt;USE zlatozar_test;&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;And remember SQL is case insensitive!&lt;/b&gt;  Capitalization and underscores help you to program in SQL.&lt;pre class="brush: sql"&gt;CREATE TABLE doughnut_list&lt;br /&gt;  (&lt;br /&gt;  doughnut_name VARCHAR(10),&lt;br /&gt;  doughnut_type VARCHAR(6)&lt;br /&gt;  );&lt;br /&gt;&lt;/pre&gt;Choosing the best matching data type for each column in your table will reduce the size and make  operations on your data faster. You can't recreate an existing table or  database. Here is some basic rules:  &lt;i&gt;1. Break you data up in categories before you create your table. Pay special     attention to the type of data for each column.&lt;/i&gt;  &lt;i&gt;2. TIMESTAMP is usually used to capture the current time. DATETIME is best used     to store a future event.&lt;/i&gt;  &lt;i&gt;3. Check your work with:&lt;/i&gt;&lt;pre class="brush: sql"&gt;DESC doughnut_list;&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;How to delete a table?&lt;/b&gt;&lt;pre class="brush: sql"&gt;DROP TABLE doughnut_list;&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;DROP TABLE&lt;/b&gt; deletes your table and any data in it. Now it is possible to recreate table and put new  categories.  &lt;b&gt;How to insert in a table?&lt;/b&gt;&lt;pre class="brush: sql"&gt;INSERT INTO your_table (col_name1, col_name2, ....)&lt;br /&gt;  VALUES ('val1', 'val2', ....);&lt;br /&gt;&lt;/pre&gt;Values has to be in the same order as the column names. Any value that goes into a &lt;b&gt;VARCHAR, CHAR, DATE,&lt;/b&gt;  or &lt;b&gt;BLOB&lt;/b&gt; column has single quotes around it. &lt;b&gt;DEC&lt;/b&gt; and &lt;b&gt;INT&lt;/b&gt; don't use quotes.  You can insert few columns and leave some out.  &lt;b&gt;NULL&lt;/b&gt; will be inserted for missing. NULL is not zero, it is "nothing" - undefined value.  &lt;b&gt;A column with a NULL value IS NULL, but does not EQUAL NULL!&lt;/b&gt;  &lt;i&gt;A good practice is to avoid it, but how?&lt;/i&gt;  Check what is inserted:&lt;pre class="brush: sql"&gt;SELECT * FROM doughnut_list;&lt;br /&gt;&lt;/pre&gt;- You can control NULL!&lt;pre class="brush: sql"&gt;CREATE TABLE doughnut_list&lt;br /&gt;  (&lt;br /&gt;      doughnut_name VARCHAR(10) NOT NULL,&lt;br /&gt;      doughnut_type VARCHAR(6) NOT NULL&lt;br /&gt;  );&lt;br /&gt;&lt;/pre&gt;- You can add defaults.&lt;pre class="brush: sql"&gt;CREATE TABLE doughnut_list&lt;br /&gt;  (&lt;br /&gt;      doughnut_name VARCHAR(10) NOT NULL,&lt;br /&gt;      doughnut_type VARCHAR(6) NOT NULL,&lt;br /&gt;      doughnut_cost DEC(3, 2) NOT NULL DEFAULT 1.00&lt;br /&gt;  );&lt;br /&gt;&lt;/pre&gt;Using &lt;b&gt;DEFAULT&lt;/b&gt; value fills the empty columns with a specified value.3 SELECT statement ~~~~~~~~~~~~~~~~~~~~~~~3.1 WHERE ==========   We use WHERE clause that five the RDBMS something specific to search for. SELECT well return the rows that match the condition.   The VARCHAR, CHAR, BLOB, DATE and TIME data types needs single quotes.   DEC and INT, no not.   RDBMS will ignore the quotes and treat your DEC and INT values as numbers,   even though the quotes indicate they are text values!   When inserting quotes have to be escaped with *\* or double *'*.   You can specify which columns wish to see. Use '*' to see all.   Use AND, OR for better WHERE condition. We can have more than one AND, OR.  =  equal  &amp;lt;&amp;gt; not equal  &amp;lt;  less than  &amp;gt;  greater than  &amp;lt;= and =&amp;gt;   &lt;b&gt;Exception is NULL!&lt;/b&gt;&lt;pre class="brush: sql"&gt;SELECT drink_name FROM drink_info WHERE calories IS NULL;&lt;br /&gt;&lt;/pre&gt;3.2 LIKE =========   &lt;b&gt;%&lt;/b&gt;  stand-in for any number of unknown character.   LIKE '%CA', any end with CA   &lt;b&gt;_&lt;/b&gt;  stand-in for only one unknown character.   3.3 Selecting ranges =====================   1st  .... WHERE calories &amp;gt; 30 AND calories &amp;lt; 50;   2nd  ... WHERE calories BETWEEN 30 AND 50; (including 30 and 50);3.4 IN =======  ... rating IN ('innovative', 'fabulous');3.5 NOT ========   &lt;b&gt;NOT&lt;/b&gt; lets you negate your results and get the opposite values.4 DELETE and UPDATE ~~~~~~~~~~~~~~~~~~~~~~~~  You can't relay on the rows in the table being in chronological order.  You can't use DELETE to delete the value from a single column or tableful of column.  You can delete every row from the table with:&lt;pre class="brush: sql"&gt;DELETE FROM your_table;&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;Be careful with DELETE, use SELECT first to be sure you will delete the right data.&lt;/b&gt;  You can use UPDATE tho update a single row or multiple rows, depending on the WHERE clause.  Update can replace DELETE/INSERT combination.  UPDATE statements can be used on multiple records in your table. Use them with basic math operations to manipulate your numeric values.5 Importance to be &lt;i&gt;Normal&lt;/i&gt;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  &lt;b&gt;The simpler query the better!&lt;/b&gt;  How you're going to use your data will affect how you set up your table.  Relational database means how the columns relate to each other to describe the thing.  The challenge is to describe the thing using column in a way that makes getting the information out of it easy.  Here is a simple plan:  1. Pick your thing, the one thing you want your table to describe.     (What's the main thing you want your table to be about?)    2. Make a list of the information you need to know about your one thing when you're     know about your one thing when you're using the table.     (How will you use this table?)    3. Using the list, break down the information about your thing into pieces you can use     for organizing your table.     (How can you most easily query this table?)&lt;b&gt;Atomic data: Data is atomic if it's been broken down into smallest piece of data thatcan't or shouldn't be divided.&lt;/b&gt;Simple rules to have atomic data:1. What is the ONE THING your table describes?2. How will you use the table to get at the ONE THING?   (Design your table to be easy to query)3. Do your columns contain atomic data to make your queries short and to the point?&lt;i&gt;TIP: Making your data atomic means breaking it down into the smallest pieces that you needto create an efficient table, not just the smallest possible pieces you can.&lt;/i&gt;Here is the official rules for atomic data:  &lt;b&gt;Rule 1&lt;/b&gt;: A column with atomic data can't have several values of the same type of data in a column.  (You don't have to look for cell information using LAKE)  &lt;b&gt;Rule 2&lt;/b&gt;: A table with atomic data can't have multiple columns with the same  type of data.          teacher    student_1   student_2   student_3           ----------+------------+------------+------------          Zlatozar   Eli          Rosi         Monika      Too many student columns!Making your table NORMAL, means they follow some standard rules, so making your data atomicis the first step in creating a NORMAL table!Benefits of NORMAL tables- Normal tables won't have duplicate data, which will reduce the size of your database.- Faster queries.5.1 1NF ========   Each row of data must contain atomic values.   Each row of data must have a unique identifier, known as Primary Key (no repeating groups of data)   &lt;i&gt;Hm, and what is Primary Key?&lt;/i&gt;   A primary key is a column in you table that makes each record unique.   &lt;b&gt;Primary Key rules:&lt;/b&gt;   &lt;i&gt;- A primary key can't be NULL.&lt;/i&gt;   &lt;i&gt;- The primary key must be given a value when the record is inserted.&lt;/i&gt;   &lt;i&gt;- The primary key must be compact&lt;/i&gt;   &lt;i&gt;- The primary key values can't be changed&lt;/i&gt;   &lt;i&gt;TIP: The best primary key may be a new primary key.&lt;/i&gt;   A key made of two or more columns is known as a &lt;b&gt;COMPOSITE KEY&lt;/b&gt;.   COMPOSITE KEY is a primary key composed of multiple columns, creating a unique key.   &lt;i&gt;TIP:&lt;/i&gt;   SHOW CREATE TABLE my_table_name;   &lt;i&gt;gives you the SQL for table creation and you can use copy paste.&lt;/i&gt;   Try also:&lt;pre class="brush: sql"&gt;SHOW COLUMNS FROM table_name;&lt;br /&gt;  SHOW CREATE DATABASE databse_name;&lt;br /&gt;  SHOW INDEX FROM table_name;&lt;br /&gt;&lt;/pre&gt;Example for table creation that has primary key:&lt;pre class="brush: sql"&gt;CREATE TABLE my_contacts&lt;br /&gt;  (&lt;br /&gt;      contact_id INT NOT NULL AUTO_INCREMENT,&lt;br /&gt;      ............&lt;br /&gt;      PRIMARY KEY (contact_id)&lt;br /&gt;  )&lt;br /&gt;&lt;/pre&gt;You can add primary key with &lt;b&gt;ALTER&lt;/b&gt;. It will add keys to all rows.   6 ALTER ~~~~~~~~~~~~  The &lt;b&gt;ALTER&lt;/b&gt; command allows you to change almost everything in your table without having  to reinsert data. But if you change type of the column to different one, you risk losing  your data.  ALTER TABLE can help you only to improve your table design, nothing more.- Use RENAME&lt;pre class="brush: sql"&gt;ALTER TABLE projects RENAME TO project_list;&lt;br /&gt;&lt;/pre&gt;- Use CHANGE - modify both the name and data type of an existing column&lt;pre class="brush: sql"&gt;ALTER TABLE project_list&lt;br /&gt;  CHANGE COLUMN number proj_id INT NOT NULL AUTO_INCREMENT,&lt;br /&gt;  ADD PRIMARY KEY ('proj_id');&lt;br /&gt;&lt;/pre&gt;You can change more than one column in a single statement.- Use MODIFY - modify the data type or position of an existing column&lt;pre class="brush: sql"&gt;ALTER TABLE project_list&lt;br /&gt;  MODIFY COLUMN proj_desc VARCHAR(120);&lt;br /&gt;&lt;/pre&gt;- Use ADD - add a column to your table - you pick the data type&lt;pre class="brush: sql"&gt;ALTER TABLE my_contacts&lt;br /&gt;  ADD COLUMN contact_id INT NOT NULL AUTO_INCREMENT FIRST,&lt;br /&gt;  ADD PRIMARY KEY (contact_id);&lt;br /&gt;&lt;/pre&gt;FIRST says that the column will be first in the table. Also you can use: AFTER your_column,  BEFORE your_column, SECOND, THIRD and you get the idea ;)- Use DROP - drops a column from your table&lt;pre class="brush: sql"&gt;ALTER TABLE project_table&lt;br /&gt;  DROP COLUMN start_date;&lt;br /&gt;&lt;/pre&gt;Once you've dropped a column, everything that was stored in it is removed too!    &lt;i&gt;TIP: Use SELECT first to see data that you intend to drop.&lt;/i&gt;7 Advanced SELECT ~~~~~~~~~~~~~~~~~~~~~~7.1 CASE =========   The CASE expression combines all the UPDATE statements by checking an existing column's   value against a condition.&lt;pre class="brush: sql"&gt;UPDATE my_table&lt;br /&gt;  SET new_column =&lt;br /&gt;  CASE&lt;br /&gt;  WHEN column1 = somevalue1&lt;br /&gt;  THEN newvalue1&lt;br /&gt;  WHEN column2 = somevalue2&lt;br /&gt;  THEN newvalue2&lt;br /&gt;  ELSE newvalue3&lt;br /&gt;  END;&lt;br /&gt;&lt;/pre&gt;Order matters! Also you can use all ADD and OR combinations in WHEN clause.7.2 ORDER BY =============   If you want to order your query then try ORDER BY. ORDER BY allows you to alphabetically   order any column.&lt;pre class="brush: sql"&gt;SELECT&lt;br /&gt;  ....&lt;br /&gt;  ORDER BY column_name;&lt;br /&gt;&lt;/pre&gt;It is possible to order by two columns. Better, you can sort by as many columns as you need.   Example:&lt;pre class="brush: sql"&gt;SELECT * FROM movie_table&lt;br /&gt;  ORDER BY category, purchased, title;&lt;br /&gt;&lt;/pre&gt;Order by category, then for a particular category order by purchased, and then for a particular purchased film order by title.   (category (purchased (title)))   Use keyword &lt;b&gt;DESC&lt;/b&gt; after your column name in ORDER BY clause to reverse the order of you results.7.3 GROUP BY =============&lt;pre class="brush: sql"&gt;SELECT first_name, SUM(sales)&lt;br /&gt;  FROM cookie_sales&lt;br /&gt;  GROUP BY first_name&lt;br /&gt;  ORDER BY SUM(sales) DESC;&lt;br /&gt;&lt;/pre&gt;Group together all the &lt;i&gt;first_name&lt;/i&gt; values. Imagine that GROUP BY divide the table for every   first_name and then pass every table to the SUM function(see below).   In this way for every name we have the total sales (sum of all sales) from high-to-low.   &lt;i&gt;TIP: Using GROUP BY combines the duplicates into one single value for each group. But be careful this will not work for   tables like this&lt;/i&gt;     Interests         --------------     books, sport       pets, books      *(Hint: Use joins)*7.4 SQL functions ==================   SQL language has some special keywords called functions. Each function is a bit a code   that preform an operation on a value or values.7.4.1 SUM ----------&lt;pre class="brush: sql"&gt;SELECT SUM(sales)&lt;br /&gt;  FROM cookie_sales&lt;br /&gt;  WHERE first_name = 'Nicole';&lt;br /&gt;&lt;/pre&gt;SUM function totals the values in the sales column.7.4.2 AVG, MIN, MAX, COUNT ---------------------------    COUNT will return the number of rows in a column - single number&lt;pre class="brush: sql"&gt;SELECT COUNT(*)&lt;br /&gt;  FROM Student;&lt;br /&gt;&lt;/pre&gt;Return the number of rows in a table.7.5 SELECT DISTINCT ====================&lt;pre class="brush: sql"&gt;SELECT COUNT(DISTINCT sale_data)&lt;br /&gt;  FROM cookie_sales;&lt;br /&gt;&lt;/pre&gt;Result will be one row because of the COUNT.   &lt;b&gt;DISTINCT&lt;/b&gt; is a keyword.7.6 LIMIT ==========   Limits the number of results. Also possible&lt;pre class="brush: sql"&gt;LIMIT 2&lt;br /&gt;  LIMIT 0,4&lt;br /&gt;  LIMIT 1,1&lt;br /&gt;&lt;/pre&gt;8 Multi-table database design ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  &lt;i&gt;TIP: Your table design should do the heavy lifting for you. Don't write convoluted queries  to "get around" a badly designed table. Ignoring the problem isn't the answer.&lt;/i&gt;  We need to thing outside of a single table. How to add another table?  &lt;i&gt;TIP: We need to move the non-atomic columns in our table into new tables!&lt;/i&gt;  A description of the data (the columns and tables) in your database, along with any other related  objects and the way they all connected in known as a SCHEMA.  &lt;i&gt;TIP: Creating a diagram of your table lets you keep the design of the table separate from  the data that's inside of it.&lt;/i&gt;  &lt;b&gt;How to go from one table to two?&lt;/b&gt; Here is the algorithm:  - Remove the column and put it in its own table  - Add columns that will let us identify it.    Example:      my_contacts              interests     -----------------       -----------------      contact_id(pk)           int_id(pk)      last_name                last_name      first_name               first_name                               interests    &lt;b&gt;How to connect tables?&lt;/b&gt; 'first_name' and 'last_name' combination is not unique!          my_contacts              interests     -----------------       -----------------      contact_id(pk)           int_id(pk)      last_name                interests      first_name               contact_id(fk)    &lt;b&gt;contact_id&lt;/b&gt; in interest table is &lt;b&gt;foreign&lt;/b&gt; key!    The FOREIGN KEY is a column in a table that references the PRIMARY KEY of another table!    'contact_id' is unique so we know the reference.    Foreign key facts:&lt;i&gt;  1. A foreign key can have a different name than the primary key it comes from.  2. The primary key used by a foreign key is also known as a PARENT KEY. The table where the     primary key is from is known as a parent table.    3. The foreign key can be used to make sure that the rows in one table have corresponding rows     in another table.    4. Foreign key values can be null, even though primary key values can't.    5. Foreign keys don't have to be unique - in fact, they often aren't.&lt;/i&gt;A NULL foreign key means that there's no matching primary key in the parent table!But we can make sure that a foreign key contains a meaningful value, one that exist in the parent table,by using a CONSTRAINT.Constraint defines rules for relation. Creating a foreign key as a constraint in your table gives youdefinite advantages. You'll get errors if you violate the rules, which will stop you accidentallydoing anything to break the table.&lt;b&gt;Referential integrity:&lt;/b&gt; You will only be able to insert values into your foreign key that existin the table the key came from, the parent table.&lt;i&gt;TIP: You can use a foreign key to reference a unique value in the parent table. It doesn't haveto be the primary key of the parent table, but it must be unique.&lt;/i&gt;&lt;i&gt;TIP: Foreign key could be added with ALTER TABLE.&lt;/i&gt;Example:&lt;pre class="brush: sql"&gt;CREATE TABLE interests&lt;br /&gt;  (&lt;br /&gt;      int_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,&lt;br /&gt;      interest VARCHAR(50) NOT NULL,&lt;br /&gt;      contact_id INT NOT NULL,&lt;br /&gt;      CONSTRAINT my_contacts_contact_id_FK&lt;br /&gt;      FOREIGN KEY (contact_id)&lt;br /&gt;      REFERENCES my_contacts (contact_id);&lt;br /&gt;  )&lt;br /&gt;&lt;/pre&gt;&lt;i&gt;TIP: How to form constraint names? parent_table_foreign_key_name&amp;gt;_FK&lt;/i&gt;There is many types of relation.8.1 ONE-TO-ONE ===============   One-To-One: exactly one row of a parent table is related to one row of a child table.   We used if for example we would like to isolate some data from the parent table.   Advantages:&lt;b&gt;   - Pulling the data out may allow you to write faster queries.   - If you have a column containing values you don't yet know,   you can isolate it and avoid NULL values in your main table.   - You may wish to make some of your data less accessible.   - If you have a large piece of data, a BLOB type for example,   you may want that large data in a separate table.&lt;/b&gt;8.2 ONE-TO-MANY ================   One-to-many: a record in Table A can have MANY matching records in Table B, but a record in Table B   can only match ONE record in Table A.8.3 MANY-TO-MANY =================   Unacceptable! &lt;b&gt;How to fix that?&lt;/b&gt;   We need a table to step in between these two many-to-many tables and simplify the relationship to one-to-many.   We need what is called a &lt;b&gt;JUNCTION TABLE&lt;/b&gt;, which contain the primary key columns of the two tables we want to relate.   In this way we have tow one-to-many relationships.   When a column's data must change when another column's data is modified, the first column   is functionally dependent on the second.   For example if we have table Person with columns name and initials. Initials column is functional dependent   on column name. We say that column initials is &lt;b&gt;dependent column&lt;/b&gt;.   A partial functional dependency means that a non-key column is dependent on some, but not all,   of the columns in a composite primary key.   If in table Person, primary key is SSN and name, initials is partially dependent on name.   If changing any of the non-key columns might cause any of the other columns to change,   you have a transitive dependency.   You can say: when any non-key column is related to any of the other non-key columns.   &lt;b&gt;But how to avoid partial dependency?&lt;/b&gt;   One simple way is to use ID for a primary key. Adding primary key columns to our tables is   helping us achieve 2NF, because the second normal form focuses on how the primary key in a   table relates to data in it.   Your 1NF table is also 2NF if all the columns in table are part of the primary key OR it has   a single column primary key. More strictly here is the rules:&lt;b&gt;   Rule 1: Be in 1NF   Rule 2: Have no partial functional dependencies.&lt;/b&gt;   &lt;i&gt;Tip: Any table with an artificial primary key and no composite primary key is always 2NF.&lt;/i&gt;&lt;b&gt;   Third Normal Form or 3NF:   Rule 1: Be in 2NF   Rule 2: Have no transitive dependencies&lt;/b&gt;   Practical rule for decomposition to 3NF:&lt;b&gt;If A is in functional dependency with B then A is a key in decomposed tables!&lt;/b&gt;Example:table &lt;b&gt;Apply&lt;/b&gt;(SSN, Student_Name, Collage_Name)SSN is in functional dependency with Student_Name =&gt; Create two tables with key SSN, table &lt;b&gt;Student&lt;/b&gt;(SSN, Student_Name)and table &lt;b&gt;Apply&lt;/b&gt;(SSN, Collage_Name).&lt;b&gt;Nirvana, or what is 4NF&lt;/b&gt;&lt;b&gt;   Forth Normal Form or 4NF:   Rule 1: Be in 3NF   Rule 2: Have no multivalued dependencies&lt;/b&gt;Let's explain this with example. Imagen that you have table &lt;b&gt;Apply&lt;/b&gt;(SSN, Student_Name, High_School).It is in 3NF because there is no functional dependencies, but SSN is in &lt;b&gt;multivalued dependencies&lt;/b&gt; with Student_Nameand High_School because it is a key for every Student_Name and High_School combination (Student_Name*High_School - number of conbinations).Practical rule for decomposition to 4NF:&lt;b&gt;If A is in multivalued dependency with B and C then A is a key in decomposed tables!&lt;/b&gt;Example:table &lt;b&gt;Apply&lt;/b&gt;(SSN, Student_Name, High_School)SSN is in multivalued dependency with Student_Name and High_School =&gt; Create two tables with key SSN, table &lt;b&gt;Apply&lt;/b&gt;(SSN, Student_Name)and table &lt;b&gt;HighSchool&lt;/b&gt;(SSN, High_School).9 Start with joins ~~~~~~~~~~~~~~~~~~~~~~~  Because now we have many table and all the information is spread. Using joins we can collect data  easily.9.1 AS =======  Variant 1:&lt;pre class="brush: sql"&gt;CREATE TABLE profession&lt;br /&gt;  (&lt;br /&gt;  id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,&lt;br /&gt;  profession VARCHAR(20)&lt;br /&gt;  ) AS&lt;br /&gt;  SELECT profession FROM my_contacts&lt;br /&gt;  GROUP BY profession&lt;br /&gt;  ORDER BY profession;&lt;br /&gt;&lt;/pre&gt;Variant 2:&lt;pre class="brush: sql"&gt;CREATE TABLE profession AS&lt;br /&gt;  SELECT profession FROM my_contacts&lt;br /&gt;  GROUP BY profession&lt;br /&gt;  ORDER BY profession;&lt;br /&gt;&lt;/pre&gt;&lt;pre class="brush: sql"&gt;ALTER TABLE profession&lt;br /&gt;  ADD COLUMN  id INT(11) NOT NULL AUTO_INCREMENT FIRST,&lt;br /&gt;  ADD PRIMARY KEY (id);&lt;br /&gt;&lt;/pre&gt;In both variants AS is used to references result of a query. It is used also for   name aliases.&lt;pre class="brush: sql"&gt;CREATE TABLE profession&lt;br /&gt;  (&lt;br /&gt;  id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,&lt;br /&gt;  profession VARCHAR(20)&lt;br /&gt;  ) AS&lt;br /&gt;  SELECT profession AS mc_prof FROM my_contacts&lt;br /&gt;  GROUP BY mc_prof&lt;br /&gt;  ORDER BY mc_prof;&lt;br /&gt;&lt;/pre&gt;The alias change the name of the column in result but doesn't change the original   column name in any way. An alias is temporary! Table aliases are also called correlation names.   They are very useful in long queries.  &lt;i&gt;TIP: Some time we can alias without AS:&lt;/i&gt;&lt;pre class="brush: sql"&gt;SELECT profession mc_prof&lt;br /&gt;  FROM my_contacts mc&lt;br /&gt;  GROUP BY mc_prof&lt;br /&gt;  ORDER BY mc_prof;&lt;br /&gt;&lt;/pre&gt;Before we start with joins, let's define simplest join called - Cartesian join, Cartesian product,   cross product. It means join all!   Toys table                             Boys table     toy_id      toy                  boy_id    boy    ---------+----------------      ---------+----------------           1   hula hoop                   1   Zlatko           2   balsa glider                2   Mitko           5   baseball cards     The &lt;b&gt;CROSS JOIN&lt;/b&gt; returns every row from one table crossed with every row from second&lt;pre class="brush: sql"&gt;SELECT t.toy, b.boy&lt;br /&gt;  FROM toys AS t&lt;br /&gt;  CROSS JOIN boys AS b;&lt;br /&gt;&lt;/pre&gt;(or you can just write: SELECT toys.toy, boys.boy FROM toys, boys;)   This join get number of toys multiplied by numbers of boys to account for every possible combination.   &lt;i&gt;TIP: Using CROSS JOIN by mistake you can hanging your machine.&lt;/i&gt;   But why we need CROSS JOIN? Answer is simple, to understand better INNER JOIN.   An INNER JOIN is a CROSS JOIN with some result rows removed by a condition in a query.   Here is the syntax:&lt;pre class="brush: sql"&gt;SELECT some_columns&lt;br /&gt;  FROM table1&lt;br /&gt;  INNER JOIN&lt;br /&gt;  table2&lt;br /&gt;  ON some_condition;&lt;br /&gt;&lt;/pre&gt;An &lt;b&gt;INNER JOIN&lt;/b&gt; combines the records from two tables using comparison operators in a condition.9.2 EQUIJOIN =============   This is a inner joins test for equality.&lt;pre class="brush: sql"&gt;SELECT t.toy, b.boy&lt;br /&gt;  FROM boys&lt;br /&gt;  INNER JOIN&lt;br /&gt;  toys&lt;br /&gt;  ON boys.toy_id = toys.toy_id;&lt;br /&gt;&lt;/pre&gt;9.3 NON-EQUIJOIN =================&lt;pre class="brush: sql"&gt;SELECT t.toy, b.boy&lt;br /&gt;  FROM boys&lt;br /&gt;  INNER JOIN&lt;br /&gt;  toys&lt;br /&gt;  ON boys.toy_id &amp;lt;&amp;gt; toys.toy_id&lt;br /&gt;  ORDER BY boys.boy;&lt;br /&gt;&lt;/pre&gt;9.4 NATURAL JOIN =================   Natural joins only work if the column you're joining by has the same name in both tables.   Toys table                                     Boys table     toy_id      toy                            toy_id       boy    ---------+----------------                ---------+----------------           1   hula hoop                             1   Zlatko           2   balsa glider                          2   Mitko           5   baseball cards  &lt;pre class="brush: sql"&gt;SELECT boys.boy, toys.toy,&lt;br /&gt;  FROM boys&lt;br /&gt;  NATURAL JOIN&lt;br /&gt;  toys;&lt;br /&gt;&lt;/pre&gt;This two tables are joined on 'toy_id' column.   Natural join inner joins identify matching column names.   &lt;i&gt;TIP: You can join more than one table&lt;/i&gt;   The same effect you can achieve using query inside a query - subqueries!10 SUB-QUERIES ~~~~~~~~~~~~~~~~~~~  Simple data base to illustrate the queries:  [Simple database] &lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-s-Sbt9UusNk/TawR3INNszI/AAAAAAAAC2o/jisw1UfFW-8/s1600/simple_database.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="300" src="http://4.bp.blogspot.com/-s-Sbt9UusNk/TawR3INNszI/AAAAAAAAC2o/jisw1UfFW-8/s400/simple_database.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;A subquery is a query that is wrapped within another query. It's also called an INNER query.  Subquery is nothing more than a query inside another query. The outside query is known as  containing query, or outer query. The query on the inside is the inner query, or subquery.  Example 1:&lt;pre class="brush: sql"&gt;SELECT some_column, another_column&lt;br /&gt;  FROM table&lt;br /&gt;  WHERE column = (SELECT column FROM table);&lt;br /&gt;&lt;/pre&gt;Because it use the = operator, this subquery will return a single value, one row from one column  (sometimes called a cell, but in SQL known as a scalar value), which is compared to the  columns in the WHERE clause. If it returns more you'll get an error.  Example 2: JOINS &amp;lt;=&amp;gt; SUBQUERYS&lt;pre class="brush: sql"&gt;SELECT last_name, first_name&lt;br /&gt;  FROM my_contacts&lt;br /&gt;  WHERE zip_code = (SELECT zip_code FROM&lt;br /&gt;  zip_code WHERE city = 'Memphis' AND state = 'TN');&lt;br /&gt;&lt;/pre&gt;is &lt;b&gt;equivalent&lt;/b&gt; to:&lt;pre class="brush: sql"&gt;SELECT last_name, first_name&lt;br /&gt;  FROM my_contacts mc&lt;br /&gt;  NATURAL JOIN zip_code zc&lt;br /&gt;  WHERE zc.city = 'Memphis' AND zc.state = 'TN';&lt;br /&gt;&lt;/pre&gt;&lt;i&gt;TIP: Joins are faster, subquerys are more readable.&lt;/i&gt;  Because subquerys are very verbose it is a good idea to use aliases - column aliases.  Example:&lt;pre class="brush: sql"&gt;SELECT mc.first_name AS firstname, mc.last_name AS lastname,&lt;br /&gt;  mc.phone AS phone, jc.title AS jobtitle&lt;br /&gt;  FROM job_current AS jc&lt;br /&gt;  NATURAL JOIN my_contacts AS mc&lt;br /&gt;  WHERE jobtitle IN (SELECT title FROM job_listings);&lt;br /&gt;&lt;/pre&gt;The tricky part about subqueries isn't the structure; it's figuring out what part of  the query needs to be the subquery. Or even if you need one at all.  Example:  &lt;b&gt;Who make the most money out of all of my contacts?&lt;/b&gt;- Identify a query that answers part of the question.&lt;pre class="brush: sql"&gt;SELECT MAX(salary) FROM job_current;&lt;br /&gt;&lt;/pre&gt;- Continue dissecting your query. We need to select names.&lt;pre class="brush: sql"&gt;SELECT mc.first_name, mc.last_name&lt;br /&gt;  FROM my_contacts AS mc;&lt;br /&gt;&lt;/pre&gt;- Finally, figure out how to link the two.&lt;pre class="brush: sql"&gt;SELECT mc.first_name, mc.last_name, jc.salary&lt;br /&gt;  FROM my_contacts AS mc&lt;br /&gt;  NATURAL JOIN job_current AS jc;&lt;br /&gt;&lt;/pre&gt;- And now add the WHERE clause to link the two&lt;pre class="brush: sql"&gt;SELECT mc.first_name, mc.last_name, jc.salary FROM my_contacts AS mc&lt;br /&gt;  NATURAL JOIN job_current AS jc&lt;br /&gt;  WHERE jc.salary = (SELECT MAX(jc.salary) FROM job_current jc);&lt;br /&gt;&lt;/pre&gt;If a subquery is used as a column expression in a SELECT statement, it can only return one value from one column.&lt;pre class="brush: sql"&gt;SELECT mc.first_name, mc.last_name,&lt;br /&gt;  (SELECT state FROM zip_code WHERE mc.zip_code = zip_code) AS state&lt;br /&gt;  FROM my_contacts mc;&lt;br /&gt;&lt;/pre&gt;If the subquery stands alone and doesn't reference anything form the outerquery, it is a noncorrelated subquery.&lt;pre class="brush: sql"&gt;SELECT mc.first_name, mc.last_name, jc.salary&lt;br /&gt;  FROM my_contacts AS mc&lt;br /&gt;  NATURAL JOIN job_current AS jc&lt;br /&gt;  WHERE jc.salary &amp;gt; (SELECT jc.salary&lt;br /&gt;                  FROM my_contacts mc NATURAL JOIN job_current jc&lt;br /&gt;                  WHERE email = 'some@somedomain.com");&lt;br /&gt;&lt;/pre&gt;In noncorrelated subquery you can use IN or NOT IN to test if the values returned in thesubquery are members of a set (or not). This is possible because noncorrelated subqueries could return more than one column.&lt;pre class="brush: sql"&gt;SELECT mc.first_name, mc.last_name, mc.phone, jc.title&lt;br /&gt;  FROM job_current jc&lt;br /&gt;  NATURAL JOIN my_contacts mc&lt;br /&gt;  WHERE jc.title NOT IN (SELECT title FROM job_listings);&lt;br /&gt;&lt;/pre&gt;A very common use for correlated subqueries is to find all the rows in the outer queryfor which no rows exist in a related table:&lt;pre class="brush: sql"&gt;SELECT mc.first_name firstname, mc.last_name lastname, mc.email email&lt;br /&gt;  FROM my_contacts mc&lt;br /&gt;  WHERE NOT EXIST&lt;br /&gt;  (SELECT * FROM job_current jc&lt;br /&gt;  WHERE mc.contact_id = jc.contact_id);&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;NOT EXIST&lt;/b&gt; finds the first and last names and so on form 'my_contacts' table who are notcurrently listed in the 'job_current' table.&lt;i&gt;TIP: You can use just EXIST&lt;/i&gt;&lt;b&gt;What is the best approach when trying to construct a subquery inside a subquery?&lt;/b&gt;Your best bet is to write little queries for the various parts of the question. Thenlook at them and see how you need to combine them.Also correlated subqueries exist! A correlated subquery means that the inner query relieson the outer query before it can be resolved.Example:  People how have three interests.&lt;pre class="brush: sql"&gt;SELECT mc.first_name, mc.last_name&lt;br /&gt;  FROM my_contacts AS mc&lt;br /&gt;  WHERE 3 = (&lt;br /&gt;           SELECT COUNT(*) FROM contact_interest&lt;br /&gt;           WHERE contact_id = mc.contact_id&lt;br /&gt;           );&lt;br /&gt;&lt;/pre&gt;The outer query has to be executed before we know what the value of 'mc.contact_id' is!Inner query uses the same aliases or correlation name for 'my_contacts'. &lt;b&gt;mc&lt;/b&gt; that was created in the outer query.11 Outer joins, self-joins, and unions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  With an inner join, you're comparing rows from two table, but the order of those  two tables doesn't matter. Outer joins have more to do with the relationship between  two tables than the inner joins.  The &lt;b&gt;LEFT OUTER JOIN&lt;/b&gt; takes all the rows in the left table and maches them to rows  in the left table and matches them to rows in the right table. It is useful when the  left table and the right table have a one-to-many relationship.  The left outer join matches EVERY ROW in the LEFT table with a row from the right table.  The big secret to understanding an outer join is to know which table is on the left and which is  on the right.&lt;pre class="brush: sql"&gt;SELECT t1.column, t2.column&lt;br /&gt;  FROM table1 t1&lt;br /&gt;  LEFT OUTER JOIN table2 t2&lt;br /&gt;  ON t1.table_id = t2.table_id;&lt;br /&gt;&lt;/pre&gt;table1 is the LEFT, table2 is RIGHT. So LEFT table will "say" how many columns result table will have.  The big difference is that an outer join gives you a row whether there's a match with the other  table or not! So then, a NULL value in the results of a left outer join means that the right table  ha NO VALUES that corresponding to the left tables.  The same with the RIGHT OUTER JOIN. The right outer join evaluates the right table against the left  table.  &lt;i&gt;TIP: It will be easier to always stick with one, say the left outer join.&lt;/i&gt;  You can use the same table as both the right and the left table in an outer join - self-join!  &lt;b&gt;But when it will be handy?&lt;/b&gt;  A SELF-REFERENCING foreign key is the primary key of a table used in that same table for another purpose.  The self-referencing part means that it is a key that is referencing another field in the same table.  In tables where we have self-referencing we can use self-join. In this way we simulate having two tables.  The self-join allows you to query a single table as though there were two tables with exactly the  same information in them.11.1 Unions ============   Except JOINS and SUBQUERIES there is another way to get multi-table information - UNIONS.   UNION combines the results of two or more queries into one table, based on what you specify in the   list of the SELECT.   Example:&lt;pre class="brush: sql"&gt;SELECT title FROM job_current&lt;br /&gt;  UNION&lt;br /&gt;  SELECT title FROM job_desired&lt;br /&gt;  UNION&lt;br /&gt;  SELECT title FROM job_available;&lt;br /&gt;&lt;/pre&gt;UNION can take one ORDER BY at the end of the statement. This is because UNION concatenates and   groups the results from the multiple SELECT statements.&lt;pre class="brush: sql"&gt;SELECT title FROM job_current&lt;br /&gt;  UNION&lt;br /&gt;  SELECT title FROM job_desired&lt;br /&gt;  ORDER BY title;&lt;br /&gt;&lt;/pre&gt;Remember that the number of columns in each SELECT statement must match. Also UNION suppresses all   duplicate values from results. If you DO want to see duplicate, you can use operator UNION ALL!&lt;pre class="brush: sql"&gt;SELECT title FROM job_current&lt;br /&gt;  UNION ALL&lt;br /&gt;  SELECT title FROM job_desired&lt;br /&gt;  ORDER BY title;&lt;br /&gt;&lt;/pre&gt;More useful example:&lt;pre class="brush: sql"&gt;CREATE TABLE my_union AS&lt;br /&gt;  SELECT title FROM job_current&lt;br /&gt;  UNION&lt;br /&gt;  SELECT title FROM job_desired;&lt;br /&gt;&lt;/pre&gt;11.2 INTERSECT and EXCEPT ==========================   INTERSECT and EXCEPT are used in much the same way as UNION - to find parts of queries that overlap.   INTERSECT returns only those columns that are in the first query and also in the second query.   EXCEPT returns only those columns that are in the first query, but NOT in the second query.   &lt;i&gt;TIP: This two operations DO NOT EXIST in MySQL.&lt;/i&gt;   &lt;i&gt;TIP: It is a good practice to be consistent. Subqueries and joins are equivalent and if you have started using joins, used all the time. The same is for subqueries usage.&lt;/i&gt;   Using joins and subqueries for self-join   - Join&lt;pre class="brush: sql"&gt;SELECT c1.name, c2.name AS boss&lt;br /&gt;  FROM person_info c1&lt;br /&gt;  INNER JOIN person_info c2&lt;br /&gt;  ON c1.boss_id = c2.id;&lt;br /&gt;&lt;/pre&gt;- Subqueries&lt;pre class="brush: sql"&gt;SELECT c1.name,&lt;br /&gt;  (SELECT name FROM person_info&lt;br /&gt;  WHERE c1.boss_id = id) AS boss&lt;br /&gt;  FROM person_info c1;&lt;br /&gt;&lt;/pre&gt;11.3 A Visual Explanation of SQL Joins =======================================Assume we have the following two tables. Table A is on the left, and Table B is on the right. We'll populate them with four records each.  id name               id  name  -- ----               --  ----  1  &lt;b&gt;Pirate&lt;/b&gt;      1   Rutabaga  2  Monkey             2   &lt;b&gt;Pirate&lt;/b&gt;  3  &lt;b&gt;Ninja&lt;/b&gt;        3   Darth Vader  4  Spaghetti          4   &lt;b&gt;Ninja&lt;/b&gt;Let's join these tables by the name field in a few different ways and see if we can get a conceptual match to those nifty Venn diagrams. &lt;pre class="brush: sql"&gt;SELECT * FROM TableA&lt;br /&gt;  INNER JOIN TableB&lt;br /&gt;  ON TableA.name = TableB.name&lt;br /&gt;&lt;/pre&gt;[Inner Join]&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-h87ctN3Or6Y/TawSRu5ZqxI/AAAAAAAAC2w/x4Y0akqMLvc/s1600/inner_join.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="262" width="400" src="http://2.bp.blogspot.com/-h87ctN3Or6Y/TawSRu5ZqxI/AAAAAAAAC2w/x4Y0akqMLvc/s400/inner_join.png" /&gt;&lt;/a&gt;&lt;/div&gt;id  name       id   name  --  ----       --   ----  1   Pirate     2    Pirate  3   Ninja      4    Ninja&lt;b&gt;Inner join&lt;/b&gt; produces only the set of records that match in both Table A and Table B.&lt;pre class="brush: sql"&gt;SELECT * FROM TableA&lt;br /&gt;  FULL OUTER JOIN TableB&lt;br /&gt;  ON TableA.name = TableB.name&lt;br /&gt;&lt;/pre&gt;id    name            id    name  --    ----            --    ----  1     Pirate          2     Pirate  2     Monkey          null  null  3     Ninja           4     Ninja  4     Spaghetti       null  null  null  null            1     Rutabaga         null  null            3     Darth Vader[Full Outer Join]&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-8rM7xiMj3Lc/TawSZWU9YdI/AAAAAAAAC24/3mMpH8o_HmY/s1600/full_outer_join.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="262" width="400" src="http://1.bp.blogspot.com/-8rM7xiMj3Lc/TawSZWU9YdI/AAAAAAAAC24/3mMpH8o_HmY/s400/full_outer_join.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;b&gt;Full outer join&lt;/b&gt; produces the set of all records in Table A and Table B, with matching records from both sides where available.If there is no match, the missing side will contain null.&lt;pre class="brush: sql"&gt;SELECT * FROM TableA&lt;br /&gt;  LEFT OUTER JOIN TableB&lt;br /&gt;  ON TableA.name = TableB.name&lt;br /&gt;&lt;/pre&gt;id  name             id    name  --  ----             --    ----  1   Pirate           2     Pirate  2   Monkey           null  null  3   Ninja            4     Ninja  4   Spaghetti        null  null[Left Outer Join]&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-eEAkDYuIIdM/TawSh1UdmdI/AAAAAAAAC3A/b7kDAUXSExY/s1600/left_outer_join.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="262" width="400" src="http://3.bp.blogspot.com/-eEAkDYuIIdM/TawSh1UdmdI/AAAAAAAAC3A/b7kDAUXSExY/s400/left_outer_join.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;b&gt;Left outer join&lt;/b&gt; produces a complete set of records from Table A, with the matching records (where available) in Table B.If there is no match, the right side will contain null.&lt;pre class="brush: sql"&gt;SELECT * FROM TableA&lt;br /&gt;  LEFT OUTER JOIN TableB&lt;br /&gt;  ON TableA.name = TableB.name&lt;br /&gt;  WHERE TableB.id IS null&lt;br /&gt;&lt;/pre&gt;id  name            id     name  --  ----            --     ----  2   Monkey          null   null  4   Spaghetti       null   null[Exclude Right Side]&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-reQ4AH_axwA/TawSsZH56YI/AAAAAAAAC3I/9G1LQwY_Wtk/s1600/exclude_right_side.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="262" width="400" src="http://1.bp.blogspot.com/-reQ4AH_axwA/TawSsZH56YI/AAAAAAAAC3I/9G1LQwY_Wtk/s400/exclude_right_side.png" /&gt;&lt;/a&gt;&lt;/div&gt;To produce the set of records only in Table A, but not in Table B, we perform the same left outer join, then &lt;b&gt;exclude the records we don't want from the right side via a where clause.&lt;/b&gt;&lt;pre class="brush: sql"&gt;SELECT * FROM TableA&lt;br /&gt;  FULL OUTER JOIN TableB&lt;br /&gt;  ON TableA.name = TableB.name&lt;br /&gt;  WHERE TableA.id IS null &lt;br /&gt;  OR TableB.id IS null&lt;br /&gt;&lt;/pre&gt;id    name          id    name  --    ----          --    ----  2     Monkey        null  null  4     Spaghetti     null  null  null  null          1     Rutabaga  null  null          3     Darth Vader[Exclude Both Sides]&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-EBuTphI7r4Y/TawSy3V-jbI/AAAAAAAAC3Q/4ZX-EA7i-Ys/s1600/exlude_both_sides.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="262" width="400" src="http://4.bp.blogspot.com/-EBuTphI7r4Y/TawSy3V-jbI/AAAAAAAAC3Q/4ZX-EA7i-Ys/s400/exlude_both_sides.png" /&gt;&lt;/a&gt;&lt;/div&gt;To produce the set of records unique to Table A and Table B, we perform the same full outer join, then &lt;b&gt;exclude the records we don't want from both sides via a where clause.&lt;/b&gt;There's also a cartesian product or cross join, which as far as I can tell, can't be expressed as a Venn diagram:&lt;pre class="brush: sql"&gt;SELECT * FROM TableA&lt;br /&gt;  CROSS JOIN TableB&lt;br /&gt;&lt;/pre&gt;This joins "everything to everything", resulting in 4 x 4 = 16 rows, far more than we had in the original sets. If you do the math, you can see why this is a very dangerous join to run against large tables.12 Constraints, views, and transactions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~12.1 Adding CHECK CONSTRAINT =============================   A constraint is a restriction on what you can insert into a column. Constraints are added when we   create a table. Some of the constraints we've already seen include NOT   NULL, PRIMARY KEY, FOREIGN KEY, and UNIQUE.      There's another sort of column constraint, called a CHECK.      A CHECK constraint restrict what values you can insert into a column. It uses the same conditionals as WHERE clause.   Example:&lt;pre class="brush: sql"&gt;CREATE TABLE piggy_bank&lt;br /&gt;  (&lt;br /&gt;      id INT AUTO_INCREMENT NOT NULL PRIMARY KEY,&lt;br /&gt;      coin CHAR(1) CHECK (coin IN ('P', 'N', 'D', 'Q'))&lt;br /&gt;  )&lt;br /&gt;&lt;/pre&gt;If the value you're trying to insert fails the CHECK condition, you get an error.   &lt;i&gt;TIP: CHECK doesn't enforce data integrity in MySQL. In MySQL you can work around it with triggers.&lt;/i&gt;12.2 Views ===========   If you have a long an complex query that you have to run constantly you can crate a view. Creating   view is really simple:&lt;pre class="brush: sql"&gt;CREATE VIEW web_designers AS&lt;br /&gt;  SELECT mc.first_name, mc_last_name, mc_phone&lt;br /&gt;  FROM my_contacts mc&lt;br /&gt;  NATURAL JOIN job_desired jd&lt;br /&gt;  WHERE jd.title = 'Web Designer';&lt;br /&gt;&lt;/pre&gt;Instead of CREATE TABLE you write CREATE VIEW. Then you treat is as table:&lt;pre class="brush: sql"&gt;SELECT * FROM web_designers;&lt;br /&gt;&lt;/pre&gt;&lt;i&gt;TIP: When you actually use your view in a query, it's behaving as though it were a subquery.&lt;/i&gt;   Let's dissect SELECT query. What it says is "Select everything from the subquery that returns the   first/last name and phone of all the people from 'my_contacts' who are looking for a job as web designer". In code this looks like this:&lt;pre class="brush: sql"&gt;SELECT * FROM (SELECT mc.first_name, mc.last_name, mc.phone&lt;br /&gt;                FROM my_contacts mc&lt;br /&gt;                NATURAL JOIN job_desired jd&lt;br /&gt;                WHERE jd.title = 'Web Designer') AS web_designers;&lt;br /&gt;&lt;/pre&gt;(We gave a name to our subquery - web_designers)   A VIEW is basically a table that only exist when you use the view in a query. It's considered a   virtual table because it acts like a table, and some operations that can be performed on a table   can be preformed on a view.   &lt;i&gt;TIP: Virtual table doesn't stay in the database. It gets created when we use the view and then deleted.&lt;/i&gt;   &lt;b&gt;Why views are good for your database?&lt;/b&gt;&lt;i&gt;   1. You can keep changes to your database structure from breaking applications that depend on your tables.   2. Views make your life easier bey simplifying you complex query into a simple command.   3. You can create views that hide information that isn't needed by the user.&lt;/i&gt;&lt;b&gt;Is it possible to inserting, updating, and deleting with views?&lt;/b&gt;Yes, but it depends. If your view used aggregate values (like SUM, COUNT, and AVG), you won't beable to use it to change data. Also, if your view contains GROUP BY, DISTINCT, or HAVING, it won'tchange data either. Most of the time it might be easier to INSERT, UPDATE, and DELETE the old-fashioned way.&lt;i&gt;TIP: CHECK OPERATION checks each query you try to INSERT or UPDATE to see if it's allowed according to the   WHERE clause in your view&lt;/i&gt;An updatable view is a view that allows you to change the underlying tables. The important pointhere is that an updatable view includes all the NOT NULL columns form the tables it references.That way, when you INSERT using view, you can be certain that you will have a value for every columnyou required to have a value in. The opposite for non-updatable views, it includes all the NOT NULLcolumns.When you're finished with your view, just drop it.&lt;pre class="brush: sql"&gt;DROP VIEW view_name;&lt;br /&gt;&lt;/pre&gt;&lt;i&gt;TIP: CHECK constraints and views both help maintain control when you have multiple users.&lt;/i&gt;12.3 Transaction =================   A transaction is a set of SQL statements that accomplish a single unit of work.   During a transaction, if all the steps can't be completed without interference, none of them   should be completed.   &lt;b&gt;What is ACID?&lt;/b&gt;   Atomicity: All of the pieces of the transaction must be completed, or none of them will be completed.   Consistency: A complete transaction leaves the database in a consistent state at the end of the transaction.   Isolation: It means that every transaction has a consistent view of the database regardless of other   transactions taking place at the same time.   Durability: After the transaction, the database needs to save the data correctly and protect it   from power outages or other threads.   Example:&lt;pre class="brush: sql"&gt;START TRANSACTION;&lt;br /&gt;  ........&lt;br /&gt;  /* START TRANSACTION keeps track of all the SQL that follows until you enter either&lt;br /&gt;  COMMIT or ROLLBACK */&lt;br /&gt;  .......&lt;br /&gt;  COMMIT;&lt;br /&gt;&lt;/pre&gt;&lt;i&gt;TIP: No changes will occur to the database until you COMMIT.&lt;/i&gt;   &lt;b&gt;What is storage engine?&lt;/b&gt;   Storage engine is the behind-the-scenes structure that stores all your database data and structures.   Some types allows transaction; some types do not, but they are faster.      &lt;i&gt;TIP: For MySQL you need make sure your storage engine is either BDB of InnoDB, the two choices      that support transactions.&lt;/i&gt;      RDBMS keeps a record of everything that has been done when you are inside a transaction. It's   called transaction log, and it keeps getting bigger and bigger the more you do in transaction.   It's best to save using transactions for when you really need to be able to undo what you're   doing to avoid wasting space and making your RDBMS faster.13 Security ~~~~~~~~~~~~~~~~~  See your database documentation.  &lt;i&gt;TIP: You can control exactly what users can do to tables and columns with the GRANT statement.&lt;/i&gt;  Example:&lt;pre class="brush: sql"&gt;GRANT SELECT ON my_contacts TO programmer;&lt;br /&gt;&lt;/pre&gt;If you decide to remove privilege you need REVOKE.  Example:&lt;pre class="brush: sql"&gt;REVOKE SELECT ON my_contacts FROM programmer;&lt;br /&gt;&lt;/pre&gt;There is a lot details here but they are more for database administrators, that's why we just skip them.&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14240039-5274137755592707529?l=zlatozar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zlatozar.blogspot.com/feeds/5274137755592707529/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14240039&amp;postID=5274137755592707529' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/5274137755592707529'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/5274137755592707529'/><link rel='alternate' type='text/html' href='http://zlatozar.blogspot.com/2011/04/sql-crash-course-1-databasebefore-you.html' title='SQL crash course'/><author><name>Zlatozar</name><uri>http://www.blogger.com/profile/16257250071061885492</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/17/6760/640/RabotnotoMqsto.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-s-Sbt9UusNk/TawR3INNszI/AAAAAAAAC2o/jisw1UfFW-8/s72-c/simple_database.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14240039.post-2897970731326780359</id><published>2011-03-02T18:59:00.004+02:00</published><updated>2011-11-24T14:43:57.701+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Lisp'/><category scheme='http://www.blogger.com/atom/ns#' term='emacs'/><title type='text'>Advanced Emacs Commands</title><content type='html'>&lt;pre style="color: #111111; font-size: 10pt;"&gt;&lt;h2&gt;Common default Emacs key prefixes&lt;/h2&gt;&lt;b&gt;Key prefix      Description&lt;/b&gt;&lt;br /&gt;C-c             Commands particular to the current editing mode&lt;br /&gt;C-x             Commands for files and buffers&lt;br /&gt;C-h             Help commands&lt;br /&gt;M-x             Literal function name&lt;br /&gt;C-h b           Show key bindings&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Emacs window-manipulation commands&lt;/h2&gt;&lt;b&gt;Key               Function                   Description&lt;/b&gt;&lt;br /&gt;C-x 4 f           find-file-other-window     Open a new file in a new buffer, drawing it in a new vertical&lt;br /&gt;                                             window.&lt;br /&gt;&lt;br /&gt;undefined         scroll-all-mode            Toggle the scroll-all minor mode. When it's on, all windows&lt;br /&gt;                                             displaying the buffer in the current window are scrolled &lt;br /&gt;                                             simultaneously and in equal, relative amounts.&lt;br /&gt;&lt;br /&gt;C-x 3    split-window-horizontally           Split the current window in half down the middle, stacking the new&lt;br /&gt;                                             buffers horizontally.&lt;br /&gt;&lt;br /&gt;undefined         follow-mode                Toggle follow, a minor mode. When it's on in a buffer, all windows&lt;br /&gt;                                             displaying the buffer are connected into a large virtual window.&lt;br /&gt;&lt;br /&gt;C-x ^             enlarge-window             Make the current window taller by a line; preceded by a negative,&lt;br /&gt;                                             this makes the current window shorter by a line.&lt;br /&gt;&lt;br /&gt;C-x }   shrink-window-horizontally           Make the current active window thinner by a single column.&lt;br /&gt;&lt;br /&gt;C-x {   enlarge-window-horizontally          Make the current active window wider by a single column.&lt;br /&gt;&lt;br /&gt;C-x -   shrink-window-if-larger-than-buffer  Reduce the current active window to the smallest possible size for&lt;br /&gt;                                             the buffer it contains.&lt;br /&gt;&lt;br /&gt;C-x +            balance-windows             Balance the size of all windows, making them approximately equal.&lt;br /&gt;&lt;br /&gt;undefined        compare-windows             Compare the current window with the next window, beginning with&lt;br /&gt;                                             point in both windows and moving point in both buffers to the&lt;br /&gt;                                             first character that differs until reaching the end of the buffer.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Emacs text manipulation commands&lt;/h2&gt;&lt;b&gt;Key              Function                    Description&lt;/b&gt;&lt;br /&gt;C-x Tab          indent-rigidly              This command indents lines in the region (or at point).&lt;br /&gt;&lt;br /&gt;undefined        fill-region                 This command fills all paragraphs in the region.&lt;br /&gt;&lt;br /&gt;M-q              fill-paragraph              This command fills the single paragraph at point.&lt;br /&gt;&lt;br /&gt;M-\              delete-horizontal-space     This command removes any horizontal space to the right and left of&lt;br /&gt;                                             point.&lt;br /&gt;&lt;br /&gt;C-o              open-line                   This command opens a new line of vertical space below point,&lt;br /&gt;                                             without moving point.&lt;br /&gt;&lt;br /&gt;C-t              transpose-chars             This command transposes the single characters to the right and&lt;br /&gt;                                             left of point.&lt;br /&gt;&lt;br /&gt;M-t              transpose-words             This command transposes the single words to the right and left of &lt;br /&gt;                                             point.&lt;br /&gt;&lt;br /&gt;C-x C-t          transpose-lines             This command transposes the line at point with the line before it.&lt;br /&gt;&lt;br /&gt;M-^              delete-indentation          This command joins the line at point with the previous line.&lt;br /&gt;&lt;b&gt;Preface with C-1 to join the line at point with the next line (C-1 M-^)&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;M-u              uppercase-word              This command converts the text at point to the end of the word to&lt;br /&gt;                                             uppercase letters.&lt;br /&gt;&lt;br /&gt;M-l              downcase-word               This command converts the text at point to the end of the word to &lt;br /&gt;                                             lowercase letters.&lt;br /&gt;&lt;br /&gt;C-x C-l          downcase-region             This command converts the region to lowercase letters.&lt;br /&gt;&lt;br /&gt;C-x C-u          upcase-region               This command converts the region to uppercase letters.&lt;br /&gt;&lt;br /&gt;M-m              back-to-indentation         This command, given anywhere on a line, positions point at the &lt;br /&gt;                                             first non blank character on the line. &lt;br /&gt;&lt;br /&gt;C-s C-w                                      This command, add the (rest of the) word at the pointer for &lt;b&gt;search&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Emacs commands for using registers&lt;/h2&gt;Emacs registers are general-purpose storage mechanisms that can store one of many things, including text,&lt;br /&gt;a rectangle, a position in a buffer, or some other value or setting. Every register has a label, which is&lt;br /&gt;a single character that you use to reference it.&lt;br /&gt;&lt;br /&gt;A register can be redefined, but it can contain only one thing at a time. Once you exit Emacs, all registers&lt;br /&gt;are cleared.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Key               Function                   Description&lt;/b&gt;&lt;br /&gt;C-x r space X     point-to-register          Save point to register named X.&lt;br /&gt;&lt;br /&gt;C-x r s X         copy-to-register           Save the region to register named X.&lt;br /&gt;&lt;br /&gt;C-x r r X         copy-rectangle-to-register Save the selected rectangle to register named X.&lt;br /&gt;&lt;br /&gt;undefined         view-register              View the contents of a given register.&lt;br /&gt;&lt;br /&gt;C-x r j X         jump-to-register           Move point to the location given in register named X.&lt;br /&gt;&lt;br /&gt;C-x r i X         insert-register            Insert the contents of register named X at point.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Emacs commands for using bookmarks&lt;/h2&gt;Emacs has another facility for saving positions in buffers. These Emacs bookmarks work the same as registers,&lt;br /&gt;but their labels can be longer than a single character, and they're more permanent: &lt;b&gt;If you save them, you &lt;br /&gt;can use them between sessions.&lt;/b&gt; They persist until you remove them. As their name implies, bookmarks are &lt;br /&gt;handy for saving your position in a buffer so that you can return to it at a later time, most often during a &lt;br /&gt;later Emacs session.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Key               Function                   Description&lt;/b&gt;&lt;br /&gt;C-x r m Bookmark  bookmark-set               Set a bookmark named Bookmark.&lt;br /&gt;&lt;br /&gt;C-x r l           bookmarks-bmenu-list       List all saved bookmarks.&lt;br /&gt;&lt;br /&gt;undefined         bookmark-delete            Delete a bookmark.&lt;br /&gt;&lt;br /&gt;C-x r b Bookmark  bookmark-jump              Jump to the location set in the bookmark named Bookmark.&lt;br /&gt;&lt;br /&gt;undefined         bookmark-save              Save all bookmarks to the bookmark file, &lt;b&gt;~/.emacs.bmk.&lt;/b&gt;&lt;br /&gt;                                             (you can redefine it)&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Emacs commands for using rectangles&lt;/h2&gt;Did you ever wish you could select a box of text from a document for copying, killing, or yanking purposes?&lt;br /&gt;You can. In Emacs, a selection of text specified by any two opposite of its four corners is called a rectangle.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Key               Function                   Description&lt;/b&gt;&lt;br /&gt;C-space           set-mark-command           Marks one corner of a rectangle (point marks the opposite corner).&lt;br /&gt;&lt;br /&gt;C-x r k           kill-rectangle             Kills the current rectangle and saves it in a special rectangle &lt;br /&gt;                                             buffer.&lt;br /&gt;&lt;br /&gt;C-x r d           delete-rectangle           Deletes the current rectangle and doesn't save it for yanking.&lt;br /&gt;&lt;br /&gt;C-x r c           clear-rectangle            Clears the current rectangle, replacing the entire &lt;br /&gt;                                             area with whitespace.&lt;br /&gt;&lt;br /&gt;C-x r o           open-rectangle             Opens the current rectangle, filling the entire area with &lt;br /&gt;                                             whitespace  and moving all text from the rectangle to the right.&lt;br /&gt;&lt;br /&gt;C-x r y           yank-rectangle             Yanks the contents of the last-killed rectangle at point, moving &lt;br /&gt;                                             all existing text to the right.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Mark rings&lt;/h2&gt;You should never have to scroll around randomly in a buffer to find &lt;b&gt;"that place you were just looking at"&lt;/b&gt;. &lt;br /&gt;Whenever you take a diversion (e.g. by searching, or pressing M-&amp;lt;  or M-&amp;gt;), Emacs uses the mark to save &lt;br /&gt;your previous position, kind of like sticking your finger behind one page of a book while you go to glance at &lt;br /&gt;another page. You can return to the mark with &lt;b&gt;C-x C-x&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;However, Emacs saves up to &lt;b&gt;16&lt;/b&gt; previous values of the mark, and you can jump to previous ones with &lt;b&gt;C-u C-SPC&lt;/b&gt;. &lt;br /&gt;This makes mark and the mark ring a valuable navigation tool. You can use it somewhat mindlessly:&lt;br /&gt;&lt;b&gt;if you ever find yourself asking "where was I just now?" you can often just press &lt;b&gt;C-u C-SPC&lt;/b&gt; until you&lt;br /&gt;find yourself back in the right place.&lt;/b&gt;&lt;br /&gt;  &lt;br /&gt;&lt;h2&gt;Programming&lt;/h2&gt;&lt;b&gt;Key                 Function                   Description&lt;/b&gt;&lt;br /&gt;M-x                 check-parens               Checking for unmatched parentheses&lt;br /&gt;C-x w h REGEXP FACE                            Highlight matches of pattern REGEXP in current buffer with FACE.&lt;br /&gt;&lt;br /&gt;C-x w p PHRASE FACE                            Highlight matches of phrase PHRASE in current buffer with FACE.&lt;br /&gt;                                               (PHRASE can be any REGEXP, but spaces will be replaced by matches&lt;br /&gt;                                               to whitespace and initial lower-case letters will become case &lt;br /&gt;                                               insensitive.)&lt;br /&gt;&lt;br /&gt;C-x w l REGEXP FACE                            Highlight lines containing matches of REGEXP in current buffer &lt;br /&gt;                                               with FACE.&lt;br /&gt;&lt;br /&gt;C-x w r REGEX                                  Remove highlighting on matches of REGEXP in current buffer&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Tips:&lt;/b&gt;&lt;br /&gt;C-SPC                                          Make mark in some place and then disable it with &lt;b&gt;C-g&lt;/b&gt;&lt;br /&gt;                                               Go somewhere else and do it again and again etc.&lt;br /&gt;C-u C-SPC                                      Back to previous mark, and back and back etc.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Highlighting Regexps, Phrases, And Lines&lt;/h2&gt;&lt;b&gt;Key        Function                          Description&lt;/b&gt;&lt;br /&gt;M-s h p    highlight-phrase                  It will ask you for a phrase and highlighting color and then highlight&lt;br /&gt;                                             all the matching phrases in the buffer.&lt;br /&gt;M-s h r    highlight-regexp                  Highlight anything that matches an arbitrary regexp&lt;br /&gt;M-s h l    highlight-lines-matching-regexp   Highlights the entire line that contains the match to the regular expression&lt;br /&gt;M-s h u    unhighlight-regexp                Un-highlight the matches&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Useful references:&lt;/b&gt;&lt;br /&gt;&lt;a href="http://www.cb1.com/%7Ejohn/computing/emacs/beyond-tutorial.html"&gt;Beyond Emacs Tutorial&lt;/a&gt;&lt;br /&gt;&lt;a href="http://wttools.sourceforge.net/emacs-stuff/emacs-keybindings.html"&gt;Reference Card&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14240039-2897970731326780359?l=zlatozar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zlatozar.blogspot.com/feeds/2897970731326780359/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14240039&amp;postID=2897970731326780359' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/2897970731326780359'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/2897970731326780359'/><link rel='alternate' type='text/html' href='http://zlatozar.blogspot.com/2011/03/advanced-emacs-commands.html' title='Advanced Emacs Commands'/><author><name>Zlatozar</name><uri>http://www.blogger.com/profile/16257250071061885492</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/17/6760/640/RabotnotoMqsto.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14240039.post-700546364895304694</id><published>2011-02-25T12:32:00.014+02:00</published><updated>2011-04-05T16:14:45.190+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='source control'/><title type='text'>Mercurial for team members collaboration</title><content type='html'>&lt;pre style="color: #111111; font-size: 10pt"&gt;В моя екип често се налага да се работи от двама или трима за реализация на нова фукционалност.&lt;br /&gt;&lt;br /&gt;Фирмата политика е да се ползва Subversion, така че за да се обмени временен код е необходимо&lt;br /&gt;да се миние през "централния" Subversion, да се обменят файлове или patches.&lt;br /&gt;Това може и да сработи ако са двама човека, но става много по-трудно ако са повече. Да не говорим, че по този начин много лесно се пополират бъгове.&lt;br /&gt;Затова погледахме към дистрибутивните системи за версии (DVCS), каквито са Git и Mercurial.&lt;br /&gt;Каква ни беше целта?&lt;br /&gt;&lt;b&gt;&lt;br /&gt;1. Лесно да обменяме промени в кода.&lt;br /&gt;2. Лесно да поправяме кода на другия&lt;br /&gt;3. Лесен merge&lt;br /&gt;4. Работа от вкъщи&lt;br /&gt;5. В Subversion да отиват само неща, които са напълно завършени.&lt;br /&gt;6. QA екипа да може да взема временен код от всеки от нас.&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Да, това е възможно. Mercurial ни се видя по-интуитивен и затова избрахме него.&lt;br /&gt;Ето и инфраструктурата, която направихме.&lt;br /&gt;&lt;br /&gt;1. Направихме клон на Subversion проекта с &lt;a href="https://bitbucket.org/durin42/hgsubversion/wiki/Home"&gt;hgsubversion&lt;/a&gt; и го кръстихме &lt;b&gt;Develop&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;На определен за целта сървър инсталираме Mercurial и правим потребител с това име.&lt;br /&gt;В неговата директория &lt;b&gt;.hgrc&lt;/b&gt; конфигурирана ето така:&lt;br /&gt;&lt;pre  class="brush: plain"&gt;[ui]&lt;br /&gt;username = Mercurial Administrator  (mercurial@example.com)&lt;br /&gt;merge = internal:merge&lt;br /&gt;&lt;br /&gt;[auth]&lt;br /&gt;project.prefix = url to Subversion repository&lt;br /&gt;project.username = subversion user name&lt;br /&gt;project.password = subversion user password&lt;br /&gt;&lt;br /&gt;[web]&lt;br /&gt;contact = develop_admin@example.com&lt;br /&gt;description = Develop Mercurial Repository&lt;br /&gt;style = gitweb&lt;br /&gt;allow_archive = bz2 gz&lt;br /&gt;allow_push = *&lt;br /&gt;push_ssl = false&lt;br /&gt;&lt;br /&gt;[alias]&lt;br /&gt;tip = log -r tip&lt;br /&gt;. = summary&lt;br /&gt;&lt;br /&gt;[extensions]&lt;br /&gt;pretxnchangegroup.forbid_2heads = path to where "forbid_2head.py" is located&lt;br /&gt;fetch =&lt;br /&gt;rebase =&lt;br /&gt;bookmarks =&lt;br /&gt;progress =&lt;br /&gt;color =&lt;br /&gt;hgext.mq =&lt;br /&gt;hgext.extdiff =&lt;br /&gt;hgext.graphlog =&lt;br /&gt;hgsubversion = path to where hgsubversion was build&lt;br /&gt;&lt;br /&gt;[defaults]&lt;br /&gt;diff = --unified 5&lt;br /&gt;cdiff = -q&lt;br /&gt;commit = -v&lt;br /&gt;&lt;br /&gt;[diff]&lt;br /&gt;git=True&lt;br /&gt;showfunc = 1&lt;br /&gt;unified = 8&lt;br /&gt;&lt;br /&gt;[extdiff]&lt;br /&gt;cmd.cdiff = colordiff&lt;br /&gt;opts.cdiff = -uprN&lt;br /&gt;&lt;br /&gt;[bookmarks]&lt;br /&gt;track.current = True&lt;br /&gt;&lt;br /&gt;[hooks]&lt;br /&gt;changegroup=hg diff --stat -r $HG_NODE -r tip&lt;br /&gt;# Prevent "hg pull" if MQ patches are applied.&lt;br /&gt;prechangegroup.mq-no-pull = ! hg qtop &gt; /dev/null 2&gt;&amp;1&lt;br /&gt;# Prevent "hg push" if MQ patches are applied.&lt;br /&gt;preoutgoing.mq-no-push = ! hg qtop &gt; /dev/null 2&gt;&amp;1&lt;br /&gt;# Prevent "hg update" if MQ patches are applied.&lt;br /&gt;preupdate.mq-no-update = ! hg qtop &gt; /dev/null 2&gt;&amp;1&lt;br /&gt;&lt;/pre&gt;Няколко неща трябва да бъдат инсталирани - colordiff и &lt;a href="http://mercurial.selenic.com/wiki/HgSubversion"&gt;hgsubversion&lt;/a&gt;. За да "сервира" нещата не използаме вградения сервер в Mercurial, а пускаме Apache. Подобна конфигурация може да видите &lt;a href="http://mercurial.selenic.com/wiki/PublishingRepositories#single"&gt;тук&lt;/a&gt;Картинката изглежда ето така:&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-v14C66a2eyk/TZsVswkv25I/AAAAAAAAC2g/FGDPYGNiL_I/s1600/Branching_Model.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="400" width="300" src="http://4.bp.blogspot.com/-v14C66a2eyk/TZsVswkv25I/AAAAAAAAC2g/FGDPYGNiL_I/s400/Branching_Model.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;b&gt;Master&lt;/b&gt; всъшност е Subversion trunk. По този начин избягваме неприятнатa операция &lt;b&gt;merge&lt;/b&gt;през Subversion. От тук нататък всичко става в Mercurial и само готови и проверени неща отиват в Subversion. Много много важно нещо да не забравя да кажа - &lt;b&gt;Master&lt;/b&gt;  не трябва да има "разклонения" т.е. трябва да се забрани "dual head". За целта слагаме &lt;a href="http://hg.netbeans.org/nb-hooks/file/7a9c59b644c6/forbid_2head.py"&gt;"forbid_2head.py"&lt;/a&gt;2. Всеки от екипа прави клониниг от &lt;b&gt;Develop&lt;/b&gt;Ето как изглежда работата ни:&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-27jlSVfgB_s/TZsU33UT8NI/AAAAAAAAC2Q/DFHZjRpXHnw/s1600/Team_Collaboration.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="298" width="400" src="http://4.bp.blogspot.com/-27jlSVfgB_s/TZsU33UT8NI/AAAAAAAAC2Q/DFHZjRpXHnw/s400/Team_Collaboration.png" /&gt;&lt;/a&gt;&lt;/div&gt;За целта всеки от нас си настройва локален Mercurial сървър.&lt;pre  class="brush: plain"&gt;[ui]&lt;br /&gt;username = zlatozar (zlatozar@example.com)&lt;br /&gt;&lt;br /&gt;[alias]&lt;br /&gt;tip = log -r tip&lt;br /&gt;. = summary&lt;br /&gt;, = glog -l15 --template '\033[33;40m{rev} \033[37;40m{desc|firstline|fill68} \033[1;30;40m({date|age} by {author|person})\033[0;37;40m \033[33;40m{tags}\033[37;40m \033[35;40m{branches}\033[37;40m\n\n'&lt;br /&gt;&lt;br /&gt;[web]&lt;br /&gt;contact = zlatozar@example.com&lt;br /&gt;description = Zlatozar's Public Repository&lt;br /&gt;style = gitweb&lt;br /&gt;#allow_push = *&lt;br /&gt;push_ssl = false&lt;br /&gt;allow_archive = bz2 gz&lt;br /&gt;&lt;br /&gt;[extensions]&lt;br /&gt;fetch =&lt;br /&gt;rebase =&lt;br /&gt;bookmarks =&lt;br /&gt;progress =&lt;br /&gt;color =&lt;br /&gt;hgext.mq =&lt;br /&gt;hgext.extdiff =&lt;br /&gt;hgext.graphlog =&lt;br /&gt;&lt;br /&gt;[defaults]&lt;br /&gt;diff = --unified 5&lt;br /&gt;cdiff = -q&lt;br /&gt;commit = -v&lt;br /&gt;&lt;br /&gt;[diff]&lt;br /&gt;git=True&lt;br /&gt;showfunc = 1&lt;br /&gt;unified = 8&lt;br /&gt;&lt;br /&gt;[extdiff]&lt;br /&gt;cmd.kdiff3 =&lt;br /&gt;&lt;br /&gt;[bookmarks]&lt;br /&gt;track.current = True&lt;br /&gt;&lt;br /&gt;[merge-tools]&lt;br /&gt;kdiff3.args = $base $local $other -o $output&lt;br /&gt;&lt;br /&gt;[hooks]&lt;br /&gt;changegroup=hg diff --stat -r $HG_NODE -r tip&lt;br /&gt;# Prevent "hg pull" if MQ patches are applied.&lt;br /&gt;prechangegroup.mq-no-pull = ! hg qtop &gt; /dev/null 2&gt;&amp;1&lt;br /&gt;# Prevent "hg push" if MQ patches are applied.&lt;br /&gt;preoutgoing.mq-no-push = ! hg qtop &gt; /dev/null 2&gt;&amp;1&lt;br /&gt;# Prevent "hg update" if MQ patches are applied.&lt;br /&gt;preupdate.mq-no-update = ! hg qtop &gt; /dev/null 2&gt;&amp;1&lt;br /&gt;&lt;/pre&gt;На локалната машина трябва да се инсталира - mercurial, colordiff и kdiff3.3. Всеки от екипа има публично хранилище, от което може да се вземат промените.Скрипта, с който всеки си пуска сървъра е следния:&lt;pre  class="brush: shell"&gt;#!/bin/sh&lt;br /&gt;#&lt;br /&gt;# Startup script for local mercurial server&lt;br /&gt;#&lt;br /&gt;APP_BIN=/usr/bin/hg&lt;br /&gt;&lt;br /&gt;#&lt;br /&gt;# Change following lines&lt;br /&gt;#&lt;br /&gt;SRC=path to cloned Develop repository that user works on&lt;br /&gt;SRCNAME="project name (Zlatozar's repository)"&lt;br /&gt;&lt;br /&gt;# Path to PID file of running mercurial process.&lt;br /&gt;PID_FILE=${SRC}/hg.pid&lt;br /&gt;&lt;br /&gt;state=$1&lt;br /&gt;case "$state" in&lt;br /&gt;    'start')&lt;br /&gt;        echo "Mecurial Server service starting..."&lt;br /&gt;        (cd ${SRC} ;${APP_BIN} serve --name "${SRCNAME}"  -d  -p 1111 --pid-file ${PID_FILE})&lt;br /&gt;        ;;&lt;br /&gt;&lt;br /&gt;    'stop')&lt;br /&gt;        if [ -f "${PID_FILE}" ]; then&lt;br /&gt;            PID=`cat "${PID_FILE}"`&lt;br /&gt;            if [ "${PID}" -gt 1 ]; then&lt;br /&gt;                kill -TERM ${PID}&lt;br /&gt;                echo "Stopping the Mercurial service PID=${PID}."&lt;br /&gt;            else&lt;br /&gt;                echo Bad PID for Mercurial -- \"${PID}\"&lt;br /&gt;            fi&lt;br /&gt;        else&lt;br /&gt;            echo No PID file recorded for mercurial&lt;br /&gt;        fi&lt;br /&gt;        ;;&lt;br /&gt;&lt;br /&gt;    *)&lt;br /&gt;        echo "$0 {start|stop}"&lt;br /&gt;        exit 1&lt;br /&gt;        ;;&lt;br /&gt;esac&lt;br /&gt;&lt;/pre&gt;Уговорката е локалния Mercurial да е на порт 1111. &lt;b&gt;Забележка:&lt;/b&gt;Тук може да има проблем ако IP се получава през DHCP.Тогава трява всеки от екипа да има хранилище на Mercurial сървъра. Един вид публично хранилище,на което може да се слага код, когато някоя работа изисква повече от един човек.И това е! Може свободно да обменяме. А ако възникни пороблем, по който работят повече хора правим отделен клон и работим. Като свършим просто го прекратяваме.&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-AuVHGzyuZU0/TZsVE__4wsI/AAAAAAAAC2Y/UP9TkOSOWV8/s1600/Hotfix_Branches.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="400" width="291" src="http://1.bp.blogspot.com/-AuVHGzyuZU0/TZsVE__4wsI/AAAAAAAAC2Y/UP9TkOSOWV8/s400/Hotfix_Branches.png" /&gt;&lt;/a&gt;&lt;/div&gt;Почти сме преключили, сега е време да изменим мисленето си и стила си на работа с дистрибутивните сорс системи. Ето &lt;a href="http://blogs.sun.com/tor/entry/mercurial_tip_checking_in_regularly"&gt;тук&lt;/a&gt; има такъв.Happy hacking!&lt;a href="http://hginit.com/"&gt;Joel tutorial&lt;/a&gt;&lt;a href="http://mercurial.aragost.com/kick-start/en/basic/"&gt;Practical Example&lt;/a&gt;&lt;a href="http://mercurial.selenic.com/guide/"&gt;Official Mercurial Guide&lt;/a&gt;&lt;a href="http://hgbook.red-bean.com/read/"&gt;Mercurial Definitive guide&lt;/a&gt;&lt;a href="http://wiki.sofia.postpath.com/wiki/images/e/e3/Mercurial_reference_card.pdf"&gt;Mercurial Cheatsheet&lt;/a&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14240039-700546364895304694?l=zlatozar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zlatozar.blogspot.com/feeds/700546364895304694/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14240039&amp;postID=700546364895304694' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/700546364895304694'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/700546364895304694'/><link rel='alternate' type='text/html' href='http://zlatozar.blogspot.com/2011/02/mercurial-for-team-comunication.html' title='Mercurial for team members collaboration'/><author><name>Zlatozar</name><uri>http://www.blogger.com/profile/16257250071061885492</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/17/6760/640/RabotnotoMqsto.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-v14C66a2eyk/TZsVswkv25I/AAAAAAAAC2g/FGDPYGNiL_I/s72-c/Branching_Model.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14240039.post-6206689089354465937</id><published>2010-12-10T13:05:00.008+02:00</published><updated>2011-11-16T19:22:06.958+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>C++ project rules</title><content type='html'>&lt;b&gt;C++&lt;/b&gt; is a big and complex language that's why before starting new project it is very important to set up rules that whole team must follow.&lt;br /&gt;&lt;br /&gt;Here is rules that my team follows:&lt;br /&gt;&lt;br /&gt;&lt;pre style="color: #111111; font-size: 10pt;"&gt;#_______________________________________________________________________________&lt;br /&gt;#&lt;br /&gt;#   &lt;b&gt;README&lt;/b&gt;&lt;br /&gt;#_______________________________________________________________________________&lt;br /&gt;#&lt;br /&gt;&lt;br /&gt; 1. Prerequisites&lt;br /&gt; 2. Building&lt;br /&gt; 3. Installing&lt;br /&gt; 4. Project structure&lt;br /&gt; 5. Code convention&lt;br /&gt; 6. Tools&lt;br /&gt; 7. Contributing&lt;br /&gt; &lt;br /&gt;#_______________________________________________________________________________&lt;br /&gt;#                                                                 PREREQUISITES&lt;br /&gt;&lt;br /&gt; This project requires:&lt;br /&gt;  * Cross-platform CMake v2.8.1+&lt;br /&gt;  * GNU Make or equivalent.&lt;br /&gt;  * GCC or an alternative, reasonably conferment C++ compiler.&lt;br /&gt;  * Boost C++ Libraries v1.42+ [HEADERS and LIBRARIES]&lt;br /&gt;  * Qt Framework v4.5+&lt;br /&gt;  * glog v0.3+&lt;br /&gt;  * gtest v1.4+&lt;br /&gt;&lt;br /&gt;All include are located in &lt;b&gt;$(PROJECT_ROOT)/extern&lt;/b&gt; as symbolic links to&lt;br /&gt;installation directories so we can use them in unified way.&lt;br /&gt;&lt;br /&gt;1. boost &lt;br /&gt;   &lt;a href="http://www.boost.org/doc/libs/?view=categorized"&gt;http://www.boost.org/doc/libs/?view=categorized&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;2. googletest &lt;br /&gt;   &lt;a href="http://code.google.com/p/googletest/"&gt;http://code.google.com/p/googletest/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;3. google-glog&lt;br /&gt;   &lt;a href="http://code.google.com/p/google-glog/"&gt;http://code.google.com/p/google-glog/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;(optional)&lt;br /&gt;&lt;br /&gt;4. gmock&lt;br /&gt;   &lt;a href="http://code.google.com/p/gmock/"&gt;http://code.google.com/p/gmock/&lt;/a&gt;&lt;br /&gt;   &lt;br /&gt;5. soci&lt;br /&gt;   &lt;a href="http://soci.sourceforge.net/"&gt;http://soci.sourceforge.net/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;#_______________________________________________________________________________&lt;br /&gt;#                                                                      BUILDING&lt;br /&gt;&lt;br /&gt; This project uses the Cross-platform CMake build system. However, we&lt;br /&gt; have conveniently provided a wrapper configure script and Makefile so that&lt;br /&gt; the typical build invocation of &lt;b&gt;"./configure"&lt;/b&gt; followed by &lt;b&gt;"make"&lt;/b&gt; will work.&lt;br /&gt; For a list of all possible build targets, use the command "make help".&lt;br /&gt;&lt;br /&gt; NOTE: Users of CMake may believe that the top-level Makefile has been&lt;br /&gt; generated by CMake; it hasn't, so please do not delete that file.&lt;br /&gt;&lt;br /&gt;#_______________________________________________________________________________&lt;br /&gt;#                                                                    INSTALLING&lt;br /&gt;&lt;br /&gt; Once the project has been built (see "BUILDING"), execute &lt;b&gt;"sudo make install"&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#_______________________________________________________________________________&lt;br /&gt;#                                                             PROJECT STRUCTURE&lt;br /&gt;&lt;br /&gt;Given project template contains general solution. You can remove or add some directories.&lt;br /&gt;For example you can add &lt;b&gt;"gen"&lt;/b&gt; directory for all generated files or remove &lt;b&gt;"lib"&lt;/b&gt; if some&lt;br /&gt;package doesn't produce library code. &lt;br /&gt;&lt;br /&gt;To illustrate structure with example I added three directories (all with suffix .package).&lt;br /&gt;You can remove them by searching project for .package or rename and reuse Make/CMake files.&lt;br /&gt;&lt;br /&gt;Here is the basic source structure of the project:&lt;br /&gt;&lt;br /&gt;        &lt;b&gt;tools&lt;/b&gt;   - Directory for scripts and CMake modules&lt;br /&gt;                &lt;br /&gt;                  &lt;b&gt;bin&lt;/b&gt;     - holds scripts for code building and checking&lt;br /&gt;                  &lt;b&gt;share&lt;/b&gt;   - resources that are needed by tools (like CMake modules)&lt;br /&gt;&lt;br /&gt;        &lt;b&gt;doc&lt;/b&gt;     - Output of doxygen and other documents related to project&lt;br /&gt;&lt;br /&gt;                  Contains all Doxygen generated documents(removed by distclean) and project main page&lt;br /&gt;&lt;br /&gt;        &lt;b&gt;extern&lt;/b&gt;  - Directory holds external libraries that are common for all packages as symbolic links.&lt;br /&gt;&lt;br /&gt;                  Keep there only libraries that are not in OS distribution or &lt;br /&gt;                  if you want to control versions. It's not allowed to be modified.&lt;br /&gt;&lt;br /&gt;                  &lt;b&gt;For example:&lt;/b&gt;&lt;br /&gt;                          ln -s /opt/gtest-1.4.0 /opt/gtest&lt;br /&gt;&lt;br /&gt;                  How to install external libs:&lt;br /&gt;                  &lt;br /&gt;                  1. Build them using prefix. For example boost:&lt;br /&gt;&lt;br /&gt;                     &lt;b&gt;TIP:&lt;/b&gt; It is convenient to use one prefix for libraries followed by lib name&lt;br /&gt;                         ./bootstrap.sh --prefix=/opt/boost-1.42.0&lt;br /&gt;                         ./bjam toolset=gcc install&lt;br /&gt;                         ln -s /opt/boost-1.42.0 /opt/boost&lt;br /&gt;&lt;br /&gt;                  2. Set the ROOT directory of a library in your environment so CMake/Makefile&lt;br /&gt;                     can easily find/use them.&lt;br /&gt;                  &lt;br /&gt;                   &lt;b&gt;For example:&lt;/b&gt;&lt;br /&gt;                         export BOOST_ROOT=/opt/boost&lt;br /&gt;&lt;br /&gt;                     &lt;b&gt;TIP:&lt;/b&gt; If Boost is big for you take a look on very useful tool &lt;b&gt;"bcp"&lt;/b&gt; or&lt;br /&gt;                          build only required:&lt;br /&gt;&lt;br /&gt;                          ./bootstrap.sh --with-&amp;lt;library_name&amp;gt;&lt;br /&gt;                     &lt;br /&gt;                     &lt;b&gt;TIP:&lt;/b&gt; If CMake can't find some module try:&lt;br /&gt;&lt;br /&gt;                          cmake --help-module &amp;lt;module_name&amp;gt; (e.g. FindBoost)&lt;br /&gt;&lt;br /&gt;                  3. Put libraries location in &lt;b&gt;LD_LIBRARY_PATH&lt;/b&gt;. Compiler search first here.&lt;br /&gt;&lt;br /&gt;                         export LD_LIBRARY_PATH = .:path/to/lib/directory&lt;br /&gt;&lt;br /&gt;                  4. Make symbolic link:&lt;br /&gt;                      &lt;br /&gt;                         cd extern&lt;br /&gt;                         ln -s /opt/Qt Qt&lt;br /&gt;&lt;br /&gt;                  5. If you have third party library that is used from many packages and it is possible/want&lt;br /&gt;                     to modify create directory &lt;b&gt;"src/thirdparty"&lt;/b&gt; and put it there&lt;br /&gt;                  &lt;br /&gt;        &lt;b&gt;base&lt;/b&gt;      - Common macros, base classes and useful templates used through project&lt;br /&gt;&lt;br /&gt;        &lt;b&gt;"package"&lt;/b&gt; - Directory for a independent static/dynamic library or sub-project&lt;br /&gt;&lt;br /&gt;                  &lt;b&gt;bin&lt;/b&gt;         - Holds the output of compile process.&lt;br /&gt;                  &lt;b&gt;bin.debug&lt;/b&gt;   (ignored by svn)&lt;br /&gt;&lt;br /&gt;                  &lt;b&gt;doc&lt;/b&gt;         - Package specific documentation&lt;br /&gt;&lt;br /&gt;                  &lt;b&gt;include&lt;/b&gt;     - Package API. Include files that will be used from other packages.&lt;br /&gt;                              (automatically transferred) &lt;br /&gt;&lt;br /&gt;                  &lt;b&gt;lib&lt;/b&gt;         - Holds the output of build process if the result is&lt;br /&gt;                                a library (shared library by default)&lt;br /&gt;&lt;br /&gt;                  &lt;b&gt;share&lt;/b&gt;       - Holds shared resources&lt;br /&gt;&lt;br /&gt;                  &lt;b&gt;sub-package&lt;/b&gt; - Code that is part of the enclosing package&lt;br /&gt;&lt;br /&gt;                              &lt;b&gt;TIP:&lt;/b&gt; Use nested namespaces for sub-package&lt;br /&gt;&lt;br /&gt;                  &lt;b&gt;thirdparty&lt;/b&gt;  - Holds the third party sources that could be modified for needs of library&lt;br /&gt;&lt;br /&gt;                  &lt;b&gt;.&lt;/b&gt;           - All code has to be located here&lt;br /&gt;                            &lt;br /&gt;                              &lt;b&gt;TIP:&lt;/b&gt; Makefile or CMake will copy all public API (header files)&lt;br /&gt;                                   in include directory. Doxygen skip it to avoid duplications.&lt;br /&gt;&lt;br /&gt;                  &lt;b&gt;test&lt;/b&gt;        - Holds simple tests for the package&lt;br /&gt;                               (all test files are excluded form doxygen)&lt;br /&gt;                             &lt;br /&gt;                             &lt;b&gt;TIP:&lt;/b&gt; You can divide tests as:&lt;br /&gt;                                      unit&lt;br /&gt;                                      integration&lt;br /&gt;                                      end-to-end&lt;br /&gt;&lt;br /&gt;                         &lt;b&gt;data&lt;/b&gt;    - Data that will be used by test (optional)&lt;br /&gt;&lt;br /&gt;Control template instantiations - No other file in the project should generate any specialized function&lt;br /&gt;code even if the source code is available when the file is compiled (see g++ &lt;b&gt;fno-implicit-templates&lt;/b&gt; parameter).&lt;br /&gt;Every template specialization that is required is generated in one separate file and linked with the other&lt;br /&gt;modules in the final link phase. Also remember that generation of the same function specialization&lt;br /&gt;(by compiler or the user) more than once in compilation unit is an error.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;GOOD PROGRAMMING PRACTICES:&lt;/b&gt;&lt;br /&gt;      * During development you can use Makefile that is located in packages!&lt;br /&gt;      * Locate all common template classes in base directory&lt;br /&gt;      * Schemes for reducing template code size&lt;br /&gt;        - cut member functions that do not depend on the type of the template argument&lt;br /&gt;        - use counted pointers&lt;br /&gt;      * Release to Release binary compatibility (&lt;b&gt;RRBC&lt;/b&gt;) rules&lt;br /&gt;        - the existing class hierarchy must remain unchanged&lt;br /&gt;        - declarations for new virtual functions must appear after the declarations for&lt;br /&gt;          all pre-existing virtual functions&lt;br /&gt;        - all old virtual functions must remain and be declared in the same order&lt;br /&gt;        - non-virtual functions and static member functions can be added without restriction&lt;br /&gt;        - previously existing public or protected functions must continue to exist&lt;br /&gt;        - the total size of an instance of a class must remain unchanged, and all public&lt;br /&gt;          or protected data members must continue to exist and must remain at the same offset&lt;br /&gt;          within the class. Private date that is referenced from public or protected inline&lt;br /&gt;          members functions count as public data.&lt;br /&gt;#_______________________________________________________________________________&lt;br /&gt;#                                                               CODE CONVENTION&lt;br /&gt;&lt;br /&gt;C++ code convention resources:&lt;br /&gt;       &lt;a href="http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml"&gt;http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml&lt;/a&gt; (use &lt;b&gt;tools/bin/cppling.py&lt;/b&gt;)&lt;br /&gt;with combination/or&lt;br /&gt;       &lt;br /&gt;&lt;a href="http://www.amazon.com/Elements-Style-Sigs-Reference-Library/dp/0521893089?ie=UTF8&amp;amp;tag=from_word_to_word-73&amp;amp;link_code=bil&amp;amp;camp=213689&amp;amp;creative=392969" imageanchor="1" target="_blank"&gt;&lt;img alt="The Elements of C++ Style (Sigs Reference Library)" src="http://ws.amazon.com/widgets/q?MarketPlace=US&amp;amp;ServiceVersion=20070822&amp;amp;ID=AsinImage&amp;amp;WS=1&amp;amp;Format=_SL160_&amp;amp;ASIN=0521893089&amp;amp;tag=from_word_to_word-73" /&gt;&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=from_word_to_word-73&amp;amp;l=bil&amp;amp;camp=213689&amp;amp;creative=392969&amp;amp;o=1&amp;amp;a=0521893089" style="border: medium none ! important; margin: 0px ! important; padding: 0px ! important;" width="1" /&gt;&lt;b&gt;"The Elements of C++ Style"&lt;/b&gt; book&lt;br /&gt;&lt;br /&gt;1. Naming Your Files&lt;br /&gt;&lt;br /&gt;   1.1 Each class definition should be in its own file where each file is named directly &lt;br /&gt;       after the class's name (like in Java).&lt;br /&gt;   &lt;br /&gt;       ClassName.h    // defines class ClassName&lt;br /&gt;       ClassName.cpp&lt;br /&gt;&lt;br /&gt;   1.2 Use separate files for each namespace-scope class, struct, union, enumeration, function, or&lt;br /&gt;       overloaded function group&lt;br /&gt;&lt;br /&gt;Give each file the same name as the element it contains, using the same case.&lt;br /&gt;Consider also using separate files for template specializations.&lt;br /&gt;&lt;br /&gt;   1.3 PkgConf/PkgDoc files in projects are for package configuration/documentation,&lt;br /&gt;       AppConf/AppDoc for application as a whole.&lt;br /&gt;&lt;br /&gt;2. Namespaces&lt;br /&gt;&lt;br /&gt;   2.1 Every module, package in a project has own namespace.&lt;br /&gt;&lt;br /&gt;Namespaces simply wrap all enclosed names with another name and they group logically related entities.&lt;br /&gt;Namespace name should not correspond to a single entity but rather to a category to which names in the&lt;br /&gt;namespace logically belong.&lt;br /&gt;&lt;br /&gt;   2.2  Namespace names are all lower-case, and based on project names and possibly their directory structure.&lt;br /&gt;       &lt;br /&gt;Here is the name convention: &lt;b&gt;project_subdir&lt;/b&gt;. In this way we mimic directory structure.&lt;br /&gt;&lt;br /&gt;   2.3. It's usually sufficient to have one or two levels of namespace, with the odd extra level for internal&lt;br /&gt;        details.&lt;br /&gt;&lt;br /&gt;   2.4 Use unnamed namespaces instead of static to hide local functions and variables&lt;br /&gt;&lt;br /&gt;3. Classes&lt;br /&gt;&lt;br /&gt;   3.1 The object life cycle involves three activities: &lt;b&gt;creation, destruction, and assignment&lt;/b&gt;!&lt;br /&gt;&lt;br /&gt;   3.2 Always implement destructor, copy constructor and copy assignment operator (the rule of three)&lt;br /&gt;       plus constructor and do not forget to call them from derived classes if use inheritance.&lt;br /&gt;       Use &lt;b&gt;DISALLOW_COPY_AND_ASSIGN&lt;/b&gt; macros to disallow copy and assignment.&lt;br /&gt;&lt;br /&gt;   3.3 Be very careful especially when you have a pointers to dynamically allocated memory in your class&lt;br /&gt;       * A constructor to either make an initial allocation or set the pointer to &lt;b&gt;NULL&lt;/b&gt;.&lt;br /&gt;       * A destructor to delete the dynamically allocated memory. Destructors are not inherited,&lt;br /&gt;         and you cannot explicitly call a destructor of a base class, so define them virtual.&lt;br /&gt;       * A copy constructor to make a copy of the dynamically allocated memory (deep copy).&lt;br /&gt;       * An overloaded assignment operator to delete previous allocated and make a copy of the dynamically&lt;br /&gt;         allocated memory (deep copy).&lt;br /&gt;&lt;br /&gt;You can think of an assignment operator as a combination of a destructor and a copy constructor.&lt;br /&gt;And do not forget to check for self assignment! An overloaded assignment operator defined in a derived&lt;br /&gt;class doesn't automatically invoke the assignment operator for it's base class part so do not forget to call&lt;br /&gt;assignment operator of the base class!&lt;br /&gt;&lt;br /&gt;   3.4 Keep order:&lt;br /&gt;&lt;pre class="brush: cpp"&gt;class ClassName&lt;br /&gt;{&lt;br /&gt;  &amp;lt;friends classes&amp;gt;&lt;br /&gt;  public:    // Behaviors (methods) that you want clients to use.&lt;br /&gt;    // Method declarations&lt;br /&gt;    // Member declarations&lt;br /&gt;  protected: // Methods of a subclass can call a protected method&lt;br /&gt;             // or access a protected member of an object&lt;br /&gt;    // Method declarations&lt;br /&gt;    // Member declarations&lt;br /&gt;  private:   // Only if you want to restrict a access from subclasses&lt;br /&gt;    // Method declarations&lt;br /&gt;    // Member declarations&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;3.5 Naming convention        * The naming of the class always starts with a capital letter.        * If it is an interface(pure virtual) starts with &lt;b&gt;"I"&lt;/b&gt;.        * For all class members use underscore prefix '_' e.g  _speed all other are camelCase.        * Class methods are camelCase().        * Give Function Parameters the Same Name as the Member Variables You Assigned Them to&lt;pre class="brush: cpp"&gt;class Customer&lt;br /&gt;{&lt;br /&gt;  public:&lt;br /&gt;    Customer(const string&amp;amp; name);&lt;br /&gt;    void setName(const string&amp;amp; name);&lt;br /&gt;  private:&lt;br /&gt;    string _name;&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;* Constant types with &lt;b&gt;'k'&lt;/b&gt; e.g. kDefaultSpeed        * Static types with &lt;b&gt;'s'&lt;/b&gt;.        * Free functions(not in a class) has to be in lower case using '_' and located in file that starts          with lower case. Good practice is to include file name in free functions name.          For example in file &lt;b&gt;vmdsock.cpp&lt;/b&gt; to have methods:             vmdsock_init();             vmdsock_create();        * Pluralize the Names of Collections        * Use "other" for Parameter Names in Copy Constructors and Assignment Operators        * Use &lt;b&gt;size_t&lt;/b&gt; where positive "int" numbers are required e.g. method parameters and loops    3.6 Consider the unit tests to be part of the actual implementation.Corresponding test class(test functionality) is in file which name starts with 'test' and it is locatedin test directory. It is good practice to group test and &lt;b&gt;GTest&lt;/b&gt; framework allows that.&lt;b&gt;Example of test grouping:&lt;/b&gt;     Fine-Grained Test:     testClassName.cpp  // contains tests for ClassName functionality, class API         Medium-Grained Tests:  testInsertBadData()     Large-Grained Tests:   testInsert()    3.7 To test classes for creation, assigning and all overloading operations create class with main method:        ClassNameTest.cpp   // easily you can run all static checkers on it!        or create something like that:&lt;pre class="brush: cpp"&gt;#ifdef __TEST__&lt;br /&gt;  int main(int argc, char *argv[]) {&lt;br /&gt;  ...&lt;br /&gt;#endif&lt;br /&gt;&lt;/pre&gt;Run a program transparently, but print a stack trace if it fails.&lt;pre class="brush: shell"&gt;gdb -batch -ex "run" -ex "bt" ${my_program} 2&amp;gt;&amp;amp;1 | grep -v ^"No stack."$&lt;br /&gt;&lt;/pre&gt;For automated unit tests we wanted our program to run normally, but if it crashed,        to add a stack trace to the output log. 3.8 If constructor takes only one parameter make it explicit. This will prevent confusing automatic        conversions         .......        explicit Car(const Driver&amp;amp; driver) {}           .......    3.9 Place each member variable in the initialization list in the same order as they fall        in the class declarationInitialization order is declared in the class itself, not in the constructor!That is because of caveat with initializer lists: they initialize data members in the order that theyappear in the class definition, not their order in the initializer list.    3.10 Think about using composition before using inheritance.    3.11 If you choose inheritance, keep following rules:      * Constructor must not call virtual functions.      * If class has even one virtual function implement virtual destructor      * Keep in mind that constructors, assignment operator and friends methods cannot be inherited      * Do not forget to call base constructor(initialize base), base copy constructor and base operator= first    3.12 Use mix-in (-able e.g. Callable) classes instead of multiple inheritance.    3.13 When you want class to be "abstract", define destructor as virtual.In this way prevent a class from being instantiated.    3.14 Think of private inheritance as "implemented using". See AddapterPattern (GoF)&lt;b&gt;NOTE:&lt;/b&gt; The Liskov Substitution Principal states that it should always be possible to substitute      a base class for a derived class without any change in behavior. If you want to break this principal you      can use private inheritance.    3.15 Declare Enumerations within a Namespace or ClassTo avoid symbolic name conflicts between enumerators and other global names,nest enum declarations within the most closely related class or common namespace.If this is not possible, prefix each enumerator name with a unique identifier suchas the enumeration or module name.    3.16 Accept objects by reference and primitive or pointer types by value    3.17 Use a non-virtual function for behavior that is common to all classes         in the hierarchy and should not be overridden in derived classes.        3.18 Use a virtual function(and destructor) to define default behavior that may be         overridden in derived classes.    3.19 When picking data members for a class careful choose between: pointer(very flexible),         reference and value.If polymorphic behavior of data member is essential, use reference or a pointer as data member.&lt;b&gt;GOOD PROGRAMMING PRACTICES:&lt;/b&gt;      * Use size_t variables for simple loop iteration and array subscripts      * When you write a subclass, you need to be aware of the interaction between parent classes and childclasses. Here is the construction order:        - The base class, if any, is constructedC++ will automatically call the default constructor for the parent class if one exists. But you can chain theconstructor just as when initializing data members in the initializer list        - Non-static data members are constructed in the order in which they were declared        - The body of the constructor is executed      * It is good style to repeat the virtual specification in a derived class      * Use default arguments to reduce the number of constructors      * Avoid using large arrays as automatic variables, use pointer to array      * Use QuickCheck++, Boost.Contract++4. Documenting and logging   4.1 Put all documentation of methods and classes in header files in source files document implementation       issues if necessary.   4.2 Use Java stile of documenting, doxygen will make documentation.GLOG is not just logging levels. It is much more, for example conditional logging, check macros, debug support.For more information see:     &lt;a href="http://google-glog.googlecode.com/svn/trunk/doc/glog.html"&gt;http://google-glog.googlecode.com/svn/trunk/doc/glog.html&lt;/a&gt;5. What to &lt;b&gt;inline&lt;/b&gt;?   -small methods, such as accessors for private data   -functions returning state information about object   -small functions that are called repeatedly&lt;b&gt;GOOD PROGRAMMING PRACTICES:&lt;/b&gt;      * Place the method definition directly in the class definition and rarely use "inline" keyword.6. What to be in header files?      6.1 The header files should never contain definitions of functions or variables with the exceptions of       inline functions.   6.2 They should not contain definitions of unnamed namespaces.The header file may contain declarations of any names that have internal linkage, including const identifiers;types defined by typedef, class, struct, and enum; inline functions; named namespaces; and template declarationsand definitions.   6.3 A header file essentially should contain only interface information or specification of some implementation       file(s) of a library.In other words, everything included in a header file only serves as reference, and should not inflictany byte in the executable. But of course you can put some methods that will be inlined.7. Includes   7.1 Use following order:&lt;pre class="brush: cpp"&gt;#include &amp;lt;corresponding .h file&amp;gt;&lt;br /&gt;#include &amp;lt;C headers&amp;gt;&lt;br /&gt;#include &amp;lt;STL headers&amp;gt;&lt;br /&gt;#include &amp;lt;"external" libraries&amp;gt;  // third party code&lt;br /&gt;#include &amp;lt;"internal" libraries&amp;gt;  // from other packages&lt;br /&gt;    &lt;br /&gt;&amp;lt;forward references&amp;gt;&lt;br /&gt;&lt;/pre&gt;7.2 Start include declaration from the root for the project:       #include "helper.package/include/subject_extract.h"   7.3 A file should never depend on an implementation file; in other words, you should       never write:            #include "something.cpp"   7.4 In implementation .cpp file do not write #includes that are already included in header files   7.5 Don't include a header file when a forward declaration is all you need&lt;b&gt;GOOD PROGRAMMING PRACTICES:&lt;/b&gt;      * If you use a lot of forward declarations you might choose to prefer using &lt;b&gt;boost::checked_delete&lt;/b&gt;.8. When to use friend methods?   -use them for testing private data stuff&lt;b&gt;NOTES:&lt;/b&gt; 1. Also you can use simple hack:          g++ -Dprivate=public .....       2. GTEST has a special macro for mark test methods as friends - &lt;b&gt;FRIEND_TEST&lt;/b&gt;   -for overloading operators to reflect syntax   -for methods that you don't want to become part of class interface   -provide better protection than other techniques when functions need to communicate    with more than one class.    For example:&lt;pre class="brush: cpp"&gt;/**&lt;br /&gt;* This provides a neat solution to the problem: &lt;br /&gt;* the multiply function has access to private data in&lt;br /&gt;* both classes but we have not "opened them up" to anyone else.&lt;br /&gt;*/&lt;br /&gt;class Vector&lt;br /&gt;{&lt;br /&gt;  friend Vector operator* (const Matrix&amp;amp; lhs, const Vector&amp;amp; rhs);&lt;br /&gt;  ....&lt;br /&gt;}     &lt;br /&gt;class Matrix&lt;br /&gt;{&lt;br /&gt;  friend Vector operator* (const Matrix&amp;amp; lhs, const Vector&amp;amp; rhs);&lt;br /&gt;  ....&lt;br /&gt;}&lt;br /&gt;// free function&lt;br /&gt;Vector operator* (const Matrix&amp;amp; lhs, const Vector&amp;amp; rhs) {&lt;br /&gt;  ....&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;GOOD PROGRAMMING PRACTICES:&lt;/b&gt;      * Define friends methods in &lt;b&gt;.cpp&lt;/b&gt; file(there is no need to repeated friend keyword)9. Be &lt;b&gt;Const&lt;/b&gt; CorrectConst is a powerful tool for writing safer code, and it can help compiler optimizations.Your default choice for passing objects as parameters should be const reference.Only if you explicitly need to change the object should you omit the const.10. &lt;b&gt;Hungarian&lt;/b&gt; notationThe right way to use it is to invent prefixes that provide useful information: the prefix indicatesthe "intent" rather than the "type". In particular, variables with the same C++ type but with differentroles often have different prefixes. &lt;b&gt;For example:&lt;/b&gt;In a graphics application, variables representing coordinates have prefixes x, y, and, z.Then xCar, yCar, zCar (they all integers) is more meaningful.11. Implementation hiding    11.1 Use &lt;b&gt;PIMPL&lt;/b&gt;(pointer to implementation) Idiom for public APIOvercome the language's separation anxiety: C++ makes private members inaccessible, but notinvisible. Where the benefits warrant it, consider making private members truly invisible using thePimpl idiom to implement compiler firewalls and increase information hiding.    11.2 Hide reference to a "secret" class. Use fallowing is the technique:FileOps.h - &lt;b&gt;typical approach&lt;/b&gt;&lt;pre class="brush: cpp"&gt;// "Cache" is the secret class&lt;br /&gt;class FileOps&lt;br /&gt;{&lt;br /&gt;  public: &lt;br /&gt;    FileOps(const string, Cache&amp;amp;);&lt;br /&gt;    ........&lt;br /&gt;  private:&lt;br /&gt;    string _fileName;&lt;br /&gt;    ......&lt;br /&gt;    Cache&amp;amp; _cache;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;FileOps.h that &lt;b&gt;hide secrets&lt;/b&gt;&lt;pre class="brush: cpp"&gt;// "Cache" is the secret class&lt;br /&gt;class FileOps&lt;br /&gt;{&lt;br /&gt;  public: &lt;br /&gt;    FileOps(const string inFileName);&lt;br /&gt;    ........&lt;br /&gt;  private:&lt;br /&gt;    string _fileName;&lt;br /&gt;    ......&lt;br /&gt;    Cache* _cache; // not Cache&amp;amp;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;FileOps.cpp&lt;pre class="brush: cpp"&gt;............&lt;br /&gt;FileOps::FileOps(const string inFileName) : _cache(new Cache()) {&lt;br /&gt;.........&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;12. FormattingUse &lt;b&gt;Allman&lt;/b&gt; brace style (also called exdented style) with modifications: use the curly brace on thesame line as the leading statement, except in the case of a function, class, or method name.&lt;b&gt;GOOD PROGRAMMING PRACTICES:&lt;/b&gt;      * Separate logical blocks in files with some comment separator      * For emacs buffer aligning use &lt;b&gt;'google-c-style.el'&lt;/b&gt;      * YASnipped plug-in for Emacs could be used14. &lt;b&gt;Ownership!&lt;/b&gt;When passing an object to a method, you have to think fairly carefully about whether you aretransferring ownership.When the ownership(= responsibility to destroy) of the object is passed to another function,it is usually better to use a smart pointer, such as &lt;b&gt;std::auto_ptr&lt;/b&gt;.&lt;pre class="brush: cpp"&gt;void manage(std::auto_ptr&amp;lt;T&amp;gt; t) {&lt;br /&gt;...&lt;br /&gt;}&lt;br /&gt;...&lt;br /&gt;// The reader of this code clearly sees ownership transfer.&lt;br /&gt;std::auto_ptr&amp;lt;T&amp;gt; t(new T);&lt;br /&gt;manage(t);&lt;br /&gt;&lt;/pre&gt;If a call to library returns memory pointers, who is responsible for freeing the memory:the caller or the library? If the library is responsible, when is the memory freed? Think about!References clarify ownership of memory! If you are writing a method and another programmer passes youa reference to an object, it is clear that you can read and modify(if not &lt;b&gt;const&lt;/b&gt;) the object, but you haveno easy way of freeing its memory, so this is a sign that you are not responsible for destroying.&lt;b&gt;GOOD PROGRAMMING PRACTICES:&lt;/b&gt;     * As much as possible, avoid returning a reference from a function because       - you can't indicate object creation failure       - created object could not be local. Who owns it?     * Use reference or pointer only if you want to return something polymorphic     * If you need reference counting smart pointer see SmartPointer or share_ptr&amp;lt;T&amp;gt;.     * If function do pointer arithmetic with parameter it is better to be defined as array       e.g. void X::f(T agrp[])     * If you want to forbid pointer arithmetic and delete just make it &lt;b&gt;const&lt;/b&gt;       e.g. void X::f(T* const agrp)15. Prefer shared librariesIf you rapidly change the API then you need to recompile all of the programs that use the library inboth the shared and the static case. If you change the library but do not change the API then you mustrecompile all the programs that use the library only if they are linked statically.16. User object pool for large number of short-lived objectsIf you know that your program needs a large number of short-lived objects of the same type, you cancreate a pool, or cache, of those objects. See &lt;b&gt;ObjectPool&lt;/b&gt; and Flyweight(GoF)           * You need to frequently create and destroy objects.       * They are similar in size.       * Allocating them on the heap is slow or could lead to memory fragmentation.       * Each object encapsulates a resource such as a database or network connection         that is slow to acquire and could be reused.17. ExceptionsWhen harmed, take exception: Prefer using exceptions over error codes to report errors. Use statuscodes (e.g., return codes, errno) for errors when exceptions cannot be used, and for conditions thatare not errors. Use other methods, such as graceful or ungraceful termination, when recovery isimpossible or not required.&lt;b&gt;GOOD PROGRAMMING PRACTICES:&lt;/b&gt;       * Use &lt;b&gt;RAII&lt;/b&gt; programming idiom       * If your code is with exceptions use &lt;b&gt;auto_ptr&lt;/b&gt; for all local variables to make your code         exception save.       * Throw by value, catch by reference18. When to use parametrized types vs inheritance and delegation?       * use parametrized types when T doesn't affect its behavior and there is         no hierarchical structure between T objects       * use parametrized types if efficiency is essential(to avoid the overhead of virtual functions)       * use instances if the types of objects being operated on are not known at compile time19. Destructors, deallocation, and swap never fail! Period!Everything they attempt shall succeed: Never allow an error to be reported from a destructor, aresource deallocation function (e.g., operator delete), or a swap function. Specifically, typeswhose destructors may throw an exception are flatly forbidden from use with the C++ standardlibrary.20. &lt;b&gt;STL&lt;/b&gt;    20.1 Use vector by default. Otherwise, choose an appropriate container    20.2 Store only values and smart pointers in containers    20.3 Prefer push_back to other ways of expanding a sequence    20.4 Check whether an operation invalidates iterators before using it    20.5 Ensure that template arguments satisfy the requirements of the corresponding         template parameter.    20.6 Don’t store auto-pointers in STL containers.    20.7 If you are traversing a container without changing its contents, use a &lt;b&gt;const_iterator&lt;/b&gt;#_______________________________________________________________________________#                                                                         TOOLSUse &lt;b&gt;valgrind, cppcheck&lt;/b&gt; and &lt;b&gt;splint&lt;/b&gt; to check code    &lt;a href="http://valgrind.org/"&gt;http://valgrind.org&lt;/a&gt;    &lt;a href="http://cppcheck.wiki.sourceforge.net/"&gt;http://cppcheck.wiki.sourceforge.net&lt;/a&gt;    &lt;a href="http://www.splint.org/"&gt;http://www.splint.org&lt;/a&gt;Wrapper in other language around C++    &lt;a href="http://www.swig.org/"&gt;http://www.swig.org/&lt;/a&gt;Better error messages information:    &lt;a href="http://www.bdsoft.com/tools/stlfilt.html"&gt;http://www.bdsoft.com/tools/stlfilt.html&lt;/a&gt;(optional)Better C++ GDB debug:    &lt;a href="http://sourceware.org/gdb/wiki/ProjectArcher"&gt;http://sourceware.org/gdb/wiki/ProjectArcher&lt;/a&gt;Alternative compiler:    &lt;a href="http://clang.llvm.org/"&gt;http://clang.llvm.org/&lt;/a&gt;    &lt;a href="http://dragonegg.llvm.org/"&gt;http://dragonegg.llvm.org&lt;/a&gt;#_______________________________________________________________________________#                                                                  CONTRIBUTINGHere is typical project structure:&lt;a href="http://code.google.com/p/various-code-fragments/source/browse/#svn/trunk/cpp/project.template"&gt;http://code.google.com/p/various-code-fragments/source/browse/#svn/trunk/cpp/project.template&lt;/a&gt;#_______________________________________________________________________________#                                                                REQUIRED BOOKS &lt;iframe src="http://rcm.amazon.com/e/cm?lt1=_blank&amp;bc1=000000&amp;IS2=1&amp;bg1=FFFFFF&amp;fc1=000000&amp;lc1=0000FF&amp;t=fromwordtowor-20&amp;o=1&amp;p=8&amp;l=as4&amp;m=amazon&amp;f=ifr&amp;ref=ss_til&amp;asins=0470932449" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"&gt;&lt;/iframe&gt;&lt;iframe src="http://rcm.amazon.com/e/cm?lt1=_blank&amp;bc1=000000&amp;IS2=1&amp;bg1=FFFFFF&amp;fc1=000000&amp;lc1=0000FF&amp;t=fromwordtowor-20&amp;o=1&amp;p=8&amp;l=as4&amp;m=amazon&amp;f=ifr&amp;ref=ss_til&amp;asins=1460966163" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"&gt;&lt;/iframe&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14240039-6206689089354465937?l=zlatozar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zlatozar.blogspot.com/feeds/6206689089354465937/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14240039&amp;postID=6206689089354465937' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/6206689089354465937'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/6206689089354465937'/><link rel='alternate' type='text/html' href='http://zlatozar.blogspot.com/2010/12/c-project-rules.html' title='C++ project rules'/><author><name>Zlatozar</name><uri>http://www.blogger.com/profile/16257250071061885492</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/17/6760/640/RabotnotoMqsto.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14240039.post-4886527288423018876</id><published>2010-11-15T15:07:00.017+02:00</published><updated>2011-03-02T18:47:13.976+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>UNIX tools during C++ coding</title><content type='html'>&lt;pre style="color: #111111; font-size: 10pt"&gt;&lt;h2&gt;GCC&lt;/h2&gt;1. gcc/g++ useful tips and tricks:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;See current C++ settings:&lt;br /&gt;&lt;pre  class="brush: plain"&gt;gcc -v -x c++ /dev/null -fsyntax-only&lt;br /&gt;&lt;/pre&gt;See all preprocessor defines:&lt;pre  class="brush: plain"&gt;gcc -dM -E - &lt; /dev/null&lt;br /&gt;&lt;/pre&gt;See what you have after pre-processing:     &lt;pre  class="brush: plain"&gt;g++ -E -I.. -o _file_name_.ii _file_name_.cpp&lt;br /&gt;&lt;/pre&gt;See exactly where is defined something that you use it (e.g. for_each algorithm):&lt;pre  class="brush: plain"&gt;grep --color=auto for_each -C10 _file_name_.ii&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;NOTE:&lt;/b&gt; set alias for colored grep because you will use it a lotSee what files the linker opens and in what order:&lt;pre  class="brush: plain"&gt;g++ -Wl,-t _parameters_for_compilation_&lt;br /&gt;&lt;/pre&gt;See all includes, even those on the system path, so you can checkif it is taken from the right place:&lt;pre  class="brush: plain"&gt;g++ -M _file_name_&lt;br /&gt;&lt;/pre&gt;2. Use "strace" (man strace) when program running to see what is opened.&lt;p&gt;A system call, or syscall, is where a program crosses the boundary between user code and the kernel.Fortunately for us using strace, that boundary is where almost everything interesting happens in a typical program.&lt;/p&gt;It logs all accesses to the OS, such as memory allocation, file I/O, system calls and launching sub-processes&lt;pre  class="brush: plain"&gt;strace -f -o strace.log ./_program_ _program_parameters_&lt;br /&gt;&lt;/pre&gt;You just want to see what files the program touches, or when it reads and writes data, or some other subset.&lt;pre  class="brush: shell"&gt;strace -f -e trace=process,file,desc sh -c \&lt;br /&gt;'for d in _some_directory_/*; do ls $d &gt;/dev/null; done'&lt;br /&gt;&lt;/pre&gt;3. Use "ldd" (man ldd) to see what is needed and how is loaded&lt;pre class="brush: plain"&gt;ldd ./_program_&lt;br /&gt;&lt;/pre&gt;4. Use command "nm" (man nm) that lists symbols contained in the object file or shared library&lt;pre  class="brush: plain"&gt;nm -D libhelp.package.so&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;This command lists symbol names from object files. These symbol names can be either functions, global variables, or static variables. For each symbol, the value, symbol type, and symbol name are displayed.Lower case symbol types mean the symbol is local, while upper case means the symbol is global or external.&lt;/p&gt;In combination you can use &lt;b&gt;c++filt&lt;/b&gt;(see additional tools) for demangling of symbols:&lt;pre  class="brush: plain"&gt;nm libhelp.package.so | grep &amp;lt;searched symbol&amp;gt; | c++filt&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;NOTE:&lt;/b&gt; install c++filt from &lt;a href="http://www.bdsoft.com/tools/stlfilt.html"&gt;here&lt;/a&gt;5. For quick console code search skipping test directory ('ack' installed)&lt;pre  class="brush: plain"&gt;find . -name \*.cpp | grep -v test/ | xargs ack -C 3 -w '_your_search_'&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;NOTE:&lt;/b&gt; I have this in my &lt;b&gt;.ackrc&lt;/b&gt;:&lt;pre  class="brush: plain"&gt;# Add CMake files&lt;br /&gt;--type-set=cmake=.txt,.cmake&lt;br /&gt;&lt;/pre&gt;ack will automatically skips .svn .CVS etc.6. Use "pc" to see snapshot of current processes&lt;pre  class="brush: plain"&gt;ps -efwH&lt;br /&gt;&lt;/pre&gt;7. For complex declaration use &lt;b&gt;"cdecl"&lt;/b&gt;For:&lt;pre  class="brush: cpp"&gt;typedef void(Number:: *Action)(int &amp;);&lt;br /&gt;&lt;/pre&gt;Returns:&lt;b&gt;"declare Action as pointer to member of class Number function (reference to int) returning void"&lt;/b&gt;&lt;p/&gt;&lt;b&gt;Decoding Rule-set:&lt;/b&gt;&lt;p/&gt;&lt;pre  class="brush: plain"&gt;Rule 1:  Read from left to right looking for an identifier&lt;br /&gt;Rule 2:  If the identifier is with parentheses, then evaluate inside the parentheses first&lt;br /&gt;Rule 3:   look right for postfix operators ( ) or [ ]. If [] then it is an array, else if ()&lt;br /&gt;          then it is a function.&lt;br /&gt;Rule 4:   look left for prefix pointer asterisk '*'. If found the identifier is a pointer.&lt;br /&gt;&lt;br /&gt;Rule 5a: If a const and/or volatile is next to a type specifier (int, long, etc.) it applies&lt;br /&gt;         to that specifier&lt;br /&gt;Rule 5b: if a const and/or volatile is not next to a type then it applies to the pointer asterisk on its&lt;br /&gt;         immediate left&lt;br /&gt;&lt;/pre&gt;8. Problems with network, see mtrmtr is something like combination for traceroute and ping9. See disassembly output use following script&lt;pre  class="brush: shell"&gt;#!/bin/sh&lt;br /&gt;gcc -S -fverbose-asm -g -O0 test_program.c -o test_program.s&lt;br /&gt;as -alhnd test_program.s &gt; test_program.1st&lt;br /&gt;&lt;/pre&gt;&lt;h2&gt;GDB&lt;/h2&gt;&lt;p&gt;&lt;b&gt;The Fundamental Law of Debugging:&lt;/b&gt; avoid bugs when you’re coding, but plan forbugs in your code.&lt;/p&gt;One factor that often distinguishes an experienced programmer from a novice is his or her debugging skills.1. Compile-Time Debug Mode&lt;p&gt;You can use preprocessor &lt;b&gt;#ifdefs&lt;/b&gt; to selectively compile the debug code into your program.The advantage of this method is that your debug code is not compiled into the "release" binary,and so does not increase its size. The disadvantages are that there is no way to enable debugging at a customer site for testing or following the discovery of a bug, and your code starts to look cluttered and indecipherable.&lt;/p&gt;In order to generate a debug version of the program, it should be compiled with the symbol &lt;b&gt;DEBUG_MODE&lt;/b&gt;defined. Your compiler should allow you to specify symbols to define during compilation.For example, g++ allows you to specify &lt;b&gt;–Dsymbol&lt;/b&gt; on the compile command.2. Start-Time Debug Mode&lt;p&gt;Start-time debug mode is an alternative to &lt;b&gt;#ifdefs&lt;/b&gt; that is just as simple to implement. A command-lineargument to the program can specify whether it should run in debug mode. Unlike compile-time debugmode, this strategy includes the debug code in the "release" binary, and allows debug mode to be enabledat a customer site.However, it still requires users to restart the program in order to run it in debugmode, which is not always an attractive alternative for customers, and which may prevent you fromobtaining useful information about bugs.&lt;/p&gt;&lt;pre  class="brush: cpp"&gt;bool isDebugSet(int argc, char** argv) {&lt;br /&gt;for (int i = 0; i &lt; argc; i++) {&lt;br /&gt;    if (strcmp(argv[i], "-d") == 0) {&lt;br /&gt;      return (true);&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  return (false);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;3. Run-Time Debug ModeThe most flexible way to provide a debug mode is to allow it to be enabled or disabled at run time. Oneway to provide this feature is to supply an asynchronous interface that controls debug mode on the fly. 4. Ring Buffers&lt;p&gt;Debug mode is useful for debugging reproducible problems and for running tests. However, bugs oftenappear when the program is running in nondebug mode, and by the time you or the customer enablesdebug mode, it is too late to gain any information about the bug. One solution to this problem is to enabletracing in your program at all times. You usually need only the most recent traces to debug a program,so you should store only the most recent traces at any point in a program’s execution. One way to providethis limitation is through careful use of log file rotations.&lt;/p&gt;5. GDB session example&lt;pre  class="brush: plain"&gt;r[un]                        Run to next breakpoint or to end&lt;br /&gt;s[tep]                       Single-step, descending into functions&lt;br /&gt;n[ext]                       Single-step without descending into functions&lt;br /&gt;fin[ish]                     Finish current function, loop, etc. (useful!)&lt;br /&gt;c[ontinue]                   Continue to next breakpoint or end&lt;br /&gt;bt                           displays a stack frame for each active subroutine&lt;br /&gt;up                           Go up one context level on stack (to caller)&lt;br /&gt;                             Move to the function that called the present function&lt;br /&gt;do[wn]                       Go down one level (only possible after up)&lt;br /&gt;p[rint] &amp;lt;name&amp;gt;               Print value of variable called &amp;lt;name&amp;gt;&lt;br /&gt;p/x &amp;lt;name&amp;gt;                   Print value of &amp;lt;name&amp;gt; in HEX format&lt;br /&gt;p &amp;lt;name&amp;gt;@&amp;lt;n&amp;gt;                 Print &amp;lt;n&amp;gt; values starting at &amp;lt;name&amp;gt;&lt;br /&gt;p &amp;lt;chars&amp;gt; (&amp;lt;tab&amp;gt;)            List all variables starting with &amp;lt;chars&amp;gt;&lt;br /&gt;b[reak] &amp;lt;name&amp;gt;               Set a breakpoint at function &amp;lt;name&amp;gt;&lt;br /&gt;b &amp;lt;class&amp;gt;::&amp;lt;name&amp;gt;            Set a breakpoint at &amp;lt;name&amp;gt; in &amp;lt;class&amp;gt;&lt;br /&gt;b &amp;lt;class&amp;gt;::&amp;lt;tab&amp;gt;             List all members in &amp;lt;class&amp;gt;&lt;br /&gt;b &amp;lt;file name&amp;gt;:line number    Set a breakpoint in &amp;lt;file name&amp;gt;&lt;br /&gt;h[elp] b                     Documentation for setting breakpoints&lt;br /&gt;i[nfo] b                     List breakpoints&lt;br /&gt;i                            List all info commands&lt;br /&gt;dis[able] 1                  Disable breakpoint 1&lt;br /&gt;en[able] 1                   Enable breakpoint 1&lt;br /&gt;d[elete] 1                   Delete breakpoint 1&lt;br /&gt;d 1 2                        Delete breakpoints 1 and 2&lt;br /&gt;d                            Delete all breakpoints&lt;br /&gt;cond[ition] 1 &amp;lt;expr&amp;gt;         Stop at breakpoint 1 only if &amp;lt;expr&amp;gt; is true&lt;br /&gt;cond 1                       Make breakpoint 1 unconditional&lt;br /&gt;comm[ands] 1                 Add a list of gdb commands to execute each time breakpoint 1 is hit&lt;br /&gt;(usually just print &amp;lt;var&amp;gt;)&lt;br /&gt;e[xamine]                    Examine memory for a given memory address&lt;br /&gt;&lt;/pre&gt;Here is example debug session for class &lt;b&gt;"Guitar"&lt;/b&gt; with methods &lt;b&gt;"tick"&lt;/b&gt;.After setting a breakpoint in the "tick" method of the class "Guitar" and continuingto the breakpoint, gdb prints something like:&lt;pre  class="brush: plain"&gt;Breakpoint 2, Guitar::tick (this=0x805cde8) at Guitar.cpp:100&lt;br /&gt;(gdb)&lt;br /&gt;&lt;/pre&gt;The "this" variable points to the current instance of the "Guitar" object. If an instance variable, say "pluckAmp", cannot be found when you try to print it, try instead&lt;pre  class="brush: plain"&gt;(gdb) p this-&gt;pluckAmp&lt;br /&gt;$1 = 0.296875&lt;br /&gt;&lt;/pre&gt;Also, &lt;b&gt;"this"&lt;/b&gt; can be dereferenced to list all instance variables:&lt;pre  class="brush: plain"&gt;(gdb) p *this&lt;br /&gt;$2 = {&amp;lt;plucked3&amp;gt; = {&amp;lt;instrmnt&amp;gt; = {&amp;lt;stk&amp;gt; = {static STK_SINT8 = 1, &lt;br /&gt;static srate = 22050, _vptr.Stk = 0x8059020}, &lt;br /&gt;lastOutput = 0}, delayLine = 0x805ce70, delayLine2 = 0x8064f18, &lt;br /&gt;combDelay = 0x806cfb0, filter = 0x8075040, filter2 = 0x80750f8}&lt;br /&gt;&lt;/pre&gt;Suppose we're interested in &lt;b&gt;filter2&lt;/b&gt; above:&lt;pre  class="brush: plain"&gt;(gdb) p filter2&lt;br /&gt;$3 = (BiQuad *) 0x80750f8&lt;br /&gt;&lt;/pre&gt;Very cryptic! What does it mean? It says that "filter2" is an instance of the "BiQuad" class, so itcan be dereferenced.&lt;pre  class="brush: plain"&gt;(gdb) p *filter2&lt;br /&gt;$4 = {&amp;lt;filter&amp;gt; = {&amp;lt;stk&amp;gt; = {static STK_SINT8 = 1, &lt;br /&gt;static srate = 22050, _vptr.Stk = 0x80590e0}, &lt;br /&gt;gain = 0.60459499999999999, nB = 3, nA = 3, &lt;br /&gt;b = 0x8075140,  a = 0x8075120, &lt;br /&gt;outputs = 0x8075180, inputs = 0x8075160}, &amp;lt;no data fields&amp;gt;}&lt;br /&gt;(gdb)&lt;br /&gt;&lt;/pre&gt;Note that the superclass instance variables are enclosed in curly brackets!(the leaf class instance variables begin with &lt;b&gt;"gain"&lt;/b&gt; in this example).Suppose we want to see the "filter2" coefficients:&lt;pre  class="brush: plain"&gt;(gdb) p filter2-&amp;gt;b[0] @ 3&lt;br /&gt;$5 = {1, -1.03, 0.21540000000000001}&lt;br /&gt;(gdb) p filter2-&amp;gt;a[0] @ 3&lt;br /&gt;$6 = {1, -1.3337300000000001, 0.446191}&lt;br /&gt;(gdb)&lt;br /&gt;&lt;/pre&gt;and so on.     &lt;b&gt;How to set breakpoints in a template?&lt;/b&gt;&lt;pre  class="brush: plain"&gt;objdump -t libMyLib.so | c++filt | grep 'BarAbstract.*Baz'&lt;/pre&gt;Result is:&lt;pre  class="brush: plain"&gt;0000d2d6 w F .text 0000000a     MY_PLUGIN_A::Foo&amp;lt;MY_PLUGIN_A::BarAbstract&amp;gt;::Baz()&lt;br /&gt;&lt;/pre&gt;now&lt;pre  class="brush: plain"&gt;(gdb) b MY_PLUGIN_A::Foo&amp;lt;MY_PLUGIN_A::BarAbstract&amp;gt;::Baz()&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;How to inspecting crashes?&lt;/b&gt;When program crash  we  want to know who called this method and we would like to be ableto examine values in the calling methods.So at the gdb prompt, we type backtrace which gives me the following output:&lt;pre  class="brush: plain"&gt;(gdb) bt&lt;br /&gt;#0  Node&amp;lt;int&amp;gt;::next (this=0x0) at main.cc:28&lt;br /&gt;#1  0x2a16c in LinkedList&amp;lt;int&amp;gt;::remove (this=0x40160, &lt;br /&gt;item_to_remove=@0xffbef014) at main.cc:77&lt;br /&gt;#2  0x1ad10 in main (argc=1, argv=0xffbef0a4) at main.cc:111&lt;br /&gt;(gdb)&lt;br /&gt;&lt;/pre&gt;So in addition to what we knew about the current method and the local variables, we can now also see what methods called us and what their parameters were. For example, we can see that we were called by&lt;b&gt;LinkedList&amp;lt;int&amp;gt;::remove ()&lt;/b&gt; where the parameter item_to_remove is at address &lt;b&gt;0xffbef014&lt;/b&gt;.It may help us to understand our bug if we know the value of &lt;b&gt;item_to_remove&lt;/b&gt;, so we want to see the valueat the address of item_to_remove. This can be done using the gdb x command using the address as a parameter.Here is what happens:&lt;pre  class="brush: plain"&gt;(gdb) x 0xffbef014&lt;br /&gt;0xffbef014: 0x00000001&lt;br /&gt;(gdb)&lt;br /&gt;&lt;/pre&gt;So the program is crashing while trying to run &lt;b&gt;LinkedList&lt;int&gt;::remove&lt;/b&gt; with a parameter of 1.We have now narrowed the problem down to a specific function and a specific value for the parameter.&lt;p/&gt;You can use up command to browse backtrace:&lt;pre  class="brush: plain"&gt;(gdb) up 2&lt;br /&gt;(gdb) list (to source code at this line)&lt;br /&gt;&lt;/pre&gt;&lt;h2&gt;gprof&lt;/h2&gt;&lt;b&gt;Have a performance problems?&lt;/b&gt;Debugging will not help. Take a look at GNU gprof (Kprof for X addicted).Here is typical gprof session. Let's have a file &lt;b&gt;NameDB.cpp&lt;/b&gt; and corresponding &lt;b&gt;NameDBTest.cpp&lt;/b&gt;that contains main method:1. Compile it&lt;pre  class="brush: plain"&gt;g++ -pg -g2 -O2 -lc -o namedb NameDB.cpp NameDBTest.cpp&lt;br /&gt;&lt;/pre&gt;2. Then you have to run it so the information will be collected. File "gmon.out" will be created by gprof.&lt;pre  class="brush: plain"&gt;./namedb&lt;br /&gt;&lt;/pre&gt;3. First look at the "flat profile" &lt;pre  class="brush: plain"&gt;gprof namedb gmon.out -p&lt;br /&gt;&lt;/pre&gt;4. Then you can see call graph&lt;pre  class="brush: plain"&gt;gprof namedb gmon.out -q&lt;br /&gt;&lt;/pre&gt;5. Finally, you might want to have an "annotated source" listing, which prints out the source code to the application,with notes on how many times each function is called.&lt;pre  class="brush: plain"&gt;gprof namedb gmon.out -A&lt;br /&gt;&lt;/pre&gt;gprof's biggest limitation: &lt;b&gt;it only profiles user time while the application is running.&lt;/b&gt;Typically, applications spend some of their time in user code and some in "system code," such as kernel system calls.You can see spent time:&lt;pre  class="brush: plain"&gt;time ./namedb&lt;br /&gt;&lt;/pre&gt;Result is:&lt;pre  class="brush: plain"&gt;real    0m15.350s&lt;br /&gt;user    0m15.014s&lt;br /&gt;sys     0m0.017s&lt;br /&gt;&lt;/pre&gt;"man time" for more information.To measure time spend on certain block of code you can use &lt;b&gt;boost::progress_timer&lt;/b&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14240039-4886527288423018876?l=zlatozar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zlatozar.blogspot.com/feeds/4886527288423018876/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14240039&amp;postID=4886527288423018876' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/4886527288423018876'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/4886527288423018876'/><link rel='alternate' type='text/html' href='http://zlatozar.blogspot.com/2010/11/unix-tools-during-c-coding.html' title='UNIX tools during C++ coding'/><author><name>Zlatozar</name><uri>http://www.blogger.com/profile/16257250071061885492</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/17/6760/640/RabotnotoMqsto.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14240039.post-3383696394234763767</id><published>2008-02-27T13:17:00.010+02:00</published><updated>2008-12-03T14:08:20.450+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='думи'/><title type='text'>Моето сто процентово, съвършено момиче</title><content type='html'>от &lt;b&gt;Харуки Мураками*&lt;/b&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;В една красива априлска утрин, на не много широка улица в модерния квартал Харайку в Токио, се разминах със сто процентово, съвършено момиче.&lt;br /&gt;Ако трябва да бъда честен, тя не изглеждаше добре. Не впечатляваше по никакъв начин. Не беше и облечена с нещо по-специално. Отзад косата и все още беше сплескана от възглавницата. Не беше и много млада - около тридесетте, затова може би неправилно да я наричам "момиче". Но въпреки това, сега гледайки я от тридесетина метра: Да, тя е сто процентово, съвършено момиче. В момента, в който се разминахме, устата ми стана суха като пустиня и нещо в гърдите ми се разбунтува.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Може би имате свой тип момичета - такива с слаби глезени, или да кажем с големи очи, или изящни пръсти или си привлечен от жена, която цени храната. Аз също имам свои тип, разбира се. Понякога в ресторанта се улавям, че съм се втренчил в момичето на съседната маса, само защото има хубава форма на носа. Никои не може да твърди, че неговото сто процентово, съвършено момиче е от определен, конкретен тип. Така като ми правят впечатление носовете аз не мога да се сетя за гърдите и, дори и да са били големи. Всичко, за което се сещам е, че не беше голяма хубавица. Малко е странно.&lt;br /&gt;&lt;br /&gt;&lt;em&gt;"Вчера срещнах сто процентово, съвършено момиче"&lt;/em&gt; - ще кажа на някой.&lt;br /&gt;&lt;br /&gt;&lt;em&gt;"Така ли?"&lt;/em&gt; - ще ми отвърне той. &lt;em&gt;"Красавица, а?"&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;"Не, не мисля."&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;"Тогава е била твой тип, нали?"&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;"Ами не знам. Не мога да си я спомня точно. Нито очите и, нито големината на гърдите."&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;"Много странно."&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;"Да. Странно наистина."&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;"Както и да е"&lt;/em&gt; ми отвръща отегчено, &lt;em&gt;"Какво направи? Заговори ли я? Или тръгна след нея?"&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;"О, не. Просто се разминахме по улицата."&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;Тя вървеше от изток на запад, а аз от запад на изток. Беше наистина превъзходна априлска сутрин. Щеше ми се да бях я заговорил. Половин час щеше да е предостатъчно. Просто ще я помоля да ми разкаже за себе си, аз да и кажа нещо за мен, какво обичам да правя. Да се опитам да и обясня сложността на ориста и как тя ни довела на малката уличка в тази прекрасна априлска утрин на 1981. Със сигурност щеше да се получи нещо натъпкано с топли тайни, нещо като античен часовник, създаден във време на спокойствие и мир.&lt;br /&gt;След като поговорихме, може би щяхме да обядваме някъде, после да изгледаме филм на Уди Алън и да пийнем по коктейл в фоайето на някой хотел. При добро стечение на обстоятелствата, щяхме да се любим. Може би сърцето ми щеше да откликне. Сега разстоянието между нас е 30 метра. Как да се доближа до нея? Какво да и кажа?&lt;br /&gt;&lt;br /&gt;&lt;em&gt;"Добро утро, госпожице. Ще може ли да ми отделите няколко минутки за разговор?"&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;Смешно е. Ще звуча като продавач на евтина стока.&lt;br /&gt;&lt;br /&gt;&lt;em&gt;"Извинете ме, бихте ли ми казали дали има в квартала денонощно химическо чистене?"&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;Не, глупаво е. Не нося никакви дрехи за химическо. Кой ще се хване на такава лъжа? А защо не, да кажа истината.&lt;br /&gt;&lt;br /&gt;&lt;em&gt;"Добро утро. Вие за мен сте сто процентово, съвършено момиче."&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;Не, тя няма да повярва. Или може би ще повярва, но няма да иска да говори с мен. Извинете, би казала тя, може да съм сто процентово, съвършено момиче за вас, но аз не мисля че вие сте сто процентово, съвършено момче за мен. Може и така да стане и тогава аз ще съм в неловка ситуация и ще ми се прииска да се разпадна на хиляди парчета. Едва ли ще мога да се съвзема от такъв шок. Аз съм на 32 и едно е сигурно, ще остарявам. &lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Разминахме се пред един цветарски магазин. Топла струя въздух докосна кожата ми. Усещах аромата на рози премесен с влагата, изпаряваща се от топлия асфалт. Не мога да започна разговора. Тя носеше бял пуловер. В лявата и ръка видях, че държи писмо, на което му липсваше само пощенска марка. Вероятно е писала на някой дълго писмо. Може би е прекарала цялата нощ в писане, личеше по сънените и очи. Това писмо може би описваше нейната най-съкровена тайна. Направих още няколко крачки и пак се обърнах, тя се бе изгубила в тълпата. Сега вече късно, но знаех какво точно да и кажа. Това щеше да е дълъг разговор, прекалено дълъг, за да мога да го опиша в подробности. Идеята, която ме осени не беше от най-практичните.&lt;br /&gt;Как да я опиша? Ами ще започна с &lt;em&gt;"Имало едно време"&lt;/em&gt; и ще завърша с &lt;em&gt;"Тъжна история, не мислиш ли?"&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Имало едно време, едно момче и едно момиче. Момчето било на 18, а момичето на 16. Той не изглеждал много добре, а и тя не била неземна красавица. Просто, самотно момче и обикновено момиче, като всички останали. Но те вярвали с цялото си сърце, че на този свят за тях съществуват сто процентово, съвършено момиче и сто процентово, съвършено момче. Да, те вярвали в това чудо. И един ден това чудо се случило. Този ден те се засекли на ъгъла на две малки улички.&lt;br /&gt;&lt;br /&gt;&lt;em&gt;"Това е странно"&lt;/em&gt;, казал той.&lt;br /&gt;&lt;br /&gt;&lt;em&gt;"Аз те търсих през всичкото това време. Няма да повярваш, но ти си моето сто процентово, съвършено момиче."&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;"Ами да!"&lt;/em&gt; казала му тя, &lt;em&gt;"ти си моето сто процентово, съвършено момче. Така съм си представяла всеки един детайл. Това е като сбъднат сън."&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;Те седнали на една пейка в парка, разказвали си своите истории и се държали за ръце. Те не били самотни вече. Постепенно открили, че си пасват на сто процента. Колко прекрасното нещо е да откриеш или да бъдеш открит от твоята половинка. Твоята сто процентова, съвършена половинка! Това е чудо, космическа сила. Така както си седели и говорели обаче, малко по-малко започнало да е прокрадва съмнение: Може ли една мечта да се случи толкова лесно? И така в една от техните паузи в разговора, момчето казало на момичето, &lt;br /&gt;&lt;br /&gt;&lt;em&gt;"Нека да направим един тест - само веднъж. Ако ние сме сто процента един за друг, тогава един ден, някъде ние ще се срещнем пак. И ако това стане, ние ще сме сигурни, че сме родени един за друг и веднага ще се оженим. Веднага. Какво мислиш?"&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;"Да,"&lt;/em&gt; казала тя, &lt;em&gt;"точно така би било добре да направим."&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;И така те се разделили, тя тръгнала на изток, той на запад. Теста, на който се подложили бил напълно излишен. Не е трябвало да го правят, защото те наистина били един за друг на 100%, и е истинско чудо, че са се срещнали. Младостта им изиграла лоша шега, нямало как да знаят. Студената и безразлична съдба си играела безмилостно с тях.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Една зима и двамата легнали болни, поразени от ужасен грип. Седмици наред били между живота и смъртта. Накрая загубили всички свои спомени. Когато се събудили, не помнели нищо. Те станали двама лъчезарни млади хора, но макар да полагали непрестанно усилия не могли да си възвърнат предишните знания и чувства. Слава богу, те се превърнали в истински граждани, които знаят как да се прехвърлят от една спирка в метрото на друга, знаели и да как да изпращат специални колетни пратки. Дори очаквали отново любовта в проценти, 75% дори 85%.&lt;br /&gt;Времето летяло с неочаквана лекота. Скоро той навършил 32, а тя 30. В една красива априлска утрин в търсене на ароматно кафе, за събуждане момчето вървяло от запад на изток, докато момичето вървяло от изток на запад, за да прати писмо. И това става на не много широка улица в модерния квартал Харайку в Токио. Те се разминали по средата на улицата. За много кратко светъл лъч просветнал в загубената им памет и поразил сърцата им. Всеки един от тях почувствал някакво странно усещане право в гърдите. Те знаели:&lt;br /&gt;&lt;br /&gt;Тя е моето сто процентово, съвършено момиче.&lt;br /&gt;&lt;br /&gt;Той е моето сто процентово, съвършено момче.&lt;br /&gt;&lt;br /&gt;Но пламъчето на техните спомени бил толкова слаб и те не могли да имат решителността отпреди четиринадесет години.&lt;br /&gt;Без да проронят и дума, те се разминават и изчезват в тълпата. Завинаги.&lt;br /&gt;&lt;br /&gt;Тъжна история, не мислиш ли?&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Да, вече знам, това трябваше да и кажа.&lt;/b&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;* преведено по мой вкус&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14240039-3383696394234763767?l=zlatozar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zlatozar.blogspot.com/feeds/3383696394234763767/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14240039&amp;postID=3383696394234763767' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/3383696394234763767'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/3383696394234763767'/><link rel='alternate' type='text/html' href='http://zlatozar.blogspot.com/2008/02/blog-post_27.html' title='Моето сто процентово, съвършено момиче'/><author><name>Zlatozar</name><uri>http://www.blogger.com/profile/16257250071061885492</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/17/6760/640/RabotnotoMqsto.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14240039.post-350795154648396251</id><published>2008-02-20T14:52:00.006+02:00</published><updated>2010-11-15T15:26:25.557+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='misc'/><title type='text'>Metallica в България!</title><content type='html'>Бях на първия концерт в Пловдив, беше невероятно! Сега в София на &lt;b&gt;25 юли&lt;/b&gt; на Националния стадион "Васил Левски". Идва лято, а през лятото наистина стават чудеса. Леле Metallica, не мога да повярвам. Естествено започвам да разучавам всички песни, защото предния път мрънках под носа. Започвам с &lt;em&gt;"Die Die My Darling"&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;object width="425" height="355"&gt;&lt;param name="movie" value="http://www.youtube.com/v/4GIisWJJG28&amp;rel=1"&gt;&lt;/param&gt;&lt;param name="wmode" value="transparent"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/4GIisWJJG28&amp;rel=1" type="application/x-shockwave-flash" wmode="transparent" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14240039-350795154648396251?l=zlatozar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zlatozar.blogspot.com/feeds/350795154648396251/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14240039&amp;postID=350795154648396251' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/350795154648396251'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/350795154648396251'/><link rel='alternate' type='text/html' href='http://zlatozar.blogspot.com/2008/02/metallica.html' title='Metallica в България!'/><author><name>Zlatozar</name><uri>http://www.blogger.com/profile/16257250071061885492</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/17/6760/640/RabotnotoMqsto.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14240039.post-4981671923001010070</id><published>2008-02-05T00:58:00.004+02:00</published><updated>2010-11-15T15:26:42.534+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='misc'/><title type='text'>Led Zeppelin като терапия</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp;Колко бавно минава времето, когато нещо ти тежи. Нещо те яде отвътре и не си намираш място. Обвиняваш се и връщаш времето назад. Всички казват "нормално е", но никой не знае до кога. Няма универсално лекарство. Няма и универсален съвет. Аз с моите мисли и много много въпроси. От време на време, като остана сам нещо ме хваща за гърлото, подтискам се и угасвам. Самотата ми тежи. Не трябва да оставам сам, аз си знам.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Сега обаче откривам истинското приятелство. Разбират ме, че страдам и се грижат за мен. Не ме оставят сам. Обичам приятелите си и аз ще помагам и аз ще бъда с тях. Бих се погубил ако ги нямах.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Бавно оптимизмът ми се завръща. Винаги има и добра страна. Ще престана да си задавам въпроси, за да не си черня дните и мислите. Няма да се предам! Не съм сторил лошо. Един ден ще има Rock'n Roll, baby и аз ще бъда по-силен от всякога. Знам, че няма невъзможни неща.&lt;br /&gt;&lt;br /&gt;&lt;em&gt;"Невъзможно е само силна дума, използвана от слаби хора, намиращи за по-лесно да живеят в света, който им е отреден, вместо да открият силата в себе си да го променят. Невъзможно не е факт. То е убеждение. Невъзможно не е твърдение. То е предизвикателство. Невъзможно е осъществимо. Невъзможно е временно. Невъзможно е нищо."&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;object width="425" height="355"&gt;&lt;param name="movie" value="http://www.youtube.com/v/5BC6Es3m6T4&amp;rel=1"&gt;&lt;/param&gt;&lt;param name="wmode" value="transparent"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/5BC6Es3m6T4&amp;rel=1" type="application/x-shockwave-flash" wmode="transparent" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14240039-4981671923001010070?l=zlatozar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zlatozar.blogspot.com/feeds/4981671923001010070/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14240039&amp;postID=4981671923001010070' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/4981671923001010070'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/4981671923001010070'/><link rel='alternate' type='text/html' href='http://zlatozar.blogspot.com/2008/02/led-zeppelin.html' title='Led Zeppelin като терапия'/><author><name>Zlatozar</name><uri>http://www.blogger.com/profile/16257250071061885492</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/17/6760/640/RabotnotoMqsto.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14240039.post-4478019929395796475</id><published>2008-02-02T17:42:00.001+02:00</published><updated>2008-02-29T17:48:16.417+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='думи'/><title type='text'>Сънувах татко</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_O17Am5thzlA/R6SjWuj10rI/AAAAAAAAA2M/5D0qjgywl94/s1600-h/02022008825.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_O17Am5thzlA/R6SjWuj10rI/AAAAAAAAA2M/5D0qjgywl94/s400/02022008825.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5162430683724239538" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;&lt;br /&gt;Сънувах татко! Мил и добър.&lt;br /&gt;&lt;br /&gt;С много внимание ми обясняваше нещо, не помня какво точно. Обичаше да му помагам или да ми показва как се прави нещо. Да съм до него. Харесваше му близостта ни. Беше търпелив и усърден. Липсва ми страшно много! Искам да ме съветва, да се допитвам до него, да ми е опора.&lt;br /&gt;Защо Господи ми го отне?&lt;br /&gt;&lt;br /&gt; Татко винаги се грижеше за мен, и сега, когато се нуждая от него слезе да ми помогне. Беше със старите сини работнически дрехи усмихнат и вдъхващ кураж. С прошарена коса и меки топли длани, които усещах на рамото си.&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;"Как си, Злате?"&lt;/em&gt; -  ми казва.&lt;br /&gt;&lt;em&gt;"Тъжно ми е татко!"&lt;/em&gt; - отвръщам.&lt;br /&gt;&lt;em&gt;"Ех сине, всичко ще се нареди, аз съм до теб!"&lt;/em&gt;&lt;br /&gt;&lt;br /&gt; Исках да го докосна и да усетя мириса на машинно масло премесен с тютюнев дим пропит в дрехите му. Самото присъствие ме успокояваше и ми даваше сигурност. Близо до него, какво по-утешаващо от това. Татко, винаги съм те обичал, помагай и идвай в сънищата ми, нужен си ми.&lt;br /&gt;&lt;br /&gt;Бях добро дете, не можех да го гледам на стълбите пред къщата тъжен с цигара в ръка заради някоя моя постъпка. Не можех да си позволя да го натъжа. Съвест и честност, това ни е крепяло. Не наранявам хората. Добър човек съм, помагам и сега. Какво съм сторил и с какво съм заслужил това, което ми причини жената до мен. Не съм жесток и никога няма да бъда. Татко ме учеше на това. Той наистина е преживял много и съдбата е била сурова с него. Не, не е се озлоби, просто пушеше много. Едни красив мъж, който тъеше много мъка в себе си. Мъка наслоена с времето. Как да го нараниш, затова бях добър син. Бих дал всичко от себе си да е до мен и да е щастлив. &lt;br /&gt;&lt;br /&gt;Ще се радва да съм щастлив и аз, затова ми помага, затова идва в сънищата ми, затова и аз ще го обичам. Той е моя татко!&lt;br /&gt;&lt;br /&gt;Идвай в сънищата ми, чакам те. Чу ли?&lt;br /&gt;&lt;br/&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14240039-4478019929395796475?l=zlatozar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zlatozar.blogspot.com/feeds/4478019929395796475/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14240039&amp;postID=4478019929395796475' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/4478019929395796475'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/4478019929395796475'/><link rel='alternate' type='text/html' href='http://zlatozar.blogspot.com/2008/02/blog-post.html' title='Сънувах татко'/><author><name>Zlatozar</name><uri>http://www.blogger.com/profile/16257250071061885492</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/17/6760/640/RabotnotoMqsto.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_O17Am5thzlA/R6SjWuj10rI/AAAAAAAAA2M/5D0qjgywl94/s72-c/02022008825.jpg' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14240039.post-486257486042322747</id><published>2008-01-18T15:03:00.008+02:00</published><updated>2011-03-02T17:34:09.546+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>Start/Stop openvpn script</title><content type='html'>Днес ми се наложи да направя VPN до Исландия с openvpn и дадения ми ключ (zlatozar.ovpn). Под линукс малко се озорих. То не бяха bridges то не беше чудо. Затова реших да сложа скрипта, който написах с много помощ от Google.&lt;br /&gt;Първо си проверявам ip-то и routing таблицата:&lt;br /&gt;&lt;pre&gt;$sudo ifconfig&lt;br /&gt;$sudo route -n&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;След това стартирам скрипта (кръстил съм го open_vpn_script.sh):&lt;br /&gt;&lt;pre  class="brush: shell"&gt;#!/bin/bash&lt;br /&gt;&lt;br /&gt;#################################&lt;br /&gt;#&lt;br /&gt;# Set up Ethernet bridge on Linux&lt;br /&gt;# Requires: bridge-utils&lt;br /&gt;#&lt;br /&gt;#NOTE:&lt;br /&gt;# iptables -A INPUT -i tap0 -j ACCEPT&lt;br /&gt;# iptables -A INPUT -i br0 -j ACCEPT&lt;br /&gt;# iptables -A FORWARD -i br0 -j ACCEPT&lt;br /&gt;#&lt;br /&gt;#################################&lt;br /&gt;&lt;br /&gt;# Define Bridge Interface&lt;br /&gt;br="br0"&lt;br /&gt;&lt;br /&gt;# Define list of TAP interfaces to be bridged,&lt;br /&gt;# for example tap="tap0 tap1 tap2".&lt;br /&gt;tap="tap0"&lt;br /&gt;&lt;br /&gt;# Define physical ethernet interface to be bridged&lt;br /&gt;# with TAP interface(s) above.&lt;br /&gt;eth="eth0"&lt;br /&gt;&lt;br /&gt;eth_ip="your current ip"&lt;br /&gt;&lt;br /&gt;eth_netmask="255.255.255.0"&lt;br /&gt;eth_broadcast="xxx.xxx.xxx.255"&lt;br /&gt;&lt;br /&gt;gw="your  getway"&lt;br /&gt;&lt;br /&gt;case "$1" in&lt;br /&gt;&lt;br /&gt;    start)&lt;br /&gt;        for t in $tap; do&lt;br /&gt;            openvpn --mktun --dev $t&lt;br /&gt;        done&lt;br /&gt;&lt;br /&gt;        brctl addbr $br&lt;br /&gt;        brctl addif $br $eth&lt;br /&gt;&lt;br /&gt;        for t in $tap; do&lt;br /&gt;            brctl addif $br $t&lt;br /&gt;        done&lt;br /&gt;&lt;br /&gt;        ifconfig $eth 0.0.0.0 promisc up&lt;br /&gt;&lt;br /&gt;        ifconfig $br $eth_ip netmask $eth_netmask broadcast $eth_broadcast&lt;br /&gt;        route add default gw $gw&lt;br /&gt;        ;;&lt;br /&gt;&lt;br /&gt;    stop)&lt;br /&gt;        ifconfig $br down&lt;br /&gt;        brctl delbr $br&lt;br /&gt;&lt;br /&gt;        for t in $tap; do&lt;br /&gt;            openvpn --rmtun --dev $t&lt;br /&gt;        done&lt;br /&gt;&lt;br /&gt;        ifconfig $eth $eth_ip netmask $eth_netmask broadcast $eth_broadcast&lt;br /&gt;        route add default gw $gw&lt;br /&gt;        ;;&lt;br /&gt;&lt;br /&gt;    *)&lt;br /&gt;    echo "usage openvpn-bridge {start|stop}"&lt;br /&gt;&lt;br /&gt;    exit 1&lt;br /&gt;    ;;&lt;br /&gt;esac&lt;br /&gt;&lt;br /&gt;exit 0&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;И сега вече пускам смело:&lt;br /&gt;&lt;pre&gt;# Start&lt;br /&gt;sudo ./open_vpn_script.sh start&lt;br /&gt;sudo openvpn zlatozar.ovpn&lt;br /&gt;&lt;br /&gt;# Stop&lt;br /&gt;sudo ./open_vpn_script.sh stop&lt;br /&gt;sudo route -n&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Сега ми изглежда лесно, но не мислех така сутринта.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14240039-486257486042322747?l=zlatozar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zlatozar.blogspot.com/feeds/486257486042322747/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14240039&amp;postID=486257486042322747' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/486257486042322747'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/486257486042322747'/><link rel='alternate' type='text/html' href='http://zlatozar.blogspot.com/2008/01/startstop-openvpn-script.html' title='Start/Stop openvpn script'/><author><name>Zlatozar</name><uri>http://www.blogger.com/profile/16257250071061885492</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/17/6760/640/RabotnotoMqsto.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14240039.post-5232456280536837189</id><published>2007-09-28T16:58:00.019+03:00</published><updated>2011-03-02T17:19:35.454+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Enum as dispatcher</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Вчера видях един от коментарите на предишно мое писание (&lt;a href="http://zlatozar.blogspot.com/2007/08/repeated-operations-pattern.html#links"&gt;ето това&lt;/a&gt;) и се сетих за нещо, което може да ми влезне в употреба. След като имам краен брой операции (enum), не може ли да "разхвърлям". Добре, няма да е много трудно. Примерно две операции: минус и плюс.&lt;br /&gt;&lt;pre class="brush: java"&gt;protected interface SumHandler {&lt;br /&gt;   String handle(int one, int two);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;protected enum Operation {&lt;br /&gt;&lt;br /&gt;    minus(new MinusHandler()), plus(new PlusHandler());&lt;br /&gt;    SumHandler handler;&lt;br /&gt;&lt;br /&gt;    Operation(SumHandler handler) {&lt;br /&gt;        this.handler = handler;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public String process(int one, int two) {&lt;br /&gt;        return handler.handle(one, two);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Това е случая, в който операциите плюс и минус са мнооого трудоемки или пък ни тряба отделна инстанция за всеки един от тях. При мен случая обаче е друг, много кратки обработки(даже тривиални), за които не е нужен никакво състояние.&lt;br /&gt;Затова се изхитрям и ги реализирам като стойност, на която "присвоявам" функция. Да така е макар, че не се вижда на пръв поглед.&lt;br /&gt;&lt;pre class="brush: java"&gt;public class EnumAsDispatcher {&lt;br /&gt;    private final static Logger log = Logger.getLogger(EnumAsDispatcher.class);&lt;br /&gt;&lt;br /&gt;    protected interface SumHandler {&lt;br /&gt;        String handle(int one, int two);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private static SumHandler minusHandler = new SumHandler() {&lt;br /&gt;&lt;br /&gt;    public String handle(int one, int two) {&lt;br /&gt;        log.debug("Substitution: one = " + one + ", two = " + two);&lt;br /&gt;        return "Success substitution";&lt;br /&gt;    }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;private static SumHandler plusHandler = new SumHandler() {&lt;br /&gt;    public String handle(int one, int two) {&lt;br /&gt;        log.debug("Sum: one = " + one + ", two = " + two);&lt;br /&gt;        return "Success sum";&lt;br /&gt;    }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;/** Enumeration for all operations (with attached functionality for each operation) */&lt;br /&gt;protected enum Operation {&lt;br /&gt;    minus(minusHandler), plus(plusHandler);&lt;br /&gt;&lt;br /&gt;    SumHandler handler;&lt;br /&gt;&lt;br /&gt;    Operation(SumHandler handler) {&lt;br /&gt;        this.handler = handler;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public String process(int one, int two) {&lt;br /&gt;        return handler.handle(one, two);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;    public static void main(String[] args) {&lt;br /&gt;&lt;br /&gt;        String mathOperation = "minus";&lt;br /&gt;&lt;br /&gt;        Operation operation = Operation.valueOf(mathOperation);&lt;br /&gt;        operation.process(1, 2);&lt;br /&gt;&lt;br /&gt;        mathOperation = "plus";&lt;br /&gt;&lt;br /&gt;        operation = Operation.valueOf(mathOperation);&lt;br /&gt;        operation.process(2, 1);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Така че благодаря за подсказката&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14240039-5232456280536837189?l=zlatozar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zlatozar.blogspot.com/feeds/5232456280536837189/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14240039&amp;postID=5232456280536837189' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/5232456280536837189'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/5232456280536837189'/><link rel='alternate' type='text/html' href='http://zlatozar.blogspot.com/2007/09/enum-as-dispatcher.html' title='Enum as dispatcher'/><author><name>Zlatozar</name><uri>http://www.blogger.com/profile/16257250071061885492</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/17/6760/640/RabotnotoMqsto.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14240039.post-1399101802539260098</id><published>2007-08-31T16:09:00.001+03:00</published><updated>2011-03-02T17:20:23.930+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Repeated operations shortcut</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp;Когато пиша някакъв код се стремя той да е макасимално четим(разбирай опростен и подреден), но с времето нещата набъбват и четимоста отстъпва място на елегантноста. Ето и конкретния случай. Имам си класа &lt;b&gt;SFAdapter&lt;/b&gt;, който прави връзката към SalesForce.com и изпънява заявките. Този менаджер може да бъде всъшност всякакъв примерно към базата. В него имах само три неща - инициализация на връзката, логин и метод за подаване на заявките:&lt;br /&gt;&lt;pre&gt;................&lt;br /&gt;public SFAdapter(final String sfUser, final String sfPass) {&lt;br /&gt;if( sfUser==null || sfPass==null ) return;&lt;br /&gt;&lt;br /&gt;this.sfUser=sfUser;&lt;br /&gt;this.sfPass=sfPass;&lt;br /&gt;try {&lt;br /&gt;binding = (SoapBindingStub) new SforceServiceLocator().getSoap(new URL("some_url"));&lt;br /&gt;} catch (Exception e) {&lt;br /&gt;&lt;br /&gt;.....................&lt;br /&gt;&lt;br /&gt;protected void doLogin() .............&lt;br /&gt;&lt;br /&gt;public QueryResult query(final String ) .............&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Да обаче проеката си нараства и се налага да се добавят все повече и повече методи, който са абсолуютно еднакви като структура:&lt;br /&gt;&lt;pre&gt;public типа_които_ще_върне име(параметри) {&lt;br /&gt;try {&lt;br /&gt;&lt;br /&gt;изпънява_заявката&lt;br /&gt;&lt;br /&gt;// следват нещата, които ще направи при грешка&lt;br /&gt;} catch (UnexpectedErrorFault uef) {&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;И какво се получава - много писане. Верно проситчки неща ама много писане беее. Сегиз-тогиз е добре да се консултираш. Ето в какво се превърна кода след консултацията с колегите.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Повтарящите се неща да се на едно място. Операциите трябва да се уеднаквят. Това е посоката на мислене. И самия код:&lt;br /&gt;&lt;pre&gt;public void delete(final String[] ids) {&lt;br /&gt;executeInSf(new WriteCommand&amp;lt;Object&amp;gt;() {&lt;br /&gt;public Object execute() throws UnexpectedErrorFault, RemoteException {&lt;br /&gt;binding.delete(ids);&lt;br /&gt;return null;&lt;br /&gt;}&lt;br /&gt;});&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public SObject[] retrieve(final String fieldList, final String sObjectType, final String[] ids) {&lt;br /&gt;return executeInSf(new ReadCommand&amp;lt;SObject[]&amp;gt;() {&lt;br /&gt;public SObject[] execute() throws UnexpectedErrorFault, RemoteException {&lt;br /&gt;return binding.retrieve(fieldList, sObjectType, ids);&lt;br /&gt;}&lt;br /&gt;});&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;private &amp;lt;T&amp;gt; T executeInSf(Command&amp;lt;T&amp;gt; c) throws RecoverableSFException, CriticalSFException {&lt;br /&gt;try {&lt;br /&gt;return c.execute();&lt;br /&gt;} catch (UnexpectedErrorFault uef) {&lt;br /&gt;if (uef.getExceptionCode().equals(ExceptionCode.INVALID_SESSION_ID)) {&lt;br /&gt;try {&lt;br /&gt;doLogin();&lt;br /&gt;return c.execute();&lt;br /&gt;} catch (UnexpectedErrorFault e) {&lt;br /&gt;throw c.createException(e);&lt;br /&gt;} catch (InvalidIdFault e) {&lt;br /&gt;................... &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;interface Command&amp;lt;T extends Object&amp;gt; {&lt;br /&gt;T execute() throws UnexpectedErrorFault, RemoteException;&lt;br /&gt;RecoverableSFException createException(Exception cause);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;abstract class ReadCommand&amp;lt;T extends Object&amp;gt; implements Command&amp;lt;T&amp;gt;{&lt;br /&gt;public SFReadException createException(Exception cause) {&lt;br /&gt;return new SFReadException(cause);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;abstract class WriteCommand&amp;lt;T extends Object&amp;gt; implements Command&amp;lt;T&amp;gt;{&lt;br /&gt;public SFWriteException createException(Exception cause) {&lt;br /&gt;return new SFWriteException(cause);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;С простички думи. Операцията, която трябва да се изпълни я дефинираме в интерфейс(Command), а нещата които се повтарят в един метод, който приема като параметър този инерфейс(executeInSf). Следва и самото изпълнение(retrieve), която не прави нищо друго освен да иплементира изпълнението на операцията - execute метода.&lt;br /&gt;&lt;b&gt;NOTE:&lt;/b&gt; В метода delete забележете, че нама return, а execute трябва задължително да върне стойност и тя е null.&lt;br /&gt;Малко се усложниха нещата, защото имам два вида грешки:&lt;br /&gt;&lt;pre&gt;try {&lt;br /&gt;doLogin();&lt;br /&gt;return c.execute();&lt;br /&gt;} catch (UnexpectedErrorFault e) {&lt;br /&gt;// see here!&lt;br /&gt;throw c.createException(e);&lt;br /&gt;...........&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Правилото е, ако има има различия и допълнителни неща те се отделят в абстрактни класове, които наследяват инерфейса.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;И всичко това само, защото в Java не можем да предаваме функции. Ако беше така, на executeInSf щахме да предадем функцията, която трябва да се изпълни. Може би посоката на мислене трябва да е към езици за функционално програмиране.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14240039-1399101802539260098?l=zlatozar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zlatozar.blogspot.com/feeds/1399101802539260098/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14240039&amp;postID=1399101802539260098' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/1399101802539260098'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/1399101802539260098'/><link rel='alternate' type='text/html' href='http://zlatozar.blogspot.com/2007/08/repeated-operations-pattern.html' title='Repeated operations shortcut'/><author><name>Zlatozar</name><uri>http://www.blogger.com/profile/16257250071061885492</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/17/6760/640/RabotnotoMqsto.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14240039.post-2208926953918304691</id><published>2007-08-02T15:31:00.000+03:00</published><updated>2007-08-02T18:13:34.991+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='daily'/><title type='text'>Daily thoughts - 4</title><content type='html'>&lt;br&gt;&lt;br /&gt;&lt;b&gt;Enum as dispatcher&lt;/b&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Днес доработвах един код и ми хрумна идея. Какво ще стане ако се наложи да се направят две различни операции по даден критерий? В моя случай критерия е дали обекта е получен от XML или HTML файл. В зависимост се тръгва по две отделни "пътеки" да ги наречем (някъде навътре в бизнес логиката). Естественно първото нещо, което хрумва е да се приложи Factory pattern. Идеята не е никак лоша ако "пътеките" са дълги, резултатните обекти са много различни и се очаква критериите да набъбват. Тогава много лесно може да се добави трети обект в йерархията. Картинката е:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;                     +-------------+&lt;br /&gt;                     |             |&lt;br /&gt;                     | BaseObject  |&lt;br /&gt;                     +-------------+&lt;br /&gt;                        ^  ^   ^&lt;br /&gt;                    +---|  |   |------+&lt;br /&gt;                    |      |          |&lt;br /&gt;                    |      |          |&lt;br /&gt;              XMLObject HTMLObject NextObject&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Имайки тази йерархия следва и да имам дипечер, който да казва какво да се истанцира. Нещо такова:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public class ObjectFactory {&lt;br /&gt;    .........&lt;br /&gt;    public static ObjectReader getObjectReader( InputStream is ) {&lt;br /&gt;        int objectType = figureOutObjectType( is );&lt;br /&gt;&lt;br /&gt;        switch( objectType ) {&lt;br /&gt;        case ObjectReaderFactory.XML:&lt;br /&gt;            return new XMLReader( is );&lt;br /&gt;        case ObjectReaderFactory.HTML:&lt;br /&gt;            return new HTMLReader( is );&lt;br /&gt;        ..........&lt;br /&gt;        // etc.&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Да ама при мен ситуацията се различава - двата обекта са почти идентични. Те се различават само по едно единственно действие - операцията diff. Ако е XML се пуска някъде в "пътеката" &lt;em&gt;xmldiff.py&lt;/em&gt; ако не, &lt;em&gt;htmldiff.py&lt;/em&gt;. Ще имам само на едно място &lt;b&gt;if&lt;/b&gt;. Не мога ли да сложа действието в типа. Така измествам фокуса. Естественно щом имам изброим брой действия най-добре да си ползвам &lt;b&gt;enum&lt;/b&gt;. Хехе там лесно мога да дефинирам и операцията в зависимост от типа:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public enum DiffType {&lt;br /&gt;&lt;br /&gt;    XML {&lt;br /&gt;&lt;br /&gt;        String diffProgram()&lt;br /&gt;        {&lt;br /&gt;            return FileConstants.PYTHON_XMLDIFF_PROGRAM;&lt;br /&gt;        }&lt;br /&gt;    },&lt;br /&gt;&lt;br /&gt;    HTML {&lt;br /&gt;&lt;br /&gt;        String diffProgram()&lt;br /&gt;        {&lt;br /&gt;            return FileConstants.PYTHON_HTMLDIFF_PROGRAM;&lt;br /&gt;        }&lt;br /&gt;    };&lt;br /&gt;&lt;br /&gt;    // declare the methods defined by this enum&lt;br /&gt;    public abstract String diffProgram();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Ееее от тук нататък е лесно.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;private void diffFilePrepare(final MobileOperator operator) throws IOException&lt;br /&gt;{&lt;br /&gt;    .........&lt;br /&gt;    // dispach by type&lt;br /&gt;    diffMaker.madeDiffDisplay(operator.getDiffType());&lt;br /&gt;    .........&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;public void madeDiffDisplay(DiffType type) throws IOException&lt;br /&gt;    {&lt;br /&gt;        .........&lt;br /&gt;        try {&lt;br /&gt;            pythonLine[0] = "python";&lt;br /&gt;            pythonLine[1] = type.diffProgram();&lt;br /&gt;&lt;br /&gt;        .........&lt;br /&gt;        } catch (InterruptedException e) {&lt;br /&gt;            log.error("External program was interupted.");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Така хем си знам типа, хем и операцията за този тип. По-четимо го намирам. Е, разбира се то това е частен случай. Иначе Factory pattern rulez!&lt;br /&gt;&lt;br/&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14240039-2208926953918304691?l=zlatozar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zlatozar.blogspot.com/feeds/2208926953918304691/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14240039&amp;postID=2208926953918304691' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/2208926953918304691'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/2208926953918304691'/><link rel='alternate' type='text/html' href='http://zlatozar.blogspot.com/2007/08/daily-thoughts-4.html' title='Daily thoughts - 4'/><author><name>Zlatozar</name><uri>http://www.blogger.com/profile/16257250071061885492</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/17/6760/640/RabotnotoMqsto.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14240039.post-4284789828720701891</id><published>2007-07-23T17:34:00.000+03:00</published><updated>2007-08-07T17:17:44.374+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='daily'/><title type='text'>Daily thoughts - 3</title><content type='html'>&lt;br/&gt;&lt;br /&gt;Тази събота и неделя си поиграх да си направя firewall ето и резултата:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/bin/bash&lt;br /&gt;&lt;br /&gt;#INSTALL(Debian rulez)&lt;br /&gt;#      1. write this file as /etc/init.d/firewall&lt;br /&gt;#      2. chmod 755 /etc/init.d/firewall&lt;br /&gt;#      3. update-rc.d firewall defaults&lt;br /&gt;#&lt;br /&gt;#REMOVE&lt;br /&gt;#    update-rc.d -f firewall remove&lt;br /&gt;#&lt;br /&gt;# Author: zlatozar@gmail.com&lt;br /&gt;# Date: 2007/03/04&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#Our complete stateful firewall script.  This firewall can be customized for &lt;br /&gt;#a laptop, workstation, router or even a server. :)&lt;br /&gt;&lt;br /&gt;#change this to the name of the interface that provides your "uplink"&lt;br /&gt;#(connection to the Internet)&lt;br /&gt;&lt;br /&gt;UPLINK="eth0"&lt;br /&gt;&lt;br /&gt;#if you're a router (and thus should forward IP packets between interfaces),&lt;br /&gt;#you want ROUTER="yes"; otherwise, ROUTER="no"&lt;br /&gt;&lt;br /&gt;ROUTER="yes"&lt;br /&gt;&lt;br /&gt;#change this next line to the static IP of your uplink interface for static SNAT, or&lt;br /&gt;#"dynamic" if you have a dynamic IP.  If you don't need any NAT, set NAT to "" to&lt;br /&gt;#disable it.&lt;br /&gt;&lt;br /&gt;NAT="dynamic"&lt;br /&gt;&lt;br /&gt;#change this next line so it lists all your network interfaces, including lo&lt;br /&gt;&lt;br /&gt;INTERFACES="lo eth0 eth1"&lt;br /&gt;&lt;br /&gt;#change this line so that it lists the assigned numbers or symbolic names (from&lt;br /&gt;#/etc/services) of all the services that you'd like to provide to the general&lt;br /&gt;#public.  If you don't want any services enabled, set it to ""&lt;br /&gt;&lt;br /&gt;SERVICES="http https ftp smtp ssh rsync"&lt;br /&gt;# SRVICES_SAMBA="netbios-ssn microsoft-ds"&lt;br /&gt;&lt;br /&gt;start() {&lt;br /&gt;&lt;br /&gt;    echo "Starting firewall..."&lt;br /&gt;    iptables -P INPUT DROP&lt;br /&gt;    iptables -A INPUT -i ! ${UPLINK} -j ACCEPT&lt;br /&gt;    iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT&lt;br /&gt;    &lt;br /&gt;    #enable public access to certain services&lt;br /&gt;    for x in ${SERVICES}&lt;br /&gt;      do&lt;br /&gt;      iptables -A INPUT -p tcp --dport ${x} -m state --state NEW -j ACCEPT&lt;br /&gt;    done&lt;br /&gt; &lt;br /&gt;    # SAMBA ---------&lt;br /&gt;    iptables -A INPUT -p tcp --dport 137:139 -j ACCEPT&lt;br /&gt;    iptables -A INPUT -p tcp --dport 445 -j ACCEPT&lt;br /&gt;&lt;br /&gt;    iptables -A INPUT -p udp --dport 137:139 -j ACCEPT&lt;br /&gt;    iptables -A INPUT -p udp --dport 1025:65535 -j ACCEPT&lt;br /&gt;    # --------- &lt;br /&gt;&lt;br /&gt;    iptables -A INPUT -p tcp -i ${UPLINK} -j REJECT --reject-with tcp-reset&lt;br /&gt;    iptables -A INPUT -p udp -i ${UPLINK} -j REJECT --reject-with icmp-port-unreachable&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;    #explicitly disable ECN&lt;br /&gt;    if [ -e /proc/sys/net/ipv4/tcp_ecn ]&lt;br /&gt; then&lt;br /&gt; echo 0 &gt; /proc/sys/net/ipv4/tcp_ecn&lt;br /&gt;    fi   &lt;br /&gt;&lt;br /&gt;    #disable spoofing on all interfaces&lt;br /&gt;    for x in ${INTERFACES} &lt;br /&gt;      do &lt;br /&gt;      echo 1 &gt; /proc/sys/net/ipv4/conf/${x}/rp_filter     &lt;br /&gt;    done&lt;br /&gt;&lt;br /&gt;    if [ "$ROUTER" = "yes" ]&lt;br /&gt; then&lt;br /&gt; #we're a router of some kind, enable IP forwarding&lt;br /&gt; echo 1 &gt; /proc/sys/net/ipv4/ip_forward&lt;br /&gt; if [ "$NAT" = "dynamic" ]&lt;br /&gt;     then&lt;br /&gt;     #dynamic IP address, use masquerading &lt;br /&gt;     echo "Enabling masquerading (dynamic ip)..."&lt;br /&gt;     iptables -t nat -A POSTROUTING -o ${UPLINK} -j MASQUERADE&lt;br /&gt; elif [ "$NAT" != "" ]&lt;br /&gt;     then&lt;br /&gt;     #static IP, use SNAT&lt;br /&gt;     echo "Enabling SNAT (static ip)..."&lt;br /&gt;     iptables -t nat -A POSTROUTING -o ${UPLINK} -j SNAT --to ${UPIP}&lt;br /&gt; fi&lt;br /&gt;    fi&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;stop() {&lt;br /&gt;    echo "Stopping firewall..."&lt;br /&gt;    iptables -F INPUT&lt;br /&gt;    iptables -P INPUT ACCEPT&lt;br /&gt;    &lt;br /&gt;    #turn off NAT/masquerading, if any&lt;br /&gt;    iptables -t nat -F POSTROUTING&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;# Menu&lt;br /&gt;&lt;br /&gt;case "$1" in&lt;br /&gt;    start)&lt;br /&gt;        start&lt;br /&gt;        ;;&lt;br /&gt;    stop)&lt;br /&gt;        stop&lt;br /&gt;        ;;&lt;br /&gt;    *)&lt;br /&gt;        echo "Usage: /etc/init.d/firewall {start|stop}"&lt;br /&gt;        exit 1&lt;br /&gt;esac&lt;br /&gt;&lt;br /&gt;exit 0&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;PS. Това е firewall за моята работна станция затова се наложи да добавя специялна секция за SAMBA. Ако ще го ползвате за сервър я махнете.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14240039-4284789828720701891?l=zlatozar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zlatozar.blogspot.com/feeds/4284789828720701891/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14240039&amp;postID=4284789828720701891' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/4284789828720701891'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/4284789828720701891'/><link rel='alternate' type='text/html' href='http://zlatozar.blogspot.com/2007/07/daily-thoughts-3.html' title='Daily thoughts - 3'/><author><name>Zlatozar</name><uri>http://www.blogger.com/profile/16257250071061885492</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/17/6760/640/RabotnotoMqsto.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14240039.post-7366168946270624367</id><published>2007-06-29T15:24:00.012+03:00</published><updated>2011-04-11T16:14:58.846+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Start study JavaScript</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp;Ща не ща, налага се да уча JavaScript. Както винаги почнах да го разглеждам отдалече. Като за начало ми трябваше нещо като въведение. Потъсих в google и се спрях на &lt;a href="http://developer.mozilla.org/en/docs/A_re-introduction_to_JavaScript"&gt;ре-интро&lt;/a&gt;. Не е кой знае какво, но важните концепции са там. Разбира се това съвсем не е достатъчно се огледах за следващата порция. Намерих я в вид на видео лекции. Те са на &lt;a href="http://www.crockford.com/"&gt;Douglas Crockford&lt;/a&gt;, който се води JS гурото на Yahoo. Много добри практики показва този човек. Не ги разбрах всичките и затова ще трябва пак да ги прегледам. Ето и линковете:&lt;br /&gt;&lt;pre&gt;Beginers&lt;br /&gt;http://video.yahoo.com/video/play?vid=111593&amp;amp;fr=&lt;br /&gt;http://video.yahoo.com/video/play?vid=111594&amp;amp;fr=&lt;br /&gt;http://video.yahoo.com/video/play?vid=111595&amp;amp;fr=&lt;br /&gt;http://video.yahoo.com/video/play?vid=111596&amp;amp;fr=&lt;br /&gt;&lt;br /&gt;Advanced&lt;br /&gt;http://video.yahoo.com/video/play?vid=111585&amp;amp;fr=&lt;br /&gt;http://video.yahoo.com/video/play?vid=111586&amp;amp;fr=&lt;br /&gt;http://video.yahoo.com/video/play?vid=111587&amp;amp;fr=&lt;br /&gt;and&lt;br /&gt;http://video.yahoo.com/watch/630959/2974197&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Super Advanced&lt;/b&gt;&lt;br /&gt;http://ejohn.org/apps/learn/&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;http://jibbering.com/faq/faq_notes/closures.html&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;DOM&lt;br /&gt;http://video.yahoo.com/video/play?vid=111582&amp;amp;fr=&lt;br /&gt;http://video.yahoo.com/video/play?vid=111583&amp;amp;fr=&lt;br /&gt;http://video.yahoo.com/video/play?vid=111584&amp;amp;fr=&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;Others&lt;/pre&gt;&lt;pre&gt;http://yuiblog.com/crockford/ &lt;/pre&gt;&lt;br /&gt;So far so good. Имам някакви базови знаня ама как да започна да пиша и да бриша. Тъй като много от нещата си пиша в Eclipse и Emacs трябваше да ги настроя. За Eclipse свалих JSEclipse, a &lt;a href="http://download.macromedia.com/pub/labs/jseclipse/autoinstall/site.xml"&gt;тук&lt;/a&gt; е update сайта. При Emacs има избор, най-доброто мисля е &lt;a href="http://code.google.com/p/js2-mode/"&gt;това&lt;/a&gt;. В него има инструкция как да се инсталира. Редакторите ги докарах, ама как ще тествам нещата. Оказа се, че има &lt;a href="http://developer.mozilla.org/en/docs/Introduction_to_the_JavaScript_shell"&gt;JavaScript Shell&lt;/a&gt;. Много добре работи. Ето как го настроих.&lt;br /&gt;&lt;pre&gt;cvs -d :pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot login&lt;br /&gt;cvs -d :pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot co -l mozilla/js/src mozilla/js/src/config mozilla/js/src/editline mozilla/js/src/fdlibm&lt;br /&gt;&lt;br /&gt;cd mozilla/js/src&lt;br /&gt;make -f Makefile.ref&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;И сега нещата са много лесни. Правя си update преди да почна:&lt;br /&gt;&lt;pre&gt;cd mozilla&lt;br /&gt;cvs up&lt;br /&gt;&lt;br /&gt;cd mozilla/js/src&lt;br /&gt;make -f Makefile.ref&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Направих си и alias в .bashrc. Така че и откъдето и да напиша js си отварям js-shell.&lt;br /&gt;&lt;pre&gt;alias js='/home/zlatozar/js-shell/mozilla/js/src/Linux_All_DBG.OBJ/js -i'&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Удобно е да провериш нещо набъзо. Особенно за примерите от книгата или ако има някаква по заплетена ситуация. Май имам всичко необходимо. Сега само четене и практика. И разбира се много debug с чудесния Firefox plug-in &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/1843"&gt;FireBug&lt;/a&gt;. Поставянето на breakpoint става като се напише &lt;b&gt;debugger&lt;/b&gt; в кода. Нищо работа.&lt;br /&gt;&lt;br /&gt;Друг вариант е да се ползва &lt;a href="http://www.mozilla.org/rhino/"&gt;Rhino&lt;/a&gt;. &lt;br /&gt;Като чета нещо в случая книгата "JavaScript Definitive Guide" си подчертавам най-важните, така че лесно да мога да се върна към тях и да ги запомня. Ето и линк към примерите от книгата &lt;a href="http://www.davidflanagan.com/javascript5/"&gt;http://www.davidflanagan.com/javascript5/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;И най-важното е да се разбере, че JavaScript e:&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;A language which has Scheme like semantics and Java like syntax&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Core JavaScript Language Notes:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="height: 600px; overflow: auto;"&gt;&lt;br /&gt;&lt;b&gt;Intro&lt;/b&gt;&lt;br /&gt;When a JavaScript interpreter is embedded in a web browser, the result is client-side JavaScript.&lt;br /&gt;Mozilla provides two different versions of the JavaScript 1.5 interpreter. One is written in C and is called &lt;i&gt;SpiderMonkey&lt;/i&gt;. The other is written in Java and, in a flattering reference to this book, is called &lt;i&gt;Rhino&lt;/i&gt;. Useful tool that is not strictly a debugger is jslint, which looks for common problems in JavaScript code (see &lt;a href="http://jslint.com"&gt;jslint&lt;/a&gt;). JavaScript programs are written using the Unicode character set. It is a case-sensitive language. Note, however, that HTML is not case-sensitive (although XHTML is).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Lexical Structure&lt;/b&gt;&lt;br /&gt;You may omit the semicolon if each of your statements is placed on a separate line. JavaScript allows you to work with three primitive datatypes: numbers, strings of text (known as strings), and Boolean truth values (known as booleans). It also defines two trivial datatypes, null and undefined, each of which defines only a single value. In addition to these primitive datatypes, JavaScript supports a composite datatype known as an object. An object (that is, a member of the datatype object) represents a collection of values (either primitive values, such as numbers and strings, or composite values, such as other objects). Objects in JavaScript have a dual nature: an object can represent an unordered collection of named values or an ordered collection of numbered values. JavaScript defines another special kind of object, known as a &lt;i&gt;function&lt;/i&gt;. A function is an object that has executable code associated with it. A function may be invoked to perform some kind of operation.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Numbers&lt;/b&gt;&lt;br /&gt;JavaScript differs from programming languages such as C and Java in that it does not make a distinction between integer values and floating-point values. All numbers in JavaScript are represented as floating-point values. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Strings&lt;/b&gt;&lt;br /&gt;A string is a sequence of Unicode letters, digits, punctuation characters, and so on; it is the JavaScript datatype for representing text. A string comprises a sequence of zero or more Unicode characters enclosed within single or double quotes (' or "). Double-quote characters may be contained within strings delimited by single-quote characters, and single-quote characters may be contained within strings delimited by double quotes. One of the built-in features of JavaScript is the ability to concatenate strings. If you use the + operator with numbers, it adds them. But if you use this operator on strings, it joins them by appending the second to the first. Numbers are automatically converted to strings when needed. If a number is used in a string concatenation expression. To make number-to-string conversions more explicit, use the String( ) function:&lt;br /&gt;&lt;pre  class="brush: javascript"&gt;var string_value = String(number); &lt;br /&gt;&lt;/pre&gt;Another technique for converting numbers to strings uses the toString( ) method: &lt;br /&gt;&lt;pre  class="brush: javascript"&gt;string_value = number.toString( );  &lt;br /&gt;&lt;/pre&gt;When a string is used in a numeric context, it is automatically converted to a number. This means, for example, that the following code actually works: &lt;br /&gt;&lt;pre  class="brush: javascript"&gt;var product = "21" * "2"; // product is the number 42&lt;br /&gt;&lt;/pre&gt;To allow more flexible conversions, you can use parseInt( ) and parseFloat( ). These functions convert and return any number at the beginning of a string, ignoring any trailing nonnumbers. parseInt( ) parses only integers, while parseFloat( ) parses both integers and floating-point numbers. If a string begins with &lt;b&gt;0x&lt;/b&gt; or &lt;b&gt;0X&lt;/b&gt;, parseInt( ) interprets it as a hexadecimal number.&lt;br /&gt;Strings are intentionally &lt;b&gt;immutable&lt;/b&gt;. Strings are compared by value.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Booleans&lt;/b&gt;&lt;br /&gt;Boolean values are represented by the literals &lt;i&gt;true&lt;/i&gt; and &lt;i&gt;false&lt;/i&gt;. Boolean values are easily convertible to and from other types and are often automatically converted. If a boolean value is used in a numeric context, true converts to the number 1 and false converts to the number 0. If a boolean value is used in a string context, true converts to the string "true" and false converts to the string "false". If a number is used where a boolean value is expected, the number is converted to True unless the number is 0 or NaN, which are converted to false. If a string is used where a boolean value is expected, it is converted to true except for the empty string, which is converted to false. null and the undefined value convert to false, and any non-null object, array, or function converts to true.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Objects&lt;/b&gt;&lt;br /&gt;An object is a collection of named values. These named values are usually referred to as properties of the object. (Sometimes they are called fields of the object, but this usage can be confusing.) To refer to a property of an object, you refer to the object, followed by a period and the name of the property. When a function value is stored in a property of an object, that function is often called a method, and the property name becomes the method name. To invoke a method of an object, use the . syntax to extract the function value from the object and then use the ( ) syntax to invoke that function. For example, to invoke the write( ) method of an object named document, you can use code like this:&lt;br /&gt;&lt;pre  class="brush: javascript"&gt;document.write("this is a test"); &lt;br /&gt;&lt;/pre&gt;Objects in JavaScript can serve as associative arrays; that is, they can associate arbitrary data values with arbitrary strings. When an object is used in this way, a different syntax is generally required to access the object's properties: a string containing the name of the desired property is enclosed within square brackets. Using this syntax, you can access the properties of the image object mentioned previously with code like this: &lt;br /&gt;&lt;pre  class="brush: javascript"&gt;image["width"] &lt;br /&gt;image["height"] &lt;br /&gt;&lt;/pre&gt;An object literal (also called an object initializer) consists of a comma-separated list of colon-separated property/value pairs, all enclosed within curly braces. Thus, the object point in the previous code can also be created and initialized with this line: &lt;br /&gt;&lt;pre  class="brush: javascript"&gt;var point = { x:2.3, y:-1.2 }; &lt;br /&gt;&lt;/pre&gt;When a non-null object is used in a Boolean context, it converts to true. When an object is used in a string context, JavaScript calls the toString( ) method of the object and uses the string value returned by that method. When an object is used in a numeric context, JavaScript first calls the valueOf( ) method of the object.&lt;br /&gt;&lt;br /&gt;Douglas Crockford: &lt;i&gt;"JavaScript is fundamentally about objects. Arrays are objects. Functions are objects. Objects are objects. So what are objects? Objects are collections of name-value pairs. The names are strings, and the values are strings, numbers, booleans, and objects (including arrays and functions). Objects are usually implemented as hashtables so values can be retrieved quickly.&lt;br /&gt;&lt;br /&gt;If a value is a function, we can consider it a method. When a method of an object is invoked, the this variable is set to the object. The method can then access the instance variables through the this variable.&lt;br /&gt;&lt;br /&gt;Objects can be produced by constructors, which are functions which initialize objects. Constructors provide the features that classes provide in other languages, including static variables and methods."&lt;/i&gt;&lt;br /&gt;&lt;b&gt;Arrays&lt;/b&gt;&lt;br /&gt;An array is a collection of data values, just as an object is. While each data value contained in an object has a name, each data value in an array has a number, or index. In JavaScript, you retrieve a value from an array by enclosing an index in square brackets after the array name. Arrays may contain any type of JavaScript data, including references to other arrays or to objects or functions. For example: &lt;br /&gt;&lt;pre  class="brush: javascript"&gt;document.images[1].width &lt;br /&gt;&lt;/pre&gt;Associative arrays are indexed by strings. Also note that JavaScript does not support multidimensional arrays, except as arrays of arrays. Finally, because JavaScript is an untyped language, the elements of an array do not all need to be of the same type, as they do in typed languages like Java. Creating:&lt;br /&gt;&lt;pre  class="brush: javascript"&gt;var a = new Array( );&lt;br /&gt;a[3] = { x:1, y:3 }; &lt;br /&gt;&lt;br /&gt;var a = new Array(10); &lt;br /&gt;var b = [1.2, "JavaScript", true, { x:1, y:3 }];&lt;br /&gt;&lt;/pre&gt;Undefined elements can be included in an array literal by simply omitting a value between commas. For example, the following array contains five elements, including three undefined elements: &lt;br /&gt;&lt;pre  class="brush: javascript"&gt;var sparseArray = [1,,,,5]; &lt;br /&gt;&lt;/pre&gt;You can access elements of an array using square brackets ([]), and you can access elements of an object using a dot (.). Both [] and . are treated as operators in JavaScript. &lt;br /&gt;The . operator expects an object as its left-side operand and an identifier (a property name) as its right-side operand. The right-side operand should not be a string or a variable that contains a string; it should be the literal name of the property or method, without quotes of any kind. Here are some examples:&lt;br /&gt;&lt;pre  class="brush: javascript"&gt;document.lastModified &lt;br /&gt;navigator.appName &lt;br /&gt;frames[0].length &lt;br /&gt;document.write("hello world") &lt;br /&gt;&lt;/pre&gt;If the specified property does not exist in the object, JavaScript does not issue an error but instead simply returns undefined as the value of the expression.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;null and undefined&lt;/b&gt;&lt;br /&gt;The JavaScript keyword &lt;i&gt;null&lt;/i&gt; is a special value that indicates no value. null is usually considered a special value of object typea value that represents no object. null is a unique value, distinct from all other values. When a variable holds the value null, you know that it does not contain a valid object, array, number, string, or boolean value. When null is used in a Boolean context, it converts to false. When used in a numeric context, it converts to 0. And when used in a string context, it converts to "null". &lt;br /&gt;&lt;i&gt;undefined&lt;/i&gt; is returned when you use either a variable that has been declared but never had a value assigned to it or an object property that does not exist. Note that this special undefined value is not the same as null. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Wrapper Objects&lt;/b&gt;&lt;br /&gt;JavaScript besides supporting the number, string, and boolean datatypes, JavaScript also supports Number, String, and Boolean classes. These classes are wrappers around the primitive datatypes. A wrapper contains the same primitive data value, but it also defines properties and methods that can be used to manipulate that data. Note that any number, string, or boolean value can be converted to its corresponding wrapper object with the Object( ) function: &lt;br /&gt;&lt;pre  class="brush: javascript"&gt;var number_wrapper = Object(3); &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;By Reference, by Value&lt;/b&gt;&lt;br /&gt;The basic rule in JavaScript is this: primitive types are manipulated by value, and reference types, as the name suggests, are manipulated by reference. Numbers and booleans are primitive types in JavaScript primitive because they consist of nothing more than a small, fixed number of bytes that are easily manipulated at the low levels of the JavaScript interpreter. Objects, on the other hand, are reference types. Arrays and functions, which are specialized types of objects, are therefore also reference types. These datatypes can contain arbitrary numbers of properties or elements, so they cannot be manipulated as easily as fixed-size primitive values can.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Varables&lt;/b&gt;&lt;br /&gt;An important difference between JavaScript and languages such as Java and C is that JavaScript is untyped. This means, in part, that a JavaScript variable can hold a value of any datatype, unlike a Java or C variable, which can hold only the one particular type of data for which it is declared. A feature related to JavaScript's lack of typing is that the language conveniently and automatically converts values from one type to another, as necessary. Variables declared with var are permanent: attempting to delete them with the &lt;i&gt;delete&lt;/i&gt; operator causes an error.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;If you attempt to read the value of an undeclared variable, JavaScript generates an error. If you assign a value to a variable that you have not declared with var, JavaScript implicitly declares that variable for you. Note, however, that implicitly declared variables are always created as global variables, even if they are used within the body of a function. &lt;br /&gt;To prevent the creation of a global variable (or the use of an existing global variable) when you meant to create a local variable to use within a single function, you must always use the var statement within function bodies. It's best to use var for all variables, whether global or local.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Within the body of a function, a local variable takes precedence over a global variable with the same name. If you declare a local variable or function parameter with the same name as a global variable, you effectively hide the global variable.  JavaScript does not have block-level scope. All variables declared in a function, no matter where they are declared, are defined throughout the function. In the following code, the variables i, j, and k all have the same scope: all three are defined throughout the body of the function. &lt;br /&gt;&lt;pre  class="brush: javascript"&gt;function test(o) {     &lt;br /&gt;   var i = 0;                        // i is defined throughout function &lt;br /&gt;   if (typeof o == "object") { &lt;br /&gt;      var j = 0;                     // j is defined everywhere, not just block &lt;br /&gt;      for(var k=0; k &amp;lt; 10; k++) {  // k is defined everywhere, not just loop &lt;br /&gt;         document.write(k); &lt;br /&gt;      } &lt;br /&gt;      document.write(k);            // k is still defined: prints 10 &lt;br /&gt;   } &lt;br /&gt;   document.write(j);               // j is defined, but may not be initialized &lt;br /&gt;} &lt;br /&gt;&lt;/pre&gt;Local variable is defined throughout, it is not actually initialized until the var statement is executed.&lt;br /&gt;&lt;b&gt;REMEMBER:&lt;/b&gt;&lt;br /&gt;&lt;pre  class="brush: javascript"&gt;function f( ) {     &lt;br /&gt;   var scope;        // Local variable is declared at the start of the function &lt;br /&gt;   alert(scope);     // It exists here, but still has "undefined" value &lt;br /&gt;   scope = "local";  // Now we initialize it and give it a value &lt;br /&gt;   alert(scope);     // And here it has a value &lt;br /&gt;} &lt;br /&gt;&lt;/pre&gt;&lt;b&gt;It is good programming practice to place all your variable declarations together at the start of any function.&lt;/b&gt;  &lt;br /&gt;&lt;br /&gt;Undeclared variables are undefined because they simply do not exist. As described earlier, assigning a value to an undeclared variable does not cause an error; instead, it implicitly declares the variable in the global scope. The second kind of undefined variable is one that has been declared but has never had a value assigned to it. If you read the value of one of these variables, you obtain its default value, undefined. Variables in JavaScript are fundamentally the same as object properties.    &lt;br /&gt;&lt;br /&gt;&lt;i&gt;When the JavaScript interpreter starts up, one of the first things it does, before executing any JavaScript code, is create a global object. The properties of this object are the global variables of JavaScript programs. When you declare a global JavaScript variable, what you are actually doing is defining a property of the global object. In top-level code (i.e., JavaScript code that is not part of a function), you can use the JavaScript keyword &lt;b&gt;this&lt;/b&gt; to refer to the global object. Within functions, this has a different use.&lt;/i&gt; &lt;br /&gt;&lt;br /&gt;Each time the JavaScript interpreter begins to execute a function, it creates a new execution context for that function. An execution context is, obviously, the context in which any piece of JavaScript code executes. An important part of the context is the object in which variables are defined. Thus, JavaScript code that is not part of any function runs in an execution context that uses the global object for variable definitions. And every JavaScript function runs in its own unique execution context with its own call object in which local variables are defined. Client-side JavaScript code in each frame or window runs in its own execution context and has its own global object.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Every JavaScript execution context has a scope chain associated with it. This scope chain is a list or chain of objects. When JavaScript code needs to look up the value of a variable x (a process called variable name resolution), it starts by looking at the first object in the chain. If that object has a property named x, the value of that property is used. If the first object does not have a property named x, JavaScript continues the search with the next object in the chain. If the second object does not have a property named x, the search moves on to the next object, and so on.&lt;/b&gt;    &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Expressions and Operators&lt;/b&gt; &lt;br /&gt;When constructing JavaScript expressions, you must pay attention to the datatypes that are being passed to operators and to the datatypes that are returned. Different operators expect their operands' expressions to evaluate to values of a certain datatype. For example, it is not possible to multiply strings, so the expression "a" * "b" is not legal in JavaScript. Note, however, that JavaScript tries to convert expressions to the appropriate type whenever possible, so the expression "3" * "5" is legal. Its value is the number 15, not the string "15". The == and === operators check whether two values are the same, using two different definitions of sameness. Both operators accept operands of any type, and both return true if their operands are the same and false if they are different. The === operator is known as the identity operator, and it checks whether its two operands are "identical" using a strict definition of sameness. The == operator is known as the equality operator; it checks whether its two operands are "equal" using a more relaxed definition of sameness that allows type conversions.  &lt;br /&gt;&lt;pre  class="brush: javascript"&gt;// If max_width is defined, use that.  Otherwise look for a value in &lt;br /&gt;// the preferences object.  If that is not defined use a hard-coded constant. &lt;br /&gt;var max = max_width || preferences.max_width || 500;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Statements&lt;/b&gt; &lt;br /&gt;&lt;pre  class="brush: plain"&gt;with(object)&lt;br /&gt;  statement&lt;br /&gt;&lt;/pre&gt;This statement effectively adds object to the front of the scope chain, executes statement, and then restores the scope chain to its original state.  &lt;br /&gt;&lt;pre  class="brush: javascript"&gt;// Access form elements directly here. For example: &lt;br /&gt;with(frames[1].document.forms[0]) {     &lt;br /&gt;   name.value = ""; &lt;br /&gt;   address.value = ""; &lt;br /&gt;   email.value = ""; &lt;br /&gt;} &lt;br /&gt;&lt;/pre&gt;&lt;b&gt;Objects and Arrays&lt;/b&gt; &lt;br /&gt;An important point to notice about object properties is that you can create a new property of an object simply by assigning a value to it. Although you declare variables with the var keyword, there is no need (and no way) to do so with object properties. Furthermore, once you have created an object property by assigning a value to it, you can change the value of the property at any time simply by assigning a new value: &lt;br /&gt;&lt;pre  class="brush: javascript"&gt;book.title = "JavaScript: The Rhino Book" &lt;br /&gt;&lt;/pre&gt;Objects are often called an associative array - a data structure that allows you to dynamically associate arbitrary values with arbitrary strings. The term map is often used to describe this situation as well: JavaScript objects map strings (property names) to values. In JavaScript, every object has a constructor property that refers to the constructor function that initializes the object. The instanceof operator checks the value of the constructor property, so the code above could also be written: &lt;br /&gt;&lt;pre  class="brush: javascript"&gt;if ((typeof o == "object") &amp;amp;&amp;amp; (o instanceof Date))  // Then do something with the Date object... &lt;br /&gt;&lt;/pre&gt;&lt;b&gt;Function&lt;/b&gt; &lt;br /&gt;Functions may have parameters, or arguments local variables whose value is specified when the function is invoked. Functions often use these arguments to compute a return value that becomes the value of the function-invocation expression. When a function is invoked on an object, the function is called a method, and the object on which it is invoked is passed as an implicit argument of the function.  If the "return" statement does not have an associated expression, it returns the "undefined" value.&lt;br /&gt;&lt;b&gt; If you pass more arguments than the function expects, the function ignores the extra argumetnts. If you pass fewer than expected, the parameters you omit are given the undefined value.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Example of nested function: &lt;br /&gt;&lt;pre  class="brush: javascript"&gt;function hypotenuse(a, b) { &lt;br /&gt;   function square(x) { return x*x; } &lt;br /&gt;   return Math.sqrt(square(a) + square(b)); &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Nested functions may be defined only at the top level of the function within which they are nested. That is, they may not be defined within statement blocks, such as the body of an if statement or while loop. Note that this restriction applies only to functions defined with the function statement. Function literal expressions, may appear anywhere. Example of function literal: &lt;br /&gt;&lt;pre  class="brush: javascript"&gt;var f = function fact(x) { if (x &amp;lt;= 1) return 1; else return x*fact(x-1); }; &lt;br /&gt;&lt;/pre&gt;Because function literals are created by JavaScript expressions rather than statements, they are quite flexible and are particularly well suited for functions that are used only once and need not be named. For example, the function specified by a function literal expression can be stored into a variable, passed to another function, or even invoked directly:  &lt;br /&gt;&lt;pre  class="brush: javascript"&gt;f[0] = function(x) { return x*x; };                // Define a function and store it&lt;br /&gt;a.sort(function(a,b){return a-b;});                // Define a function; pass it to another&lt;br /&gt;var tensquared = (function(x) {return x*x;})(10);  // Define and invoke &lt;br /&gt;&lt;/pre&gt;Function names are often verbs or phrases that begin with verbs. It is a common convention to begin function names with a lowercase letter. When a name includes multiple words, one convention is to separate words with underscores like_this(); another convention is to begin all words after the first with an uppercase letter likeThis(). Functions that are supposed to be internal or hidden are sometimes given names that begin with an underscore.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Optional Arguments&lt;/b&gt;&lt;br /&gt;When a function is invoked with fewer arguments than are declared, the additional arguments have the undefined value! It is often useful to write functions so that some arguments are optional and may be omitted when the function is invoked. Note that when designing functions with optional arguments, you should be sure to put the optional ones at the end of the argument list so that they can be omitted. The programmer who calls your function cannot omit the first argument and pass the second, for example. In this case, he would have to explicitly pass undefined or null as the first argument. Functions like this one that can accept any number of arguments are called variadic functions, variable arity functions, or varargs functions. Within the body of a function, the identifier arguments has special meaning. arguments is a special property that refers to an object known as the Arguments object. The Arguments object is an array-like object that allows the argument values passed to the function to be retrieved by number, rather than by name.  In addition to its array elements, the Arguments object defines a callee property that refers to the function that is currently being executed. This property is rarely useful, but it can be used to allow unnamed functions to invoke themselves recursively. For instance, here is an unnamed function literal that computes factorials: &lt;br /&gt;&lt;pre  class="brush: javascript"&gt;function(x) { &lt;br /&gt;   if (x &amp;lt;= 1) return 1; &lt;br /&gt;   return x * arguments.callee(x-1); &lt;br /&gt;} &lt;br /&gt;&lt;/pre&gt;&lt;b&gt;Functions as Data&lt;/b&gt; &lt;br /&gt;In JavaScript, however, functions are not only syntax but also data, which means that they can be assigned to variables, stored in the properties of objects or the elements of arrays, passed as arguments to functions, and so on. &lt;br /&gt;&lt;pre  class="brush: javascript"&gt;var a = square(4);  // a contains the number 16 var b = square;     &lt;br /&gt;// Now b refers to the same function that square does &lt;br /&gt;var c = b(5);       // c contains the number 25 &lt;br /&gt;&lt;/pre&gt;&lt;b&gt;Functions as Methods&lt;/b&gt; &lt;br /&gt;A method is nothing more than a JavaScript function that is stored in a property of an object and invoked through that object. Methods have one very important property: the object through which a method is invoked becomes the value of the this keyword within the body of the method. Thus, when you invoke o.m(), the body of the method can refer to the object o with the this keyword. Here is a concrete example:  &lt;br /&gt;&lt;pre  class="brush: javascript"&gt;var calculator = {       &lt;br /&gt;   // An object literal     operand1: 1, &lt;br /&gt;   operand2: 1, &lt;br /&gt;   compute: function() { &lt;br /&gt;            this.result = this.operand1 + this.operand2; &lt;br /&gt;   } &lt;br /&gt;}; &lt;br /&gt;calculator.compute();       // What is 1+1? &lt;br /&gt;print(calculator.result);   // Display the result &lt;br /&gt;&lt;/pre&gt;&lt;b&gt;IMPORTANT:&lt;/b&gt; When a function is invoked as a function rather that as a method, the this keyword refers to the global object. &lt;br /&gt;Confusingly, this is true even when a nested function is invoked (as a function) within a containing method that was invoked as a method: the this keyword has one value in the containing function but (counterintuitive) refers to the global object within the body of the nested function.   The length property of a function itself, however, has a different meaning. This read-only property returns the number of arguments that the function expects to be passed that is, the number of parameters it declares in its parameter list.&lt;br /&gt;&lt;br /&gt;ECMAScript specifies two methods that are defined for all functions, call() and apply(). These methods allow you to invoke a function as if it were a method of some other object. The first argument to both call() and apply() is the object on which the function is to be invoked; this argument becomes the value of the this keyword within the body of the function.   &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Lexical Scoping&lt;/b&gt; &lt;br /&gt;Functions in JavaScript are lexically rather than dynamically scoped. This means that they run in the scope in which they are defined, not the scope from which they are executed. When a function is defined, the current scope chain is saved and becomes part of the internal state of the function. At the top level, the scope chain simply consists of the global object, and lexical scoping is not particularly relevant. When you define a nested function, however, the scope chain includes the containing function. This means that nested functions can access all of the arguments and local variables of the containing function.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The Call Object&lt;/b&gt;&lt;br /&gt;When the JavaScript interpreter invokes a function, it first sets the scope to the scope chain that was in effect when the function was defined. Next, it adds a new object, known as the call object (the ECMAScript specification uses the term activation object) to the front of the scope chain. The call object is initialized with a property named arguments that refers to the Arguments object for the function. Named parameters of the function are added to the call object next. Any local variables declared with the var statement are also defined within this object. Since this call object is at the head of the scope chain, local variables, function parameters, and the Arguments object are all in scope within the function. This also means that they hide any properties with the same name that are further up the scope chain, of course.  Note that unlike arguments, this is a keyword, not a property in the call object.   &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Classes, Constructors, and Prototypes&lt;/b&gt; &lt;br /&gt;You have also seen other kinds of JavaScript objects created with a similar syntax:  &lt;br /&gt;&lt;pre  class="brush: javascript"&gt;var array = new Array(10); &lt;br /&gt;var today = new Date( ); &lt;br /&gt;&lt;/pre&gt;The new operator must be followed by a function invocation. It creates a new object, with no properties and then invokes the function, passing the new object as the value of the this keyword. A function designed to be used with the new operator is called a constructor function or simply a constructor. A constructor's job is to initialize a newly created object, setting any properties that need to be set before the object is used.   &lt;br /&gt;&lt;pre  class="brush: javascript"&gt;// Define the constructor. Note how it initializes the object referred to by "this". &lt;br /&gt;function Rectangle(w, h) { &lt;br /&gt;   this.width = w; &lt;br /&gt;   this.height = h; &lt;br /&gt;   // Note: no return statement here &lt;br /&gt;} &lt;br /&gt;&lt;/pre&gt;Notice how the constructor uses its arguments to initialize properties of the object referred to by the this keyword. You have defined a class of objects simply by defining an appropriate constructor function; all objects created with the Rectangle( ) constructor are now guaranteed to have initialized width and height properties. This means that you can write programs that rely on this fact and treat all Rectangle objects uniformly.  It turns out that every JavaScript object includes an internal reference to another object, known as its &lt;b&gt;prototype&lt;/b&gt; object. Any properties of the prototype appear to be properties of an object for which it is the prototype. Another way of saying this is that a JavaScript object inherits properties from its prototype. &lt;br /&gt;After creating the empty object, &lt;b&gt;new&lt;/b&gt; sets the prototype of that object. The prototype of an object is the value of the prototype property of its constructor function. All functions have a prototype property that is automatically created and initialized when the function is defined. The initial value of the prototype property is an object with a single property.  This is clearer with an example. Here is the Rectangle( ) constructor:  &lt;br /&gt;&lt;pre  class="brush: javascript"&gt;// The constructor function initializes those properties that &lt;br /&gt;// will be different for each instance. &lt;br /&gt;function Rectangle(w, h) { &lt;br /&gt;   this.width = w; &lt;br /&gt;   this.height = h; &lt;br /&gt;} &lt;br /&gt;// The prototype object holds methods and other properties that &lt;br /&gt;// should be shared by each instance. &lt;br /&gt;Rectangle.prototype.area = function( ) { return this.width * this.height; } &lt;br /&gt;&lt;/pre&gt;This means that the prototype object is an ideal place for methods and other constant properties.  When you read property p of an object o, JavaScript first checks to see if o has a property named p. If it does not, it next checks to see if the prototype object of o has a property named p. This is what makes prototype-based inheritance work. When you write the value of a property, on the other hand, JavaScript does not use the prototype object. Therefore, property inheritance occurs only when you read property values, not when you write them.Note that you must never add properties to Object.prototype.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Using closures&lt;/b&gt; &lt;br /&gt;&lt;b&gt;closure&lt;/b&gt; is a function plus the scope that was in effect when the function was defined.[*] By defining a function, therefore, you can use its local scope as a private namespace. Nested functions defined within the outer function have access to this private namespace. The advantages of this are twofold.  First, since the private namespace is also the first object on the scope chain, functions in the namespace can refer to other functions and properties in the namespace without requiring a fully qualified name.  The second advantage to using a function to define a private namespace has to do with the fact that it is truly private. There is no way to access the symbols defined within the function from outside the function. Those symbols become available only if the function that contains them exports them to an external, public namespace. What this means is that a module can choose to export only its public functions, leaving implementation details such as helper methods and variables locked up in the privacy of the closure.   &lt;br /&gt;&lt;pre  class="brush: javascript"&gt;// Create the namespace object.  Error checking omitted here for brevity. var com; &lt;br /&gt;if (!com) com = {}; &lt;br /&gt;if (!com.davidflanagan) com.davidflanagan = {}; &lt;br /&gt;com.davidflanagan.Class = {}; &lt;br /&gt;// Don't stick anything into the namespace directly. &lt;br /&gt;// Instead we define and invoke an anonymous function to create a closure &lt;br /&gt;// that serves as our private namespace. This function will export its &lt;br /&gt;// public symbols from the closure into the com.davidflanagan.Class object &lt;br /&gt;// Note that we use an unnamed function so we don't create any other &lt;br /&gt;// global symbols. &lt;br /&gt;(function( ) {  // Begin anonymous function definition &lt;br /&gt;    // Nested functions create symbols within the closure &lt;br /&gt;    function define(data) { counter++; /* more code here */ } &lt;br /&gt;    function provides(o, c) { /* code here */ } &lt;br /&gt;    // Local variable are symbols within the closure. &lt;br /&gt;    // This one will remain private within the closure &lt;br /&gt;    var counter = 0; &lt;br /&gt;    // This function can refer to the variable with a simple name &lt;br /&gt;    // instead of having to qualify it with a namespace &lt;br /&gt;    function getCounter( ) { return counter; } &lt;br /&gt;    // Now that we've defined the properties we want in our private &lt;br /&gt;    // closure, we can export the public ones to the public namespace &lt;br /&gt;    // and leave the private ones hidden here. &lt;br /&gt;    var ns = com.davidflanagan.Class; &lt;br /&gt;    ns.define = define; &lt;br /&gt;    ns.provides = provides; &lt;br /&gt;    ns.getCounter = getCounter; &lt;br /&gt;})( );          // End anonymous function definition and invoke it &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Module Pattern&lt;/b&gt; &lt;br /&gt;&lt;br /&gt;Global variables are evil. Within YUI, we use only two globals: YAHOO and YAHOO_config. Everthing in YUI makes use of members within the YAHOO object hierarchy or variables that are scoped to such a member. We advise that you exercise similar discipline in your own applications, too.  Douglas Crockford has been teaching a useful singleton pattern for achieving this discipline, and I thought his pattern might be of interest to those of you building on top of YUI. Douglas calls this the “module pattern.” Here’s how it works: &lt;br /&gt;&lt;br /&gt;1. Create a namespace object: If you’re using YUI, you can use the YAHOO.namespace() method: &lt;br /&gt;&lt;pre  class="brush: javascript"&gt;YAHOO.namespace("myProject");&lt;br /&gt;&lt;/pre&gt;This assigns an empty object myProject as a member of YAHOO (but doesn’t overwrite myProject if it already exists). Now we can begin adding members to YAHOO.myProject. &lt;br /&gt;&lt;br /&gt;2. Assign the return value of an anonymous function to your namespace object: &lt;br /&gt;&lt;pre  class="brush: javascript"&gt;YAHOO.myProject.myModule = function () {&lt;br /&gt;   return  {&lt;br /&gt;            myPublicProperty: "I'm accessible as YAHOO.myProject.myModule.myPublicProperty.";&lt;br /&gt;            myPublicMethod: function () {&lt;br /&gt;            YAHOO.log("I'm accessible as YAHOO.myProject.myModule.myPublicMethod.");&lt;br /&gt;   }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;}(); // the parens here cause the anonymous function to execute and return&lt;br /&gt;&lt;/pre&gt;Note the very last line with the closing curly brace and then the parentheses &lt;b&gt;()&lt;/b&gt; — this notation causes the anonymous function to execute immediately, returning the object containing myPublicProperty and myPublicMethod. As soon as the anonymous function returns, that returned object is addressable as YAHOO.myProject.myModule.  &lt;br /&gt;&lt;br /&gt;3. Add “private” methods and variables in the anonymous function prior to the return statement. So far, the above code hasn’t bought us any more than we could have gotten by assigning myPublicProperty and myPublicMethod directly to YAHOO.myProject.myModule. But the pattern does provide added utility when we place code before the return statement:  &lt;br /&gt;&lt;pre  class="brush: javascript"&gt;YAHOO.myProject.myModule = function () {&lt;br /&gt;                              //"private" variables:&lt;br /&gt;                              var myPrivateVar = "I can be accessed only from within YAHOO.myProject.myModule.";&lt;br /&gt;&lt;br /&gt;                              //"private" method:&lt;br /&gt;                              var myPrivateMethod = function () {&lt;br /&gt;                              YAHOO.log("I can be accessed only from within YAHOO.myProject.myModule");&lt;br /&gt;                            }&lt;br /&gt;&lt;br /&gt;return  {&lt;br /&gt;   myPublicProperty: "I'm accessible as YAHOO.myProject.myModule.myPublicProperty."&lt;br /&gt;   myPublicMethod: function () {&lt;br /&gt;                      YAHOO.log("I'm accessible as YAHOO.myProject.myModule.myPublicMethod.");&lt;br /&gt;&lt;br /&gt;                     // Within myProject, I can access "private" vars and methods:&lt;br /&gt;                     YAHOO.log(myPrivateVar);&lt;br /&gt;                     YAHOO.log(myPrivateMethod());&lt;br /&gt;&lt;br /&gt;                     // The native scope of myPublicMethod is myProject; we can&lt;br /&gt;                     // access public members using "this":&lt;br /&gt;                     YAHOO.log(this.myPublicProperty);&lt;br /&gt;                   }&lt;br /&gt;  };&lt;br /&gt;}(); // the parens here cause the anonymous function to execute and return&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In the codeblock above, we’re returning from an anonymous function an object with two members. These members are addressable from within YAHOO.myProject.myModule as this.myPublicProperty and this.myPublicMethod respectively. From outside of YAHOO.myProject.myModule, these public members are addressable as YAHOO.myProject.myModule.myPublicProperty and YAHOO.myProject.myModule.myPublicMethod.  The private variables myPrivateProperty and myPrivateMethod can only be accessed from within the anonymous function itself or from within a member of the returned object. They are preserved, despite the immediate execution and termination of the anonymous function, through the power of closure — the principle by which variables local to a function are retained after the function has returned. As long as YAHOO.myProject.myModule needs them, our two private variables will not be destroyed.  &lt;br /&gt;&lt;br /&gt;4. Do something useful with the pattern. Let’s look at a common use case for the module pattern. Suppose you have a list, some of whose list items should be draggable. The draggable items have the CSS class draggable applied to them. &lt;br /&gt;&lt;pre  class="brush: plain"&gt;&amp;lt;!--This script file includes all of the YUI utilities:--&amp;gt;&lt;br /&gt;&amp;lt;script type="text/javascript"&lt;br /&gt;src="http://yui.yahooapis.com/2.2.2/build/utilities/utilities.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;ul id="myList"&amp;gt;&lt;br /&gt;&amp;lt;li class="draggable"&amp;gt;Item one.&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;lt;li&amp;gt;Item two.&amp;lt;/li&amp;gt; &amp;lt;!--item two won't be draggable--&amp;gt;&lt;br /&gt;&amp;lt;li class="draggable"&amp;gt;Item three.&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;lt;/ul&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;script&amp;gt;&lt;br /&gt;YAHOO.namespace("myProject");&lt;br /&gt;YAHOO.myProject.myModule = function () {&lt;br /&gt;&lt;br /&gt;//private shorthand references to YUI utilities:&lt;br /&gt;var yue = YAHOO.util.Event,&lt;br /&gt;yud = YAHOO.util.Dom;&lt;br /&gt;&lt;br /&gt;//private method:&lt;br /&gt;var getListItems = function () {&lt;br /&gt;&lt;br /&gt;                   //note that we can use other private variables here, including&lt;br /&gt;                   //our "yud" shorthand to YAHOO.util.Dom:&lt;br /&gt;                   var elList = yud.get("myList");&lt;br /&gt;                   var aListItems = yud.getElementsByClassName(&lt;br /&gt;                      "draggable",     //get only items with css class "draggable"&lt;br /&gt;                      "li",            //only return list items&lt;br /&gt;                       elList          //restrict search to children of this element&lt;br /&gt;                       );&lt;br /&gt;                  return aListItems;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;//the returned object here will become YAHOO.myProject.myModule:&lt;br /&gt;return  {&lt;br /&gt;&lt;br /&gt;          aDragObjects: [],    // a publicly accessible place to store our DD objects&lt;br /&gt;          init: function () {&lt;br /&gt;                // we'll defer making list items draggable until the DOM is fully loaded:&lt;br /&gt;                yue.onDOMReady(this.makeLIsDraggable, this, true);&lt;br /&gt;          },&lt;br /&gt;&lt;br /&gt;          makeLIsDraggable: function () {&lt;br /&gt;                var aListItems = getListItems(); // these are the elements we'll make draggable&lt;br /&gt;                for (var i=0, j=aListItems.length; i&amp;lt;j; i++) {&lt;br /&gt;                   this.aDragObjects.push(new YAHOO.util.DD(aListItems[i]));&lt;br /&gt;                }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;};&lt;br /&gt;}(); // the parens here cause the anonymous function to execute and return&lt;br /&gt;&lt;br /&gt;// The above code has already executed, so we can access the init&lt;br /&gt;// method immediately:&lt;br /&gt;YAHOO.myProject.myModule.init();&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;This example is a simple one, and it’s deliberately verbose — if this was all we were doing, we could doubtless write it in a more compact way. However, this pattern scales well as the project becomes more complex and as its API grows. It stays out of the global namespace, provides publicly addressable API methods, and supports protected or “private” data and methods along the way. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Function scope can create an encapsulation. Use an anonymous function to wrap your application.&lt;/b&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;ПП Понякога не е достатъчно и за бърза справка ползвам &lt;a href="http://developer.mozilla.org/en/docs/JavaScript"&gt;това&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14240039-7366168946270624367?l=zlatozar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zlatozar.blogspot.com/feeds/7366168946270624367/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14240039&amp;postID=7366168946270624367' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/7366168946270624367'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/7366168946270624367'/><link rel='alternate' type='text/html' href='http://zlatozar.blogspot.com/2007/06/start-study-javascript.html' title='Start study JavaScript'/><author><name>Zlatozar</name><uri>http://www.blogger.com/profile/16257250071061885492</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/17/6760/640/RabotnotoMqsto.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14240039.post-7302096961902609714</id><published>2007-06-20T16:44:00.002+03:00</published><updated>2008-03-13T14:53:37.125+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='думи'/><title type='text'>За Хенри Милър и други мисли</title><content type='html'>&lt;br/&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Днес се сетих за Хенри Милър. Със сигурност е много подценяван. Хората си правят изводи само като видят обложката на "Sexus", много секс сцени и никаква фабула. Винаги ми е харесвал Хенри Милър! При него няма рамки. Четейки го, се престраших да пиша. Почнах от дълги писма. Трудно е да се пишат, винаги намираш написаното за тривиално. В писмата ми от казармата имаше повече въпроси и никаква интрига. Коресопнденцията ми се превръщаше във въпроси отговори. &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Стила на Хенри е "течащ". Ето как си представям творческия му делник. Става късно и докато си пие кафето се "хваща" за някоя мисъл и я разтяга докрай. Понякога има огомни скокове от действие към действие и какво от това, в повечето дисциплинирани писатели нямат успех.Почнах да пиша писмата си с много кураж. Оставям се на течението и каквото излезе. В началото дори реших дори да не ги препрочитам. Получаваха се дълги и изпъстрени с тлъсти правописни грешки писма. Хората обичат да си естествен, когато намерят твоя грешка се окуражават и престрашават. Получава се комуникация. Твоите грешки са стимул за друг. Достатъчно ли са умни, за да видят капана? Това ме вълнува! Понякога съм се възползвал от това. Днес имахме интервю. Кога може да ти падне гарда? Какво ще кажеш от един грешащ изпитващ добродушко. От такива може скоро и да си нокдоун. Често включвам тоя трик при воденето на интервюта. Не бих казал, че е подло. Просто техника премесена с чувство за хумор. Греша и чакам реакцията. Задаването на въпроси от рода на "Избройте най-добрите и най-лошите си качества" ме вбесява безкрайно. Бих отоговорил "Най-доброто ми качество е, че не виждам лошите си качества". Клишетата убиват. Изпадаш в друга лига. Ако отговориш с добре заучено клише дали си ценен? Това може да значи - да, ти разбираш, че интервюиращия е тъпанар и му отвръщащ подобаващо или да и аз съм чел тази книга и мога да цитирам безкрай. &lt;br /&gt;Духовитите и интелигентни хора умело лавират и на свой ред те поставят на изпитание. Забавлявам се истински. Винаги се опитвам да открия, какво имат като ценност, което ще е валидно близките 10 години. Не искам да знае перфектени еднодневки, искам да имам личност насреща, която и да умее да се забавлява. Да има идеи, да има мнение. Да е добър човек.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Все се питам дали човек трябва да има две страни преди работа и след работа. Дори и това не е достатъчно. Дали трябва да е многолик? Обичам такива хора. Обичам да откривам различните лица на хората в житейските ситуации. Следя и анализирам, може би дори се и уча. Не случайно има такива максими или там както се казваха, "Човек се познава, когато е на път". Тогава си до него и следиш реакциите. E, човек не се ли познава, когато е по голяма нужа? Явно не е доказано. Изкуството според мен е да знаеш, кога да превключиш. Аз съм открил за себе си че не трябва се застоявам - изнервям се и по-скоро вредя на околните отколкото да им помагам. &lt;br /&gt;Обичам да чета Хенри Милър и това си е.&lt;br /&gt;&lt;br/&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14240039-7302096961902609714?l=zlatozar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zlatozar.blogspot.com/feeds/7302096961902609714/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14240039&amp;postID=7302096961902609714' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/7302096961902609714'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/7302096961902609714'/><link rel='alternate' type='text/html' href='http://zlatozar.blogspot.com/2007/06/blog-post.html' title='За Хенри Милър и други мисли'/><author><name>Zlatozar</name><uri>http://www.blogger.com/profile/16257250071061885492</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/17/6760/640/RabotnotoMqsto.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14240039.post-8006823351895142042</id><published>2007-06-05T16:20:00.002+03:00</published><updated>2011-03-07T12:24:04.980+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='daily'/><category scheme='http://www.blogger.com/atom/ns#' term='source control'/><title type='text'>Daily thoughts - 2</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; Макар че съм работил доста с Subversion днес ми се наложи да направя merge и доста се поизпотих. Инсталацията и простичкия commit, update не са всичко. Сценария е trunk, branch-1.2.0 и много учудващо branch-1.2, които е бранч на branch-1.2.0 (не знам кои го е измислил така). Картинката е следната:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;+-----------------&gt; branch-1.2&lt;br /&gt;|   Merge ^&lt;br /&gt;|         |&lt;br /&gt;+--------------------------&gt; branch-1.2.0&lt;br /&gt;|&lt;br /&gt;|&lt;br /&gt;trunk ---------------------------------------------&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Задачата? Промените от branch-1.2.0 да идат в branch-1.2, но от всичко а от определен момент (commit). Един ден четох как да го направя от команден ред и днес се престраших да експериментирам.&lt;br /&gt;&lt;br /&gt;Подготвям си нещата като вземам последните версии на "моя" и "чуждия" branch.&lt;br /&gt;&lt;pre&gt;svn update --show-updates&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Добре е да има застраховка и затова слагам един таг.&lt;br /&gt;&lt;pre&gt;svn copy -m "Tag before merge with branch 1.2.0"  https://svn.company.com/product/branches/1.2  https://svn.company.com/product/tags/release-1.2-M01&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;После отивам в директорията на "чуждия" branch и искам да видя всички промени от самото създаване на branch-a до сега:&lt;br /&gt;&lt;pre&gt;svn log --stop-on-copy -v &gt; changes.log&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Същото правя и за "моя" branch, като тука по-специялно ме интересува кога точно в създаден. Най-отдолу пише:&lt;br /&gt;&lt;pre&gt;------------------------------------------------------------------------&lt;br /&gt;r3777 | someone | 2007-04-04 18:20:31 +0300 (Wed, 04 Apr 2007) | 1 line&lt;br /&gt;Changed paths:&lt;br /&gt;A /branches/1.2 (from /branches/1.2.0:3776)&lt;br /&gt;&lt;br /&gt;Creating branch for development of 1.2.x versions&lt;br /&gt;------------------------------------------------------------------------&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Отварям си културно changes.log и почвам да разглеждам. Ахааа ето и версията, от която нататък трябва да взема промените - r3785&lt;br /&gt;&lt;br /&gt;Изводите. До r3777 двата branch-a са си еднакви и игнорирам промените. Намирам си версията от която нататък ми трябват промените и се готвя за merge. Все забравям, че HEAD е последната версия а не trunk-a, който е с CVS минало ще ме разбере :)&lt;br /&gt;За merge се задава диапазона и после откъде да се вземе този диапазон. Плахо проверявам с --dry-run от r3785 до сега т.е. HEAD.&lt;br /&gt;&lt;pre&gt;cd &lt;my branch&gt;&lt;br /&gt;svn merge --dry-run -r3785:HEAD https://svn.company.com/product/branches/1.2.0&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;А това значи: Дай ми всички промени в branch-1.2.0 от версия 3785 до последната и ги приложи в текущия branch (1.2)&lt;br /&gt;&lt;br /&gt;Виждам каво ме чака и се хвърлям в огъня.&lt;br /&gt;&lt;pre&gt;svn merge -r3785:HEAD https://svn.company.com/product/branches/1.2.0&lt;br /&gt;&lt;br /&gt;U    administration/webroot/waf/layout/porduct/core/services/assets/model/Asset.jsp&lt;br /&gt;U    lib/plica-waf.jar&lt;br /&gt;U    lib/plica-waf-web.jar&lt;br /&gt;U    lib/plica-waf-src.jar&lt;br /&gt;C    core/webroot/skin/i18n/en.js&lt;br /&gt;U    core/webroot/skin/basic2/main.css&lt;br /&gt;A    core/webroot/skin/adb&lt;br /&gt;A    core/webroot/skin/adb/main.css&lt;br /&gt;U    core/webroot/skin/super/main.css&lt;br /&gt;U    core/src/java/product/extensions/reminders/model/display.properties&lt;br /&gt;U    core/src/java/product/core/services/subscriptions/model/display.properties&lt;br /&gt;A    core/src/js/box/adb.js&lt;br /&gt;U    core/src/js/PlaybackManager.js&lt;br /&gt;U    core/src/js/widgets/config.js&lt;br /&gt;U    core/src/js/widgets/epg.js&lt;br /&gt;U    core/src/js/widgets/reminders.js&lt;br /&gt;U    core/src/js/widgets/broadcast.js&lt;br /&gt;?    dir_conflicts.prej&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ух само един конфликт и нещо странно в директорията - dir_conflicts.prej. Лесно се справам с програмния конфликт.&lt;br /&gt;&lt;pre&gt;svn resolved core/webroot/skin/i18n/en.js&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Как обаче да подходя с dir_conflicts.prej? Първо какво значи това - станало е конфликт в svn properties. Ето и лекарството:&lt;br /&gt;&lt;pre&gt;# see what we have&lt;br /&gt;svn proplist .&lt;br /&gt;&lt;br /&gt;# see the problem&lt;br /&gt;less dir_conflicts.prej&lt;br /&gt;&lt;br /&gt;# find the problem - it was in svn:ignore&lt;br /&gt;svn propedit svn:ignore .&lt;br /&gt;&lt;br /&gt;# change svn:ignore (add or remove something). In my case I have to add.&lt;br /&gt;svn propset svn:ignore bin .&lt;br /&gt;&lt;br /&gt;# do it&lt;br /&gt;svn resolved .&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Съвесно проверявам статуса и разликите:&lt;br /&gt;&lt;pre&gt;svn status --show-updates&lt;br /&gt;svn diff |colordiff&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;изтрелвам всичко&lt;br /&gt;&lt;pre&gt;svn commit -m "Merged branch 1.2.0 to branch 1.2"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Все още не мога да свикна с Subversion, защото винаги правя аналогии с CVS-a. Много по-добър от CVS-а! Вижда ми се малко прекалено, ако разбира се ако забравим преименуването на файловете. Другото дразнещо нещо е merge-a. Ако ви се наложи да правите постоянен merge с trunk-a да речем, тогава вие и само вие трябва да държите списък за това от къде до къде сте направили merge. Какво имам в предвид. Ако в понеделник сте направили:&lt;br /&gt;&lt;pre&gt;svn merge -r5238:HEAD http://svn.company.com/product/trunk&lt;br /&gt;svm commit -m "merge commit"&lt;br /&gt;Commit at 5302&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Трябва да запомните това число 5302 и във вторник да почните точно от там.&lt;br /&gt;&lt;pre&gt;svn merge -r5302:HEAD http://svn.company.com/product/trunk&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Иначе ще получите много конфликти и пак ще се наложи да ги оправяте ръчно. Subversion просто не държи списък на направените merges и до къде са направени. Запазете вяра обаче в версия 1.5 това ще бъде коригирано. До тогава може да ползвате svnmerge и тези &lt;a href="http://kenkinder.com/svnmerge/"&gt;напътствия&lt;/a&gt;.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;И сега най-инересната част. След като синхронизирам branch-a 3 седмици с trunk и отделно активно се добавя код branch-a идва обратната задача - всичко от този branch да иде обратно в trunk. Много глупаво и напрактика двойна работа, ама нищо приемам го като предизвикателство.&lt;br /&gt;&lt;pre&gt;cd trunk&lt;br /&gt;svn merge http://svn.company.com/product/trunk http://svn.company.com/product/branches/1.2 .&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;с други думи всички разлики(HEAD:HEAD) в текущата директория, която е всъщност trunk-a.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14240039-8006823351895142042?l=zlatozar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zlatozar.blogspot.com/feeds/8006823351895142042/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14240039&amp;postID=8006823351895142042' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/8006823351895142042'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/8006823351895142042'/><link rel='alternate' type='text/html' href='http://zlatozar.blogspot.com/2007/06/daily-thoughts-2_05.html' title='Daily thoughts - 2'/><author><name>Zlatozar</name><uri>http://www.blogger.com/profile/16257250071061885492</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/17/6760/640/RabotnotoMqsto.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14240039.post-3450151915934384310</id><published>2007-05-17T10:06:00.000+03:00</published><updated>2007-05-30T15:23:50.686+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='daily'/><title type='text'>Daily thoughts - 1</title><content type='html'>&lt;br/&gt;&lt;br /&gt;&lt;b&gt;"Just think--you could be rich one day!"&lt;/b&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Много често ми се налага да решавам проблеми като търся в Google или питам приятели, колеги и форуми. После минава извесно време и бре, същия проблем. Да, ама как го реших, кого попитах? Та нали затова се водят бележки. Аз дори си имам един файл на Descktop-a - notes.txt. Като направя нещо или видя добро решение си пиша в него. Помага ама не е универсално, вече загубих два такива. Много ми се ще и да споделям, да видя коментари и макар и да звучи егоистично, да си пазя нещата. Другата ми идея е, под този етикет - daily да си споделям настроенията. Нещо кратко, може би интимно. Така ще си стане истински дневник. До сега писанията ми са повече като "статии". Това ми отнема повече време и blog-a ми остава за много време един и същт.&lt;br&gt;&lt;br /&gt;Е това беше анонса. Надявам се да не пиша само няколко реда, като тези в телеграфен стил. Лесно става и води до пристрастяване. Това не трябва да са неща за издатели, а нещо споделено.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14240039-3450151915934384310?l=zlatozar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zlatozar.blogspot.com/feeds/3450151915934384310/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14240039&amp;postID=3450151915934384310' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/3450151915934384310'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/3450151915934384310'/><link rel='alternate' type='text/html' href='http://zlatozar.blogspot.com/2007/05/daily-thoughts-1.html' title='Daily thoughts - 1'/><author><name>Zlatozar</name><uri>http://www.blogger.com/profile/16257250071061885492</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/17/6760/640/RabotnotoMqsto.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14240039.post-4714690665564063096</id><published>2007-02-04T20:47:00.001+02:00</published><updated>2007-10-24T12:20:57.680+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>How to process dependant tasks</title><content type='html'>&lt;p&gt;&lt;br /&gt;Математиците казват, че ако можеш да си дефинираш поставената задачата, то тя наполовина е решена. Програмистите се шегуват, че всяко задание е решено тогава и само тогава, когато решението удоволетворява и всички бъдещи изменения на заданието. Вярно е, че непрекъснато се променят условията, но всички го знаят. Затова може би се приема за решение всяко лесно изменимо приложение. Искам да споделя процеса на решение на една задача, с която си играх тези дни. Много малко книги са написани така, че да покажат еволюцията на идеата в главата на автора. Дадени са cool решения и те карат да се подтискаш. Всяко решение си има исторя. Ето и първоначалното "поръчение", което получих:&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;i&gt;&lt;br /&gt;Получаваш два обеката SuperTask и Task, които са в определено състояние (state). Можеш да изпълниш SuperTask само при условие, че можеш да доведеш Task до състояние "Complated". Състоянията са две - Completed, NotStarted.&lt;br /&gt;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Тъй като тази структура не е нищо особенно я аз мога да се справя мнооо лесно като напиша нещо от рода на (примерно):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;.....&lt;br /&gt;Task task = superTask.getChildTask();&lt;br /&gt;if (Task.COMPLATED_STATE.equals(task.getStatus())) {&lt;br /&gt;    superTask.process();&lt;br /&gt;} else {&lt;br /&gt;    log.debug("Child task is not ready..");&lt;br /&gt;    // do something else&lt;br /&gt;}&lt;br /&gt;.....&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Е, какво пък толкова - върши работа и е добре четимо. Много се чудя на колеги, които гадаят какво може да се случи и залитат в една посока. Не знам дали ви се е случвало такова нещо. И после какво, идва новото задание и наистина е интересно да се гледа реакцията. Ами когато сочи в друга посока? За да се докаже човек прави и "задни салта" за промяна на кода и нито крачка назад. Понякога тази крачка е и невъзможна ако "новата посока" прекалено късно и върху "гадаенето" са се понатрупали досна нови добавки. Затова аз съм си за принципа KISS - Keep it Simple Stupid. Така си винаги в посоката, в която духне вятъра.&lt;br /&gt;Не закъснява и промяната:&lt;br /&gt;&lt;i&gt;&lt;br /&gt;SuperTask може да има и повече от един Child. За да може да се обработи всички Child трябва да са в Completed. Няма промяна на броя на състоянията. &lt;br /&gt;&lt;/i&gt;&lt;br /&gt;Та като говорим за вятъра, каква може да е посоката. Ами ако се увеличава броя на Task? О, не е "big deal" си казвам нали има цикъл &lt;b&gt;for&lt;/b&gt;. Слагам &lt;b&gt;for&lt;/b&gt; и си свиркам, вместо за ден аз се оправям за час. Па и шефа доволен. Обаче мамка му ако се променят броя на състоянията - закивам. Тогава ще стане едно &lt;b&gt;if ... else&lt;/b&gt; няма оправяне. Може да се достигне до нещо от рода на: &lt;br /&gt;&lt;pre&gt;&lt;br /&gt;if(STATUS_COMPLETED.equals(this.status)) return false;&lt;br /&gt;...     &lt;br /&gt;if(taskFromSf.getStatus()!= null &amp;&amp; !taskFromSf.getStatus().equals(status)){&lt;br /&gt;...&lt;br /&gt;}&lt;br /&gt;if(STATUS_VERIFICATION.equals(status)){&lt;br /&gt;....   &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Аз никак не мога да се оправям с такъв "хоп-хоп" код. Все му губя нишката. А и тестването става нещо ужасно. При това условие ще влезе в този &lt;b&gt;if&lt;/b&gt;, а иначе в онзи. Ами нали уж Java, нали уж обекти джиджи-биджи. Не искам блок-схеми решение. И в един момент уж последното задание направо настръхнах:&lt;br /&gt;&lt;i&gt;&lt;br /&gt;Child могат да имат повече от две състояния - цели 4 (NotStarted, Verivication, Activating, Completed)&lt;br /&gt;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Казах си стига! И започнах да мисля как да пооправя нещата. Тъй като всичко е на английски в началото залитнах като се хванах за думичката "state". Не е ли очевидно - "State Pattarn". Цял ден експлоатирах идеята. Да ама не. Получи се нещо ама беше извратено. Аз се занимавам с Таsk процедирам с него, по определен начин. Няма ли да е добре да се съберат всияки операции върху този обект на едно място. Да кажа:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;task.process();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;и в зависимост от състоянието на Task, process да реаргира по различен начин. Леле и на това ако не му се вика polymorphism. Един обект да има много(poly-) форми (-morphism). После ми изникна примерчето от една книжка - много видове криптиране и всеки в отделен клас. И тогава:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;file.crypt();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;и в зависимост от това какъв ТИП (= STATE) e file, crypt() реаргира по различен начин. Главата в книгата беше озаглавена "Strategy Pattern". Добре де, ама защо да избера него. Един пасаж ме убеди:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;To alter the behavior of the context (file.crypt()), a client object needs to &lt;br&gt;configure the context with the selected strategy instance. This type of &lt;br&gt;arrangement completely separates the implementation of an algorithm from the context that uses it. &lt;br&gt;&lt;br /&gt;As a result, when an existing algorithm implementation is changed or a new algorithm&lt;br&gt; is added to the group, both the context and the client object (that uses the context) remain unaffected.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Хехе ами да ми дават колкото си състояния тогава аз ще си ги отделям и ще им имплементирам специфичен process() метод (..и други ако трябва). Важно е да четеш "правилините" книги, ей.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;               +--------------+                +----------------+&lt;br /&gt;               |     State    |                | TaskWorkflow   |     &lt;br /&gt;               |              | &lt;--------------|  (Contex)      |&lt;br /&gt;               +--------------+                +----------------+&lt;br /&gt;                  /       \&lt;br /&gt;                 /  ...    \&lt;br /&gt;                /           \&lt;br /&gt;     +----------------+      +----------------+&lt;br /&gt;     |VerificationTask|      | ActivationTask |&lt;br /&gt;     |                |      |                | &lt;br /&gt;     +----------------+      +----------------+&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Мога да отделя всичко не е късно. Радвам се. Внимателно си подбирам интерфейсите и  систематизирам нещата:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;interface SystemInterface {&lt;br /&gt;&lt;br /&gt;    // our specific operations &lt;br /&gt;    void escalate(); &lt;br /&gt;    void persist();&lt;br /&gt;    void reverse();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;interface State extends SystemInterface {&lt;br /&gt;&lt;br /&gt;    // Possible states&lt;br /&gt;    String NOTSTARTED_STATE = "Not Started";&lt;br /&gt;    String ACTIVATION_STATE = "Activation";&lt;br /&gt;    String VERIFICATION_STATE = "Verification";&lt;br /&gt;    String COMPLATE_STATE = "Complate";&lt;br /&gt;&lt;br /&gt;    // workflow operaion&lt;br /&gt;    void process();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class NotStartedState implements State ...&lt;br /&gt;public class ActivationState implements State ...&lt;br /&gt;public class ValidationState implements State ...&lt;br /&gt;public class ComplatedState implements State ...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Пфуу усетих се навреме. Готов съм да посрешна следващата буря, нещата се подредени и най-важното всеки след мен ще ги разбере. Знам къде какво ме чака и знам къде да го намеря. За десерт са ми оставили нещо специално:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;&lt;br /&gt;Всеки Task може да има също наследници и те наследници...демек до безкрай. Task отива  в Completed т.и.с.т.к всички негови наследници са достигнали Complete. И най-потресаващото, че една задача може да е преди друга.&lt;br /&gt;&lt;/i&gt;&lt;br /&gt;Много ме обърка последното изискване - признавам.&lt;br /&gt;Както са ме е учил другаря Цанков по математика, бързам да онагледя нещата:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;               +--------------+&lt;br /&gt;               |  Super Task  |&lt;br /&gt;               |              |  ROOT&lt;br /&gt;               +--------------+&lt;br /&gt;                  /       \&lt;br /&gt;                 /   ...   \&lt;br /&gt;                /           \&lt;br /&gt;               *             *&lt;br /&gt;     +--------------+   +--------------+&lt;br /&gt;     | Child Task 1 |   | Child Task 2 |&lt;br /&gt;     |(Verification)|   | (Activating) |   LEVEL 1&lt;br /&gt;     +--------------+   +--------------+&lt;br /&gt;             /                \&lt;br /&gt;            /        ...       \&lt;br /&gt;           /                    \&lt;br /&gt;          *                      *&lt;br /&gt;   +--------------+     +--------------+&lt;br /&gt;   | Child Task 3 |     | Child Task 4 |&lt;br /&gt;   | (NotStarted) |     | (Completed)  |   LEVEL 2&lt;br /&gt;   +--------------+     +--------------+&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Така такаааа, почват разсъжденията по картинка. Имам ги типовите операции значи сега трябва да се средоточа по обхождането на дървото, което в крайна сметка се получи. След като има предусловие трябва да почна от долу-нагоре. Рекурсия ще играе тука момче, но след Lisp закалката само се усмихвам под (заченка на) мустак. Важно е да се уточни тука и как се изгражда дървото и как работя с него. Като дадено имам SuperTask и после започвам да закачам един вид "условията" - Task. Така че, в Task имам:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    public void addChildTask(TaskObj child) {&lt;br /&gt;&lt;br /&gt;        assert child != null;&lt;br /&gt;&lt;br /&gt;        child.setParentTask(this);&lt;br /&gt;        childTasks.add(child);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Искам да кажа, че аз сам си изграждам дървото. Добре де, аз не моооо ли да кажа getAllChildTask(). Мога, ето как:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    public List&amp;lt;TaskObj&amp;gt; getAllChildTasks() {&lt;br /&gt;&lt;br /&gt;        List&amp;lt;TaskObj&amp;gt; taskStack = new ArrayList&amp;lt;TaskObj&amp;gt;();&lt;br /&gt;&lt;br /&gt;        Iterator&amp;lt;TaskObj&amp;gt; subTasks = childTasks.iterator();&lt;br /&gt;        while ( subTasks.hasNext() ) {&lt;br /&gt;            taskStack.addAll(subTasks.next().getAllChildTasks());&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        taskStack.add(this);&lt;br /&gt;        &lt;br /&gt;        return taskStack;&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Докато си пусках тестовете видях, че греша и добавям и смия SuperTask. Обаче ме осени следната идея: това не е ли ми дава и реда на изпълнение на task.process()? Не ми ли дава свобода да се "движа" навсякъде с SuperTask и спокоино да си вземам обектите, към които има referece? Ами да!&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Call stack&lt;br /&gt;+--------------------------+&lt;br /&gt;| 3 | 4 | 1 | 2| SuperTask |&lt;br /&gt;+--------------------------+&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Е, не са в идеален ред, но за мен е важно, че е спазен реда на извикване по нива LEVEL2, LEVEL1, ROOT. За реда(кой преди кой) на обработването на Task се получи някак естествено, след като аз си изграждам дървото, който е по-напред е по-дълбоко в йерархията и точка. Ами май май това е. За сега няма ново поръчение.&lt;br /&gt;&lt;p&gt;&lt;br /&gt;Малко изводи да си направим сега. Всеки програмист се влияе от кода написан преди него. Ако аз бях видял нещо от рода на:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  while(salesOrders.hasNext()){ &lt;br /&gt;    SalesOrder salesOrder = salesOrders.next();&lt;br /&gt;    Iterator&lt;Service&gt; services = salesOrder.getProduct().getServices().iterator();&lt;br /&gt;    while(services.hasNext()){&lt;br /&gt;      Service service = services.next();&lt;br /&gt;      Iterator&lt;Resource&gt; resources = service.getResources().iterator();&lt;br /&gt;      while(resources.hasNext()){&lt;br /&gt;        Resource resource = resources.next();&lt;br /&gt;        if(resource.getValue()!=null) continue;&lt;br /&gt;      &lt;br /&gt;        boolean automated = lookup.isResourceAutomatic(resource.getName());&lt;br /&gt;        String hashKey = automated+"/"+ service.getRfsName()+"/"+ resource.getRoleQueue();&lt;br /&gt;        TaskObj workTaskObj = tasksInMotion.get(hashKey);&lt;br /&gt;        if(workTaskObj==null || workTaskObj.getResources().size()==9){&lt;br /&gt;          TaskObj newWorkTaskObj =  new TaskObj(&lt;br /&gt;     ....&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;от мен какъв код се очаква за бога? Добър програмист не е този, който може да го чете, а този който не го допуска. Хората по природа са мързеливи и тръгват по пътя с най-малко съпротивление. Когато се поставят и срокове ставата гадни хакове. Прихващаме бързо лошите неща. Когато един софтуер започне да се "крепи" в крайна сметка се получава по-зле и по-зле и по-... Това, че рефакторираш използвайки Extract Method и Rename е като да си подменяш плочките на банята в къща без основи. Това е началото на края. Далече от това! Важното е да направиш промяната навреме, да евоюираш заедно с посоката на заданията. И другото е да атакауваш проблема в неговата основа, а не да се търсят заобикони пътища. Ako да речем ми трябва и точен ред на извикване няма да се опитвам да променям целия workflow, а ще потърся начин да изградя самата структура по-добре. Task се взема/слага в базата през Hibernate. Тогава сменям част от кода на Hibernate и имам:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!--  Relation Foreign key  --&amp;gt;&lt;br /&gt;&amp;lt;many-to-one name="parentTask" class="TaskObj"&lt;br /&gt;          foreign-key="FK_TASK_PARENT_ID" lazy="false"&amp;gt;&lt;br /&gt; &amp;lt;column name="PARENT_TASK_ID" not-null="false" /&amp;gt;&lt;br /&gt;&amp;lt;/many-to-one&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;bag name="childTasks" cascade="all" lazy="false"&amp;gt;&lt;br /&gt; &amp;lt;key column="PARENT_TASK_ID" /&amp;gt;&lt;br /&gt; &amp;lt;one-to-many class="TaskObj" /&amp;gt;&lt;br /&gt;&amp;lt;/bag&amp;gt;&lt;br /&gt;&lt;br /&gt;вместо:&lt;br /&gt;.............&lt;br /&gt;&amp;lt;set name="childTasks" cascade="all" lazy="false"&amp;gt;&lt;br /&gt; &amp;lt;key column="PARENT_TASK_ID" /&amp;gt;&lt;br /&gt; &amp;lt;one-to-many class="TaskObj" /&amp;gt;&lt;br /&gt;&amp;lt;/set&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;и вече разполагам с List интерфейс, вместо с Set и мога лесно да променя "Call Stack"-a.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    public Stack&amp;lt;TaskObj&amp;gt; getDependenciesCallStack() {&lt;br /&gt;&lt;br /&gt;        Stack&amp;lt;TaskObj&amp;gt; taskStack = new Stack&amp;lt;TaskObj&amp;gt;();&lt;br /&gt;&lt;br /&gt;        for ( TaskObj child : getChildTasks() ) {&lt;br /&gt;            taskStack.push(child);&lt;br /&gt;            taskStack.addAll(child.getDependenciesCallStack());&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        return taskStack;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Винаги съм подозрителен и затова решавам да си направя визоализация на дървото от задачи:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    private int currentPosition = 0;&lt;br /&gt;    private final StringBuffer listTask = new StringBuffer(100);&lt;br /&gt;&lt;br /&gt;    private static final int INDENT_STEP = 5;&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * Display(first) TaskObj taskId and subject in a tree structure&lt;br /&gt;     */&lt;br /&gt;    public void dumpTaskTree() {&lt;br /&gt;&lt;br /&gt;        // display title&lt;br /&gt;        listTask.append("\n============================\n");&lt;br /&gt;        listTask.append("(ROOT) ").append(this.getSubject()).append('\n');&lt;br /&gt;&lt;br /&gt;        final Set subtasks = this.getChildTasks();&lt;br /&gt;        final Iterator tIter = subtasks.iterator();&lt;br /&gt;        while ( tIter.hasNext() ) {&lt;br /&gt;            final TaskObj metaTask = (TaskObj) tIter.next();&lt;br /&gt;&lt;br /&gt;            // Task properties that I need&lt;br /&gt;            listTask.append("   !-- ");&lt;br /&gt;            listTask.append(metaTask.getSubject());&lt;br /&gt;            listTask.append('(');&lt;br /&gt;            listTask.append(metaTask.getId());&lt;br /&gt;            listTask.append(", ");&lt;br /&gt;            listTask.append(metaTask.getStatus());&lt;br /&gt;            listTask.append(")\n");&lt;br /&gt;&lt;br /&gt;            subTasksDraw(metaTask, INDENT_STEP);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        log.debug(listTask.toString());&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * Draw childes task(rest) of a meta task if they exist&lt;br /&gt;     * &lt;br /&gt;     * @param metaTask&lt;br /&gt;     * @param shift&lt;br /&gt;     *            indentation step&lt;br /&gt;     */&lt;br /&gt;    private void subTasksDraw(final TaskObj metaTask, final int shift) {&lt;br /&gt;        final Set subtasks = metaTask.getChildTasks();&lt;br /&gt;        final Iterator tIter = subtasks.iterator();&lt;br /&gt;&lt;br /&gt;        while ( tIter.hasNext() ) {&lt;br /&gt;            final TaskObj aTask = (TaskObj) tIter.next();&lt;br /&gt;&lt;br /&gt;            currentPosition = currentPosition + shift;&lt;br /&gt;            for ( int i = 0; i &lt; currentPosition; i++ ) {&lt;br /&gt;                listTask.append("  ");&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            listTask.append("\\+--- ");&lt;br /&gt;            listTask.append(aTask.getSubject());&lt;br /&gt;            listTask.append('(');&lt;br /&gt;            listTask.append(aTask.getId());&lt;br /&gt;            listTask.append(", ");&lt;br /&gt;            listTask.append(aTask.getStatus());&lt;br /&gt;            listTask.append(")\n");&lt;br /&gt;&lt;br /&gt;            subTasksDraw(aTask, shift);&lt;br /&gt;        }&lt;br /&gt;        currentPosition = 0;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;И последно: &lt;b&gt;"Premature optimization is the root of all evil."&lt;/b&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;ПП.&lt;br /&gt;Той: "Добро утро, ще можите ли да добавите и друг тип обекти към SuperTak, освен Task?"&lt;br /&gt;Аз: "Да. Чували ли сте за Visitor Pattern?"&lt;br /&gt;Той: "А може ли ..." (внезапно изгубва съзнание и диалога прекъсва)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14240039-4714690665564063096?l=zlatozar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zlatozar.blogspot.com/feeds/4714690665564063096/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14240039&amp;postID=4714690665564063096' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/4714690665564063096'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/4714690665564063096'/><link rel='alternate' type='text/html' href='http://zlatozar.blogspot.com/2007/02/how-to-process-dependant-tasks.html' title='How to process dependant tasks'/><author><name>Zlatozar</name><uri>http://www.blogger.com/profile/16257250071061885492</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/17/6760/640/RabotnotoMqsto.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14240039.post-116334284208027962</id><published>2006-11-12T16:45:00.002+02:00</published><updated>2011-03-07T12:23:17.055+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Lisp'/><category scheme='http://www.blogger.com/atom/ns#' term='emacs'/><title type='text'>Lisp environment</title><content type='html'>Средата за разработка е била винаги важна и затова доста си играя с настройките. Все искам кода да е добре подреден, да имам лесен начин да достъпвам документацията, да има code completion и разни други глезотийки. Така и стана с Lisp средата за разработка. Просто задължителните неща са: SBCL, Linux и Emacs. Въпроса е как ще напаснем тези три неща и колко бързо ще свикнем с Emacs.&lt;br /&gt;Аз използвам Debian и нещата, които се инсталират допълнително са:&lt;br /&gt;&lt;pre&gt;sudo aptitude install sbcl&lt;br /&gt;sudo aptitude install w3&lt;br /&gt;sudo aptitude install w3-el-e21&lt;br /&gt;sudo aptitude install hyperspec&lt;br /&gt;sudo aptitude install emacs-goodies-el&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Другото "важно" е да се смени клавишната комбинация за превключване от/към кирилица. В emacs "alt-shift" e много застъпена, така че "alt-alt"(Gnome default) или "ctrl-ctrl" e за предпочитане.&lt;br /&gt;Аз не обичам много да пиша така,че искам да използвам и history-то на REPL-a. Както в моя shell. Като изплзвам стрелките да виждам какво е било. Затова инсталирам linedit:&lt;br /&gt;&lt;pre&gt;&amp;gt; sbcl&lt;br /&gt;* (require :asdf-install)&lt;br /&gt;* (asdf-install:install :linedit)   ;first-time installation only&lt;br /&gt;&lt;br /&gt;* (require :linedit)                ;if already installed&lt;br /&gt;* (linedit:install-repl) &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Готови ли сте и за моя dot.emacs:&lt;br /&gt;&lt;pre&gt;;;; Can use now Common Lisp functions                                                                                                                                                                &lt;br /&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;                                                                                                                                                             &lt;br /&gt;&lt;br /&gt;(require 'cl)                                                                                                                                                                                        &lt;br /&gt;&lt;br /&gt;;;; Art                                                                                                                                                                                              &lt;br /&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;                                                                                                                                                             &lt;br /&gt;&lt;br /&gt;(set-background-color "black")                                                                                                                                                                       &lt;br /&gt;(set-face-background 'default "black")                                                                                                                                                               &lt;br /&gt;(set-face-background 'region "black")                                                                                                                                                                &lt;br /&gt;(set-face-foreground 'default "white")                                                                                                                                                               &lt;br /&gt;(set-face-foreground 'region "gray60")                                                                                                                                                               &lt;br /&gt;(set-foreground-color "white")                                                                                                                                                                       &lt;br /&gt;(set-cursor-color "red")                                                                                                                                                                             &lt;br /&gt;&lt;br /&gt;;;; System settinngs                                                                                                                                                                                 &lt;br /&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;                                                                                                                                                             &lt;br /&gt;&lt;br /&gt;;; Misc customizations                                                                                                                                                                               &lt;br /&gt;(setq inhibit-startup-message t)        ;no splash screen                                                                                                                                            &lt;br /&gt;&lt;br /&gt;(auto-compression-mode t)               ;turn on auto file uncompression                                                                                                                             &lt;br /&gt;&lt;br /&gt;(menu-bar-mode 0)                       ;turn off unused UI                                                                                                                                          &lt;br /&gt;&lt;br /&gt;(setq tab-width 4)                      ;tab size                                                                                                                                                    &lt;br /&gt;&lt;br /&gt;(setq display-time-24hr-format t)       ;display the current time                                                                                                                                    &lt;br /&gt;(display-time)                                                                                                                                                                                       &lt;br /&gt;&lt;br /&gt;(global-font-lock-mode t)               ;colorize all buffers                                                                                                                                        &lt;br /&gt;(setq font-lock-maximum-decoration t)                                                                                                                                                                &lt;br /&gt;&lt;br /&gt;(show-paren-mode t)                     ;highlight parens                                                                                                                                            &lt;br /&gt;(defconst query-replace-highlight t)    ;highlight during query                                                                                                                                      &lt;br /&gt;(defconst search-highlight t)           ;highlight incremental search                                                                                                                                &lt;br /&gt;(transient-mark-mode t)                 ;higlight the marked region (C-SPC)                                                                                                                          &lt;br /&gt;&lt;br /&gt;;; Some useful key bindings                                                                                                                                                                          &lt;br /&gt;(global-set-key [home] 'beginning-of-line)                                                                                                                                                           &lt;br /&gt;(global-set-key [end] 'end-of-line)                                                                                                                                                                  &lt;br /&gt;&lt;br /&gt;;; Column &amp;amp; line numbers in mode bar                                                                                                                                                                 &lt;br /&gt;(column-number-mode t)                                                                                                                                                                               &lt;br /&gt;(line-number-mode t)                                                                                                                                                                                 &lt;br /&gt;&lt;br /&gt;(setq frame-title-format "%b")          ;set title to buffer name                                                                                                                                    &lt;br /&gt;&lt;br /&gt;;; Ediff customizations                                                                                                                                                                              &lt;br /&gt;(defconst ediff-ignore-similar-regions t)                                                                                                                                                            &lt;br /&gt;(defconst ediff-use-last-dir t)                                                                                                                                                                      &lt;br /&gt;(defconst ediff-diff-options " -b ")                                                                                                                                                                 &lt;br /&gt;&lt;br /&gt;(setq dired-listing-switches "-l")      ;better list display                                                                                                                                         &lt;br /&gt;(setq ls-lisp-dirs-first t)             ;display dirs first in dired                                                                                                                                 &lt;br /&gt;&lt;br /&gt;;; Specify where backup files are stored                                                                                                                                                             &lt;br /&gt;(setq backup-directory-alist (quote ((".*" . "~/.backups"))))                                                                                                                                        &lt;br /&gt;&lt;br /&gt;(setq custom-file "~/.emacs-custom.el") ;what to load if error                                                                                                                                       &lt;br /&gt;(load custom-file 'noerror)                                                                                                                                                                          &lt;br /&gt;&lt;br /&gt;;; Type brackets in pairs                                                                                                                                                                            &lt;br /&gt;(setq skeleton-pair t)                                                                                                                                                                               &lt;br /&gt;(global-set-key (kbd "[") 'skeleton-pair-insert-maybe)                                                                                                                                               &lt;br /&gt;(global-set-key (kbd "{") 'skeleton-pair-insert-maybe)                                                                                                                                               &lt;br /&gt;(global-set-key (kbd "\"") 'skeleton-pair-insert-maybe)&lt;br /&gt;&lt;br /&gt;;;; Common Lisp                                                                                                                                                                                      &lt;br /&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;                                                                                                                                                             &lt;br /&gt;&lt;br /&gt;;; Specify modes for Lisp file extensions                                                                                                                                                            &lt;br /&gt;(setq auto-mode-alist                                                                                                                                                                                &lt;br /&gt;(append '(                                                                                                                                                                                     &lt;br /&gt;("\\.lisp$" . lisp-mode)                                                                                                                                                             &lt;br /&gt;("\\.lsp$" . lisp-mode)                                                                                                                                                              &lt;br /&gt;("\\.cl$" . lisp-mode)                                                                                                                                                               &lt;br /&gt;("\\.asd$" . lisp-mode)                                                                                                                                                              &lt;br /&gt;("\\.system$" . lisp-mode)                                                                                                                                                           &lt;br /&gt;)auto-mode-alist))                                                                                                                                                                   &lt;br /&gt;&lt;br /&gt;;; SLIME and generic Common Lisp.                                                                                                                                                                    &lt;br /&gt;(require 'slime)                                                                                                                                                                                     &lt;br /&gt;&lt;br /&gt;(setq slime-edit-definition-fallback-function 'find-tag)                                                                                                                                             &lt;br /&gt;&lt;br /&gt;(setq inferior-lisp-program "sbcl"                                                                                                                                                                   &lt;br /&gt;lisp-indent-function 'common-lisp-indent-function                                                                                                                                               &lt;br /&gt;slime-complete-symbol-function 'slime-fuzzy-complete-symbol                                                                                                                                     &lt;br /&gt;common-lisp-hyperspec-root "file:/usr/share/doc/hyperspec/" ;; Debian                                                                                                                           &lt;br /&gt;slime-startup-animation t)                                                                                                                                                                      &lt;br /&gt;&lt;br /&gt;(add-hook 'lisp-mode-hook (lambda () (slime-mode t)))                                                                                                                                                &lt;br /&gt;(add-hook 'slime-repl-mode-hook (lambda () (slime-mode t)))                                                                                                                                          &lt;br /&gt;(add-hook 'inferior-lisp-mode-hook (lambda () (inferior-slime-mode t)))                                                                                                                              &lt;br /&gt;&lt;br /&gt;(defun customised-lisp-keyboard()                                                                                                                                                                    &lt;br /&gt;(local-set-key [C-tab] 'slime-fuzzy-complete-symbol)                                                                                                                                               &lt;br /&gt;(local-set-key [return] 'newline-and-indent))                                                                                                                                                      &lt;br /&gt;&lt;br /&gt;(add-hook 'lisp-mode-hook 'customised-lisp-keyboard)                                                                                                                                                 &lt;br /&gt;&lt;br /&gt;(global-set-key "\C-cs" 'slime-selector)                                                                                                                                                             &lt;br /&gt;&lt;br /&gt;;; Search in lispdoc.org                                                                                                                                                                             &lt;br /&gt;(defun lispdoc ()                                                                                                                                                                                    &lt;br /&gt;"Searches lispdoc.com for SYMBOL, which is by default the symbol                                                                                                                                   &lt;br /&gt;currently under the curser. Use M-x lispdoc"                                                                                                                                                         &lt;br /&gt;(interactive)                                                                                                                                                                                      &lt;br /&gt;(let* ((word-at-point (word-at-point))                                                                                                                                                             &lt;br /&gt;(symbol-at-point (symbol-at-point))                                                                                                                                                         &lt;br /&gt;(default (symbol-name symbol-at-point))                                                                                                                                                     &lt;br /&gt;(inp (read-from-minibuffer                                                                                                                                                                  &lt;br /&gt;(if (or word-at-point symbol-at-point)                                                                                                                                                &lt;br /&gt;(concat "Symbol (default " default "): ")                                                                                                                                         &lt;br /&gt;"Symbol (no default): "))))                                                                                                                                                      &lt;br /&gt;(if (and (string= inp "") (not word-at-point) (not                                                                                                                                               &lt;br /&gt;symbol-at-point))                                                                                                                              &lt;br /&gt;(message "you didn't enter a symbol!")                                                                                                                                                       &lt;br /&gt;(let ((search-type (read-from-minibuffer                                                                                                                                                       &lt;br /&gt;"full-text (f) or basic (b) search (default b)? ")))                                                                                                                     &lt;br /&gt;(browse-url (concat "http://lispdoc.com?q="                                                                                                                                                  &lt;br /&gt;(if (string= inp "")                                                                                                                                                 &lt;br /&gt;default                                                                                                                                                          &lt;br /&gt;inp)                                                                                                                                                       &lt;br /&gt;"&amp;amp;search="                                                                                                                                                       &lt;br /&gt;(if (string-equal search-type "f")                                                                                                                           &lt;br /&gt;"full+text+search"                                                                                                                                       &lt;br /&gt;"basic+search")))))))&lt;br /&gt;;; Fontify *SLIME Description* buffer                                                                                                                                                                &lt;br /&gt;(defun slime-description-fontify ()                                                                                                                                                                  &lt;br /&gt;"Fontify sections of SLIME Description."                                                                                                                                                           &lt;br /&gt;(with-current-buffer "*SLIME Description*"                                                                                                                                                         &lt;br /&gt;(highlight-regexp                                                                                                                                                                                &lt;br /&gt;(concat "^Function:\\|"                                                                                                                                                                         &lt;br /&gt;"^Macro-function:\\|"                                                                                                                                                                   &lt;br /&gt;"^Its associated name.+?) is\\|"                                                                                                                                                        &lt;br /&gt;"^The .+'s arguments are:\\|"                                                                                                                                                           &lt;br /&gt;"^Function documentation:$\\|"                                                                                                                                                          &lt;br /&gt;"^Its.+\\(is\\|are\\):\\|"                                                                                                                                                              &lt;br /&gt;"^On.+it was compiled from:$")                                                                                                                                                          &lt;br /&gt;'hi-green-b)))                                                                                                                                                                                  &lt;br /&gt;&lt;br /&gt;(defadvice slime-show-description (after slime-description-fontify activate)                                                                                                                         &lt;br /&gt;"Fontify sections of SLIME Description."                                                                                                                                                           &lt;br /&gt;(slime-description-fontify))                                                                                                                                                                       &lt;br /&gt;&lt;br /&gt;;; Use W3M                                                                                                                                                                                           &lt;br /&gt;(require 'w3m)                                                                                                                                                                                       &lt;br /&gt;&lt;br /&gt;(defun w3m-browse-url-other-window (url &amp;amp;optional newwin)                                                                                                                                            &lt;br /&gt;(interactive                                                                                                                                                                                       &lt;br /&gt;(browse-url-interactive-arg "w3m URL: "))                                                                                                                                                         &lt;br /&gt;(let ((pop-up-frames nil))                                                                                                                                                                         &lt;br /&gt;(switch-to-buffer-other-window                                                                                                                                                                   &lt;br /&gt;(w3m-get-buffer-create "*w3m*"))                                                                                                                                                                &lt;br /&gt;(w3m-browse-url url)))                                                                                                                                                                           &lt;br /&gt;&lt;br /&gt;(setq browse-url-browser-function                                                                                                                                                                    &lt;br /&gt;(list (cons "^ftp:/.*"  (lambda (url &amp;amp;optional nf)                                                                                                                                             &lt;br /&gt;(call-interactively #'find-file-at-point url)))                                                                                                                      &lt;br /&gt;(cons "."  #'w3m-browse-url-other-window)))                                                                                                                                          &lt;br /&gt;&lt;br /&gt;;;; JavaScript                                                                                                                                                                                       &lt;br /&gt;;;; http://web.comhem.se/~u34308910/emacs.html#javascript                                                                                                                                            &lt;br /&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;                                                                                                                                                             &lt;br /&gt;&lt;br /&gt;(autoload 'javascript-mode "javascript" nil t)                                                                                                                                                       &lt;br /&gt;(add-to-list `auto-mode-alist `("\\.js\\'" . javascript-mode)) &lt;br /&gt;&lt;br /&gt;;;; Helper functions                                                                                                                                                                                 &lt;br /&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; &lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Сега нещата стоят по друг начин, писането на Lisp е песен. Ето и командите, които най-често използвам:&lt;br /&gt;&lt;pre&gt;LISP RELATED&lt;br /&gt;&lt;br /&gt;; Parants&lt;br /&gt;&lt;b&gt;M-(&lt;/b&gt; Prints ()&lt;br /&gt;&lt;br /&gt;; Compilation&lt;br /&gt;&lt;b&gt;C-c M-k&lt;/b&gt; slime-compile-file&lt;br /&gt;&lt;b&gt;C-c C-c&lt;/b&gt; slime-compile-defun&lt;br /&gt;&lt;br /&gt;; Evaluation&lt;br /&gt;&lt;b&gt;C-M-x&lt;/b&gt; slime-eval-defun&lt;br /&gt;&lt;br /&gt;; Documentation&lt;br /&gt;&lt;b&gt;C-c C-d a&lt;/b&gt; slime-apropos&lt;br /&gt;&lt;b&gt;C-c C-d h&lt;/b&gt; slime-hyperspec-lookup&lt;br /&gt;&lt;b&gt;C-c C-m&lt;/b&gt; slime-macroexpand-1&lt;br /&gt;&lt;br /&gt;; Cross-reference&lt;br /&gt;&lt;b&gt;C-c C-w r&lt;/b&gt; slime-who-references&lt;br /&gt;&lt;br /&gt;; Manage Slime&lt;br /&gt;&lt;b&gt;M-x slime&lt;/b&gt; start slime&lt;br /&gt;&lt;b&gt;C-c C-c&lt;/b&gt; slime compile defun&lt;br /&gt;&lt;b&gt;C-c C-k&lt;/b&gt; slime compile and load file&lt;br /&gt;&lt;b&gt;C-c M-g&lt;/b&gt; slime quit&lt;br /&gt;&lt;br /&gt;&lt;b&gt;C-c C-t&lt;/b&gt; slime clear repl&lt;br /&gt;&lt;b&gt;M-p&lt;/b&gt; slime prev command&lt;br /&gt;&lt;b&gt;M-n&lt;/b&gt; slime next command&lt;br /&gt;&lt;br /&gt;&lt;b&gt;M-r&lt;/b&gt; slime search prev commands&lt;br /&gt;&lt;b&gt;M-s&lt;/b&gt; slime search next commands&lt;br /&gt;&lt;br /&gt;&lt;b&gt;C-c C-z&lt;/b&gt; go to lisp buffer&lt;br /&gt;&lt;b&gt;C-c C-q&lt;/b&gt; close all parens&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Ето един много добър линк за Emacs командите: &lt;a href="http://www.cb1.com/%7Ejohn/computing/emacs/beyond-tutorial.html"&gt;Beyond Emacs Tutorial&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Oстана да се добави малко творчество и нещата добиват завършен вид. Горе долу подхода ми е следния:&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;1. Всичко(functions, classes, special variables, and constants) го слагам в defun, за да мога лесно да го проверя дали има грешки с С-с С-с. Ако нещо много ме усъмни(да проверя нещо как работи) се прехвърлям на REPL с C-c C-z и го изпълнявам.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;2. Програмата трябва да е lоаdable, сиреч да не се прави нищо допълнително, за да може да се стартира самостоятелно. Ако програмата да кажем, че се казва proba.lisp не ползва допълнителни библиотеки, тогава няма нищо за правене. По-сложнен е другия случай, да иска. Да кажем ползва &lt;b&gt;cl-ppcre&lt;/b&gt;. Тогава в кода има:&lt;br /&gt;&lt;pre&gt;(defpackage #:proba&lt;br /&gt;(:use #:cl #:cl-ppcre))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Това само по себе си не е достатъчно. Ако направим:&lt;br /&gt;&lt;pre&gt;(load (compile-file "proba"))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Получаваме следната грешка: &lt;b&gt;The name "CL-PPCRE" does not designate any package&lt;/b&gt;. Ха сега де.&lt;br /&gt;По някакъв начин трябва да съм сигурен, че cl-ppcre ще се зареди и компилира преди моя файл proba.lisp. Най-лесния вариант е да изплзвам &lt;b&gt;ASDF&lt;/b&gt;. Създавам един файл proba.asd и в него слагам:&lt;br /&gt;&lt;pre&gt;(asdf:defsystem #:proba&lt;br /&gt;:depends-on (#:cl-ppcre)&lt;br /&gt;:components ((:file "proba")))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Ако пък работя в REPL-a ще използвам: &lt;b&gt;,load-system&lt;/b&gt; или &lt;b&gt;(asdf:oos 'asdf:load-op 'proba)&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;3. Ами ако проета от един файл нарасне и стане проект? Тогава ще се наложи да разделяме на малки файлове и да ги "вържем" по някакъв начин. Да речем proba.lisp нарасне много и аз реша да го рефакторирам и изкарам някои операции в друг файл - operations.lisp. За целта ще се наложи да работя с пакети. Създавам файла package.lisp и в началото на proba.lisp и operations.lisp указвам, на кой пакет пренадлежат.&lt;br /&gt;&lt;pre&gt;(in-package #:proba)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Послендия файл ще изглежда малко променен:&lt;br /&gt;&lt;pre&gt;(asdf:defsystem #:proba&lt;br /&gt;:depends-on (#:cl-ppcre)&lt;br /&gt;:components ((:file "package")&lt;br /&gt;(:file "operations"&lt;br /&gt;:depends-on ("package"))&lt;br /&gt;(:file "proba"&lt;br /&gt;:depends-on ("package"&lt;br /&gt;"operations"))))&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;4. Приготвям се за финиширане като се попитам: А какви са нещата от проекта, които могат да се използеват дирекно(кои са интерфейсите)? Определям ги и променям пакетната дефиниция в package.cl:&lt;br /&gt;&lt;pre&gt;(defpackage #:proba&lt;br /&gt;(:use #:cl #:cl-ppcre)&lt;br /&gt;(:export #:blah&lt;br /&gt;#:blah2&lt;br /&gt;#:useful-thing3&lt;br /&gt;#:*logfile-directory*))&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;5. И накрая малко хитрости. Винаги стартирам проета си от неговата директория. Ако съм направил нещо наистина полезно правя нещата още по-глобални като линквам .asd в &lt;b&gt;~/.sbcl/systems/&lt;/b&gt;.&lt;br /&gt;&lt;pre&gt;cd ~/.sbcl/system&lt;br /&gt;ln -s ../../Lisp/proba/proba.asd .&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Така много лесно мога да си ползвам проета отвсякъде като пиша просто:&lt;b&gt;(require 'proba)&lt;/b&gt;. Или ако от друг проект ми притрябват моите "полезни" неща от proba. Просто:&lt;br /&gt;&lt;pre&gt;(asdf:defsystem #:useful_thing3&lt;br /&gt;:depends-on (#:proba #:drakma)&lt;br /&gt;:components (...))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;В общи линии така върви моя Лисп път.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Update(15.12.2009:&lt;/b&gt; Нещата в моя .emacs непрекъснато се променят в затова реших да ги сложа &lt;a href="http://code.google.com/p/zlatozar/source/browse/#svn/trunk/lisp"&gt;тук&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14240039-116334284208027962?l=zlatozar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zlatozar.blogspot.com/feeds/116334284208027962/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14240039&amp;postID=116334284208027962' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/116334284208027962'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/116334284208027962'/><link rel='alternate' type='text/html' href='http://zlatozar.blogspot.com/2006/11/lisp-evironment.html' title='Lisp environment'/><author><name>Zlatozar</name><uri>http://www.blogger.com/profile/16257250071061885492</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/17/6760/640/RabotnotoMqsto.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14240039.post-116225754509877117</id><published>2006-10-31T03:17:00.001+02:00</published><updated>2008-04-15T14:46:45.395+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='думи'/><title type='text'>Мисли, не казани</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/x/blogger/5870/1282/1600/352393/Malyk_Zlatko.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://photos1.blogger.com/x/blogger/5870/1282/320/107155/Malyk_Zlatko.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Много от нещата тръгнаха от тази невинна снимка, направена преди много много години. Гледах я и мислите се заредиха. Връщах се многократно в моето щастливо детство. Първо спомени, после тъга. Един толкова обикновен мой портрет от социалистическата детска градина.&lt;br /&gt;Знаех ли какво ме чака? Имах ли представа, колко много ще се променя? Шеметно детство в малкя град, заобиколен с много приятели и любов. Още ме грее този спомен.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14240039-116225754509877117?l=zlatozar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zlatozar.blogspot.com/feeds/116225754509877117/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14240039&amp;postID=116225754509877117' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/116225754509877117'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/116225754509877117'/><link rel='alternate' type='text/html' href='http://zlatozar.blogspot.com/2006/10/blog-post.html' title='Мисли, не казани'/><author><name>Zlatozar</name><uri>http://www.blogger.com/profile/16257250071061885492</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/17/6760/640/RabotnotoMqsto.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14240039.post-116125645789293442</id><published>2006-10-19T14:13:00.000+03:00</published><updated>2007-05-29T15:47:01.318+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='freebsd'/><title type='text'>Thoughts on HFSC</title><content type='html'>Реших да напиша стятия за PF ама то като гледам с каква скорост се развивата няма да стане скоро. Затова ще опитам да си разясня HFCS планировчика. Ще поясня основните неща, оптимизацията и "хватките" са си ваше дело.&lt;br /&gt;&lt;br /&gt;   Откъде идва името HFSC? Това е съкращение на Hierarchical Fair Service Curve Algorithm. Ето и каква е идеята. Добре е планировчика да се самонаглася и да взема рашения според случая - selfadopted.&lt;br /&gt;В HFSC има &lt;b&gt;ДВА&lt;/b&gt; планировчика(packet schedularas). Първия е гарантирания или т.н. realtime, а втория linkshare. HFSC ще избере автоматично, коj от двата ще използва ako на места параметрите се препокриват. Параметрите, които контролират тези два планировчика са:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;realtime - &lt;/b&gt; той контролира минималната ширина (bandwidth), която се изисква от опашката. Когато има възможност HFSC предпочита този, той е default. Големината му ще нараства докато се достигне лимита на канала или се достигне &lt;b&gt;upperlimit&lt;/b&gt; ограничението. Ако нямаме realtime планировчик или "интернета" ни е малко и не можем да гарантираме нужния минимум, ще се използва &lt;b&gt;linkshare&lt;/b&gt;. Този параметър e опционален.&lt;br /&gt;&lt;br /&gt;Още по нагледно:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;   if (there is an eligible packet)&lt;br /&gt;      /* real-time criteria */&lt;br /&gt;      send eligible packet with min. deadline d ;&lt;br /&gt;   else&lt;br /&gt;      /* link-sharing criteria */&lt;br /&gt;      send packet with min. virtual time v ;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;linkshare - &lt;/b&gt; той определя колко да се вземе трафика за текущата от опашката баща (parent queue). Разпределя пропорционално интернета. Ако имаме излишък той ще се използва според допълнителните параметри или докато се достигне upperlimit (ako e упоменат). И този параметър е опционален.&lt;br /&gt;&lt;br /&gt;Mалко по особено е. Където са дефинирани realtime и linkshare и параметрите в тях се препокриват ще се предпочете realtime. Realtime е планировчика по подразбиране. И още нещо, ако в дефиницията на опашката (а не в altq) не се използва linkshare &lt;b&gt;задължително&lt;/b&gt; трябва да се напише &lt;b&gt;bandwidth&lt;/b&gt;! В противен случай &lt;b&gt;pfctl&lt;/b&gt; ще се оплаче. Запомнете го, макар май се промени това в новите версии на pf.&lt;br /&gt;&lt;br /&gt;Надлежно показвам какво съм видял в кода:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  ls - linkshare&lt;br /&gt;  rt - realtime&lt;br /&gt;  ul - upper limit&lt;br /&gt;&lt;br /&gt;  /* if link_share is not specified, use bandwidth */&lt;br /&gt;  if (opts-&gt;lssc_m2 == 0)&lt;br /&gt;     opts-&gt;lssc_m2 = pa-&gt;bandwidth;&lt;br /&gt;&lt;br /&gt;  if ((opts-&gt;rtsc_m1 &gt; 0 &amp;&amp;amp; opts-&gt;rtsc_m2 == 0) ||&lt;br /&gt;      (opts-&gt;lssc_m1 &gt; 0 &amp;&amp;amp; opts-&gt;lssc_m2 == 0) ||&lt;br /&gt;      (opts-&gt;ulsc_m1 &gt; 0 &amp;&amp;amp; opts-&gt;ulsc_m2 == 0)) {&lt;br /&gt;&lt;br /&gt;     warnx("m2 is zero for %s", pa-&gt;qname);&lt;br /&gt;     return (-1);&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Пример:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;altq on $ext_if hfsc bandwidth 45Mb   &lt;br /&gt;  queue{dns, ssh, www, mail, other}&lt;br /&gt;     queue dns bandwidth 10%&lt;br /&gt;     queue ssh bandwidth 10%&lt;br /&gt;     queue mail bandwidth 20%&lt;br /&gt;     queue www bandwidth 40%&lt;br /&gt;     queue other hfsc(default)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;upperlimit - &lt;/b&gt; това е максималното количество "интернет", което някоя от опашките може да използва. И още нещо, което се разбира ама аз да си го кажа: Стойността на upperlimmit трябва да е по-голяма от лимитите поставени в realtime и linkshare. Този параметър е опционален.&lt;br /&gt;&lt;br /&gt;Нуждаем се и от малко теория. Ето и необходимата порция.&lt;br /&gt;След всеки един от тези параметри има число, което указва каква част от интернет потока трябва да се задели или от следните 3 числа (m1 d m2). Какво заначат тези числа&lt;br /&gt;&lt;br /&gt;&lt;b&gt;m1&lt;/b&gt; - първоначалното количество интернет.&lt;br /&gt;&lt;b&gt;d&lt;/b&gt; - забавянето (time delay, in milliseconds)&lt;br /&gt;&lt;b&gt;m2&lt;/b&gt; - корекция на количеството интернет&lt;br /&gt;&lt;br /&gt;Тези параметри определят така наречената "сервизна крива" (service curve). Tя може да бъде два типа:&lt;br /&gt;изпъкнала (convex) при m1 &gt; m2&lt;br /&gt;вдлъбната (concave) при  m1 &lt; m2.&lt;br&gt;&lt;br /&gt;&lt;b&gt;ВАЖНО:&lt;/b&gt;&lt;br /&gt;1) realtime параметрите не могат да бъдат по-големи от 75% от целия ни интернет (total interface bandwidth)&lt;br /&gt;2) кривата на realtime трябва да е винаги изпъкнала (m1 &gt; m2).&lt;br /&gt;&lt;br /&gt;Да онагледим нещата:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;# PARENT QUEUE DEFINITION&lt;br /&gt;altq on $ext_if hfsc bandwidth 45Mb   &lt;br /&gt;  queue{dmznet, prvnet, others}&lt;br /&gt;&lt;br /&gt;# CHILD QUEUE DEFINITIONS&lt;br /&gt;# ако пакетите се задържат до 10 сек. ще вземе 50% или повече&lt;br /&gt;# от цялия интернет. Когато пакетите пристигат повече и повече и&lt;br /&gt;# планировчика ги задържа повече от 10 сек. ще се опита да се коригира&lt;br /&gt;# и завземе 65% от интернета.&lt;br /&gt;  queue dmznet hfsc(linkshare (50% 10000 65%))&lt;br /&gt;&lt;br /&gt;# и тук е същото, само че ще се коригира към по-малко!&lt;br /&gt;  queue prvnet hfsc(linkshare (40% 5000 25%))&lt;br /&gt;  queue others hfsc(default)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Нека да поясним нещата. Може да разглеждате опашките като скачени съдове, едното е за сметка на другото. Затова сумата от параметрите от един вид не трябва да надвишават количеството интернет (total bandwith) като default опашката не влиза в тия сметки. Тези стойности могат да са %, b, Kb, Mb, Gb.&lt;br /&gt;&lt;br /&gt;Да направим анализ. Да кажем, че в DMZ зоната има FTP сървър и в един момент почва да бълва трафик и "тръбата" от 50% не може да смогне (бави пакетите повече от 10 сек.) затова планировчика я разширява автоматично. Разширяването е за сметка обаче на privnet. Защо съм сложил съм 5 сек? Расъждавам така, ако някое типче тръгне да сваля нещо ще запълни "тръбата" и аз ще го резна като изрично намаля капациета. Второ, ако забавянето е повече от 5 сек. то някъде другаде(в случая dmz зоната) става нещо, трябва повече интернет. Хм, за оптимизацията се разбрахме не мога да кажа точно какво трябва да е забавянето (delay).&lt;br /&gt;&lt;b&gt;Запамети.&lt;/b&gt; Горната граница на разширяването може да се ограничи единствено от upperlimit.&lt;br /&gt;&lt;br /&gt;Нещата стават още по-интересни, когато намесим и realtime. Kакто ви казах могат да бъдат дефинирани едновременно. HFSC автоматично ще избере, кои ще свърши по-добра работа. Може да изберете да имат еднакви параметри, може и да измислите нещо по-хитро. Дерзайте, но не забравяйте, че сервизната крива на realtime винаги трябва да бъде изпъкнала (m1 &gt; m2). И от тук и простичкото правило: ако искате при забавяне да увеличите канала - linkshare, ako не - realtime.&lt;br /&gt;&lt;br /&gt;Пример:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;# PARENT QUEUE DEFINITION&lt;br /&gt;altq on $ext_if hfsc bandwidth 45Mb&lt;br /&gt;  queue{dmznet, prvnet, others}&lt;br /&gt;&lt;br /&gt;# CHILD QUEUE DEFINITIONS&lt;br /&gt;  queue dmznet hfsc(linkshare (50% 10000 65%))&lt;br /&gt; &lt;br /&gt;  # HFSC ще избере сам.&lt;br /&gt;  queue prvnet hfsc(realtime (40% 5000 25%) linkshare (40% 5000 25%))&lt;br /&gt;  queue others hfsc(default)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;И остана последно смятането на количествата интернет. Сравнете следните два примера:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;# CBQ&lt;br /&gt;altq on $ext_if cbq bandwidth 20Mb    queue{dmznet, prvnet, others}&lt;br /&gt;&lt;br /&gt; # prvnet gets 8Mb&lt;br /&gt; queue prvnet bandwidth 40% queue{host1, host2}&lt;br /&gt;    # host1 gets 4Mb&lt;br /&gt;    queue host1 bandwidth 50%&lt;br /&gt;&lt;br /&gt;    # host2 gets 4Mb&lt;br /&gt;    queue host2 bandwidth 50%&lt;br /&gt;&lt;br /&gt;# HFSC&lt;br /&gt;altq on $ext_if hfsc bandwidth 20Mb    queue{dmznet, prvnet, others}&lt;br /&gt;&lt;br /&gt;  # prvnet gets 8Mb&lt;br /&gt;  queue prvnet hfsc(linkshare 40%) queue{host1, host2}&lt;br /&gt;     # host1 gets 4Mb&lt;br /&gt;     queue host1 hfsc(linkshare 20%)&lt;br /&gt;&lt;br /&gt;     # host2 gets 4Mb&lt;br /&gt;     queue host2 hfsc(linkshare 20%)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Какво се забелязва? CBQ разпределя параметрите спрямо parent опашката, а HFSC спрямо root! Много често се греши внимавайте!&lt;br /&gt;&lt;br /&gt;Искам да спомена и един друг параметър, който често пипам qlimit. Той определя колко да е голяма опашката и от там колко гладко да се обработва. По подразбиране е 50 пакета. Преди да правите радикални промени поиграйте си с qlimit.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;queue oRel  bandwidth 128Kb qlimit 100  hfsc( linkshare 128Kb ) { oRelTCP, oRelUDP }       &lt;br /&gt;       queue oRelTCP bandwidth 64Kb qlimit 60 hfsc( linkshare 64Kb default red )            &lt;br /&gt;       queue oRelUDP bandwidth 64Kb qlimit 60 hfsc( linkshare 64Kb)      &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Какво да използваме? Ако искаме да сортираме трафика по приоритет ще се възползваме от PRIQ. Ако искаме да разпределим нещата "на калпак" - CBQ. И накрая ако искаме всичко това плюс разни други красиви добавки HFSC.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14240039-116125645789293442?l=zlatozar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zlatozar.blogspot.com/feeds/116125645789293442/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14240039&amp;postID=116125645789293442' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/116125645789293442'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/116125645789293442'/><link rel='alternate' type='text/html' href='http://zlatozar.blogspot.com/2006/10/thoughts-on-hfsc.html' title='Thoughts on HFSC'/><author><name>Zlatozar</name><uri>http://www.blogger.com/profile/16257250071061885492</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/17/6760/640/RabotnotoMqsto.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14240039.post-116065617510248693</id><published>2006-10-12T15:28:00.000+03:00</published><updated>2008-01-14T14:35:57.776+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Lisp'/><title type='text'>The Zen of LISP clusure</title><content type='html'>&lt;b&gt;Definitions:&lt;/b&gt;&lt;br /&gt;A function plus its enviroment is called a closure.&lt;br /&gt;&lt;br /&gt;A closure typically comes about when one function is declared entirly within the body of another, and inner function refer to local variables of the outer function.&lt;br /&gt;&lt;br /&gt;Example:&lt;br /&gt;&lt;pre class="programlisting"&gt;&lt;br /&gt;(defparameter *fn* &lt;br /&gt; (let ((count 0))&lt;br /&gt;  #'(lambda () (setf count (1+ count))))) ; function closure.&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;code&gt;count&lt;/code&gt; is lambda enviroment( or lambda use &lt;code&gt;count&lt;/code&gt; ).&lt;br /&gt;&lt;br /&gt;Possible usage:  Closures can be used for modularity so you don't have to encapsulate data in classes to prevent it from becoming global. &lt;br /&gt;&lt;br /&gt;Тhe names introduced by a LET form turns out not to be a name binding to some immutable values. The names refer to local variables! Such variables(a.k.a lexical variables) follow typical lexical scoping rules, so that LISP always looks up the innermost variable definition when a variable name is to be evaluated. &lt;br /&gt;&lt;br /&gt;Example:&lt;br /&gt;&lt;pre class="programlisting"&gt;&lt;br /&gt;(defun bar () &lt;br /&gt;  (foo) &lt;br /&gt;  (let ((*x* 20)) (foo)) &lt;br /&gt;  (foo)) &lt;br /&gt;&lt;br /&gt;CL-USER: (bar) &lt;br /&gt;X: 10 &lt;br /&gt;X: 20 &lt;br /&gt;X: 10 &lt;br /&gt;NIL &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Definition:&lt;/b&gt;&lt;br /&gt;A lexical variable is a variable that can only be referenced at the textual location of the code that creates it.&lt;br /&gt;&lt;br /&gt;Everything starts from LET (a.k.a binding form). Here is the LET definition:&lt;br /&gt;&lt;br /&gt;&lt;pre class="programlisting"&gt;&lt;br /&gt;(let (&lt;i class="emphasis"&gt;variable&lt;/i&gt;*) &lt;br /&gt;  &lt;i class="emphasis"&gt;body-form&lt;/i&gt;*)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;where each &lt;em&gt;variable&lt;/em&gt; is a variable initialization form. When the LET form is evaluated, all the initial value forms are first evaluated. Then new bindings are created and initialized to the appropriate initial values before the body forms are executed. Within the body of the LET, the variable names refer to the newly created bindings. After the LET, the names refer to whatever, if anything, they referred to before(out of local scope) the LET. What happend when we use this variable in inner defined function?&lt;br /&gt;&lt;br /&gt;What is more interesting is that, due to the ability to return functions as values, the local variable has a life span longer than the expression defining it. Consider the following example:&lt;br /&gt;&lt;br /&gt;&lt;pre class="programlisting"&gt;&lt;br /&gt;CL-USER: (setf inc (let ((counter 0)) &lt;br /&gt;                      #'(lambda () &lt;br /&gt;                          (incf counter))))&lt;br /&gt;inc&lt;br /&gt;CL-USER: (funcall inc)&lt;br /&gt;1&lt;br /&gt;CL-USER: (funcall inc)&lt;br /&gt;2&lt;br /&gt;CL-USER: (funcall inc)&lt;br /&gt;3&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;                                      +---------------------+&lt;br /&gt;                                      |                     |&lt;br /&gt;                    +-------- lambda function --------+     |&lt;br /&gt;                    |    func. enviroment             |     |use&lt;br /&gt;               ref. |               ===========       |     |&lt;br /&gt;INC --------------&gt; |               | counter |&lt;------|---- +&lt;br /&gt;                    |               ===========       |&lt;br /&gt;                    +---------------------------------+&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;em&gt;counter&lt;/em&gt; has nice "secret" live inside lambda function.&lt;br /&gt;We assign a value to the global variable &lt;b&gt;inc&lt;/b&gt;. That value is obtained by first defining local variable counter using LET, and then within the lexical scope of the local variable, a &lt;b&gt;lambda&lt;/b&gt; expression is evaluated, thereby creating an annonymous function, which is returned as a value to be assigned to &lt;b&gt;inc&lt;/b&gt;. The most interesting part is in the body of that &lt;b&gt;lambda&lt;/b&gt; expression - it increments the value of the local variable counter! When the &lt;b&gt;lambda&lt;/b&gt; expression is returned, the local variable persists, and is accessible only through the annonymous function.&lt;br /&gt;&lt;br /&gt;The thing to remember from this example is that, in other kinds of languages like Java and C/C++ the lexical scope of a local variable somehow coincide with its life span. After executation passes beyond the boundary of a lexical scope, all the local variables defined within it cease to exist. This is not true in languages supporting that return functions as values. Lexical scoping is enforced strictly, and therefore the only place from which you can alter the value of counter is within the lexical scope of the variable - the lambda expression. As a result, the counter state is effectively encapsulated. The only way to modify it is by going through the annonymous function stored in inc. The technical term to refer to this thing that is stored in &lt;b&gt;inc&lt;/b&gt;, this thing that at the same time captures both the definition of a function and the variables referenced within the function body is called a function closure.&lt;br /&gt;&lt;br /&gt;NOTE: If you keep in mind that "#'" means roughly "allocate  (in the heap)&lt;br /&gt;a closure for the following LAMBDA expression".&lt;br /&gt;&lt;br /&gt;What if we want to define multiple interface functions for the encapsulated counter? Simple, just return all of them:&lt;br /&gt;&lt;br /&gt;&lt;pre class="programlisting"&gt;&lt;br /&gt;CL-USER: (setf list-of-funcs (let ((counter 0))&lt;br /&gt;                                (list #'(lambda ()&lt;br /&gt;                                          (incf counter))&lt;br /&gt;                                      #'(lambda ()&lt;br /&gt;                                          (setf counter 0)))))&lt;br /&gt;CL-USER: (setf inc (first list-of-funcs))&lt;br /&gt;CL-USER: (setf reset (second list-of-funcs))&lt;br /&gt;CL-USER: (funcall inc)&lt;br /&gt;1&lt;br /&gt;CL-USER: (funcall inc)&lt;br /&gt;2&lt;br /&gt;CL-USER: (funcall inc)&lt;br /&gt;3&lt;br /&gt;CL-USER: (funcall reset)&lt;br /&gt;0&lt;br /&gt;CL-USER: (funcall inc)&lt;br /&gt;1&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;NIRVANA!&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14240039-116065617510248693?l=zlatozar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zlatozar.blogspot.com/feeds/116065617510248693/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14240039&amp;postID=116065617510248693' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/116065617510248693'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/116065617510248693'/><link rel='alternate' type='text/html' href='http://zlatozar.blogspot.com/2006/10/zen-of-lisp-clusure.html' title='The Zen of LISP clusure'/><author><name>Zlatozar</name><uri>http://www.blogger.com/profile/16257250071061885492</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/17/6760/640/RabotnotoMqsto.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14240039.post-115994992775328012</id><published>2006-10-04T11:16:00.023+03:00</published><updated>2011-12-21T13:32:34.556+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='misc'/><title type='text'>CV</title><content type='html'>&lt;b&gt;PERSONAL INFO&lt;/b&gt;&lt;br /&gt;=========================================================&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_O17Am5thzlA/Sq5BX5lLAaI/AAAAAAAACts/qUKiOLUfZVI/s1600-h/p1000391.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="Zlatozar Zhelyazkov" border="0" id="BLOGGER_PHOTO_ID_5381310483603849634" src="http://3.bp.blogspot.com/_O17Am5thzlA/Sq5BX5lLAaI/AAAAAAAACts/qUKiOLUfZVI/s200/p1000391.jpg" style="cursor: pointer; float: left; height: 200px; margin: 0pt 10px 10px 0pt; width: 150px;" /&gt;&lt;/a&gt;&lt;br /&gt;&amp;nbsp; Name: &lt;b&gt;Zlatozar Zhelyazkov&lt;/b&gt;&lt;br /&gt;&amp;nbsp; Birth Date: 05 May 1973&lt;br /&gt;&amp;nbsp; Address: Sofia, Nadejda 2&lt;br /&gt;&amp;nbsp; Family Status: &amp;nbsp;Married&lt;br /&gt;&lt;br /&gt;&amp;nbsp; Email: &amp;nbsp;&lt;b&gt;zlatozar@gmail.com&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;EDUCATION&lt;/b&gt;&lt;br /&gt;=========================================================&lt;br /&gt;1991 – 1996&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;b&gt;Technical University of Sofia&lt;/b&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Specialty: Computer Science&lt;br /&gt;&lt;br /&gt;Thesis in Cryptographic Algorithms.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;EXPIRIENCE&lt;/b&gt;&lt;br /&gt;=========================================================&lt;br /&gt;&lt;br /&gt;06/1998 – 03/2001&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;i&gt;&lt;b&gt;BG Contact&lt;/b&gt;&lt;/i&gt; (&lt;a href="http://www.bg-contact.com/"&gt;http://www.bg-contact.com&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Position: Head of Toshiba Technical Service (Office Plovdiv)&lt;/b&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Service Parts Logistics&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Customer support&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Toshiba products maintenance&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;New Toshiba products presentation&lt;br /&gt;&lt;br /&gt;3/2001 – 9/2001&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;i&gt;&lt;b&gt;ProSyst, Sofia&lt;/b&gt;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Position: Junior Java Developer&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Project:&lt;/b&gt; ProSyst Application Server&lt;br /&gt;&lt;br /&gt;10/2001 – 05/2005&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;i&gt;&lt;b&gt;IFAO Group, Bulgaria&lt;/b&gt;&lt;/i&gt; (&lt;a href="http://www.ifao.net/"&gt;www.ifao.net&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Position: Java Developer&lt;/b&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;CVS and Subversion support&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Versions building&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Product installation on servers&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Writing JSP and XSL files for presentation layer&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Business logic implementation&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Writing Booking Business logic&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Project:&lt;/b&gt; Cytric (&lt;a href="http://www.cytric.net/"&gt;www.cytric.net&lt;/a&gt;)&lt;br /&gt;&lt;b&gt;cytric&lt;/b&gt; provides an instant overview of the locations of all a company´s travelers. Its Software-as-a-Service (SaaS) principle. Other highlights include optimized hotel search, integration of new airline programs and the import of offline bookings into cytric Enterprise Reporting.&lt;br /&gt;&lt;br /&gt;05/2005 – 08/2008&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;i&gt;&lt;b&gt;Industria, Bulgaria&lt;/b&gt;&lt;/i&gt; (&lt;a href="http://www.industria.com/"&gt;www.industria.com&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Position: Senior Java Developer&lt;/b&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Perforce, Subversion support&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Linux servers maintainer&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Java code review&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Writing Java server side&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Writing UI (JavaScript part)&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Project:&lt;/b&gt; IMS Universal&lt;br /&gt;&lt;b&gt;Industria IMS Universal&lt;/b&gt; is based on TM Forum's NGOSS architecture and an open standards compliant workflow-processing engine. The system's business process-driven foundation provides telecom operators and service providers with a unified view of their converged network delivery channels, independent of the underpinning technologies.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Project:&lt;/b&gt; Zignal IPTV&lt;br /&gt;Zignal suite of IPTV software solutions and devices is specifically designed for use by broadband network operators, multi-play service providers, hoteliers and other large-scale operators.&lt;br /&gt;&lt;br /&gt;09/2008 – 03/2010&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;i&gt;&lt;b&gt;Xentio, Bulgaria&lt;/b&gt;&lt;/i&gt; (&lt;a href="http://xentio.com/"&gt;www.xentio.com&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Position: Senior Java Developer&lt;/b&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Application architecture decisions&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Choose suitable frameworks and technologies&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Write application critical parts&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Code review&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Project:&lt;/b&gt;    MAPS for ASML company (&lt;a href="http://asml.com/"&gt;www.asml.com&lt;/a&gt;)&lt;br /&gt;MAPS is a tool that aids in defining and maintaining machine, test and factory constants.&lt;br /&gt;&lt;br /&gt;04/2010 – 10/2011&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;i&gt;&lt;b&gt;Cisco, Bulgaria&lt;/b&gt;&lt;/i&gt; (&lt;a href="http://www.cisco.com/"&gt;www.cisco.com&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Position: Software Engeneer&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Project:&lt;/b&gt;   Cisco Web Mail&lt;br /&gt;&lt;br /&gt;10/2011 - present&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;i&gt;&lt;b&gt;Cisco, Bulgaria&lt;/b&gt;&lt;/i&gt; (&lt;a href="http://www.cisco.com/"&gt;www.cisco.com&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Position: Software Engineer at  Architecture Team&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Project:&lt;/b&gt;   &lt;a href="http://www.cisco.com/web/products/quad/index.html"&gt;Cisco Quad&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;COMPUTER SKILLS&lt;/b&gt;&lt;br /&gt;=========================================================&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Languages: &amp;nbsp; Java, JavaScript, C++, Lisp, Python, Bash Shell&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Systems: &amp;nbsp; Windows, Linux (Debian fan), FreeBSD&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Application servers: WebLogic, JBOSS&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Database: Oracle, MySQL&lt;br /&gt;&lt;br /&gt;&lt;b&gt;FRAMEWORKS, TECHNOLOGIES&lt;/b&gt;&lt;br /&gt;=========================================================&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;SVN, Mercurial, Git&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Hibernate, iBatis&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;XSL, XPath, XQuery&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Ant, Maven, Make/CMake&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;ANTLR&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;GWT&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;BRAINBENCH CERTIFICATS&lt;/b&gt;&lt;br /&gt;=========================================================&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Programming: &amp;nbsp; Java-Non GUI (Master), XML, C, OO Design Patters.&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Network Administration: &amp;nbsp; Basic Linux Administrations.&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Other: Written English&lt;br /&gt;&lt;br /&gt;&lt;b&gt;ADDITIONAL CERTIFICATS&lt;/b&gt;&lt;br /&gt;=========================================================&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Toshiba fax and copiers engineer.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;ARTICLES/CODE&lt;/b&gt;&lt;br /&gt;=========================================================&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;a href="http://www.linux-bg.org/cgi-bin/y/index.pl?page=article&amp;amp;id=devs&amp;amp;key=380207153"&gt;Destination FreeBSD&lt;/a&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;a href="http://zlatozar.blogspot.com/search/label/programming"&gt;About Programming&lt;/a&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;a href="http://code.google.com/p/various-code-fragments/"&gt;My public code repository&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;AMAZON PROFILE&lt;/b&gt;&lt;br /&gt;=========================================================&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;a href="https://www.amazon.com/gp/pdp/profile/A203PA80IV6H2F?ie=UTF8&amp;ref_=sv_ys_4"&gt;Amazone profile&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;LANGUAGES&lt;/b&gt;&lt;br /&gt;=========================================================&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;English, Russian&lt;br /&gt;&lt;br /&gt;&lt;b&gt;INTERESTS&lt;/b&gt;&lt;br /&gt;=========================================================&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Football, Swimming, Boxing, Reading, Writing&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14240039-115994992775328012?l=zlatozar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zlatozar.blogspot.com/feeds/115994992775328012/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14240039&amp;postID=115994992775328012' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/115994992775328012'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/115994992775328012'/><link rel='alternate' type='text/html' href='http://zlatozar.blogspot.com/2006/10/cv.html' title='CV'/><author><name>Zlatozar</name><uri>http://www.blogger.com/profile/16257250071061885492</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/17/6760/640/RabotnotoMqsto.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_O17Am5thzlA/Sq5BX5lLAaI/AAAAAAAACts/qUKiOLUfZVI/s72-c/p1000391.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14240039.post-115790896329916833</id><published>2006-09-10T20:21:00.002+03:00</published><updated>2011-03-02T17:20:05.853+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Fashion Axis-Hibernate</title><content type='html'>Дали ще бъдем модерни ако решим да използваме Java, Linux, JBoss, Apache Axis и Hibernate3?&lt;br /&gt;Определено ДА. Наскоро ми се наложи да сглобя нещо такова за много кратко време.&lt;br /&gt;Като разпитах се оказа, че това и често избирана комбинация при разработката на софтуер. Затова ще споделя моя опит и идеи.&lt;br /&gt;Да се направи нещо такова:&lt;br /&gt;&lt;i&gt; Имаме някакъв уеб базирано приложение и когато се обърнем към него през уеб сървисите, които той предлага, взема нещо от базата дани и ни врща резултат.&lt;/i&gt;&lt;br /&gt;Ама и аз какво описание дадох. Много общо го формулирах ама който се интересува ще му стане ясно за какво идва реч.&lt;br /&gt;&lt;br /&gt;Ето какви мисли ме налегнаха, когато видях задачата и как си отговорих на тях.&lt;br /&gt;&lt;i&gt;&lt;br /&gt;Каква линукс дистрибуция да използвам?&lt;br /&gt;Как да напрявя така че да променям приложението най-безболезнено?&lt;br /&gt;Дали ще мога да генерирам част от кода?&lt;br /&gt;и още един допълнителен: Какво ще ям довечера?&lt;br /&gt;&lt;/i&gt;&lt;br /&gt;Първия въпрос го отсях веднага щом ми казаха, че имам пълна свобода за хостващата система.&lt;br /&gt;Казах си, да бъде Debian. При Дебиан нещата с инсталирането на java са специфични. Няма .deb пакети затова човек сам трябва да си го направи. Ето как:&lt;br /&gt;&lt;pre&gt;1. Като root си инсталирам нещата, които ми трябват за създаването на java пакета:&lt;br /&gt;# apt-get install java-package&lt;br /&gt;&lt;br /&gt;2. Важно! "fakeroot" се използва за създаването на .deb&lt;br /&gt;# apt-get install fakeroot&lt;br /&gt;&lt;br /&gt;3. Вече не съм root.&lt;br /&gt;&lt;br /&gt;4. Изтеглям &amp;lt;SUN JAVA SDK FILENAME&amp;gt;.bin от сайта на Sun .&lt;br /&gt;Изтегляния файл го записвам в една temp директория.&lt;br /&gt;&lt;br /&gt;5. Смело стартирам &lt;br /&gt;$ fakeroot make-jpkg &amp;lt;SUN JAVA SDK FILENAME&amp;gt;.bin&lt;br /&gt;&lt;br /&gt;6. Инсталирам Java .deb Packagе вече като root:&lt;br /&gt;# dpkg -i &amp;lt;GENERATED DEB PACKAGE FILENAME&amp;gt;.deb&lt;br /&gt;&lt;br /&gt;7. Проверявам какво съм направил и дали рабои&lt;br /&gt;$ java -version&lt;br /&gt;&lt;br /&gt;5. Setup на JAVA_HOME, CLASSPATH и JBOSS_HOME в /etc/profile&lt;br /&gt;&lt;br /&gt;export JAVA_HOME=/usr/lib/j2sdk1.5-sun/&lt;br /&gt;export CLASSPATH=.&lt;br /&gt;&lt;br /&gt;export JBOSS_HOME=/opt/jboss-4.0.4.GA&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Подготвям се старателно и за JBOSS. Директорията /opt съм я отделил предвидливо в отделен patition. Създавам и user - jboss.&lt;br /&gt;Логвам се като jboss свалям последната версия на сървъра и разархивирам в /opt. Да обаче като гледам как се пуска си викам, абе какво ще стане ако сървъра се рестартира? Някои трябва да го стартира автоматично всеки път. За production сървъра ще е добре jboss да се пуска като демон. Ето как става и това:&lt;br /&gt;&lt;pre&gt;#! /bin/sh&lt;br /&gt;# /etc/init.d/jboss&lt;br /&gt;#&lt;br /&gt;&lt;br /&gt;# NOTE: Points JBoss installation dir&lt;br /&gt;JBOSS=/opt/jboss-4.0.4.GA&lt;br /&gt;&lt;br /&gt;start(){&lt;br /&gt;echo "Starting jboss..."&lt;br /&gt;su -l jboss -c "$JBOSS/bin/run.sh &amp;gt; /dev/null 2&amp;gt; /dev/null &amp;amp;"&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;stop(){&lt;br /&gt;echo "Stopping jboss..."&lt;br /&gt;su -l jboss -c "$JBOSS/bin/shutdown.sh -S &amp;amp;"&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;restart(){&lt;br /&gt;stop&lt;br /&gt;sleep 60&lt;br /&gt;# protect against any services that can't stop before we restart&lt;br /&gt;# (warning this kills all Java instances running as 'jboss' user)&lt;br /&gt;su -l jboss -c 'killall java'&lt;br /&gt;start&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;case "$1" in&lt;br /&gt;start)&lt;br /&gt;start&lt;br /&gt;;;&lt;br /&gt;stop)&lt;br /&gt;stop&lt;br /&gt;;;&lt;br /&gt;restart)&lt;br /&gt;restart&lt;br /&gt;;;&lt;br /&gt;*)&lt;br /&gt;echo "Usage: /etc/init.d/jboss {start|stop|restart}"&lt;br /&gt;exit 1&lt;br /&gt;esac&lt;br /&gt;&lt;br /&gt;exit 0&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;В Дебиан, за да сложиш една програма като демон съпките са следните:&lt;br /&gt;&lt;pre&gt;# инсталираме&lt;br /&gt;Write this file as /etc/init.d/jboss&lt;br /&gt;chmod 755 /etc/init.d/jboss&lt;br /&gt;update-rc.d jboss defaults&lt;br /&gt;&lt;br /&gt;# ако искаме да го разкараме&lt;br /&gt;update-rc.d -f jboss remove&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Имам си средата за исталация на приложението, време е да се заема със структурата на проекта. Това е и отговора на моя втори въпрос. &lt;br /&gt;Искам всяко нещо да си знае мястото и ant скрипта да ми е максимално упростен. Да знам къде се намират генерираните файлове и къде е бизнес логиката. Мислих, мислих и ето какво измислих:&lt;br /&gt;&lt;pre&gt;bin - тук се намират всички компилирани класове. &lt;br /&gt;Запомнете, при компилация всички конфигорационни файлове трябва да се копират&lt;br /&gt;тук(всичко от conf directory)!&lt;br /&gt;conf - конфигорационни файлове&lt;br /&gt;data (dbschema.sql)- sql който ще се генерира&lt;br /&gt;lib - всички нужни директории&lt;br /&gt;src (com.zlatozar.persistence, com.zlatozar.persistence.base, com.zlatozar.soap, com.zlatozar.common)- всички сорсове&lt;br /&gt;test (com.zlatozar...) - всички тестове. Запомнете, че src и test трябва да имат еднаква структура&lt;br /&gt;webcontent (html, jsp) - нещата за нашия сайт&lt;br /&gt;WEB-INF (web.xml, server-config.wsdd)- нужните конфигурации за сайта&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;При тази схема на проекта много лесно мога да генерирам нужния ми war файл и да пускам всички тестове. Идва най-интересната част за мен, настройката на Apache Axis. Нека първо да погледнем катинката и после е лесно - разказ по картинка.&lt;br /&gt;&lt;a href="http://photos1.blogger.com/blogger/5870/1282/1600/axis-cycle.0.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" src="http://photos1.blogger.com/blogger/5870/1282/320/axis-cycle.0.jpg" style="cursor: pointer; display: block; margin: 0px auto 10px; text-align: center;" /&gt;&lt;/a&gt;&lt;br /&gt;Какви са минималните усилия за направата на Web Services(WS)? Пиша интерфейса, който искам да се вижда "навън" и пиша клас, които го имплементира всичко друго е Axis гимнастика. Давам пример:&lt;br /&gt;&lt;pre&gt;package com.zlatozar.soap;&lt;br /&gt;public interface SaySomething extends java.rmi.Remote {&lt;br /&gt;&lt;br /&gt;public String sayHello(String name) throws java.rmi.RemoteException;&lt;br /&gt;&lt;br /&gt;public String sayGoodbye() throws java.rmi.RemoteException;&lt;br /&gt;&lt;br /&gt;public String writeSometingToDB(String id, String something)  throws java.rmi.RemoteException;&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;ето и имплементацията:&lt;br /&gt;&lt;pre&gt;package com.zlatozar.soap;&lt;br /&gt;&lt;br /&gt;import java.rmi.RemoteException;&lt;br /&gt;import com.zlatozar.persistence.QueryManager;&lt;br /&gt;&lt;br /&gt;public class SaysomethingSoapBindingImpl implements SaySomething {&lt;br /&gt;&lt;br /&gt;public String sayHello(String name) throws RemoteException {&lt;br /&gt;return "hello " + name + " !";&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public String sayGoodbye() throws RemoteException {&lt;br /&gt;return "goodbye my master !";&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public String writeSomethingToDB(String id, String something)&lt;br /&gt;throws RemoteException {&lt;br /&gt;&lt;br /&gt;Something ft = new SomethingBase(id, something);&lt;br /&gt;QueryManager.saveTicketToDB(ft);&lt;br /&gt;&lt;br /&gt;return "Done. Persistance is cool. Bye.";&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Utilties methods&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Обаче тук има една важна особенност: пише се SaysomethingSoapBindingImpl, а не SaySomethingSoapBindingImpl. Гледаме картинката. От тези два класа искаме да получим всичко за "axis deployment"(server side). Тук е и тънката хватка. От тези два класа генерирам .wsdl файла после от него нещата които са ми необходими - SaysomethingSoapBindingSkeleton и server-config.wsdd. Вижте и ant scrip-a ми:&lt;br /&gt;&lt;pre&gt;&amp;lt;!-- ================================ --&amp;gt;&lt;br /&gt;&amp;lt;!--       Axis tools definiion       --&amp;gt;&lt;br /&gt;&amp;lt;!-- ================================ --&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;taskdef name="axis-java2wsdl" classname="org.apache.axis.tools.ant.wsdl.Java2WsdlAntTask"&amp;gt;&lt;br /&gt;&amp;lt;classpath refid="compile.classpath" /&amp;gt;&lt;br /&gt;&amp;lt;/taskdef&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;taskdef name="axis-wsdl2java" classname="org.apache.axis.tools.ant.wsdl.Wsdl2javaAntTask"&amp;gt;&lt;br /&gt;&amp;lt;classpath refid="compile.classpath" /&amp;gt;&lt;br /&gt;&amp;lt;/taskdef&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- ================================ --&amp;gt;&lt;br /&gt;&amp;lt;!--       Axis code generation       --&amp;gt;&lt;br /&gt;&amp;lt;!-- ================================ --&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;target name="export-wsdl" depends="prepare"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;axis-java2wsdl&lt;br /&gt;classname="com.zlatozar.soap.SaySomething" &lt;br /&gt;style="rpc"&lt;br /&gt;classpathref="compile.classpath"&lt;br /&gt;namespace="urn:soap.zlatozar.com" &lt;br /&gt;location="http://${server.name}:8080/${project.distname}/soap/${project.distname}" &lt;br /&gt;output="${basedir}\generated\${project.distname}.wsdl"&amp;gt;&lt;br /&gt;&amp;lt;/axis-java2wsdl &amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/target&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;target name="export-java" depends="export-wsdl"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;axis-wsdl2java &lt;br /&gt;output="${basedir}\generated" &lt;br /&gt;serverside="true" &lt;br /&gt;skeletondeploy="true" testcase="true"&lt;br /&gt;url="${basedir}\generated\${project.distname}.wsdl" &lt;br /&gt;verbose="true" &lt;br /&gt;debug="true"&amp;gt;&lt;br /&gt;&amp;lt;/axis-wsdl2java&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;java &lt;br /&gt;classname="org.apache.axis.utils.Admin" &lt;br /&gt;fork="true" &lt;br /&gt;failonerror="true" &lt;br /&gt;classpathref="compile.classpath"&lt;br /&gt;dir="${basedir}\WEB-INF\"&amp;gt;&lt;br /&gt;&amp;lt;arg value="server" /&amp;gt;&lt;br /&gt;&amp;lt;arg file="${basedir}\generated\com\zlatozar\soap\deploy.wsdd" /&amp;gt;&lt;br /&gt;&amp;lt;/java&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- copy the files we need to the src/com/zlatozar/soap dir --&amp;gt;&lt;br /&gt;&amp;lt;copy todir="src/com/zlatozar/soap" includeEmptyDirs="no"&amp;gt;&lt;br /&gt;&amp;lt;fileset dir="generated/com/zlatozar/soap"&amp;gt;&lt;br /&gt;&amp;lt;patternset&amp;gt;&lt;br /&gt;&amp;lt;include name="*SoapBindingSkeleton.java" /&amp;gt;&lt;br /&gt;&amp;lt;/patternset&amp;gt;&lt;br /&gt;&amp;lt;/fileset&amp;gt;&lt;br /&gt;&amp;lt;/copy&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- copy the wsdd to WEB-INF/server-config.wsdd --&amp;gt;&lt;br /&gt;&amp;lt;copy file="generated/com/zlatozar/soap/deploy.wsdd" &lt;br /&gt;tofile="WEB-INF/server-config.wsdd" /&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- copy generated WSDL file --&amp;gt;&lt;br /&gt;&amp;lt;copy file="generated/${project.distname}.wsdl" &lt;br /&gt;todir="." /&amp;gt;&lt;br /&gt;&amp;lt;/target&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Такааа, да поясним. Създавам директория generated, която след това мога да изтрия лесно. Генерирам wsdl файла и го използвам за генерацията на SaysomethingSoapBindingSkeleton. В soap пакета трябва да имам генериран SaysomethingSoapBindingSkeleton.java, а в WEB-INF server-config.wsdd. В писането на build.xml обърнете внимание на &lt;b&gt;namespace="urn:soap.zlatozar.com"&lt;/b&gt; - името на пакета ама в обратен ред и прехвърлянето на generated/com/zlatozar/soap/deploy.wsdd в WEB-INF/server-config.wsdd.&lt;br /&gt;До тук бяхме с Axis. Да се заемем с конфигурирането на Hibernate3.&lt;br /&gt;&lt;br /&gt;Само да кажа, че бях доста затруднен, не в самото конфигуриране а да измисля "доброто конфигуриране".&lt;br /&gt;Тъй като това беше първия ми сблъсък с Hibernate3 исках да намерея бърз начин да науча основните стъпки.&lt;br /&gt;&lt;br /&gt;От къде да прочета нещо?&lt;br /&gt;&lt;a href="http://www.gloegl.de/8.html"&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.xylax.net/hibernate/"&gt;Разберах как се "мапват" класове и таблици&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.onjava.com/lpt/a/4386"&gt;По advanced неща&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Как да генерирам java класовете от .hbm.xml файловете?&lt;br /&gt;За целта трябва да имам hibernate-tools.jar. Този jar е част от Hibernate-tools проекта и за да го имате трябва да свалите този&lt;br /&gt;проект, който не е никак малък като обем и от там да си гепите толкова полезния tool. При мен нещата стоят ето така:&lt;br /&gt;&lt;pre&gt;&amp;lt;!-- Hibernate code generation --&amp;gt;&lt;br /&gt;&amp;lt;target name="hibernategen" depends="init" description="Generate what hibernate needs"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;property name="libHibernatetool" value="lib/hibernatetool" /&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;path id="hibernateTool"&amp;gt;&lt;br /&gt;&amp;lt;pathelement location="${outputDir}" /&amp;gt;&lt;br /&gt;&amp;lt;fileset dir="${libHibernatetool}"&amp;gt;&lt;br /&gt;&amp;lt;include name="*.jar" /&amp;gt;&lt;br /&gt;&amp;lt;/fileset&amp;gt;&lt;br /&gt;&amp;lt;/path&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;taskdef name="hibernate-tool" classname="org.hibernate.tool.ant.HibernateToolTask" classpathref="hibernateTool" /&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;hibernate-tool&amp;gt;&lt;br /&gt;&amp;lt;configuration configurationfile="${conf}/hibernate.cfg.xml" /&amp;gt;&lt;br /&gt;&amp;lt;hbm2ddl export="true" drop="true" create="true" format="true" outputfilename="dbschema.sql" destdir="data" /&amp;gt;&lt;br /&gt;&amp;lt;hbm2java destdir="${sourceDir}" /&amp;gt;&lt;br /&gt;&amp;lt;/hibernate-tool&amp;gt;&lt;br /&gt;&amp;lt;/target&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;След като имам нужните .hbm.xml лесно мога да получа нужните ми класове и sql-a.&lt;br /&gt;&lt;br /&gt;Една добра идея е да отделя генерираните неща от нещата, които се променят. Какво имам в предвид. При генерацията се получават POJO обекти и нищо повече, а аз може да искам да добавя нещо повече в тези обекти, като utility методи. Как да отделя променящото се от непроменящото се? Вижте:&lt;br /&gt;&lt;pre&gt;&amp;lt;hibernate-mapping package="com.zlatozar.persistence.base"&amp;gt;&lt;br /&gt;&amp;lt;class name="SomethingBase" table="SAYSOMETHING_T"&amp;gt;&lt;br /&gt;&amp;lt;meta attribute="implement-equals"&amp;gt;true&amp;lt;/meta&amp;gt;&lt;br /&gt;&amp;lt;meta attribute="scope-field"&amp;gt;protected&amp;lt;/meta&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;id name="sys_oid" column="SYS_OID" type="long"&amp;gt;&lt;br /&gt;&amp;lt;generator class="increment" /&amp;gt;&lt;br /&gt;&amp;lt;/id&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;property name="id" type="string" column="ID_C"&amp;gt;&lt;br /&gt;&amp;lt;meta attribute="use-in-equals"&amp;gt;true&amp;lt;/meta&amp;gt;&lt;br /&gt;&amp;lt;/property&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;property name="something" type="string"&lt;br /&gt;column="SOMETHING_C"&amp;gt;&lt;br /&gt;&amp;lt;meta attribute="use-in-equals"&amp;gt;true&amp;lt;/meta&amp;gt;&lt;br /&gt;&amp;lt;/property&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/class&amp;gt;&lt;br /&gt;&amp;lt;/hibernate-mapping&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;И така имам си com.zlatozar.persistens.base за POJO обектите - hibernate да си генира там каквото иска. Аз си имам:&lt;br /&gt;&lt;pre&gt;public class Something extends SomthingBase&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;и си работя с него. А самото генериране не е сложно като видяхте. Почти свършихме само още няколко мисли за hibernate.&lt;br /&gt;Остана управлението на сесиите към базата. Аз имам един Singleton клас InitSessionFactory, който отваря и затваря сесията.&lt;br /&gt;&lt;pre&gt;public static SessionFactory getInstance() {&lt;br /&gt;if ( sessionFactory == null )&lt;br /&gt;initSessionFactory();&lt;br /&gt;&lt;br /&gt;return sessionFactory;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;a всички запитвания минават през QueryManager. Нещo такова:&lt;br /&gt;&lt;pre&gt;public static void saveSomthing(SomethingBase aSome) {&lt;br /&gt;&lt;br /&gt;Transaction tx = null;&lt;br /&gt;Session session = InitSessionFactory.getInstance().getCurrentSession();&lt;br /&gt;try {&lt;br /&gt;tx = session.beginTransaction();&lt;br /&gt;&lt;br /&gt;session.save(aSome);&lt;br /&gt;&lt;br /&gt;tx.commit();&lt;br /&gt;} catch (HibernateException e) {&lt;br /&gt;log.error("Opperation will be rolled back", e);&lt;br /&gt;&lt;br /&gt;if (tx != null &amp;amp;&amp;amp; tx.isActive())&lt;br /&gt;tx.rollback();&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Е това е за сега. Решил съм да споделям и програмиските си главоблъскници. Meчтая си скоро да напиша същото и на Lisp...&lt;br /&gt;.....&lt;br /&gt;Какво ли ще вечерям все пак?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14240039-115790896329916833?l=zlatozar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zlatozar.blogspot.com/feeds/115790896329916833/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14240039&amp;postID=115790896329916833' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/115790896329916833'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/115790896329916833'/><link rel='alternate' type='text/html' href='http://zlatozar.blogspot.com/2006/09/fashion-axis-hibernate.html' title='Fashion Axis-Hibernate'/><author><name>Zlatozar</name><uri>http://www.blogger.com/profile/16257250071061885492</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/17/6760/640/RabotnotoMqsto.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14240039.post-115616970647842952</id><published>2006-08-21T17:14:00.002+03:00</published><updated>2010-11-15T15:27:20.018+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='misc'/><title type='text'>Хапещите от "Форма Д"</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp;Не купувайте от "Форма Д"! Само това ще ви кажа. Сблъсках се с небивала простотия. Е, яд си ме е ама ще ви обясня за какво става въпрос та да се знае. Грешките на едни трябва да са поука за други.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Започваме с малко предистория. Дамата която държи веригата от магазини(два на брой) е от Първомай(както и аз). Казва се Даниела, откъдето идва и "Д"-то в името на фирмата. Асистира сестра й. Парите не трябва да излизат от семейството - това го приемам. Майка, баща и братовчеди са наредени по веригата. Лошото е, че манталитета и облика на магазините не е претърпял развие. Остават си една семейна бакалия с жените начело. Келепира, келепира е важен.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Тази събота отидох да си купя теракота от техния магазин на Карловско шосе в Пловдив. Леля Пенка-майката се изфука майсторски и даде отстъпка. Какво си купих? Да направим сметката.&lt;br /&gt;&lt;br /&gt;Fenix Crema - 18.10лв на квадрат&lt;br /&gt;Nature Beige - 18.10лв на квадрат&lt;br /&gt;&lt;br /&gt;Общо платих: 887лв. Цената, която платих не е достатъчна за да включва транспорт (е не можели да запалят буса за такова количество) затова добавям и 4 курса до Пловдив - 40лв. Стана 927лв. Щото имат и само един работник в склада аз и брат ми помагаме активно в товаренето, от един град сме няма начин. Сега правим и проверка в Интернет. Пускам в Google: Ceramic Floor tiles price. E, видяхте ли? Цените са около 4 евро да удвоим цената за доставката и получаваме 8 евро. Значи аз съм си платил и та предплатил. Макар че ми е дадена и отстъпка иначе са по 21.30лв. Нормално, плащам много очаквам и много. Келепир, келепир.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Добрите момченца отиват и да помагат. Товара започва...&lt;br /&gt;&lt;br /&gt;&lt;em&gt;"Аз на СОТ момче не вярвам, всички са маскари"&lt;/em&gt; - разсъждава чичо Наско - бащата. &lt;br /&gt;&lt;em&gt;"Я да си имам аз в склада и една каракачанка вързана на къс синджир. Ама лоша да трепе хора. Аз не си давам труда току така. Я да видим, кой ще краде хехехех".&lt;/em&gt; Да ама аз си плащам. Иначе магазина много излъскан и леля Пенка-майката много мазна. Парите бързо се вземат ама стоката се дава трудно.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Слизаме в склада. Плочките са почти насипни. Опаковани са по 10 с много тиксо. Твърди се, че са първо качество. Товарим ли товарим в тъмния склад, добре е да имаш познати навсякъде. Никой не знае че има изненада с бели зъби скрита в ъгъла.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Синджира се и къса, оковите падат звяра изскача. Кучето напада в гръб брат ми. Работника хвърля всичко и се качва на високо. Настава паника. Брат ми е жестоко нахапан. Подло и неочаквано, типично за фирма "Форма Д". Имаше страх и кръв. По братски винаги сме си помагали. В един момент взехме надмощие и погнахме кучето. Искахме то да умре. Ние не сме братя варвари, ние не обичаме нападения в гръб.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Чичо Наско, чичо Наско той пари е дал и го хранил с хляб 6 месеца.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;em&gt;"Въх убихте ми кучето бе, серсеми!"&lt;/em&gt; - крещи и тича към нас видимо вдигнал кръвното. Айде спаси кучето и си спести шамара, който му бях нарекъл - мир да има. Ама как исках да умре(кучето)!&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Искам да ви кажа нещо семейна фирма "Форма Д". Вие сте лъскави и кухи! Спрете с келепира и се докажете с честност и обноски. Вие сте търговци не си мислете, че хора като мен и брат ми ви крадат. Спрете да се подмазвате това не ви прави по-добри търговци. Палете буса и угаждайте на клиентите. Не лъжете. Назначете способни хора, а не комшията от Първомай. И не на последно място хранете кучетата си с кучешка храна, а не с хляб и помия.&lt;br /&gt;&lt;br /&gt;Внимание в София кучетата са две!&lt;br /&gt;&lt;br /&gt;Сбогом вие не съществувате за мен.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14240039-115616970647842952?l=zlatozar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zlatozar.blogspot.com/feeds/115616970647842952/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14240039&amp;postID=115616970647842952' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/115616970647842952'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/115616970647842952'/><link rel='alternate' type='text/html' href='http://zlatozar.blogspot.com/2006/08/blog-post.html' title='Хапещите от &quot;Форма Д&quot;'/><author><name>Zlatozar</name><uri>http://www.blogger.com/profile/16257250071061885492</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/17/6760/640/RabotnotoMqsto.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14240039.post-115161261269783735</id><published>2006-06-29T22:42:00.001+03:00</published><updated>2011-03-02T17:16:05.113+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='source control'/><title type='text'>The force of Perforce</title><content type='html'>&lt;h3&gt;INTRO: Kick start&lt;/h3&gt;&lt;br /&gt;&lt;strong&gt;I'm a new colleague and I do not know how to start with Perforce. Can you explain me just the basics steps?&lt;/strong&gt;&lt;br /&gt;* Install Perforce&lt;br /&gt;* Second you have to setup your client. Client in Perforce world is your workstatation, your workspase. &lt;br /&gt;--- Open P4V this is a GUI for Perforce. Then &lt;em&gt;Connections -&amp;gt; Open New Connection&lt;/em&gt; &lt;br /&gt;Now you have to fill fields. Here is some terms:&lt;br /&gt;&lt;pre&gt;Client:&lt;/pre&gt;The client name. The name of your workspace.&lt;br /&gt;&lt;pre&gt;Owner:&lt;/pre&gt;The user who created this client.&lt;br /&gt;&lt;pre&gt;Root:&lt;/pre&gt;The root directory of the client file workspace, under which all client files will be placed. Here is mine: &lt;br /&gt;&lt;pre&gt;C:\src\mainline&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;Options:&lt;/pre&gt;Just use default...&lt;br /&gt;&lt;pre&gt;View:&lt;/pre&gt;&lt;br /&gt;A mapping from the files in the depot to files in the client workspace.&lt;br /&gt;A new view takes effect on the next &lt;em&gt;'p4 sync'&lt;/em&gt;.&lt;br /&gt;See view(mapping) example:&lt;br /&gt;&lt;pre&gt;//depot/mainline/... //ZLATOZAR/...&lt;/pre&gt;&lt;br /&gt;So &lt;em&gt;//depot/mainline/...&lt;/em&gt; will be mapped to my root. &lt;br /&gt;--- Get things from depot. Depot is the repository. Type in workspace(root) command prompt:&lt;br /&gt;&lt;pre&gt;p4 sync&lt;/pre&gt;&lt;br /&gt;* Before you start change file you have to declare that you want to edit it. Weird indeed but don't forget it. &lt;br /&gt;All other knows that you are going to change this file. Your file is in changelist. &lt;br /&gt;&lt;pre&gt;p4 edit //depot/mainline/Project1/MyFile.cs&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;* When you finish submit your changelist &lt;br /&gt;&lt;pre&gt;p4 submit&lt;/pre&gt;&lt;br /&gt;or file by file&lt;br /&gt;&lt;pre&gt;p4 submit TelephoneComponentHandler.cs&lt;/pre&gt;&lt;br /&gt;That is. Now more details.&lt;br /&gt;&lt;h3&gt;PART ONE: The depot&lt;/h3&gt;&lt;br /&gt;1. Filespec Syntax &lt;br /&gt;Perforce provides its own uniform syntax for referring to workspace and depot contents. This syntax is known as a file specifier, or "filespec." &lt;br /&gt;Its converts filespecs to native file references for local operations. Depots, where Perforce keeps master file content, and workspaces, where users work on files, are hierarchical structures of directories and files.  &lt;br /&gt;&lt;br /&gt;A filespec uses "//" to indicate the root of the hierarchy, and "/" as a directory path and file name separator. &lt;br /&gt;For example: &lt;br /&gt;&lt;pre&gt;//depot/mainline/Project1/MyNewFile.cs&lt;/pre&gt;&lt;br /&gt;IMPORTANT ! &lt;br /&gt;File names are case insensitive or case sensitive it depends from instalation. &lt;br /&gt;Just check it and remeber.&lt;br /&gt;&lt;pre&gt;//depot/mainline/project1/mynewfile.cs&lt;/pre&gt;is the same? And also spaces in filenames and pathnames have to be quoted when they are referenced in views &lt;br /&gt;-- It is possible to use wild cards &lt;br /&gt;&lt;pre&gt;//depot/mainline/Project*/ComponentHandler.cs&lt;/pre&gt;&lt;br /&gt;--- Use "dot-dot-dot" &lt;br /&gt;The "..." wildcard matches filename characters at or below a directory level. &lt;br /&gt;&lt;pre&gt;//depot/.../SomeInnerProject/...&lt;/pre&gt;&lt;br /&gt;2. File and directory revisions &lt;br /&gt;IMPORTANT ! &lt;br /&gt;Perforce's filespecs always refer to files, not directories. In fact there are no Perforce commands that operate on directories. &lt;br /&gt;Use wild cards to refer directories. &lt;br /&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;/em&gt;&lt;br /&gt;I will describe a lot of commands, but for more information use command prompt help. Just type: &lt;br /&gt;&lt;pre&gt;p4 help&lt;/pre&gt;&lt;br /&gt;then&lt;br /&gt;&lt;pre&gt;p4 help [some of subjects]&lt;br /&gt;p4 help [command that you are interested]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Perforce stores file versions in a sequence of numbered revisions. A filespec can refer to an absolute, numbered file revision, prefixed with &lt;code&gt;#&lt;/code&gt;. &lt;br /&gt;Filespecs can also refer to dates and labels, prefixed with @. And also label can be used to refer to file revisions to which it has been applied. &lt;br /&gt;Examples: &lt;br /&gt;--- displays all files in Project1 &lt;br /&gt;&lt;pre&gt;p4 files //depot/mainline/Project1/*&lt;br /&gt;............&lt;br /&gt;//depot/mainline/Project1/MyFile.cs#15 - edit change 5401 (text)&lt;br /&gt;............&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;--- display revisions of files for a specific version &lt;br /&gt;&lt;pre&gt;p4 files //depot/mainline/Project1/*#15&lt;/pre&gt;&lt;br /&gt;--- display files using date and first letter of the file name &lt;br /&gt;&lt;pre&gt;p4 files //depot/mainline/Project1/M*@5/16/2006&lt;/pre&gt;&lt;br /&gt;3. Changes and changelists &lt;br /&gt;Perforce uses changelists to track changes submitted to the depot. Every changelist commit number is a snapshot of the depot (It is similar to tags in CVS). Versioning numbers are global &lt;br /&gt;See my ASCII graphic: &lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Date:           05/05/2006  07/05/2006      23/05/2006&lt;br /&gt;|          |               |&lt;br /&gt;|    |        |            |    |&lt;br /&gt;file1 -----------| #1 |--------|------------| #2 |------&lt;br /&gt;|    |        |            |    |&lt;br /&gt;|          |               |&lt;br /&gt;|        |    |            |&lt;br /&gt;file2 -----------------------| #1 |----------------------&lt;br /&gt;|        |    |            |         &lt;br /&gt;|          |               |&lt;br /&gt;|    |        |               |&lt;br /&gt;file3 -----------| #1 |---------------------------------&lt;br /&gt;|    |        |               |&lt;br /&gt;|          |               |&lt;br /&gt;Changelist trak:   @102       @109             @114&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;4. Browsing the file tree &lt;br /&gt;See examples: &lt;br /&gt;--- to list all depots &lt;br /&gt;&lt;pre&gt;p4 depots&lt;/pre&gt;&lt;br /&gt;(or &lt;code&gt;p4 dirs "//*"&lt;/code&gt;) &lt;br /&gt;--- to list all dirs and subdirs &lt;br /&gt;&lt;pre&gt;p4 dirs "//depot/*"&lt;/pre&gt;&lt;br /&gt;--- see file changes history &lt;br /&gt;&lt;pre&gt;p4 changes -m5 //depot/mainline/Project1/TheFile.cs&lt;/pre&gt;&lt;br /&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;/em&gt;: The &lt;code&gt;-m5&lt;/code&gt; flag restricts the output to the five most recent changes. Each change is identified with a changelist number and the first 30-odd characters of a description. If you want to see entire descriptions, use changes &lt;code&gt;-l&lt;/code&gt;. &lt;br /&gt;--- what is on the default change list when I commit my files &lt;br /&gt;&lt;pre&gt;p4 describe -s 5401&lt;/pre&gt;&lt;br /&gt;--- shows file revision numbers and the action (add, delete, etc.) that took place at each revision &lt;br /&gt;&lt;pre&gt;p4 filelog //depot/mainline/Project1/TheHandler.cs&lt;/pre&gt;&lt;br /&gt;--- to see all changes and changelist &lt;br /&gt;&lt;pre&gt;p4 annotate -c //depot/mainline/Project1/TheHandler.cs | more&lt;/pre&gt;&lt;br /&gt;(P4V's &lt;em&gt;Time-lapse View&lt;/em&gt; is generated from the output of the annotate command.) &lt;br /&gt;--- if you want to take a file(some revision) and pass it to another file &lt;br /&gt;&lt;pre&gt;p4 print -q //depot/mainline/Project1/TheHandler.cs &amp;gt; newTCH.txt&lt;/pre&gt;&lt;br /&gt;--- compare revisions &lt;br /&gt;&lt;pre&gt;p4 diff2 //depot/mainline/Project1/TheHandler.cs#14&lt;br /&gt;//depot/mainline/IProject1/TheHandler.cs#15 | more&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;(&lt;code&gt;p4 diff [old revision] [new revision]&lt;/code&gt;) &lt;br /&gt;In P4V the &lt;em&gt;Tools -&amp;gt; Diff&lt;/em&gt; files command can be used to diff any two files or revisions. It shows only different lines! Eclipse diff wins... &lt;br /&gt;The same command can be used to compare any two revisions of a directory. That is realy impressive. Keep in mind that Perforce can compare and merge onky text files. &lt;br /&gt;--- discover file types &lt;br /&gt;See: &lt;pre&gt;p4 help filetypes&lt;/pre&gt;&lt;br /&gt;+x &lt;br /&gt;The workspace file is executable. &lt;br /&gt;+w &lt;br /&gt;The file is writable as soon as it's copied to the workspace. (Normally you have to open files to make them writable.) &lt;br /&gt;+k &lt;br /&gt;RCS-like keywords in the file are expanded when the file is copied to the workspace. &lt;br /&gt;+l &lt;br /&gt;The file is exclusively locked when opened so that only one person can have it open at a time. &lt;br /&gt;+m &lt;br /&gt;The file's modification time is propagated with the file so that it shows up in the timestamp of synchronized copies. &lt;br /&gt;+S &lt;br /&gt;Only one revision (the head revision) of the file is stored in the depot. &lt;br /&gt;(This is useful for files generated and submitted by nightly builds, for example.) &lt;br /&gt;&lt;br /&gt;Commbinations are also posible:   &lt;pre&gt;binary+lw&lt;/pre&gt;etc. &lt;br /&gt;&lt;br /&gt;&lt;h3&gt;PART TWO: Files, workspace and change list&lt;/h3&gt;&lt;br /&gt;1. Creating workspace. Working with local files &lt;br /&gt;The first thing you do before you can work on files is define a client workspace for yourself. A client workspace specification, or client spec, tells Perforce where in your local filesystem you want your workspace to be rooted. It has a view that defines the areas of the depot you want access to, and maps them to directories beneath the workspace root. &lt;br /&gt;--- set up new  &lt;br /&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;/em&gt;: If &lt;strong&gt;P4CLIENT&lt;/strong&gt; is not set, the name of your host machine will be used as the current workspace name. &lt;br /&gt;&lt;br /&gt;For example, say you want to configure a workspace named Zlatozar-BG. First, you open up a client form in default editor: &lt;br /&gt;&lt;pre&gt;p4 client Zlatozar-BG&lt;/pre&gt;&lt;br /&gt;An easy way: In P4V with the &lt;em&gt;Connection  -&amp;gt; Open Connection&lt;/em&gt;. Fill fields. &lt;br /&gt;--- synchronyze workspace. Current dir. &lt;br /&gt;&lt;pre&gt;p4 sync&lt;/pre&gt;&lt;br /&gt;--- get only one part &lt;br /&gt;&lt;pre&gt;p4 sync //depot/mainline/Project1/&lt;/pre&gt;&lt;br /&gt;--- view all changes that are made after my commit &lt;br /&gt;&lt;pre&gt;p4 changes "@&amp;gt;5401"&lt;/pre&gt;&lt;br /&gt;&lt;strong&gt;How to rewrite all my current changes?&lt;/strong&gt; &lt;br /&gt;* Check all files that you have changed &lt;br /&gt;&lt;pre&gt;p4 diff -sa&lt;/pre&gt;&lt;br /&gt;* Reverting files is how you discard changes you've made to local files, rather than submitting them &lt;br /&gt;&lt;pre&gt;p4 revert //depot/[path to the file]&lt;/pre&gt;&lt;br /&gt;&lt;strong&gt;How to restore localy removed files?&lt;/strong&gt; &lt;br /&gt;* Find them &lt;br /&gt;&lt;pre&gt;p4 diff -sd&lt;/pre&gt;&lt;br /&gt;* List the files Perforce thinks you have with the have command &lt;br /&gt;&lt;pre&gt;p4 have //.../Project1/...&lt;/pre&gt;&lt;br /&gt;* Restore(force) them &lt;br /&gt;&lt;pre&gt;p4 sync -f //.../Project1/...&lt;/pre&gt;&lt;br /&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;/em&gt;: Workspace files are under your control and there's nothing to stop you or the programs you run from erasing files Perforce put there. But because Perforce thinks you have them already, you won't be able to replace them with a simple sync. So force it. &lt;br /&gt;2. Working with local files &lt;br /&gt;When you synchronize your workspace with depot files, Perforce normally puts read-only files on your local disk. To make files writable, you have to open them. You also have to open files you plan to add to or delete from the depot.Remember, in Perforce, an "open file" is a file you plan to submit to the depot. Don't confuse Perforce's meaning of "open" with the idea of opening files in an application. &lt;br /&gt;--- open for edit &lt;br /&gt;&lt;pre&gt;p4 edit //depot/mainline/Project1/TheHandler.cs&lt;/pre&gt;&lt;br /&gt;Now file is writable and in changelist. Team knows that you are working on that file if they type: &lt;br /&gt;&lt;pre&gt;p4 opened -a //.../Project1/...&lt;/pre&gt;&lt;br /&gt;&lt;strong&gt;How many programers can work(open) on the same file?&lt;/strong&gt; &lt;br /&gt;All programers but first commiter wins. Rest of them have to resolve possible conflicts. &lt;br /&gt;When you open file Perforce worns you thst another programmer works on it. Somthing like: &lt;br /&gt;&lt;pre&gt;... - also opened by gosho@...&lt;/pre&gt;&lt;br /&gt;(Read more about &lt;code&gt;p4 resolve&lt;/code&gt;....it is not so easy.) &lt;br /&gt;--- add files to depot &lt;br /&gt;There is no need to open file to add it. You can open files only if they're in your workspace view. &lt;br /&gt;&lt;pre&gt;p4 add //.../Project1/SofiaHandler.cs&lt;br /&gt;p4 submit&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;--- delete files from depot &lt;br /&gt;&lt;pre&gt;p4 delete //.../Project1/StrangeHandler.cs&lt;br /&gt;p4 submit&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;As you open files, they are associated with a pending changelist. Your local changes don't affect the depot until you submit your files. What you submit to the depot is not individual files, really, but the entire pending changelist. &lt;br /&gt;IMOPRTANT ! &lt;br /&gt;Remove all uchenged files first or commit files one by one &lt;br /&gt;&lt;pre&gt;p4 revert -a&lt;br /&gt;p4 submit&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This is a weak point realy... be careful. It is posible to commit unchanged files. Realy realy weak point. Sorry. You can use this script:&lt;br /&gt;&lt;pre&gt;# throw away (opened but) unchanged files&lt;br /&gt;# (in Perforce it's a little bit too easy&lt;br /&gt;# to checkin unchanged files)&lt;br /&gt;&lt;br /&gt;p4 diff -sr | p4 -x - revert&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;strong&gt;Hi. I'm very creative programmer and I work on many differen tasks. How can I separate my works?&lt;/strong&gt; &lt;br /&gt;* The answear is - create different changelist for diffrent tasks an gave them proper names. &lt;br /&gt;&lt;pre&gt;p4 change&lt;/pre&gt;&lt;br /&gt;This command brings up a spec form, just like submit. The form will list all the files opened in your default changelist. Simply fill in a description and save the form to move files to the new changelist. &lt;br /&gt;* Open for edit in the right changelist &lt;br /&gt;&lt;pre&gt;p4 edit -c dt-456&lt;/pre&gt;&lt;br /&gt;* Submit right changelist (eg. "dt-456") &lt;br /&gt;&lt;pre&gt;p4 submit -c dt-456&lt;/pre&gt;&lt;br /&gt;* Empty pending changelists can be deleted &lt;br /&gt;&lt;pre&gt;p4 change -d dt-456&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;PART THREE: Misc&lt;/h3&gt;&lt;br /&gt;1. Snapshots &lt;br /&gt;Every time a user submits files to Perforce, a snapshot of the depot is created automatically. The changelist number created at submit time is effectively a global revision number. It can be use to reference any file or set of files in the depot snapshot. Don't forget that. &lt;br /&gt;For example when submit change list: &lt;br /&gt;&lt;pre&gt;p4 submit&lt;br /&gt;..........&lt;br /&gt;Change 5401 submitted.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;As you see the submit number is global. So you can refer it. If you want to take spesific change list (actually this is a snapshot): &lt;br /&gt;&lt;pre&gt;p4 sync //depot/mainline/...@5401&lt;/pre&gt;&lt;br /&gt;or  &lt;br /&gt;&lt;pre&gt;p4 diff2 -q //depot/mainline/...@5400 //depot/mainline/...@5401&lt;/pre&gt;&lt;br /&gt;(and I found out all my changes) &lt;br /&gt;or just  use P4V's &lt;em&gt;Folder Diff&lt;/em&gt; tool to compare snapshots... &lt;br /&gt;2. Labels &lt;br /&gt;In Perforce, as in many SCM systems, you can tag files with a label. To give names to snapshots. A label lets you use memorable names like REL2.0.1 to refer to specific configurations of file revisions. &lt;br /&gt;--- see all labels maded from karl &lt;br /&gt;&lt;pre&gt;p4 labels |grep alex&lt;/pre&gt;&lt;br /&gt;--- applying a label to files &lt;br /&gt;&lt;pre&gt;p4 tag -l rel-2.0.1 //depot/mainline/...&lt;/pre&gt;&lt;br /&gt;--- referring label &lt;br /&gt;&lt;pre&gt;p4 sync @rel-2.0.1&lt;/pre&gt;&lt;br /&gt;--- all files in label &lt;br /&gt;&lt;pre&gt;p4 files @rel-2.0.1&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;3. Jobs &lt;br /&gt;A job is an object in the Perforce database that can be used to tie development activity to external information. Jobs can be used for anything—requirements, project plans, to-do lists — but their most common use is for defect tracking. &lt;br /&gt;&lt;h3&gt;PART FOUR: Resolving and merging (advanced level)&lt;/h3&gt;&lt;br /&gt;&lt;h3&gt;PART FIVE: Branching and merging (black belts)&lt;/h3&gt;&lt;br /&gt;To be continued...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14240039-115161261269783735?l=zlatozar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zlatozar.blogspot.com/feeds/115161261269783735/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14240039&amp;postID=115161261269783735' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/115161261269783735'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/115161261269783735'/><link rel='alternate' type='text/html' href='http://zlatozar.blogspot.com/2006/06/force-of-perforce.html' title='The force of Perforce'/><author><name>Zlatozar</name><uri>http://www.blogger.com/profile/16257250071061885492</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/17/6760/640/RabotnotoMqsto.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14240039.post-114702821565641724</id><published>2006-05-07T21:54:00.001+03:00</published><updated>2010-11-15T15:27:35.120+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='misc'/><title type='text'>Исландия моя любов</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/5870/1282/1600/DSC02810.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://photos1.blogger.com/blogger/5870/1282/320/DSC02810.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Струва си да се разгледа тази страна. Ето и още снимки &lt;a href="http://picasaweb.google.com/zlatozar/Iceland"&gt;тук&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14240039-114702821565641724?l=zlatozar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zlatozar.blogspot.com/feeds/114702821565641724/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14240039&amp;postID=114702821565641724' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/114702821565641724'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/114702821565641724'/><link rel='alternate' type='text/html' href='http://zlatozar.blogspot.com/2006/05/blog-post.html' title='Исландия моя любов'/><author><name>Zlatozar</name><uri>http://www.blogger.com/profile/16257250071061885492</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/17/6760/640/RabotnotoMqsto.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14240039.post-114399174054883820</id><published>2006-04-02T18:27:00.000+03:00</published><updated>2007-10-14T15:15:47.450+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>How to solve it?</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(by G. Polya)&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Getting Acquainted&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Where should I start?&lt;/span&gt; Start from the statement of the problem.&lt;br&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;What can I do?&lt;/span&gt; Visualize the problem as a whole as clear and as vividly as you can. Do not concern yourself with details for the moment. &lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;What can I gain by doing so?&lt;/span&gt; You should understand the problem, familiarize yourself with it, impress its purpose on your mind. The attention bestowed on the problem may also stimulate your memory and prepare for the recollection of relevent points.&lt;br /&gt;&lt;br&gt;&lt;br&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Working for Better Understanding&lt;/span&gt;&lt;br /&gt;(Questions are: What is the unknown? What are the data? What is the condition?)&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Where should I start?&lt;/span&gt; Start again from the statement of the problem. Start when this statement is so clear to you and so well impressed on your mind that you may lose sight of it for a while without fear of losing it altogether.&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;What can I do?&lt;/span&gt; Isolete principal parts of your problem. The hypothesis and the conclusion are the principal parts of a "problem to prove"; the unknown, the data, and the conditions are the principal parts of a "problem to find." Go through the principal parts of your problem, consider them one by one, consider them in turn, consider them in various combinations, relating eache detail to other details and each to the whole of the problem.&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;What can gain by doing so?&lt;/span&gt; You should prepare and clarify details which are likely to play role afterwards.&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Drow a figure. Introduce suitable notation. Separate the parts of the condition. Can you write them down?&lt;/span&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Hunting for the Helpful Idea&lt;/span&gt;&lt;br /&gt;(Questions are: Have you seen it before? Do you know a related problem? Here is a problem related to yours and solved before. Could you use it?)&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Where should I start?&lt;/span&gt; Start from the consideration of the principals parts of your problem. Start when these principal parts are distinctly arranged and clearly conceived, thanks to your previous work, and when your memory seems responsive.&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;What can I do?&lt;/span&gt; Concider your problem from various sides and seek contacts with your formery acqired knowledge.&lt;br /&gt;Consider your problem from various sides. Emphasize different different parts, examine different details, examine the same details repeatedly but in different ways, combine the details differently, approach them from different sides. Try to see some new meaning in each detail, some new interpretation of the whole.&lt;br /&gt;Seek contacts with your formery acquired knowledge. Try to think of what helped you in similar situations in the past. Try to recognize something familiar in what you examine, try to perceive somthing useful in what you recognize.&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;What could I perceive?&lt;/span&gt; A helpful idea, perhaps a decisive idea that shows you at a glance the way to the vary end.&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;How can the idea could be helpful?&lt;/span&gt; It shows you the whole of the way or a part of the way; it suggest to you more or less distinctly how can proceed. Ideas are more or less distinctly how you can proceed. Ideas are more or less complete. You are lucky if you have any idea at all.&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;What can I do with an incomplete idea?&lt;/span&gt; You sould consider it. If it looks advantageous you sould concider it longer. If it looks reliable you should ascertain how far it leads you, and reconsinder the situation. The situation has changed, thanks to your helpful idea. Consider the new situation from various sides and seek contacts with your formery acquired knowledge.&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;What can I gain by doing so again?&lt;/span&gt; You may be lucky and have anoder idea. Perhaps your next idea will lead you to the solution right away. Perhaps you need a few more helpful ideas after the next. Perheps you will be more led astray by some of yours ideas. Neverthe less you should be grateful for all new ideas, also for the lesser ones, also for the hazy ones, also for the supplementary ideas adding some precision to a hazy one, or attempting the correction of a less fortunate one. Even if you do not have any appreciable new ideas for a while you should be grateful if your conception of the problem becomes more complete or more coherent, more homogeneous or better balanced.&lt;br /&gt;&lt;br&gt;&lt;br&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Carrying Out the Plan&lt;/span&gt;&lt;br /&gt;(Questions are: Carrying out your plan of the solution, check each step. Can you see clearly that the step is correct? Can you prove thet it is correct?)&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Where should I start?&lt;/span&gt; Start from lucky idea that led you to the solution. Start when you feel sure of your grasp of the main connection and you feel confident that you can supplay the minor details that may be wanting.&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;What can I do?&lt;/em&gt; Make your grasp quite secure. Carry through in detail all the algebriac or geometric operations which you have recognized previously as feasible. Convince yourself of thr correctnrss of each step by formal reasoning, or by intuitive insight, or both ways if you can. If your problem is very complex you may distinguish "great" steps and "small" steps, each great step being composed of several small ones. Check first the great steps, and get down to the smaller ones afterwards.&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;What can I gain by doing so?&lt;/em&gt; A presentation of the solution each step of which is correct beyond doubt.&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Where should I start?&lt;/em&gt; From the solution, complete and correct in each detail.&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;What can I do?&lt;/em&gt; Consider the solution from various sides and seek contacts with your forery acquired knowlidge.&lt;br /&gt;Consider the details of the solution and try to make them as simple as you can; survey more extensive parts of the solution and try to make them shorter; try to see the whole solution at a glance. Try to modify to their advantage smaller or larger parts of the solution, try to improve the whole solution, to make it intuitive, to fit it into formery acquired knowledge as naturally as possible. Scrutinize  the method that led you to the solution, try to see its points, and try to make use of it for other problems. Scrutinize the result and try to make use of it for other problems.&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;What can I gain by doing so?&lt;/em&gt; You may find a new and better solution, you may discover new and interesting facts. In any case, if you get into the habit of sureveying and scrutinizing your solutions in this way, you will acquire some knowledge well orderedand ready to use, and you will develop your ability of solving problems.&lt;br /&gt;&lt;br /&gt;Nice illustration could be found &lt;a href="http://www.idiagram.com/CP/cpprocess.html"&gt;here&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Next step is, How to work?&lt;/span&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;These days our lives are busier than ever. We work more than ever. We are more stressed and exhausted than ever before. And yet we get less done and are not as happy.&lt;br /&gt;&lt;br /&gt;It doesn’t have to be that way.&lt;br /&gt;&lt;br /&gt;The problem is that we are overloaded with information and tasks, and we try to get everything done instead of just the most essential things. Solution: focus on only the essential, eliminate the rest, and allow yourself to get into that beautiful state known as “flow”.&lt;br /&gt;&lt;br /&gt;And although it can be hard to give up all the busy-ness that we’ve grown accustomed to, the change will have tremendous benefits on our sanity, our stress levels, our happiness, and yes, our productivity.&lt;br /&gt;&lt;br /&gt;Here are 10 simple ways to be more productive with less effort:&lt;br /&gt;&lt;br /&gt;   &lt;b&gt;1.&lt;/b&gt; &lt;em&gt;Clear your head.&lt;/em&gt; It’s impossible to gain perspective, and to know what is truly essential, if we are in the middle of an information stream. Take an hour, or half a day if possible, to shut off the information flow, and to get a larger view of your life and your job. The time you take off will be well worth it. Tell everyone that you are unavailable, shut off all communications, shut yourself in somewhere private, and take some time to think about what is important. What do you want? Where are you going? What will it take to get there? Another good way to clear your head, which is necessary for focus, is to write down everything that you need to do, all your tasks and projects and ideas. Dump the contents of your mind on paper, and then stop thinking about them for a little while.&lt;br /&gt;&lt;br /&gt;   &lt;b&gt;2.&lt;/b&gt; &lt;em&gt;Focus on the essential tasks.&lt;/em&gt; Once you’ve gotten your head cleared, you need to figure out what tasks are most essential. Ask yourself this magic question: “What task can you do that will get you the most return on your time?” Figure out the project that will get you the most recognition, win you awards, or get you the most business. Something that will pay off big. Not something you’ll forget about in a week, but something that others will remember you by. This is an essential task. Make a list of these types of tasks — they’re your most important things to do this week.&lt;br /&gt;&lt;br /&gt;   &lt;b&gt;3.&lt;/b&gt; &lt;em&gt;Eliminate the rest.&lt;/em&gt; Now look at your overall list. What’s on there that’s not essential? Can you just drop them from your schedule? Or delegate them to someone else? If not, put them on a “waiting list”. Then, as you focus on your essential tasks, check back on this waiting list every now and then. Sometimes you’ll realize that the less essential tasks weren’t really necessary at all.&lt;br /&gt;&lt;br /&gt;   &lt;b&gt;4.&lt;/b&gt; &lt;em&gt;Do essential tasks first.&lt;/em&gt; If you’ve got a list of things to do today, and one or two of them are truly essential, do those items first thing in the morning. Don’t wait until later in the day, because they’ll get pushed back as other urgent stuff comes up. Get them out of the way, and your productivity will truly soar.&lt;br /&gt;&lt;br /&gt;   &lt;b&gt;5.&lt;/b&gt; &lt;em&gt;Eliminate distractions.&lt;/em&gt; You can put essential stuff on your list all year long, but if you are constantly interrupted by email notifications, IM, cell phones, your RSS reader, gadgets and widgets, social media, forums and the like, you’ll never be productive. Turn these things off, disconnect yourself from the Internet if possible, clear your desk of all papers, clear your walls and surrounding areas, and allow yourself to truly focus.&lt;br /&gt;&lt;br /&gt;   &lt;b&gt;6.&lt;/b&gt; &lt;em&gt;Use simple tools.&lt;/em&gt; Don’t fidget with a bunch of gadgets or the latest and coolest applications. Find a simple notebook for writing things down, a simple to-do list (no frills) and the simplest application possible for doing your work. Then forget about the tools and think only of the task at hand. If you’re too worried about the tools, you’re not actually doing anything.&lt;br /&gt;&lt;br /&gt;   &lt;b&gt;7.&lt;/b&gt; &lt;em&gt;Do one thing at a time.&lt;/em&gt; Multi-tasking is a waste of time. You can’t get things done with a million things going on at once, pulling for your attention. Focus on the essential task in front of you, to the exclusion of all else, and you are much more likely to get it completed, in less time, with less effort.&lt;br /&gt;&lt;br /&gt;   &lt;b&gt;8.&lt;/b&gt; &lt;em&gt;Find quiet.&lt;/em&gt; In addition to a quiet working environment, you need time every day that you can call your own, where you don’t have to do work. This could be through reading, taking a bath, walking in nature, going swimming at the beach, going jogging, meditating. Not reading your feeds. Get away from the information overload and find that peace that will allow you to truly focus when you do work, and to review your day in your mind, and to get the perspective to see what is essential.&lt;br /&gt;&lt;br /&gt;   &lt;b&gt;9.&lt;/b&gt; &lt;em&gt;Make the most of your work.&lt;/em&gt; It’s one thing to write something great, or to create something fantastic. But it’s entirely another thing to make that great thing explode, to get you attention, to earn the recognition you deserve — which will lead to more business or more opportunities. Once you’ve created the Next Great Thing, promote it, show it to others, find a way to have it carry you as far as it can take you. Don’t just create something and move on to the next thing. Use your energy and talents to their fullest extent.&lt;br /&gt;&lt;br /&gt;  &lt;b&gt;10.&lt;/b&gt; &lt;em&gt;Simplify some more.&lt;/em&gt; Once you’ve simplified down to the essential, and eliminated distractions, you should become productive. But distractions and the unnecessary have a way of creeping back in and accumulating. Every now and then, take a look at what you’re doing, at the information coming into your life, at how you spend your time and the tools you use. Then simplify some more.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14240039-114399174054883820?l=zlatozar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zlatozar.blogspot.com/feeds/114399174054883820/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14240039&amp;postID=114399174054883820' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/114399174054883820'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/114399174054883820'/><link rel='alternate' type='text/html' href='http://zlatozar.blogspot.com/2006/04/how-to-solve-it.html' title='How to solve it?'/><author><name>Zlatozar</name><uri>http://www.blogger.com/profile/16257250071061885492</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/17/6760/640/RabotnotoMqsto.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14240039.post-114251887869296761</id><published>2006-03-16T16:15:00.000+02:00</published><updated>2006-03-22T14:03:00.616+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='freebsd'/><title type='text'>Polished FreeBSD box</title><content type='html'>И сега, когато си имаме &lt;a href="http://zlatozar.blogspot.com/2005_08_10_zlatozar_archive.html"&gt;Super FreeBSD Box&lt;/a&gt; е време за някой хватки, които ще ни помогнат в нашето ежедневие.&lt;br /&gt;&lt;br&gt;&lt;br&gt;&lt;br /&gt;&lt;strong&gt;1. &lt;/strong&gt;Клавиатурната подредба, малко е кофти. Insert, Home, End... не работят. So what?&lt;br&gt;&lt;br /&gt;Сложете в .inputrc.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;set meta-flag on&lt;br /&gt;set output-meta on&lt;br /&gt;set convert-meta off&lt;br /&gt;&lt;br /&gt;"\e[1~": beginning-of-line&lt;br /&gt;"\e[2~": yank&lt;br /&gt;"\e[3~": delete-char&lt;br /&gt;"\e[4~": end-of-line&lt;br /&gt;"\e[C": forward-char&lt;br /&gt;"\e[D": backward-char&lt;br /&gt;"\e[A": previous-history&lt;br /&gt;"\e[B": next-history&lt;br /&gt;"\C-?": delete-char&lt;br /&gt;"\C-H": backward-delete-char&lt;br /&gt;"\e[1~": beginning-of-line&lt;br /&gt;"\e[4~": end-of-line&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;strong&gt;2. &lt;/strong&gt;Искате ви се да имате готин emacs:&lt;br&gt;&lt;br /&gt;Сложете в .emacs:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;;; Syntax highlight&lt;br /&gt;(global-font-lock-mode t)&lt;br /&gt;&lt;br /&gt;;; Higlight the marked region (C-SPC)&lt;br /&gt;(transient-mark-mode t)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;;; Some useful key bindings&lt;br /&gt;(global-set-key [home] 'beginning-of-line)&lt;br /&gt;(global-set-key [end] 'end-of-line)&lt;br /&gt;&lt;br /&gt;;; Display matters&lt;br /&gt;(display-time)&lt;br /&gt;&lt;br /&gt;(setq blink-cursor nil)&lt;br /&gt;(setq column-number-mode t)&lt;br /&gt;(setq visible-bell t)&lt;br /&gt;(setq tab-width 4)&lt;br /&gt;&lt;br /&gt;;; wheel mouse&lt;br /&gt;(global-set-key [mouse-4] 'scroll-down)&lt;br /&gt;(global-set-key [mouse-5] 'scroll-up)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;3. &lt;/strong&gt; Ама мен bash по ме кефи. OK, baby!&lt;br&gt;&lt;br /&gt;Инсталирате си го и направете&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;chsh -s /usr/local/bin/bash&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;strong&gt;4. &lt;/strong&gt; Искам prompt-та да ми е по-така!&lt;br&gt;&lt;br /&gt;В .bashrc се написва:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;PS1="\t \u@(\[$(tput md)\]\w\[$(tput me)\])"&lt;br /&gt;case `id -u` in&lt;br /&gt;        0) PS1="${PS1}# ";;&lt;br /&gt;        *) PS1="${PS1}$ ";;&lt;br /&gt;esac&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;strong&gt;5. &lt;/strong&gt; Как да mount-на флопито?&lt;br&gt;&lt;br /&gt;Създравате директорита /fdd в root директорията. После в /etc/fstab се добавя:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;/dev/fd0      /fdd            msdos   rw,noauto       0       0&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;и сега вече се пише само: mount /fdd&lt;br /&gt;&lt;br&gt;&lt;br&gt;&lt;br /&gt;&lt;strong&gt;6. &lt;/strong&gt; Как лесно да си пусна настройките на X-a?&lt;br&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;/usr/X11R6/bin/xorgconfig -textmode&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;strong&gt;7. &lt;/strong&gt; Как да ми проработи колелцето на мишката?&lt;br&gt;&lt;br /&gt;Добавете следните редове в /etc/X11/xorg.conf&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Option "ZAxisMapping" "4 5"&lt;br /&gt;Option "Buttons" "5"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;strong&gt;8. &lt;/strong&gt; Искам да си играя игрички, човече? &lt;br&gt;&lt;br /&gt;OK, ама нещата тук не са лесни. Трябва да се инсталира nVidia драйвера. Ето и стъпките, които трябва да се следват:&lt;br&gt;&lt;br /&gt;&lt;br /&gt;--- Редактираме /boot/loader.conf. В него добавяме:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#Nvidia driver&lt;br /&gt;nvidia_load="YES"&lt;br /&gt;&lt;br /&gt;#Nvidia's agp driver&lt;br /&gt;agp_load="YES"&lt;br /&gt;&lt;br /&gt;#Linux compatibility support&lt;br /&gt;linux_load="YES"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;---(optional) Ако нямате инсталирани следните приложения, направете го:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;cd /usr/ports/emulators/linux_base-8 &amp;amp;&amp;amp; make install clean&lt;br /&gt;cd /usr/ports/x11/linux-XFree86-libs &amp;amp;&amp;amp; make install clean&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;--- Инсталираме nVidia драйвера&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;cd /usr/ports/x11/nvidia-driver &amp;amp;&amp;amp; make install clean&lt;br /&gt;cd /usr/ports/x11/nvidia-settings &amp;amp;&amp;amp; make install clean&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;--- (IMPORTANT) Трябва да забраним FreeBSD драйвера!&lt;br /&gt;Редактираме &lt;strong&gt;/boot/device.hints&lt;/strong&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;hint.agp.0.disabled="1"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;--- Конфигурираме X server, като редактираме /etc/X11/xorg.conf&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;# (1) Uncomment&lt;br /&gt;Load "glx"&lt;br /&gt;&lt;br /&gt;# (2) Scroll down to the "server flags" section of the file&lt;br /&gt;# and insert the line shown below&lt;br /&gt;Option "NvAGP" "1"&lt;br /&gt;&lt;br /&gt;# (3) In the part that says "Driver", replace the "nv" with "nvidia",&lt;br /&gt;Driver "nvidia"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;--- (EXTRAS) Maлко да засилим нещата, като добавим в &lt;strong&gt;/etc/sysctl.conf&lt;/strong&gt;:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#Enable AGP Side band Addressing&lt;br /&gt;hw.nvidia.registry.EnableAGPSBA=1&lt;br /&gt;&lt;br /&gt;#Enable AGP Fast Writes&lt;br /&gt;hw.nvidia.registry.EnableAGPFW=1&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;E това е за сега, но това е само началото...&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14240039-114251887869296761?l=zlatozar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zlatozar.blogspot.com/feeds/114251887869296761/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14240039&amp;postID=114251887869296761' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/114251887869296761'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/114251887869296761'/><link rel='alternate' type='text/html' href='http://zlatozar.blogspot.com/2006/03/polished-freebsd-box.html' title='Polished FreeBSD box'/><author><name>Zlatozar</name><uri>http://www.blogger.com/profile/16257250071061885492</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/17/6760/640/RabotnotoMqsto.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14240039.post-114034988928461620</id><published>2006-02-19T13:23:00.002+02:00</published><updated>2008-02-29T18:04:13.709+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='думи'/><title type='text'>Да лекуваш рак с витамини</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp;Витамините винаги помагат, когато са комбинирани с надежда. Има ги в изобилие. Понякога дори вършат чудеса и извеждат душата от Долината на сенките. Помнете ми думата - помагат. Ама бил си добър. Не се отпускай, добрината не дава имунитет.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Колкото и пари да има за раково болните, нищо не е по-добро от навремената реакция от точната диагностика. Да, морфин ще има до края на дните ти. Заменя ли това радостта при отварянето на очите рано в хладната утрин и удоволствието да съществуваш? Отговаря ли това на въпроса, защо аз?&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Тъжно е като гледаш умиращ каубой за десет секунди на големия екран. Боли го и държи дясната си ръка  върху корема. Един подлец го е прострелял. Нечовешко е обаче, когато най-близкия до теб се мъчи с месеци и години улучен от съдбата. Бори се и не знае кой да обвини. Съдбата стреля на посоки, казвам ви.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Инжекцията не е решение, тя е временна забрава. И ето тогава идват витамините. Те са бъдещето и надеждата за утрин без болка. Утрин, но без кафе, то е храна за плевела в теб. Приложи само кураж и чаша студен чай. Бори се с кошмарите и некадърността на провинциалните лекари. Движи се и упражнявай волята си. Тази рецепта няма упътване, само едно наставление - опитай се да живееш!&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Невъзможното е нищо. Аз съм до теб и държа ръката ти, татко. Ще ти давам витамините и ще си говорим за идващото лято.&lt;br /&gt;&lt;em&gt;"Ей Заре, покрива е за ремонт."&lt;/em&gt; Усмихвам се - &lt;em&gt;"Разбира се че ще помагам, татко."&lt;/em&gt;&lt;br /&gt;Добротата не е застраховка, тя е качество което ти притежаваш и затова ние те обичаме.&lt;br /&gt;&lt;br/&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14240039-114034988928461620?l=zlatozar.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zlatozar.blogspot.com/feeds/114034988928461620/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14240039&amp;postID=114034988928461620' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/114034988928461620'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14240039/posts/default/114034988928461620'/><link rel='alternate' type='text/html' href='http://zlatozar.blogspot.com/2006/02/blog-post.html' title='Да лекуваш рак с витамини'/><author><name>Zlatozar</name><uri>http://www.blogger.com/profile/16257250071061885492</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/17/6760/640/RabotnotoMqsto.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14240039.post-113829027835518400</id><published>2006-01-26T15:55:00.001+02:00</published><updated>2011-03-02T17:21:49.341+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='source control'/><title type='text'>Synchronize yourself</title><content type='html'>&lt;a href="http://photos1.blogger.com/blogger/5870/1282/1600/eclipse.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://photos1.blogger.com/blogger/5870/1282/200/eclipse.jpg" border="0" alt="Eclipse forever" /&gt;&lt;/a&gt;Случвало ли ви се е най-добрите идеи по "страничния" проект да идват на работното място? Как може да направите проекта достояние на други? Е, ще се опитам да ви опиша инсталирането на &lt;strong&gt;subversion&lt;/strong&gt;, направата на &lt;strong&gt;repository&lt;/strong&gt; и как да имаме лесен оталечен достъп до кода. Има много &lt;strong&gt;version control system&lt;/strong&gt;, но може да се каже, че &lt;strong&gt;subversion&lt;/strong&gt; е една от най-добрите. &lt;br /&gt;И така да започваме. Операционата система разбира се е FreeBSD!&lt;br /&gt;Web достъпa до нашето &lt;strong&gt;repository&lt;/strong&gt; ще гарантира Apache server.&lt;br /&gt;&lt;pre&gt;cd /usr/ports/www/apache20&lt;br /&gt;make install WITH_BERKELEYDB=db42 &amp;&amp; make clean&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;За да се стартира автоматично напишете следното в &lt;strong&gt;/etc/rc.conf&lt;/strong&gt;:&lt;br /&gt;&lt;pre&gt;apache2_enable="YES"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Имаме работещ web server, компилиран така, че да се сработи с &lt;strong&gt;subversion&lt;/strong&gt;. Ето и следващата стъпка:&lt;br /&gt;&lt;pre&gt;cd /usr/ports/devel/subversion&lt;br /&gt;make install -DWITH_MOD_DAV_SVN &amp;&amp; make clean&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Създаваме и мястото, където ще се съхраняват и нашите проекти.&lt;br /&gt;&lt;pre&gt;mkdir -p /home/svn/repos&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;От тук нататък &lt;strong&gt;subversion&lt;/strong&gt; поема нещата в свои ръце:&lt;br /&gt;&lt;pre&gt;svnadmin create --fs-type fsfs /home/svn/repos/&amp;lt;името&amp;gt;/&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Знайте, че може да имате повече от едно хранилище! Командата по-горе можете да изпълните многократно, само с различни имена на хранилището. Писали сте нещо, което е важно за вас? Бързо се погрижете за него:&lt;br /&gt;&lt;pre&gt;cd &amp;lt;пътя до проекта&amp;gt;&lt;br /&gt;svn import . file:///home/svn/repos/името --message 'Initial repository layout'&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Време е Apache да разбере за съществуването на хранилището.&lt;br /&gt;Довряваме му се изцяло:&lt;br /&gt;&lt;pre&gt;chown -R www:www /home/svn/&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;em&gt;Забележка:&lt;/em&gt; Пускайте тази команда винаги, когато правите нещо "зад гърба" на Apache, за да нямате проблеми с правата на файловете.&lt;br /&gt;Напишете следното в &lt;strong&gt;/usr/local/etc/apache2/httpd.conf&lt;/strong&gt;:&lt;br /&gt;&lt;pre&gt;# Subversion settings&lt;br /&gt;&amp;lt;Location /repos&amp;gt;&lt;br /&gt;DAV svn&lt;br /&gt;&lt;br /&gt;SVNParentPath /home/svn/repos&lt;br /&gt;SVNIndexXSLT "/svnindex.xsl"&lt;br /&gt;&lt;br /&gt;AuthzSVNAccessFile /home/svn/svn-authz-access&lt;br /&gt;&lt;br /&gt;AuthType Basic&lt;br /&gt;AuthName "Subversion repository"&lt;br /&gt;AuthUserFile /home/svn/svn-auth-file&lt;br /&gt;&lt;br /&gt;Satisfy Any&lt;br /&gt;Require valid-user&lt;br /&gt;&amp;lt;/Location&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;strong&gt;svnindex.xsl&lt;/strong&gt; прави интерфейса много по-приятен. Намерете го и го поставете на правилното място - корена на хранилищата:&lt;br /&gt;&lt;pre&gt;locate subversion |grep xsl&lt;br /&gt;cp /usr/local/share/subversion/xslt/* /home/svn/repos/&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://photos1.blogger.com/blogger/5870/1282/1600/repository.jpg"&gt;&lt;img src="http://photos1.blogger.com/blogger/5870/1282/320/repository.jpg" border="0" alt="View result" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Редовете:&lt;br /&gt;&lt;pre&gt;AuthUserFile /home/svn/svn-auth-file&lt;br /&gt;Require valid-user&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;изискват от нас на създадем валидни потребители. За целта:&lt;br /&gt;&lt;pre&gt;htpasswd -cmb /home/svn/svn-auth-file &amp;lt;user&amp;gt; &amp;lt;password&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Аз лично малко задълбочавам нещата, като давам достъп до определени директории(предполага се, че имаме повече от едно хранилище). Реда:&lt;br /&gt;&lt;pre&gt;AuthzSVNAccessFile /home/svn/svn-authz-access&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;ни задължава да създадем файла /home/svn/svn-authz-access. Ето и неговото съдържание:&lt;br /&gt;&lt;pre&gt;# Directory access /home/svn/svn-authz-access&lt;br /&gt;# directory specific authorization control&lt;br /&gt;&lt;br /&gt;[groups]&lt;br /&gt;owner = zlatozar&lt;br /&gt;codedelight-developers = zlatozar&lt;br /&gt;algorithms-developers = zlatozar&lt;br /&gt;&lt;br /&gt;[/]&lt;br /&gt;@owner = rw&lt;br /&gt;&lt;br /&gt;[codedelight:/]&lt;br /&gt;@codedelight-developers = rw&lt;br /&gt;* = r&lt;br /&gt;&lt;br /&gt;[algorithms:/]&lt;br /&gt;@algorithms-developers = rw&lt;br /&gt;* = r&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;em&gt;Забележка:&lt;/em&gt; В групите, потребителите се изброяват с запетая.&lt;br /&gt;&lt;br /&gt;Без да се впускам в подробности, това е накратко конфигурацията. Вече можете спокойно да си изтеглите кода.&lt;br /&gt;&lt;pre&gt;svn checkout http://&amp;lt;domain_name&amp;gt;/repos/&amp;lt;repository_name&amp;gt;/&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Приятна работа! Опааа! Не забравите, че сте компилирали приложенията с параметри, така че ще трябва да се "пипне" и &lt;strong&gt;/usr/local/etc/pkgtools.conf&lt;/strong&gt;. Преговор за това как се прави update можете да направите &lt;a href="http://zlatozar.blogspot.com/2005_08_10_zlatozar_archive.html"&gt;тук&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Защото &lt;strong&gt;subversion&lt;/strong&gt; все още не е популярна, ще внеса и малко допълнителни бележки. Да предположим, че ще трябва да се грижим за някакъв голям проект, по който ще работят много програмисти. Конфигурациите за Apache сървара описани по-горе важат с пълна сила. Особености има в самата организация на &lt;strong&gt;repository&lt;/strong&gt;-то. Какво имам впредвид. Subversion няма вградена подръжка на &lt;strong&gt;branches&lt;/strong&gt; и &lt;strong&gt;tags&lt;/strong&gt;! Вместо това използва копия. За да се разграничават се създават три допълнителни директории - &lt;strong&gt;trunk, branches&lt;/strong&gt; и &lt;strong&gt;tags&lt;/strong&gt;. Сега "зачеването" ще е малко по-различно. Текущата(или работната) версия ще е в trunk.&lt;br /&gt;&lt;pre&gt;$ mkdir Project&lt;br /&gt;$ mkdir Project/trunk&lt;br /&gt;$ mkdir Project/branches&lt;br /&gt;$ mkdir Project/tags&lt;br /&gt;&lt;br /&gt;$ ls Project&lt;br /&gt;branches tags trunk&lt;br /&gt;&lt;br /&gt;$ mv hello.c Project/trunk/&lt;br /&gt;$ mv Makefile Project/trunk/&lt;br /&gt;&lt;br /&gt;$ ls Project/trunk/&lt;br /&gt;Makefile hello.c&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Това му е по-различното. Само да не се забравя, че пътя е пълен. Пример:&lt;br /&gt;&lt;br /&gt;1. Импортва ме (примерно)&lt;br /&gt;&lt;pre&gt;$ svn import --message "Initial import" http://domain/repos/името&lt;br /&gt;Adding     Project/trunk&lt;br /&gt;Adding     Project/trunk/hello.c&lt;br /&gt;Adding     Project/branches&lt;br /&gt;Adding     Project/tags&lt;br /&gt;&lt;br /&gt;Committed revision 1.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Забележете, че се импортват всички допълнителни директории (trunk, branches, tags).&lt;br /&gt;&lt;br /&gt;2. Ако ще теглим текущата версия&lt;br /&gt;&lt;pre&gt;$ svn checkout file:///home/svn/repos/името/trunk&lt;br /&gt;A hello.c&lt;br /&gt;A Makefile&lt;br /&gt;Checked out revision 1.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Появява се и един служебен файл - &lt;strong&gt;.svn&lt;/strong&gt;. Там е служебната информация.&lt;br /&gt;Ако ни трябва branch или tag указваме пътя до тях. Много от нещата в subversion са същите като в CVS.&lt;br /&gt;&lt;pre&gt;svn status името_на_файла&lt;br /&gt;svn log името_на_файла&lt;br /&gt;svn commit името_на_файла&lt;br /&gt;svn update името_на_файла&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;За създаването на тагове нещата са ра
