ADF Super Code Snippets

Oracle’s ADF (Application Developer Framework) is J2EE technology stack to rapidly develop enterprise applications. As with all enterprise applications, ADF focuses on data handling and makes it quite easy to present the data to the users in variety of ways. As you will already know that ADF is a blanket term which encompasses many layers of the full tech stack. So ADF is divided into: –
* ADF Faces – Based on Java Server Faces 1.2 specification, this provides the UI of the application. It is built over Apache MyFaces Trinidad 1.2.x. So this is the View layer of ADF stack.
* ADFc – ADF Controller controls the life cycle of a typical ADF application. In fact it is part of ADF Faces. ADF Task Flows too form part of this layer.
* ADFm – ADF Model provides the brick and mortar to bind ADF Faces to the Model layer. In fact ADFm includes the Binding layer. This allows for loose coupling between the View and Model layers.
* ADF BC – ADF Business Components form the Model layer. It forms the data abstraction layer which does quite a lot of heavy lifting for the ADF stack.

The aim of this post is to list out some tips and code snippets which you may undoubtedly need while coding in ADF.

Some Important notes first

1 Clearing the selection on a ADF tree/tree-table/table from bean

First make sure the tree or tree-table or table does not have selectedRowKeys attribute set. Now you will notice that no row will be selected when the tree loads for the first time, but when user makes a selection then tree builds and stores the RowKeySet of the node the user selected. So, now whenever the tree loads and if the last selected row is visible then it will be shown selected. To work around this, we need to manually clear the tree’s selected rowkeyset after the user has made his selection (e.g. When we hide the tree, just before the tree is shown). Use the following code for that:-

RowKeySet rks = getTree().getSelectedRowKeys();
if (rks != null) {
    rks.clear();
}

2 Get the VO bound to an iterator

Sometimes we may need to manually execute an iterator, for this we need to get the handle to the VO instance bound to an iterator.

private ViewObject getVOFromIterator(DCIteratorBinding it) {
    ViewObject vo = null;
    if (it.hasRSI()) {
        return it.getRowSetIterator().getRowSet().getViewObject();
    } else {
        return it.getViewObject();
    }
}

3 Programmatically add partial target

AdfFacesContext.getCurrentInstance().addPartialTarget(targetComponent);

Make sure that targetComponent is not null else we may get NullPointerException.

4 Get query entered by user in Adf quickQuery component

QueryDescriptor qd = queryEvent.getDescriptor();
AttributeCriterion ac = qd.getCurrentCriterion();
String attrLabel = ac.getAttribute().getLabel();
Object attrValue = ac.getValues().get(0);

Note if you try ac.getValues() then it will mention that it has zero elements, even when get(0) returns a value.

5 Building Disclosed RowKeySet for nodes in a tree/tree-table

/**
* Ref: http://www.oracle.com/technetwork/developer-tools/adf/learnmore/61search-in-rendered-trees-177577.pdf
* @param treeBinding
* @param keys
* @return
*/
private RowKeySet buildDiscloseRowKeySet(JUCtrlHierBinding treeBinding, RowKeySet keys) {
    RowKeySetImpl discloseRowKeySet = new RowKeySetImpl();
    Iterator iter = keys.iterator();
    while (iter.hasNext()) {
        List keyPath = (List)iter.next();
        JUCtrlHierNodeBinding node = treeBinding.findNodeByKeyPath(keyPath);
        if (node != null && node.getParent() != null && !node.getParent().getKeyPath().isEmpty()) {
            //store the parent path
            discloseRowKeySet.add(node.getParent().getKeyPath());
            //call method recursively until no parents are found
            RowKeySetImpl parentKeySet = new RowKeySetImpl();
            parentKeySet.add(node.getParent().getKeyPath());
            RowKeySet rks = buildDiscloseRowKeySet(treeBinding, parentKeySet);
            discloseRowKeySet.addAll(rks);
        }
    }
    return discloseRowKeySet;
}

6 Select a node in tree/tree-table

Variant 1

private void selectNode(List<List<?>> pathKeys, org.apache.myfaces.trinidad.component.UIXTree targetComponent) {
    List<Object> lstKeys = new ArrayList<Object>();
    for(int level = 0; level < pathKeys.size(); level++) {
        List<?> keys = pathKeys.get(level);
        Object[] oKeys = new Object[keys.size()];
        for (int index = 0; index < oKeys.length; index++) {
            oKeys[index] = keys.get(index);
        }
        lstKeys.add(new Key(oKeys));
    }
    if(lstKeys.size() == 1) {
        lstKeys = Collections.singletonList(lstKeys.get(0));
    } else {
        lstKeys = Collections.unmodifiableList(lstKeys);
    }
    RowKeySet keyset = new RowKeySetImpl();
    keyset.setCollectionModel((CollectionModel)(targetComponent.getValue()));
    keyset.add(lstKeys);
    targetComponent.setSelectedRowKeys(keyset); //After this targetComponent.setDisclosedRowKeys()
                                                //needs to be called to reveal the node is its parents
                                                //are collapsed.
}

Where pathKeys is of the following form:- Take an example, where we want to select node C, in the following tree.

A [Row from VO1, keys A1]
|--B [Row from VO2, keys B1, B2, B3]
    |--C [Row from VO3, keys C1, C2]

Then pathKeys will be a list like shown below:-

{ {A1}, {B1, B2, B3}, {C1, C2} }

Variant 2 (Maybe this is a better approach, but not tested)

private void selectNode(List<List<?>> pathKeys, org.apache.myfaces.trinidad.component.UIXTree targetComponent) {
    List<Object> lstKeys = new ArrayList<Object>();
    for(int level = 0; level < pathKeys.size(); level++) {
        List<?> keys = pathKeys.get(level);
        Object[] oKeys = new Object[keys.size()];
        for (int index = 0; index < oKeys.length; index++) {
            oKeys[index] = keys.get(index);
        }
        lstKeys.add(new Key(oKeys));
    }
    if(lstKeys.size() == 1) {
        lstKeys = Collections.singletonList(lstKeys.get(0));
    } else {
        lstKeys = Collections.unmodifiableList(lstKeys);
    }
    JUCtrlHierBinding treeBinding = (JUCtrlHierBinding) ((CollectionModel)targetComponent.getValue()).getWrappedData();
    JUCtrlHierNodeBinding nodeBinding = treeBinding.findNodeByKeyPath(lstKeys);
    Key rowKey = nodeBinding.getRowKey();
    JUIteratorBinding iterator = nodeBinding.getIteratorBinding();
    iterator.setCurrentRowWithKey(rowKey.toStringFormat(true));
}

7 Create a flexible query (search box) which allows you to use custom ViewCriteria with ADF quickQuery

Custom Quick Query ADF Component

Custom Quick Query ADF Component

To create search box like the one above.

UI code

<af:quickQuery id="qq1" queryListener="#{pageFlowScope.Bean.invokeSearch}"
    searchDesc="Quick Search" shortDesc="Quick Search" label="Quick Search">
    <af:inputText id="itQq1" value="#{pageFlowScope.Bean.searchKeyword}"
        simple="true" partialTriggers="cb3" shortDesc="Quick Search"/>
    <f:facet name="end">
        <af:commandButton text="Clear" id="cb3" actionListener="#{pageFlowScope.Bean.clearSearch}"/>
    </f:facet>
</af:quickQuery>

  • We have defined our own input box so that Go button and the auto-generated input boxes get disabled if quickQuery doesn’t have any model.
  • Our custom input box allows us to directly read and modify the input box’s content. This is needed by Clear functionality.
  • Input box has simple set to true, so that its label is not displayed.
  • Official quickQuery reference – http://jdevadf.oracle.com/adf-richclient-demo/docs/tagdoc/af_quickQuery.html.

Bean code (in Bean.java)

private String searchKeyword;

public String getSearchKeyword() {
    return searchKeyword;
}

public void setSearchKeyword(String keyword) {
    searchKeyword = keyword;
}

public void invokeHierSearch(QueryEvent queryEvent) {
    if (searchKeyword != null && !searchKeyword.isEmpty()) {
        DCIteratorBinding it = ADFUtil.findIterator("VOIterator");
        ViewObject vo = getVOFromIterator(it);
        vo.applyViewCriteria(vo.getViewCriteriaManager().getViewCriteria("SearchCriteria"));
        vo.setNamedWhereClauseParam("keyword", searchKeyword);
        vo.executeQuery(); //Iterator will be executed after UI is updated.
        searchVisible = true;
    } else {
        searchVisible = false;
    }
    AdfFacesContext.getCurrentInstance().addPartialTarget(...); //Update UI
}

public void clearSearch(ActionEvent e) {
    searchKeyword = null;
    invokeHierSearch(null);
}

private ViewObject getVOFromIterator(DCIteratorBinding it) {
    ViewObject vo = null;
    if (it.hasRSI()) {
        return it.getRowSetIterator().getRowSet().getViewObject();
    } else {
        return it.getViewObject();
    }
}

8 Get reference to Bindings from bean

DCBindingContainer bindings = ((DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry());

9 Programmatically execute iterator

DCBindingContainer bindings = ((DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry());
bindings.findIteratorBinding("Iterator").executeQuery();

10 Get reference to method binding (operation binding) in bean

Get bindings from 8.

OperationBinding meth = bindings.getOperationBinding("methodBindingId");
Map args = meth.getParamsMap();
args.put(“arg1”, arg1Value);
…
meth.execute();

11 Get reference to pageFlowScope in bean

AdfFacesContext.getCurrentInstance().getPageFlowScope()

This returns a Map which we can use to read or set values.

12 Evaluate random EL value expressions in bean

FacesContext fc = FacesContext.getCurrentInstance();
ELContext elContext = fc.getELContext();
ExpressionFactory ef = fc.getApplication().getExpressionFactory();
ValueExpression exp = ef.createValueExpression(elContext, "#{expression}", ClassOfOutcomeOfExpression.class);
ClassOfOutcomeOfExpression obj = (ClassOfOutcomeOfExpression) exp.getValue(elContext);

ClassOfOutcomeOfExpression can be Object if you don’t care about the outcome. It has too much boilerplate code.

So place the following code in bean.

private <T> T evaluateEL(String el, Class<T> type) {
    FacesContext fc = FacesContext.getCurrentInstance();
    ELContext elContext = fc.getELContext();
    ExpressionFactory ef = fc.getApplication().getExpressionFactory();
    ValueExpression exp = ef.createValueExpression(elContext, el, type);
    return (T) exp.getValue(elContext);
}

13 Evaluate random EL method expressions in bean

FacesContext fc = FacesContext.getCurrentInstance();
ELContext elContext = fc.getELContext();
ExpressionFactory ef = fc.getApplication().getExpressionFactory();
MethodExpression meth = ef.createMethodExpression(elContext, "#{expression}", Outcome.class, new Class[]{Arg1.class, Arg2.class, …});
Outcome obj = (Outcome) meth.invoke(elContext, new Object[]{arg1Obj, arg2Obj, …});

Example: You need to code the below if you override treetable’s selectionListener.

MethodExpression meth = ef.createMethodExpression(elContext, "#{bindings.treeBinding.treeModel.makeCurrent}",
    Object.class, new Class[]{SelectionEvent.class});
meth.invoke(elContext, new Object[]{selectionEvent});

14 Get value from attribute binding in bean

Get bindings from 8.

((oracle.binding.AttributeBinding)bindings.getControlBinding("bindingName")).getInputValue();

15 Get value from list binding in bean

Get bindings from 8.

((JUCtrlListBinding)bindings.getControlBinding("bindingName")) .attributeValue();

16 Implementing custom selection listener

In this use-case we are providing our own selection listener for the TreeTable because we are interested in capturing the selected node’s VO row instance.

public void onTreeSelect(SelectionEvent selectionEvent) {
    //Invoking makeCurrent manually since it will no longer be called as we have provided our own.
    FacesContext fc = FacesContext.getCurrentInstance();
    ELContext elContext = fc.getELContext();
    ExpressionFactory ef = fc.getApplication().getExpressionFactory();
    MethodExpression meth = ef.createMethodExpression(elContext, "#{bindings.treeBinding.treeModel.makeCurrent}",
        Object.class, new Class[]{SelectionEvent.class});
    meth.invoke(elContext, new Object[]{selectionEvent}); //Selection done now getting data from model.
    RichTreeTable myTree = (RichTreeTable) selectionEvent.getSource(); //changed for Serialization
    RowKeySet rowKeys = selectionEvent.getAddedSet();
    if (rowKeys != null) {
        CollectionModel treeModel = (CollectionModel) myTree.getValue();
        JUCtrlHierBinding treeBinding = (JUCtrlHierBinding) treeModel.getWrappedData();
        Iterator selection = rowKeys.iterator();
        while (selection.hasNext()) {
            //Will loop only once since we have allowed single selection.
            List key = (List) selection.next();
            JUCtrlHierNodeBinding nodeBinding = treeBinding.findNodeByKeyPath(key);
            Row row = nodeBinding.getRow(); //Your custom code which will use row.
                                            //row will be the instance of ViewRowImpl
                                            //which backs the currently selected node.
        }
    }
}

17 Get all rows (nodes) of a Tree or TreeTable

In my use-case I wanted to iterate over all the rows in the TreeTable to find if it has any rows with pending changes. This was to prevent the user from carrying out some actions if there were unsaved changes. There are many ways to achieve this, like check if transaction or view port is dirty, but I did not care about the state of various other components on the page which are outside the tree.

public List<Row> getTreeNodes(CollectionModel treeModel) {
    List<Row> rows = new ArrayList<Row>();
    JUCtrlHierBinding treeBinding = (JUCtrlHierBinding) treeModel.getWrappedData();
    Queue<JUCtrlHierNodeBinding> nodeBindings = new LinkedList<JUCtrlHierNodeBinding>();
    nodeBindings.add(treeBinding.getRootNodeBinding());
    while (!nodeBindings.isEmpty()) {
        List<JUCtrlHierNodeBinding> childNodes = nodeBindings.remove().getChildren();
        if (childNodes != null) {
            for (JUCtrlHierNodeBinding _node : childNodes) {
                nodeBindings.add(_node); rows.add(_node.getRow());
            }
        }
    }
    return rows;
}

18 Programmatically loading resource bundle

Recently I had one requirement where I needed to programmatically load a resource bundle from a managed bean and read the translated strings. I could not find any official documentation on this, and the net is rife with many alternatives which did not work for me. Anyway here is my version which is simple and works well for me.

//import java.util.ResourceBundle;
//import oracle.javatools.resourcebundle.BundleFactory;
ResourceBundle myBundle = BundleFactory.getBundle("fully.qualified.class_name.of.the.bundle");
String msg = getMsg(myBundle, "myKey");

Where the method getMsg() is

public String getMsg(ResourceBundle bundle, String key) {
    if (bundle == null) {
        return "";
    }
    try {
        return bundle.getString(key);
    } catch (MissingResourceException ex) { //Log error here. }
    return "";
}

Please make sure that the bundle class is available on the classpath.

Disclaimer: The views expressed on this blog are my own and do not necessarily reflect the views of my employer. This is may or may not be the recommended way. This is provided here merely in the spirit of sharing. You are more than welcome to post a correction or make an addition in the comment section below. I will happily update this post accordingly.

Bertrand Russell (Famous Mathematician and Logician)

Digit Math: Introduction

The person in the above image is Bertrand Russell. Famous Mathematician and Logician.  An excellent graphic novel, Logicomix, is based around his life. That is a must read.

First thing first. Even if you are not a Math demi-god, it is fine, Digit Math is still for you. In fact my academic track record shows that I barely survived Mathematics! I invented this thing when I was in standard eleventh while trying to create some shortcut formula, because I kept forgetting long formulae and was very slow in arithmetic. Digit Math is a slightly different approach to classical Math. To understand this all you need to know is how to add and multiply, and a little bit of logic. That is it.

What is Digit Math?

Numbers are group of digits. Classical Mathematical operators is not meant to deal with part of the number. Digit Math allows that. You can interact with a single digit or a group of digits in a number. You might wonder, what is the use? Well, I would say, for fun. Like puzzles, this too forces you to think differently. It is not all nonsense fun though.

Can you prove that any number which ends with 5 must be divisible by 5? Well try that using classical Math. I have used Digit Math to prove the same. There some more empirical facts which I have proved using Digit Math. One of that is proving that multiplying any number by \(10^n\) will indeed give us that number but followed by \(n\) zeroes. This might look obvious to you, but think, why does adding \(6\) \(100\) times yields \(600\).

Before we begin…

Before we begin I must list out the notations and symbols I would be using. They were introduced specifically for this, since I know of no existing symbols which convey the same information.

Symbols and Operators

I would be using these symbols throughout the articles on Digit Math, so pay attention to them.

\(\omega\) (With-operator)

This is the main operator, which delimits the digits or groups of digits. I call this ‘with-operator’. So, 251 can be written as \(2\omega51\) (spoken as two-with-fifty-one) or \(25\omega1\) (spoken as twenty-five-with-one) or \(2\omega5\omega1\) (spoken as two-with-five-with-one) or even \(0\omega251\). They all are the same, only the digit partitioning is different. How you partition depends on the problem at hand.

\(]x[\) (Digit Group operator)

This is used in multiple ways. Its primary use is to group digits into a digits group. While in \(2\omega51\) it is quite clear that 2 and 51 are different digit groups of one and two digits respectively, but sometimes we need to convey more information about a digit group.

  • \(]x[\) – This is equal to the number of digits in x, when used on its own. So, \(]25[ = 2\).
  • \(]x[^y\) – This means that x should have y digits. Note that I said ‘should’ have. So, it is possible that while problem solving, at intermediate steps we can have less or more digits. Eventually, the final result must have exactly y digits. This kind of notation is usually used when actual value of x is not known and x is part of a bigger number. So, \(2\omega]x[^2\) means that this is a number which starts with 2 but ends with two digits.
  • Underline notation – Take the example of \(2\omega]345[^2\). Here 3 is the extra digit in this digit group which has the maximum capacity of two digits. In this case since all the digits are known, so here we can use a short-hand notation of underlining the excess digit in the group. So, \(2\omega]345[^2 = 2\omega\underline{3}45\). (Note that 3 is underlined.)

\(\omega\sum\) (Digits summation operator)

So,$$\omega\sum_{i=1}^3a_i = a_3{\omega}a_2{\omega}a_1$$

Note that \(a_1\) is the leftmost item and \(a_3\) the rightmost. Maintaining the sequence in digitized equations is of massive importance.

Precedence of With-operator

\(\omega\) has lower precedence than multiply and division. So the full operator precedence would be

B – Bracket
O – Orders (powers, roots, etc.)
M – Multiply
D – Divide
W – With (\(\omega\))
A – Add
S – Subtract

Properties of With-operator

  • This is not commutative. This is because, \(2\omega5 = 25 \neq 52 = 5\omega2\).
  • This is associative, but only when none of the digit groups have excess digits. That is, less number of digits than required is tolerated. So, \(a\omega(b{\omega}c) = (a{\omega}b){\omega}c\).
  • This is distributive, but only when all digit groups have the exact number of digits. So, less digits is not tolerated here. So, \(n \times (a{\omega}b) = (na)\omega(nb)\).

Some Important Formulae

General formula of transformation

This provides the relation between a normal equation and a digitized equation.

So,$$\omega\sum_{i=1}^{n}a_i = \sum_{i=1}^{n}a_i \times {10}^{n-i}$$

Provided \(a_i\) has one digit only (i.e. \(]a_i[ = 1\)). This is not hard to see, how the above is true.

Bi-multiplication formula

This formula is vital. This describes how the groups of digits behave when they are multiplied. This starts with how we usually manually multiply two numbers.

$$
\begin{align}
x\omega y&\\
\underline{\times\hspace1em a\omega b}&\\
bx\omega by&\\
ax \omega ay\hspace1.5em&\\
\overline{ax\omega (ay+bx)\omega by}&
\end{align}
$$

So,

$$\underline{x \omega y \times a \omega b = ax \omega (ay+bx) \omega by}\tag{bi-multiplication formula}$$

The above relation is pretty easy to understand, but it does say how many digits should be in each group (digits separated by \(\omega\)). To understand this, try multiplying 12 by 34, the manual way. This would be like

$$
\begin{align}
1\omega 2&\\
\underline{\times\hspace1em 3\omega 4}&\\
4\omega 8&\\
3 \omega 6\hspace1.5em&\\
\overline{3\omega (6+4)\omega 8}&\\
\Rightarrow 3\omega 10\omega 8&\\
\Rightarrow 4\omega 0\omega 8&\tag{adding carry over 1 from center to left group}\\
\Rightarrow 408&
\end{align}
$$

Now lets try multiplying 111 by 123.

$$
\begin{align}
01\omega 11&\tag{prefixing with 0 to equate digit counts}\\
\underline{\times\hspace1em 01\omega 23}&\\
23\omega 253&\\
1 \omega 11\hspace1.5em&\\
\overline{1\omega (11+23)\omega 253}&\\
\Rightarrow 1\omega (11+23+2)\omega 53&\tag{2 is the carry over from 253}\\
\Rightarrow 1\omega 36\omega 53&\\
\Rightarrow 13653&
\end{align}
$$

So you can observe from the above scenarios that:-

$$
]a\times b[ = n\hspace1em\ldots\text{where ]a[ = ]b[ = n}
$$

Similarly,

$$
]a + b[ = n\hspace1em\ldots\text{where ]a[ = ]b[ = n}
$$

Any excess digits should be carried over to the digit group on the left and added there.

So,

$$
\begin{align}
1&\\
\underline{+\hspace1em9}&\\
0\omega\underline{1}0&\\
\Rightarrow (0+1)\omega0\\
\Rightarrow 1\omega0\\
\Rightarrow 10
\end{align}
$$

If  \(]a[ \neq ]b[\) then I am not sure what should be \(]a \times b[\). So, we need to make sure that all digit groups have equal number of digits. This is restrictive but fortunately this does not cause problem as there is always a way around.

One more example. Let’s multiply 98 by 76.

$$
\begin{align}
9\omega 8&\\
\underline{\times\hspace1em 7\omega 6}&\\
54\omega 48&\\
63 \omega 56\hspace1.5em&\\
\overline{63\omega (56+54)\omega 48}&\\
\Rightarrow 63\omega 110\omega 48&\\
\Rightarrow 63\omega (110+4)\omega 8&\tag{since max size of each group is 1}\\
\Rightarrow 63\omega 114\omega 8&\\
\Rightarrow (63+11)\omega 4\omega 8&\\
\Rightarrow 74\omega4\omega8&\\
\Rightarrow 7448&
\end{align}
$$

Rules for using the bi-multiplication formula

You have already witness many of the rules, but let me summarize them for clearly. For the following assume that we are multiplying \(a\omega b\) by \(x\omega y\).

  • Make two fragments of both the numbers, by placing \(\omega\) at the positions suitable for you. Remember, the number of digits in all the four fragments should be equal. That is, \(]a[ = ]b[ = ]x[ = ]y[\).Partitioning \(255\) as \(2\omega55\) is perfectly fine, since \(]02[ = ]55[ = 2\).
  • If the number of digits in \(by\) or \(ay+bx\) terms are less than the required number then insert zeroes in front of them to get the exact number of digits.
  • If the number of digits in \(by\) or \(ay+bx\) terms are more than the required number then remove the excess digits from the front (left) of them and add these excess digits to the group on left. Note, that shifting of excess digits (carry over) should started from the rightmost group and then progress towards left sequentially.
  • When all the above conditions are met then you are good to remove the \(\omega\) (with-operator).

So, finally the bi-multiplication formula can be precisely expressed as,

$$\boxed{x \omega y \times a \omega b = ax\hspace2pt\omega\hspace2pt]ax+by[^n\hspace2pt\omega\hspace2pt]by[^n}\hspace1em\ldots\text{where ]a[ = ]b[ = ]x[ = ]y[ = n}$$

Squaring formula

This is directly derivable from bi-multiplication formula.

$$
\begin{align}
(a \omega b)^2&\\
\Rightarrow& a \omega b \times a \omega b\\
\Rightarrow& \boxed{a^2\omega ]2ab[^n \omega ]b^2[^n}\hspace1em\ldots\text{where ]a[ = ]b[ = n}
\end{align}
$$

General Powering Formula

For now I will provide only the formula. The proof is provided later in this article. The way I derived it was to I manually find the values of \((a\omega b)^2\), \((a\omega b)^3\), \((a\omega b)^4\) and so on. I found a pattern in all these and from there I got this formula. It was later when it struck me as to how to prove it.

$$
\boxed{(a\omega b)^n = \omega\sum_{r=0}^n\hspace1em{]^nC_r \times a^{(n-r)} \times b^r[}^d}\hspace1em\ldots\text{where ]a[ = ]b[ = d}
$$

Notice that the above equation looks very similar to Binomial equation. In fact I found this to be true for many equations. If we replace \(+\) by \(\omega\) then we end up with a ‘digitized’ version of that equation.

Now let me demonstrate how to use this equation. Let’s find cube of 99, i.e. \(99^3\).

$$
\begin{align}
&(9\omega9)^3\\
&= ]^3C_0 \times 9^3 \times 9^0[^1 \omega ]^3C_1 \times 9^2 \times 9^1[^1\\
&= 9^3 \omega 3\times9^3 \omega 3\times9^3 \omega 9^3\tag{for brevity removing ].[ operator}\\
&= 729 \omega \underline{218}7 \omega \underline{218}7 \omega \underline{72}9\\
&= 729 \omega \underline{218}7 \omega \underline{225}9 \omega 9\tag{adding carry overs}\\
&= 729 \omega \underline{241}2 \omega 9 \omega 9\\
&= 970 \omega 2 \omega 9 \omega 9\\
&= 970299
\end{align}
$$

I didn’t underline the excess digits in leftmost group, since that is anyway not going to affect the result. Now let us find \(241^4\).

$$
\begin{align}
&(02\omega41)^4\\
&= \omega\sum_{r=0}^4\hspace1em]^4C_r \times 2^{(4-r)} \times 41^r[^2\\
&= ^4C_0.2^4\hspace0.5em\omega\hspace0.5em^4C_1.2^3.41\hspace0.5em\omega\hspace0.5em^4C_2.2^2.41^2\hspace0.5em\omega\hspace0.5em^4C_3.2.41^3\hspace0.5em\omega\hspace0.5em^4C_4.41^4\\
&= 16\omega\underline{13}12\omega\underline{403}44\omega\underline{5513}68\omega\underline{28257}61\\
&= 16\omega\underline{13}12\omega\underline{403}44\omega\underline{5796}25\omega61\\
&= 16\omega\underline{13}12\omega\underline{461}40\omega25\omega61\\
&= 16\omega\underline{17}73\omega40\omega25\omega61\\
&= 33\omega73\omega40\omega25\omega61\\
&= 3373402561
\end{align}
$$

Note, one important observation. Here you can immediately identify the last couple of digits of the final result by evaluating for the last term. Unlike in Binomial Theorem, where all the terms need to be added. So, there at least last few digits of all the terms need to be added to get the  last few digits of the final result. This is an advantage for General Powering formula, but unfortunately we cannot say the for other digit groups which are at higher place order. The reason is simple, they may have to be added with carry-overs from the groups (terms) on the right.

A corollary of the General Formula of Transformation (for two digits)

With to Plus form

$$a\omega b = 10a+b$$

The above equation is true only when \(b\) has one digit. The more general equation is:-

$$\boxed{a\omega b = a.10^d+b}\hspace1em\text{where d}=]b[\hspace1em\ldots\text{Corollary 1}$$

Plus to With form

$$a\omega b = 10a +b \Rightarrow a\omega b = 9a + a + b \Rightarrow \boxed{a+b = a\omega b -9a}\hspace1em\ldots\text{Corollary 2}$$

Negative digits

We all are aware of negative numbers but in digit equations we might end up with negative digits! I see no physical significance of that but let’s try to find out some mathematical meaning of this.

$$
\begin{align}
a\omega(-b) &= 10a + (-b)\\
&= 10a -b\\
&= 10a + b -2b\\
&= a\omega b -2b
\end{align}
$$

Altire,

$$
\begin{align}
a\omega(-b) &= -(-10a + b)\\
&= -(10a+b -20a)\\
&= -(a\omega b – 20a)\\
&= -(a\omega b) +20a
\end{align}
$$

$$
\therefore \boxed{a\omega(-b) = a\omega b-2b = -(a\omega b)+20a}
$$

Remember, \((-a)\omega b \neq -(a\omega b)\). The former means that only the digit \(a\) is negative. The later means that the complete number is negative.

Similarly,

$$
\boxed{(-a)\omega b = a\omega b-20a = -(a\omega b)+2b}
$$

Also similarly evaluating, we get,

$$
\boxed{(-a)\omega(-b) = -(a\omega b)}\hspace1em\ldots\text{Corollary 3}
$$

So, we see that in a negative number all the digits too are negative. Not surprising, since in a positive number all digits are positive.

Proof of General Powering Formula

Since I already know this formula, so I just need to prove that it is correct. For this the best tool is Mathematical Induction. So, the formula to prove is

$$(a\omega b)^n = \omega\sum_{r=0}^n\hspace1em{]^nC_r \times a^{(n-r)} \times b^r[}^d$$

Case 1: n = 0

So,

$$
\begin{align}
L.H.S. &= (a\omega b)^0 = 1\\
\\
\\
R.H.S. &= \omega\sum_{r=0}^0\hspace1em ^0C_r \times a^{(0-r)} \times b^r\\
&= 1\times a^0 \times b^0\\
&= 1\tag{Proved}
\end{align}
$$

Case 2: n = 1

$$
\begin{align}
L.H.S.&= (a\omega b)^1 = a\omega b\\
\\
\\
R.H.S. &= \omega\sum_{r=0}^1\hspace1em ^1C_r \times a^{(1-r)} \times b^r\\
&= ^1C_0. a^1. b^0 \omega ^1C_1.a^0.b^1\\
&= a\omega b\tag{Proved}
\end{align}
$$

Case 3: For n

Suppose that the formula is true for all values of \(n\), then by Mathematical Induction, the formula must be valid for \(n+1\) too.

So,

$$
\begin{align}
&(a\omega b)^{(n+1)}\\
&= (a\omega b)^n \times (a\omega b)\\
&= (a\omega b)^n \times (a\times 10^d+b)\hspace1em\ldots\text{where d}=]b[\tag{By Corollary 1}\\
&= 10^da\times(a\omega b)^n + b\times (a\omega b)^n\\
&= 10^da\times(\omega\sum_{r=0}^n\hspace1em ^nC_r\times a^{(n-r)} \times b^r) +\\
&\hspace2em b\times(\omega\sum_{r’=0}^n\hspace1em ^nC_{r’}\times a^{(n-r’)} \times b^{r’}) \tag{Since formula is correct for n}\\
&= 10^d\times(a^{(n+1)} \hspace2pt\omega\hspace2pt \omega\sum_{r=1}^n\hspace1em ^nC_r\times a^{(n+1-r)} \times b^r) +\\
&\hspace2em(\omega\sum_{r’=0}^{(n-1)}\hspace1em ^nC_{r’}\times a^{(n-r’)} \times b^{(r’+1)} \hspace2pt\omega\hspace2pt b^{(n+1)})\tag{1}
\end{align}
$$

Since \(]a[\hspace2pt=\hspace2pt]b[\hspace2pt=\hspace2pt d\), so every term of \(\omega\sum\) too will have \(d\) digits, as per General Powering Formula. This implies that term \(b^{(n+1)}\) in equation (1) too has \(d\) digits. So, if we can rewrite (1) as below:-

$$
\begin{align}
a^{(n+1)} \hspace2pt\omega\hspace2pt&\omega\sum_{r=1}^n\hspace1em ^nC_r\times a^{(n+1-r)} \times b^r\tag{2}\\
+\hspace2em\hspace2em &\omega\sum_{r’=0}^{(n-1)}\hspace1em ^nC_{r’}\times a^{(n-r’)} \times b^{(r’+1)} \hspace2pt\omega\hspace2pt b^{(n+1)}\tag{3}\\
a^{n+1} \hspace2pt\omega\hspace2pt & \overline{\omega\sum_{r=1}^n\hspace1em {^nC_r\times a^{n+1-r} \times b^r \brace + ^nC_{(r-1)}\times a^{n-(r-1)} \times b^{(r-1)+1}} \hspace2pt\omega\hspace2pt b^{n+1}}\\
\Rightarrow a^{n+1} \hspace2pt\omega\hspace2pt &\bigg( \omega\sum_{r=1}^n\hspace1em ^nC_r\times a^{n+1-r} \times b^r + ^nC_{r-1}\times a^{n+1-r} \times b^{r}\bigg) \hspace2pt\omega\hspace2pt b^{n+1}\tag{4}
\end{align}
$$

Notice that in the above, I have removed the \(10^d\) factor since all it did is to shift its term by \(d\) digits to left, that is, by exact number of digits in the \(b^{(n+1)}\) group. After removing the first digit group from equation (2) and last digit group from equation (3), \(\omega\sum\) in both the equations have \(n-1\) digit groups left. Each of these digit groups will get added term by term, i.e. group \(1\) of (2) will get added to group \(0\) of (3) and so on. So this implies \(r’ = r – 1\).

Further simplifying,

$$
\begin{align}
(4)&= a^{n+1} \hspace2pt\omega\hspace2pt \bigg(\omega\sum_{r=1}^n\hspace1em a^{n+1-r}.b^r(\frac{n!}{r!(n-r)!}+\frac{n!}{(r-1)!(n-r+1)!})\bigg) \hspace2pt\omega\hspace2pt b^{n+1}\\
&= a^{n+1} \hspace2pt\omega\hspace2pt \bigg(\omega\sum_{r=1}^n\hspace1em a^{n+1-r}.b^r.\frac{(n+1)!}{r!(n+1-r)!}.(\frac{n+r-1}{n+1}+\frac{r}{n+1})\bigg) \hspace2pt\omega\hspace2pt b^{n+1}\\
&= a^{n+1} \hspace2pt\omega\hspace2pt \bigg(\omega\sum_{r=1}^n\hspace1em a^{n+1-r}.b^r.^{n+1}C_r.(1)\bigg) \hspace2pt\omega\hspace2pt b^{n+1}\\
&= \bigg(C_0^{n+1}.a^{n+1-0}.b^0\bigg) \hspace2pt\omega\hspace2pt \bigg(\omega\sum_{r=1}^n\hspace1em C_r^{n+1}.a^{n+1-r}.b^r\bigg) \hspace2pt\omega\hspace2pt \bigg(C_{n+1}^{n+1}.a{(n+1-(n+1))}.b{n+1}\bigg)\\
&= \omega\sum_{r=0}^{(n+1)}\hspace1em ^{(n+1)}C_r.a^{(n+1)-r}.b^r\\
\end{align}
$$

So, proved that \((a\omega b)^{(n+1)} = \omega\sum_{r=0}^{(n+1)}\hspace1em ^{(n+1)}C_r.a^{(n+1)-r}.b^r\) when \((a\omega b)^n = \omega\sum_{r=0}^n\hspace1em ^nC_r.a^{n-r}.b^r\).

So, all cases proved.

Application of Digit Math

Now time to see Digit Math in action. I will be using this to prove some empirical concepts.

Link to list of applications of Digit Math.

CInk version 2 finally released!

Finally CInk version 2 has been released.

Some key new things

  • New website with complete API documentation and guides on how you can use CInk JS code.
  • Finally released the full source code of CInk renderer and compiler. License – GPL v3.
  • CInk finally supports all the features of original CFDG, including Paths.
  • CInk has introduced support for texts which extends the capabilities of CFDG considerably. Check out the cool demo – Neon Letters. To learn more about it see – “Text transforms” section here.

Last but not the least, you can post comments on CInk website. The comments section is at the bottom of each page.

Goto Cink website – cink.applegrew.com.

Migrate from Apache to Nginx: The new guide

`AG_BACKQUOTE_TURN_ON`

If you are here then most probably, like me you too want to migrate from Apache to Nginx. Well I have already migrated and I am loving it! You can get a quick recap of Apache vs Nginx comparison here. Via this blog post I will share and explain my Nginx conf, in the hope that this can prove helpful for you. I have assumed that you have Nginx and Php-FPM installed. You can read how to install Ngnix from here – http://goo.gl/tq6vT. I installed it from its source. You can install PHP-FPM as per the guide at – http://goo.gl/Fx9hJ. My repo had PHP-FPM so I was saved from this trouble.

The net is littered with loads of blog posts on this topic, but most of them are either out of date or make contradictory suggestions. I have scoured the net and cooked up my own Nginx config based on many helpful blog posts on them. My config has been progressively tweaked as per my needs. I now feel that it is good enough to be shared.

To see if my Nginx config suites your needs, you first need to understand my use case. I have four domains hosted on the same server – applegrew.com, cink.applegrew.com, fb.applegrew.com and this blog.

  • applegrew.com – This serves some static HTML, few XMLs and dynamic web pages (PHP).
  • cink.applegrew.com – This is my Chrome Experiment site and has no dynamic web pages, only static files like HTMLs, images, text files, etc.
  • fb.applegrew.com – I added this one recently to host my Facebook Apps. So, naturally this has dynamic web pages, coded in PHP. Since, FB has mandated that from 1 Oct, 2011, all FB Apps must be accessible via HTTPS, so, this domain is configured to be accessible via both HTTP and HTTPS. The Nginx config for this takes care of setting the PHP parameter `$_SERVER[‘HTTPS’]` when HTTPS is used.
  • blog.applegrew.com– Configuring Nginx for this blog was no easy task. This blog is powered by WordPress. If you too have a WordPress blog then you MUST install the following WP plugins for performance. The Nginx config that I have shared assumes that these plugins are installed and takes full advantage of it.

    Must have WordPress plugins:-

    • WP Super Cache– Excellent plugin which generates static HTML files for your blog. Nobody updates their blog every minute. It’s not a Twitter. So, why generate that same page again and again for every user who visits you blog? The solution is to cache the generate page. Later when any user visits your blog then that user will be served the cached page. This saves a ton of overhead. Particularly when you are using Nginx, since, we run PHP and Nginx processes separately. So we can configure Nginx to serve the generated file, if present, and completely bypass PHP. This plugin is smart enough to refresh the cache when you make a new post or update it.

      Tip: Install this plugin after you have finalized your sites design, else you will have to manually clean the cache to make the site changes available.

    • WP Minify– This plugin strips out all the JS and CSS links from your blog and then combines them generate a unified CSS and JS. The result is cut down on the number of requests to your server for additional CSS and JS files. This plugin also minifies the combined CSS and JS files, which produces a much smaller file.

      Tip: If you install a new plugin after you install this one, and if that is not working, then try clearing the cache of this plugin. Since, it is possible that the new plugin will try to put some new CSS or JS which might get stripped out but not cached in the combined file.

Now its time for the configs.


nginx.conf

[code lang=”cink”]
user apache apache; #The uid and gid of the nginx process
worker_processes 4; #Number of worker processes that needs to be created.

error_log /var/log/error-n.log;

pid /usr/local/nginx/logs/nginx.pid;

events {
worker_connections 1000;
}

http {
include mime.types; #Includes a config file which is available with ngix’s default installation.
index index.html index.htm index.php index.shtml;

log_format main ‘$remote_addr – $remote_user [$time_local] "$request" ‘
‘$status $body_bytes_sent "$http_referer" ‘
‘"$http_user_agent" "$http_x_forwarded_for"’;

sendfile on;
keepalive_timeout 5;

gzip on;

# Sets the default type to text/html so that gzipped content is served
# as html, instead of raw uninterpreted data.
#default_type text/html;

server {#If someone tries to access the url http://applegrew.com/xxx then
#this will redirect him to http://www.applegrew.com/xxx.
server_name applegrew.com;
rewrite ^ http://www.applegrew.com$request_uri? permanent;
}

server {#The config for www.applegrew.com
server_name www.applegrew.com;

access_log /var/www/applegrew.com/access-n.log main; #Where access log will be written for this domain.
error_log /var/www/applegrew.com/error-n.log;

root /var/www/applegrew.com/html; #The document root for this domain.

location ~ /admin/ { deny all; } #Denies access to some www.applegrew.com/admin/ url
location ~ /private/ { deny all; }

include cacheCommon.conf; #This caches common static files. This config is given later in this post.
include drop.conf; #This config is given later in this post.
include php.conf; #Configures PHP access for this domain. This config is given later in this post.
include err.conf; #Some common custom error messages I show. This config is given later in this post.
}

server {#Config to serve HTTP traffic.
server_name fb.applegrew.com;

access_log /var/www/fb.applegrew.com/access.log main;
error_log /var/www/fb.applegrew.com/error.log;

root /var/www/fb.applegrew.com/html;

include cacheCommon.conf;
include php.conf;
include drop.conf;
include err.conf;
}

server {//Config to serve HTTPS traffic.
listen 443;
server_name fb.applegrew.com;

ssl on;
ssl_certificate /var/ssl/fb.applegrew.com.crt; #See http://goo.gl/mvHo7 to know how to create crt file.
ssl_certificate_key /var/ssl/fb_applegrew_com.key;

access_log /var/www/fb.applegrew.com/access.log main;
error_log /var/www/fb.applegrew.com/error.log;

root /var/www/fb.applegrew.com/html;

include cacheCommon.conf;
include phpssl.conf; #Notice the difference. This is not php.conf. This config will be provided later in this post.
include drop.conf;
include err.conf;
}

server {
server_name blog.applegrew.com;

access_log /var/www/blog.applegrew.com/access-n.log main;
error_log /var/www/blog.applegrew.com/error-n.log;

root /var/www/blog.applegrew.com/html;

#If tgz file mathcing the request already exists then that will be sent, skipping on the fly compression by nginx.
gzip_static on;

location / {
# does the requested file exist exactly as it is? if yes, serve it and stop here
if (-f $request_filename) { break; }

# sets some variables to help test for the existence of a cached copy of the request
set $supercache_file ”;
set $supercache_uri $request_uri;

# IF the request is a post, has a query attached, or a cookie
# then don’t serve the cache (ie: users logged in, or posting comments)
if ($request_method = POST) { set $supercache_uri ”; }
if ($query_string) { set $supercache_uri ”; }
if ($http_cookie ~* "comment_author_|wordpress|wp-postpass_" ) {
set $supercache_uri ”;
}

# if the supercache_uri variable hasn’t been blanked by this point, attempt
# to set the name of the destination to the possible cache file
if ($supercache_uri ~ ^(.+)$) {
set $supercache_file /wp-content/cache/supercache/$http_host/$1index.html;
}

# If a cache file of that name exists, serve it directly
if (-f $document_root$supercache_file) { rewrite ^ $supercache_file break; }

# Otherwise send the request back to index.php for further processing
if (!-e $request_filename) { rewrite . /index.php last; }

#try_files $uri $uri/ /index.php;
}
location ~ /wp-config\.php { deny all; }
location ~ /wp-content/bte-wb/.*\..* { deny all; }

include cacheCommon.conf;
include drop.conf;
include php.conf;
include err.conf;

#Let wordpress show its own error pages.
fastcgi_intercept_errors off;
}

server {
server_name cink.applegrew.com;

access_log /var/www/cink.applegrew.com/access-n.log main;
error_log /var/www/cink.applegrew.com/error-n.log;

root /var/www/cink.applegrew.com/html;

include cacheCommon.conf;
include drop.conf;
include err.conf;
}

server {#If none the above matched then maybe the url was accessed, (say) via the IP directly. We then show applegrew.com.
listen 80 default;
server_name _;
access_log /var/www/applegrew.com/access.log-n main;

server_name_in_redirect off;

rewrite ^ http://www.applegrew.com$request_uri? permanent;
include err.conf;
}
}
[/code]


cacheCommon.conf

[code lang=”cink”]
#Asks browsers to cache files with extension ico, css, gif, jpg, jpeg, png, txt and xml.
location ~* \.(?:ico|css|js|gif|jpe?g|png|txt|xml)$ {
# Some basic cache-control for static files to be sent to the browser
expires max;
add_header Pragma public;
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
}
[/code]


drop.conf

[code lang=”cink”]
location = /favicon.ico { access_log off; log_not_found off; } #Don’t log this.
location ~ /\. { access_log off; log_not_found off; deny all; } #Block . (dot) files access
#Don’t log and deny access to files which end with ~, as these are usually backup files.
location ~ ~$ { access_log off; log_not_found off; deny all; }
[/code]


err.conf

[code lang=”cink”]
error_page 500 502 503 504 /50x.html;
error_page 403 404 /404.html; # Yes for 403 too we show 404 error, just to mislead.
location = /50x.html {
root /home/webadmin/err/;
}
location = /404.html {
root /home/webadmin/err/;
}
[/code]


php.conf

[code lang=”cink”]
location ~ \.php { #All requests that end with .php are directed to PHP process.
include phpparams.conf; #This file is described later in this post.
}
[/code]


phpssl.conf

[code lang=”cink”]
location ~ \.php {#This the same as php.conf but adds few ssl specific configs.
fastcgi_param HTTPS on; #This sets $_SERVER[‘HTTPS’] to ‘on’.
fastcgi_param SSL_PROTOCOL $ssl_protocol; #This sets the $_SERVER[‘SSL_PROTOCOL’].
fastcgi_param SSL_CIPHER $ssl_cipher; #This sets the $_SERVER[‘SSL_CIPHER’].
fastcgi_param SSL_SESSION_ID $ssl_session_id; #This sets the $_SERVER[‘SSL_SESSION_ID’].
fastcgi_param SSL_CLIENT_VERIFY $ssl_client_verify; #This sets the $_SERVER[‘SSL_CLIENT_VERIFY’].

include phpparams.conf;
}
[/code]
We need to set the `$_SESSION` ourselves since unlike mod_php (in Apache), Php-Fpm is not embedded in Nginx and it doesn’t have these information available to it unless we set it. The above config doesn’t set all the flags a script might expect, but the usual ones. If need to set some more then go to Nginx HttpSslModule’s Built-in variables section.


phpparams.conf

[code lang=”cink”]
#PHP FastCGI
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;

fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;

fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx;

fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;

fastcgi_connect_timeout 60;
fastcgi_send_timeout 180;
fastcgi_read_timeout 180;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;

fastcgi_pass unix:/usr/local/nginx/logs/php5-fpm.sock; #I have configured both Php-Fpm and Nginx to communicate via file sockets.
[/code]


/etc/php-fpm.conf

[code]
include=/etc/php-fpm.d/*.conf
pid = /var/run/php-fpm/php-fpm.pid
error_log = /var/log/php-fpm/error.log
log_level = error
[/code]


/etc/php-fpm.d/www.conf

[code]
[www]
listen = /usr/local/nginx/logs/php5-fpm.sock
listen.allowed_clients = 127.0.0.1
user = apache
group = apache

pm = dynamic
pm.max_children = 6; #This can be increased on 512MB RAM. For 256MB you ca use 2.
pm.start_servers = 3; #This can be increased. For 256MB you can use 1.
pm.min_spare_servers = 3; #This can be increased. For 256MB you can use 1.
pm.max_spare_servers = 5; #This can be increased. For 256MB you can use 1.
pm.max_requests = 500
slowlog = /var/log/php-fpm/www-slow.log
php_admin_value[error_log] = /var/log/php-fpm/www-error.log #All PHP errors will go into this.
php_admin_flag[log_errors] = on
[/code]
Note: The settings above are indicative. You need to experiment with different settings on your system. I have a MySql DB too running on the same system. In my case the minimal settings for 256MB RAM too cause problem. The PHP process used to choke after 4-5 days of running. So, finally I was forced to increase server RAM to 512MB.


/etc/init.d/nginxd

I wrote this shell script to start stop nginx as a service on my CentOS server.
[code lang=”bash”]
#!/bin/bash
# chkconfig: 235 85 15
# description: The Nginx Server is an efficient and extensible \
# server implementing the current HTTP standards.

cmd=/usr/local/nginx/sbin/nginx #Change this to match your Nginx installation path.
start() {
pgrep ‘nginx$’ > /dev/null
if (( $? != 0 ))
then
echo ‘Staring nginx’
$cmd
RETVAL=$?
if (( $RETVAL == 0 ))
then
echo ‘Started successfully’
fi
else
echo ‘Nginx already running’
RETVAL=0
fi
}

RETVAL=0
case "$1" in
start)
start
;;
stop)
echo ‘Shutting down Nginx quickly’
$cmd -s stop
RETVAL=$?
;;
quit)
echo ‘Gracefully shutting down Nginx’
$cmd -s quit
RETVAL=$?
;;
restart)
echo ‘Stopping Nginx’
$cmd -s stop
start
;;
reload)
echo ‘Reloading cofig’
$cmd -s reload
RETVAL=$?
;;
reopen)
echo ‘Reopening log files’
$cmd -s reopen
RETVAL=$?
;;
help)
$cmd -?
RETVAL=$?
;;
test)
echo ‘Test config’
$cmd -t
RETVAL=$?
;;
*)
echo $"Usage: nginx {start|stop|quit|restart|reload|reopen|help|test}"
echo "stop – quick shutdown"
echo "quit – graceful shutdown"
echo "reload – close workers, load config, start new workers"
echo "reopen – reopen log files"
echo "test – only tests the config"
RETVAL=3
esac

exit $RETVAL
[/code]
You can install the above by copying the nginxd file to /etc/init.d then run
`sudo /sbin/chkconfig nginxd –add`
`sudo /sbin/chkconfig nginxd on`

You can the give commands to the script by
`sudo /sbin/service nginxd command here`


Well, I hope this post been helpful.