domingo, 29 de abril de 2018

Los 5 lenguajes más odiados


Lei un articulo sobre los 5 lenguajes más odiados y en parte le doy la razon en parte no.

Los lenguajes son :

  1. Perl
  2. Delphi
  3. VBA
  4. Objective-C
  5. PHP
Voy a empezar con las criticas, primero Delphi no es un lenguaje de programación el lenguaje es object pascal, que como lenguaje no es tan malo, en realidad me resulta mejor que c++. 

Segundo, no se como han listado los lenguajes, porque hay muchos que son más odiables como COBOL o el lenguaje que usaba Clarion.  

Lo positivo es que coincido con casi todos, Perl es inhumano e inentendible, VBA y Objective-C nunca los pude aprender o programar decentemente. 

Pero banco a muerte a Object Pascal y a PHP. Me han dado de comer y pasamos ratos agradables juntos. En mi opinion, se podría hacer un lindo lenguaje totalmente orientado a objeto como Ruby o Scala inspirado en Object Pascal y la rompería. 

Como leerán esto es solo una opinión, y a ustedes que lenguaje no les gusta?

Azure Sphere, el sistema operativo de Microsoft con kernel Linux


A esta altura no me sorprende nada, ya el carton esta lleno. Microsoft presento un sistema operativo con kernel Linux, lo llama Azure Sphere y el objetivo principal es que sea un sistema operativo para internet de las cosas.

Según rumores el principal motivo de utilizar Linux es la seguridad. No existe nada más seguro que un kernel linux.

Dejo un video:


Dejo link: https://www.microsoft.com/en-us/azure-sphere/

jueves, 26 de abril de 2018

Google abre convocatoria para becas de investigación en Latinoamérica: Lara


Quiero hacerme eco de esta noticia. Por las dudas si un pichon de investigador me lee.

Google lanzó la quinta versión de su programa de becas de investigación para Latinoamérica.

El gigante de internet lanzó recientemente la quinta versión de su programa de becas Latin America Research Awards (Lara por sus siglas en inglés). Este programa tiene como objetivo principal solucionar algunos de los desafíos actuales a través de la tecnología.  La convocatoria estará abierta hasta el próximo 25 de mayo de 2018 y solo podrán participar las personas que actualmente sean estudiantes de maestría o doctorado en Latinoamérica, así como aquellos que se desempeñen como profesores o tutores.

Si te interesa, tenes que dejar de leer este blog y leer este :
https://latam.googleblog.com/2018/04/registrate-en-lara-2018-premios-de-investigacion-de-google-para-america-latina.html

Apache Spark Sql

Spark Sql es parte de Spark y permite consultar datos en Spark, utilizando un lenguaje estructurado similar a SQL. Podemos exportar datos a xml, json, etc.

Spark Sql nos permite consultar archivos batch, conjunto de datos Json o tablas Hive. Spark Sql trae características muy útiles y en las ultimas versiones ha agregado importantes mejoras en las que podemos nombrar:

DataFrames: es una abstracción que permite que funcione como SQL query engine distribuido.
Una Api de origen de datos (datasource) que permite conectarse con orígenes de datos de diferente estructura.
Un servidor JDBC que hace fácil conectarnos con base de datos relacionales y permite procesar datos de igual manera que una herramienta BI tradicional.

En un ambiente Spark SQL, los 2 componentes más importantes son el DataFrame y el SQLContext. Que los veremos en próximos posts!!

martes, 24 de abril de 2018

Eclipse Photon is coming...


Eclipse Photon, la decimoséptima versión anual del Proyecto Eclipse, se lanzará el 27 de junio de 2018, por lo visto trae varias mejoras. Entre las que podemos nombrar:


  • Mejoras gráficas y mejor soporte para temas oscuros (que estan de moda)
  • Mejor soporte a java 9 y 10. Por ejemplo, al crear un proyecto de Java 9 (o superior), ahora hay una opción para crear un archivo module-info.java.
  • Todas las rutas de archivos (incluidos los duplicados) se muestran en el cuadro de diálogo Abrir recurso.
  • Todos los archivos se actualizan automáticamente cuando se accede, sin intervención manual.

En fin muchos buenos cambios. Esperamos con ganas esta versión.

Dejo link: https://projects.eclipse.org/releases/photon

sábado, 21 de abril de 2018

Scala y swing se unen gracias scala-swing

Si queremos programar en Scala con ventanas podemos usar la plataforma Java. La plataforma Java nos ofrece diferentes opciones en las que tenemos a Swing.

Pero esto nos puede llevar mucho trabajo y tendríamos que llamar desde Scala funciones de java un lió, por ende Scala nos brinda una librería llamada scala-swing

scala-swing nos permite escribir código swing de forma Scala y a la vez nos facilita muchísimo este trabajo.

Veamos un ejemplo:

Programamos un archivo llamado: Ventana.scala

package com.assembly

import scala.swing._
import scala.swing.event._

object Ventana extends SimpleSwingApplication {

  def top = new MainFrame {
    title = "SwingApp"
    var numclicks = 0

    object label extends Label {
      val prefix = "Tocaste el boton : "
      text = prefix + "0  "
      listenTo(button)
      reactions += {

        case ButtonClicked(button) =>
          numclicks = numclicks + 1
          text = prefix + numclicks
      }

    }

    object button extends Button {
      text = "Soy El buton"
    }

    contents = new FlowPanel {
      contents.append(button, label)
      border = Swing.EmptyBorder(5, 5, 5, 5)
    }
  }

}

Para llamar esta clase podemos utilizar un Objeto, llamado Main :

package com.assembly

object Main {
 
  def main(args: Array[String]): Unit = {
    val ventana = Ventana
    ventana.startup(args)
  }
 
}

Y Listo!!

Dejo link: https://github.com/scala/scala-swing

martes, 17 de abril de 2018

Lenguajes que compilan para Python


Quiero compartir un link sobre un lenguajes que son compatibles con python o que pueden correr sobre la plataforma.

Lo interesante del link es la cantidad de lenguajes funcionales.

Y otra cosa interesante es que se puede bajar el libro: "Functional Programming in Python"

Dejo link:
https://github.com/vindarel/languages-that-compile-to-python
https://github.com/sfermigier/awesome-functional-python

domingo, 15 de abril de 2018

Ejemplo de una aplicación en Spark


La aplicación de muestra en esta sección es una aplicación simple para contar palabras. Este es el mismo ejemplo que se utiliza para enseñar el procesamiento de big data con Hadoop. Realizaremos algunos análisis de datos en un archivo de texto para contar cuántas palabras hay en el archivo y cuántas veces se repiten. El archivo de texto y el conjunto de datos en este ejemplo son pequeños, pero los mismos programas Spark se pueden usar para grandes conjuntos de datos sin modificaciones de código. De forma similar a Hadoop, el entorno de tiempo de ejecución Spark distribuirá automáticamente los datos a diferentes nodos en el clúster para un procesamiento de datos más rápido.
Para mantener el ejemplo simple, usaremos el shell Spark Scala.
Primero, instalemos Spark en nuestra máquina local, esto ya lo vimos en post pasados.
Con spark instalado y listo, podemos utilizar el API de stark para procesar archivos. Por lo tanto abrimos el shell de scala (yo voy a utilizar linux)
Me paro en la carpeta bin de spark y escribo:

$ ./spark-shell
Using Spark's default log4j profile: org/apache/spark/log4j-defaults.properties
Setting default log level to "WARN".
To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).
18/04/15 11:04:39 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
18/04/15 11:04:39 WARN Utils: Your hostname, toto resolves to a loopback address: 127.0.1.1; using 172.17.0.1 instead (on interface docker0)
18/04/15 11:04:39 WARN Utils: Set SPARK_LOCAL_IP if you need to bind to another address
Spark context Web UI available at http://172.17.0.1:4040
Spark context available as 'sc' (master = local[*], app id = local-1523801082307).
Spark session available as 'spark'.
Welcome to
      ____              __
     / __/__  ___ _____/ /__
    _\ \/ _ \/ _ `/ __/  '_/
   /___/ .__/\_,_/_/ /_/\_\   version 2.2.1
      /_/
       
Using Scala version 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_161)
Type in expressions to have them evaluated.
Type :help for more information.

scala> import org.apache.spark.SparkContext
import org.apache.spark.SparkContext

scala> import org.apache.spark.SparkContext._
import org.apache.spark.SparkContext._

scala> val txtFile = "../NOTICE"
txtFile: String = ../NOTICE

scala> val txtData = sc.textFile(txtFile)
txtData: org.apache.spark.rdd.RDD[String] = ../NOTICE MapPartitionsRDD[1] at textFile at <console>:30

scala> txtData.cache()
res2: txtData.type = ../NOTICE MapPartitionsRDD[1] at textFile at <console>:30

scala> txtData.count()
res3: Long = 661                 

De esta manera sabemos la cantidad de lineas de archivo “NOTICE”, si queremos saber la cantidad de veces que aparece las palabras podemos hacer:

scala> val wcData = txtData.flatMap(l => l.split(" ")).map(word => (word, 1)).reduceByKey(_ + _)
wcData: org.apache.spark.rdd.RDD[(String, Int)] = ShuffledRDD[6] at reduceByKey at <console>:36

scala> wcData.collect().foreach(println)
(created,1)
(Unless,4)
(Technology,1)
(Sébastien,1)
...


Lo que hace en la primera linea es :
  • Divide una linea por espacio “ ”
  • Luego crea una tupla (palabra, 1), imaginate que queda algo así: (palabra1,1) , (palabra2,1), (palabra1,1), (palabra1,1)
  • Por lo tanto aplica una reducción por key es decir va sumando cuantas veces aparecen las palabras agrupándolos por key y queda de la siguiente manera: (palabra1,3) , (palabra2,1)


En la segunda linea imprimirme el resultado.

Y Listo!!

viernes, 13 de abril de 2018

Estadísticas de las base de datos relacionales.

Para que una base de datos relacional pueda resolver una consulta SQL de forma óptima necesita conocer los datos físicos de cada tabla, índice o cluster que intervienen en ella. Estos datos se almacenan en el diccionario de datos.

En oracle pueden ser consultadas usando las vistas adecuadas: dba_tables, dba_tab_statistics, dba_tab_col_statistics, dba_tab_histograms, dba_indexes, dba_ind_statistics… etc.

En concreto, es el optimizador quién de todos los planes de ejecución posibles analiza estos datos estadísticos para evaluar cuál de todos supone un menor coste en términos de I/O y uso de CPU.

Las estadísticas deben reflejar verazmente el estado físico de los objetos, y conforme vayan sufriendo transformaciones éstas se irán quedando obsoletas. Es por esto por lo que hay que recopilar las estadísticas de nuevo a medida que ya no reflejen la situación real de los objetos a los que describen.

Si una tabla no posee estadísticas, el motor de base de datos puede recopilar ciertos datos dinámicamente en el momento de la consulta. Esto se llama muestreo dinámico “dynamic sampling”.

Las estadísticas se pueden recopilar  manual o automáticamente. Por omisión, Oracle recopila las estadísticas a través del job programado con scheduler en una ventana de tiempo predefinida: por ejemplo de lunes a viernes de 22:00 a 6:00 y sábados y domingos completos. Durante esta recopilación automática se toman datos de tablas sin estadísticas o con estadísticas obsoletas (que han sufrido más de 10% de modificaciones desde la anterior toma de datos) pero antes debe haberse configurado el parámetro STATISTICS_LEVEL a un valor distinto de BASIC.

En oracle para seguir el número de registros modificados existe la vista existe all_tab_modifications. Ésta muestra el número aproximado de inserciones, modificaciones, borrados y truncados que ha sufrido la tabla desde la última recopilación. La vista es consultable por el usuario pero hay que tener en cuenta que estos datos no son visibles inmediatamente. Existe un retardo de unos minutos para evitar que la escritura interfiera en el rendimiento.

Para recopilar las estadísticas manualmente hay diferentes funciones dependiendo el motor por ejemplo en oracle hay que usar el paquete DBMS_STATS. Dicho paquete tiene métodos para:

  • Recopilar estadísticas.
  • Borrar estadísticas.
  • Guardar y asignar estadísticas.
  • Crear o borrar tablas donde guardar juegos de estadísticas.
  • Bloquear y desbloquear las estadísticas de las tablas.
  • Retornar las estadísticas que tenía una tabla en un momento dado.

En Oracle podemos ejecutar las estadísticas para todos los esquemas de la siguiente forma:

SQL> exec dbms_stats.gather_database_stats;
Procedimiento PL/SQL terminado correctamente.

En Postgres por ejemplo existe una herramienta llamada ANALYZE que permite correr las estadísticas de forma manual :

ANALYZE [ VERBOSE ] [ table_name [ ( column_name [, ...] ) ] ]

Como se puede ver hay diferentes modos de correr esto pero lo más común sería:

ANALYZE VERBOSE users;

En sql server, tambien podemos actualizar las estadísticas utilizando UPDATE STATISTICS o el  stored procedure sp_updatestats, veamos unos ejemplos:

USE AdventureWorks2012;
GO

UPDATE STATISTICS Sales.SalesOrderDetail;
GO

La actualización de estadísticas garantiza que las consultas compilan con estadísticas actualizadas. Sin embargo, actualizar las estadísticas hace que las consultas se recompilen. Por lo tanto puede haber una compensación de rendimiento entre la mejora de los planes de consulta y el tiempo que lleva recompilar las consultas.

Y por ultimo, algo muy importante es hacer backup tambien de las estadísticas, dado que si pasa algo con la base de datos, no solo vamos a querer restaurarla sino tambien que sea usable. Por lo tanto a la hora de hacer backup incluyamos las estadísticas.

jueves, 12 de abril de 2018

Y si , ya se esta hablando de Java 11...


Java 10 no pudo traer otra cosa que los rumores de lo que se viene en java 11.

Primera noticia es que CORBA, Java EE, and JavaFX, ya no tendrán soporte en esta versión. Java 11 también está configurado para perder algunas capacidades mediante la eliminación de los módulos CORBA y Java EE (recientemente renombrado Jakarta EE), así como la eliminación de JavaFX.

Y las nuevas características planificadas incluyen:

  • Epsilon como Java garbage collector , Epsilon manejará la asignación de memoria sin implementar ningún mecanismo de recuperación de memoria. 
  • Una  nueva sintaxis de variable local para parámetros lambda, dado que se debe alinear la sintaxis de una declaración de parámetro formal en una expresión implícitamente tipada con la sintaxis de una declaración de variable local. Esto permitiría usar var cuando se declaran parámetros formales de una expresión lambda implícitamente tipada.
  • El formato de archivo de clase Java se ampliará para soportar un nuevo de grupo constantes, CONSTANT_Dynamic. El objetivo es reducir el costo y la interrupción del desarrollo de nuevas formas de restricciones de archivos de clase materializables.

Como conclusión podemos afirmar que no va ha ver ningún gran cambio en Java 11, solo unos cambios que permitirán mejorar el desempeño del ecosistema java.

Dejo link:
https://www.javaworld.com/article/3266372/core-java/java-11-roadmap-the-new-features-you-can-expect.html

miércoles, 11 de abril de 2018

Tipo de Variables compartidas en Spark



Spark provee 2 tipos de variables compartidas para hacer más eficiente correr spark en un cluster. Hay variables broadcasts y accumutators.

La variable broadcasts, permite a los desarrolladores tener las variables de solo lectura almacenadas en caché en cada máquina en local. Se pueden usar para dar más eficientemente copias de conjuntos de datos de entrada grande a los nodos en el clúster.

Variable accumutators, usan una operación asociativa y, por lo tanto, pueden ser soportados de manera eficiente en paralelo. Se pueden usar para implementar contadores (como en MapReduce) o sumas. Las tareas que se ejecutan en el clúster pueden agregarse a una variable de acumulador mediante el método de agregar. Sin embargo, no pueden leer su valor. Solo el programa del controlador puede leer el valor del acumulador.

martes, 10 de abril de 2018

Entendiendo EXPLAIN PLAN de Oracle


Dado que SQL es un lenguaje declarativo, nosotros no le decimos como hacer las cosas, solo le decimos que hacer. Por lo tanto el motor de base de datos, decide que camino tomar.

Si tenemos un problema de performace en alguna consulta, lo que podemos hacer es pedirle a oracle que nos explique que esta haciendo, y de esta manera ver si le falta un indice o si la podemos ayudar.

La instrucción EXPLAIN PLAN muestra los planes de ejecución elegidos por el optimizador de Oracle para las instrucciones SELECT, UPDATE, INSERT y DELETE. El plan de ejecución de una declaración es la secuencia de operaciones que Oracle realiza para ejecutar la instrucción.

Muestra la siguiente información:
  • Un orden de las tablas a las que hace referencia la consulta o update
  • Un método de acceso para cada tabla mencionada en la consulta o update
  • Un método de combinación para tablas afectadas por operaciones de combinación de la instrucción.
  • Operaciones de datos como filtro, clasificación o agregación
Además la tabla de plan contiene información sobre lo siguiente:
  • Optimización, como el costo y la cardinalidad de cada operación
  • Particionamiento, como el conjunto de particiones accedidas
  • Ejecución paralela
Los resultados de EXPLAIN PLAN le permiten determinar si el optimizador selecciona un plan de ejecución particular, como por ejemplo, bucles anidados. También nos ayuda a comprender las decisiones del optimizador, como por qué el optimizador eligió una unión de bucles anidados en lugar de una combinación de hash, y le permite comprender el rendimiento de una consulta.

Para ejecutar el EXPLAIN PLAN debemos ejecutar por ejemplo esta query:

EXPLAIN PLAN FOR
  SELECT last_name FROM employees;
En este caso se escribio el plan de ejecución en una vista por lo que si queremos verlo, podemos hacer: 

SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY());
Luego podemos escribir otros post que nos enseñen como entender los query plans. Pero eso es todo por ahora. 




sábado, 7 de abril de 2018

Problema de database locking usando hibernate

Tuve un problema de database locking (loqueo en una búsqueda de castellanización) en la aplicación que estoy trabajando, el tema era que nadie debería escribir en la tabla que se loqueaba.

Lo primero que hice es ver el log de hibernate y pedirle que me muestre el sql, eso se logra cambiando el parámetro "show_sql". Analizando los sql, cuando se consultaba esta entidad hibernate hacia unos update y deletes que eran rarísimos, porque solo era una consulta. Es decir no debía hacer eso.

Luego de un analisis del codigo de consulta no encontre nada raro... Por lo tanto me puse a ver el mapeo y tampoco, nada raro...

Luego de caer en un pozo depresivo, vi la luz. Al parecer esta entidad estaba contenida por otra entidad, la cual en el método get ordenaba la lista. Parece ilógico, pero no lo es.

Cuando se hacia un get de esta lista, la aplicación ordenaba la lista y hibernate asumia que esta lista había cambiado, claro el no sabe que ya se había guardado ordenada. Por lo tanto cada vez que se hacia un get, hibernate removía la lista vieja y guardaba una nueva, sin importar si había cambios o no.

No se si esto se arreglo en futuras versiones de hibernate, pero como linea general traten siempre que usen hibernate que los métodos get no hagan nada (solo lo que deben hacer, retornar el valor)

Como lo solucione? muy fácil, hice un método get que no ordenaba, es decir el típico get y hice otro método getSorted que lo use en mi código. Y listo!

Espero que les sirva. 

viernes, 6 de abril de 2018

Libros gratuitos

Me llegaron ests libros de java geeks :

Get schooled by Java Code Geeks

Download Dev Guides!

 
Microsoft Azure is now more than seven years old. Like all seven-year-olds, Azure has been through some memorable teething troubles over the years, as well as some incredible growth and change. Microsoft still faces some significant challenges in increasing the adoption of its Azure platform. As Azure continues to evolve to meet the needs of modern app development processes and systems, developers will need to stay up to date with the latest changes in order to keep using the platform as efficiently as possible. In this eBook, we’ll look back at the history of Microsoft Azure and you’ll learn how to stay up to speed with Microsoft’s latest updates to Azure. You’ll also learn about the effect of the recent .NET Core release, as well as new considerations for app developers working with Azure and new ways they can use the platform to facilitate their app development processes. Finally, we’ll take a look at what’s new with Azure, exploring the innovations that could change the way developers work across platforms, both on-premises and in the cloud.
 
 
The primary intended audience for this document is any expert in professional services who needs to assure the health of SharePoint and systems connected to it. If you’re a systems architect, you can gain understanding of SharePoint components and how other applications can take advantage of SharePoint. If you’re an independent consultant, you’ll learn about the elements of comprehensive coverage and total visibility into operations with prebuilt monitoring configurations. Everything in this eBook is based on real-world examples and configurations where AppDynamics was deployed to monitor SharePoint. There’s no private or identifying information here, but it is not designed for the average SharePoint user. The level of detail can be overwhelming and not very useful for non-technical colleagues. This book can be used to help guide users through specific problems, but make sure that you work through those issues first and do not confuse the user with topics that take more specialized technical knowledge and experience.
 
 
IntelliJ IDEA is a Java integrated development environment (IDE) for developing computer software. It is developed by JetBrains, and is available as an Apache 2 Licensed community edition, and in a proprietary commercial edition. The IDE provides for integration with build/packaging tools like grunt, bower, gradle, and SBT. It supports version control systems like GIT, Mercurial, Perforce, and SVN. Databases like Microsoft SQL Server, ORACLE, PostgreSQL, and MySQL can be accessed directly from the IDE. IntelliJ supports plugins through which one can add additional functionality to the IDE. One can download and install plugins either from IntelliJ’s repository website or through IDE’s inbuilt plugin install feature. 
 
 
Hibernate ORM (Hibernate in short) is an object-relational mapping framework, facilitating the conversion of an object-oriented domain model to a traditional relational database. Hibernate solves the object-relational impedance mismatch problems by replacing direct persistence-related database accesses with high-level object handling functions. Hibernate is one of the most popular Java frameworks out there. For this reason we have provided an abundance of tutorials here at Java Code Geeks, most of which can be found here. Now, we wanted to create a standalone, reference post to provide a framework on how to work with Hibernate and help you quickly kick-start your Hibernate applications. Enjoy!
 

miércoles, 4 de abril de 2018

Spark web console


Cuando corres spark en cualquier modo, se pueden ver los jobs y otras estadísticas en la consola web que se encuentra en : localhost:4040

Esta consola tiene los siguientes tabs: Jobs, Stages, Storage, Environment y Executors.

lunes, 2 de abril de 2018

Ur, un lenguaje funcional puro

Ur es un lenguaje de programación similar a ML y Haskell, pero presenta un sistema de tipos significativamente más rico. Ur es funcional puro, estáticamente tipado y estricto. Ur soporta metaprogramación basada en el sitema de row types.

Ur/Web es Ur más una biblioteca estándar especial y reglas asociadas para el análisis sintáctico y la optimización web. Ur/Web admite la construcción de aplicaciones web dinámicas respaldadas por bases de datos SQL. Ur/Web utiliza el tipado estatioco de tal manera que las paginas generadas no pueden :

  • Sufrir cualquier tipo de ataque de inyección de código
  • Retornar HTML no válido
  • Contiener enlaces muertos o invalidos dentro de la aplicación
  • Tener desajustes entre formularios HTML y los campos esperados por sus controladores
  • Incluir el código del lado del cliente que hace suposiciones incorrectas sobre los servicios de estilo "AJAX" que proporciona el servidor web remoto
  • Intentar consultas SQL no válidas
  • Usar referencias o bases de datos impropias en la comunicación con bases de datos SQL o entre navegadores y servidores web


Este tipo de seguridad es solo la base de la metodología Ur/Web. También es posible usar la metaprogramación para construir piezas de aplicación significativas mediante el análisis de la estructura de tipos. Por ejemplo, la demostración incluye un functor estilo ML para construir una interfaz de administración para una tabla SQL arbitraria. El sistema de tipo garantiza que la sub-aplicación de interfaz siempre estará libre de los errores mencionados anteriormente, sin importar qué descripción de tabla bien tipada.

El compilador de Ur/Web también produce código de objeto muy eficiente que no utiliza la recolección de elementos no utilizados. Estos programas compilados a menudo serán incluso más eficientes de lo que la mayoría de los programadores se tomarían la molestia de escribir en C. Por ejemplo, el servidor web independiente generado para la demostración utiliza menos memoria RAM que el shell bash. El compilador también genera versiones JavaScript del código del lado del cliente, sin necesidad de escribir esas partes de las aplicaciones en un lenguaje diferente.

Y como esto furra poco la implementación de todo esto es de código abierto.

Dejo link: http://www.impredicative.com/ur/