Consulta sobre codigo ¿? :-(

Hola a todos los miembros de la lista, hace un par de dias que estoy
analizando un codigo (concretamente de metasploit 3.2) y he llegado a
lib/rex/text.rb. Luego de ver unos cuantos metodos me he trabado en uno
(self.converge_sets), aca se los dejo libre para que lo vean. Lo he
traceado
con NetBeans para ver si lo entendia pero me sigo trabando en la linea
marcado con <---------, las otras partes ya las tengo bastante claras
pero
no puedo entender que utilidad tiene ese bucle while.

Este metodo lo que hace es devolver un string con un tamaño igual a la
cantidad de elementos de sets, agarra cada caracter basandose en el
offsets,
me ha costado un poco analizarla ya que no tengo mucha experiencia con
recursividad pero ya he logrado entender como trabaja. Aunque la linea
que
les marque me esta dando fuertes dolores de cabeza, cualquier ayuda sera
agradecida.

def converge_sets(sets, idx, offsets, length) # :nodoc:
buf = sets[idx][offsets[idx]].chr

    if (sets[idx + 1])
            buf += converge_sets(sets, idx + 1, offsets, length)
    else

            while (idx >= 0 and ((offsets[idx] = (offsets[idx] + 1) 

%
sets[idx].length)) == 0) <-------
idx -= 1
end

            if (idx < 0)
                    raise RuntimeError, "Maximum permutations 

reached"
end
end

    buf

end

puts converge_sets([“ABCDEFGHIJKLMNOPQRSTUVWXYZ”,
“abcdefghijklmnopqrstuvwxyz”, “0123456789”],0,[0,0,0],0)

Esto se puede llamar con sets asi: [Rex::Text::UpperAlpha,

Rex::Text:::LowerAlpha, Rex::Text::Numerals]

pero lo deje asi para mirarlo mas rapidamente con NetBeans

Antes que nada les doy gracias por su tiempo, y quedo a la espera de una
pronta respuesta. Atentamente Gustavo Javier desde Argentina.

P.D.: Si necesitan algo o no quedo clara la pregunta, diganlo que lo
comentare con mas tiempo.

Estuve mirando un poco, hay otra función que llama a converge_sets
tantas
veces como ‘lenght’ le indiques aparte de las veces que se llama
recursivamente. La idea es armar una ensalada de caracteres según las
cadenas que le pasás con ‘sets’, no?. Lo que ví que hace con offsets,
como
dijiste, es tomar, cuando inicia, el primer caracter de cada cadena de
‘sets’ y lo acumulla en ‘buf’, cambia los valores de offsets y asi puede
elegir otros caracteres de la cadena. Si borras la parte ‘else’ del if,
en
converge_sets, te genera una cadena usando siempre los primeros
caracteres
de las cadenas de ‘sets’. Parece que esa parte del while es un algoritmo
de
permutación para mezclar las cadenas. El array ‘offsets’ varía por que
se
pasa como copia.
No sé si ayudó en algo, avisá!

Yo lo probé así:

(esto está extraido de
http://metasploit.com/dev/trac/browser/framework3/trunk/lib/rex/text.rb)

UpperAlpha = “ABCDEFGHIJKLMNOPQRSTUVWXYZ”
LowerAlpha = “abcdefghijklmnopqrstuvwxyz”
Numerals = “0123456789”

def converge_sets(sets, idx, offsets, length) # :nodoc:
buf = sets[idx][offsets[idx]].chr
if (sets[idx + 1])
buf += converge_sets(sets, idx + 1, offsets, length)
else

            while (idx >= 0 and ((offsets[idx] = (offsets[idx] + 1) 

%
sets[idx].length)) == 0)
idx -= 1
end

            if (idx < 0)
                    raise RuntimeError, "Maximum permutations 

reached"
end
end

    buf

end

def pattern_create(length, sets = [ UpperAlpha, LowerAlpha, Numerals ])
buf = ‘’
idx = 0
offsets = []

                 sets.length.times { offsets << 0 }

                 until buf.length >= length
                         begin
                                 buf += converge_sets(sets, 0, 

offsets,
length)
rescue RuntimeError
break
end
end

                 # Maximum permutations reached, but we need more 

data
if (buf.length < length)
buf = buf * (length / buf.length.to_f).ceil
end

                 buf[0,length]

end

pattern_create(1000)

On Tue, Nov 18, 2008 at 11:03 PM, Javier A.

On Wed, Nov 19, 2008 at 2:03 AM, Javier A.
[email protected] wrote:

            while (idx >= 0 and ((offsets[idx] = (offsets[idx] + 1) %

sets[idx].length)) == 0) <-------

Por una parte esta la logica del algoritmo mismo, pero podria ser que
lo que dificulta que entiendas esa condicion es que hay contiene una
asignacion:

offsets[idx] = …

Si es el caso, piensa por ejemplo en

if user = User.find_by_login(params[:login])
# hay user, y se asigno a la variable “user”
end

Sucede que en Ruby las asignaciones son expresiones, evaluan al valor
(o array de valores) que es asignado.

Hay gente a la que no le gusta asignar en una condicion porque se
puede deslizar un bug si en realidad querias “==”, algunas IDEs lo
marcan como warning. Esta bien. A mi en particular me gusta usarlo por
lo compacto que queda, y Rails lo usa por todas partes.

Claro, ahi tengo el problema yo, vos decis que se pasa como referencia,
entonces la modificacion que le hago a offsets dentro de converge_sets
queda
accesible desde los otros lados???.

Y Juan tenias razon con tu suposicion es un metodo que se encarga de
hacer
una permutacion de caracteres indicandoles un tamaño, y cualquier ayuda
o
punto de vista viene bien!

El 19 de noviembre de 2008 6:24, Juan Matías [email protected]
escribió:

Perdón, ‘offset’ no se pasa como copia. Se pasa como referencia.

2008/11/19 Juan Matías [email protected]

while (idx >= 0 and ((offsets[idx] = (offsets[idx] + 1) %
sets[idx].length)) == 0)
idx -= 1
end

Ahora sí! , mirá, si probás en una consola:
Suponiendo una cadena de 5 caracteres

1 % 5
=> 1
2 % 5
=> 2
3 % 5
=> 3
4 % 5
=> 4
5 % 5
=> 0

Cuando el valor de ‘offsets’, en este caso el tercer elemento, alcanza
el
valor igual a la longitud de la tercer cadena lo pone en 0 y pasa al
segundo
elemento del offset, le suma 1 y vuelva a alternar sobre el tercer
elemento
de ‘offsets’.

Cadenas Offsets Buf+=
ABC, abc, 012 [0,0,0] Aa0
ABC, abc, 012 [0,0,1] Aa1
ABC, abc, 012 [0,0,2] Aa2 #Acá ‘offsets[2]’ se pone en cero
porque
es el resultado del módulo y suma 1 a offsets[1]
ABC, abc, 012 [0,1,0] Ab0
ABC, abc, 012 [0,1,1] Ab1
ABC, abc, 012 [0,1,2] Ab2 #Acá ‘offsets[2]’ se pone en cero
porque
es el resultado del módulo y suma 1 a offsets[1]
ABC, abc, 012 [0,2,0] Ac0
ABC, abc, 012 [0,2,1] Ac1
ABC, abc, 012 [0,2,2] Ac2 #Acá ‘offsets[2]’ se pone en cero
porque
es el resultado del módulo y suma 1 a offsets[1]
etc…etc…

Está muy bueno, y muy simple. Bah, simple, ahora que lo entiendo. Nunca
se
me hubiese ocurrido.

2008/11/19 Javier A. [email protected]

Ah, disculpen que no responda ahora pero me tengo que ir a trabajar.

Otra cosa, mi problema no es con la asignacion, lo que me pasa con ese
while
es que no entiendo para que usa el modulo, ya que al usarlo como esta
ahi
solo seria true (o diferente de nil ;-)) cuando el offsets este
apuntando al
ultimo caracter???

El 19 de noviembre de 2008 6:38, Javier A.
[email protected]escribió:

Consulte en san google y no pude sacarme la ultima duda, perdon si soy
muy
pesado.

Pero Juan, como sabes cuando un mensaje (argumento en C) es mandado por
referencia en vez de por valor. Me refiero al tipico ejemplo del C. que
pasando el argumento como puntero como &variable te permite modificarla.
Como se hace esto con ruby.

En otras palabras como sabes que offsets se paso por referencia???

El 19 de noviembre de 2008 13:35, Javier A.
[email protected]escribió:

ahhhhhhh, ahora si estamos. Hay que decir que al que se le ocurrio ese
codigo no tenia mucho tiempo libre, ejjejeeje. Gracias a todos por su
ayuda!

El 19 de noviembre de 2008 7:36, Juan Matías [email protected]
escribió:

Se llama referencia por valor como dijo Xavier. Estás pasando la
instancia
del array y modificándola dentro de otra función, estás tocando la
instancia.

Si!, soy amante de la consola. Ejemplo:

def modificar(string); string[3] = ‘-’ ;end
a = “123456789”
=> “123456789”
modificar(a)
=> “-”
a
=> “123-56789”

Que no es lo mismo que:

a = “123456789”
def modificar(string); string = “123-56789”; end
modificar(a)
=> “123-56789”
a
=> “123456789”

A esto se refiere Xavier con referencia por valor, no?

Como te dije borré el while y ví que los caracteres no se mezclaban, ahí
recordé esta cuestión de la referencia y la copia.

2008/11/19 Xavier N. [email protected]

El 19/11/2008, a las 19:31, Juan Matías
escribió:> Se llama referencia por valor como dijo Xavier. Estás pasando la

instancia del array y modificándola dentro de otra función, estás
tocando la instancia.

Para evitar que una función modifique el valor, se suele usar dup

funcion_que_modifica_variable(variable.dup)

Aunque en ruby no suele ser necesario.

2008/11/19 Juan Matías [email protected]:

a = “123456789”
def modificar(string); string = “123-56789”; end
modificar(a)
=> “123-56789”
a
=> “123456789”

A esto se refiere Xavier con referencia por valor, no?

Exacto.

Al pasar referencias, si el objeto al que apuntan es mutable puede
suceder que el metodo cambie su estado. Pero eso no tiene que ver con
el argot “paso por referencia/valor”.

Como las referencias se pasan por valor, lo que no podras hacer es
cambiarle la referencia misma al caller. Es lo que ilustra el segundo
ejemplo.

2008/11/19 Javier A. [email protected]:

Pero Juan, como sabes cuando un mensaje (argumento en C) es mandado por
referencia en vez de por valor. Me refiero al tipico ejemplo del C. que
pasando el argumento como puntero como &variable te permite modificarla.
Como se hace esto con ruby.

Ruby, C y Java solo tienen paso por valor. Perl solo tiene paso por
referencia.

Cuando en C usas & estas pasando un puntero por valor. En Java y en
Ruby uno pasa referencias por valor.

Agradezco su ayuda, ya he entendido como viene la cosa.

Bueno, aunque sea por un rato!!!

Gracias a todos

El 19 de noviembre de 2008 16:40, Xavier N. [email protected]
escribió:

El 19/11/2008, a las 20:07, Guillermo Álvarez Fernández
escribió:> Para evitar que una función modifique el valor, se suele usar dup

funcion_que_modifica_variable(variable.dup)

Aunque en ruby no suele ser necesario.

Perdón por la tremenda gilipollez que acabo de poner. :frowning:

Buenas gente,

Lanzo un request a los que esteis utilizando gettext en la sala (a
poder ser la 1.93.0) para ver si os ocurre lo mismo que a mi (y os doy
la solución).

Escenario:

  • Un modelo con varios campos (pongamos 15)
  • Con algunos campos “obligatorios” (validates_presence_of …)
  • Con un formulario normalillo utilizando el helper “error_message_on”
    en el template.
  • Provad a intentar grabar un registro sin nada rellenado (para que
    salten las validaciones)

Contad los segundos que tarda en renderizarse el template con los
errores, si te dá más de 30 segundos, has ganado un gallifante.

En nuestro caso en producción la cosa se lleva 120 segundos en
renderizar.

¡¡¡¡ 120 segundos !!!

Cosas del gettext. Si os mirais las vueltas que da para mostrar el
error_message_on os puede pasar algo. (Todavia me estoy recuperando).

Total, si has llegado hasta aqui después de hacer la prueba y te ha
tardado muuuucho en renderizar los errores, puedes buscarte la vida tu
mismo, o aplicar el hack que me acabo de sacar de la manga:

------------ CUT HERE -----------------
module ActiveRecord
class Errors
def localize_error_messages(append_field = true) # :nodoc:
# e.g.) foo field: “%{fn} foo” => “Foo foo”, “foo” => “Foo foo”.
return @__errors unless @__errors.nil?
@__errors = {}
each {|attr, msg|
next if msg.nil?
@__errors[attr] ||= []
@__errors[attr] << localize_error_message(attr, msg,
append_field)
}
@__errors
end
end
end
------------ CUT HERE -----------------

Básicamente sobreescribimos el método localize_error_messages de
gettext para que “cachee” el resultado de los errores localizados, si
quereis investigar más y os atreveis a echarle mas mano a gettext, el
pollo está en gettext/active_record.rb, en las lineas 281 a 336 aprox.

Espero vuestras pruebas y comentarios.

Salutaciones,

Isaac Feliu