Consultas útiles Oracle parte 1 de 2

Veremos en esta primera entrega algunas “recetas ” , es decir consultas típicas muy útiles para lanzar contra una BBDD Oracle


¿Quién no tiene su chuleta de consultas útiles que se suelen utilizar en el día a día, y en nuestras aventuras y desventuras con un BBDD  Oracle?

En este pequeño  post vamos  a ver un resumen de consultas SQL de Oracle,  basadas  la mayoría sobre las vistas del diccionario de Oracle,  y animo a todo el que quiera añadir otras que considere de utilidad a responder el post publicando las suyas, a ver si entre todos creamos un repositorio que podamos consultar desde cualquier lugar para facilitarnos la vida, o sacarnos de algún que otro apuro.

 

 

Consulta Oracle SQL sobre la vista que muestra el estado de la base de datos

En primer lugar veamos  uan simple consulta muy general para    ver como esta la BBDD  en el momento de la consulta  .

 

La  consulta es bastante sencilla:

select * from v$instance




Con esta interesante consulta podemos  ver el numero de la instancia y su sombre , la version de BBDD, el tiempo desde el que esta arrancada la BBDD y es  estado en general  de la BBDD

Esa vista es tan interesante que de hecho se usa otra consulta Oracle SQL que muestra si la base de datos está abierta  :

select status from v$instance






Consulta Oracle SQL sobre la vista que muestra los parámetros generales de Oracle

Si queremos leer unos  258 parámetros generales de una BBDD  Oracle v 9   , en efecto  podemos recuperar  sus valores directamente con la siguiente consulta:

select * from v$system_parameter






De esta  consulta podemos obtener valores muy  interesantes ,como podemos ver en la pantalla anterior. De hecho basada en esa vista , podemos recuperar  algunos  de los mas importantes   simplemente filtrando  por el campo “name“.   A continuación   aquí algunas de las mas destacadas: 

  • Si solo queremos  conocer la Versión de Oracle   lanzaremos esta consulta

select value from v$system_parameter where name = ‘compatible’

  • Si solo queremos  conocer  la Ubicación y nombre del fichero spfile

select value from v$system_parameter where name = ‘spfile’

  • Esta Consulta Oracle SQL es  para conocer la Ubicación y número de ficheros de control

select value from v$system_parameter where name = ‘control_files

 
  • Y por ultimo una consulta Oracle SQL para conocer el Nombre de la base de datos

select value from v$system_parameter where name = ‘db_name’

 

 

Una vista muy parecida  a v$system  es la vista  v$parameter  ,la cual nos permite ver parámetros de Oracle, valor actual y su descripción

 

SELECT v.name, v.value value, decode(ISSYS_MODIFIABLE, 'DEFERRED',

'TRUE', 'FALSE') ISSYS_MODIFIABLE, decode(v.isDefault, 'TRUE', 'YES',

'FALSE', 'NO') "DEFAULT", DECODE(ISSES_MODIFIABLE, 'IMMEDIATE',

'YES','FALSE', 'NO', 'DEFERRED', 'NO', 'YES') SES_MODIFIABLE,

DECODE(ISSYS_MODIFIABLE, 'IMMEDIATE', 'YES', 'FALSE', 'NO',

'DEFERRED', 'YES','YES') SYS_MODIFIABLE , v.description

FROM V$PARAMETER v

WHERE name not like 'nls%' ORDER BY 1


 




Consulta Oracle SQL sobre la vista que muestra las conexiones actuales a Oracle


Ahora  vamos   a ver la vista v$session . La vista V$SESSION es la base de toda la información relacionada con el estado actual del sistema:

  • ¿Cuántas sesiones hay actualmente corriendo en la base de datos?
  • ¿Qué consulta se está ejecutando?
  • ¿Cuánto tardan en ejecutarse estas consultas?
 V$SESSION es el primer lugar cuando DBA comienza a buscar información relacionada con el rendimiento  e información de la ejecución de las consultas, un DBA puede llegar a consultar un centenar de veces al día esta vista, así que puede ser interesante inspeccionar su contenido


 Como casi todas las consultas que vamos a ver ,para visualizar  el resultado de esta consulta  es necesario entrar con privilegios de administrador


Veamos una consulta general para obtener los usuarios conectados a la BBDD;

select osuser, username, machine, program from v$session order by osuser




También sobre esa misma vista podemos lanzar una consulta  que muestra el número de conexiones actuales a Oracle    agrupado por aplicación que realiza la  conexión:

 

select program Aplicacion, count(program) Numero_Sesiones

from v$session

group by program

order by Numero_Sesiones desc



Otra consulta interesante  basada en la vista v$session ,  es la siguiente que  muestra los usuarios de Oracle conectados y el número de sesiones por usuario:

select username Usuario_Oracle, count(username) Numero_Sesiones

from v$session

group by username

order by Numero_Sesiones desc






Cada vez que se conecta a los datos se crea una sesión en la base de datos para realizar sus operaciones. Un DBA puede ver fácilmente esto consultando la vista de sistema V$SESSION.

Para ello  podemos lanzar  la siguiente consulta (en el caso del entorno RAC, DBA debe utilizar GV$SESSION en lugar de V$SESSION).

selectcount(*),type fromv$sessiongroup by type;

 

 

Puede utilizar la consulta siguiente para identificar qué usuario está creando un número alto de sesiones.

select SID,USERNAME,COMMAND,PROCESS,TERMINAL,PROGRAM from v$session where type=’USER’;

 

 

 

  • SID es la ID de la sesión, USERNAME es el nombre del usuario de la base de datos.
  • Process es el número de proceso. 
  • Terminal es el nombre del sistema que esta ejecutando la consulta. 
  • Program muestra el nombre del programa que esta usando la consulta.



Consultas  sobre el Diccionario de datos

Esta es una de las consultas mas potentes pues incluye todas las vistas y tablas de la Base de Datos. segun la version de la BBDD Oracle  puede llegar la consulta  a lanzar el resultados de unss 500 tablas.

Simplemente    para obtenerla podemos lanzar la siguiente consulta:

select * from dictionary

 

Este es resultado obtenido  lanzado  contra una BBDD Oracle 9:

 

TABLE_NAME COMMENTS
ALL_ALL_TABLES Description of all object and relational tables accessible to the user
ALL_APPLY Details about each apply process that dequeues from the queue visible to the current user
ALL_APPLY_CONFLICT_COLUMNS Details about conflict resolution on tables visible to the current user
ALL_APPLY_DML_HANDLERS Details about the dml handler on tables visible to the current user
ALL_APPLY_ERROR Error transactions that were generated after dequeuing from the queue visible to the current user
ALL_APPLY_KEY_COLUMNS Alternative key columns for a STREAMS table visible to the current user
ALL_APPLY_PARAMETERS Details about parameters of each apply process that dequeues from the queue visible to the current user
ALL_APPLY_PROGRESS Information about the progress made by the apply process that dequeues from the queue visible to the current user
ALL_ARGUMENTS Arguments in object accessible to the user
ALL_ASSOCIATIONS All associations available to the user
ALL_AUDIT_POLICIES All fine grained auditing policies in the database
ALL_BASE_TABLE_MVIEWS All materialized views with log(s) in the database that the user can see
ALL_CAPTURE Details about each capture process that stores the captured changes in a queue visible to the current user
ALL_CAPTURE_PARAMETERS Details about parameters for each capture process that stores the captured changes in a queue visible to the current user
ALL_CAPTURE_PREPARED_DATABASE Is the local database prepared for instantiation?
ALL_CAPTURE_PREPARED_SCHEMAS All user schemas at the local database that are prepared for instantiation
ALL_CAPTURE_PREPARED_TABLES All tables visible to the current user that are prepared for instantiation
ALL_CATALOG All tables, views, synonyms, sequences accessible to the user
ALL_CLUSTERS Description of clusters accessible to the user
ALL_CLUSTER_HASH_EXPRESSIONS Hash functions for all accessible clusters
ALL_COLL_TYPES Description of named collection types accessible to the user
ALL_COL_COMMENTS Comments on columns of accessible tables and views
ALL_COL_PRIVS Grants on columns for which the user is the grantor, grantee, owner,
 or an enabled role or PUBLIC is the grantee
ALL_COL_PRIVS_MADE Grants on columns for which the user is owner or grantor
ALL_COL_PRIVS_RECD Grants on columns for which the user, PUBLIC or enabled role is the grantee
ALL_CONSTRAINTS Constraint definitions on accessible tables
ALL_CONS_COLUMNS Information about accessible columns in constraint definitions
ALL_CONS_OBJ_COLUMNS List of types an object column or attribute is constrained to in the tables accessible to the user
ALL_CONTEXT Description of all active context namespaces under the current session
ALL_DB_LINKS Database links accessible to the user
ALL_DEF_AUDIT_OPTS Auditing options for newly created objects
ALL_DEPENDENCIES Dependencies to and from objects accessible to the user
ALL_DIMENSIONS Description of the dimension objects accessible to the DBA
ALL_DIM_ATTRIBUTES Representation of the relationship between a dimension level and
 a functionally dependent column
ALL_DIM_CHILD_OF Representaion of a 1:n hierarchical relationship between a pair of levels in
 a dimension
ALL_DIM_HIERARCHIES Representation of a dimension hierarchy
ALL_DIM_JOIN_KEY Representation of a join between two dimension tables. 
ALL_DIM_LEVELS Description of dimension levels visible to DBA
ALL_DIM_LEVEL_KEY Representations of columns of a dimension level
ALL_DIRECTORIES Description of all directories accessible to the user
ALL_ERRORS Current errors on stored objects that user is allowed to create
ALL_EVALUATION_CONTEXTS rule evaluation contexts seen by user
ALL_EVALUATION_CONTEXT_TABLES tables in all rule evaluation contexts seen by the user
ALL_EVALUATION_CONTEXT_VARS variables in all rule evaluation contexts seen by the user
ALL_EXTERNAL_LOCATIONS Description of the external tables locations accessible to the user
ALL_EXTERNAL_TABLES Description of the external tables accessible to the user
ALL_INDEXES Descriptions of indexes on tables accessible to the user
ALL_INDEXTYPES All indextypes available to the user
ALL_INDEXTYPE_COMMENTS Comments for user-defined indextypes
ALL_INDEXTYPE_OPERATORS All operators available to the user
ALL_IND_COLUMNS COLUMNs comprising INDEXes on accessible TABLES
ALL_IND_EXPRESSIONS FUNCTIONAL INDEX EXPRESSIONs on accessible TABLES
ALL_IND_PARTITIONS
ALL_IND_SUBPARTITIONS
ALL_INTERNAL_TRIGGERS Description of the internal triggers on the tables accessible to the user
ALL_JOIN_IND_COLUMNS Join Index columns comprising the join conditions
ALL_LIBRARIES Description of libraries accessible to the user
ALL_LOBS Description of LOBs contained in tables accessible to the user
ALL_LOB_PARTITIONS
ALL_LOB_SUBPARTITIONS
ALL_LOB_TEMPLATES
ALL_LOG_GROUPS Log group definitions on accessible tables
ALL_LOG_GROUP_COLUMNS Information about columns in log group definitions
ALL_METHOD_PARAMS Description of method parameters of types accessible
to the user
ALL_METHOD_RESULTS Description of method results of types accessible
to the user
ALL_MVIEWS All materialized views in the database
ALL_MVIEW_AGGREGATES Description of the materialized view aggregates accessible to the user
ALL_MVIEW_ANALYSIS Description of the materialized views accessible to the user
ALL_MVIEW_DETAIL_RELATIONS Description of the materialized view detail tables accessible to the user
ALL_MVIEW_JOINS Description of a join between two columns in the
WHERE clause of a materialized view accessible to the user
ALL_MVIEW_KEYS Description of the columns that appear in the GROUP BY
list of a materialized view accessible to the user
ALL_MVIEW_LOGS All materialized view logs in the database that the user can see
ALL_MVIEW_REFRESH_TIMES Materialized views and their last refresh times  for each master table that the user can look at
ALL_NESTED_TABLES Description of nested tables in tables accessible to the user
ALL_OBJECTS Objects accessible to the user
ALL_OBJECT_TABLES Description of all object tables accessible to the user
ALL_OBJ_COLATTRS Description of object columns and attributes contained in the tables accessible to the user
ALL_OPANCILLARY All ancillary operators available to the user
ALL_OPARGUMENTS All arguments of the operators available to the user
ALL_OPBINDINGS All binding functions for operators available to the user
ALL_OPERATORS All operators available to the user
ALL_OPERATOR_COMMENTS Comments for user-defined operators
ALL_PARTIAL_DROP_TABS All tables with patially dropped columns accessible to the user
ALL_PART_COL_STATISTICS
ALL_PART_HISTOGRAMS
ALL_PART_INDEXES
ALL_PART_KEY_COLUMNS
ALL_PART_LOBS
ALL_PART_TABLES
ALL_PENDING_CONV_TABLES All tables accessible to the user which are not upgraded to the latest type version
ALL_POLICIES All policies for objects if the user has system privileges or owns the objects
ALL_POLICY_CONTEXTS All policy driving context defined for all synonyms, tables, or views accessable to the user
ALL_POLICY_GROUPS All policy groups defined for any synonym, table or view accessable to the user
ALL_PROBE_OBJECTS
ALL_PROCEDURES Description of all procedures available to the user
ALL_PROPAGATION Streams propagation seen by the user
ALL_PUBLISHED_COLUMNS
ALL_QUEUES All queues accessible to the user
ALL_QUEUE_PUBLISHERS
ALL_QUEUE_TABLES All queue tables accessible to the user
ALL_REFRESH All the refresh groups that the user can touch
ALL_REFRESH_CHILDREN All the objects in refresh groups, where the user can touch the group
ALL_REFRESH_DEPENDENCIES Description of the detail tables that materialized views depend on for
refresh
ALL_REFS Description of REF columns contained in tables accessible to the user
ALL_REGISTERED_MVIEWS Remote materialized views of local tables that the user can see
ALL_REGISTERED_SNAPSHOTS Remote snapshots of local tables that the user can see
ALL_REGISTRY_BANNERS
ALL_REPAUDIT_ATTRIBUTE Information about attributes automatically maintained for replication
ALL_REPAUDIT_COLUMN Information about columns in all shadow tables for replicated tables which are accessible to the user
ALL_REPCAT
ALL_REPCATLOG Information about asynchronous administration requests
ALL_REPCOLUMN Replicated top-level columns (table) sorted alphabetically in ascending order
ALL_REPCOLUMN_GROUP All column groups of replicated tables which are accessible to the user
ALL_REPCONFLICT All conflicts with available resolutions for user’s replicated tables
ALL_REPDDL Arguments that do not fit in a single repcat log record
ALL_REPFLAVORS Flavors defined for replicated object groups
ALL_REPFLAVOR_COLUMNS Replicated columns in flavors
ALL_REPFLAVOR_OBJECTS Replicated objects in flavors
ALL_REPGENERATED Objects generated to support replication
ALL_REPGENOBJECTS Objects generated to support replication
ALL_REPGROUP Information about replicated object groups
ALL_REPGROUPED_COLUMN Columns in the all column groups of replicated tables which are accessible to the user
ALL_REPGROUP_PRIVILEGES Information about users who are registered for object group privileges
ALL_REPKEY_COLUMNS Primary columns for a table using column-level replication
ALL_REPOBJECT Information about replicated objects
ALL_REPPARAMETER_COLUMN All columns used for resolving conflicts in replicated tables which are accessible to the user
ALL_REPPRIORITY Values and their corresponding priorities in all priority groups which are accessible to the user
ALL_REPPRIORITY_GROUP Information about all priority groups which are accessible to the user
ALL_REPPROP Propagation information about replicated objects
ALL_REPRESOLUTION Description of all conflict resolutions for replicated tables which are accessible to the user
ALL_REPRESOLUTION_METHOD All conflict resolution methods accessible to the user
ALL_REPRESOLUTION_STATISTICS Statistics for conflict resolutions for replicated tables which are accessible to the user
ALL_REPRESOL_STATS_CONTROL Information about statistics collection for conflict resolutions for replicated tables which are accessible to the user
ALL_REPSCHEMA N-way replication information
ALL_REPSITES N-way replication information
ALL_RULES Rules seen by the user
ALL_RULESETS Rulesets seen by the user: maintained for backward compatibility
ALL_RULE_SETS Rule sets seen by the user
ALL_RULE_SET_RULES Rules in all rule sets seen by the user
ALL_SECONDARY_OBJECTS All secondary objects for domain indexes
ALL_SEQUENCES Description of SEQUENCEs accessible to the user
ALL_SNAPSHOTS Snapshots the user can access
ALL_SNAPSHOT_LOGS All snapshot logs in the database that the user can see
ALL_SOURCE Current source on stored objects that user is allowed to create
ALL_SOURCE_TABLES
ALL_SOURCE_TAB_COLUMNS
ALL_SQLJ_TYPES Description of types accessible to the user
ALL_SQLJ_TYPE_ATTRS Description of attributes of types accessible to the user
ALL_SQLJ_TYPE_METHODS Description of methods of types accessible to the user
ALL_STORED_SETTINGS Parameter settings for objects accessible to the user
ALL_STREAMS_GLOBAL_RULES Global rules created on the streams capture/apply/propagation process that interact with the queue visible to the current user
ALL_STREAMS_SCHEMA_RULES Rules created by streams administrative APIs on all user schemas
ALL_STREAMS_TABLE_RULES Rules created by streams administrative APIs on tables visible to the current user
ALL_SUBPARTITION_TEMPLATES
ALL_SUBPART_COL_STATISTICS
ALL_SUBPART_HISTOGRAMS
ALL_SUBPART_KEY_COLUMNS
ALL_SUBSCRIBED_COLUMNS
ALL_SUBSCRIBED_TABLES
ALL_SUBSCRIPTIONS
ALL_SUMDELTA Direct path load entries accessible to the user
ALL_SUMMARIES Description of the summaries accessible to the user
ALL_SYNONYMS All synonyms accessible to the user
ALL_TABLES Description of relational tables accessible to the user
ALL_TAB_COLS Columns of user’s tables, views and clusters
ALL_TAB_COLUMNS Columns of user’s tables, views and clusters
ALL_TAB_COL_STATISTICS Columns of user’s tables, views and clusters
ALL_TAB_COMMENTS Comments on tables and views accessible to the user
ALL_TAB_HISTOGRAMS Histograms on columns of all tables visible to user
ALL_TAB_MODIFICATIONS Information regarding modifications to tables
ALL_TAB_PARTITIONS
ALL_TAB_PRIVS Grants on objects for which the user is the grantor, grantee, owner,
 or an enabled role or PUBLIC is the grantee
ALL_TAB_PRIVS_MADE User’s grants and grants on user’s objects
ALL_TAB_PRIVS_RECD Grants on objects for which the user, PUBLIC or enabled role is the grantee
ALL_TAB_SUBPARTITIONS
ALL_TRIGGERS Triggers accessible to the current user
ALL_TRIGGER_COLS Column usage in user’s triggers or in triggers on user’s tables
ALL_TYPES Description of types accessible to the user
ALL_TYPE_ATTRS Description of attributes of types accessible to the user
ALL_TYPE_METHODS Description of methods of types accessible to the user
ALL_TYPE_VERSIONS Description of each type version accessible to the user
ALL_UNUSED_COL_TABS All tables with unused columns accessible to the user
ALL_UPDATABLE_COLUMNS Description of all updatable columns
ALL_USERS Information about all users of the database
ALL_USTATS All statistics
ALL_VARRAYS Description of varrays in tables accessible to the user
ALL_VIEWS Description of views accessible to the user
USER_ALL_TABLES Description of all object and relational tables owned by the user’s
USER_AQ_AGENT_PRIVS
USER_ARGUMENTS Arguments in object accessible to the user
USER_ASSOCIATIONS All assocations defined by the user
USER_ATTRIBUTE_TRANSFORMATIONS
USER_AUDIT_OBJECT Audit trail records for statements concerning objects, specifically: table, cluster, view, index, sequence,  [public] database link, [public] synonym, procedure, trigger, rollback segment, tablespace, role, user
USER_AUDIT_POLICIES All fine grained auditing policies for objects in user schema
USER_AUDIT_SESSION All audit trail records concerning CONNECT and DISCONNECT
USER_AUDIT_STATEMENT Audit trail records concerning  grant, revoke, audit, noaudit and alter system
USER_AUDIT_TRAIL Audit trail entries relevant to the user
USER_AWS Analytic Workspaces owned by the user
USER_AW_PS Pagespaces in Analytic Workspaces owned by the user
USER_BASE_TABLE_MVIEWS All materialized views with log(s) owned by the user in the database
USER_CATALOG Tables, Views, Synonyms and Sequences owned by the user
USER_CLUSTERS Descriptions of user’s own clusters
USER_CLUSTER_HASH_EXPRESSIONS Hash functions for the user’s hash clusters
USER_CLU_COLUMNS Mapping of table columns to cluster columns
USER_COLL_TYPES Description of the user’s own named collection types
USER_COL_COMMENTS Comments on columns of user’s tables and views
USER_COL_PRIVS Grants on columns for which the user is the owner, grantor or grantee
USER_COL_PRIVS_MADE All grants on columns of objects owned by the user
USER_COL_PRIVS_RECD Grants on columns for which the user is the grantee
USER_CONSTRAINTS Constraint definitions on user’s own tables
USER_CONS_COLUMNS Information about accessible columns in constraint definitions
USER_CONS_OBJ_COLUMNS List of types an object column or attribute is constrained to in the tables owned by the user
USER_DB_LINKS Database links owned by the user
USER_DEPENDENCIES Dependencies to and from a users objects
USER_DIMENSIONS Description of the dimension objects accessible to the DBA
USER_DIM_ATTRIBUTES Representation of the relationship between a dimension level and
 a functionally dependent column
USER_DIM_CHILD_OF Representaion of a 1:n hierarchical relationship between a pair of levels in
 a dimension
USER_DIM_HIERARCHIES Representation of a dimension hierarchy
USER_DIM_JOIN_KEY Representation of a join between two dimension tables. 
USER_DIM_LEVELS Description of dimension levels visible to DBA
USER_DIM_LEVEL_KEY Representations of columns of a dimension level
USER_ERRORS Current errors on stored objects owned by the user
USER_EVALUATION_CONTEXTS rule evaluation contexts owned by user
USER_EVALUATION_CONTEXT_TABLES tables in user rule evaluation contexts
USER_EVALUATION_CONTEXT_VARS variables in user rule evaluation contexts
USER_EXTENTS Extents comprising segments owned by the user
USER_EXTERNAL_LOCATIONS Description of the user’s external tables locations
USER_EXTERNAL_TABLES Description of the user’s own external tables
USER_FREE_SPACE Free extents in tablespaces accessible to the user
USER_INDEXES Description of the user’s own indexes
USER_INDEXTYPES All user indextypes
USER_INDEXTYPE_COMMENTS Comments for user-defined indextypes
USER_INDEXTYPE_OPERATORS All user indextype operators
USER_IND_COLUMNS COLUMNs comprising user’s INDEXes and INDEXes on user’s TABLES
USER_IND_EXPRESSIONS Functional index expressions in user’s indexes and indexes on user’s tables
USER_IND_PARTITIONS
USER_IND_SUBPARTITIONS
USER_INTERNAL_TRIGGERS Description of the internal triggers on the user’s own tables
USER_JOBS All jobs owned by this user
USER_JOIN_IND_COLUMNS Join Index columns comprising the join conditions
USER_LIBRARIES Description of the user’s own libraries
USER_LOBS Description of the user’s own LOBs contained in the user’s own tables
USER_LOB_PARTITIONS
USER_LOB_SUBPARTITIONS
USER_LOB_TEMPLATES
USER_LOG_GROUPS Log group definitions on user’s own tables
USER_LOG_GROUP_COLUMNS Information about columns in log group definitions
USER_METHOD_PARAMS Description of method parameters of the user’s own types
USER_METHOD_RESULTS Description of method results of the user’s own types
USER_MVIEWS All materialized views in the database
USER_MVIEW_AGGREGATES Description of the materialized view aggregates created by the user
USER_MVIEW_ANALYSIS Description of the materialized views created by the user
USER_MVIEW_DETAIL_RELATIONS Description of the materialized view detail tables of the materialized
views created by the user
USER_MVIEW_JOINS Description of a join between two columns in the
WHERE clause of a materialized view created by the user
USER_MVIEW_KEYS Description of the columns that appear in the GROUP BY
list of a materialized view  created by the user
USER_MVIEW_LOGS All materialized view logs owned by the user
USER_MVIEW_REFRESH_TIMES Materialized views and their last refresh times for each master table that the user can look at
USER_NESTED_TABLES Description of nested tables contained in the user’s own tables
USER_OBJECTS Objects owned by the user
USER_OBJECT_SIZE Sizes, in bytes, of various pl/sql objects
USER_OBJECT_TABLES Description of the user’s own object tables
USER_OBJ_AUDIT_OPTS Auditing options for user’s own tables and views
USER_OBJ_COLATTRS Description of object columns and attributes contained in tables owned by the user
USER_OPANCILLARY All ancillary opertors defined by user
USER_OPARGUMENTS All operator arguments of operators defined by user
USER_OPBINDINGS All binding functions or methods on operators defined by the user
USER_OPERATORS All user operators
USER_OPERATOR_COMMENTS Comments for user-defined operators
USER_OUTLINES Stored outlines owned by the user
USER_OUTLINE_HINTS Hints stored in outlines owned by the user
USER_PARTIAL_DROP_TABS User tables with unused columns
USER_PART_COL_STATISTICS
USER_PART_HISTOGRAMS
USER_PART_INDEXES
USER_PART_KEY_COLUMNS
USER_PART_LOBS
USER_PART_TABLES
USER_PASSWORD_LIMITS Display password limits of the user
USER_PENDING_CONV_TABLES All user’s tables which are not upgraded to the latest type version
USER_POLICIES All row level security policies for synonyms, tables, or views owned by the user
USER_POLICY_CONTEXTS All policy driving context defined for synonyms, tables, or views in current schema
USER_POLICY_GROUPS All policy groups defined for any synonym, table, or view
USER_PROCEDURES Description of the users own procedures
USER_PROXIES Description of connections the user is allowed to proxy
USER_PUBLISHED_COLUMNS
USER_QUEUES All queues owned by the user
USER_QUEUE_PUBLISHERS
USER_QUEUE_SCHEDULES
USER_QUEUE_TABLES All queue tables created by the user
USER_REFRESH All the refresh groups
USER_REFRESH_CHILDREN All the objects in refresh groups, where the user owns the refresh group
USER_REFS Description of the user’s own REF columns contained in the user’s own tables
USER_REGISTERED_MVIEWS Remote materialized views of local tables currently using logs owned by the user
USER_REGISTERED_SNAPSHOTS Remote snapshots of local tables currently using logs owned by the user
USER_REGISTRY
USER_REPAUDIT_ATTRIBUTE Information about attributes automatically maintained for replication
USER_REPAUDIT_COLUMN Information about columns in all shadow tables for user’s replicated tables
USER_REPCAT
USER_REPCATLOG Information about the current user’s asynchronous administration requests
USER_REPCOLUMN Replicated columns for the current user’s table in ascending order
USER_REPCOLUMN_GROUP All column groups of user’s replicated tables
USER_REPCONFLICT
USER_REPDDL Arguments that do not fit in a single repcat log record
USER_REPFLAVORS Flavors current user created for replicated object groups
USER_REPFLAVOR_COLUMNS Replicated columns from current user’s tables in flavors
USER_REPFLAVOR_OBJECTS Replicated user objects in flavors
USER_REPGENERATED Objects generated for the current user to support replication
USER_REPGENOBJECTS Objects generated for the current user to support replication
USER_REPGROUP Replication information about the current user
USER_REPGROUPED_COLUMN Columns in the all column groups of user’s replicated tables
USER_REPGROUP_PRIVILEGES Information about users who are registered for object group privileges
USER_REPKEY_COLUMNS Primary columns for a table using column-level replication
USER_REPOBJECT Replication information about the current user’s objects
USER_REPPARAMETER_COLUMN All columns used for resolving conflicts in user’s replicated tables
USER_REPPRIORITY Values and their corresponding priorities in user’s priority groups
USER_REPPRIORITY_GROUP Information about user’s priority groups
USER_REPPROP Propagation information about the current user’s objects
USER_REPRESOLUTION Description of all conflict resolutions for user’s replicated tables
USER_REPRESOLUTION_METHOD All conflict resolution methods accessible to the user
USER_REPRESOLUTION_STATISTICS Statistics for conflict resolutions for user’s replicated tables
USER_REPRESOL_STATS_CONTROL Information about statistics collection for conflict resolutions for user’s replicated tables
USER_REPSCHEMA N-way replication information about the current user
USER_REPSITES N-way replication information about the current user
USER_RESOURCE_LIMITS Display resource limit of the user
USER_RESUMABLE Resumable session information for current user
USER_ROLE_PRIVS Roles granted to current user
USER_RSRC_CONSUMER_GROUP_PRIVS Switch privileges for consumer groups for the user
USER_RSRC_MANAGER_SYSTEM_PRIVS system privileges for the resource manager for the user
USER_RULES Rules owned by the user
USER_RULESETS Rulesets owned by the user: maintained for backward compatibility
USER_RULE_SETS Rule sets owned by the user
USER_RULE_SET_RULES Rules in user rule sets
USER_SECONDARY_OBJECTS All secondary objects for domain indexes
USER_SEGMENTS Storage allocated for all database segments
USER_SEQUENCES Description of the user’s own SEQUENCEs
USER_SNAPSHOTS Snapshots the user can look at
USER_SNAPSHOT_LOGS All snapshot logs owned by the user
USER_SOURCE Source of stored objects accessible to the user
USER_SOURCE_TABLES
USER_SOURCE_TAB_COLUMNS
USER_SQLJ_TYPES Description of the user’s own types
USER_SQLJ_TYPE_ATTRS Description of attributes of the user’s own types
USER_SQLJ_TYPE_METHODS Description of methods of the user’s own types
USER_STORED_SETTINGS Parameter settings for objects owned by the user
USER_SUBPARTITION_TEMPLATES
USER_SUBPART_COL_STATISTICS
USER_SUBPART_HISTOGRAMS
USER_SUBPART_KEY_COLUMNS
USER_SUBSCRIBED_COLUMNS
USER_SUBSCRIBED_TABLES
USER_SUBSCRIPTIONS
USER_SUMMARIES Description of the summaries created by the user
USER_SYNONYMS The user’s private synonyms
USER_SYS_PRIVS System privileges granted to current user
USER_TABLES Description of the user’s own relational tables
USER_TABLESPACES Description of accessible tablespaces
USER_TAB_COLS Columns of user’s tables, views and clusters
USER_TAB_COLUMNS Columns of user’s tables, views and clusters
USER_TAB_COL_STATISTICS Columns of user’s tables, views and clusters
USER_TAB_COMMENTS Comments on the tables and views owned by the user
USER_TAB_HISTOGRAMS Histograms on columns of user’s tables
USER_TAB_MODIFICATIONS Information regarding modifications to tables
USER_TAB_PARTITIONS
USER_TAB_PRIVS Grants on objects for which the user is the owner, grantor or grantee
USER_TAB_PRIVS_MADE All grants on objects owned by the user
USER_TAB_PRIVS_RECD Grants on objects for which the user is the grantee
USER_TAB_SUBPARTITIONS
USER_TRANSFORMATIONS
USER_TRIGGERS Triggers owned by the user
USER_TRIGGER_COLS Column usage in user’s triggers
USER_TS_QUOTAS Tablespace quotas for the user
USER_TYPES Description of the user’s own types
USER_TYPE_ATTRS Description of attributes of the user’s own types
USER_TYPE_METHODS Description of methods of the user’s own types
USER_TYPE_VERSIONS Description of each version of the user’s types
USER_UNUSED_COL_TABS User tables with unused columns
USER_UPDATABLE_COLUMNS Description of updatable columns
USER_USERS Information about the current user
USER_USTATS All statistics on tables or indexes owned by the user
USER_VARRAYS Description of varrays contained in the user’s own tables
USER_VIEWS Description of the user’s own views
AUDIT_ACTIONS Description table for audit trail action type codes.  Maps action type numbers to action type names
COLUMN_PRIVILEGES Grants on columns for which the user is the grantor, grantee, owner, or
 an enabled role or PUBLIC is the grantee
DATABASE_COMPATIBLE_LEVEL Database compatible parameter set via init.ora
DBMS_ALERT_INFO
DBMS_LOCK_ALLOCATED
DICTIONARY Description of data dictionary tables and views
DICT_COLUMNS Description of columns in data dictionary tables and views
DUAL  
GLOBAL_NAME global database name
INDEX_HISTOGRAM statistics on keys with repeat count
INDEX_STATS statistics on the b-tree
NLS_DATABASE_PARAMETERS Permanent NLS parameters of the database
NLS_INSTANCE_PARAMETERS NLS parameters of the instance
NLS_SESSION_PARAMETERS NLS parameters of the user session
RESOURCE_COST Cost for each resource
ROLE_ROLE_PRIVS Roles which are granted to roles
ROLE_SYS_PRIVS System privileges granted to roles
ROLE_TAB_PRIVS Table privileges granted to roles
SESSION_PRIVS Privileges which the user currently has set
SESSION_ROLES Roles which the user currently has enabled.
TABLE_PRIVILEGES Grants on objects for which the user is the grantor, grantee, owner,
 or an enabled role or PUBLIC is the grantee
ALL_HISTOGRAMS Synonym for ALL_TAB_HISTOGRAMS
ALL_JOBS Synonym for USER_JOBS
ALL_OUTLINES Synonym for USER_OUTLINES
ALL_OUTLINE_HINTS Synonym for USER_OUTLINE_HINTS
ALL_SNAPSHOT_REFRESH_TIMES Synonym for ALL_MVIEW_REFRESH_TIMES
CAT Synonym for USER_CATALOG
CLU Synonym for USER_CLUSTERS
COLS Synonym for USER_TAB_COLUMNS
DICT Synonym for DICTIONARY
GV$ACTIVE_INSTANCES Synonym for GV_$ACTIVE_INSTANCES
GV$ACTIVE_SESS_POOL_MTH Synonym for GV_$ACTIVE_SESS_POOL_MTH
GV$AW_CALC Synonym for GV_$AW_CALC
GV$AW_OLAP Synonym for GV_$AW_OLAP
GV$AW_SESSION_INFO Synonym for GV_$AW_SESSION_INFO
GV$BH Synonym for GV_$BH
GV$LOADISTAT Synonym for GV_$LOADISTAT
GV$LOADPSTAT Synonym for GV_$LOADPSTAT
GV$LOCK_ACTIVITY Synonym for GV_$LOCK_ACTIVITY
GV$MAX_ACTIVE_SESS_TARGET_MTH Synonym for GV_$MAX_ACTIVE_SESS_TARGET_MTH
GV$MLS_PARAMETERS Synonym for GV_$MLS_PARAMETERS
GV$NLS_PARAMETERS Synonym for GV_$NLS_PARAMETERS
GV$NLS_VALID_VALUES Synonym for GV_$NLS_VALID_VALUES
GV$OPTION Synonym for GV_$OPTION
GV$PARALLEL_DEGREE_LIMIT_MTH Synonym for GV_$PARALLEL_DEGREE_LIMIT_MTH
GV$PQ_SESSTAT Synonym for GV_$PQ_SESSTAT
GV$PQ_TQSTAT Synonym for GV_$PQ_TQSTAT
GV$QUEUEING_MTH Synonym for GV_$QUEUEING_MTH
GV$RSRC_CONSUMER_GROUP Synonym for GV_$RSRC_CONSUMER_GROUP
GV$RSRC_CONSUMER_GROUP_CPU_MTH Synonym for GV_$RSRC_CONSUME_GROUP_CPU_MTH
GV$RSRC_PLAN Synonym for GV_$RSRC_PLAN
GV$RSRC_PLAN_CPU_MTH Synonym for GV_$RSRC_PLAN_CPU_MTH
GV$SESSION_LONGOPS Synonym for GV_$SESSION_LONGOPS
GV$TEMPORARY_LOBS Synonym for GV_$TEMPORARY_LOBS
GV$TIMEZONE_NAMES Synonym for GV_$TIMEZONE_NAMES
GV$VERSION Synonym for GV_$VERSION
IND Synonym for USER_INDEXES
OBJ Synonym for USER_OBJECTS
SEQ Synonym for USER_SEQUENCES
SM$VERSION Synonym for SM_$VERSION
SYN Synonym for USER_SYNONYMS
TABS Synonym for USER_TABLES
USER_HISTOGRAMS Synonym for USER_TAB_HISTOGRAMS
USER_SNAPSHOT_REFRESH_TIMES Synonym for USER_MVIEW_REFRESH_TIMES
V$ACTIVE_INSTANCES Synonym for V_$ACTIVE_INSTANCES
V$ACTIVE_SESS_POOL_MTH Synonym for V_$ACTIVE_SESS_POOL_MTH
V$AW_CALC Synonym for V_$AW_CALC
V$AW_OLAP Synonym for V_$AW_OLAP
V$AW_SESSION_INFO Synonym for V_$AW_SESSION_INFO
V$BH Synonym for V_$BH
V$INSTANCE Synonym for V_$INSTANCE
V$LOADISTAT Synonym for V_$LOADISTAT
V$LOADPSTAT Synonym for V_$LOADPSTAT
V$LOCK_ACTIVITY Synonym for V_$LOCK_ACTIVITY
V$MAX_ACTIVE_SESS_TARGET_MTH Synonym for V_$MAX_ACTIVE_SESS_TARGET_MTH
V$MLS_PARAMETERS Synonym for V_$MLS_PARAMETERS
V$NLS_PARAMETERS Synonym for V_$NLS_PARAMETERS
V$NLS_VALID_VALUES Synonym for V_$NLS_VALID_VALUES
V$OPTION Synonym for V_$OPTION
V$PARALLEL_DEGREE_LIMIT_MTH Synonym for V_$PARALLEL_DEGREE_LIMIT_MTH
V$PARAMETER Synonym for V_$PARAMETER
V$PQ_SESSTAT Synonym for V_$PQ_SESSTAT
V$PQ_TQSTAT Synonym for V_$PQ_TQSTAT
V$QUEUEING_MTH Synonym for V_$QUEUEING_MTH
V$RSRC_CONSUMER_GROUP Synonym for V_$RSRC_CONSUMER_GROUP
V$RSRC_CONSUMER_GROUP_CPU_MTH Synonym for V_$RSRC_CONSUMER_GROUP_CPU_MTH
V$RSRC_PLAN Synonym for V_$RSRC_PLAN
V$RSRC_PLAN_CPU_MTH Synonym for V_$RSRC_PLAN_CPU_MTH
V$SESSION Synonym for V_$SESSION
V$SESSION_CONNECT_INFO Synonym for V_$SESSION_CONNECT_INFO
V$SESSION_LONGOPS Synonym for V_$SESSION_LONGOPS
V$SQLAREA Synonym for V_$SQLAREA
V$SQLTEXT Synonym for V_$SQLTEXT
V$SYSTEM_PARAMETER Synonym for V_$SYSTEM_PARAMETER
V$TEMPORARY_LOBS Synonym for V_$TEMPORARY_LOBS
V$TIMEZONE_NAMES Synonym for V_$TIMEZONE_NAMES
V$VERSION Synonym for V_$VERSION


Basándonos en el resultado  anterior  vamos a  ver algunas consultas sencillas ,por ejemplo:

  • Podemos lanzar  una consulta  que muestra los datos de una tabla especificada.En este caso filtramos  por todas las tablas que lleven la cadena “XXX”:  select * from ALL_ALL_TABLES where upper(table_name) like ‘%XXX%’
  • Consulta  que muestra las descripciones de los campos de una tabla especificada, peor en este caso con todas las tablas que lleven la cadena “XXX”: select * from ALL_COL_COMMENTS where upper(table_name) like ‘%XXX%’
  • Consulta para conocer las tablas propiedad del usuario actual: select * from user_tables
  • Consulta  para conocer todos los objetos propiedad del usuario conectado a Oracle  select * from user_catalog

 

 

Enviar correo internamente usando JavaMail API

Veremos como enviar fácilmente correos electrónicos en nuestra aplicación móvil mediante el Android Studio


En realidad no es demasiado difícil crear un aplicación capaz de enviar correos electrónicos usando el IDE de Android Studio  .De hecho gracias al APi de Javmail   podremos enviar e-mails sin utilizar la aplicación de correo electrónico que android incluye por defecto utilizando javamail API para crear nuestro propio email del remitente herramientas que enviará correo internamente.

Tenemos que seguir los pasos que se dan a continuación:

1. Descargar los archivos de biblioteca de api de java.

Tenemos que descargar  tres   librerías java: 

    1. activation.jar
    2. mail.jar.
    3.  additionnal.jar

    Lo puede descargar de Clic aquí.

    2 Ahora crear una  app en Android studio

    3-Ir a la carpeta del proyecto -> aplicación -> libs y agregue todos los archivos jar en libs ahora uno por uno, haga clic en biblioteca de archivos en la opción haga clic en Agregar como biblioteca en todos los archivos jar.

    libs

    También puede Agregar biblioteca por otro camino, pero lo  importante es que incluya esta tres librerías:

    1. activation.jar
    2. mail.jar.
    3.  additionnal.jar

    Ir a archivo >Proyecto estructura > seleccione aplicación> opción derecha haga clic en dependencias ahora haga clic en el botón de pulse(+) para agregar > seleccione dependencia de archivo> archivo seleccione Biblioteca > OK.

    addjar

    4. Ahora abrir el archivo manifest.xml y poner los permisos de internet.

     <uses-permission android:name="android.permission.INTERNET"/>

    Ahora busque manifiesto está buscando como.

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.sp.sendmailinternally">
        <uses-permission android:name="android.permission.INTERNET"/>
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    </manifest>

    4. Ahora abrael fichero  activity_main.xml para crear el archivo de diseño agregar después de código.

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/activity_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        tools:context="com.sp.sendmailinternally.MainActivity">
        <EditText
            android:id="@+id/edittext_recipient_id"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="Recipient Email"
            android:textSize="18sp" />
        <EditText
            android:id="@+id/edittext_subject"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="Subject"
            android:textSize="18sp" />
        <EditText
            android:id="@+id/edittext_message"
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:gravity="start"
            android:hint="Message"
            android:textSize="18sp" />
        <Button
            android:id="@+id/btn_send_mail"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:text="Send Mail"
            android:textAllCaps="false" />
    </LinearLayout>

    5. Cree la  clase de Asyntask para el envío de llamada correo API.

    package com.sp.sendmailinternally;
    import android.app.ProgressDialog;
    import android.content.Context;
    import android.os.AsyncTask;
    import android.widget.Toast;
    import java.util.Properties;
    import javax.mail.Message;
    import javax.mail.MessagingException;
    import javax.mail.PasswordAuthentication;
    import javax.mail.Session;
    import javax.mail.Transport;
    import javax.mail.internet.InternetAddress;
    import javax.mail.internet.MimeMessage;
    /**
     * Created by ps205 on 3/1/17.
     */
    public class SendMailAsynTask extends AsyncTask<Void, Void, Void> {
        //Declaring Variables
        private Context context;
        private Session session;
        //Information to send email
        private String email;
        private String subject;
        private String message;
        //Progressdialog to show while sending email
        private ProgressDialog progressDialog;
        //Class Constructor
        public SendMailAsynTask(Context context, String email, String subject, String message) {
            //Initializing variables
            this.context = context;
            this.email = email;
            this.subject = subject;
            this.message = message;
        }
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            //Showing progress dialog while sending email
            progressDialog = ProgressDialog.show(context, "Sending message", "Please wait...", false, false);
        }
        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);
            //Dismissing the progress dialog
            progressDialog.dismiss();
            //Showing a success message
            Toast.makeText(context, "Message Sent", Toast.LENGTH_LONG).show();
        }
        @Override
        protected Void doInBackground(Void... params) {
            //Creating properties
            Properties props = new Properties();
            //Configuring properties for gmail
            //If you are not using gmail you may need to change the values
            props.put("mail.smtp.host", "smtp.gmail.com");
            props.put("mail.smtp.socketFactory.port", "465");
            props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
            props.put("mail.smtp.auth", "true");
            props.put("mail.smtp.port", "465");
            //Creating a new session
            session = Session.getDefaultInstance(props,
                    new javax.mail.Authenticator() {
                        //Authenticating the password
                        protected PasswordAuthentication getPasswordAuthentication() {
                            return new PasswordAuthentication(Config.EMAIL, Config.PASSWORD);
                        }
                    });
            try {
                //Creating MimeMessage object
                MimeMessage mm = new MimeMessage(session);
                //Setting sender address
                mm.setFrom(new InternetAddress(Config.EMAIL));
                //Adding receiver
                mm.addRecipient(Message.RecipientType.TO, new InternetAddress(email));
                //Adding subject
                mm.setSubject(subject);
                //Adding message
                mm.setText(message);
                //Sending email
                Transport.send(mm);
            } catch (MessagingException e) {
                e.printStackTrace();
            }
            return null;
        }
    }

    6. Ahora abra MainActivity.java y agregue el siguiente código.

    package com.sp.sendmailinternally;
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.view.View;
    import android.widget.Button;
    import android.widget.EditText;
    public class MainActivity extends AppCompatActivity {
        EditText edittext_recipient_id, edittext_subject, edittext_message;
        Button btn_send_mail;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            //initializr vista para encontar vista por id
            edittext_recipient_id = (EditText) findViewById(R.id.edittext_recipient_id);
            edittext_subject = (EditText) findViewById(R.id.edittext_subject);
            edittext_message = (EditText) findViewById(R.id.edittext_message);
            btn_send_mail = (Button) findViewById(R.id.btn_send_mail);
    //activar un listener  onclick en un  boton
            btn_send_mail.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    //get  input data from view
                    String mRecipientMail = edittext_recipient_id.getText().toString();
                    String mSubject = edittext_subject.getText().toString();
                    String mMessage = edittext_message.getText().toString();
                    new SendMailAsynTask(MainActivity.this, mRecipientMail, mSubject, mMessage).execute();
    //llama al contructor de send mail asyntask mediante el envio de un parametroperameter } }); } }

    7. Ya puede construir y ejecutar la aplicación  

    Nota:- cuando ponga su id debe ser accesible acceso menos seguro aplicaciones .Para cambiar configuración para motivos de seguridad de correo vaya a cambiar la configuración   y actiíela .

     

    sendmail1

    Por cierto todo el código  esta disponible en descargar código fuente

     

     

     

    ¿Que se puede hacer para mejorar el rendimiento de las consultas en Oracle 11?

    Para mejorar las consultas en oracle nos ayudamos de los indices, los cuales serán mas útil cuanto mas rápido podamos encontrar un registro en él respecto buscarlo en la tabla padre; de aquí se deduce fácilmente que todos los índices que podemos crear no son igual de efectivos, además de que conforme evolucionan los datos dentro de la tabla y por tanto dentro de sus índices, dicha efectividad puede cambiar con el tiempo. Por otro lado, hay ocasiones en los que sale a cuenta mirar directamente la tabla en lugar de pasar antes por el índice.


    Tradicionalmente para mejorar el rendimiento de las consultas en SQL contra una BBDD Oracle , una vez optimizada la consulta con técnicas  de Tuneling ( por ejemplo usando Hints si procede) ,   siempre pasamos a dos técnicas clásicas :

    • Reconstruyendo los  índices existente en base de datos ,para lo cual previamente comprobaremos si esos índices deberían de ser reconstruidos  
    • Actualizando estadísticas sobre las tablas que realizamos las consultas.

    Veamos mas despacio de que estamos hablando: 

     

    Reconstrucción de indices

    El índice de una base de datos es una estructura de datos que mejora la velocidad de las operaciones, permitiendo un rápido acceso a los registros de una tabla por lo que se suelen usar sobre aquellos campos sobre los cuales se vayan a realizar búsquedas frecuentes dado que su  funcionamiento es similar al índice de un libro: guardando duplas de elemento que se desea indexar junyo a su posición en la base de datos, de modo que para buscar un elemento que esté indexado, sólo necesitamos que buscar en el índice de dicho elemento para, una vez encontrado, devolver el registro que se encuentre en la posición marcada por el índice.

    Los índices pueden ser creados usando una o más columnas, preparando la base de datos tanto para búsquedas rápidas al azar como para ordenaciones eficientes de los registros.

    Los índices son construidos sobre árboles B, B+, B* o sobre una mezcla de ellos, funciones de cálculo u otros métodos.

    El espacio en disco requerido para almacenar el índice es típicamente menor que el espacio de almacenamiento de la tabla (puesto que los índices generalmente contienen solamente los campos clave de acuerdo con los que la tabla será ordenada, y excluyen el resto de los detalles de la tabla), lo que da la posibilidad de almacenar en memoria los índices de tablas que no cabrían en ella. En una base de datos relacional un índice es una copia de parte de una tabla.

    La siguiente consulta SQL mostrará el tamaño en megabytes de un índice determinado, en nuestro caso del índice PK_FACTURACION_CODIGO perteneciente a la tabla FACTURACION y el campo CODIGO del ejemplo. La consulta SQL para mostrar el tamaño ocupado por un índice es la siguiente:

    select segment_name, sum(bytes)/1024/1024 MB
    from dba_extents
    where segment_name = ‘INDICE DE EJEMPLO’
    group by segment_name

     

     

    Es importante periódicamente examinar y determinar qué índices son susceptibles de ser reconstruidos. Cuando un índice está descompensado puede ser porque algunas partes de éste han sido accedidas con mayor frecuencia que otras dando como resultado problemas de contención de disco o cuellos de botella en el sistema.

    Normalmente reconstruimos un índice con el comando ALTER INDEX  (esta sentencia se utiliza para cambiar o reconstruir un índice existente en la base de datos).

    Para poder ejecutar este comando el índice debe de estar en el propio esquema donde intentes ejecutarlo o deberías de tener el privilegio alter any index. También tenemos que tener en cuenta que para realizar la reconstrucción de un índice deberíamos de tener cuota suficiente sobre el tablespace que lo lanzamos.

    Para reconstruir un índice bastaría con lazar la siguiente sentencia

    ALTER INDEX <index_name> REBUILD;

    Para reconstruir una partición de un índice podríamos hacer lo siguiente

    ALTER INDEX <index_name> REBUILD PARTITION <nb_partition> NOLOGGING;

    Nota: En algunos casos cuando alguno de los índices tiene algún tipo de corrupción no es posible reconstruirlo. La solución en este caso es borrar el índice y recrearlo

     

     

     

    Actualización de estadísticas

    Cuando una base de datos Oracle recibe una sentencia “SQL” para resolver una consulta, se llevan a cabo diversas acciones para lograr la entrega del resultado.

    Dentro de los diversos pasos uno de los más importantes es el llevado a cabo por el optimizador basado en costos “Cost Based Optimizer o CBO”. Para que el “CBO” pueda determinar de forma exacta el plan de ejecución de para un “SQL Query” debe disponer de la información de las estadísticas de las tablas e índices que participan en el “SQL Query”, esta información comúnmente es conocida como “Optimizer statistics” “Estadisticas del optimizador”, la misma describe como esta compuesto y distribuido internamente el objeto.

    Estas estadísticas son utilizadas por el optimizador para elegir el mejor plan de ejecución para cada instrucción SQL.

    El tiempo necesario para colectar las estadísticas en algunos casos puede ser de gran medida. En el manejador se pueden utilizar diversos métodos para tratar de reducir el tiempo de esta tarea en la mayor proporción posible.

     

    Es importante tener por tanto actualizadas las estadísticas de la base de datos. Para saber si las estadísticas se están lanzando correctamente podemos hacer una consulta sobre la tabla ALL_INDEXES en oracle 11  (en Oracle 10  es  dba_indexes )y ver el campo last_analyzed para observar cuando se ejecutaron sobre ese índice las estadísticas.

    Nota: la columna “LAST_ANALYZED” la cual puede ser encontrada en vistas tales como: “DBA_TABLES”, “DBA_INDEXES”, “DBA_TAB_COL_STATISTICS” indica la fecha en que fue calculada la estadística para dicho objeto por ultima vez.

     

    Como ejemplo  , si queremos  saber cuando fue la ultima vez que se ejecutaron estadísticas sobre todas las tablas perteneciente a un determinado esquema de BBDD  lanzaremos la siguiente consulta:

    SELECT LAST_ANALYZED,table_name FROM ALL_INDEXES ;

     

     

    Como vemos con las fechas podemos  hacernos una idea , de lo actualizado que están las estadisticas   sobre cada tabla   

    Para actualizar las estadísticas de forma global para  un  esquema de BBDD,  podemos utilizar  el paquete DBM_STATS  de la la siguiente forma:

    Execute DBMS_STATS.gather_schema_stats(‘Esquema’);

     

    Una vez actualizadas las estadísticas de los índices de la base de datos lanzamos la siguiente consulta:

    SELECT LAST_ANALYZED,table_name FROM ALL_INDEXES ;
    SELECT index_name, blevel,
    DECODE(blevel,0,'OK BLEVEL',1,'OK BLEVEL',2,
    'OK BLEVEL',3,'OK BLEVEL',4,'OK BLEVEL','BLEVEL HIGH') OK
    FROM dba_indexes where table_owner='DBPROD08';

     

    Con esta sentencia obtendremos el nombre nombre del índice, el blevel y si es correcto este indice.

    Los índices que deberíamos de reconstruir son los que en la columna ok aparecen como BLEVEL HIGH.

    Blevel (branch level) es parte del formato del B-tree del índice e indica el número de veces que ORACLE ha tenido que reducir la búsqueda en ese índice. Si este valor está por encima de 4 el índice debería de ser reconstruido.

    .

    Extracción de datos de un pdf desde Java

    Veremos como es posible automatizar al extraccion de informacion contenida en un fichero en formato pdf


    A veces  necesitamos  extraer información de texto procedente de  ficheros  en formato pdf   por ejemplo  para automatizar la extracción de determinada información  relevante que contengan o simplemente porque deseamos guardar la información editable  en  otro formato mas amigable. En realidad es realmente interesante    intentar   automatizar esta  tarea  pues así nos   evitamos  manipulaciones manuales   y tediosas lo cual seguramente nos hagan perder mucho tiempo  con la gran escasez de este elemento de la vida moderna del que  tampoco disponemos

    Vamos  a ver dos métodos  para hacerlo  usando el IDE  de  Eclipse y el lenguaje Java

    Método 1; mediante un paso intermedio con conversión previa de los ficheros pdf a ficheros de texto

    PDF to TXT Converter es una aplicación de Windows para convertir archivos pdf a archivos de formato de texto sin formato en modo batch. Este programa también admite la conversión de rango de páginas específicas a archivos txt  de modo que después de la conversión, obtendrá el texto editable del documento PDF original

    PDF to TXT Converter

    Esta  utilidad la podemos descargar   desde  aqui

    Hay una pequeña pega con este programa, pues dado que es shareware en la versión gratuita   tiene  bastantes limitaciones ,entre ellas que no se procesaran más de 200 documentos de un sola vez  ( si se intenta con más de esa cantidad   el programa pierde el control)

    Un punto a su favor es que permite convertir automáticamente directorios enteros  con contenido de ficheros pdf y de este modo no necesitamos seleccionar  uno a uno cuál de ellos queremos convertir ( pero no olvide que, a no ser que compre la version completa, solo debería contener como máximo 200  ficheros)

    Como vemos ,lo interesante de este programa  es que permite convertir los  ficheros pdf a texto  lo cual nos facilitara  procesar estos  muy fácilmente desde   java

    Ahora    vamos a   ver un ejemplo    cómo extraer  los metadatos de un documento  de tipo texto obtenido usando el programa anterior

    La idea es que a partir de los pdf convertidos previamente a txt , es que iremos  leyendo el contenidos de cada fichero txt e  interpretando las cadenas extraidas de los pdf para buscar  por ejemplo cuatro  meta-datos que necesitamos , haciendo  cuenta del orden en el que aparecen asi como las palabras justo anteriors:
    -meta1,
    -meta2
    -meta3
    -meta4:

    En esta búsqueda tiene sentido el número de orden en el que aparecen las cadenas anteriores a  la busqueda  pues según el orden en que aparezca corresponderá a un meta-dato u otro.

    En este caso meta2 hay que buscarlo dos veces , pero según este orden la cadena siguiente es meta2 o meta4

    Veamos el ejemplo;

    //*******************************************************
    //BLOQUE PRINCIPAL PARA EXTRAER  4 METADATOS de un fichero
    //*******************************************************

    //abre el fichero
    Scanner in =null;
    DecimalFormat formateador = new DecimalFormat(“####################”);
    Integer contador=0;

    //solo procesaremos los ficheros con la extrension txt
    if (sub.matches(tipofichero)) try{

    in = new Scanner(new FileReader(nombreFichero));
    in.useLocale(Locale.ENGLISH);

    //lee el fichero palabra a palabra

    while (in.hasNext())
    {
    //lee primera palabra
    String palabra = in.next();
    caa=palabra;

    if (procesa==true)
    {
    //System.out.println(“Palabra:”+palabra+ “contador=”+contador);

    if (contador==1)
    {instalacion=palabra;
    }
    if (contador==5)
    {nif=palabra;
    }

    procesa=false;
    contador++;

    }

    if (caa.matches(“pedido:”))
    {
    // System.out.println(“<<<Palabra pedido: ENCONTRADA:>>>”);
    procesan=true;
    contador++;
    }

    if (caa.matches(“instalación:”))
    {
    //System.out.println(“<<<<Palabra instalación: ENCONTRADA:>>>>”);//fecha
    procesa=true;
    contador++;
    }

    if (caa.matches(“NIF/NIE/Pasaporte:”))
    {
    // System.out.println(“<<<<Palabra NIF/NIE/Pasaporte: ENCONTRADA>>>>”);
    procesa=true;
    contador++;
    }

    //lee números
    while (in.hasNextDouble())
    {
    // lee un double

    double d = in.nextDouble();

    if (procesan==true)
    {
    //System.out.println(“Número:”+formateador.format(d)+”contador=”+contador);
    if (contador==3)
    {pedido=d;
    }
    if (contador==7)
    {linea=d;
    }
    procesan=false;
    contador++;
    }

    }

    } // while (in.hasNext())

    //resumen de datos capturados del pdf convertidos en txt y capturada en 4 campos que necesitamos

    System.out.println(“Instalacion:”+instalacion); //fecha
    System.out.println(“Pedido:”+formateador.format(pedido));
    System.out.println(“NIF:”+nif);
    System.out.println(“Telefono:”+formateador.format(linea));

    ….

     

    Método 2  directo usando la Liberia ItextPDF

    iText es una biblioteca Open Source para crear y manipular archivos PDFRTF, y HTML en Java. Fue escrita por Bruno LowagiePaulo Soares, y otros; está distribuida bajo la Affero General Public License.

    El mismo documento puede ser exportado en múltiples formatos, o múltiples instancias del mismo formato. Los datos pueden ser escritos a un fichero o, por ejemplo, desde un servlet a un navegador web.

    Más recientemente, ha sido extendida a una biblioteca PDF de propósito general, capaz de rellenar formularios, mover páginas de un PDF a otro, y otras cosas. Estas extensiones son a menudo mutuamente excluyentes. Una clase te permite rellenar en formularios, mientras una clase diferente e incompatible hace posible copiar páginas de un PDF a otro.

    El soporte de PDF de iText es, sin embargo, bastante extensivo. Esto soporta firmas basadas en PKI de PDF, cifrado de 40-bit y 128-bit, corrección de colores, PDF/X, gestión de colores por perfiles ICC, y es anfitriona de otras característica

    Podemos descargar el fichero itextpdf-5.1.0.jar  desde el respositorio de Maven   o de esta web  http://www.java2s.com/Code/Jar/i/Downloaditextpdf510jar.htm

    No debemos olvidar importar el jar desde el Ide  del  Eclipse   en propiedades del proyecto-->Java Build Path–>libraries –>Add External   JARs

    Este es un ejemplo  de captura sencilla   de como procesar un pdf directaeente

    import java.io.IOException;

    import com.itextpdf.text.pdf.PdfReader;
    import com.itextpdf.text.pdf.parser.PdfTextExtractor;

    public class prueba {

    /**
    * @param args
    */
    public static void main(String[] args) {
    try {

    PdfReader reader = new PdfReader(“d:/ttttt.pdf”);

    System.out.println(“This PDF has “+reader.getNumberOfPages()+” pages.”);
    String page = PdfTextExtractor.getTextFromPage(reader, 1);
    System.out.println(“Page Content:\n\n”+page+”\n\n”);
    System.out.println(“Is this document tampered: “+reader.isTampered());
    System.out.println(“Is this document encrypted: “+reader.isEncrypted());

    reader.close();
    } catch (IOException e) {
    e.printStackTrace();
    }

    }

    }

    Es importante la sentencia String page = PdfTextExtractor.getTextFromPage(reader, 1);  porque si ponemos 0 o un valor superior daría error

    Como   gracias  a la librería podemos capturar la informacion del   fichero pdf y aplicar la clase Sacanne para analizar las cadenas     para buscar determinada  informacion  que queremos catalogar vamos a  ver   el ejemplo anterior  usando los mismos campos  y con la misma casuitica:

    Este seria el mismo ejemplo de la  primer parte  , pero usando directamente los fichero pdf sin convertir a pdf:

    import java.awt.Rectangle;
    import java.awt.print.PageFormat;
    import java.io.BufferedWriter;
    import java.io.File;
    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.io.PrintStream;
    import java.io.PrintWriter;
    import java.text.DecimalFormat;
    import java.util.List;
    import java.io.BufferedWriter;
    import java.io.File;
    import java.io.FileOutputStream;

    import java.io.IOException;

    import java.io.FileReader;
    import java.io.OutputStreamWriter;
    import java.io.Writer;
    import java.util.Scanner;
    import java.util.Locale;
    import java.io.FileNotFoundException;
    import java.nio.charset.StandardCharsets;
    import java.text.DecimalFormat;

    import java.io.StringReader;

    import java.util.Locale;
    import java.util.Scanner;

    import com.itextpdf.text.pdf.PdfReader;
    import com.itextpdf.text.pdf.parser.PdfTextExtractor;

    public class Main {

    /**
    * @param args
    */

    public static void main(final String[] args) throws IOException {

    String instalacion=””;
    String nif=””;
    double pedido=0;
    double linea=0;
    boolean procesa=false;
    boolean procesan=false;
    String tipofichero=”pdf”; // solo tomaremos ficheros con esta extension
    String caa = substring(20);

    String ruta = “D:\temp\ficheros\”;
    String ficherox=”28348758018_20181201000002.pdf”;
    String fichero=ruta+ ficherox;
    System.out.println(“Fichero a analizar =” +ficherox);

    int numero=ficherox.length()-3; //calcula donde empieza la extension del fichero
    // System.out.println(“numero=”+numero);
    String sub =ficherox.substring( numero); //calcula la extension del fichero
    System.out.println(“Extension del fichero :”+sub);

    //abrimos el PDF
    PdfReader reader = new PdfReader(fichero);
    int pages = reader.getNumberOfPages();
    System.out.println(“Este PDF tiene “+pages+” paginas.”);

    //empezamos la coversion a pdf
    String page = PdfTextExtractor.getTextFromPage(reader, 1); ////<———————————————–aqui da errror
    System.out.println(“Contenido del documento de la pagina “+pages);
    System.out.println(“\n\n”+page+”\n\n”);

    /////////////////////////////////////////////////////////////////////
    //solo procesaremos los ficheros con la extrension pdf
    ////////////////////////////////////////////////////////////////////

    if (sub.matches(tipofichero))

    /// try

    {

    //para procesar el texto lo copiamos a una cadena
    String nombreFichero = page ; //Fichero;

    System.out.println(“Convertido salida del conversor a un String “);

    //borra el scanner
    // Scanner in =null;

    //formatos de numeros
    DecimalFormat formateador = new DecimalFormat(“####################”);

    //inicializa conatdor
    int contador=0;

    //in = new Scanner(new FileReader(nombreFichero));///AQUI ESTA EL PROBLEMA PUES SCANNER NO EST ACEPTADNO EL STRING

    Scanner in = new Scanner(nombreFichero);

    in.useLocale(Locale.ENGLISH);
    System.out.println(“Es correcto el pdfl Convertido salida del conversor a un String “);
    //lee el fichero palabra a palabra

    while (in.hasNext()) //leemos toda la cadena
    {
    //lee primera palabra
    String palabra = in.next();
    caa=palabra;

    if (procesa==true)
    {
    //System.out.println(“Palabra:”+palabra+ “contador=”+contador);

    if (contador==1)
    {instalacion=palabra;
    }
    if (contador==5)
    {nif=palabra;
    }

    procesa=false;
    contador++;

    }

    if (caa.matches(“pedido:”))
    {
    // System.out.println(“<<<Palabra pedido: ENCONTRADA:>>>”);
    procesan=true;
    contador++;
    }

    if (caa.matches(“instalación:”))
    {
    //System.out.println(“<<<<Palabra instalación: ENCONTRADA:>>>>”);//fecha
    procesa=true;
    contador++;
    }

    if (caa.matches(“NIF/NIE/Pasaporte:”))
    {
    // System.out.println(“<<<<Palabra NIF/NIE/Pasaporte: ENCONTRADA>>>>”);
    procesa=true;
    contador++;
    }

    //lee números
    while (in.hasNextDouble())
    {
    // lee un double

    double d = in.nextDouble();

    if (procesan==true)
    {
    //System.out.println(“Número:”+formateador.format(d)+”contador=”+contador);
    if (contador==3)
    {pedido=d;
    }
    if (contador==7)
    {linea=d;
    }
    procesan=false;
    contador++;
    }

    }

    } // while (in.hasNext())
    in.close();

    //resumen de datos capturados del pdf convertido en txt

    System.out.println(“Instalacion:”+instalacion); //fecha
    System.out.println(“Pedido:”+formateador.format(pedido));
    System.out.println(“NIF:”+nif);
    System.out.println(“Telefono:”+formateador.format(linea));

    //fin de metatados de un documento INDIVIDUAL en el xml

    }

    }

    private static String substring(int i) {
    // TODO Auto-generated method stub
    return null;
    }//CLASS
    }

     

     

    Con esta librería como vemos  podemos procesar  de un modo relativamente sencilllo   cualquier contenido de un fichero  pdf    de un modo muy potente  como acabamos de ver .

    Shell scripting : variables y operaciones

    Est post es continuacion de la introduccion a c-shell


    Bash , c-shell  o simplemente shell scripting es  un lenguaje de script  creado a fines de la década de 1980 por un programador llamado Brian Fox, que trabajaba para la Free Software Foundation . Fue pensado como una alternativa de software libre para el shell Bourne (de hecho, su nombre es un acrónimo de Bourne Again SHell ), e incorpora todas las características de ese shell, así como nuevas características como la aritmética de enteros y el control de trabajo

    Bash es un “shell de Unix”, es decir  una interfaz de línea de comandos para interactuar con el sistema operativo por lo que está ampliamente disponible, siendo el shell predeterminado en muchas distribuciones de GNU / Linux y en Mac OSX, con puertos existentes para muchos otros sistemas.

    Además del modo interactivo, donde el usuario escribe un comando a la vez, con ejecución y respuesta inmediatas, Bash (como muchos otros shells) también tiene la capacidad de ejecutar un script completo de comandos, conocido como “Bash shell script” (o “Bash script” o “shell script” o simplemente “script”)  que es justo   lo que vamos a tratar en este post como continuación de un  post anterior introductorio donde exponimos ale tipico Hello world en c-shell

    close up code coding computer

    Tuberías y sustitución de comandos 

    Como hemos visto, el valor de retorno de un comando, tomado estrictamente, es solo un pequeño entero no negativo destinado a indicar el éxito o el fracaso. Su salida real es lo que escribe en el flujo de salida estándar. De forma predeterminada, el texto escrito en el flujo de salida estándar se imprime en el terminal, pero hay algunas formas en que se puede “capturar” y usar como el verdadero valor de retorno del comando.

    Tuberías 

    Cuando una secuencia de comandos se vincula entre sí en una tubería, la salida de cada comando se pasa como entrada al siguiente. Esta es una técnica muy poderosa, ya que nos permite combinar varios programas de utilidad pequeños para crear algo complejo.

    Sustitución de comandos 

    La sustitución de comandos es un poco como expansión de variable, pero ejecuta un comando y captura su salida, en lugar de simplemente recuperar el valor de una variable. Por ejemplo, considere nuestro ejemplo de get_password anterior:

    #! / bin / bash
    
    función get_password (  ) 
    # Uso: get_password VARNAME 
    #Le pide al usuario una contraseña; lo guarda como $ VARNAME.
    # Devuelve un estado de salida distinto de cero si la entrada estándar no #es un terminal, o si el comando  "leer" devuelve un estado de salida #tinto de cero.
    
    {
      if [[ -t 0 ]] ; then
        read -r -p 'Password:' -s "$1" && echo
      else
        return 1
      fi
    }
     
    get_password PASSWORD && echo "$PASSWORD"

    Realmente no hay razón para que la persona que llama deba guardar la contraseña en una variable.

    Si get_password simplemente imprimió la contraseña en su salida estándar, entonces la persona que llama podría usar la sustitución de comandos y usarla directamente:

     #! / bin / bash
     
    función get_password (  ) 
    # Uso: get_password 
    # Pide al usuario una contraseña; Imprime para capturar llamando al código. 
    # Devuelve un estado de salida distinto de cero si la entrada estándar no es un terminal, o si 
    # salida estándar * es * un terminal, o si el comando "leer" devuelve un 
    estado de salida distinto de cero #.
     {
      if [[ -t 0 ]] && ! [[ -t 1 ]] ; then
        local PASSWORD
        read -r -p 'Password:' -s PASSWORD && echo >&2
        echo "$PASSWORD"
      else
        return 1
      fi
    }
     
    echo "$(get_password)"
    
    

    Para evaluar "$ (get_password)" , Bash ejecuta el comando get_password en una subshell, capturando su salida estándar y reemplaza $ (get_password) por la salida capturada.

    Además de la notación $ (...) , también se admite una notación más antigua  (con comillas inversas), y aún se encuentra con bastante frecuencia. Las dos notaciones tienen el mismo efecto, pero la sintaxis de  es más restrictiva y, en casos complejos, puede ser más complicado acertar.

    La sustitución de comandos permite anidar como vemos .  Se permite, expresiones  "$ (b" $ (c) ")" . (es decir ,ejecuta el comando c , usando su salida como un argumento para b , y usando la salida de eso como un argumento para a .)

    Una sustitución de comando puede contener una secuencia de comandos, en lugar de un solo comando de modo que se captura la salida de todos estos comandos.

    Como hemos visto anteriormente, se pueden usar puntos y coma en lugar de líneas nuevas para separar los comandos, lo cual  es particularmente común en la sustitución de comandos.

    Una sustitución de comando puede incluso contener asignaciones de variables y definiciones de funciones (aunque, como los comandos sustituidos se ejecutan dentro de una subshell, las asignaciones de variables y las definiciones de funciones dentro del comando no se verán fuera de ella; solo son útiles si se usan dentro de los comandos sustituidos ).

    Aritmética de shell 

    Las expresiones aritméticas en Bash se modelan estrechamente en las de C, por lo que son muy similares a las de otros lenguajes derivados de C, como C ++, Java, Perl, JavaScript, C # y PHP.

    Una diferencia importante es que Bash solo admite aritmética de enteros (números enteros), no aritmética de punto flotante (decimales y fracciones); Por ejemplo  algo como 3 + 4 significa lo que esperarías (7), pero algo como 3.4 + 4.5 es un error de sintaxis. Algo así como 13/5 está bien, pero realiza una división de enteros, por lo que se evalúa en 2 en lugar de en 2.6.

    Expansión aritmética 

    Quizás la forma más común de usar expresiones aritméticas es en la expansión aritmética , donde el resultado de una expresión aritmética se usa como un argumento para un comando

    . La expansión aritmética se denota $ ((...)) . Por ejemplo, este comando:

     echo  $ ((  3  +  4  *  (  5  -  1  )  ))
    

    impresiones 19 .

    expr (en desuso) 

    Otra forma de usar expresiones aritméticas es mediante el programa Unix “expr”, que era popular antes de que Bash admitiera las matemáticas.  Similar a la expansión aritmética, este comando:

     echo  ` expr 3 + 4  \ *  \ (  5 - 1  \)  `
    

    impresiones 19 .

    Tenga en cuenta que el uso de “expr” requiere un carácter de escape “\” antes del operador de multiplicación “*” y los paréntesis. Tenga en cuenta los espacios entre los símbolos de cada operador, incluidos los paréntesis.

    Operadores numéricos

    Además de las notaciones familiares + (adición) y - (resta), las expresiones aritméticas también son compatibles con * (multiplicación), / (división entera, descrita anteriormente), % (división de módulo, la operación “resto”; por ejemplo, 11 dividido por 5 es 2 el resto 1, entonces 11% 5 es 1 ), y ** (“exponenciación”, es decir, involución; por ejemplo, 2 4 = 16, entonces 2 ** 4 es 16 ).

    Los operadores + y - , además de sus sentidos “binarios” (dos operandos) de “suma” y “resta”, tienen sentidos “unarios” (un operando) de “positivo” y “negativo”. Unary + tiene básicamente ningún efecto; unary - invierte el signo de su operando. Por ejemplo, - (3 * 4) evalúa a -12 , y - (- (3 * 4)) evalúa a 12 .

    Referente a variables 

    Dentro de una expresión aritmética, se puede hacer referencia a las variables de shell directamente, sin usar expansión variable (es decir, sin el signo de dólar $ ).

    Por ejemplo, esto:

     i  =  2 +3
     echo  $ ((  7  * i ))
    

    impresiones 35 . (Tenga en cuenta que primero se evalúa i , que produce 5 y luego se multiplica por 7. Si hubiéramos escrito $ i en lugar de i , se habría realizado una mera sustitución de cadenas; 7 * 2 + 3 es igual a 14 + 3, es decir, 17 – Probablemente no sea lo que queremos.

    El ejemplo anterior se muestra usando “expr”:

     i  =  ` expr 2 + 3  ' 
    eco  ' expr 7  \ *  $ i  `
    

    impresiones 35 .

    Asignación a variables 

    Las variables de shell también se pueden asignar dentro de una expresión aritmética. La notación para esto es similar a la asignación de variables regulares, pero es mucho más flexible.

    Por ejemplo, el ejemplo anterior podría reescribirse así:

     echo  $ ((  7  *  (  i  =  2  +  3  )  ))
    

    excepto que esto establece $ i a 5 en lugar de a 2 + 3 .

    Tenga en cuenta que, aunque la expansión aritmética parece un poco a la sustitución de comandos, se no se ejecuta en un subnivel; este comando realmente establece $ i a 5 , y los comandos posteriores pueden usar el nuevo valor. (Los paréntesis dentro de la expresión aritmética son solo el uso matemático normal de paréntesis para controlar el orden de las operaciones).

    Además del operador de asignación simple = , Bash también admite operadores compuestos como + = , - = , * = , / = y % = , que realizan una operación seguida de una asignación. Por ejemplo, ((i * = 2 + 3)) es equivalente a ((i = i * (2 + 3))) . En cada caso, la expresión en su conjunto se evalúa al nuevo valor de la variable; por ejemplo, si $ i es 4 , entonces ((j = i * = 3)) establece tanto $ i como $ j en 12 .

    Por último, Bash soporta operadores de incremento y decremento.

    El operador incremental ++ incrementa el valor de una variable en 1; si precede al nombre-variable (como el operador “pre-incremento”), entonces la expresión se evalúa al nuevo valor de la variable , y si sigue al nombre-variable (como el operador “post-incremento”), entonces la expresión se evalúa al valor antiguo de la variable .

    Por ejemplo, si $ i es 4 , entonces ((j = ++ i)) establece tanto $ i como $ j en 5 , mientras que ((j = i ++)) establece $ i en 5$ j a 4 . El operador de disminución - es exactamente el mismo, excepto que disminuye el valor de la variable en 1. La reducción previa y posterior de la reducción son completamente análogas al incremento previo y al incremento posterior.

    Las expresiones aritméticas como sus propios comandos 

    Un comando puede consistir completamente en una expresión aritmética, usando cualquiera de las siguientes sintaxis:

     ((  i  =  2 + 3  ))
    
     let  'i = 2 + 3'
    

    Cualquiera de estos comandos establecerá $ i en 5 . Ambos estilos de comando devuelven un estado de salida de cero (“exitoso” o “verdadero”) si la expresión se evalúa como un valor distinto de cero, y un estado de salida de uno (“falla” o “falso”) si la expresión se evalúa como cero. Por ejemplo, esto:

     ((  0  ))  ||  echo zero
     ((  1  ))  &&  echo non-zero
    

    imprimirá esto:

    zero
    non-zero

    La razón de este comportamiento contraintuitivo es que en C, cero significa “falso” y los valores distintos de cero (especialmente uno) significan “verdadero”. Bash mantiene ese legado dentro de las expresiones aritméticas, luego lo convierte en la convención habitual de Bash al final.

    El operador de coma 

    Las expresiones aritméticas pueden contener múltiples sub-expresiones separadas por comas , . El resultado de la última sub-expresión se convierte en el valor general de la expresión completa. Por ejemplo, esto:

     echo  $ ((  i  =  2 , j  =  2  + i, i * j ))
    

    establece $ i en 2 , establece $ j en 4 e imprime 8 .

    De hecho , la función incorporada admite múltiples expresiones directamente sin necesidad de una coma; por lo tanto, los siguientes tres comandos son equivalentes:

     ((  i  =  2 , j  =  2 + i, i * j ))
    
     let  'i = 2, j = 2 + i, i * j'
    
     let  'i = 2'  'j = 2 + i'  'i * j'
    

    Operadores de comparación, booleanos y condicionales 

    Las expresiones aritméticas son compatibles con los operadores de comparación de enteros < , > , <= (significado ≤), > = (significado ≥), == (significado =) y ! = (Significado). Cada uno evalúa a 1 para “verdadero” o 0 para “falso”.

    También son compatibles con los operadores booleanos:

    • && (“and”), que se evalúan como 0 si cualquiera de sus operandos es cero, y 1 de lo contrario;
    •  ||(“or”), que se evalúa en 1 si alguno de sus operandos es distinto de cero, y en 0 en caso contrario;
    • ! (“not”), que se evalúa en 1 si su operando es cero, y en 0 en caso contrario.

    Aparte de que utilizan cero para significar valores “falsos” y valores distintos de cero para significar “verdaderos”, son como los operadores && , || , y ! que hemos visto fuera de expresiones aritméticas. Al igual que esos operadores, estos son operadores “abreviados” que no evalúan su segundo argumento si su primer argumento es suficiente para determinar un resultado. Por ejemplo, (((i = 0) &&(j = 2))) no evaluará el (j = 2)parte, y por lo tanto no establecerá $ j en 2 , porque el operando izquierdo de && es cero (“falso”).

    ¿Y soportan el operador condicional b ? e1 : e2 . Este operador evalúa e1 y devuelve su resultado, si b es distinto de cero; de lo contrario, evalúa e2 y devuelve su resultado.

    Estos operadores se pueden combinar de formas complejas:

     ((  i  =  (  ( a> b && c <d + e ||  f  == g + h ) ? j: k )  ))
    

    Aritmética de bucles 

    Arriba, vimos un estilo de for-loop, que se veía así:

    # imprimir todos los enteros del 1 al 20: 
    for i in {1..20} ; do
      echo $i
    done

    Bash también admite otro estilo, modelado en los bucles for de C y lenguajes relacionados, usando aritmética de shell:

    # imprimir todos los enteros del 1 al 20: 
    for (( i = 1 ; i <= 20 ; ++i )) ; do
      echo $i
    done

    Este bucle for utiliza tres expresiones aritméticas separadas, separadas por punto y coma (y no comas , son expresiones completamente separadas, no solo subexpresiones):

    • La primera es una expresión de inicialización, se ejecuta antes de que comience el bucle.
    • El segundo es una expresión de prueba; se evalúa antes de cada posible iteración del bucle (incluida la primera), y si se evalúa a cero (“falso”), entonces el bucle sale.
    • El tercero es una expresión de conteo; Se evalúa al final de cada iteración de bucle. En otras palabras, este bucle for es exactamente equivalente a este bucle while:
    # imprimir todos los enteros del 1 al 20: 
    (( i = 1 ))
    while (( i <= 20 )) ; do
      echo $i
      (( ++i ))
    done

    pero, una vez que se acostumbre a la sintaxis, se hace más claro lo que está sucediendo.

    Operadores bitwise 

    Además de aritméticas y booleanas operadores regulares, Bash también ofrece a los operadores bit a bit “”, significa que los operadores que operan sobre números enteros qua cadenas de bits en lugar de qua enteros.

    Si aún no está familiarizado con este concepto, puede ignorarlo de manera segura.

    Al igual que en C, los operadores bitwise son :

    • & (bitwise “and”),
    • (bitwise “or”),
    • ^ (bitwise “exclusive or”),
    • ~ (bitwise “not”),
    •  << (desplazamiento a la izquierda en modo bit), y
    • >> (desplazamiento a la derecha en modo bit), así como
    •  & =
    •  | =
    • ^ = (que incluyen la asignación, al igual que + = ).

    Literales enteros 

    Una constante entera se expresa como un entero literal . Ya hemos visto muchos de estos; 34 , por ejemplo, es un literal entero que denota el número 34.

    Todos los ejemplos anteriores  han sido decimales (base diez) literales enteros, que es el valor predeterminado; pero, de hecho, los literales pueden expresarse en cualquier base en el rango 2–64, utilizando el valor de base de notación # (la propia base se expresa en base diez).

    Por ejemplo, esto:

     echo $ (( 12 )) # usa el valor predeterminado de base diez (decimal)
     echo $ (( 10 # 12 )) # especifica explícitamente base diez (decimal)
     echo $ (( 2 # 1100 )) # base dos (binario)
     echo $ (( 8 # 14 )) # base ocho (octal)
     echo $ (( 16 # C )) # base dieciseis (hexadecimal)
     eco $ (( 8 + 2 # 100 )) # ocho en base diez (decimal), más cuatro en base dos (binario)
    

    Imprimirá 12 seis veces. (Tenga en cuenta que esta notación solo afecta a cómo se interpreta un literal entero. El resultado de la expansión aritmética todavía se expresa en base diez, independientemente).

    Para las bases 11 a 36, ​​las letras inglesas A a Z se usan para los valores de dígitos 10 a 35. Esto no distingue entre mayúsculas y minúsculas. Sin embargo, para las bases 37 a 64, son las letras inglesas en minúsculas las que se usan para los valores de dígitos 10 a 35, mientras que las letras mayúsculas se usan para los valores de dígitos 36 a 61, el signo at @ se usa para las cifras el valor 62, y el subrayado _ se usa para el valor de dígitos 63. Por ejemplo, 64 # @ A3 indica 256259 ( 62 × 64 2 + 36 × 64 + 3 ).

    También hay dos notaciones especiales: el prefijo de un literal con 0 indica la base ocho (octal), y el prefijo de 0x o 0X indica la base dieciséis (hexadecimal). Por ejemplo, 030 es equivalente a 8 # 30 , y 0x6F es equivalente a 16 # 6F .

    Variables enteras 

    Una variable se puede declarar como una variable entera, es decir, su “atributo entero” se puede “establecer”, usando esta sintaxis:

    declare -i n
    Después de ejecutar el comando anterior, cualquier asignación subsiguiente a n hará que el lado derecho se interprete automáticamente como una expresión aritmética. Por ejemplo, esto:
    declare -i n
    n='2 + 3 > 4'
     Es más o menos equivalente a esto:
     n  =  $ ((  2  +  3 > 4  ))
    

    excepto que la primera versión declare -incontinuará afectando las tareas posteriores también.

    En la primera versión, note el uso de comillas en el lado derecho de la tarea. Si hubiéramos escrito n = 2 + 3> 4 , habría significado “ejecutar el comando + con el argumento 3 , pasando la variable de entorno n configurada a 2 y redirigiendo la salida estándar al archivo 4 “; es decir, establecer el atributo entero de una variable no afecta el análisis global de las declaraciones de asignación, sino que simplemente controla la interpretación del valor que finalmente se asigna a la variable.

    Podemos “anular” el atributo entero de una variable, desactivando este comportamiento, usando el comando opuesto:

    
    
    declare +i n

    El comando declare incorporado también tiene otros usos: hay algunos otros atributos que una variable puede tener, y declare tiene algunas otras características además de activar y desactivar los atributos. Además, algunas de sus propiedades destacan:

    • Al igual que con local y export , el argumento puede ser una asignación de variable; por ejemplo, establece el atributo entero de $ n y lo establece en 5 .declare -i n = 2 +3
    • Al igual que con local y export , se pueden especificar múltiples variables (y / o asignaciones) a la vez; por ejemplo, declare -i n=2+3 establece tanto el atributo entero de $ m como el de $ n .
    • Cuando se usa dentro de una función, declare implícitamente localiza la variable (a menos que la variable ya sea local), lo que también tiene el efecto de desarmarla localmente (a menos que se use la sintaxis de asignación).

    Aritmética no entera 

    Como se mencionó anteriormente, Bash shell arithmetic solo admite aritmética de enteros. Sin embargo, los programas externos a menudo se pueden usar para obtener una funcionalidad similar para valores no enteros.

    En particular, la utilidad de Unix común bc se usa a menudo para esto. El siguiente comando:

     echo  "  $ (  echo  '3.4 + 2.2'  | bc )  "
    

    impresiones 5.6 .

    No hace falta decir que, dado que bc no está tan estrechamente integrado con Bash como lo es la aritmética de shell, no es tan conveniente; por ejemplo, algo como esto:

    # imprimir las potencias de dos, de 1 a 512: 
    for (( i = 1 ; i < 1000 ; i *= 2 )) ; do
      echo $i
    done

    sería, para soportar no enteros, convertirse en algo como esto:

    # imprimir los poderes de la mitad, de 1 a 1/512: 
    i=1
    while [ $( echo "$i > 0.001" | bc ) = 1 ] ; do
      echo $i
      i=$( echo "scale = scale($i) + 1 ; $i / 2" | bc )
    done

    Parte de esto se debe a que ya no podemos usar un aritmética for-loop; parte de esto se debe a que hacer referencia a las variables y asignarlas a las variables es más complicado ahora (ya que bc no es consciente de las variables de la shell, solo de las suyas, no relacionadas); y parte de ello se debe a que bc se comunica con el shell solo a través de entrada y salida.

    !Y  esto  es todo por hoy!Pero no se preocupe en proximos post trataremos otrso temas como entrada/salida, funcionaes complejas y mucho mas

    Mas informacion en  https://en.wikibooks.org/wiki/Bash_Shell_Scripting

    Editar ficheros con linux

    Emacs proporciona un potente editor para el sistema operativo GNUcomo GNU / Linux , Sin embargo, GNU Emacs incluye soporte para algunos otros sistemas que los voluntarios eligen apoyar.


    Para muchas personas, una de las piezas de software más importantes es un procesador de textos, aunque obviamente si ese equipo es un Linux  para  escribir documentos se usen otros programas como LibreOffice Writer,Open Office ,ete c o incluso servicios en linea como google docs , un editor de texto, sigue siendo hoy en dia  una herramienta indispensable  pera  ver contenido de ficheros ASCIII ( por ejemplo tipo logs, txt ,etc )   y también  para editar o ver  scripts de shell, programas PostScript, páginas web y más.

    Un editor de texto opera en archivos de texto sin formato almacenando solo los caracteres que escribe no agregando ningún código oculto de formateo. Es decir ,si escribimos unos caracteres   y presionamos Enter en un editor de texto y lo guardamos, el archivo contendrá exactamente esos caracteres y una nueva línea. Sin embargo si usamos  un  procesador de textos, dicho fichero  que contenga el mismo texto sería miles de veces más grande (con abiword por ejemplo un archivo de unos pocos caracteres  podiria ocupar 2.526 bytes, el archivo LibreOffice.org contendria sobre 7.579 bytes).

    Puede escribir scripts en cualquier editor de texto, desde el e3 básico o nano hasta el emacs o nedit completos.

    Los mejores editores de texto le permiten tener más de un archivo abierto a la vez. Hacen que el código de edición sea más fácil con, por ejemplo,con  resaltado de sintaxis, sangría automática, autocompletado, revisión ortográfica, macros, búsqueda y reemplazo, y la importante funcion de deshacer.

    En última instancia, qué editor se  elige es una cuestión de preferencia personal pero en  GNU  uno muy bueno  es  emacs

    emacs1.PNG

    Emacs viene autodocumentado de serie con un manual al que puede acceder usando el comando info. Ya sea desde una terminal de los sistemas operativos GNU y Unix, o desde el propio Emacs, escribiendo M-x info RET (esto quiere decir Meta- x o ESC x, la palabra “info”, seguido de la tecla return), o escribiendo C-h i (eso es Control-h seguido de la i). Ademá Emacs trae consigo un tutorial interactivo que le guiará paso a paso a través de una sesión de edición en la cual aprenderá los elementos básicos del uso de Emacs como editor de texto.

    Para realizarlo, proceda de la siguiente manera:

    • Utilice C-h t (presione Control y h, suelte ambas teclas, y luego pulse t).
    • Si eso no resulta, intente mediante F1 t.
    • Si eso no resulta tampoco, intente M-x help-with-tutorial (Pulse Esc, suéltela, pulse x, suéltela, escriba help-with-tutorial, pulse Enter).

    Si desea leer el tutorial en un idioma distinto al Inglés, use el comando M-x help-with-tutorial-spec-language. (en el momento se encuentran disponibles: bg, cn, cs, de, es, fr, it, ja, ko, nl, pl, ro, ru, sk, sl, sv, th, zh  , es decir también esta en español)

    Las opciones más habituales:

    • Obtener ayuda C-h (Mantenga presionada la tecla CTRL y presione h)
    • Deshacer cambios C-x u Salir Emacs C-x C-c
    • Obtener un tutorial C-h t Usar información para leer documentos C-h i
    • Manuales de pedido C-h RET
    • Activar la barra de menú F10 o ESC `o M-`
    • `C- ‘significa usar la tecla CTRL.
    • ` M-‘ significa usar la tecla Meta (o Alt).Si no tiene una clave Meta, en su lugar puede escribir ESC seguido del carácter).

    El entorno puede modificar el modo en que secuencias como C-h o F1 son interpretadas.

     

    Cuadro de Referencia Resumido

    Apertura de archivos: C-x C-f – luego escriba el nombre del archivo, puede usar la tecla TAB para  autocomplementar de modo automático.

    Creación de nuevos documentos: C-x C-f – luego escriba el nombre de un archivo que no exista aun; use TAB para  autocomplementar de modo automático.

    Guardar archivo: C-x C-s

    Destruir búfer (cerrar archivo): C-x k

    Separar ventanas (para ver dos archivos al mismo tiempo):

    • Una sobre la otra: C-x 2
    • Una al lado de la otra: C-x 3

    Unificar ventanas (maximizar una ventana)C-x 1

    Cambiar de ventana (luego de haber hecho una separación): C-x o

    Cambiar de búfer (si está editando múltiples archivos): C-x b

    Menú de búferes (listado de búferes): C-x C-b

    Ejecutar comandos de cuyo atajo por teclado se ha olvidado: M-x – luego escriba el nombre del comando, TAB puede ser usado para autocomplementar.

    Obtener ayuda: C-h, luego cualquiera de las siguientes teclas:

    • k – ¿qué hace cierta secuencia de teclado?
    • f – ¿qué hace cierta función?
    • m – ¿qué secuencias de teclado están definidas en este modo?
    • w – ¿a qué teclas está asociada una función?
    • a – ¿qué nombres de comandos coinciden con cierta cadena?

     

     

    Como ve, emacs  es un editor  ASCII  muy diferente a los editores basados en sistemas windows , pero como se ve tambien puede ser muy potente para trabajar desde una consola depurando o inlcuso escribiendo nuestros propios scripts en c-shell

    Sistema de reconocimiento de colores para personas con discapacidades visuales

    En este   post veremos un proyecto del concurso RetoTech que organiza ENDESA, cuya idea es que las personas con problemas de visión, puedan acercar el dispositivo a un objeto o prenda, y escuchen en su móvil el color de la misma.


    ColorDec  es un interesantismo  proyecto  que representará  al colegio Lope de Vega de 3ª de el ESO  para el concurso RetoTech que organiza ENDESA    creado por   Esther Scott, Irene Yebra, Irene Jimenez,Lucia Gomez y Paula  Vidal  ,  con el propósito de   ayudar  a  personas con discapacidad  visual para  mejorar su percepción de los colores,  gracias  a un hardware de bajo coste basado en Arduino   y una aplicación móvil  que ellas mismas han escrito usando el Mit App Inventor, una herramienta de la que por cierto hemos hablado en numerosas ocasiones en este blog .

    El proyecto  tiene  pues su base  en un Arduino Nano, al que le han acoplado  un modulo bluetooth  para el envío de datos a  un smartphone  mediante los pines 9 (Rxd)  , 8(Txd)  para los datos  vía serie,   así como  VCC y gnd para la alimentación desde Arduino al  propio modulo  Bluetooth.

    Para el reconocimiento de colores cuenta con un sensor especializado como es  el GY33 ( unos 15€ en Amazon)  el cual conectan al propio Arduino via I2C  por los pines A4,A5  alimentándose desde el propio Arduino  desde los pines  5v y GND.

    El  GY-33 es un modulo  de reconocimiento de color de bajo costo que puede alimentarse  entre  3-5 V, con bajo consumo de energía, de  tamaño pequeño y facilidad de instalación.
    Su principio de funcionamiento radica en que la iluminación de la irradiación de luz LED debe medirse  hacia el objeto de modo que la  luz de retorno es  detectada por los filtros de valores RGB y el propio modulo identifica los colores según los valores RGB.
    Este módulo, soporta dos maneras de envió de  datos:

    • Via serie,  es decir mediante UART en serie (nivel TTL) configurando la conexión a 9600bps y 115200bps  siendo la velocidad en baudios del puerto en serie  configurable.
    • I2C (mediante 2 líneas) que es el que han empleado en este circuito mediante  lso pnes A4 y A5 .

    El modulo puede hacer  un reconocimiento simple de 7 colores y no es necesario calcular el valor RGB o se puede gestionar  el dato de una manera compleja como vamos a ver.

    Se complementa  el circuito   final con un pulsador(pin2)  con su respectiva resistencia para evitar rebotes    y la alimentación de  todo el conjunto  por un pila de 9v desde los pines VIN y GND de Arduino.

    El diagrama   final  lo  podemos ver en  la imagen de mas abajo:

     

    esquema

     

    El dispositivo esta pensado para ser portátil de modo que sujetándolo con una mano se apoya en el objeto del que se  desea conocer el color , se pulsa el botón para que este lo transmita (tras convertirlo de RBG a HSV) por bluetooth al teléfono móvil del usuario, desde donde una APP   lo  reproduce hablando en inglés o castellano.

    En cuanto al software para este  proyecto ha sido realizado utilizando el IDE de Arduino para programar un Arduino Nano, al que se le ha conectado un módulo Bluetooth, un Pulsador y un módulo GY-33 para el reconocimiento de color  lo cual es tarea del firmware de Arduino gestionarlo

    El programa del Arduino, en su inicialización realiza un balance de blanco, y después espera a que se pulse el pulsador para leer el color, convertirlo a HSV y enviarlo por Bluetooth al móvil.

    El código provisional para el firmware de Arduino que aun esta es proceso de mejora  nos lo comparten en estas lineas:

     

    Colorview4-ino_1.png

    Colorview4-ino_2.png

    Colorview4-ino_3

    Ya desde el teléfono, se conecta al Arduino por Bluetooth, se cargan dos arrays con los datos de dos ficheros CSV, uno con los códigos RGB de los colores y otro con los nombre de esos colores .

    Se busca el color en el array y si se encuentra ese será el que el teléfono lea en voz alta.

    Sino se encuentra entre los más de 600 códigos RGB, se usa el código en HVS para construir una frase que describe como es el color y se envía al sistema de síntesis de voz del teléfono.

    La conversión a HVS han tenido que hacerla al no poder ordenar los códigos RGB para poder situarse sobre el color más cercano al leído.

    Amablemente nos han compartido sin código escrito con el MIt App Inventor  para desplegarlo en un terminal Android

     

    App-Inventor-Blocks 2-page.png

     

    Es sin duda  un sistema  de mínimo coste  que puede ser de muchísima ayuda para  identificar  los colores para personas con deficiencias visuales,  así que le deseamos desde este blog  toda la suerte posible . El premio es una plaza para cada una de las cinco en un campamento de verano donde seguirán aprendiendo robótica y programación , así que queridos lectores porfavor  si os parece interesante  todo el esfuerzo de esta   chicas y  merece vuestra confianza, esta es la dirección para  votar   su proyecto:

    https://pr.easypromosapp.com/voteme/826101/630232517

    Personalmente  ya he votado porque me ha parecido impresionante el trabajo realizado , así que desde esta lineas  les deseamos toda la suerte en este concurso  y ojala puedan seguir aprendiendo  y perfeccionando sus conocimientos  tecnicos de modo que puedan seguir ayudando a construir un mundo mucho mejor gracias al uso de la tecnología y su ingenio