Categorías
Python

Python y PyQt: La construcción de una calculadora de escritorio GUI

 

Tabla de Contenidos

  • Fetching DataThe guión
  • El guión
  • Visualización
  • BowerUpdate index.html
  • actualización index.html
  • D3SetupMain ConfigBubble ConfigSVG ConfigRequest la instalación de DataTooltipsRefactorCSS
  • configuración principal
  • burbuja Config
  • SVG Config
  • solicitar los datos
  • OceanDeploy sobre herramientas
  • Refactor
  • CSS
  • DeployingSetup digital ConfigUpdate app.py:Deploy! Configuración
  • Digital Océano
  • Implementar Config
  • actualización app.py:
  • Implementar!
  • próximos pasos
  • El guión
  • actualización index.html Configuración
  • configuración principal
  • burbuja Config
  • SVG Config
  • solicitar los datos sobre herramientas
  • Refactor
  • CSS
  • Configuración

  • digital Océano
  • Implementar Config
  • actualización app.py:
  • Implementar!

En este tutorial vamos a construir una aplicación web a los datos de agarre desde el NASDAQ-100 y visualizar como un gráfico de burbujas con D3. Luego, para colmo, vamos a implementar esta en Ocean Digital a través de Dokku.

Nota: Los gráficos de burbujas son perfectos para la visualización de cientos de valores en un espacio pequeño. Sin embargo, son más difíciles de leer debido a que puede ser difícil diferenciar los círculos de tamaño similar. Si está trabajando con sólo unos pocos valores, un gráfico de barras es probablemente la mejor opción ya que es mucho más fácil de leer.

principales herramientas utilizadas en este tutorial: v2.7.8 Python, v0.10.1 Frasco, las solicitudes v2.4.1, v3.4.11 D3, Dokku v0.2.3 y v1.3.9 Bower

Empiece por localizar y descargar el archivo _app_boilerplate .zip de este repositorio. Este archivo contiene un frasco repetitivo. Una vez descargado, extraer el archivo y carpetas, active un virtualenv, e instalar las dependencias con Pip:

pip install -r requirements.txt

Entonces prueba para asegurarse de que funciona: Fuego hasta el servidor, abra su navegador y vaya a http: // localhost: 5000 /. Debería ver “Hola, mundo!” mirando atrás a usted.

Recogida de Datos

Crear una nueva ruta y la función de vista en el archivo app.py :

@app.route("/data")
def data():
return jsonify(get_data())

actualización de las importaciones:

from flask import Flask, render_template, jsonify
from stock_scraper import get_data

lo tanto, cuando esa ruta se llama, convierte el valor devuelto por una función llamada get_data () para JSON y luego devuelve. Esta función reside en un archivo llamado stock_scraper.py , que – sorpresa! – obtiene datos desde el NASDAQ-100.

El guión

Añadir stock_scraper.py al directorio principal.

Tu turno : Crear el guión por su cuenta, siguiendo estos pasos:

¿Cómo te fue? ¿Necesitas ayuda? Echemos un vistazo a una posible solución: acontecimiento

import csv
import requests

URL = "http://www.nasdaq.com/quotes
asdaq-100-stocks.aspx?render=download"

def get_data():
r = requests.get(URL)
data = r.text
RESULTS = {'children': []}
for line in csv.DictReader(data.splitlines(), skipinitialspace=True):
RESULTS['children'].append({
'name': line['Name'],
'symbol': line['Symbol'],
'symbol': line['Symbol'],
'price': line['lastsale'],
'net_change': line['netchange'],
'percent_change': line['pctchange'],
'volume': line['share_volume'],
'value': line['Nasdaq100_points']
})
return RESULTS

de qué?

NOTA: También es posible usar una comprensión dict para crear los diccionarios individuales. Este es un método mucho más eficiente, sin embargo se sacrifica la legibilidad. Tu llamada.

tiempo para probar: Fuego hasta el servidor y vaya a http: // localhost: 5000 / datos. Si todo va bien, debería ver un objeto que contiene los datos de saldos pertinentes.

Con los datos en la mano, que ahora puede trabajar con visualizándolo en el front-end.

Visualización

Junto con HTML y CSS, que va a utilizar Bootstrap, Javascript / jQuery, y D3 al poder nuestro front-end. También utilizaremos el lado del cliente herramienta de gestión de la dependencia Bower de descargar y administrar estas bibliotecas.

Tu turno : Siga las instrucciones de instalación para configurar Bower en su máquina. Consejo: Usted tendrá que instalar Node.js antes de instalar Bower .

listo? Se necesitan archivos

Bower

dos para obtener glorieta ir – bower.json y .bowerrc .

Este último archivo se utiliza para configurar Bower. Añadir al directorio principal:

{
"directory": "static/bower_components"
}

esto sólo indica que se desea las dependencias instaladas en el directorio bower_components (convención) dentro del directorio estática de la aplicación.

Mientras tanto, el primer archivo, bower.json , almacena la glorieta de manifiesto – que significa que contiene metadatos sobre los componentes Bower, así como la propia aplicación. El archivo se puede crear de forma interactiva con el comando init glorieta. Hacerlo ahora. Basta con aceptar todos los valores predeterminados.

Ahora, podemos instalar las dependencias.

$ bower install bootstrap#3.2.0 jquery#2.1.1 d3#3.4.11 --save

La bandera –save añade los paquetes a la bower.json dependencias matriz. Echale un vistazo. También, asegúrese de que las versiones de dependencia en bower.json coinciden con las versiones que especificamos – es decir, de arranque # 3.20.

Con nuestras dependencias instaladas, vamos a hacerlos accesibles en nuestra aplicación.

actualización index.html




Flask Stock Visualizer<itle><br /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link href={{ url_for('static', filename='./bower_components/bootstrap/dist/css/bootstrap.min.css') }} rel="stylesheet" media="screen"> <link href={{ url_for('static', filename='main.css') }} rel="stylesheet" media="screen"> </head><br /> <body></p> <div class="container"> </div> <p> <script src={{ url_for('static', filename='./bower_components/jquery/dist/jquery.min.js') }}></script><br /> <script src={{ url_for('static', filename='./bower_components/bootstrap/dist/js/bootstrap.min.js') }}></script><br /> <script src={{ url_for('static', filename='./bower_components/d3/d3.min.js') }}></script><br /> <script src={{ url_for('static', filename='main.js') }}></script><br /> </body><br /> </html><br /> </code> </p> <h2> D3 </h2> <p> con tantos marcos de visualización de datos por ahí, ¿por qué D3? Bueno, D3 es un nivel bastante bajo, por lo que vamos a construir el tipo de marco que desea. Una vez que anexar los datos a la DOM, se utiliza una combinación de CSS3, HTML5, SVG y para crear la visualización real. A continuación, puede añadir interactividad a través de transiciones incorporada basada en los datos de-D3. </p> <p> Para ser justos, esta biblioteca no es para todos. Puesto que usted tiene una gran cantidad de libertad para construir lo que quiere, la curva de aprendizaje es bastante alto. Si usted está buscando para un comienzo rápido, echa un vistazo a Python-NVD3, que es un contenedor de D3, que sirve para facilitar el trabajo con D3 mucho, mucho más fácil. No estamos utilizando todo por este tutorial sin embargo, ya Python-NVD3 no soporta gráficos de burbujas. </p> <p> <strong> Tu turno </strong>: Ir a través de la introducción D3 tutorial. </p> <p> Ahora vamos a código. Configuración </p> <h3> </h3> <p> Agregue el código siguiente para <em> main.js </em>: </p> <p> <code>// Custom JavaScript</p> <p>$(function() {<br /> console.log('jquery is working!');<br /> createGraph();<br /> });</p> <p>function createGraph() {<br /> // Code goes here<br /> }<br /> </code> </p> <p> Aquí, después de la carga de la página inicial, registramos ‘! JQuery está trabajando’ a la consola y luego se disparó una función llamada createGraph (). Prueba de esto. Pon en marcha el servidor A continuación, vaya a http: // localhost: 5000 / y con la consola JavaScript abierta, actualice la página. Debería ver el ‘jQuery está trabajando!’ Texto si todo iba bien. </p> <p> Añadir la siguiente etiqueta en el archivo index.html <em> </em>, dentro de la etiqueta </p> <div> que tiene un id de contenedor (después de la línea 10), para mantener la D3 gráfico de burbujas: </p> <p> <code></p> <div id="chart"></div> <p></code> </p> <h3> configuración principal </h3> <p> Añadir la siguiente código a la función createGraph () en <em> main.js </em>: </p> <p> <code>var width = 960; // chart width<br /> var height = 700; // chart height<br /> var format = d3.format(",d"); // convert value to integer<br /> var color = d3.scale.category20(); // create ordinal scale with 20 colors<br /> var sizeOfRadius = d3.scale.pow().domain([-100,100]).range([-50,50]); // https://github.com/mbostock/d3/wiki/Quantitative-Scales#pow<br /> </code> </p> <p> Asegúrese de consultar los comentarios de código para una explantación, así como la documentación oficial D3. Mira nada hasta que no entiende. <em> Un codificador debe ser autosuficiente! </em> </p> <h3> burbuja Config </h3> <p> <code>var bubble = d3.layout.pack()<br /> .sort(null) // disable sorting, use DOM tree traversal<br /> .size([width, height]) // chart layout size<br /> .padding(1) // padding between circles<br /> .radius(function(d) { return 20 + (sizeOfRadius(d) * 30); }); // radius for each circle<br /> </code> </p> <p> Una vez más, añadir el código anterior para la función createGraph (), y comprobar la documentación para cualquier pregunta. </p> <h3> SVG Config </h3> <p> A continuación, añadir el siguiente código a createGraph (), que selecciona el elemento con el id de la tabla, a continuación, añade los círculos junto con una serie de atributos: </p> <p> <code>var svg = d3.select("#chart").append("svg")<br /> .attr("width", width)<br /> .attr("height", height)<br /> .attr("class", "bubble");<br /> </code> </p> <p> Continuando con el createGraph () función, ahora tenemos que tomar los datos, que se pueden hacer de forma asíncrona con D3. </p> <h3> solicitar los datos </h3> <p> <code>// REQUEST THE DATA<br /> d3.json("/data", function(error, quotes) {<br /> var node = svg.selectAll('.node')<br /> .data(bubble.nodes(quotes)<br /> .filter(function(d) { return !d.children; }))<br /> .enter().append('g')<br /> .attr('class', 'node')<br /> .attr('transform', function(d) { return 'translate(' + d.x + ',' + d.y + ')'});</p> <p> node.append('circle')<br /> .attr('r', function(d) { return d.r; })<br /> .style('fill', function(d) { return color(d.symbol); });</p> <p> node.append('text')<br /> .attr("dy", ".3em")<br /> .style('text-anchor', 'middle')<br /> .text(function(d) { return d.symbol; });<br /> });<br /> </code> </p> <p> Así, nos encontramos con el punto final / datos que hemos creado antes para devolver los datos. El resto de este código simplemente añade las burbujas y el texto en el DOM. Se trata de código repetitivo estándar, modificado ligeramente para nuestros datos. </p> <h3> sobre herramientas </h3> <p> Ya que tenemos un espacio limitado en el gráfico, aún dentro de la función createGraph (), Vamos a añadir algo sobre herramientas que muestran información adicional sobre cada uno específico de valores. </p> <p> <code>// tooltip config<br /> var tooltip = d3.select("body")<br /> .append("div")<br /> .style("position", "absolute")<br /> .style("z-index", "10")<br /> .style("visibility", "hidden")<br /> .style("color", "white")<br /> .style("padding", "8px")<br /> .style("background-color", "rgba(0, 0, 0, 0.75)")<br /> .style("border-radius", "6px")<br /> .style("font", "12px sans-serif")<br /> .text("tooltip");<br /> </code> </p> <p> Estos son sólo los estilos CSS asociados con la información sobre herramientas. Todavía tenemos que añadir los datos reales. Actualizar el código donde añadimos los círculos para el DOM: </p> <p> <code>node.append("circle")<br /> .attr("r", function(d) { return d.r; })<br /> .style('fill', function(d) { return color(d.symbol); })</p> <p> .on("mouseover", function(d) {<br /> tooltip.text(d.name + ": $" + d.price);<br /> tooltip.style("visibility", "visible");<br /> })<br /> .on("mousemove", function() {<br /> return tooltip.style("top", (d3.event.pageY-10)+"px").style("left",(d3.event.pageX+10)+"px");<br /> })<br /> .on("mouseout", function(){return tooltip.style("visibility", "hidden");});<br /> </code> </p> <p> probar esto, vaya a http: // localhost: 5000 /. Ahora, cuando Hoover sobre un círculo, verá algunos metadatos subyacente – nombre de la empresa y el precio de las acciones. </p> <p> <strong> Tu turno </strong>: Añadir más metadatos. ¿Qué otros datos cree que es relevante? Pensar en lo que estamos mostrando aquí – el cambio relativo en el precio. Usted tal vez podría calcular el precio anterior y mostrar: </p> <h3> Refactor </h3> <p> stocksWhat si sólo queríamos para visualizar las acciones con un índice de valor ponderado de mercado modificado – la columna de la NASDAQ-100 Puntos – mayor que 0,1? </p> <p> Añadir un condicional a los get_data () Función: </p> <p> <code>def get_data():<br /> r = requests.get(URL)<br /> data = r.text<br /> RESULTS = {'children': []}<br /> for line in csv.DictReader(data.splitlines(), skipinitialspace=True):<br /> if float(line['Nasdaq100_points']) > .01:<br /> RESULTS['children'].append({<br /> 'name': line['Name'],<br /> 'symbol': line['Symbol'],<br /> 'symbol': line['Symbol'],<br /> 'price': line['lastsale'],<br /> 'net_change': line['netchange'],<br /> 'percent_change': line['pctchange'],<br /> 'volume': line['share_volume'],<br /> 'value': line['Nasdaq100_points']<br /> })<br /> return RESULTS<br /> </code> </p> <p> Ahora, vamos a aumentar el radio de cada burbujas, en la sección de configuración de la burbuja <em> main.js </em>; modificar el código en consecuencia: </p> <p> <code>// Radius for each circle<br /> .radius(function(d) { return 20 + (sizeOfRadius(d) * 60); });<br /> </code> </p> <h3> CSS </h3> <p> Por último, vamos a añadir algunos estilos básicos para <em> main.css </em>: </p> <p> <code>body {<br /> padding-top: 20px;<br /> font: 12px sans-serif;<br /> font-weight: bold;<br /> }<br /> </code> </p> <p> mirada buena? Listo para implementar? </p> <h2> Implementación de </h2> <p> Dokku es un código abierto, Heroku-como, Plataforma como servicio (PaaS), alimentado por acoplable. Una vez configurado, puede llevar a su aplicación a la misma con Git. </p> <p> Estamos utilizando Océano Digital como nuestro anfitrión. Empecemos. Configuración </p> <h3> Digital Océano </h3> <p> Regístrese para obtener una cuenta, si no tiene ya uno. A continuación, siga esta guía para agregar una clave pública. </p> <p> Crear un nuevo Droplet – especificar un nombre, tamaño y ubicación. Para la imagen, haga clic en la pestaña “Aplicaciones” y seleccione la aplicación Dokku. Asegúrese de seleccionar su clave SSH. </p> <p> Una vez creado, completar la configuración mediante la introducción de la dirección IP de la gotita de nueva creación en el navegador, que le llevará a la pantalla de configuración Dokku. Confirmar que la clave pública es correcta, haga clic en “Finalizar configuración”. </p> <p> Ahora el VPS puede aceptar empujones. </p> <h3> Implementar Config </h3> <h3> actualización app.py: </h3> <p> <code>if __name__ == '__main__':<br /> port = int(os.environ.get('PORT', 5000))<br /> app.run(host='0.0.0.0', port=port)<br /> </code> </p> <p> Así, en primer lugar tratar de agarrar el puerto desde el entorno de la aplicación, y si no lo encuentra, el valor predeterminado es el puerto 5000. </p> <p> Asegúrese de actualizar las importaciones, así: </p> <p> <code>import os<br /> </code> </p> <h3> Implementar! </h3> <p> confirmar los cambios, a continuación, empuje: git push Dokku maestro. Si todo va bien, debería ver el URL de la aplicación en su terminal: </p> <p> <code>=====> Application deployed:<br /> http://192.241.208.61:49155<br /> </code> </p> <p> probarlo. Vaya a http://192.241.208.61:49155. (Una vez más, asegúrese de añadir su dirección IP junto con el puerto correcto.) Usted debe ver a su aplicación en vivo! (Ver la imagen en la parte superior de este post para una vista previa.) </p> <h2> próximos pasos </h2> <p> Quieres llevar esto al siguiente nivel? Añadir las siguientes características para la aplicación: </p> <p> Estas características (! Y más) se incluirá en la próxima edición de los cursos de Python real, llegando a principios de octubre 2014! </p> <p> comentario a continuación si tiene alguna pregunta. </p> <p> Salud! </p> </div><!-- .entry-content --> </div><!-- .post-inner --> <div class="section-inner"> </div><!-- .section-inner --> <nav class="pagination-single section-inner" aria-label="Entrada" role="navigation"> <hr class="styled-separator is-style-wide" aria-hidden="true" /> <div class="pagination-single-inner"> <a class="previous-post" href="https://eltecnofilo.es/introduccion-a-la-programacion-orientada-a-objetos-poo-en-python/"> <span class="arrow" aria-hidden="true">←</span> <span class="title"><span class="title-inner">Introducción a la programación orientada a objetos (POO) en Python</span></span> </a> <a class="next-post" href="https://eltecnofilo.es/inicio-de-sesion-en-python/"> <span class="arrow" aria-hidden="true">→</span> <span class="title"><span class="title-inner">Inicio de sesión en Python</span></span> </a> </div><!-- .pagination-single-inner --> <hr class="styled-separator is-style-wide" aria-hidden="true" /> </nav><!-- .pagination-single --> <div class="comments-wrapper section-inner"> <div id="respond" class="comment-respond"> <h2 id="reply-title" class="comment-reply-title">Deja un comentario <small><a rel="nofollow" id="cancel-comment-reply-link" href="/python-y-pyqt-la-construccion-de-una-calculadora-de-escritorio-gui/#respond" style="display:none;">Cancelar la respuesta</a></small></h2><form action="https://eltecnofilo.es/wp-comments-post.php" method="post" id="commentform" class="section-inner thin max-percentage" novalidate><p class="comment-notes"><span id="email-notes">Tu dirección de correo electrónico no será publicada.</span> Los campos obligatorios están marcados con <span class="required">*</span></p><p class="comment-form-comment"><label for="comment">Comentario</label> <textarea id="comment" name="comment" cols="45" rows="8" maxlength="65525" required="required"></textarea></p><p class="comment-form-author"><label for="author">Nombre <span class="required">*</span></label> <input id="author" name="author" type="text" value="" size="30" maxlength="245" required='required' /></p> <p class="comment-form-email"><label for="email">Correo electrónico <span class="required">*</span></label> <input id="email" name="email" type="email" value="" size="30" maxlength="100" aria-describedby="email-notes" required='required' /></p> <p class="comment-form-url"><label for="url">Web</label> <input id="url" name="url" type="url" value="" size="30" maxlength="200" /></p> <p class="comment-form-cookies-consent"><input id="wp-comment-cookies-consent" name="wp-comment-cookies-consent" type="checkbox" value="yes" /> <label for="wp-comment-cookies-consent">Guardar mi nombre, correo electrónico y sitio web en este navegador para la próxima vez que haga un comentario.</label></p> <p class="form-submit"><input name="submit" type="submit" id="submit" class="submit" value="Publicar el comentario" /> <input type='hidden' name='comment_post_ID' value='7022' id='comment_post_ID' /> <input type='hidden' name='comment_parent' id='comment_parent' value='0' /> </p></form> </div><!-- #respond --> </div><!-- .comments-wrapper --> </article><!-- .post --> </main><!-- #site-content --> <div class="footer-nav-widgets-wrapper header-footer-group"> <div class="footer-inner section-inner"> <aside class="footer-widgets-outer-wrapper" role="complementary"> <div class="footer-widgets-wrapper"> <div class="footer-widgets column-one grid-item"> <div class="widget widget_search"><div class="widget-content"><form role="search" method="get" class="search-form" action="https://eltecnofilo.es/"> <label for="search-form-2"> <span class="screen-reader-text">Buscar:</span> <input type="search" id="search-form-2" class="search-field" placeholder="Buscar …" value="" name="s" /> </label> <input type="submit" class="search-submit" value="Buscar" /> </form> </div></div> <div class="widget widget_recent_entries"><div class="widget-content"> <h2 class="widget-title subheading heading-size-3">Entradas recientes</h2> <ul> <li> <a href="https://eltecnofilo.es/vps-cloud-hosting/">VPS cloud hosting</a> </li> <li> <a href="https://eltecnofilo.es/versiones-de-ejecucion-de-python-en-acoplable-como-probar-la-ultima-release-python/">Versiones de ejecución de Python en acoplable: Cómo probar la última Release Python</a> </li> <li> <a href="https://eltecnofilo.es/leer-y-escribir-archivos-csv/">Leer y escribir archivos CSV</a> </li> <li> <a href="https://eltecnofilo.es/python-puro-vs-vs-numpy-tensorflow-comparacion-de-rendimiento/">Python puro vs vs NumPy TensorFlow Comparación de Rendimiento</a> </li> <li> <a href="https://eltecnofilo.es/estructura-python-programa-lexico/">Estructura Python Programa léxico</a> </li> </ul> </div></div><div class="widget widget_recent_comments"><div class="widget-content"><h2 class="widget-title subheading heading-size-3">Comentarios recientes</h2><ul id="recentcomments"><li class="recentcomments"><span class="comment-author-link"><a href="https://wordpress.org/" rel="external nofollow ugc" class="url">A WordPress Commenter</a></span> en <a href="https://eltecnofilo.es/hello-world/#comment-1">Hello world!</a></li></ul></div></div> </div> <div class="footer-widgets column-two grid-item"> <div class="widget widget_archive"><div class="widget-content"><h2 class="widget-title subheading heading-size-3">Archivos</h2> <ul> <li><a href='https://eltecnofilo.es/2020/04/'>abril 2020</a></li> <li><a href='https://eltecnofilo.es/2020/03/'>marzo 2020</a></li> <li><a href='https://eltecnofilo.es/2019/12/'>diciembre 2019</a></li> </ul> </div></div><div class="widget widget_categories"><div class="widget-content"><h2 class="widget-title subheading heading-size-3">Categorías</h2> <ul> <li class="cat-item cat-item-22"><a href="https://eltecnofilo.es/category/python/">Python</a> </li> <li class="cat-item cat-item-1"><a href="https://eltecnofilo.es/category/uncategorized/">Uncategorized</a> </li> </ul> </div></div><div class="widget widget_meta"><div class="widget-content"><h2 class="widget-title subheading heading-size-3">Meta</h2> <ul> <li><a rel="nofollow" href="https://eltecnofilo.es/wp-login.php">Acceder</a></li> <li><a href="https://eltecnofilo.es/feed/">Feed de entradas</a></li> <li><a href="https://eltecnofilo.es/comments/feed/">Feed de comentarios</a></li> <li><a href="https://es.wordpress.org/">WordPress.org</a></li> </ul> </div></div> </div> </div><!-- .footer-widgets-wrapper --> </aside><!-- .footer-widgets-outer-wrapper --> </div><!-- .footer-inner --> </div><!-- .footer-nav-widgets-wrapper --> <footer id="site-footer" role="contentinfo" class="header-footer-group"> <div class="section-inner"> <div class="footer-credits"> <p class="footer-copyright">© 2020 <a href="https://eltecnofilo.es/">My Blog</a> </p><!-- .footer-copyright --> <p class="powered-by-wordpress"> <a href="https://es.wordpress.org/"> Funciona gracias a WordPress </a> </p><!-- .powered-by-wordpress --> </div><!-- .footer-credits --> <a class="to-the-top" href="#site-header"> <span class="to-the-top-long"> Ir arriba <span class="arrow" aria-hidden="true">↑</span> </span><!-- .to-the-top-long --> <span class="to-the-top-short"> Subir <span class="arrow" aria-hidden="true">↑</span> </span><!-- .to-the-top-short --> </a><!-- .to-the-top --> </div><!-- .section-inner --> </footer><!-- #site-footer --> <script src='https://eltecnofilo.es/wp-includes/js/comment-reply.min.js?ver=5.3.3'></script> <script src='https://eltecnofilo.es/wp-includes/js/wp-embed.min.js?ver=5.3.3'></script> <script> /(trident|msie)/i.test(navigator.userAgent)&&document.getElementById&&window.addEventListener&&window.addEventListener("hashchange",function(){var t,e=location.hash.substring(1);/^[A-z0-9_-]+$/.test(e)&&(t=document.getElementById(e))&&(/^(?:a|select|input|button|textarea)$/i.test(t.tagName)||(t.tabIndex=-1),t.focus())},!1); </script> </body> </html>