Skip navigation

Monthly Archives: July 2013

I find myself searching for this often enough to make a note of it.

sudo find . -type f -exec chmod 644 {} \; && find . -type d -exec chmod 755 {} \;

or

sudo find /path/to/docroot/. -type f -exec chmod 644 {} \; && find . -type d -exec chmod 755 {} \;

For SETUID/SETGID conscious configurations:

find /path/to/docroot -type d -exec chmod 2775 {} \; && find /path/to/docroot -type f -exec chmod 0664 {} \;

The error message:
The mobile features adapter must have a "path" config parameter defined

When using Zend Framework and doing any sort of browser detection for mobile devices, this error may pop up. It’s an error in the Zend Documentation, the page The Browscap UserAgent Features Adapter gives the config line of:

resources.useragent.mobile.features.classname = "Zend_Http_UserAgent_Device_Features_Browscap"

This is wrong, the classpath is incorrect. The correct path is:

resources.useragent.mobile.features.classname = "Zend_Http_UserAgent_Features_Adapter_Browscap"

This goes in application/config/application.ini

SELinux was complaining about ‘duplicate declaration in module X’ after a recent package update. This is the result of stale policies not being flushed, so let’s flush them all and rebuild.

rm -f /etc/selinux/targeted/modules/active/modules/*.pp
semodule -B

Hopefully this will be fixed in an upcoming release.

The previous version works well enough, but it’s fairly inefficient memory-wise and uses a rather strange method of moving data around using streams within the class. So, now we have this one:

/*
 * A Simple PDF Stamper using PDFBox
 *
 * July, 2013
 * @author jack
 */
package simplestamper;

import java.awt.Color;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Properties;
import org.apache.pdfbox.exceptions.COSVisitorException;
import org.apache.pdfbox.exceptions.CryptographyException;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.edit.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType1Font;

/**
 *
 * @author jack
 */
public class SimpleStamper {

    private static int numPages;
    private static Properties config = new Properties();
    private static String configFile;
    private static String outputFN = null;
    private static String inputFN = null;
    private static String stampString = null;
    private static String fontFamily = null;
    private static Float fontSize = null;
    private static Integer textRot = null;
    private static Color color = null;
    private static Boolean invertY = false;

    /**
     * Our Constructor
     */
    public SimpleStamper() {
        super();
    }

    /**
     * The main class. It's what plants crave.
     *
     * @param args the command line arguments args[0] -> The config file args[1]
     * -> The PDF document to be stamped args[2] -> The string to stamp
     * (optional, falls back to ss.text in the config file) args[3] -> The
     * desired name and path of the stamped PDF (optional, also defined in
     * config file as ss.outputFN)
     */
    public static void main(String[] args) throws IOException, CryptographyException, COSVisitorException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {

        // as if we were outside...
        SimpleStamper app = new SimpleStamper();

        // if we don't have any parameters...
        if (args.length == 0) {
            usage();
        } else {

            // the config file path
            configFile = args[0];

            // load the config
            loadConfig(configFile, args);

        }
        // stamp
        app.stamp();
    }

    /**
     * Loads the configuration data.
     * Note: If we add many more config values, this function should be revised as a fetching routine.
     *
     * @param configFile
     * @param args
     * @throws NoSuchFieldException
     * @throws IllegalArgumentException
     * @throws IllegalAccessException
     */
    public static void loadConfig(String configFile, String[] args) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException {

        // the input stream
        InputStream is;

        try {
            is = new FileInputStream(configFile);
            
            try {
                // try to load the config file
                config.load(is);
                is.close();
            } catch (IOException e) {
                System.out.println(e);
            }
        } catch (IOException e) {
            System.out.println(e);
        }

        // the input PDF filename/path
        if (args.length > 1) {
            inputFN = args[1];
        } else {
            // make sure we have an input filename
            try {
                inputFN = config.getProperty("ss.inputFN");
            } catch (NullPointerException e) {
                System.err.println("You must specify an input filename as the second argument, or in the properties file. (ss.inputFN)");
            }

        }

        // the string to be stamped
        if (args.length > 2) {
            stampString = args[2];
        } else {
            // make sure we have a string to stamp
            try {
                stampString = config.getProperty("ss.text");
            } catch (NullPointerException e) {
                System.err.println("You must specify a string to stamp as the third argument, or in the properties file. (ss.text)");
            }

        }

        // the output PDF filename/path
        if (args.length > 3) {
            outputFN = args[3];
        } else {
            // make sure we have an output filename
            try {
                outputFN = config.getProperty("ss.outputFN");
            } catch (NullPointerException e) {
                System.err.println("You must specify an output filename as the fourth argument, or in the properties file. (ss.outputFN)");
            }

        }

        // make sure we have a font from the prop file
        try {
            fontFamily = config.getProperty("ss.fontFamily");
        } catch (NullPointerException e) {
            System.err.println("You must specify a font in the properties file. (ss.fontFamily)");
        }

        // make sure we have a font size from the prop file
        try {
            fontSize = Float.parseFloat(config.getProperty("ss.fontSize"));
        } catch (NullPointerException e) {
            System.err.println("You must specify a font size in the properties file. (ss.fontSize)");
        }

        // text rotation
        // make sure we have a font size from the prop file
        try {
            textRot = Integer.parseInt(config.getProperty("ss.rotation"));
        } catch (NullPointerException e) {
            System.err.println("You must specify a rotation in the properties file. (ss.rotation)");
        }

        // text color. if not set in the properties file we default to black
        try {
            Field field = Color.class.getField(config.getProperty("ss.fontColor"));
            color = (Color) field.get(null);
        } catch (NullPointerException e) {
            System.err.println("You must specify a font color in the properties file. (ss.fontColor)");
        }

        // the Y value inversion bool. Do we calc yVal from the top or bottom of the page?
        invertY = "true".equals(config.getProperty("ss.invertY")) ? true : false;
    }

    /**
     * The Stamping function. Where the magic lives.
     *
     * @throws IOException
     * @throws COSVisitorException
     */
    public void stamp() throws IOException, COSVisitorException {

        // the document
        PDDocument doc = null;

        try {
            // load the incoming document into a PDDcoument
            doc = PDDocument.load(inputFN);

            // make a list array of all the pages
            List allPages = doc.getDocumentCatalog().getAllPages();

            // Create a new font object selecting one of the PDF base fonts
            PDFont font = PDType1Font.getStandardFont(fontFamily);

            // the x/y coords
            float xVal = Float.parseFloat(config.getProperty("ss.xVal"));
            float yVal = Float.parseFloat(config.getProperty("ss.yVal"));

            // for every page in the incoming doc, stamp
            for (int i = 0; i < allPages.size(); i++) {
                // create an empty page and a geo object to use for calcs
                PDPage page = (PDPage) allPages.get(i);
                PDRectangle pageSize = page.findMediaBox();

                // are we inverting the y axis?
                if (invertY) {
                    yVal = pageSize.getHeight() - yVal;
                }

                // calculate the width of the string according to the font
                float stringWidth = font.getStringWidth(stampString) * fontSize / 1000f;

                // determine the rotation stuff. Is the the loaded page in landscape mode? (for axis and string dims)
                int pageRot = page.findRotation();
                boolean pageRotated = pageRot == 90 || pageRot == 270;

                // are we rotating the text?
                boolean textRotated = textRot != 0 || textRot != 360;

                // calc the diff of rotations so the text stamps
                int totalRot = pageRot - textRot;

                // calc the page dimensions
                float pageWidth = pageRotated ? pageSize.getHeight() : pageSize.getWidth();
                float pageHeight = pageRotated ? pageSize.getWidth() : pageSize.getHeight();

                // determine the axis of rotation
                double centeredXPosition = pageRotated ? pageHeight / 2f : (pageWidth - stringWidth) / 2f;
                double centeredYPosition = pageRotated ? (pageWidth - stringWidth) / 2f : pageHeight / 2f;

                // append the content to the existing stream
                PDPageContentStream contentStream = new PDPageContentStream(doc, page, true, true, true);
                contentStream.beginText();

                // set font and font size
                contentStream.setFont(font, fontSize);

                // set the stroke (text) color
                contentStream.setNonStrokingColor(color);

                // if we are rotating, do it
                if (pageRotated) {

                    // rotate the text according to the calculations above
                    contentStream.setTextRotation(Math.toRadians(totalRot), centeredXPosition, centeredYPosition);

                } else if (textRotated) {

                    // rotate the text according to the calculations above
                    contentStream.setTextRotation(Math.toRadians(textRot), xVal, yVal);

                } else {

                    // no rotate, just move it.
                    contentStream.setTextTranslation(xVal, yVal);
                }

                // stamp the damned text already
                contentStream.drawString(stampString);

                // close and clean up
                contentStream.endText();
                contentStream.close();
            }

            doc.save(outputFN);

        } finally { // you know, PHP 5.5 now has a finally construct...

            // if the document isnt closed, do so
            if (doc != null) {
                doc.close();
            }

        }
    }

    /**
     * Attempts to provide basic usage info.
     */
    private static void usage() {
        System.err.println("usage: java -jar simplestamper \"PdfToStamp.pdf\" \"The text to stamp, in parenthesis.\" \"Output.pdf\"");
    }
}

And the config file:

# the properties for each event

#The text to be stamped.
ss.text=This is the text to be stamped.
#The x value of the stamped text, measured in pixels with the origin at bottom-left.
ss.xVal=100
#The y value of the stamped text, measured in pixels with the origin at bottom-left.
ss.yVal=200
# The counterclockwise rotation of the text in degrees (converted to radians in the app)
ss.rotation=0
#The name/path of the input file
ss.inputFN=pdf.pdf
# the filename of the stamped pdf
ss.outputFN=output.pdf

# FONT OPTIONS:
# more info: http://pdfbox.apache.org/apidocs/org/apache/pdfbox/pdmodel/font/PDType1Font.html
#
# Helvetica-BoldOblique
# Times-Italic
# ZapfDingbats
# Symbol
# Helvetica-Oblique
# Courier
# Helvetica-Bold
# Helvetica
# Courier-Oblique
# Times-BoldItalic
# Courier-Bold
# Times-Roman
# Times-Bold
# Courier-BoldOblique
ss.fontFamily=Helvetica
ss.fontSize=18
#
# The font color.
# Examples: blue, red, green, black, white, yelllow, cyan, gray, lightGray
# More Info: http://docs.oracle.com/javase/7/docs/api/java/awt/Color.html
ss.fontColor=black

# Operational Vars
#
# Do we want to calc text placement from the top (true) or bottom (false) of the page?
# (The PDF spec. dictates that we calc all y values starting from the bottom, this is why top = true)
ss.invertY=true

PDFbox is a fairly robust library for manipulating and extracting information from PDF documents. This is a short and simple Java class that utilizes PDFbox to stamp/watermark a PDF from the command line, be it a bash script or exec call. There isn’t much in the way of existing user documentation for this type of action using PDFbox, so I’m leaving it here in case it’s useful.

/*
 * A Simple PDF Stamper using PDFBox
 *
 * July, 2013
 * @author jack
 */
package simplestamper;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import org.apache.pdfbox.Overlay;
import org.apache.pdfbox.exceptions.COSVisitorException;
import org.apache.pdfbox.exceptions.CryptographyException;
import org.apache.pdfbox.exceptions.InvalidPasswordException;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.edit.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType1Font;

/**
 *
 * @author jack
 */
public class SimpleStamper {

    private static PDDocument pdf;
    private static int numPages;
    private static Properties config = new Properties();
    private static String configFile;
    private static String outputFN = null;
    private static String inputFN = null;
    private static String stampString = null;
    private static String fontFamily = null;
    private static Float fontSize = null;

    /**
     * The main class. It's what plants crave.
     *
     * @param args the command line arguments
     *      args[0] -> The config file
     *      args[1] -> The PDF document to be stamped
     *      args[2] -> The string to stamp (optional, falls back to ss.text in the config file)
     *      args[3] -> The desired name and path of the stamped PDF (optional, also defined in config file as ss.outputFN)
     */
    public static void main(String[] args) throws IOException, CryptographyException, COSVisitorException {

        // if we don't have any parameters...
        if (args.length == 0) {
            usage();
        } else {

            // the config file path
            configFile = args[0];

            // load the config
            loadConfig(configFile, args);

        }
        // stamp
        stampPdf();
    }

    /**
     * Loads the configuration data.
     *
     * @param configFile
     */
    public static void loadConfig(String configFile, String[] args) {

        // the input stream
        InputStream is;

        try {

            is = new FileInputStream(configFile);

            try {
                // try to load the config file
                config.load(is);
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        // the input PDF filename/path
        if (args.length > 1) {
            inputFN = args[1];
        }else{
            inputFN = config.getProperty("ss.inputFN");
        }

        // the string to be stamped
        if(args.length > 2){
            stampString = args[2];
        }else{
            stampString = config.getProperty("ss.text");
        }

        // the output PDF filename/path
        if(args.length > 3){
            outputFN = args[3];
        }else{
            outputFN = config.getProperty("ss.outputFN");
        }

        // make sure we have a font from the prop file
        try{
            fontFamily = config.getProperty("ss.fontFamily");
        } catch (NullPointerException e){
            System.err.println("You must specify a font in the properties file.");
        }

        // make sure we have a font size from the prop file
        try{
            fontSize = Float.parseFloat(config.getProperty("ss.fontSize"));
        } catch (NullPointerException e){
            System.err.println("You must specify a font size in the properties file.");
        }

    }

    /**
     * Coordinate the stamping procedure.
     *
     */
    public static void stampPdf() throws IOException, CryptographyException, COSVisitorException {

        // load the PDF to be stamped
        pdf = PDDocument.load(inputFN);

        if (pdf.isEncrypted()) {
            try {
                // try to open the encrypted PDF
                pdf.decrypt("");

            } catch (InvalidPasswordException e) {

                // This error message dictates that the document is encrypted and we have no password
                System.err.println("The document is encrypted or otherwise has prohibitive security settings..");
                System.exit(1);
            }
        }
        // create the overlay page with the text to be stamped
        PDDocument overlayDoc = createOverlay(stampString);

        // update the number of pages we have in the incoming pdf
        numPages = pdf.getPageCount();

        // do the overlay
        doOverlay(pdf, overlayDoc);

        // close
        pdf.close();
        overlayDoc.close();
    }

    /**
     * Creates the overlay PDF.
     *
     * @param text
     * @return PDDocument
     * @throws IOException
     * @throws COSVisitorException
     */
    public static PDDocument createOverlay(String text) throws IOException, COSVisitorException {

        // Create a document and add a page to it
        PDDocument document = new PDDocument();
        PDPage page = new PDPage();
        document.addPage(page);

        // the x/y coords
        Float xVal = Float.parseFloat(config.getProperty("ss.xVal"));
        Float yVal = Float.parseFloat(config.getProperty("ss.yVal"));

        // Create a new font object selecting one of the PDF base fonts
        PDFont font = PDType1Font.getStandardFont(fontFamily);

        // Start a new content stream which will "hold" the to be created content
        PDPageContentStream contentStream = new PDPageContentStream(document, page);

        // Create the text and position it
        contentStream.beginText();
        contentStream.setFont(font, fontSize);
        contentStream.moveTextPositionByAmount(xVal, yVal);
        contentStream.drawString(text);
        contentStream.endText();

        // Make sure that the content stream is closed:
        contentStream.close();

        //return the string doc
        return document;
    }

    /**
     * Performs the overlay of the two documents.
     *
     * @param basePDF
     * @param overlayDoc
     * @throws IOException
     * @throws COSVisitorException
     */
    private static void doOverlay(PDDocument basePDF, PDDocument overlayDoc) throws IOException, COSVisitorException {

        PDDocumentCatalog docCatalog = basePDF.getDocumentCatalog();

        // get the pages of the pdf
        List pages = docCatalog.getAllPages();
        Iterator pageIter = pages.iterator();

        while (pageIter.hasNext()) {
            PDPage page = (PDPage) pageIter.next();
        }

        Overlay overlay = new Overlay();
        PDDocument output = overlay.overlay(overlayDoc, basePDF);
        //overlay.overlay(overlayDoc, basePDF);

        // save the new doc to the file name specified in the config
        output.save(outputFN);

        // close, close
        overlayDoc.close();
        basePDF.close();
    }

    /**
     * Attempts to provide basic usage information.
     */
    private static void usage() {
        System.err.println("usage: java -jar simplestamper \"PdfToStamp.pdf\" \"The text to stamp, in parenthesis.\" \"Output.pdf\"");
    }
}

SVN is like a girl with huge tits and a pet Rhino, lots of fun most of the time but that damned Rhino keeps breaking all your shit. One of the first things to check when you notice peculiar behavior in your SVN workflow is to make sure your SVN client and the SVN server are running compatible version. I found this useful, so I’m making a note of it here.

To get the version of the SVN server:

wget -S --no-check-certificate --user='jack' password='thepassword' --spider 'https://svn.jackson-brain.com/trunk/branch' 2>&1 | sed -n '/SVN/s/.*\(SVN[0-9\/\.]*\).*/\1/p';

The client:

svn --version

Unless you have custom compiled or otherwise installed and configured the Zend OPcache extension for PHP, or are running PHP >= 5.5 in which case the extension is enabled by default.

This is simple, yet handy if you are developing within an environment where you want to test code with and without OPcache. In the .htaccess file of the directory containing the PHP you do not want cached, add the line:

php_flag opcache.enable Off

No need to restart Apache. To determine the state of OP caching within this directory, examine the output of phpinfo() executed from within that directory. Look for the section titled ‘Zend OPcache’, if it’s enabled you’ll get a good deal of stats on the items in the cache, if it’s not it will simple say ‘Disabled’.

Troubleshooting:

  1. Check .htaccess override setting in httpd.conf

This is my custom vim script, based heavily on a script I picked up from DA. The script requires the vim Bundle plugin (Vundle), once installed open a vim window and type ‘BundleInstall’ and the other plugins will be downloaded and installed for the session user. There are a few font and encoding setting that need to be configured, especially when used through putty.

"----------------------------------------------"
" Author: custom vim stuff by jack             "
"----------------------------------------------"
""" Vundle plugin manager {{{
    filetype off                                    " required to init 
    set rtp+=~/.vim/bundle/vundle/                  " include vundle
    call vundle#rc()                                " init vundle
    """ github repos, uncomment to disable a plugin {{{
        Bundle 'chrisbra/SudoEdit.vim'
        Bundle 'ervandew/supertab'
        Bundle 'gmarik/vundle'
        Bundle 'kien/ctrlp.vim'
        Bundle 'lilydjwg/colorizer'
        Bundle 'Lokaltog/vim-powerline'
        Bundle 'Lokaltog/vim-easymotion'
        Bundle 'msanders/snipmate.vim'
        Bundle 'nanotech/jellybeans.vim'
        Bundle 'scrooloose/nerdcommenter'
        Bundle 'scrooloose/nerdtree'
        Bundle 'Townk/vim-autoclose'
        Bundle 'tpope/vim-fugitive'
        Bundle 'tpope/vim-surround'
        Bundle 'trapd00r/x11colors.vim'
        Bundle 'vim-scripts/Align'
        Bundle 'vim-scripts/mru.vim'
        Bundle 'xuhdev/SingleCompile'
        " Requires a compiler or syntax/code checker, see :h Syntastic
        Bundle 'scrooloose/syntastic'
        " Requires ctags installed
        Bundle 'majutsushi/tagbar'
        " Requires a working Ruby-install (but not vim compiled with ruby)
        Bundle 'simmel/vim-pastie'
        " Requires the clang compilator
        Bundle 'Rip-Rip/clang_complete'
        " Requires the python package 'jedi' (also if you're in a
        " no-site-packages virtenv)
        Bundle 'davidhalter/jedi-vim'
""" }}}
""" User interface {{{
    """ Syntax highlighting {{{
        filetype plugin indent on                   " enable ft+plugin detect
        syntax on                                   " syntax highlighting
        set t_Co=256                                " 256-colors
        set background=dark                         " we're using a dark bg
        colors jellybeans                           " select colorscheme
        highlight Normal ctermbg=NONE               " use terminal background
        highlight nonText ctermbg=NONE              " use terminal background
        au BufRead,BufNewFile *.txt set ft=sh       " opens .txt w/highlight
    """ }}}
    """ Interface general {{{
        set cursorline                              " hilight cursor line
        set more                                    " ---more--- like less
        set number                                  " line numbers
        set scrolloff=5                             " lines above/below cursor
        set showcmd                                 " show cmds being typed
        set title                                   " window title
	set titlestring=%t
        set vb t_vb=                                " disable beep and flashing
        set wildignore=.bak,.pyc,.o,.ojb,.,a,       " ignore said files
                       \.pdf,.jpg,.gif,.png,
                       \.avi,.mkv,.so
        set wildmenu                                " better auto complete
        set wildmode=longest,list                   " bash-like auto complete
        """ Encoding {{{
            " If you're having problems with Powerline glyphs you can force
            " UTF-8 if your locale is something else. 
            " WARNING: this will affect encoding used when editing files!
            "
            set encoding=utf-8                    " For Powerline glyphs
        """ }}}
        """ Gvim {{{
            " set guifont=DejaVu\ Sans\ Mono\ for\ Powerline\ 8
            " set guifont=DejaVu\ Sans\ Mono\ for\ Powerline
            set guifont=DejaVuSansMono-Powerline
            set guioptions-=m                       " remove menubar
            set guioptions-=T                       " remove toolbar
            set guioptions-=r                       " remove right scrollbar
        """ }}}
        """ Powerline {{{
            let g:Powerline_symbols = 'fancy'       " glyphs, req. fontpatch
            let g:Powerline_symbols_override = {
                        \ 'BRANCH': [0x2213],
                        \ }                         " use ∓
            """ Powerline mode names {{{
                let g:Powerline_mode_n  = ' N '
                let g:Powerline_mode_i  = ' I '
                let g:Powerline_mode_R  = ' R '
                let g:Powerline_mode_v  = ' V '
                let g:Powerline_mode_V  = 'V·L'
                let g:Powerline_mode_cv = 'V·B'
                let g:Powerline_mode_s  = ' S '
                let g:Powerline_mode_S  = 'S·L'
                let g:Powerline_mode_cs = 'S·B'
            """ }}}
        """ }}}
    """ }}}
""" }}}
""" General settings {{{
    set hidden                                      " buffer change, more undo
    set history=200                                 " default 20
    set iskeyword+=_,$,@,%,#                        " not word dividers
    set laststatus=2                                " always show statusline
    set listchars=tab:>\                            " > to highlight 
    set list                                        " displaying listchars
    set mouse=a                                     " mouse in all modes
    set nocompatible                                " don't vi-compatible
    set noshowmode                                  " hide mode in cmd-line
    set noexrc                                      " don't use other .*rc(s)
    set nostartofline                               " no goto #1 char in line
    set nowrap                                      " don't wrap lines
    set numberwidth=5                               " 99999 lines
    set ttymouse=xterm2                             " Currently being tested
    """ Folding {{{
        set foldcolumn=0                            " hide folding column
        set foldmethod=indent                       " folds using indent
        set foldnestmax=10                          " max 10 nested folds
        set foldlevelstart=99                       " folds open by default
    """ }}}
    """ Search and replace {{{
        set gdefault                                " default s//g (global)
        set incsearch                               " "live"-search
        set ignorecase                              " case insensitive search
    """ }}}
    """ Matching {{{
        set matchtime=2                             " time to blink match {}
        set matchpairs+=<:>                         " for ci< or ci>
        set showmatch                               " tmpjump to match-bracket
    """ }}}
    """ Return to last edit position when opening files {{{
        autocmd BufReadPost *
            \ if line("'\"") > 0 && line("'\"") <= line("$") |
            \     exe "normal! g`\"" |
            \ endif
    """ }}}
""" }}}
""" Files {{{
    set autochdir                                   " always use curr. dir.
    set autoread                                    " refresh if changed
    set backup                                      " backup curr file
    set backupdir=~/.vim/backup                     " backup director{y,ies}
    set backupext=~                                 " append ~ to backups
    set confirm                                     " confirm changed files
    set noautowrite                                 " never autowrite
    set updatecount=50                              " update swp after 50chars
    """ Persistent undo. Requires Vim 7.3 {{{
        if has('persistent_undo') && exists("&undodir")
            set undodir=~/.vim/undo/                " where to store undofiles
            set undofile                            " enable undofile
            set undolevels=500                      " max undos stored
            set undoreload=10000                    " buffer stored undos
        endif
    """ }}}
""" }}}
""" Text formatting {{{
    set autoindent                                  " preserve indentation
    set backspace=indent,eol,start                  " smart backspace
    "set expandtab                                   " no real tabs
    set nrformats+=alpha                            " incr/decr letters C-a/-x
    set shiftround                                  " be clever with tabs
    set shiftwidth=4                                " default 8
    set smartcase                                   " igncase,except capitals
    set smartindent                                 " see autoindent
    set smarttab                                    " tab to 0,4,8 etc.
    "set softtabstop=4                               " "tab" feels like 
    "set tabstop=4                                   " replace  w/4 spaces
    """ Only auto-comment newline for block comments {{{
        au FileType c,cpp setlocal comments -=:// comments +=f://
    """ }}}
""" }}}
""" Keybindings {{{
    """ General {{{
        " Remap 
        let mapleader=","
        " Quickly edit/source .vimrc
        noremap ve :edit ~/.vimrc
        noremap vs :source ~/.vimrc
        " Yank(copy) to system clipboard
        noremap y "+y
        " Toggle text wrapping
        nmap  w :set invwrap:set wrap? 
        " Toggle folding
        nnoremap   @=(foldlevel('.')?'za':"\")
        vnoremap  zf
        " Delete previous word with C-BS, doesn't work in all terminals
        imap  
        " Bubbling (bracket matching)
        nmap  [e
        nmap  ]e
        vmap  [egv
        vmap  ]egv
        " Move faster
        map  
        map  
        " Treat wrapped lines as normal lines
        nnoremap j gj
        nnoremap k gk
        " Move a line of text using ALT-{j,k}
        nmap  mz:m+`z
        nmap  mz:m-2`z
        " Rebind æøå (Norwegian keys)
        noremap ø :
        noremap å [
        noremap æ ]
        " Split and switch to new pane
        nnoremap d vl             " vertical
        nnoremap s sl             " horizontal
        " We don't need any help!
        inoremap  
        nnoremap  
        vnoremap  
        " Toggle syntax highlight
        map  :if exists("syntax_on")
            \syntax offelsesyntax enableendif
    """ }}}
    """ Plugins {{{
        " Toggle tagbar (definitions, functions etc.)
        map  :TagbarToggle
        " Toggle the NERDTree file browser
        map  :NERDTreeToggle
        " Toggle pastemode, doesn't indent
        set pastetoggle=
        " SingleCompile
        nmap  :SCCompile
        nmap  :SCCompileRun
        call SingleCompile#SetCompilerTemplate('cpp', 'gcc', 'GNU C Compiler',
            \'g++', '-Wall -Wextra -pedantic -O3 -std=c++0x -o $(FILE_TITLE)$',
            \'./$(FILE_TITLE)$')
        call SingleCompile#SetOutfile('cpp', 'gcc', '$(FILE_TITLE)$')
        call SingleCompile#ChooseCompiler('cpp', 'gcc')
        " Toggle Syntastic error list. Probably should be toggleable.
        noremap lo :Errors
        noremap lc :lcl
        " Snipmate remapping
        imap  =TriggerSnippet()
    """ }}}
    """ Highlight characters past 80, toggle with h {{{
        nnoremap h :call ToggleOverLengthHighlight()
        let g:overlength_enabled = 0
        highlight OverLength ctermbg=black guibg=#212121
        function! ToggleOverLengthHighlight()
            if g:overlength_enabled == 0
                match OverLength /\%80v.*/
                let g:overlength_enabled = 1
                echo 'OverLength highlighting turned on'
            else
                match
                let g:overlength_enabled = 0
                echo 'OverLength highlighting turned off'
            endif
        endfunction
    """ }}}
    """ Toggle relativenumber using r {{{
        nnoremap r :call NumberToggle()
        function! NumberToggle()
            if(&relativenumber == 1)
                set number
            else
                set relativenumber
            endif
        endfunction
    """ }}}
""" }}}
""" Misc plugin settings {{{
    " NERDTree
    let g:NERDTreeWinPos = "left"
    let g:NERDTreeHijackNetrw=1
    " TagBar
    let g:tagbar_left = 0
    let g:tagbar_width = 30
    set tags=tags;/
    " Stop CtrlP from recalculating on files on start
    let g:ctrlp_clear_cache_on_exit = 0
    let g:ctrlp_working_path_mode = 'ra'
    let g:ctrlp_root_markers = ['.root', 'Makefile', '.git' ]
    " clang_complete - C++11
    let g:clang_user_options="-std=c++0x"
    " Syntastic
    let g:syntastic_cpp_check_header = 1
    let g:syntastic_cpp_compiler_options = ' -std=c++0x'
    let g:syntastic_mode_map = { 
        \ 'mode': 'passive',
        \ 'active_filetypes': 
            \ ['c', 'cpp', 'javascript', 'perl', 'python', 'sh'] }
    " Automatically remove preview window after autocomplete (clang_complete)
    autocmd CursorMovedI * if pumvisible() == 0|pclose|endif
    autocmd InsertLeave * if pumvisible() == 0|pclose|endif
    " Private pastie (simmel's fork of tpope's vim-pastie with help from garno)
    let g:pastie_private = 1
""" }}}
""" Use ~/.vimrc.local if exists {{{{
    if filereadable($HOME."/.vimrc.local")
        source $HOME/.vimrc.local
    endif
""" }}}

Using memcache to store objects is not a new strategy to reduce database load and improve responsiveness of an application, but it is an often overlooked option due to the ‘extra’ labor of installation and configuration. Hopefully the following information will make this easier for some and me to remember.

Installing and configuring a memcache server on linux:

  1. Download, configure, and compile memcache.
  2. Create a startup script:
    #! /bin/sh
    #
    # chkconfig: - 55 45
    # description: The memcached daemon is a network memory cache service.
    # processname: memcached
    # config: /etc/sysconfig/memcached
    # pidfile: /var/run/memcached/memcached.pid# Standard LSB functions
    #. /lib/lsb/init-functions# Source function library.
    . /etc/init.d/functions
    #
    PORT=11211
    USER=memcached
    MAXCONN=2048
    CACHESIZE=128
    OPTIONS=""
    #
    if [ -f /etc/sysconfig/memcached ];then
    . /etc/sysconfig/memcached
    fi
    #
    # Check that networking is up.
    . /etc/sysconfig/network
    #
    if [ "$NETWORKING" = "no" ]
    then
    exit 0
    fi
    #
    RETVAL=0
    prog="memcached"
    pidfile=${PIDFILE-/var/run/memcached/memcached.pid}
    lockfile=${LOCKFILE-/var/lock/subsys/memcached}
    #
    start () {
    echo -n $"Starting $prog: "
    # Ensure that /var/run/memcached has proper permissions
    if [ "`stat -c %U /var/run/memcached`" != "$USER" ]; then
    chown $USER /var/run/memcached
    fi
    #
    daemon --pidfile ${pidfile} memcached -d -p $PORT -u $USER -m $CACHESIZE -c $MAXCONN -P ${pidfile} $OPTIONS
    RETVAL=$?
    echo
    [ $RETVAL -eq 0 ] && touch ${lockfile}
    }
    stop () {
    echo -n $"Stopping $prog: "
    killproc -p ${pidfile} memcached
    RETVAL=$?
    echo
    if [ $RETVAL -eq 0 ] ; then
    rm -f ${lockfile} ${pidfile}
    fi
    }
    # restart
    restart () {
    stop
    start
    }
    # See how we were called.
    case "$1" in
    start)
    start
    ;;
    stop)
    stop
    ;;
    status)
    status -p ${pidfile} memcached
    RETVAL=$?
    ;;
    restart|reload|force-reload)
    restart
    ;;
    condrestart|try-restart)
    [ -f ${lockfile} ] && restart || :
    ;;
    *)
    echo $"Usage: $0 {start|stop|status|restart|reload|force-reload|condrestart|try-restart}"
    RETVAL=2
    ;;
    esac
    exit $RETVAL
    
  3. Add the daemon to the service manager, and enable it for runlevel3:
    • chkconfig –add –level 3 memcached
  4. Start the Memcache server:
    • service memcached start

You should now have a functioning memcache server, available on the localhost, port 11211. you can check to see if it’s running with service memcached status. Now, to use it within PHP for example you have to provide the PHP extension for memcache so that you can store and retrieve data.  For this purpose, there is a PECL extension available here: http://pecl.php.net/package/memcache

Building the extension is fairly easy:

  1. wget http://pecl.php.net/get/memcache-3.0.8.tgz
  2. tar -xvzf memcache-3.0.8.tgz
  3. cd memcache-3.0.8
  4. phpize
  5. ./configure && make && make install
  6. Check /etc/php.d/memcached.ini, if it doesn’t exist or correctly point to the compiled extension (*.so) PHP will not be able to communicate with the memcache server.

Now the easy part -> using it. For that, RTFM. http://php.net/manual/en/book.memcache.php

While re-factoring a project for performance and improved consistency, it became necessary to store objects in memory for later use to avoid serialization and anything to do with the session. Memcached to the resue? Somewhat, had to do this one by hand as the environment this project is to be deployed within has a number of custom attributes including custom compiled binaries for PHP, libmemcached, imagick, XCache, gearman, etc. Configuring and compiling memcached couldn’t have been easier:

./configure && make && sudo make install && sudo adduser memcached

(Remember to add the new user memcached will run under, using ‘nobody’ is considered to be unsafe.) Now I needed to make sure the Memcache server would start when runlevel=3, after some experimentation this is the bash script that resulted:

#! /bin/sh
#
# chkconfig: - 55 45
# description: The memcached daemon is a network memory cache service.
# processname: memcached
# config: /etc/sysconfig/memcached
# pidfile: /var/run/memcached/memcached.pid
# author: Jack Brain
# Standard LSB functions
#. /lib/lsb/init-functions
# Source function library.
. /etc/init.d/functions
PORT=11211
USER=memcached
MAXCONN=2048
CACHESIZE=128
OPTIONS=''
if [ -f /etc/sysconfig/memcached ];then
. /etc/sysconfig/memcached
fi
# Check that networking is up.
. /etc/sysconfig/network
if [ "$NETWORKING" = "no" ]
then
exit 0
fi
RETVAL=0
prog=”memcached”
pidfile=${PIDFILE-/var/run/memcached/memcached.pid}
lockfile=${LOCKFILE-/var/lock/subsys/memcached}
start () {
echo -n $”Starting $prog: “
# Ensure that /var/run/memcached has proper permissions
if [ "`stat -c %U /var/run/memcached`" != "$USER" ]; then
chown $USER /var/run/memcached
fi
daemon –pidfile ${pidfile} memcached -d -p $PORT -u $USER -m $CACHESIZE -c $MAXCONN -P ${pidfile} $OPTIONS
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && touch ${lockfile}
}
stop () {
echo -n $”Stopping $prog: “
killproc -p ${pidfile} memcached
RETVAL=$?
echo
if [ $RETVAL -eq 0 ] ; then
rm -f ${lockfile} ${pidfile}
fi
}
restart () {
stop
start
}
# See how we were called.
case “$1″ in
start)
start
;;
stop)
stop
;;
status)
status -p ${pidfile} memcached
RETVAL=$?
;;
restart|reload|force-reload)
restart
;;
condrestart|try-restart)
[ -f ${lockfile} ] && restart || :
;;
*)
echo $”Usage: $0 {start|stop|status|restart|reload|force-reload|condrestart|try-restart}”
RETVAL=2
;;
esac
exit $RETVAL