Geo Event Finder: Find musical events near you!

February 22, 2010 – 3:30 pm
Tags: , , ,

geoEventFinder_01_b

Online Link: http://geoevents.gkudos.com/

Geo Event Finder, http://geoevents.gkudos.com/ , is a Mashup (A Mashup is a web page or application that combines data or functionality from two or more external sources to create a new service)  that allows to locate musical events around the world using interactive tools on the screen as searching by artist name, city name or selecting an area over the map.

The user interface also allows to get detailed information of event location, artist biography, musical genres,  images, videos (using youtube)  and online links to different resources as ticket selling sites.   In addition, a user can interact with the application using map tools as zoom, re-center, a reference map and satellite and street basemaps.

geoEventFinder_03_b

This application uses different data sources and API’s such as :

geoEventFinder_02_b

Online Link: http://geoevents.gkudos.com/

  • Share/Bookmark

XVIII Festival GNU/Linux en la Universidad Nacional de Colombia

November 26, 2009 – 11:52 pm
Tags:

El proximo Jueves 3 de Diciembre de 2009 se llevará a cabo el decimo-octavo Festival GNU/Linux, en el auditorio del edificio de Ciencia y Tecnología en la Ciudad Universitaria de Bogotá.

Este evento desea fomentar el desarrollo académico y cultural de los estudiantes de la Universidad Nacional y del público en general, de igual forma se promoverá el desarrollo y la utilización del sofware libre.

Kudos Ltda. estará presente en el evento con la presentación “Sistemas de Información Geográfica con Software Libre” (Próximamente más detalles)

Más información en https://lsl.unal.edu.co/fl18/

  • Share/Bookmark

Modelamiento en Web de Geoinformación de la Amazonía Colombiana con el uso de Software Libre

November 6, 2009 – 8:22 pm
Tags: , , , ,

En el marco de la Semana de Geomática del IGAC (2009) se presentó el proyecto SIAT-AC (Sistema de Información Ambiental Territorial de la Amazonía Colombiana) desarrollado durante el presente año por Kudos Ltda para el SINCHI.

El SIAT-AC ss un proceso interinstitucional organizado como red de personas y entidades, basado en acuerdos y objetivos comunes para gestionar información ambiental de la Amazonía Colombiana, para apoyar con los datos y productos de información a los tomadores de decisiones en los procesos regionales para alcanzar el desarrollo sostenible.

El sistema fué desarrollado con herramientas de software libre tales como Mapserver, Postgresql, Postgis, PHP y Adobe Flex 3 SDK.

A continuación los Slides presentados durante la conferencia:

En las siguientes imágenes se pueden apreciar algunas de las características del sistema:

- Adición dinámica de Capas de Información Geográfica al visor espacial:

Adición de Capas

- Clasificación Temática Dinámica De Indicadores

SinchiClasificacion

- Exportación de Datos a Google Earth:
SinchiGoogleEarth

- Ejecución Interactiva de Modelos de Análisis Geoespacial:

SinchiPasosModelo

  • Share/Bookmark

Kudos Ltda. en la Semana de Geomática IGAC 2009

October 26, 2009 – 5:49 pm
Tags: , , ,

Durante la presente semana (26 al 30 de Octubre del 2009) el IGAC (Instituto Geográfico Agustn Codazzi) está organizando la Semana de Geomática del 2009 con el título de “Acceso al Conocimiento Geoespacial”.

La semana de Geomática tiene como objetivo dar a conocer los avances nacionales e internacionales  más recientes en campos tales como los Sistemas de Información Geográfica, la percepción remota, los sistemas de posicionamiento satelital y las infraestructuras de datos espaciales.

En el marco de dichas conferencias Kudos Ltda. estará presente con dos proyectos desarrollados durante los últimos meses:

  • “Modelamiento en web de geoinformación de la Amazonía Colombiana utilizando Software Libre” a cargo del Agrólogo Uriel Gonzalo Murcia García (Instituto Amaznico de Investigaciones Cientficas SINCHI – Colombia) y los Ingenieros  Carlos Gustavo Infante Sepúlveda  y Hellmuth Vargas (Kudos Ltda. – Colombia)   (  Fecha de la Presentación: Jueves 29 de Octubre a las 8:45 am en el auditorio de Ciencia y Tecnología del IGAC. )
  • “SIGISOT, Sistemas de Información Geográfica en la Gestión municipal” a cargo de la agróloga Doris Serrano Universidad de Córdoba – Colombia.   (Fecha de la Presentación: Viernes 30 de Octubre 2:45 pm en el Auditorio de Suelos del IGAC)
  • Share/Bookmark

Se publica QGIS 1.3.0 ‘Mimas’

September 26, 2009 – 12:06 pm
Tags:

Poco tiempo despueś de la publicación de la publicación de QGIS 1.2.0 aparece  ‘Mimas’ (QGIS 1.3.0).

Entre otros cambios se incluye lo siguiente:

  • Nuevas funcionalidades y mejoras al plugin de open street map.
  • Incorporación de librería de análisis
  • Nuevas herramientas para análisis raster
  • Nuevas herramientas tales como “identify a través de múltiples capas”.

Más información en el siguiente enlace: Announcing the release of QGIS 1.3.0 ‘Mimas’

  • Share/Bookmark

Publicada la versión 1.2.0 de Quantum GIS

September 7, 2009 – 11:07 am
Tags: ,

La organización OSGEO anunció la semana pasada la disponibilidad de la versión 1.2.0 del software para Sistemas de Información Geográfica Quantum GIS (QGIS) . Esta nueva versión incluye las siguientes mejoras notables

  • Mejoras notables en las herramientas de edición de elementos multipartes, huecos, nodos. Se agregó la opción deshacer/rehacer en la edición de capas vectoriales.
  • Nuevo plugin de OpenStreetMap para editar contenidos y contribuir datos al proyecto directamente desde QGIS
  • Nueva extensión FTools con herramientas de geoprocesamiento mejoradas
  • Mejoras al plugin de interpolación
  • El shell GRASS ha sido remplazado por uno mejorado con muchas correcciones y actualizaciones
  • Nueva opción de búsqueda en las tablas de atributos y asignación de alias de campos
  • Las conexiones PostgreSQL ahora pueden encriptarse con SSL
  • Mejoras al soporte de simbología raster y de fuentes

También se anunció la disponibilidad del Manual de Usuario actualizado para esta versión, en un esfuerzo colaborativo de un equipo de desarrolladores, documentadores y patrocinadores voluntarios.

QGIS 1.2.0 para Windows

  • Share/Bookmark

Creando un lector de GeoRSS con Adobe Flex 3

September 6, 2009 – 1:21 pm
Tags: , , ,

Uno de los ejemplos tradicionales que se desarrollan durante el aprendizaje de Flex 3 y Actionscript 3 es el de la creación de un lector de RSS. En el presente artículo se presenta una extensión de dicho ejemplo adicionando la capacidad de interpretar infomación publicada en el formato GeoRSS.

  • Qué es un RSS?

RSS es una familia de formatos de fuentes web codificados en XML. Se utiliza para suministrar a suscriptores de información actualizada frecuentemente. El formato permite distribuir contenido sin necesidad de un navegador, utilizando un software diseñado para leer estos contenidos RSS (agregador).

  • Qué es un GeoRSS?

GeoRSS es un conjunto de estándares para representar información geográfica mediante el uso de capas y está construido dentro de la familia de estándares RSS.

  • Cómo convertir un RSS en GeoRSS?

Si usted no dispone de una aplicación para convertir sus RSS en GeoRSS puede utilizar Geonames para realizar dicha traducción de formato.
El “RSS to GeoRSS Converter” de Geonames busca posibles ubicaciones (sitios geogràficos) en el texto del  rss.  Si alguna ubicación geográfica relevante es encontrada, adiciona la latitud y longitud al RSS durante la codificación a GeoRSS.

  • Que requiero para implementar el lector de GeoRSS utilizando Adobe Flex 3?

- Flex SDK

- Google Maps Flash API

  • Donde puedo descargar el código fuente del ejemplo?

Puede descargar el código fuente desde esta ubicación.

  • Que ejemplos de programación flex / actionscript  puedo encontrar en el código?

- Carga de datos en XML utilizando el objeto HTTPService

- Despliegue de datos utilizando componentes ComboBox, Datagrid e Image

- Formatear etiquetas de un ComboBox utilizando labelFunction.

- Despliegue de información HTML en el tooltip de la aplicación.

- Ejemplo básico de carga de Markers en Google Maps para Adobe Flex.

- Procesamiento de datos publicados en formatos XML, RSS y GeoRSS.

- Utilizar el servicio “Rss to GeoRSS” de Geonames con Flex y Actionscript.

  • Puedo ver en línea el código fuente del ejemplo y la aplicación resultante?

A continuación puede ver tanto la aplicación como el código fuente relacionado.






Código fuente del archivo Rss.mxml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" 
	layout="vertical"
	applicationComplete="onComplete();" 
	creationComplete="loadSourcesService.send();">
<mx:Style>
	Application{
		background-color:#ffffff;
		paddingBottom:5; 
		paddingLeft:5;
		paddingRight:5; 
		paddingTop:5;
	}
</mx:Style>	
<mx:Script>
	<![CDATA[
		import com.google.maps.controls.ZoomControlOptions;
		import mx.collections.ArrayCollection;
		import com.google.maps.overlays.MarkerOptions;
		import com.google.maps.overlays.Marker;
		import ejemplo.HTMLToolTip;
		import mx.managers.ToolTipManager;
		import flash.net.navigateToURL;
		import mx.controls.List;
		import mx.controls.Alert;
		import mx.events.ListEvent;
		import mx.rpc.events.FaultEvent;
		import mx.rpc.events.ResultEvent;
		import com.google.maps.MapType;
		import com.google.maps.LatLng;
		import com.google.maps.controls.PositionControl;
		import com.google.maps.controls.MapTypeControl;
		import com.google.maps.controls.ZoomControl;
		import com.google.maps.Map;
		import com.google.maps.MapEvent;
 
		public var map:Map;
 
	    //se invoca en el evento 'creationComplete' 
		private function onComplete() :void{
			//configuración del tooltip para despliegue de HTML
			ToolTipManager.toolTipClass = HTMLToolTip; 
		}
 
		//Manejo de la respuesta del HTTPService loadSourcesService
		private function loadSourcesService_result(evt:ResultEvent):void {
		    var resultObj:Object = evt.result;
		    sourcesCb.dataProvider = resultObj.xml.lista.item;
		}
 
		//Iniciar el Mapa
		private function startMap(event:Event):void {
			map = new Map();
			//Key de google Maps: http://code.google.com/intl/es-ES/apis/maps/documentation/flash/
			map.key = map.key = "ABQIAAAAzP_X84EVzii7yEPHkonPNRRMdub8RYo7ePgaMtJOPXtU0LG1eBQz8J6xJi_XxLQ80ti-WlGkph7kVw";
			map.addEventListener(MapEvent.MAP_READY, onMapReady);
 
			var zoomopts:ZoomControlOptions = new ZoomControlOptions();
			zoomopts.hasScrollTrack = false;
			var zoomCtrl:ZoomControl = new ZoomControl(zoomopts);
			map.addControl(zoomCtrl);
 
			// add MapType Controller
			var mapTypeCtrl:MapTypeControl = new MapTypeControl();
			map.addControl(mapTypeCtrl);
 
			// add Position Controller
			var posCtrl:PositionControl = new PositionControl();
			map.addControl(posCtrl);
			mapContainer.addChild(map);
		}
 
		private function resizeMap(event:Event):void {
			map.setSize(new Point(mapContainer.width, mapContainer.height));
		}
 
		private function onMapReady(event:MapEvent):void {
			//setCenter:  Parámetros: Coordenada Punto Central, Nivel de Zoom, Tipo de Mapa
			map.setCenter(new LatLng(4,-73),3, MapType.NORMAL_MAP_TYPE);
			//Habilita el Zoom Continuo
			map.enableContinuousZoom();
			//Habilita el Scroll del mapa utilizando el Mouse 
			map.enableScrollWheelZoom();
		}
 
		// Se invoca cuando el usuario cambia de opcion en el combo box
		// se obtiene el rss y se pasa al HTTPService 'loadRssService'
		private function getFuenteNombre ( event: ListEvent) : void{					
			if(sourcesCb.selectedItem){
				//configura la llamada al servicio geonames que recibe como parámetro
				//la url del rss que se va a georreferenciar
				//http://www.geonames.org/rss-to-georss-converter.html
				loadRssService.url= "http://ws.geonames.org/rssToGeoRSS?feedUrl="+sourcesCb.selectedItem.url;
				loadRssService.send();
				//elimina todos los markers del mapa
				map.clearOverlays();
				rssList.dataProvider = new ArrayCollection();
			}
		}
 
		//Esta funcion se llama cuando cambia el DataGrid, tiene como objetivo
		//establecer el contenido a desplegar en la descripcion, tomandolo del xml.
		private function getPage(event: ListEvent) : void{
			var selectedEq:Object = rssList.selectedItem;
			titulo.text = rssList.selectedItem.title;
			contenido.htmlText=rssList.selectedItem.description;
			//Alert.show(rssList.selectedItem["encoded"])
			mas.visible=true;
			var latlng:LatLng = new LatLng(Number(rssList.selectedItem.lat),Number(rssList.selectedItem.long));
			//lo hace solo cuando geonames devuelva la latitud y la longitud
			if(rssList.selectedItem.lat!=undefined||rssList.selectedItem.long!=undefined){
				var marker:Marker = generateMarker(selectedEq); 
				map.setCenter(latlng , 3);	
				map.addOverlay(marker);
			}
		}
 
		private function generateMarker(item:Object ):Marker{
			//crea un objeto de tipo LatLng
				var latlng:LatLng = new LatLng(Number(item.lat),Number(item.long));				
				//tooltip del Marker  
				var markerOptions : MarkerOptions= new MarkerOptions();
			    markerOptions.tooltip = item.title;
			    var marker : Marker = new Marker( latlng, markerOptions );
				return marker;
		}
 
		//Esta funcion se llama cuando se hace click en el enlace 
		//que me envia a la pagina de la fuente, coge el campo link del xml.
		private function getUrl() : void{
			//configura el request del LinkButton con el objeto link del xml 
			var u:URLRequest = new URLRequest(rssList.selectedItem.link);
        	navigateToURL(u,"_blank");
		}
 
		//Se llama cuando hay un resultado en HTTPService loadRssService
		protected function onServiceResult(event:ResultEvent):void {
			rssList.dataProvider = event.result.rss.channel.item;
			//configura la ubicacion de la imagen con el campo image.url
			imagen.source=event.result.rss.channel.image.url;
			titulo.text = "";
			contenido.htmlText='Seleccione una Noticia';
			mas.visible=false;
		}
 
 
 
		//Se llama cuando hay un fault HTTPService loadEQService y en HTTPService loadRssService
		private function load_fault(evt:FaultEvent):void {
			Alert.show('Ocurrió un Error en el Servidor', evt.fault.faultString);
		}
 
		private function  sourcesCbLabelFunction(item:Object):String{
			return item.nombre + " ("+item.pais+")";
		}
 
	]]>
</mx:Script>
	<mx:HTTPService id="loadSourcesService"
	            url="sources.xml"
	            resultFormat="object"
	            result="{loadSourcesService_result(event);}"
	            fault="load_fault(event);"
	            showBusyCursor="true" />
 
	<mx:HTTPService id="loadRssService"
	            resultFormat="object"
	            result="onServiceResult(event);"
	            fault="load_fault(event);"
	            showBusyCursor="true" />
 
	<mx:HDividedBox width="100%" height="100%">
		<mx:Panel id="panel1" width="50%" height="100%" title="Lector de GeoRSS">
			<mx:VBox id="box"  height="100%" width="100%">
				<mx:HBox width="100%">			
					<mx:ComboBox id="sourcesCb"  textAlign="left" width="100%"  
						labelFunction="sourcesCbLabelFunction"
						change="getFuenteNombre(event)" rowCount="10"
						prompt="Seleccione una opción..." />
				</mx:HBox>
				<mx:DataGrid id="rssList" width="100%" height="100%"  change="getPage(event)">
					<mx:columns>
						<mx:DataGridColumn dataField="title" headerText="Titular" 
							dataTipField="description" showDataTips="true" />
					</mx:columns>		
				</mx:DataGrid>
			</mx:VBox>
		</mx:Panel>
		<mx:Panel  width="50%" height="100%" title="Detalle de la Noticia">
			<mx:VDividedBox width="100%" height="100%">
				<mx:VBox width="100%" height="30%">
					<mx:HBox width="100%" >
						<mx:Image id="imagen" />
						<mx:LinkButton id="mas" visible="false" label="Ver mas..." click="{getUrl()}"/>	
					</mx:HBox>
					<mx:Text id="titulo" width="100%" fontWeight="bold"/>
					<mx:Text id="contenido" width="100%"/>
				</mx:VBox>
				<mx:VBox width="100%" height="70%">
					<mx:UIComponent id="mapContainer" 
			        initialize="startMap(event);" 
			        resize="resizeMap(event)" 
			        width="100%" height="100%"/>
				</mx:VBox>
			</mx:VDividedBox>	
		</mx:Panel>
	</mx:HDividedBox>
</mx:Application>

Código fuente del archivo ejemplo/HTMLToolTip.as:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package ejemplo
{
//Esta es la clase que maneja el tooltip para que muestre el contenido
//que esta en html y no como un string.
     import mx.containers.*;  
     import mx.controls.Text;  
     import mx.controls.ToolTip;  
     import mx.core.*;  
 
     public class HTMLToolTip extends ToolTip  
     {  
         public function HTMLToolTip()  
         {    super(); }  
 
         override protected function commitProperties():void{  
             super.commitProperties();  
             textField.htmlText = text;  
         }  
     } 
}

Archivo sources.xml:

<xml>
	<lista>
		<item>
			<nombre>El Tiempo - Mundo</nombre>
			<url>http://www.eltiempo.com/mundo/rss.xml</url>
			<pais>Colombia</pais>
		</item>
		<item>
			<nombre>El Tiempo - Colombia</nombre>
			<url>http://www.eltiempo.com/colombia/rss.xml</url>
			<pais>Colombia</pais>
		</item>
		<item>
			<nombre>El Espectador</nombre>
			<url>http://www.elespectador.com/rss.xml </url>
			<pais>Colombia</pais>
		</item>
		<item>
			<nombre>El Pais - America Latina</nombre>
			<url>http://www.elpais.com/rss/feed.html?feedId=17041</url>
			<pais>España</pais>
		</item>
		<item>
			<nombre>ABC - Portada</nombre>
			<url>http://www.abc.es/rss/feeds/abcPortada.xml</url>
			<pais>España</pais>
		</item>
		<item>
			<nombre>BBC Mundo</nombre>
			<url>http://www.bbc.co.uk/mundo/index.xml</url>
			<pais>Inglaterra</pais>
		</item>
		<item>
			<nombre>CNN - World</nombre>
			<url>http://rss.cnn.com/rss/edition_world.rss</url>
			<pais>Estados Unidos</pais>
		</item>
		<item>
			<nombre>Reuters - World News</nombre>
			<url>http://feeds.reuters.com/reuters/worldNews</url>
			<pais>Estados Unidos</pais>
		</item>
		<item>
			<nombre>BusinessWeek.com</nombre>
			<url>http://rss.businessweek.com/bw_rss/bwdaily</url>
			<pais>Estados Unidos</pais>
		</item>
		<item>
			<nombre>Google News</nombre>
			<url>http://news.google.com/news?output=rss</url>
			<pais>Alemania</pais>
		</item>
</lista>
</xml>
  • Share/Bookmark

Balsamiq Mockups, una herramienta efectiva para la creación de prototipos (mockups) de Componentes de Software

September 1, 2009 – 2:04 am
Tags: , , ,

Uno de los grandes problemas que tradicionalmente se presentan durante el desarrollo de software a la medida, es el de ofrecer a los usuarios finales un mecanismo que les permita comprender y evaluar de forma temprana las diferentes funcionalidades que el sistema de software les puede ofrecer.

Entre muchas propuestas, el Diseño Centrado en el Usuario (User-Centered Design) constituye una aproximación al diseño fundamentada en tratar de comprender de forma eficiente la forma en que la información es procesada por los usuarios finales que utilizarán el producto.
En ese sentido tal vez una de las herramientas más simples (y efectivas) de diseño centrado en el usuario es el de la utilización de bocetos gráficos o prototipos de interfaz de usuario (mockups) que visualmente permitan dar una idea de la forma en que lucirá el sistema, así como también de evidenciar las diferentes formas en que el usuario podrá interactuar con la aplicación.

No siempre las herramientas CASE (Computer Aided Software Engineering) tradicionales proveen mecanismos que de forma rápida y eficiente faciliten la creación de dichos mockups. Es en este punto donde Balsamiq Mockups se convierte en un programa que de forma increíblemente rápida y eficiente
permite la especificación de interfaces gráficas de usuario.

Una de las grandes fortalezas de la herramienta es su usabilidad, de tal forma que gracias a su entorno amigable tanto usuarios de software principiantes como avanzados pueden lograr resultados rápidos sin recurrir a la consulta adicional de manuales de usuario o tutoriales externos.

Gracias a su facilidad de uso, Balsamiq Mockups permite el diseño eficiente de interfaces gráficas de usuario de tal forma que los usuarios finales pueden ofrecer una rápida retroalimentación al diseño del software mucho tiempo antes de las primeras etapas de construcción y codificación de los prototipos ejecutables del mismo.

Los usuarios finales pueden interpretar visualmente las funcionalidades que potencialmente les ofrecerá el sistema, ofreciendo así la posibilidad de realizar de forma temprana los ajustes y correcciones necesarios que permitan implementar los requerimientos expresados por el cliente.

Balsamiq Mockups tiene varias versiones: Demo WebDesktop y Plugin (integrable con herramientas tales como Jira , XWiki, Confluence o FogBugz.

Técnicamente hablando, Balsamiq Mockups es una herramienta que se creó utilizando Adobe Flex ,
y que para su versión Desktop utiliza la plataforma de Adobe Air.


Intro to Balsamiq Mockups

Balsamiq Mockups provee una librería inicial de 75 componentes que pueden ser extendidos a través de la comunidad de Mockups To Go.

Otro hecho de bastante importancia para resaltar es su precio bastante accesible para cualquier empresa o individuo: $79 dólares (versión desktop)

Referencias:

  • Share/Bookmark

Crear un Lector de Podcasts con Adobe Flex 3

August 29, 2009 – 3:04 pm
Tags: ,

El código fuente publicado en esta entrada muestra una aplicación flex que permite la consulta y descarga de archivos podcast publicados en internet. A continuación una imagen de muestra del aplicativo:


Básicamente el usuario selecciona un canal del ComboBox superior y las entradas de podcast se cargan en la lista que tiene un botón de reproducción y descarga para cada uno de los items.
Cuando el usuario selecciona el botón de reproducción de una de las entradas, el componente de audio carga el mp3 relacionado en el componente del “player” que se encuentra en la parte inferior de la pantalla.

Ver aplicación en Línea (*)

Descargar Código Fuente

Notas (*) :

  • La carga de algunos RSS y el analizador de espectro solo funcionan ejecutando el aplicativo en forma local.
  • La descarga de archivos funciona únicamente si el usuario tiene instalado el  Flash Player versión 10

Código Fuente:

Mp3Player.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" 
	creationComplete="{init();}" width="100%" height="100%"
	xmlns:fx="com.fusiox.ui.*" 
	layout="vertical">
<mx:Script>
	<![CDATA[
		import mx.rpc.events.ResultEvent;
		import mx.collections.ArrayCollection;
		import mx.controls.Alert;
		import mx.utils.ObjectUtil;
        // Play & Pause Icons
		[Embed(source="assets/Pause.png")] 	[Bindable] public var iconPause:Class;
		[Embed(source="assets/Play.png")] 	[Bindable] public var iconPlay:Class;
		[Embed(source="assets/Next.png")] 	[Bindable] public var iconNext:Class;
 
 
		private var sound:Sound;						// Mp3 File 
		private var soundChannel:SoundChannel;			// Reference to playing channel 
		private var pausePosition:Number;				// Current play position (time)
		private var percent:Number;						// Current played percentage
		private var isPlaying:Boolean = false;			// Is the mp3 playing?
		private var isLoaded:Boolean = false;			// Is the mp3 loaded?
		private var updateSeek:Timer = new Timer(500);	// Timer for updating the seek bar
 
		[Bindable]
        public var podcastChannels:ArrayCollection = new ArrayCollection(
            [ {label:"Music - Free Music Everywhere Podcast", data:'http://feeds2.feedburner.com/FreeMusicEverywhere'}, 
              {label:"Music - Last.fm Free Mp3 - Electronic ", data:'http://ws.audioscrobbler.com/2.0/tag/Electronic/podcast.rss'},
              {label:"Music - Last.fm Free Mp3 - Metal ", data:'http://ws.audioscrobbler.com/2.0/tag/Metal/podcast.rss'},
              {label:"Music - Last.fm Free Mp3 - Jazz ", data:'http://ws.audioscrobbler.com/2.0/tag/Jazz/podcast.rss'},
              {label:"Music - Last.fm Free Mp3 - Rock ", data:'http://ws.audioscrobbler.com/2.0/tag/Rock/podcast.rss'},
              {label:"Music - Last.fm Free Mp3 - Classical ", data:'http://ws.audioscrobbler.com/2.0/tag/Classical/podcast.rss'},
              {label:"News - Guardian Daily", data:'http://www.guardian.co.uk/news/series/guardiandaily/podcast.xml'},
              {label:"News - Tech Weekly", data:'http://www.guardian.co.uk/technology/series/techweekly/podcast.xml'},
              {label:"News - Business Weekly", data:'http://downloads.bbc.co.uk/podcasts/worldservice/bizweekly/rss.xml'},
              {label:"News - BBC Global News", data:'http://downloads.bbc.co.uk/podcasts/worldservice/globalnews/rss.xml'},
              {label:"News - La Historia del Mundo con Diana Uribe", data:'http://www.caracol.com.co/feed.aspx?id=PROG_320899'}, 
              {label:"News - Hora de Negocios con Paola Ochoa", data:'http://www.caracol.com.co/feed.aspx?id=PROG_555605'} 
            ]);
 
		private function init():void { 
			// Add event listener for seek bar updater & start timer							
            updateSeek.addEventListener(TimerEvent.TIMER, updatePosition);
            updateSeek.start();
            // Add mouse click listener for the seek bar
            seekAudioBar.addEventListener(MouseEvent.CLICK, seek);
			// Add event listener that blurs the visualization
			viz.addEventListener("beforeVisualization", vizFade);
			selectChannel();
			//Add Events that come from each renderer. 
			rssList.addEventListener('playPodcast', playPodcast);
		}
 
		private function selectChannel():void {
            rssService.url = channelsCb.selectedItem.data;
			rssService.send();
        } 
 
        protected function onServiceResult(event:ResultEvent):void {
			rssList.dataProvider = event.result.rss.channel.item;
			next();
		}
 
		protected function playPodcast(event:Event):void {
			var selection:Object = rssList.selectedItem ; 
			loadSound(selection.enclosure.url);
		}
 
		private function loadSound(mp3Url:String):void{
			// If the song isn't loaded yet, set up a new sound load request
			sound = new Sound();
			sound.load(new URLRequest(mp3Url));
			// Add an event listener to check for song load complete event
			sound.addEventListener(Event.COMPLETE, songLoaded);
			// Show text for loading song and add event listener for updating
			sound.addEventListener(ProgressEvent.PROGRESS, updateStatus);
			sound.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
			loadProgressBar.visible=true;
			loadProgressBar.text = "0 %"
		}
		private function updateStatus(e:ProgressEvent):void {
			var loadPercent:Number = Math.round((e.bytesLoaded / e.bytesTotal) * 100);
			loadProgressBar.text = loadPercent+" %";
		}
		private function onIOError(event:IOErrorEvent):void{
		    Alert.show("The sound could not be loaded: " + event.text, "Error");
		}
 
		// Once the song is loaded...
		private function songLoaded(e:Event):void {
			if(soundChannel){
				soundChannel.stop()
			}
 
			var selection:Object = rssList.selectedItem ; 
			podTitle.text = selection.title;
 
			// Hide status text
			loadProgressBar.visible = false;
			// Remove load event listener
			sound.removeEventListener(Event.COMPLETE, songLoaded);
			// Turn on seek bar
			enableSeek();
			// Play the song
			soundChannel = sound.play(0);
            // Pull the title/artist/album from the ID3 tags and display
            theArtistAlbum.text  = "";
            if(sound.id3.TIT2){
            	theArtistAlbum.text += sound.id3.TIT2;
            }
            if(sound.id3.artist){
            	theArtistAlbum.text += ", "+ sound.id3.artist;
            }
			// Song is loaded
			isLoaded = true;
			seekAudioBar.visible = isLoaded;
			isPlaying = true;
		}
 
		// Play or Pause button has been clicked
		private function playPause(e:Event = null):void  {
			// Song playing?
			if(isPlaying) {
				// Save the current position in the track, stop playback, change button icon
				pausePosition = soundChannel.position;
				soundChannel.stop();
				playPauseBtn.setStyle("icon", iconPlay);
			// Song is not playing?
			} else {
				// The song IS loaded, so play it
				soundChannel = sound.play(pausePosition);
				// Change the button icon to the pause style
				playPauseBtn.setStyle("icon", iconPause);
			}
			// Regardless of playing state, change it now to the opposite
			isPlaying = !isPlaying;
		}
 
		// Enabled the seek (progress) bar
		public function enableSeek():void {
			seekAudioBar.enabled = true;
			seekAudioBar.visible = true;
		}			
 
		// Add a color transform to the visulization to create the fade effect
		private function vizFade(e:Event):void {
			e.target.bitmapData.colorTransform(
				e.target.bitmapData.rect, new ColorTransform(0.75,0.75,0.75,.75));
		}
 
		// Called when the seek (progress) bar needs updating
		private function updatePosition(e:Event):void {
 			// Is a song playing?
 			if(isPlaying && soundChannel) { 
 				// If the position is beyond the song start, calculate & set the percentage
 				percent = soundChannel.position > 0 ? (soundChannel.position/sound.length)*100 : 0;
				seekAudioBar.setProgress(percent,100);
	   			// Tell the seekbar to redraw itself
	   			seekAudioBar.validateNow();
	   		}
		}
 
 
 
 
 
		// Mouse click event on the seekbar calls this function
		private function seek(e:MouseEvent):void {
			// Is the song playing AND is the seekbar enabled and visible?
			if(isPlaying && seekAudioBar.enabled) { 
				// Stop playing at current position, change to new location, continue playing
				soundChannel.stop();
				pausePosition = (seekAudioBar.contentMouseX/seekAudioBar.width)*sound.length;
				soundChannel = sound.play(pausePosition);
				setVolume(this.volumeControl.value)
			}
		}
 
		private function setVolume(volume:Number):void {
            if(soundChannel){
	            var transform:SoundTransform = soundChannel.soundTransform;
	            transform.volume = volume;
            	soundChannel.soundTransform = transform;
            }
        }
 
        private function next():void{
        	var selectedIdx:int = rssList.selectedIndex;
        	if(selectedIdx < rssList.dataProvider.length){
        		rssList.selectedIndex = ++selectedIdx;
        		playPodcast(null);
        	}
        }
 
	]]>
</mx:Script>
	<mx:Style source="style.css" />
	<mx:HTTPService id="rssService" result="{onServiceResult(event)}" resultFormat="object" />
	<mx:Fade id="FadeIn" duration="3000" alphaFrom="0.0" alphaTo="1.0"/>	
	<mx:Fade id="FadeOut" duration="3000" alphaFrom="1.0" alphaTo="0.0"/>
 
	<mx:VDividedBox width="100%" height="100%">
		<mx:VBox width="100%" height="50%"  >
			<mx:Label text="My Flex Based Podcast Reader" fontWeight="bold" fontSize="16" />
			<mx:HBox width="100%">
				<mx:Label text="Available Podcasts:"/>
				<mx:ComboBox id="channelsCb" dataProvider="{podcastChannels}" width="90%" close="selectChannel();"/>	
			</mx:HBox>
			<mx:List id="rssList" width="100%" height="100%" itemRenderer="RSSRenderer" labelField="title"  />
		</mx:VBox>
		<mx:VBox id="podBox" width="100%" height="50%" horizontalAlign="center"  >
			<mx:Text id="podTitle"  fontSize="15" fontWeight="bold" maxWidth="{podBox.width}" />
			<mx:Text id="theArtistAlbum" text="or enter a new URL to load below" fontStyle="italic"/>
			<mx:HBox width="100%" height="100" >
				<fx:Visualization id="viz" type="bars" bars="96" channel="stereo" 
					width="95%" height="{volumeControl.height}" 
					audioFillColor="0xFFFFFF" audioLineColor="0xFFFFFF"/>	
				<mx:VSlider id="volumeControl" allowTrackClick="false" toolTip="{}" liveDragging="true" 
					thumbDrag="setVolume(this.volumeControl.value)" 
					height="100" value=".5" maximum="1" minimum="0"/>						
			</mx:HBox>
 
			<mx:ControlBar width="100%" >
				<mx:Button id="playPauseBtn" click="{playPause(event)}"  icon="{iconPlay}" />
				<mx:Button icon="{iconNext}" click="{next();}"/>
				<mx:ProgressBar id="seekAudioBar"  showEffect="{FadeIn}" height="16" width="100%" 
					enabled="false" visible="false" 
					mode="manual" label="" indeterminate="false" labelPlacement="center"/>	
			</mx:ControlBar>
			<mx:Label id="loadProgressBar" showEffect="{FadeIn}" hideEffect="{FadeOut}" width="100%" height="20"
					enabled="false" visible="false" 
					text="" fontWeight="bold" />
		</mx:VBox>
	</mx:VDividedBox>
</mx:Application>

RSSRenderer.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml" 
	width="100%" height="60" 
	verticalGap="0" verticalAlign="middle">
<mx:Script>
<![CDATA[
import flash.net.navigateToURL;
[Embed(source="assets/Play.png")] 	[Bindable] public var iconPlay:Class;
[Embed(source="assets/Save.png")] 	[Bindable] public var iconSave:Class;
//procesa el dato para ser configurado por el renderer	
override protected function commitProperties():void {
	super.commitProperties();
	if (data == null) { return; }
	lbl.label = data.title;
	lbl.toolTip = data.description;
	downloadProgress.text = "";
}
//
protected function playPodcast():void {
	dispatchEvent(new Event('playPodcast', true));
}
//abre la página html original donde se publicó el podcast
private function viewPost():void{
	navigateToURL(new URLRequest(data.link), "_blank");
}
//inicia el proceso de descarga del mp3
private function downloadMp3():void{
	var urlReq:URLRequest = new URLRequest(data.enclosure.url);
	var fileRef:FileReference = new FileReference();
	fileRef.addEventListener(ProgressEvent.PROGRESS, progressHandler);  
   	fileRef.addEventListener(Event.COMPLETE, completeHandler);  
	fileRef.download(urlReq);
}
//Progreso de la descarga del archivo mp3
private function progressHandler(e:ProgressEvent):void {  
     var loadPercent:Number = Math.round((e.bytesLoaded / e.bytesTotal) * 100);
	downloadProgress.text = loadPercent+" %";
} 
private function completeHandler(event:Event):void {  
     downloadProgress.text = "Download Complete";  
}  
	]]>
</mx:Script>
	<mx:LinkButton id="lbl" width="260" color="0x0" fontWeight="bold" click="{viewPost()}"  />
	<mx:Button toolTip="Play" icon="{iconPlay}" click="playPodcast()" height="32" />
	<mx:Button toolTip="Download" icon="{iconSave}" click="downloadMp3()" height="32" />
	<mx:Label id="downloadProgress" text=""  />
</mx:HBox>

Referencias:

  • Share/Bookmark

Desarrollo de aplicaciones colaborativas utilizando Flex 3, Facebook, BlazeDs, Spring y Java

August 22, 2009 – 8:40 am
Tags: , , ,

En el siguiente enlace pueden encontrar la aplicación, código fuente y demos que Kudos Ltda. presenta durante el FlashCampBogotá 2008:
Desarrollo de aplicaciones colaborativas utilizando Flex 3, Facebook, BlazeDs, Spring y Java

A continuación la presentación en SlideShare:

  • Share/Bookmark