Django Make Html/Form Helpers

I’ve been developing a django website and while doing so learning some of the neat tricks that the framework has. One thing that I’ve found and love is making custom tags in the templating system and I decided to make a few html helpers similar to Code Igniter.
(I use this for a reference)

so after creating my django project which because I’m using virtualenv so in the environment:

python2.7 bin/django-admin.py startproject budgetproject

Then I started an app called util by running:

python2.7 ../manage.py startapp util

which is where I will be putting my helpers and of course enable that in the settings which do to my directory structure looks like this (budgetproject/settings.py):

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django.contrib.admin',
    'django.contrib.admindocs',
    'budgetproject.app.homepage',
    'budgetproject.app.accounts',
    'budgetproject.util',
)

Awesome we’re set and ready to go with a directory structure of:

budgetproject
    util
        __init__.py
        models.py
        tests.py
        views.py
    __init__.py
    templates
    settings.py
    urls.py
    wsgi.py

Alright got the basics out of the way lets get to what we came for and thats to create a template tag. First we need to create the templatetags directory and create and empty file __init__.py to essentially make an empty python package:

budgetproject
    util
        templatetags
            __init__.py
        __init__.py
        models.py
        tests.py
        views.py
    ...

now lets create our file with our tags I called mine html.py and in it I put:

from django import template
import os
TEMPLATE_DIR = 'html'

register = template.Library()

@register.inclusion_tag(os.path.join(TEMPLATE_DIR,'form_open.html'))
def form_open(action,method='post'):
    return {'action': action,'method':method}
    
@register.inclusion_tag(os.path.join(TEMPLATE_DIR,'form_close.html'))
def form_close():
    return {}

Now lets go over what each section means.

from django import template
import os
TEMPLATE_DIR = 'html'

register = template.Library()

Every filter or template tag must have include template and have a variable called register that is a template.Library() type. I’m also using the os module to have relative paths and keep compatibility for different operating systems.

@register.inclusion_tag(os.path.join(TEMPLATE_DIR,'form_open.html'))
def form_open(action,method='post'):
    return {'action': action,'method':method}

The register.inclusion_tag decorator is a simple way to create an inclusion tag which basically allows you to “display some data by rendering another template” so that is why you pass the decorator and the function it decorates returns a dictionary of the data your are going to display. In this case were displaying an opening form tag so we need an action and method among other things but those are good enough for now. The reason I did an inclusion tag here instead of a simple tag and return a string will become more apparent in a moment.

@register.inclusion_tag(os.path.join(TEMPLATE_DIR,'form_close.html'))
def form_close():
    return {}

For the closing form tag I could of done a simple tag and returned a string, but I prefer to keep things consistent so I made it an inclusion tag and the included template is simply just the string.

Now lets look at those templates to see what gets included shall we? First the form_open.html template:

<form action="{{ action }}" method="{{ method }}">{% csrf_token %}

We have our form tag and the action and method variables we passed to it as well as the cross site request forgery token to prevent people from doing a cross site request hack. That is the reason I chose to make it an inclusion tag is so that I could put the csrf_token tag in the template that is included.
and the form_close.html:

</form>

again could of just done a simple tag decorator and return a string, but I wanted to keep some consistency.

Now lets take a look at our directory structure again:

budgetproject
    util
        templatetags
            __init__.py
            html.py
        __init__.py
        models.py
        tests.py
        views.py
    ...

templates
    html
        form_close.html
        form_open.html
    base.html

Awesome! except now how do we use this new found treasure? Well its actually quite simple and thats what I love about django and python after all “Simple is better than complex”. For us lets pretend we are going to use it in our base.html template. In there we would put:

{% load html %}
{# other html tags and blocks such as html, head, title, body, etc #}
{% form_open "test/url/thing" %}
{# form elements go here #}
{% form_close %}
{# other html tags and blocks such as html, head, title, body, etc #}

So fist and formost we must load our template tags by doing {% load html %} and because our util app is registered and has the templatetags directory with html.py our tags will get loaded. Then we can use our tags as we have defined i.e. {% form_open “test/url/” %} (method is optional and will default to “post”) and {% form_close %}.

Well there you have it, try it out and let me know how it works for you.

Posted in django, python | Tagged , , , | Comments Off

Map/Reduce Style Functional Programming with Go

One of the top complaints you see about Go on the golang mailing list is that Go lacks any kind of generic programming. The creators of Go have addressed this in the FAQ. Essentially, they haven’t found a suitable implementation that fits with the rest of the philosophy of Go. To me, this is unfortunate. However, Go is still a young language, and the possibility of generics finding their way into the language is still there.

In the meantime, I’d still like to be able to use functional-style programming in Go in the form of generic Map and Reduce functions.

To start, there’s a tiny bit of (optional) boiler-plate that we need to get out of the way. We need a generic type. This type will be identical to the interface{} type in order to allow any other type to be used in its place.

type Generic interface{}

This allows us to use Generic as the parameter and return types which allows us to accept and return any concrete type in our functions. You can leave this bit out and just replace all references to Generic with interface{}.

So let’s start with the Map function. The idea of Map is that it takes a list and a function. After the call to Map, a list is returned that consists of each element of the list transformed by the function that was passed in. As such, the function passed in must take one Generic and return one Generic. In most implementations of Map (in order to maintain referential transparency), they will return a new list rather than modifying the existing list in place. We’re going to follow that convention here.

Here’s what our Map function looks like in Go:

func Map(xs []Generic, f func (x Generic) Generic) []Generic {
    result := make([]Generic, len(xs))
    for i,x := range xs {
        result[i] = f(x)
    }

    return result
}

Reduce follows similar concept. It also takes a list and function, but instead of returning a list that is modified by the function, it combines or reduces the given list into a final result (which might be a list as well, but doesn’t have to be). So the function it takes requires two parameters instead of one. The first parameter will be the next unprocessed element in the list and the second parameter will be the results of the calculation up to this point. In addition, Reduce requires a third parameter. This third parameter is the initial value of the result. Again, as with Map, the passed in list is not modified.

Here’s what Reduce looks like:

func Reduce(xs []Generic, f func (x, sofar Generic) Generic, start Generic) Generic {
    result := start
    for _,x := range xs {
        result = f(x, result)
    }

    return result
}

So with the implementation of these functions out of the way, there are two important notes to make. First of all, you lose a lot of the type safety of the compiler. The Go compiler can no longer determine if the function you pass in to Map or Reduce actually works on the values that you pass into the function. This check now happens at runtime, so instead of happy compiler errors when you make a mistake, you get unhappy crashes. That means the programmer needs to be more disciplined with their code and they need to test more thoroughly. Second, the functions you pass in must be aware of the types you are using in the lists. This can get particularly complicated if you use list that aren’t of a uniform type. I recommend against that.

As an example of my second point, I’m going to demonstrate how to use Map and how I’m making the passed in function aware of what type we’re operating on.

Map([]Generic{10,20,30}, func (x Generic) Generic {
    return x.(int) * x.(int)
})

As you can see, I had to cast x to an int in order to perform that operation. If you didn’t do this, the compiler would complain of unsupported operations on x (or something of that nature). This actually highlights another weakness of these functions: the functions you pass in still won’t be generic (unless you do quite a bit of extra work). In any case, this call returns a list that looks like this: []Generic{100,400,900}.

Here’s an example using Reduce. We’re going to simply sum up the values in a list and return the sum.

Reduce([]Generic{10,20,30}, func (x, sofar Generic) Generic {
    return sofar.(int) + x.(int)
}, 0)

Again, you have to cast inside the passed in function to make sure the operations are possible. This call to reduce returns a Generic with a concrete type of int and a value of 60.

To make the functions you’re passing in to Map and Reduce more flexible and more generic, you might consider using a type switch, but that’s beyond the scope of this article.

One last thing I’d like to point out (this is my favorite part). If we combine Map and the use of a goroutine and channels we can actually begin using the results of the map before the entire Map function has returned. Here’s an example that calls Map as a new goroutine and then processes each element of the new list as they are available rather than waiting for the entire new list to be returned:

c := make(chan int)
xs := []Generic{10,20,30,40,50}
go Map(xs, func (x Generic) Generic {
    res := x.(int) * x.(int)
    c <- res
    return res
}

for i := 0; i < len(xs); i++ {
    val := <-c
    fmt.Println(val)
}

Map is calculating the square of each element of the list. Each time it has calculated a value is sends that value over a channel. The values are then received on the other end of the channel and simply printed out. This is just a toy example, but it highlights the usefulness of goroutines and communicating via channels. To make this last example more efficient, a version of Map should be created that doesn’t create a new list, and instead has the channel communication built-in. That would be a trivial modification, so I’ll leave it to the reader.

I don’t know that all this is the best approach to implementing these types of functions. You lose type safety, but gain a bit of flexibility. You also get to play with goroutines and channels in a marginally interesting way. Hopefully someone can find some more useful applications of these approaches, but even more than that, I hope that Go finds generics fairly soon. Only time will tell.

Another common tool in functional programming are streams or infinite lists. Someone else created an implementation of this for Go here: https://github.com/keep94/gofunctional2

Posted in Go | Tagged , | Comments Off

Centos install Vbox guest additions

As root (or sudo):

yum groupinstall "Development Tools"

yum install kernel-devel

go to vbox guess additions mount (something like /media/VBOXADDITIONS_4.1.10_76795/) and run

./VboxLinuxAdditions.run

init 6

 

Posted in centos | Comments Off

installing xdebug on macos x with xampp

Below copy and pasted from http://xdebug.org/find-binary.php where you can get tailored instructions on how to install xdebug specific to your system (as long as you can provide your phpinfo output) … the bolded text is my modifications …

Summary

* Xdebug installed: no
* Server API: Apache 2.0 Handler
* Windows: no
* Zend Server: no
* PHP Version: 5.3.1
* Zend API nr: 220090626
* PHP API nr: 20090626
* Debug Build: no
* Thread Safe Build: no
* Configuration File Path: /Applications/XAMPP/xamppfiles/etc
* Configuration File: /Applications/XAMPP/xamppfiles/etc/php.ini
* Extensions directory: /Applications/XAMPP/xamppfiles/lib/php/php-5.3.1/extensions/no-debug-non-zts-20090626

Instructions

1. Download xdebug-2.1.2.tgz
2. Unpack the downloaded file with tar -xvzf xdebug-2.1.2.tgz
3. Run: cd xdebug-2.1.2
4.

Run: phpize

As part of its output it should show:

Configuring for:

Zend Module Api No: 20090626
Zend Extension Api No: 220090626

If it does not, you are using the wrong phpize. Please follow this FAQ entry and skip the next step.
5. Run: ./configure CFLAGS=”-arch i386 $CFLAGS” CCFLAGS=”-arch i386 $CCFLAGS” CXXFLAGS=”-arch i386 $CXXFLAGS” LDFLAGS=”-arch i386 $LDFLAGS”
6. Run: make
7. Run: cp modules/xdebug.so /Applications/XAMPP/xamppfiles/lib/php/php-5.3.1/extensions/no-debug-non-zts-20090626
8. Edit /Applications/XAMPP/xamppfiles/etc/php.ini and add the line
zend_extension = /Applications/XAMPP/xamppfiles/lib/php/php-5.3.1/extensions/no-debug-non-zts-20090626/xdebug.so
9. Restart the webserver.

Posted in Uncategorized | Comments Off

cloning problem with centos

When you clone a centos 6 server and have it create a new mac address then it uses eth1 (your new network adapter) while keeping eth0 as the old mac address. so when you try and initials eth0 you would get something like ‘Cannot find device “eth0″‘. Since your no longer using the old eth0 we will just delete it and rename eth1 as eth0. we do that by ….

#sudo vi /etc/udev/rules.d/70-persistent-net.rules

delete the eth0 line and then edit the eth1 line to be eth0

so this …

#PCI device 0x8086:0x100e (e1000) (custom name provided by external tool)
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="[OLD MAC ADDRESS]", ATTR{type}=="1", KERNEL=="eth*", NAME=="eth0"

#PCI device 0x8086:0x100e (e1000)
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="[NEW MAC ADDRESS]", ATTR{type}=="1", KERNEL=="eth*", NAME=="eth1"

becomes …

#PCI device 0x8086:0x100e (e1000)
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="[NEW MAC ADDRESS]", ATTR{type}=="1", KERNEL=="eth*", NAME=="eth0"

and then save and exit and then run

# sudo vi /etc/sysconfig/network-scripts/ifcfg-eth0

and change the line that says

HWADDR="[OLD MAC ADDRESS]"

to

HWADDR="[NEW MAC ADDRESS]"

then just restart and eth0 will be your network interface

Posted in centos | Comments Off

sendmail with attachments

Copy the below script and run. it has all the information you should need in the comments (found at http://www.unix.com/faq-submission-queue/9417-multiple-attachments.html)
many thanks!

#! /usr/bin/ksh
#!/usr/local/bin/bash

# FOUND AT: http://www.unix.com/faq-submission-queue/9417-multiple-attachments.html
#
#  This script takes ascii files, assembles them into a mime compliant
#  message and mails them.  You can send ascii attachments.  A recipient
#  with a mime aware user agent will be able to use the agent's built-in
#  tools for attachments.  On the other hand, a recipient with an older
#  non-mime user agent will see a message that is completely in ascii and
#  will be able to easily chop the pieces up manually.
#
#
#  Options 
#
#  -t to address (required)
#  -T to name    (optional)
#  -f from addr  (optional)
#  -F from name  (optional)
#  -b body       (optional)
#  -s subject    (optional)
#  -A attachment (optional)
#  -B attachment (optional)
#  -X attachment (optional)
#  -D description(optional)
#
#  mimesender -t "Joe Blow" -T jblow@abc.com  -b body.txt  -A attach.txt
#
#  Here body.txt and attach.txt are files.  The name of the body file
#  isn't too important.  The name of the attachment file is important 
#  since it will be sent as well as the contents.  A Microsoft OS uses
#  the name to figure out what to do.  It knows what a .txt file is but
#  it will get mixed up with a .junk file. You can use the -D option to 
#  send one a different name like this:
#  mimesender -t jblow@abc.com -T "Joe Blow" -b body -A junk -D junk.txt
#
#  You can use several -t -T pairs to indicate multiple recipients.  The number
#  of pairs is limits by your shell's limit on array elements.
#
#  Here the attachment will come from a local file called "junk" but will
#  be sent with a name of "junk.txt".
#
#  Either the body or an attachment can be - in which case it will be read
#  from the script's standard in.  If you do this with an attachment, a -D
#  would be especially useful.  Only one item, either the body or an 
#  attachment can come from standard in.
#
#  Multiple attachments can be sent by using several -A options.  A -D 
#  always refers to the last -A ( or -B or -X, see below) that preceded 
#  it.  Each attachment specified by a -A can be followed by a -D to 
#  rename it at the recieving end.  The number of  -A and -D pairs is 
#  limited only by your shells limit on an array.  ksh will
#  always allow at least 512 elements.  bash allows more than that. 
#
#  -B is like -A, but it is for binary attachments.  They will be uuencoded
#  before being sent.
#
#  -X is like a hybrid of -A and -B.  The attachment is ascii, but it will 
#  be uuencoded anyway.  But before it is uuencoded, it will have the 
#  newline characters replaced with LF/CR pairs.
#
#  By default, this script will use the unix id which is running it as the
#  "From:" address.  And it will poke around in the GCOS field of /etc/passwd
#  to get the name of the user.  You can override the the name with the -F 
#  option.  This is fairly innocuous.  Many version of unix allow you to run
#  a command to update your GCOS field, and you can use that to change your
#  name, send some mail, and change it back.  The -F just saves you some time.
#  You can use -F to send mail under your screen name, or whatever.
#
#  I have also included a -f to override the address on the "From:" line.  
#  The -f may or may not work, it depends on your MTA's security policy.  If 
#  it works at all, you must use a local address.  If you use a -f, the script
#  will also output a "Sender:" line with the real id running the script.  With
#  or without that "Sender:" line, the MTA's that I have tested ensure that a
#  mail expert on the receiving system can determine the real sender.  Use -f
#  with caution, please.  You must ensure that the address you specify can
#  receive replys.  
#
#  -d is a secret debug option.

#############################################################
#                                                           #
#    Section 0 ---  Customization                           #
#                                                           #
#############################################################
#
#  You may need to customize a few things:
#  1  You must set the first line above to be the path to 
#     a shell.  mimesender will work with either ksh or bash.
#     The variable "this_shell" should then automatically set
#     itself to the shell you used based on the existence or
#     non-existence on the bash variable BASH_VERSION.  The 
#     rest of the script will check this_shell as needed.  Note
#     that a recent version of bash will be needed as it must
#     support arrays.  If you have both ksh and bash available,
#     go with ksh for the best performance.
#
#  2  Your PATH must contain the commands cat and id and sed
#     For binary attachment, your PATH must also include 
#     uuencode
#
#  3  MTA must be set to the path to your Mail Transfer Agent
#
#  4  BOUNDARY must be a string that is not used in the files
#     you want to mail.  Actually it must not appear on a line
#     by itself prepended with two hyphens.  This script can 
#     mail itself.
#
#  5  pwentry must be set to the user's entry from /etc/passwd
#     If you are using nis or nis+, or something, you must use
#     niscat or whatever.  pwentry will be treated as a bunch of
#     colon delimited fields.  Field one will be used for the 
#     sender's email address.  Field four will be treated as bunch
#     of comma delimited sub-fields.  The first one will be used as
#     the sender's name.  This is the standard way that unix mailers
#     have always worked.
#     

[[ -n $BASH_VERSION ]] && this_shell=bash || this_shell=ksh
PATH=/usr/bin
export PATH
MTA=/usr/lib/sendmail
BOUNDARY='=== This is the boundary between parts of the message. ===--'
pwentry=$(grep "^$(id -un):" /etc/passwd)

################################################################
####  In theory you should not need to touch anything else  ####
################################################################


#############################################################
#                                                           #
#    Section 0 ---  Initialization                          #
#                                                           #
#############################################################

#
#  For shell independence, mimesender does its outputting via the functions:
#  scribe_out and scribe_err.  Here we define these functions for the
#  current shell.
#

if [[ $this_shell = ksh ]] ; then
        scribe_out() { print - ${1+"$@"} ; }
        scribe_err() { print -u2 - error: ${1+"$@"} ; }
else
        scribe_out() { echo -E ${1+"$@"} ; }
        scribe_err() { echo -E error: ${1+"$@"} >&2 ; }
fi



#
#  Debugging features

DEBUG=0
DEBUGFILE=mimesender$$

if [[ $this_shell = ksh ]] ; then
        scribe_debug() { ((DEBUG)) && print -u2 - DEBUG: ${1+"$@"} ; }
else
        scribe_debug() { ((DEBUG)) && echo -E DEBUG: ${1+"$@"} >&2 ; }
fi

debug_mta() 
{
	exec 4>&1 >$DEBUGFILE
	scribe_out
	scribe_out
	while (($#)) ; do scribe_out mta arg = "$1" ; shift ; done
	scribe_out
	scribe_out start of mail
	while read l ; do scribe_out "$l" ; done
	scribe_out end of mail
	exec 1>&4 4>&-
}

#
#  Initialize variables

VERSION=0.0
IFS=""

if [[ $this_shell = ksh ]] ; then
	set -A TADDR 
	set -A TNAME 
	set -A ATTACH 
	set -A FORMAT 
	set -A DESC
else
	declare -a TADDR TNAME ATTACH FORMAT DESC
fi

((naddr=0))
((nattach=0))
((stdin_inuse=0))
((error=0))
((npart=0))

preamble1="\
        This message is in MIME format.  But if you can see this,
        you aren't using a MIME aware mail program.  You shouldn't 
        have too many problems because this message is entirely in
        ASCII and is designed to be somewhat readable with old 
        mail software."
preamble2="
        This message is in MIME format.  But if you can see this,
        you aren't using a MIME aware mail program.  Some parts of
        of this message have been uuencoded for transport.  On a Unix
        system, the program uudecode should be used to restore the file."
PREAMBLE="$preamble1"

AType="text/plain"
BType="application/octet-stream"

if [[ $this_shell = ksh ]] ; then
	CR="$(print \\r)"
else
	CR="$(echo -e \\r)"
fi


#############################################################
#                                                           #
#    Section 1 ---  Parameter Parsing and Checking          #
#                                                           #
#############################################################

#
#  Parse the command arguments

while getopts ':df:F:t:T:b:A:B:D:X:s:' opt ; do
	case $opt in
	d)	DEBUG=1
		MTA=debug_mta
		scribe_debug Debug Mode is on...no mail will be sent
		;;
	f)	FADDR=$OPTARG
		;;
	F)	FNAME=$OPTARG
		;;
	t)
		TADDR[naddr]=$OPTARG
		TNAME[naddr]=""
		((naddr=naddr+1))
		;;
	T)
		if ((naddr)) ; then
			TNAME[naddr-1]=$OPTARG
		else
			scribe_err -T must follow -t
			((error=error+1))
		fi
		;;
	b)
		BODY=$OPTARG
		((npart=npart+1))
		;;
	A|B|X)
		[[ $opt = A ]] || PREAMBLE="$preamble2"
		ATTACH[nattach]=$OPTARG
		if [[ $OPTARG = - ]] ; then
			DESC[nattach]=stdin
		else
			DESC[nattach]=$OPTARG
		fi
		FORMAT[nattach]=$opt
		((nattach=nattach+1))
		((npart=npart+1))
		;;
	D)
		if ((nattach)) ; then
			DESC[nattach-1]=$OPTARG
		else
			scribe_err -D $optarg must follow a -A argument
			((error=error+1))
		fi
		;;
	s)
		SUBJECT=$OPTARG
		;;
	\?)
		scribe_err what is -${OPTARG}?
		((error=error+1))
		;;
 :) 
		scribe_err $OPTARG need an argument
		((error=error+1))
		;;
	esac
done

#
#  Parameter error checking: an address is required

if ((!naddr)) ; then
	scribe_err "-t ADDRESS is required"
	((error=error+1))
fi


#
#  Parameter error checking: If BODY  was specified, it
#  must exist and be readable

if [[ ! -z $BODY ]] ; then
	if [[ $BODY != - ]] ; then
		if [[ ! -f $BODY ||  ! -r $BODY ]] ; then
			scribe_err  "-b $BODY is not a readable file"
			((error=error+1))
		fi
	else
		stdin_inuse=1
	fi
fi

#
#  Parameter error checking: If ATTACH was specified, it
#  must exist and be readable.  
#  Also we can use stdin only once

i=0
while ((i<nattach)); do
	if [[ ${ATTACH[i]} = - ]] ; then
		if ((stdin_inuse)) ; then
			scribe_err  only one item may come from stdin
			((errors=errors+1))
		else
			stdin_inuse=1
		fi
	else
		if [[ ! -f ${ATTACH[i]} ||  ! -r ${ATTACH[i]} ]] ; then
			scribe_err  -A ${ATTACH[i]} is not a readable file
			((error=error+1))
		fi
	((i=i+1))
	fi
done

#
#  FADDR must not have a @ in it.

if [[ $FADDR = *@* ]] ; then
	scribe_err You cannot specify a remote \"From:\" address
	((error=error+1))
fi

#
# We will abort now if we didn't like our parameters

if ((error)) ; then
	scribe_err "at least one fatal error was detected...exiting"
	exit 1
fi



#############################################################
#                                                           #
#    Section 2 ---  Build Header, Preamble, and Body        #
#                                                           #
#############################################################

#
#  Get user's name and address from the system


scribe_debug pwentry = $pwentry
if [[ $this_shell = ksh ]] ; then
	((index=0))
	while [[ $pwentry = *:* ]] ; do
		pwfield[index]=${pwentry%%${pwentry##*([!:])}}
		pwentry=${pwentry##*([!:]):}
		((index=index+1))
	done
	pwfield[index]=${pwentry}
	myname=${pwfield[4]%%,*}
	myaddr=${pwfield[0]}
else
	myaddr=$(echo "$pwentry" | sed 's/\([^:]*\).*$/\1/')
	myname=$(echo "$pwentry" | \
			sed 's/[^:]*:[^:]*:[^:]*:[^:]*:\([^,:]*\).*$/\1/')
fi

scribe_debug myaddr = $myaddr
scribe_debug myname = $myname


#
# NB the following brace.  It is the start of the stuff piped to the MTA

{

#
#  Start with the "From:" Address

if [[ -n $FADDR ]] ; then
	if [[ -n $FNAME ]] ; then
		scribe_out "From: $FNAME <${FADDR}>"
	else
		scribe_out "From: $myname <${FADDR}>"
	fi
	scribe_out  "Sender: $myname <${myaddr}>"
elif [[ -n $FNAME ]] ; then
	scribe_out "From: $FNAME <${myaddr}>"
else
	scribe_out  "From: $myname <${myaddr}>"
fi

#
#  Next we will do the "To:" Addresses

((i=0))
Line=""
while ((i<naddr)) ; do
	if [[ -n ${TNAME[i]} ]] ; then
		Addition="${TNAME[i]} <${TADDR[i]}>"
	else
		Addition="${TADDR[i]}"
	fi

	if [[ -n $Line &&  $((${#Line}+${#Addition})) -gt 75 ]] ; then
		scribe_out "$Line"
		Line=""
	fi

	if [[ -z $Line ]] ; then
		Line="To: $Addition"
	else
		Line="$Line, $Addition"
	fi
	((i=i+1))
done
scribe_out "$Line"

#
#  Some misc header lines

if [[ -n $SUBJECT ]] ; then
	scribe_out  'Subject:' $SUBJECT
fi
scribe_out  'X-Mailer: mimesender' $VERSION
scribe_out  'Mime-Version: 1.0'

#
#  Output Mime Preamble if there are multiple parts

if ((npart>1)) ; then
	scribe_out  'Content-Type: multipart/mixed; '
	scribe_out  '    boundary='\"$BOUNDARY\"
	scribe_out 
	scribe_out  "$PREAMBLE"
	scribe_out 
fi

#
#  Output message body if we have one.

if [[ -n $BODY ]] ; then
	if ((npart>1)) ; then
		scribe_out  "--${BOUNDARY}"
	fi
	scribe_out  'Content-Type: text/plain; charset=US-ASCII'
	scribe_out 
	if [[ $BODY = - ]] ; then
		cat
	else
		cat $BODY
	fi
else
	scribe_out
fi

#############################################################
#                                                           #
#    Section 3 ---  Attachments                             #
#                                                           #
#############################################################
#

#
#  Loop on our attachments... 

i=0
while ((i<nattach)) ; do
	scribe_debug Attachment $i ${ATTACH[i]} ${FORMAT[i]} ${DESC[i]}

#
#  If we are in mutipart mode, do a boundary

	if ((npart>1)) ; then
		scribe_out  "--${BOUNDARY}"
	fi

#
#  Build attachment header

	if [[ ${FORMAT[i]} = B ]] ; then
		TYPE=$BType
	else
		TYPE=$AType
	fi
	scribe_out  'Content-Type: '${TYPE}'; name="'${ATTACH[i]}\"

	if [[ ${FORMAT[i]} != A ]] ; then
		scribe_out "Content-Transfer-Encoding: x-uue"
	fi

	scribe_out  'Content-Disposition: attachment; filename="'${DESC[i]}\"
	scribe_out 

#
#  Build a pipeline to process the attachment

	if [[ ${ATTACH[i]} = - ]] ; then
		PIPELINE="cat"
	else
		PIPELINE="cat ${ATTACH[i]}"
	fi
	[[ ${FORMAT[i]} = X ]] && PIPELINE=${PIPELINE}"| sed \"s/$/\${CR}/\""
	[[ ${FORMAT[i]} != A ]] && PIPELINE=${PIPELINE}"|uuencode ${DESC[i]}"
	scribe_debug PIPELINE = "$PIPELINE"
	eval $PIPELINE

	scribe_out 
	((i=i+1))
done

#############################################################
#                                                           #
#    Section 4 ---  Send Mail                               #
#                                                           #
#############################################################
#

#
#  If in multipart mode, do final boundary

if ((npart>1)) ; then
	scribe_out  "--${BOUNDARY}--"
fi

#
#  Here is where we send the mail

} | eval $MTA ${TADDR[@]}

if ((DEBUG)) ; then
	while read l ; do scribe_debug "$l" ; done < $DEBUGFILE
	rm $DEBUGFILE
fi

exit 0
Posted in Uncategorized | Comments Off

Installing LAMP on CentOs 6

This is based off of a minimal install from the full dvd iso. these are the commands that i used when setting up my LAMP server with centos 6. Please note it doesn’t include configuration nor setting up the hostname. Mostly I put this here for my benefit … if you have questions ask.

###############################
# if not static get ip
###############################
sudo dhclient eth0

###############################
# get up to date
###############################
sudo yum update

###############################
# add epel repo
###############################
sudo rpm -Uvh http://download.fedora.redhat.com/pub/epel/6/x86_64/epel-release-6-5.noarch.rpm
# verify it worked
sudo yum check-update

###############################
# add atomic repo
###############################
#first try
sudo wget -q -O – http://www.atomicorp.com/installers/atomic | sh

#if that doesn’t work then figure out the correct url and do
sudo rpm -Uvh http://atomicorp.com/channels/atomic/centos/6/x86_64/RPMS/atomic-release-1.0-14.el6.art.noarch.rpm
# verify it worked
sudo yum check-update

###############################
# make sure were up to date
###############################
sudo yum update

###############################
# install httpd
###############################
sudo yum install httpd httpd-utils httpd-devel mod_auth_mysql

###############################
# httpd service commands (basic)
###############################
sudo service httpd start
sudo service httpd stop
sudo service httpd restart
sudo service httpd graceful
sudo service httpd status
sudo service httpd fullstatus
sudo service httpd configtest

###############################
# some debugin commands to see if apache is listening
###############################
netstat -lan | grep 80
sudo fuser 80/tcp
ps aux | grep 1547 | grep -v grep
pgrep httpd

###############################
# have httpd start every time
###############################
sudo chkconfig –level 235 httpd on

###############################
# files to edit for httpd
# default website directory /var/www/html/
###############################
sudo vi /etc/httpd/conf/httpd.conf
sudo vi /etc/httpd/conf.d/vhost.conf

###############################
# install php
# config directory /etc/php.d/
###############################
sudo yum install php php-devel php-mysql phpmyadmin php-pear php-pecl-memcache php-pecl-apc php-xmlrpc php-xml php-pecl-imagick php-mhash php-soap php-gd

###############################
# install mysql
###############################
sudo yum install mysql mysql-server mysql-bench mysql-devel
# useful (recommended) commands
sudo mysql_secure_installation

###############################
# mysqld service commands (basic)
###############################
sudo service mysqld start
sudo service mysqld stop
sudo service mysqld restart

###############################
# some debugin commands to see if mysqld is listening
###############################
netstat -lan | grep 3306
perror [error_code]

# from other computer known to be able to connect to mysql server remotely
mysql -u root -p -h [DB_SERVER_IP] #failure is error 113

###############################
# have mysqld start every time
###############################
sudo chkconfig –level 235 mysqld on

###############################
# files to edit for mysqld
###############################
sudo vi /etc/my.conf

###############################
# extra packages for debug etc
###############################
sudo yum install elinks
sudo yum install vim
sudo yum install iftop
sudo yum install man
sudo yum install git

###############################
# iptables
###############################
# commands
sudo iptables -L
sudo iptables-save > firewall-config
sudo iptables-restore < firewall-config
sudo service iptables save
sudo service iptables stop
sudo service iptables start

# entries to allow http https
-A INPUT -p tcp -m tcp –dport 80 –tcp-flags SYN,RST,ACK SYN -j ACCEPT
-A INPUT -p tcp -m tcp –dport 443 –tcp-flags SYN,RST,ACK SYN -j ACCEPT

# entries to allow mysql in general (can add -i eth0 for interface specific)
-A INPUT -p tcp -m tcp –dport 3306 -j ACCEPT

# entries to allow mysql to be connected to from a specific web server
-A INPUT -p tcp -s [WEB_SERVER_IP] –sport 1024:65535 -d [DB_SERVER_IP] –dport 3306 -m state –state NEW,ESTABLISHED -j ACCEPT
-A OUTPUT -p tcp -s [DB_SERVER_IP] –sport 3306 -d [wEB_SERVER_IP] –dport 1024:65535 -m state –state ESTABLISHED -j ACCEPT

# entries to allow mysql client to connect to mysql server indepenent of ip
-A OUTPUT -p tcp -s [WEB_SERVER_IP] –sport 1024:65535 -d 0/0 –dport 3306 -m state –state NEW,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -s 0/0 –sport 3306 -d [WEB_SERVER_IP] –dport 1024:65535 -m state –state ESTABLISHED -j ACCEPT

# example iptables-save output (with http and https allowed)
————
# Generated by iptables-save v1.4.7 on Tue Nov 29 08:11:28 2011
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [33:2300]
-A INPUT -m state –state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp –dport 80 –tcp-flags SYN,RST,ACK SYN -j ACCEPT
-A INPUT -p tcp -m tcp –dport 443 –tcp-flags SYN,RST,ACK SYN -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state –state NEW -m tcp –dport 22 -j ACCEPT
-A INPUT -j REJECT –reject-with icmp-host-prohibited
-A FORWARD -j REJECT –reject-with icmp-host-prohibited
COMMIT
# Completed on Tue Nov 29 08:11:28 2011
————

Posted in apache, centos, LAMP, mysql, php | Comments Off

Change Date From UTC To Local And Back

The Magento Database times are stored UTC and when I do direct queries on the database the date/times entered by the user are for the local timezone. I created a couple functions to switch back and forth. Originally these functions were in a model but i have adapted them to be stand alone functions. After I went through all that work it appears that in the Mage_Core_Model_Locale there are already functions to do that(storeDate and utcdate).

<?php
function gmtToLocal($datetime,$showFormat = true){
        $_date_format = 'm/d/y g:i a';
        $_date_format_db = 'Y-m-d H:i:s';

        //default timezone is UTC or GMT
        $time = strtotime($datetime);

        $tz = Mage::app()-&gt;getStore()-&gt;getConfig('general/locale/timezone');
        $oldzone = @date_default_timezone_get();
        $result = date_default_timezone_set($tz);

        $return = date((($showFormat == false)?$_date_format_db:$_date_format),$time);

        date_default_timezone_set($oldzone);

        return $return;
    }

    function localToGmt($datetime,$showFormat = false){
        $_date_format = 'm/d/y g:i a';
        $_date_format_db = 'Y-m-d H:i:s';

        //default timezone is UTC or GMT
        $tz = Mage::app()-&gt;getStore()-&gt;getConfig('general/locale/timezone');
        $oldzone = @date_default_timezone_get();
        $result = date_default_timezone_set($tz);

        $return = gmdate((($showFormat == false)?$_date_format_db:$_date_format),strtotime($datetime));

        date_default_timezone_set($oldzone);

        return $return;
    }
?>
Posted in Magento, php, time | Comments Off

Installer Add Product Attribute

Here is an installer that will add a product attribute to any number of sets and to a group (borrowed a portion from a blog which I no longer can remember as it was ages ago…if it was yours please enter a link):

<?php
    $installer = $this;
    $installer->startSetup();

    $newFields = array(
        '[attribute_code]' => array(
            'type'              => 'text',
            'label'             => '[attribute_code]',
        ),
    );

    $entities = array(
        'catalog_product',
    );

    $attributeSets = array(
        "[set_one]",
        "[set_two]", //Etc
    );

    $attributeGroup = "[group_to_add_to]";

    $setup = new Mage_Eav_Model_Entity_Setup('core_setup');
    foreach($newFields as $attributeName => $attributeDefs) {
        foreach ($entities as $entity) {
            $setup->addAttribute($entity, $attributeName, array(
                'type'                          => $attributeDefs['type'],
                'label'                         => $attributeDefs['label'],
                'class'                         => '',
                'required'                      => false,
            ));
            foreach($attributeSets as $set){
                $setup->addAttributeToSet($entity,$set,$attributeGroup,$attributeName);
            }
        }
    }

    $installer->endSetup();
?>
Posted in Magento, php | Comments Off

Installer Add Sales Order Item Attribute

Installer to add an attribute to a Sales Order Item


<?php

    $installer = $this;
    $installer->startSetup();

    $read = $installer->getConnection('read');
    $query = "SHOW COLUMNS FROM `sales_flat_order_item` WHERE `Field`='[attribute_code]'";
    $result = $read->fetchAll($query);
    if(count($result) === 0){
        $installer->run("ALTER TABLE `sales_flat_order_item` ADD COLUMN [attribute_code] varchar(255)");
    }
    $installer->endSetup();
?>

Posted in Magento, php | Comments Off