Menú

Mostrar Mensajes

Esta sección te permite ver todos los mensajes escritos por este usuario. Ten en cuenta que sólo puedes ver los mensajes escritos en zonas a las que tienes acceso en este momento.

Mostrar Mensajes Menú

Mensajes - Serapis

#831
Demos por hecho que tienes cargada la lista con 40 elementos...

Lo siguiente, es acomodar los controles label o textbox, a un array de controles.
Esto se hace creando un control (depositando con el ratón una instancia en la ventana de la interfaz), y luego seleccionarlo, copiarlo y pegarlo,... Preguntará si quieres crear un array de controles, le dices que sí y pegas tantas copias como necesites... Supongamos pues que son 6, y sean labels o textbox, para el ejemplo no importa.

Label1(0) hasta Label1(5).
Fíjate que en vb6, será un array de controles si tienen exactamente el mismo nombre (y están en la misma ventana) ... El índice habitualmente irá desde 0 hasta, 1 menos del total, esto es, si hay 6, hasta el label1(5). En realidad es una diccionario, no es un array, lo que se descubre fácilmente en 2 detalles... 1° es posible asignar un índice como 582 al label(5) durante diseño, y 2° porque dinámicamente se cargan con la instrucción Load y descargan con Unload, y no con redim y erase respectivamente...

El botón, es mejor que llame a una función que será la que hará el trabajo y a la que podremos crear y pasar los parámetros que nos interesen. Como método del botón, el evento click, ya tiene su propios parámetros, lo que da menos juego y lo deja más sucio...

Sabes lo que quieres hacer, te falta aprender a crear los conceptos para transformar luego en código... Analicemos :

- tenemos un listbox, ergo una lista... Aquí aparece una variable (que usaremos como tal)
- tenemos que la lista tiene 3 detalles de interés al caso: La cantidad que contiene, el índice para referirnos a un elemento y su valor... De aquí salen 2 variables (el valor se constata del objeto (ya lo auto contirnr la lista): índice y cantidad en la lista.
- tenemos finalmente una cantidad a copiar con cada llamada, que es exactamente la cantidad de labels... De aquí sale la última variable necesaria.

Ahora, pasemos a la lógica del programa:
1 Hay una lista con 'x' elementos.
2 Hay 'y' labels.
3 Hay un botón, que cuando se pulsa transfiere los siguientes 'y' elementos de la lista a los labels.
La lógica declara que necesitamos 'recordar', por donde vamos, para poder continuar en otra ocasión, justo por el punto en que quedamos.
Hay un detalle necesario, pero que se queda en la ambigüedad, por que no le has dado solución... Y es, qué pasa cuando se llega al final de la lista... Lo dejaré sin terminar (pero dejo esta nota de recordatorio) , queda a tu esfuerzo concretar el caso y aplicar la solución. >:D :laugh: :silbar:

Código (vb) [Seleccionar]

Din Index as integer ' recuerda dónde nos quedamos. De entrada vale 0.

Private sub command1_click()
   Call TransferirSiguienteGrupo(index, 6) ' 6 es la cantidad a transferir...
End sub

Private sub TransferirSiguienteGrupo(byref Indice as integer, byval Items as integer)
   Din k as integer, j as integer

   For k=indice to indice +Items-1
       Label1(j).caption = listbox1.list(k)
       J =(j+1)
   Next

   Indice=(indice+items)
End sub


...y eso es casi todo... Cuando lo pruebes funcionará, hasta llegar al final de la lista que dará error, pues falta por definir, qué sucede en tal situación y que dejo a tu esfuerzo el resolverlo, porque si no, te estaría haciendo la tarea completa...
#832
Cuál es la dificultad o dónde te pierdes?.
...y qué tienes hecho hasta el momento?.
#833
Empieza por hacerte entender...

¿Qué es un 'Curp' ?. Puedo imaginar que se trate de algún tipo de codificación específica, pero seguramente tan específica que fuera de cierto ámbito, nadie más sepa de qué se trata.

Haciendo una búsqueda llego a wikipedia: https://es.wikipedia.org/wiki/Clave_Única_de_Registro_de_Población

Donde se aclara que tal 'Curp' es en efecto una codificación específica de Méjico.
Pués no parece tan complicado generar dicho código. Simplemente crea funciones para obtener cada campo solicitado que se vayan concatenando...

Sea al caso los datos:
Nombre: José de la Cierva
Apellidos: Columbus Pacificus
Fecha de Nacimiento: 2020/12-31
Género: Varón
País de Nacimiento: Méjico, Yucatán





Código ( vb) [Seleccionar]


public function CrrearCurp(byref Nombre as string, byref Apellidos as string, byref FechaNac as date, byval Varon as boolean, byref NacidoEn as string, optional EsExtranjero as boolean)
  dim curp as string

  curp = spaces(18)

  mid$(curp,1,2)= GetDataApellido1(apellidos)   ' CO...
  mid$(curp,3,1) = GetDataApellido2(apellidos)   ' COP...
  mid$(curp,4,1) = GetDataNombre(Nombre)      ' COPC
  mid$(curp,5,6) = GetFechaToString(FechaNac) ' COPC201231...
  mid$(curp, 11,1) = GetValueGenero(varon)   ' COPC201231H...

  ' ya ya tienes 11 de los 18 dígitos... el resto tampoco son más complicados....

  CrearCurp = ucase$(curp) ' todo en mayúsculas...
end function

' se reclama primera letra y y primera vocal del primer apellido:
private function GetDataApellido1(byref Apellidos as string) as string
   dim k as integer, j as integer, vocal as string, letra1 as string

   letra1 = left$(apellidos)
   vocal = GetFirstVocal(Apellidos, 2)

   GetDataApellido1 = (letra1 & vocal)
end function


' se considera que no habrá errores, luego no se tratan...
private function GetFirstVocal(byref Word as string, byval Inicio as integer) as string
   dim k as integer

   k = instr(ucase$(word), "A", " ", Inicio)
   If (k= 0) then  
       k = instr(ucase$(word), "E", " ", Inicio)
       If (k= 0) then
           k = instr(ucase$(word), "I", " ", Inicio)
           If (k= 0) then
               k = instr(ucase$(word), "O", " ", Inicio)
               If (k= 0) then    
                   k = instr(ucase$(word), "U", " ", Inicio)  
               end if
           end if
       end if
   end if

   GetFirstVocal = mid$(word, inicio, 1)
end function

Código ( vb) [Seleccionar]

private function GetFirstVocal(byref Word as string, byval Inicio as integer) as string
   dim k as integer, j as integre, i as integer

    j=len(Word)
   Word = ucase$(Word)
   For k =Inicio to j
       i= instr("AEIOU", mid$(Word, k))
       If i >0 then
           GetFirstVocal=mid$("AEIOU", i, 1)
           Exit for
       End if
   Next
End function

' se reclama solo la primera letra del segundo apellido
private function GetDataApellido2(byref Apellidos as string) as string
   dim k as integer

   k= instr(apellidos," ",1)
   GetDataApellido2 = mid$(apellidos,k,1)
end function

' se reclama solo la primera letra del nombre y si es compuesto la primera del ultimo sobrenombre, si dicho sobrenombre fueran: Maria o José.
private function GetDataNombre(byref Nombre as string) as string
   dim k as integer

   k= instrrev(nombre, " ")
   if (k=0) then
       GetDataNombre = left$(Nombre, 1)
   else    ' si el nombre es compuesto, se devuelve la primera letra del último sobrenombre 'José de la Cierva', devuelve la 'C' de 'cierva'
       sobrenombre = ucase$(right$(nombre, k, len(nombre)-k))
       if ((sobrenombre = "MARÍA") or (sobrenombre= "JOSÉ")) then            
           GetDataNombre = mid$(nombre, k,1)
       else
           GetDataNombre = left$(Nombre, 1)
       end if
   end if
end function

' entendemos que viene en el formato tipo de datos 'date' si viene en otro formato, desde luego debe ajustarse al caso...
private function GetFechaToString(byref Fecha as date) as string
   dim f as string

   f= Format(fecha, "yy/MM/dd")

   GetFechaToString = replace(f, "/", "")
end function

' Los valores elegidos para representar el campo son ambiguos, pués ambos pueden siginificar ambas cosas, son intercambiables, como se ve:
'    H = "Hombre" o "Hembra"
'    M = "Macho/Masculino" o "Mujer"
private function GetValueGenero(byval Varon as boolean) as string
   if (varon= true) then
       GetValueGenero = "H"  'ver comentario, igual es el otro...
   else
       GetValueGenero = "M"  'ver comentario, igual es el otro...
   end if


Te he resuelto los primeros 11 caracteres del código, a tu esfuerzo queda el resto....
Date cuenta que hay más condicionantes, que dado que tu eres el interesado tendrás que empaparte de ellos, y corregir donde proceda... yo solo he leído el artículo de wikipedia por encima... y seguramente en la página del gobierno puedas encontrar una descripción más  detallada de cada detalle de los campos.

P. D.: me edito... Antes de mirar en Wikipedia, leí en otra parte una desafortunada descripción que me indujo a malinterpretar el segundo valor del código.. . Y al verlo hoy recordé que luego olvidé corregir... La función tachada...
#834
El problema de eliminar determinados programas 'completamente', es que hay librerías compartidas... que son utilizadas por otras aplicaciones y que al insistir (usar métodos desesperados) en 'eliminarlos completamente', se corra el riesgo de que alguna aplicación no funcione o peor... cuelgue el sistema. Un problema que luego suele ser más complicado de solucionar.
#835
Es la demostración explícita del sesgo en el entrenamiento de los algoritmos... más aún, que en las personas. El porcentaje de diferentes detalles en la alimentación del algoritmo (el ambiente circundante en el caso de las personas), determina, marca, justifica el sego del aprendizaje...
#836
No respondiendo precisamente al tema, pero igualmente supongo que puede ser apreciado por aquellos a los que estos temas les resulta de interés...


La fuerza bruta sería aún más improductible, si el password fuera hasheado en el 'servidor' con dos algoritmos disitintos ... pués exige que un mismo password coincida con los hashes almacenados para sendos algoritmos, esto reduce notablemente dos posibilidades:
1 xxxxx: Hallar un hash para el password recibido que colisione con el hash generado para el password original. ...es demostrable que cuanto más pequeña sea la contraseña original, más fácil es que logre hallarse por una colisión.

Se eleva el costo de encontrar las soluciones por colisión a:
    espacio de combinaciones: combinacionesAlgoritmo(A) * CombinacionesAlgoritmo(B)

- No debe confundirse que 'CombAlgA * CombAlgB' sea igual que 'combAlgA con password del doble de tamaño'. Éste último valor suele ofrecer muchas más combinaciones, pero complica enormemente al usuario al tener que exigirle el doble de caracteres para sus contraseñas.
Esto, curiosamente puede ser contraproducente, ya que ante tales exigencias (exigir un tamaño muy grande para las contraseñas) los usuarios suelen simplificar las contraseña en base a repetir caracteres y en general introducir secuencias más simples, lo que en definitiva en vez de aumentar la seguridad, la acaba reduciedo logrando el efecto contrario al deseado. Esto es tanto más cierto, cuanto más 'zoquete-negado' sea un usuario digital.

2 xxxxx: Explotar posibles vulnerabilidades halladas en uno o ambos algoritmos de hashing, para generar un password que colisione con el hash aún conociendo uno u ambos hashes. Nótese que el interés especial del diseño descrito estriba sobre todo en la fortaleza que se logra con esto...
- El producto de dos hashes, simplemente reduce las posibilidades de que un password distinto del original, colisione con el password original (sin necesidad de que para ello intervenga el propio usuario). Y aunque a priori no parezca muy importante porque las colisiones son difíciles, aumenta exponencialmente la fuerza de los algoritmos de hashes ante posible defectos en su diseño. Es decir complica enormemente explotar fallos y fugas en la fuerza del diseño del algoritmo. Por ello ambos algoritmos deben ser sutancialmente muy distintos, para así asumir que ambos no adolecen de exactamente los mismos errores.
Conociendo las vulnerabilidades de un algoritmo dado, y conocido un hash a ser generado, puede sortearse el algoritmo para encontrar algún password que colisione con el hash esperado. Sin embargo, ese password (que no es el original), y que ha sido generado al efecto aprovechando los defectos del diseño, acabará fallando para generar el hash con el segundo algoritmo, pués incluso aunque éste tenfa también sus defectos, no van a ser coincidentes con el previo.



Lo interesante del caso, es que con apenas unas líneas más de código (y un inapreciable tiempo de cálculo extra, que para el caso de la seguridad el tiempo de contrastar contraseñas favorece la seguridad, pués ralentiza los intentos de fuerza bruta), la seguridad aumenta notablemente.

Al caso, para no malograrlo, no deberían cometerse errores, como concatenar ambos hashes en uno, o hashear ambos hashes (con alguno u otro algoritmo), debe exigirse el test, con ambos hashes. Algo así:

bolueano = funcion Test(Password, Alias)
    string hash1, hash2
   
    hash1 = hashingAlgA(password)
    hash2 = HaslingAlgB(password)

    devolver (hash1 = Search(Alias, algA)) and (hash2 = Search(Alias, algB))

...donde las funciones 'HashingAlgA' y 'HashingAlgB' son dos funciones distintas de hashing y donde la función 'Search', localiza el hash correspondiente al 'Alias' y el tipo de algoritmo solicitado (algA y algB, serían valores enumerados o cualquier otro que identiifique claramente que hash debe entregarse).

Por supuesto nada impide que al almacenar ambos hashes en el servidor, si estén concatenados (por pura simplicidad) sabiendo que cada uno tiene un número de caracteres prefijado en el diseño y que la función 'Search', discrimina convenientemente.
#837
Primero debes establecer las propiedades:
Minimun y Maximun, no solo Value.

Y después, en el evento de recepción actualizas la propiedad value.
Si el componente de 3ºs proporciona dicho valor en el rango 0-99 (o  1-100), perfecto, si en cambio proporciona el valor transferido (cantidad total de bytes recibidos), debes hacer el cálculo manual para saber a qué porcentaje corresponde dicho valor. Para ello es de suponer que al establece rla conexión en la petición de descarga, devuelve un parámetro u disparará une vento que notifique el tamaño total (necesario para calcular el procentaje).
Si no se proporciona en ningún momento un valor yotal del fichero, es imposible saber el procentaje si el dato proporcionado es la cantidad total descargada...

Si todo te funciona bien, es probabe que el problema sea simplemente lo primero, las propiedad Minimun y Maximun tienen el mismo valor que Value, en vez de 1-100 (ó 0-99, ó 0-100).
#838
Me alegro que lo hayas resuelto.

El uso de string de tamaño fijo es otra solución, aunque si por ejemplo decidiras luego cambiar dinámicamente a 5 u otro cualquier número de columnas, habría que cambiar código.
Una rcomendación es en lo posible adoptar soluciones dinámicas, de tal manera que un cambio de valores no suponga un cambio del código, si no simplemente, pasar los valores adecuados en los parámetros.

Una solución basado en un array sería algo como:
Código ( VB) [Seleccionar]

Dim PosCols() as integer
dim Headers() as string

' Al inicializar la ventana va bien...
'   (dos formas de inicializar un array)
private sub form1_Load()
  posCols = Array(1000, 3500, 7350, 9900)
  Headers = Split("Cantidad, Producto, Precio, Subtotal", ", ")
end sub


Ya tenemos el array con los valores de inicio de cada columna...
Ahora solo falta imprimir en tales posiciones...

En los  headers, remplaza esto:
Código ( VB) [Seleccionar]

Printer.CurrentX = 1000: Printer.Print "Cantidad"
Printer.CurrentX = 3500: Printer.Print "Producto"
Printer.CurrentX = 7350: Printer.Print "Precio"
Printer.CurrentX = 9900: Printer.Print "Subtotal"


por esto:
Código ( VB) [Seleccionar]

    Dim k as integer

    printer.CurrentY = 3000
    for k = 0 to 3
        Printer.CurrentX = posCols(k): Printer.Print Headers(k)
    next


Y luego en el bucle interno (el bucle 'i', que aparece dos veces)...
Código ( VB) [Seleccionar]

        For i = 0 To numCols - 1
            Printer.CurrentX = posCols(i)
            Printer.Print List1.List(j + i)
        Next


Esto invalida la necesidad de 'n', 'anchocol', 'margenizquierdo' y 'anchopapel', aunque insisto en que es preferible parametrizar las funciones, pues les da flexibilidad y puedes reaprovechar código para otros proyectos... el código estático, necesita ser modificado para cada situación. Contradice el paradigma 'orientado a objetos' y favorece el 'código espagueti'...



#839
Dudas Generales / Re: Logaritmo exacto
7 Octubre 2020, 21:42 PM
Cita de: jca1 en  6 Octubre 2020, 23:04 PM
Mi pregunta seria por ejemplo calcular el logaritmo de base 2 con la libreria math de un numero que es por ejemplo 2^(2^(100)) lo haria eficientemente?
Yo he hecho infinitas pruebas de rendimiento, para deliverar entre distitnas formas de hacer algo en un lenguaje, cual ofrece mejor rendimiento y sobretodo al hacer cambios en algoritmos, para saber si la alternativa de cambio ofrece mejor rendimiento... pero jamás he realizado una prueba de rendimiento para determinar la eficiencia de las funciones trigonométricas, principalmente porque si no se hace un uso intensivo de las mismas, no tiene influencia notable en el resultado final de un algoritmo.

Por ejemplo, las funcione seno y coseno si tienen un uso intensivo en el trazado 3D, luego si alguien dispone de una alternativa, puede interesarle hacer unas pruebas de rendimiento y usar así la más eficiente (la que viene nativamente incluída en el lenguaje o tu propia versión).
#840
Me acabo de editar (mientras tu respondías), corrigiéndote la función al completo.... revísa mi mensaje previo y cambia la función en tu código así como la línea que invoca dicha función.

Nota los parámetros que deben ser pasados: si con 4 columnas, pasas 4, si no hay margen izquierdo, pasa 0, etc...

Por cierto, veo que ya le das un valor posicional a cada columna, cuando estableces los valores de currentX, al declarar:
Código ( vb) [Seleccionar]

Printer.CurrentX = 1000: Printer.Print "Cantidad"
Printer.CurrentX = 3500: Printer.Print "Producto"
Printer.CurrentX = 7350: Printer.Print "Precio"
Printer.CurrentX = 9900: Printer.Print "Subtotal"


Es decir están a 1000, 3500, 7350 y 9900. es decir lo estableces manualmente y no tienen un reparto equitativo, si quieres que queden con ese mismo reparto, deberías meter dichos valores en un array. Y usarlo como posición para cada columna.