Index: /trunk/workflow/inc/smarty/wf_plugins/function.wf_autocomplete_input_init.php
===================================================================
--- /trunk/workflow/inc/smarty/wf_plugins/function.wf_autocomplete_input_init.php	(revision 1428)
+++ /trunk/workflow/inc/smarty/wf_plugins/function.wf_autocomplete_input_init.php	(revision 1428)
@@ -0,0 +1,27 @@
+<?php
+/**
+ * Insere código que referencia arquivos de javascript responsáveis pela funcionalidade.
+ * @package Smarty
+ * @subpackage wf_plugins
+ * @param array $params Array de parametros (vazio)
+ * @param object &$smarty Instância do objeto smarty em uso1
+ * @return string $output codigo com referencias aos javascripts.
+ * @access public
+ */
+function smarty_function_wf_autocomplete_input_init($params, &$smarty)
+{
+	$jsEffects		= $GLOBALS['phpgw_info']['server']['webserver_url'] . '/workflow/js/scriptaculous/effects.js';
+	$jsControls		= $GLOBALS['phpgw_info']['server']['webserver_url'] . '/workflow/js/scriptaculous/controls.js';
+	$jsJson			= $GLOBALS['phpgw_info']['server']['webserver_url'] . '/workflow/js/nano/JSON.js';
+	$jsSha1			= $GLOBALS['phpgw_info']['server']['webserver_url'] . '/workflow/js/jscode/sha1.js';
+	$jsAutocomplete	= $GLOBALS['phpgw_info']['server']['webserver_url'] . '/workflow/js/jscode/wf_autocomplete_input.js';
+	$output = <<<EOF
+	<script type="text/javascript" src="$jsEffects"></script>
+	<script type="text/javascript" src="$jsControls"></script>
+	<script type="text/javascript" src="$jsJson"></script>
+	<script type="text/javascript" src="$jsSha1"></script>
+	<script type="text/javascript" src="$jsAutocomplete"></script>
+EOF;
+	return $output;
+}
+?>
Index: /trunk/workflow/inc/smarty/wf_plugins/function.wf_autocomplete_input.php
===================================================================
--- /trunk/workflow/inc/smarty/wf_plugins/function.wf_autocomplete_input.php	(revision 1428)
+++ /trunk/workflow/inc/smarty/wf_plugins/function.wf_autocomplete_input.php	(revision 1428)
@@ -0,0 +1,90 @@
+<?php
+/**
+ * Este plugin insere um input que mostra os valores que podem ser selecionados enquanto o usuário digita.
+ * Os valores são preenchidos previamente através de uma requisição ajax: a classe e método que será invocado é passado por parêmetro no momento em que o desenvolvedor utiliza o componente.
+ *
+ * @package Smarty
+ * @subpackage wf_plugins
+ * @param array $params Array de parametros
+ * - name: o nome que o componente irá receber.
+ * - ajaxClass: classe ajax que será utilizada para fazer a consulta.
+ * - ajaxMethod: método da classe que será invocado para preencher a lista de opções.
+ * - methodParam: Parâmetro para o método que será invocado para preencher a lista de opções.
+ * - idValue: (opcional) o id de um item previamente selecionado (não é visível para o usuário).
+ * - textValue: (opcional) o texto de um item inicialmente selecionado (é visível para o usuário).
+ * - minLength: (opcional) número mínimo de caracteres necessários para que as opções apareçam na lista.
+ * - style: (opcional) estilo para o campo input
+ * @param object &$smarty Instância do objeto smarty em uso
+ * @return string $output codigo que insere os select boxes.
+ * @access public
+ */
+function smarty_function_wf_autocomplete_input($params, &$smarty)
+{
+	$requiredParams = array(
+		'name',
+		'ajaxClass',
+		'ajaxMethod'
+	);
+	$defaultValues = array(
+		'minLength'	=> 1,
+		'style'		=> "width: 200px"
+	);
+	$extractParams = array(
+		'name',
+		'ajaxClass',
+		'ajaxMethod',
+		'methodParam',
+		'minLength',
+		'idValue',
+		'textValue',
+		'style'
+	);
+
+	/* verifica se todos os parâmetros obrigatórios foram passados */
+	foreach ($requiredParams as $required)
+		if (!array_key_exists($required, $params) || (empty($params[$required])))
+			$smarty->trigger_error("[wf_autocomplete_input] missing required parameter(s): $required", E_USER_ERROR);
+
+	/* atribui valores default para os parâmetros não passados */
+	foreach ($defaultValues as $key => $value)
+		if (!isset($params[$key]))
+			$params[$key] = $value;
+
+	/* extrai alguns parâmetros da matriz de parâmetros */
+	foreach ($extractParams as $extract)
+		$$extract = $params[$extract];
+
+	/* parâmetros extras são "acumulados" em uma única variável */
+	$extraParams = array();
+	foreach ($params as $key => $value_params)
+		if (!in_array($key, $extractParams))
+			$extraParams[$key] = $value_params;
+
+	$name_input = 'input' . $name;
+	$name_list	= 'list' . $name;
+	$name_response = 'response' . $name;
+
+	/* se parâmetro for um array "joga" para o javascript como um objeto JSON */
+	if (is_array($methodParam)){
+		$methodParam = json_encode($methodParam);
+	} else {
+		$sep = "'"; // se não for um objeto passa parâmetro entre aspas
+	}
+
+	/* Cria um objeto JSON com os parâmetros opcionais utilizados pelo javascript */
+	$extraParams = array ('idValue'		=> $idValue
+						, 'textValue'	=> $textValue
+						, 'minLength'	=> $minLength
+	);
+	$extraParams = json_encode($extraParams);
+
+	$output = <<<EOF
+	<input id="$name" type="hidden"/>
+	<input id="$name_input" type="text" style="$style" onfocus="checkDataLoaded('$name');" onblur="setTimeout('selectAutocompleteElement(\'$name\')', 500);"/>
+	<span id="$name_response"></span>
+	<div id="$name_list" class="autocomplete" style="display: none;"></div>
+	<script>autocompleteSelect('$name', '$ajaxClass', '$ajaxMethod', $sep$methodParam$sep, $extraParams);</script>
+EOF;
+	return $output;
+}
+?>
Index: /trunk/workflow/js/jscode/wf_autocomplete_input.js
===================================================================
--- /trunk/workflow/js/jscode/wf_autocomplete_input.js	(revision 1428)
+++ /trunk/workflow/js/jscode/wf_autocomplete_input.js	(revision 1428)
@@ -0,0 +1,143 @@
+var _cache = new Array();
+
+function checkDataLoaded(elementId)
+{
+	if (_cache['elements'][elementId]['populated'] !== true
+		&& _cache['requests'][_cache['elements'][elementId]['hash']]['populated'] == true)
+	{
+		autocompletePopulate(elementId);
+	}
+}
+
+function showResult(elementId)
+{
+	var index = $(elementId).value;
+	var textResponse = (index == -1)? "Nenhum resultado encontrado!" : "OK";
+	$('response' + elementId).innerHTML = textResponse;
+	$('response' + elementId).className = (index == -1)? "span_message_error" : "span_message_success";
+}
+
+function selectAutocompleteElement(elementId)
+{
+	if ($('input' + elementId) == null) return -1;
+	var value = $('input' + elementId).value;
+	var items = _cache['requests'][_cache['elements'][elementId]['hash']]['data'];
+	var index = autocompleteIndexOf(items, value);
+	$(elementId).value = index;
+
+	$('response' + elementId).innerHTML = typeof(items);
+	showResult(elementId);
+}
+
+function autocompleteIndexOf(array, value)
+{
+	for (key in array){
+		if (array[key].toLowerCase() == value.toLowerCase()){
+			return key;
+		}
+	}
+	return -1;
+}
+
+function arrayValues(array)
+{
+	var i = 0;
+	var arr = Array();
+	for (key in array){
+		arr[i++] = array[key];
+	}
+	return arr;
+}
+
+function autocompletePopulate(elementId)
+{
+	if (_cache['elements'][elementId]['populated'] == null){
+		var items = _cache['requests'][_cache['elements'][elementId]['hash']]['data'];
+		var values = arrayValues(items);
+		new Autocompleter.Local('input' + elementId, 'list' + elementId, values, {
+			'choices':9,
+			'partialChars': _cache['elements'][elementId]['minLength']
+		});
+	}
+	_cache['elements'][elementId]['populated'] = true;
+}
+
+function catchJsonError(dados){ return false; }
+
+function autocompleteSelect(elementId, ajaxClass, ajaxMethod, methodParam, extraParams)
+{
+	// se o parÃ¢metro for um objeto, transforma em uma string para gerar o hash
+	var _param = (typeof(methodParam) == 'object')? JSON.stringify(methodParam) : methodParam;
+	var str = ajaxClass + ajaxMethod + _param;
+	// Cria hash que identifica classe, mÃ©todo e parÃ¢metro.
+	// Componente verifica se hash jÃ¡ existe para nÃ£o fazer requisiÃ§Ãµes ajax desnecessÃ¡rias
+	var hash = new SHA1(str).hexdigest();
+
+	if(extraParams['minLength'] == null){
+		extraParams['minLength'] = 1;
+	}
+
+	if (extraParams['idValue'] != null){
+		if (extraParams['textValue'] != null){
+			$('input' + elementId).value = extraParams['textValue'];
+			$(elementId).value = extraParams['idValue'];
+			showResult(elementId);
+		}
+	}
+
+	func = function (dados)
+	{
+		var result = dados[ajaxMethod]['data'];
+		if (result !== false){
+			// guarda valores localmente
+			_cache['requests'][hash]['data'] = result;
+			_cache['requests'][hash]['populated'] = true;
+			// Envia dados para o componente
+			autocompletePopulate(elementId);
+		}
+	};
+
+	// Relaciona chamada ajax ao objeto
+	if(_cache['elements'] == null){
+		_cache['elements'] = new Array();
+	}
+
+	if(_cache['elements'][elementId] == null){
+		_cache['elements'][elementId] = new Array();
+		_cache['elements'][elementId]['hash'] = hash;
+		_cache['elements'][elementId]['minLength'] = extraParams['minLength'];
+	} else {
+		// por algum motivo componente jÃ¡ existe.
+		// Se o _cache na posiÃ§Ã£o hash nÃ£o for null, requisiÃ§Ã£o ajax jÃ¡ foi feita.
+		// Se o objeto jÃ¡ foi populado e estÃ¡ sendo escrito novamente, manda popular denovo 
+		//   (isso pode acontecer quando o componente Ã© escrito atravÃ©s de javascript)
+		if(_cache['requests'][hash] != null)
+			if (_cache['requests'][hash]['populated'] == true){
+				_cache['elements'][elementId]['populated'] = null;
+				autocompletePopulate(elementId);
+			}
+	}
+
+	// Cria array para armazenar localmente os valores da requisiÃ§Ã£o ajax
+	if(_cache['requests'] == null)
+		_cache['requests'] = new Array();
+
+	if(_cache['requests'][hash] == null){
+		_cache['requests'][hash] = new Array();
+		_cache['requests'][hash]['populated'] = null;
+		_cache['requests'][hash]['data'] = new Array();
+
+		// Faz a requisiÃ§Ã£o ajax/Json
+		var nc = new NanoController();
+		nc.setWfUrl();
+		nc.setSuccessHandler(func);
+		nc.setExceptionHandler(catchJsonError);
+		nc.setErrorHandler(catchJsonError);
+		nc.addVirtualRequest(ajaxMethod,
+		{
+			action: ajaxClass,
+			mode:   ajaxMethod
+		}, methodParam);
+		nc.sendRequest();
+	}
+}
Index: /trunk/workflow/js/jscode/sha1.js
===================================================================
--- /trunk/workflow/js/jscode/sha1.js	(revision 1428)
+++ /trunk/workflow/js/jscode/sha1.js	(revision 1428)
@@ -0,0 +1,334 @@
+/*
+ * The JavaScript implementation of the Secure Hash Algorithm 1
+ *
+ *   Copyright (c) 2008  Takanori Ishikawa  <takanori.ishikawa@gmail.com>
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ * 
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ *   3. Neither the name of the authors nor the names of its contributors
+ *      may be used to endorse or promote products derived from this
+ *      software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ *   TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ *   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * This is the javascript file for code which implements
+ * the Secure Hash Algorithm 1 as defined in FIPS 180-1 published April 17, 1995.
+ *
+ *   Author: Takanori Ishikawa <takanori.ishikawa@gmail.com>
+ *   Copyright: Takanori Ishikawa 2008
+ *   License: BSD License (see above)
+ *
+ * NOTE:
+ *   Only 8-bit string is supported, please use encodeURIComponent() function 
+ *   if you want to hash multibyte string.
+ *
+ * Supported Browsers:
+ *   [Win] IE 6, Firefox 2
+ *   [Mac] Safari 3, Firefox 2
+ *
+ * Usage:
+ *   var hexdigest = new SHA1("Hello.").hexdigest(); // "9b56d519ccd9e1e5b2a725e186184cdc68de0731"
+ *
+ * See Also:
+ *   FIPS 180-1 - Secure Hash Standard
+ *   http://www.itl.nist.gov/fipspubs/fip180-1.htm
+ *
+ */
+
+var SHA1 = (function(){
+
+  /**
+   * Spec is the BDD style test utilities.
+   */
+  var Spec = {
+    /** Replace the Spec.describe function with empty function if false. */
+    enabled: true,
+    
+    /** Indicates whether object 'a' is "equal to" 'b'. */
+    equals: function(a, b) {
+      if (a instanceof Array && b instanceof Array) {
+        if (a.length != b.length) return false;
+        for (var i = 0; i < a.length; i++) if (!Spec.equals(a[i], b[i])) return false;
+        return true;
+      }
+      if ((a != null && b != null) && (typeof a == "object" && typeof b == "object")) {
+        for (var i in a) if (!Spec.equals(a[i], b[i])) return false;
+        return true;
+      }
+      return (a == b);
+    },
+    
+    /** equivalent to xUint's assert */
+    should: function(expection, message) {
+      Spec.currentIndicator++;
+      if (!expection) {
+        var warning = [
+          "[Spec failed",
+          Spec.currentTitle ? " (" + Spec.currentTitle + ")] " : "] ",
+          (message || (Spec.currentMessage + " " + Spec.currentIndicator) || "")
+        ].join("");
+        
+        alert(warning);
+        throw warning;
+      }
+      return !!expection;
+    },
+    
+    /** Write your specification by using describe method. */
+    describe: function(title, spec) {
+      Spec.currentTitle = title;
+      for (var name in spec) {
+        Spec.currentMessage = name;
+        Spec.currentIndicator = 0;
+        spec[name]();
+        Spec.currentIndicator = null;
+      }
+      Spec.currentMessage = Spec.currentTitle = null;
+    },
+    Version: "0.1"
+  };
+  
+  // Other BDD style stuffs.
+  Spec.should.equal = function(a, b, message) { return Spec.should(Spec.equals(a, b), message); };
+  Spec.should.not = function(a, message) { return Spec.should(!a, message); };
+  Spec.should.not.equal = function(a, b, message) { return Spec.should(!Spec.equals(a, b), message); };
+  if (!Spec.enabled) Spec.describe = function(){};
+  
+  
+  // self test
+  Spec.describe("Spec object", {
+    "should": function() {
+      Spec.should(true);
+      Spec.should(1);
+    }, 
+    "should.not": function() {
+      Spec.should.not(false);
+      Spec.should.not(0);
+    },
+    "should.equal": function() {
+      Spec.should.equal(null, null);
+      Spec.should.equal("", "");
+      Spec.should.equal(12345, 12345);
+      Spec.should.equal([0,1,2], [0,1,2]);
+      Spec.should.equal([0,1,[0,1,2]], [0,1,[0,1,2]]);
+      Spec.should.equal({}, {});
+      Spec.should.equal({x:1}, {x:1});
+      Spec.should.equal({x:[1]}, {x:[1]});
+    },
+    "should.not.equal": function() {
+      Spec.should.not.equal([1,2,3], [1,2,3,4]);
+      Spec.should.not.equal({x:1}, [1,2,3,4]);
+    }
+  });
+
+
+  // -----------------------------------------------------------
+  // Utilities
+  // -----------------------------------------------------------
+  // int32 -> hexdigits string (e.g. 0x123 -> '00000123')
+  function strfhex32(i32) {
+    i32 &= 0xffffffff;
+    if (i32 < 0) i32 += 0x100000000;
+    var hex = Number(i32).toString(16);
+    if (hex.length < 8) hex = "00000000".substr(0, 8 - hex.length) + hex;
+    return hex;
+  }
+  Spec.describe("sha1", {
+    "strfhex32": function() {
+      Spec.should.equal(strfhex32(0x0),          "00000000");
+      Spec.should.equal(strfhex32(0x123),        "00000123");
+      Spec.should.equal(strfhex32(0xffffffff),   "ffffffff");
+    }
+  });
+
+  // int32 -> string (e.g. 123 -> '00000000 00000000 00000000 01111011')
+  function strfbits(i32) {
+    if (typeof arguments.callee.ZERO32 == 'undefined') {
+      arguments.callee.ZERO32 = new Array(33).join("0");
+    }
+    
+    var bits = Number(i32).toString(2);
+    // '0' padding 
+    if (bits.length < 32) bits = arguments.callee.ZERO32.substr(0, 32 - bits.length) + bits;
+    // split by 8 bits
+    return bits.replace(/(\d{8})/g, '$1 ')
+               .replace(/^\s*(.*?)\s*$/, '$1');
+  }
+  Spec.describe("sha1", {
+    "strfbits": function() {
+      Spec.should.equal(strfbits(0),   "00000000 00000000 00000000 00000000");
+      Spec.should.equal(strfbits(1),   "00000000 00000000 00000000 00000001");
+      Spec.should.equal(strfbits(123), "00000000 00000000 00000000 01111011");
+    }
+  });
+
+
+  // -----------------------------------------------------------
+  // SHA-1
+  // -----------------------------------------------------------
+  // Returns Number(32bit unsigned integer) array size to fit for blocks (512-bit strings)
+  function padding_size(nbits) {
+    var n = nbits + 1 + 64
+    return 512 * Math.ceil(n / 512) / 32;
+  }
+  Spec.describe("sha1", {
+    "padding_size": function() {
+      Spec.should.equal(padding_size(0),             16);
+      Spec.should.equal(padding_size(1),             16);
+      Spec.should.equal(padding_size(512 - 64 - 1),  16);
+      Spec.should.equal(padding_size(512 - 64),      32);
+    }
+  });
+
+  // 8bit string -> uint32[]
+  function word_array(m) {
+    var nchar = m.length;
+    var size = padding_size(nchar * 8);
+    var words = new Array(size);
+    for (var i = 0, j = 0; i < nchar; ) {
+      words[j++] = ((m.charCodeAt(i++) & 0xff) << 24) | 
+                   ((m.charCodeAt(i++) & 0xff) << 16) | 
+                   ((m.charCodeAt(i++) & 0xff) << 8)  | 
+                   ((m.charCodeAt(i++) & 0xff))
+    }
+    while (j < size) words[j++] = 0;
+    return words;
+  }
+  Spec.describe("sha1", {
+    "word_array": function() {
+      Spec.should.equal(word_array(""), [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]);
+      Spec.should.equal(word_array("1234")[0], 0x31323334);
+    }
+  });
+
+  function write_nbits(words, length, nbits) {
+    if (nbits > 0xffffffff) {
+      var lo = nbits & 0xffffffff;
+      if (lo < 0) lo += 0x100000000;
+      words[length - 1] = lo;
+      words[length - 2] = (nbits - lo) / 0x100000000;
+    } else {
+      words[length - 1] = nbits;
+      words[length - 2] = 0x0;
+    }
+    return words;
+  }
+  Spec.describe("sha1", {
+    "write_nbits": function() {
+      Spec.should.equal(write_nbits([0, 0], 2, 1),             [0, 1]);
+      Spec.should.equal(write_nbits([0, 0], 2, 0xffffffff),    [0, 0xffffffff]);
+      Spec.should.equal(write_nbits([0, 0], 2, 0x100000000),   [1, 0]);
+      Spec.should.equal(write_nbits([0, 0], 2, 0x1ffffffff),   [1, 0xffffffff]);
+      Spec.should.equal(write_nbits([0, 0], 2, 0x12300000000), [0x123, 0]);
+      Spec.should.equal(write_nbits([0, 0], 2, 0x123abcdef12), [0x123, 0xabcdef12]);
+    }
+  });
+
+  function padding(words, nbits) {
+    var i = Math.floor(nbits / 32);
+    
+    words[i] |= (1 << (((i + 1) * 32) - nbits - 1));
+    write_nbits(words, padding_size(nbits), nbits);
+    return words;
+  }
+
+  function digest(words) {
+    var i = 0, t = 0;
+    var H = [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0];
+    
+    while (i < words.length) {
+      var W = new Array(80);
+      
+      // (a)
+      for (t = 0;  t < 16; t++) W[t] = words[i++];
+      
+      // (b)
+      for (t = 16; t < 80; t++) {
+        var w = W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16];
+        W[t] = (w << 1) | (w >>> 31);
+      }
+      
+      // (c)
+      var A = H[0], B = H[1], C = H[2], D = H[3], E = H[4];
+      
+      // (d) TEMP = S5(A) + ft(B,C,D) + E + Wt + Kt;
+      //     E = D; D = C; C = S30(B); B = A; A = TEMP;
+      for (t = 0; t < 80; t++) {
+        var tmp = ((A << 5) | (A >>> 27)) + E + W[t];
+        
+        if      (t >=  0 && t <= 19) tmp += ((B & C) | ((~B) & D))        + 0x5a827999;
+        else if (t >= 20 && t <= 39) tmp += (B ^ C ^ D)                   + 0x6ed9eba1;
+        else if (t >= 40 && t <= 59) tmp += ((B & C) | (B & D) | (C & D)) + 0x8f1bbcdc;
+        else if (t >= 60 && t <= 79) tmp += (B ^ C ^ D)                   + 0xca62c1d6;
+        
+        E = D; D = C; C = ((B << 30) | (B >>> 2)); B = A; A = tmp;
+      }
+      
+      // (e) H0 = H0 + A, H1 = H1 + B, H2 = H2 + C, H3 = H3 + D, H4 = H4 + E.
+      H[0] = (H[0] + A) & 0xffffffff;
+      H[1] = (H[1] + B) & 0xffffffff;
+      H[2] = (H[2] + C) & 0xffffffff;
+      H[3] = (H[3] + D) & 0xffffffff;
+      H[4] = (H[4] + E) & 0xffffffff;
+      if (H[0] < 0) H[0] += 0x100000000;
+      if (H[1] < 0) H[1] += 0x100000000;
+      if (H[2] < 0) H[2] += 0x100000000;
+      if (H[3] < 0) H[3] += 0x100000000;
+      if (H[4] < 0) H[4] += 0x100000000;
+    }
+    
+    return H;
+  }
+
+  // message: 8bit string
+  var SHA1 = function(message) {
+    this.message = message;
+  }
+
+  SHA1.prototype = {
+    digest: function() {
+      var nbits = this.message.length * 8;
+      var words = padding(word_array(this.message), nbits);
+      return digest(words);
+    },
+
+    hexdigest: function() {
+      var digest = this.digest();
+      for (var i = 0; i < digest.length; i++) digest[i] = strfhex32(digest[i]);
+      return digest.join("");
+    }
+  };
+  
+  Spec.describe("sha1", {
+    "SHA1#hexdigest": function() {
+      Spec.should.equal(new SHA1("").hexdigest(),       "da39a3ee5e6b4b0d3255bfef95601890afd80709");
+      Spec.should.equal(new SHA1("1").hexdigest(),      "356a192b7913b04c54574d18c28d46e6395428ab");
+      Spec.should.equal(new SHA1("Hello.").hexdigest(), "9b56d519ccd9e1e5b2a725e186184cdc68de0731");
+      Spec.should.equal(new SHA1("9b56d519ccd9e1e5b2a725e186184cdc68de0731").hexdigest(), "f042dc98a62cbad68dbe21f11bbc1e9d416d2bf6");
+      Spec.should.equal(new SHA1("MD5abZRVSXZVRcasdfasdddddddddddddddds+BNRJFSLKJFN+SEONBBJFJXLKCJFSE)RUNVXDLILKVJRN)#NVFJ)WVFWRW#)NVS$Q=$dddddddddddddWV;no9wurJFSE)RUNVXDLILKVJRN)#NVFJ)WVFWRW#)NVS$Q=$dddddddddddddWV;no9wurJFSE)RUNVXDLILKVJRN)#NVFJ)WVFWRW#)NVS$Q=$dddddddddddddWV;no9wurJFSE)RUNVXDLILKVJRN)#NVFJ)WVFWRW#)NVS$Q=$dddddddddddddWV;no9wuraddddddasdfasdfd").hexdigest(), "662dbf4ebc9cdb4224766e87634e5ba9e6de672b");
+    }
+  });
+  
+  return SHA1;
+})();
Index: /trunk/workflow/templates/default/css/lightbox.css
===================================================================
--- /trunk/workflow/templates/default/css/lightbox.css	(revision 795)
+++ /trunk/workflow/templates/default/css/lightbox.css	(revision 1428)
@@ -18,7 +18,7 @@
 	width:600px;
 	min-height:50px;
-	max-height:400px;
+	max-height:600px;
 	height:auto !important;
-	height:400px;
+	height:600px;
 	margin:-220px 0 0 -300px;
 	border:1px solid #000000;
@@ -28,5 +28,5 @@
 	overflow: auto;
 	padding: 5px;
-	height: expression(this.scrollHeight > 400 ? "400px" : "auto");/* solução para o problema de altura minima no IE */
+	height: expression(this.scrollHeight > 600 ? "600px" : "auto");/* solução para o problema de altura minima no IE */
 }
 
Index: /trunk/workflow/templates/default/processes/default.css
===================================================================
--- /trunk/workflow/templates/default/processes/default.css	(revision 1144)
+++ /trunk/workflow/templates/default/processes/default.css	(revision 1428)
@@ -730,2 +730,56 @@
     vertical-align: middle;
 }
+
+div.autocomplete {
+    margin:0px;
+    padding:0px;
+    width:355px;
+    background:#fff;
+    border:1px solid #888;
+    position:absolute;
+}
+
+div.autocomplete ul {
+    margin:0px;
+    padding:0px;
+    list-style-type:none;
+}
+
+div.autocomplete ul li.selected {
+    background-color:#ffb;
+}
+
+div.autocomplete ul li {
+    margin:0;
+    padding:2px;
+    height:16px;
+    display:block;
+    list-style-type:none;
+    cursor:pointer;
+}
+
+.span_message_notice, .span_message_success, .span_message_error {
+    font-weight: bold;
+    font-size: 90%;
+    padding: 1px 6px;
+    -moz-border-radius: 3px;
+    -webkit-border-radius: 3px;
+    border-radius: 3px;
+    margin-left: 5px;
+    background:#FFF6BF;
+    color:#514721;
+    border: 1px solid #FFD324;
+    opacity: 100;
+}
+
+.span_message_success {
+    background:#E6EFC2 !important;
+    color:#264409 !important;
+    border-color:#C6D880 !important;
+}
+
+.span_message_error {
+    background:#FBE3E4 !important;
+    color:#8A1F11 !important;
+    border-color:#FBC2C4 !important;
+}
