SlideShare ist ein Scribd-Unternehmen logo
1 von 31
Downloaden Sie, um offline zu lesen
PhantomJS 
Автоматизация WebKit на JavaScript
fun-box.ru/ulsk 
Илья Василевский 
Разработчик на Ruby и CoffeeScript 
github.com/vassilevsky
1995 — 2014 (19 лет) 
Trolltech → Nokia → Digia 
C++ 
Android, Embedded Linux, iOS, OS X, QNX / 
BlackBerry 10, Sailfish OS, VxWorks, 
Wayland, Windows, Windows CE, X11 
(GNU/Linux, FreeBSD, HP-UX, Solaris, AIX) 
http://qt-project.org
Qt Core 
Qt GUI 
Qt Widgets 
Qt QML and JavaScript 
Qt Quick 
Qt Quick Controls 
Qt Quick Layouts 
Qt Network 
Qt Multimedia 
Qt Multimedia Widgets 
Qt SQL 
Qt WebKit 
Qt WebKit Widgets 
Qt Test
#include <QApplication> 
#include <QMenu> 
#include <QPixmap> 
#include <QWidget> 
#include <qmacfunctions.h> 
int main(int argc, char **argv) 
{ 
QApplication app(argc, argv); 
QWidget widget; 
widget.show(); 
// Pixmap <-> CGImage conversion 
QPixmap pixmap(":qtlogo.png"); 
CGImageRef cgImage = QtMac::toCGImageRef(pixmap); 
QPixmap pixmap2 = QtMac::fromCGImageRef(cgImage); 
return app.exec(); 
}
require 'Qt' 
require './qrc_systray.rb' 
require './window.rb' 
app = Qt::Application.new(ARGV) 
if !Qt::SystemTrayIcon.isSystemTrayAvailable 
Qt::MessageBox.critical( 
nil, 
Qt::Object.tr("Systray"), 
Qt::Object.tr("I couldn't detect any system tray on this system.") 
) 
exit 1 
end 
window = Window.new 
window.show 
app.exec
Qt Core 
Qt GUI 
Qt Widgets 
Qt QML and JavaScript 
Qt Quick 
Qt Quick Controls 
Qt Quick Layouts 
Qt Network 
Qt Multimedia 
Qt Multimedia Widgets 
Qt SQL 
Qt WebKit 
Qt WebKit Widgets 
Qt Test
QWindow 
QWebView 
QWidget QWebPage 
QWidget 
QWebFrame
Ariya Hidayat 
VP of Engineering at @ShapeSecurity 
Doctorate degree (with great honor) in Electrical Engineering 
from University of Paderborn (Germany) 
Master degree from Institute of Technology Bandung (Indonesia) 
with an exchange program with Technical University Munich (Germany) 
Bachelor degree (with honor) from Institute of Technology Bandung (Indonesia) 
Indonesian, English, German 
Indonesia → Mountain View, California 
@AriyaHidayat
Qt WebKit 
JavaScript 
API Engine 
Web 
Server 
Mongoose 
Ghost Driver 
Remote 
Selenium WebDriver 
(Wire Protocol) 
JavaScript 
Engine
$ ls -l phantomjs-1.9.7-linux-x86_64/bin 
total 74896 
-rwxr-xr-x@ 1 vassilevsky staff 38346752 26 янв 2014 phantomjs 
X11 (v1.5+) 
freetype 
fontconfig
// goodbye_world.js 
console.log('Goodbye, cruel world!'); 
phantom.exit(); 
$ phantomjs goodbye_world.js 
Goodbye, cruel world!
// screenshot.js 
var page = require('webpage').create(); 
page.open('http://www.therestartpage.com', function(status) { 
if (status == 'success') { 
page.render('restart.png'); 
} 
phantom.exit(); 
}); 
$ phantomjs screenshot.js 
$ open restart.png
// stealing.js 
var page = require('webpage').create(); 
page.open('http://victim.com', function(status) { 
if (status == 'success') { 
var usefulValue = page.evaluate(function() { 
return document.getElementById('secretId').textContent; // runs on page 
}); 
console.log('Stolen: ' + usefulValue); 
} 
phantom.exit(); 
}); 
$ phantomjs stealing.js 
Stolen: uid123456789
Qt WebKit 
JavaScript API Engine 
JavaScript Engine 
function() { 
return document.getElementById('secretId').textContent; 
} 
var page = require('webpage').create(); 
page.open('http://victim.com', function(status) { 
if (status == 'success') { 
var usefulValue = page.evaluate( ); 
console.log('Stolen: ' + usefulValue); 
} 
phantom.exit(); 
}); 
Qt WebKit
var page = require('webpage').create(); 
doSomeWork = function(param1, param2, param3) { 
doSomethingWith(param1); // runs on page 
useSomehow(param2); // runs on page 
disregard(param3); // runs on page 
} 
page.open('http://example.com', function() { 
page.evaluate(doSomeWork, value1, value2, value3); 
phantom.exit(); 
});
var page = require('webpage').create(); 
Qt WebKit 
JavaScript API Engine 
page.open('http://example.com', function() { 
page.evaluate(doSomeWork, value1, value2, value3); 
phantom.exit(); 
}); 
JavaScript Engine 
function(param1, param2, param3) { 
doSomethingWith(param1); 
useSomehow(param2); 
disregard(param3); 
} 
Qt WebKit
var page = require('webpage').create(); 
Qt WebKit 
JavaScript API Engine 
page.open('http://example.com', function() { 
page.evaluate(doSomeWork, value1, value2, value3); 
phantom.exit(); 
}); 
JavaScript Engine 
function(param1, param2, param3) { 
doSomethingWith(param1); 
useSomehow(param2); 
disregard(param3); 
} 
Qt WebKit 
J S O N
PROPERTIES 
canGoBack 
canGoForward 
clipRect 
content 
cookies 
customHeaders 
event 
focusedFrameName 
frameContent 
frameName 
framePlainText 
frameTitle 
frameUrl 
framesCount 
framesName 
libraryPath 
navigationLocked 
offlineStoragePath 
offlineStorageQuota 
ownsPages 
pages 
pagesWindowName 
paperSize 
plainText 
scrollPosition 
settings 
title 
url 
viewportSize 
windowName 
zoomFactor 
METHODS 
addCookie 
childFramesCount 
childFramesName 
clearCookies 
close 
currentFrameName 
deleteCookie 
evaluate 
evaluateAsync 
evaluateJavaScript 
getPage 
go 
goBack 
goForward 
includeJs 
injectJs 
open 
openUrl 
release 
reload 
render 
renderBase64 
sendEvent 
setContent 
stop 
switchToChildFrame 
switchToFocusedFrame 
switchToFrame 
switchToMainFrame 
switchToParentFrame 
uploadFile 
HANDLERS 
onAlert 
onCallback 
onClosing 
onConfirm 
onConsoleMessage 
onError 
onFilePicker 
onInitialized 
onLoadFinished 
onLoadStarted 
onNavigationRequested 
onPageCreated 
onPrompt 
onResourceError 
onResourceReceived 
onResourceRequested 
onResourceTimeout 
onUrlChanged
require 'childprocess' 
def phantomjs(script, timeout) 
output, input = IO.pipe 
phantomjs = ChildProcess.new("/usr/local/bin/phantomjs", "--disk-cache=true", script) 
phantomjs.io.stdout = input 
phantomjs.io.stderr = input 
Timeout.timeout(timeout) do 
phantomjs.start 
input.close 
logger.info("Attaching to PhantomJS's STDOUT and STDERR...") 
output.each_line{|line| logger.info("[PhantomJS] #{line}") } 
end 
rescue Timeout::Error 
logger.warn("PhantomJS is running longer than expected. Shutting it down...") 
phantomjs.stop 
end
page = require('webpage').create() 
page.viewportSize = {width, height} 
prepareTrack = (i) -> 
track = tracks[i] 
page.evaluate(drawTrack, track.bounds, track.locations) 
setTimeout(renderTrack, MAP_LOADING_TIME, i) 
renderTrack = (i) -> 
track = tracks[i] 
page.render(track.imagePath) 
if i + 1 == tracks.length 
phantom.exit() 
else 
prepareTrack(i + 1) 
drawTrack = (bounds, locations) -> 
setBounds(bounds) 
drawTrackLine(locations) 
page.open(hostPage) 
setTimeout(renderTrack, MAP_LOADING_TIME, 0)
!!! 5 
%html 
%head 
%meta{charset: "utf-8"} 
:css 
#map_container { position: absolute; left: 0; right: 0; top: 0; bottom: 0 } 
%body 
#map_container 
%script{src: "http://api-maps.yandex.ru/2.1/?lang=ru_RU"} 
:coffeescript 
@map = null 
ymaps.ready => 
@map = new ymaps.Map 'map_container' 
@setBounds = (bounds) -> 
@map.setBounds(bounds) 
@drawTrackLine = (locations) -> 
points = (location.point for location in locations) 
@map.geoObjects.add(new ymaps.Polyline(points))
RSpec Cucumber MiniTest 
Capybara 
Poltergeist 
PhantomJS
require 'capybara/poltergeist' 
Capybara.javascript_driver = :poltergeist 
Capybara.methods += 
page.evaluate_script 
page.execute_script 
page.within_frame 
page.within_window 
page.status_code 
page.response_headers 
page.save_screenshot 
page.driver.render_base64(format, options) 
page.driver.scroll_to(left, top) 
page.driver.basic_authorize(user, password) 
element.native.send_keys(*keys)
JS API 
class Poltergeist.Connection 
constructor: (@owner, @port) -> 
@socket = new WebSocket "ws://127.0.0.1:#{@port}/" 
@socket.onmessage = this.commandReceived 
@socket.onclose = -> phantom.exit() 
WebKit 
module Capybara::Poltergeist 
class Server 
attr_reader :socket, :fixed_port, :timeout 
def start 
@socket = WebSocketServer.new(fixed_port, timeout) 
end 
def send(message) 
@socket.send(message) or raise DeadClient.new(message) 
end 
end 
end
class Poltergeist.WebPage 
onErrorNative: (message, stack) -> 
stackString = message 
stack.forEach (frame) -> 
stackString += "n" 
stackString += " at #{frame.file}:#{frame.line}" 
stackString += " in #{frame.function}" if frame.function && frame.function != '' 
@errors.push(message: message, stack: stackString) 
class Poltergeist.Browser 
sendResponse: (response) -> 
errors = @currentPage.errors 
@currentPage.clearErrors() 
if errors.length > 0 && @js_errors 
@owner.sendError(new Poltergeist.JavascriptError(errors)) 
else 
@owner.sendResponse(response)
Casper.js 
Chutzpah 
Ghostbuster 
GhostDriver 
Lotte 
Poltergeist 
Capybara 
pjscrape 
WebSpecter 
conjure 
PhantomJS Google Charts 
capturejs 
pageres 
phantomjs-screenshots 
screenshot-app 
screenshot-as-a-service 
screenshot-service 
screenshot 
screenshot-webservice 
pyshotx 
node-webshot 
pageres 
django-screamshot 
PHP Screen 
grabshot 
basset 
Compass Magick 
Confess 
GhostStory 
Grover 
Grunt 
Guard PhantomJS 
phridge 
phantomjs-node 
node-phantom 
phantom-proxy 
phantomas 
PhantomCSS 
PhantomFlow 
phantomjs-maven-plugin 
grunt-lib-phantomjs 
grunt-contrib-qunit 
PhantomLint 
PhantomXHR 
shortcut.io 
Slippy 
SpookyJS 
Yeoman
За внимание спасибо

Weitere ähnliche Inhalte

Was ist angesagt?

Introdução ao Desenvolvimento Android com Kotlin
Introdução ao Desenvolvimento Android com KotlinIntrodução ao Desenvolvimento Android com Kotlin
Introdução ao Desenvolvimento Android com KotlinNelson Glauber Leal
 
Firefox OS learnings & visions, WebAPIs - budapest.mobile
Firefox OS learnings & visions, WebAPIs - budapest.mobileFirefox OS learnings & visions, WebAPIs - budapest.mobile
Firefox OS learnings & visions, WebAPIs - budapest.mobileRobert Nyman
 
Bs webgl소모임004
Bs webgl소모임004Bs webgl소모임004
Bs webgl소모임004Seonki Paik
 
Arquitetando seu app Android com Jetpack
Arquitetando seu app Android com JetpackArquitetando seu app Android com Jetpack
Arquitetando seu app Android com JetpackNelson Glauber Leal
 
Developing web-apps like it's 2013
Developing web-apps like it's 2013Developing web-apps like it's 2013
Developing web-apps like it's 2013Laurent_VB
 
Angular 1 + es6
Angular 1 + es6Angular 1 + es6
Angular 1 + es6장현 한
 
Fundamental Node.js (Workshop bersama Front-end Developer GITS Indonesia, War...
Fundamental Node.js (Workshop bersama Front-end Developer GITS Indonesia, War...Fundamental Node.js (Workshop bersama Front-end Developer GITS Indonesia, War...
Fundamental Node.js (Workshop bersama Front-end Developer GITS Indonesia, War...GITS Indonesia
 
Jeroen Vloothuis Bend Kss To Your Will
Jeroen Vloothuis   Bend Kss To Your WillJeroen Vloothuis   Bend Kss To Your Will
Jeroen Vloothuis Bend Kss To Your WillVincenzo Barone
 
The Power of the JVM: Applied Polyglot Projects with Java and JavaScript
The Power of the JVM: Applied Polyglot Projects with Java and JavaScriptThe Power of the JVM: Applied Polyglot Projects with Java and JavaScript
The Power of the JVM: Applied Polyglot Projects with Java and JavaScriptHazelcast
 
State management in a GraphQL era
State management in a GraphQL eraState management in a GraphQL era
State management in a GraphQL erakristijanmkd
 
Cooking Up Drama - ChefConf 2015
Cooking Up Drama - ChefConf 2015 Cooking Up Drama - ChefConf 2015
Cooking Up Drama - ChefConf 2015 Chef
 
Cristiano Betta (Betta Works) - Lightweight Libraries with Rollup, Riot and R...
Cristiano Betta (Betta Works) - Lightweight Libraries with Rollup, Riot and R...Cristiano Betta (Betta Works) - Lightweight Libraries with Rollup, Riot and R...
Cristiano Betta (Betta Works) - Lightweight Libraries with Rollup, Riot and R...Techsylvania
 
You will learn RxJS in 2017
You will learn RxJS in 2017You will learn RxJS in 2017
You will learn RxJS in 2017名辰 洪
 
Samsung WebCL Prototype API
Samsung WebCL Prototype APISamsung WebCL Prototype API
Samsung WebCL Prototype APIRyo Jin
 
Node.js for enterprise - JS Conference
Node.js for enterprise - JS ConferenceNode.js for enterprise - JS Conference
Node.js for enterprise - JS ConferenceTimur Shemsedinov
 

Was ist angesagt? (20)

Introdução ao Desenvolvimento Android com Kotlin
Introdução ao Desenvolvimento Android com KotlinIntrodução ao Desenvolvimento Android com Kotlin
Introdução ao Desenvolvimento Android com Kotlin
 
JavaScript on the Desktop
JavaScript on the DesktopJavaScript on the Desktop
JavaScript on the Desktop
 
Firefox OS learnings & visions, WebAPIs - budapest.mobile
Firefox OS learnings & visions, WebAPIs - budapest.mobileFirefox OS learnings & visions, WebAPIs - budapest.mobile
Firefox OS learnings & visions, WebAPIs - budapest.mobile
 
The jsdom
The jsdomThe jsdom
The jsdom
 
Bs webgl소모임004
Bs webgl소모임004Bs webgl소모임004
Bs webgl소모임004
 
Arquitetando seu app Android com Jetpack
Arquitetando seu app Android com JetpackArquitetando seu app Android com Jetpack
Arquitetando seu app Android com Jetpack
 
ES6 is Nigh
ES6 is NighES6 is Nigh
ES6 is Nigh
 
Developing web-apps like it's 2013
Developing web-apps like it's 2013Developing web-apps like it's 2013
Developing web-apps like it's 2013
 
Angular 1 + es6
Angular 1 + es6Angular 1 + es6
Angular 1 + es6
 
Fundamental Node.js (Workshop bersama Front-end Developer GITS Indonesia, War...
Fundamental Node.js (Workshop bersama Front-end Developer GITS Indonesia, War...Fundamental Node.js (Workshop bersama Front-end Developer GITS Indonesia, War...
Fundamental Node.js (Workshop bersama Front-end Developer GITS Indonesia, War...
 
Jeroen Vloothuis Bend Kss To Your Will
Jeroen Vloothuis   Bend Kss To Your WillJeroen Vloothuis   Bend Kss To Your Will
Jeroen Vloothuis Bend Kss To Your Will
 
The Power of the JVM: Applied Polyglot Projects with Java and JavaScript
The Power of the JVM: Applied Polyglot Projects with Java and JavaScriptThe Power of the JVM: Applied Polyglot Projects with Java and JavaScript
The Power of the JVM: Applied Polyglot Projects with Java and JavaScript
 
State management in a GraphQL era
State management in a GraphQL eraState management in a GraphQL era
State management in a GraphQL era
 
Cooking Up Drama - ChefConf 2015
Cooking Up Drama - ChefConf 2015 Cooking Up Drama - ChefConf 2015
Cooking Up Drama - ChefConf 2015
 
Cooking Up Drama
Cooking Up DramaCooking Up Drama
Cooking Up Drama
 
Cristiano Betta (Betta Works) - Lightweight Libraries with Rollup, Riot and R...
Cristiano Betta (Betta Works) - Lightweight Libraries with Rollup, Riot and R...Cristiano Betta (Betta Works) - Lightweight Libraries with Rollup, Riot and R...
Cristiano Betta (Betta Works) - Lightweight Libraries with Rollup, Riot and R...
 
You will learn RxJS in 2017
You will learn RxJS in 2017You will learn RxJS in 2017
You will learn RxJS in 2017
 
Samsung WebCL Prototype API
Samsung WebCL Prototype APISamsung WebCL Prototype API
Samsung WebCL Prototype API
 
Node.js for enterprise - JS Conference
Node.js for enterprise - JS ConferenceNode.js for enterprise - JS Conference
Node.js for enterprise - JS Conference
 
Scripting GeoServer
Scripting GeoServerScripting GeoServer
Scripting GeoServer
 

Andere mochten auch

Js testing
Js testingJs testing
Js testingMaslowB
 
Phantom js quick start
Phantom js quick startPhantom js quick start
Phantom js quick startji guang
 
Introduction to PhantomJS
Introduction to PhantomJSIntroduction to PhantomJS
Introduction to PhantomJSErol Selitektay
 
Superfast Automated Web Testing with CasperJS & PhantomJS
Superfast Automated Web Testing with CasperJS & PhantomJS Superfast Automated Web Testing with CasperJS & PhantomJS
Superfast Automated Web Testing with CasperJS & PhantomJS Hervé Vũ Roussel
 
An introduction to PhantomJS: A headless browser for automation test.
An introduction to PhantomJS: A headless browser for automation test.An introduction to PhantomJS: A headless browser for automation test.
An introduction to PhantomJS: A headless browser for automation test.BugRaptors
 
Automated Testing with Cucumber, PhantomJS and Selenium
Automated Testing with Cucumber, PhantomJS and SeleniumAutomated Testing with Cucumber, PhantomJS and Selenium
Automated Testing with Cucumber, PhantomJS and SeleniumDev9Com
 
The Mobile Story 2016 [Infographic]
The Mobile Story 2016 [Infographic]The Mobile Story 2016 [Infographic]
The Mobile Story 2016 [Infographic]Ajeet Singh
 

Andere mochten auch (7)

Js testing
Js testingJs testing
Js testing
 
Phantom js quick start
Phantom js quick startPhantom js quick start
Phantom js quick start
 
Introduction to PhantomJS
Introduction to PhantomJSIntroduction to PhantomJS
Introduction to PhantomJS
 
Superfast Automated Web Testing with CasperJS & PhantomJS
Superfast Automated Web Testing with CasperJS & PhantomJS Superfast Automated Web Testing with CasperJS & PhantomJS
Superfast Automated Web Testing with CasperJS & PhantomJS
 
An introduction to PhantomJS: A headless browser for automation test.
An introduction to PhantomJS: A headless browser for automation test.An introduction to PhantomJS: A headless browser for automation test.
An introduction to PhantomJS: A headless browser for automation test.
 
Automated Testing with Cucumber, PhantomJS and Selenium
Automated Testing with Cucumber, PhantomJS and SeleniumAutomated Testing with Cucumber, PhantomJS and Selenium
Automated Testing with Cucumber, PhantomJS and Selenium
 
The Mobile Story 2016 [Infographic]
The Mobile Story 2016 [Infographic]The Mobile Story 2016 [Infographic]
The Mobile Story 2016 [Infographic]
 

Ähnlich wie Automate WebKit with PhantomJS JavaScript

Hybrid Apps (Native + Web) via QtWebKit
Hybrid Apps (Native + Web) via QtWebKitHybrid Apps (Native + Web) via QtWebKit
Hybrid Apps (Native + Web) via QtWebKitAriya Hidayat
 
Qt & Webkit
Qt & WebkitQt & Webkit
Qt & WebkitQT-day
 
JavaScript Growing Up
JavaScript Growing UpJavaScript Growing Up
JavaScript Growing UpDavid Padbury
 
Hybrid Apps (Native + Web) using WebKit
Hybrid Apps (Native + Web) using WebKitHybrid Apps (Native + Web) using WebKit
Hybrid Apps (Native + Web) using WebKitAriya Hidayat
 
Hybrid Apps (Native + Web) using WebKit
Hybrid Apps (Native + Web) using WebKitHybrid Apps (Native + Web) using WebKit
Hybrid Apps (Native + Web) using WebKitAriya Hidayat
 
Analyzing the Performance of Mobile Web
Analyzing the Performance of Mobile WebAnalyzing the Performance of Mobile Web
Analyzing the Performance of Mobile WebAriya Hidayat
 
CasperJs Enjoy Functional Testing
CasperJs Enjoy Functional TestingCasperJs Enjoy Functional Testing
CasperJs Enjoy Functional TestingFabien POMEROL
 
Cape Cod Web Technology Meetup - 2
Cape Cod Web Technology Meetup - 2Cape Cod Web Technology Meetup - 2
Cape Cod Web Technology Meetup - 2Asher Martin
 
Mobile webapplication development
Mobile webapplication developmentMobile webapplication development
Mobile webapplication developmentGanesh Gembali
 
Integrating React.js Into a PHP Application
Integrating React.js Into a PHP ApplicationIntegrating React.js Into a PHP Application
Integrating React.js Into a PHP ApplicationAndrew Rota
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applicationsTom Croucher
 
Universal JavaScript
Universal JavaScriptUniversal JavaScript
Universal JavaScript名辰 洪
 
NoSQL and JavaScript: a love story
NoSQL and JavaScript: a love storyNoSQL and JavaScript: a love story
NoSQL and JavaScript: a love storyAlexandre Morgaut
 
soft-shake.ch - Hands on Node.js
soft-shake.ch - Hands on Node.jssoft-shake.ch - Hands on Node.js
soft-shake.ch - Hands on Node.jssoft-shake.ch
 
Training: Day Four - Struts, Tiles, Renders and Faces
Training: Day Four - Struts, Tiles, Renders and FacesTraining: Day Four - Struts, Tiles, Renders and Faces
Training: Day Four - Struts, Tiles, Renders and FacesArtur Ventura
 
FP - Découverte de Play Framework Scala
FP - Découverte de Play Framework ScalaFP - Découverte de Play Framework Scala
FP - Découverte de Play Framework ScalaKévin Margueritte
 
Drones, Flying robots and Javascript
Drones, Flying robots and JavascriptDrones, Flying robots and Javascript
Drones, Flying robots and JavascriptLaurent Eschenauer
 
Node js introduction
Node js introductionNode js introduction
Node js introductionAlex Su
 

Ähnlich wie Automate WebKit with PhantomJS JavaScript (20)

Hybrid Apps (Native + Web) via QtWebKit
Hybrid Apps (Native + Web) via QtWebKitHybrid Apps (Native + Web) via QtWebKit
Hybrid Apps (Native + Web) via QtWebKit
 
Qt & Webkit
Qt & WebkitQt & Webkit
Qt & Webkit
 
JavaScript Growing Up
JavaScript Growing UpJavaScript Growing Up
JavaScript Growing Up
 
Hybrid Apps (Native + Web) using WebKit
Hybrid Apps (Native + Web) using WebKitHybrid Apps (Native + Web) using WebKit
Hybrid Apps (Native + Web) using WebKit
 
Hybrid Apps (Native + Web) using WebKit
Hybrid Apps (Native + Web) using WebKitHybrid Apps (Native + Web) using WebKit
Hybrid Apps (Native + Web) using WebKit
 
Analyzing the Performance of Mobile Web
Analyzing the Performance of Mobile WebAnalyzing the Performance of Mobile Web
Analyzing the Performance of Mobile Web
 
CasperJs Enjoy Functional Testing
CasperJs Enjoy Functional TestingCasperJs Enjoy Functional Testing
CasperJs Enjoy Functional Testing
 
Cape Cod Web Technology Meetup - 2
Cape Cod Web Technology Meetup - 2Cape Cod Web Technology Meetup - 2
Cape Cod Web Technology Meetup - 2
 
Mobile webapplication development
Mobile webapplication developmentMobile webapplication development
Mobile webapplication development
 
Integrating React.js Into a PHP Application
Integrating React.js Into a PHP ApplicationIntegrating React.js Into a PHP Application
Integrating React.js Into a PHP Application
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
 
JS everywhere 2011
JS everywhere 2011JS everywhere 2011
JS everywhere 2011
 
Universal JavaScript
Universal JavaScriptUniversal JavaScript
Universal JavaScript
 
NoSQL and JavaScript: a love story
NoSQL and JavaScript: a love storyNoSQL and JavaScript: a love story
NoSQL and JavaScript: a love story
 
OneRing @ OSCamp 2010
OneRing @ OSCamp 2010OneRing @ OSCamp 2010
OneRing @ OSCamp 2010
 
soft-shake.ch - Hands on Node.js
soft-shake.ch - Hands on Node.jssoft-shake.ch - Hands on Node.js
soft-shake.ch - Hands on Node.js
 
Training: Day Four - Struts, Tiles, Renders and Faces
Training: Day Four - Struts, Tiles, Renders and FacesTraining: Day Four - Struts, Tiles, Renders and Faces
Training: Day Four - Struts, Tiles, Renders and Faces
 
FP - Découverte de Play Framework Scala
FP - Découverte de Play Framework ScalaFP - Découverte de Play Framework Scala
FP - Découverte de Play Framework Scala
 
Drones, Flying robots and Javascript
Drones, Flying robots and JavascriptDrones, Flying robots and Javascript
Drones, Flying robots and Javascript
 
Node js introduction
Node js introductionNode js introduction
Node js introduction
 

Mehr von Provectus

Сергей Моренец: "Gradle. Write once, build everywhere"
Сергей Моренец: "Gradle. Write once, build everywhere"Сергей Моренец: "Gradle. Write once, build everywhere"
Сергей Моренец: "Gradle. Write once, build everywhere"Provectus
 
Василий Захарченко: "Взгляд на queryDsl-sql фреймворк как альтернатива Hiber...
Василий Захарченко: "Взгляд на  queryDsl-sql фреймворк как альтернатива Hiber...Василий Захарченко: "Взгляд на  queryDsl-sql фреймворк как альтернатива Hiber...
Василий Захарченко: "Взгляд на queryDsl-sql фреймворк как альтернатива Hiber...Provectus
 
Get to know provectus
Get to know provectusGet to know provectus
Get to know provectusProvectus
 
Why I want to Kazan
Why I want to KazanWhy I want to Kazan
Why I want to KazanProvectus
 
Артем Тритяк, Lead Front-End developer в Electric Cloud
 Артем Тритяк, Lead Front-End developer в Electric Cloud Артем Тритяк, Lead Front-End developer в Electric Cloud
Артем Тритяк, Lead Front-End developer в Electric CloudProvectus
 
Максим Мазурок “Material Design in Web Applications.”
Максим Мазурок “Material Design in Web Applications.”Максим Мазурок “Material Design in Web Applications.”
Максим Мазурок “Material Design in Web Applications.”Provectus
 
Дима Гадомский (Юскутум) “Можно ли позаимствовать дизайн и функционал так, чт...
Дима Гадомский (Юскутум) “Можно ли позаимствовать дизайн и функционал так, чт...Дима Гадомский (Юскутум) “Можно ли позаимствовать дизайн и функционал так, чт...
Дима Гадомский (Юскутум) “Можно ли позаимствовать дизайн и функционал так, чт...Provectus
 
Михаил Лебединский (Termopal) “Особенности разработки веб и мобильных приложе...
Михаил Лебединский (Termopal) “Особенности разработки веб и мобильных приложе...Михаил Лебединский (Termopal) “Особенности разработки веб и мобильных приложе...
Михаил Лебединский (Termopal) “Особенности разработки веб и мобильных приложе...Provectus
 
Федор Поляков (Looksery) “Face Tracking на мобильных устройствах в режиме реа...
Федор Поляков (Looksery) “Face Tracking на мобильных устройствах в режиме реа...Федор Поляков (Looksery) “Face Tracking на мобильных устройствах в режиме реа...
Федор Поляков (Looksery) “Face Tracking на мобильных устройствах в режиме реа...Provectus
 
Виталий Чмыхун (Provectus) “Как мы автоматизировали мобайл деплоймент.”
Виталий Чмыхун (Provectus) “Как мы автоматизировали мобайл деплоймент.”Виталий Чмыхун (Provectus) “Как мы автоматизировали мобайл деплоймент.”
Виталий Чмыхун (Provectus) “Как мы автоматизировали мобайл деплоймент.”Provectus
 
Артем Крикун (AT Production) “Промо-видео для приложений.”
Артем Крикун (AT Production) “Промо-видео для приложений.”Артем Крикун (AT Production) “Промо-видео для приложений.”
Артем Крикун (AT Production) “Промо-видео для приложений.”Provectus
 
Роман Колос (ComboApp) “Методология использования инструментов аналитики в ма...
Роман Колос (ComboApp) “Методология использования инструментов аналитики в ма...Роман Колос (ComboApp) “Методология использования инструментов аналитики в ма...
Роман Колос (ComboApp) “Методология использования инструментов аналитики в ма...Provectus
 
Галина Дивакова (Clickky) “Вывод мобильных приложений в ТОП.”
Галина Дивакова (Clickky) “Вывод мобильных приложений в ТОП.”Галина Дивакова (Clickky) “Вывод мобильных приложений в ТОП.”
Галина Дивакова (Clickky) “Вывод мобильных приложений в ТОП.”Provectus
 
Евгений Плохой (CapableBits) “Продвижение приложений до и после выхода на рын...
Евгений Плохой (CapableBits) “Продвижение приложений до и после выхода на рын...Евгений Плохой (CapableBits) “Продвижение приложений до и после выхода на рын...
Евгений Плохой (CapableBits) “Продвижение приложений до и после выхода на рын...Provectus
 
Сергей Укустов (Provectus IT): "Несоциалочка на Рельсах"
Сергей Укустов (Provectus IT): "Несоциалочка на Рельсах"Сергей Укустов (Provectus IT): "Несоциалочка на Рельсах"
Сергей Укустов (Provectus IT): "Несоциалочка на Рельсах"Provectus
 
Гатиятов Руслан, технический директор ООО “Дроид Лабс”: “Система управления п...
Гатиятов Руслан, технический директор ООО “Дроид Лабс”: “Система управления п...Гатиятов Руслан, технический директор ООО “Дроид Лабс”: “Система управления п...
Гатиятов Руслан, технический директор ООО “Дроид Лабс”: “Система управления п...Provectus
 
Логотип — Бизнес или творчество
Логотип — Бизнес или творчествоЛоготип — Бизнес или творчество
Логотип — Бизнес или творчествоProvectus
 
ЕСЛИ БЫ УОЛТ ДИСНЕЙ ДЕЛАЛ ИНТЕРФЕЙСЫ. MOTION DESIGN. ПРАКТИКА
ЕСЛИ БЫ УОЛТ ДИСНЕЙ ДЕЛАЛ ИНТЕРФЕЙСЫ. MOTION DESIGN. ПРАКТИКАЕСЛИ БЫ УОЛТ ДИСНЕЙ ДЕЛАЛ ИНТЕРФЕЙСЫ. MOTION DESIGN. ПРАКТИКА
ЕСЛИ БЫ УОЛТ ДИСНЕЙ ДЕЛАЛ ИНТЕРФЕЙСЫ. MOTION DESIGN. ПРАКТИКАProvectus
 
Требования к заказчику. Роль QA в процессе постановки тех. задания
Требования к заказчику. Роль QA в процессе постановки тех. заданияТребования к заказчику. Роль QA в процессе постановки тех. задания
Требования к заказчику. Роль QA в процессе постановки тех. заданияProvectus
 

Mehr von Provectus (20)

Сергей Моренец: "Gradle. Write once, build everywhere"
Сергей Моренец: "Gradle. Write once, build everywhere"Сергей Моренец: "Gradle. Write once, build everywhere"
Сергей Моренец: "Gradle. Write once, build everywhere"
 
Василий Захарченко: "Взгляд на queryDsl-sql фреймворк как альтернатива Hiber...
Василий Захарченко: "Взгляд на  queryDsl-sql фреймворк как альтернатива Hiber...Василий Захарченко: "Взгляд на  queryDsl-sql фреймворк как альтернатива Hiber...
Василий Захарченко: "Взгляд на queryDsl-sql фреймворк как альтернатива Hiber...
 
Get to know provectus
Get to know provectusGet to know provectus
Get to know provectus
 
Why I want to Kazan
Why I want to KazanWhy I want to Kazan
Why I want to Kazan
 
Артем Тритяк, Lead Front-End developer в Electric Cloud
 Артем Тритяк, Lead Front-End developer в Electric Cloud Артем Тритяк, Lead Front-End developer в Electric Cloud
Артем Тритяк, Lead Front-End developer в Electric Cloud
 
Hackathon
HackathonHackathon
Hackathon
 
Максим Мазурок “Material Design in Web Applications.”
Максим Мазурок “Material Design in Web Applications.”Максим Мазурок “Material Design in Web Applications.”
Максим Мазурок “Material Design in Web Applications.”
 
Дима Гадомский (Юскутум) “Можно ли позаимствовать дизайн и функционал так, чт...
Дима Гадомский (Юскутум) “Можно ли позаимствовать дизайн и функционал так, чт...Дима Гадомский (Юскутум) “Можно ли позаимствовать дизайн и функционал так, чт...
Дима Гадомский (Юскутум) “Можно ли позаимствовать дизайн и функционал так, чт...
 
Михаил Лебединский (Termopal) “Особенности разработки веб и мобильных приложе...
Михаил Лебединский (Termopal) “Особенности разработки веб и мобильных приложе...Михаил Лебединский (Termopal) “Особенности разработки веб и мобильных приложе...
Михаил Лебединский (Termopal) “Особенности разработки веб и мобильных приложе...
 
Федор Поляков (Looksery) “Face Tracking на мобильных устройствах в режиме реа...
Федор Поляков (Looksery) “Face Tracking на мобильных устройствах в режиме реа...Федор Поляков (Looksery) “Face Tracking на мобильных устройствах в режиме реа...
Федор Поляков (Looksery) “Face Tracking на мобильных устройствах в режиме реа...
 
Виталий Чмыхун (Provectus) “Как мы автоматизировали мобайл деплоймент.”
Виталий Чмыхун (Provectus) “Как мы автоматизировали мобайл деплоймент.”Виталий Чмыхун (Provectus) “Как мы автоматизировали мобайл деплоймент.”
Виталий Чмыхун (Provectus) “Как мы автоматизировали мобайл деплоймент.”
 
Артем Крикун (AT Production) “Промо-видео для приложений.”
Артем Крикун (AT Production) “Промо-видео для приложений.”Артем Крикун (AT Production) “Промо-видео для приложений.”
Артем Крикун (AT Production) “Промо-видео для приложений.”
 
Роман Колос (ComboApp) “Методология использования инструментов аналитики в ма...
Роман Колос (ComboApp) “Методология использования инструментов аналитики в ма...Роман Колос (ComboApp) “Методология использования инструментов аналитики в ма...
Роман Колос (ComboApp) “Методология использования инструментов аналитики в ма...
 
Галина Дивакова (Clickky) “Вывод мобильных приложений в ТОП.”
Галина Дивакова (Clickky) “Вывод мобильных приложений в ТОП.”Галина Дивакова (Clickky) “Вывод мобильных приложений в ТОП.”
Галина Дивакова (Clickky) “Вывод мобильных приложений в ТОП.”
 
Евгений Плохой (CapableBits) “Продвижение приложений до и после выхода на рын...
Евгений Плохой (CapableBits) “Продвижение приложений до и после выхода на рын...Евгений Плохой (CapableBits) “Продвижение приложений до и после выхода на рын...
Евгений Плохой (CapableBits) “Продвижение приложений до и после выхода на рын...
 
Сергей Укустов (Provectus IT): "Несоциалочка на Рельсах"
Сергей Укустов (Provectus IT): "Несоциалочка на Рельсах"Сергей Укустов (Provectus IT): "Несоциалочка на Рельсах"
Сергей Укустов (Provectus IT): "Несоциалочка на Рельсах"
 
Гатиятов Руслан, технический директор ООО “Дроид Лабс”: “Система управления п...
Гатиятов Руслан, технический директор ООО “Дроид Лабс”: “Система управления п...Гатиятов Руслан, технический директор ООО “Дроид Лабс”: “Система управления п...
Гатиятов Руслан, технический директор ООО “Дроид Лабс”: “Система управления п...
 
Логотип — Бизнес или творчество
Логотип — Бизнес или творчествоЛоготип — Бизнес или творчество
Логотип — Бизнес или творчество
 
ЕСЛИ БЫ УОЛТ ДИСНЕЙ ДЕЛАЛ ИНТЕРФЕЙСЫ. MOTION DESIGN. ПРАКТИКА
ЕСЛИ БЫ УОЛТ ДИСНЕЙ ДЕЛАЛ ИНТЕРФЕЙСЫ. MOTION DESIGN. ПРАКТИКАЕСЛИ БЫ УОЛТ ДИСНЕЙ ДЕЛАЛ ИНТЕРФЕЙСЫ. MOTION DESIGN. ПРАКТИКА
ЕСЛИ БЫ УОЛТ ДИСНЕЙ ДЕЛАЛ ИНТЕРФЕЙСЫ. MOTION DESIGN. ПРАКТИКА
 
Требования к заказчику. Роль QA в процессе постановки тех. задания
Требования к заказчику. Роль QA в процессе постановки тех. заданияТребования к заказчику. Роль QA в процессе постановки тех. задания
Требования к заказчику. Роль QA в процессе постановки тех. задания
 

Kürzlich hochgeladen

BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEOrtus Solutions, Corp
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providermohitmore19
 
Engage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyEngage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyFrank van der Linden
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxbodapatigopi8531
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideChristina Lin
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackVICTOR MAESTRE RAMIREZ
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software DevelopersVinodh Ram
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...gurkirankumar98700
 
Introduction to Decentralized Applications (dApps)
Introduction to Decentralized Applications (dApps)Introduction to Decentralized Applications (dApps)
Introduction to Decentralized Applications (dApps)Intelisync
 
Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - InfographicHr365.us smith
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Modelsaagamshah0812
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptkotipi9215
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...ICS
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...stazi3110
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdfWave PLM
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 
What is Binary Language? Computer Number Systems
What is Binary Language?  Computer Number SystemsWhat is Binary Language?  Computer Number Systems
What is Binary Language? Computer Number SystemsJheuzeDellosa
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationkaushalgiri8080
 

Kürzlich hochgeladen (20)

Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
Engage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyEngage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The Ugly
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptx
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStack
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software Developers
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
 
Exploring iOS App Development: Simplifying the Process
Exploring iOS App Development: Simplifying the ProcessExploring iOS App Development: Simplifying the Process
Exploring iOS App Development: Simplifying the Process
 
Introduction to Decentralized Applications (dApps)
Introduction to Decentralized Applications (dApps)Introduction to Decentralized Applications (dApps)
Introduction to Decentralized Applications (dApps)
 
Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - Infographic
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.ppt
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
What is Binary Language? Computer Number Systems
What is Binary Language?  Computer Number SystemsWhat is Binary Language?  Computer Number Systems
What is Binary Language? Computer Number Systems
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanation
 

Automate WebKit with PhantomJS JavaScript

  • 2. fun-box.ru/ulsk Илья Василевский Разработчик на Ruby и CoffeeScript github.com/vassilevsky
  • 3.
  • 4. 1995 — 2014 (19 лет) Trolltech → Nokia → Digia C++ Android, Embedded Linux, iOS, OS X, QNX / BlackBerry 10, Sailfish OS, VxWorks, Wayland, Windows, Windows CE, X11 (GNU/Linux, FreeBSD, HP-UX, Solaris, AIX) http://qt-project.org
  • 5. Qt Core Qt GUI Qt Widgets Qt QML and JavaScript Qt Quick Qt Quick Controls Qt Quick Layouts Qt Network Qt Multimedia Qt Multimedia Widgets Qt SQL Qt WebKit Qt WebKit Widgets Qt Test
  • 6. #include <QApplication> #include <QMenu> #include <QPixmap> #include <QWidget> #include <qmacfunctions.h> int main(int argc, char **argv) { QApplication app(argc, argv); QWidget widget; widget.show(); // Pixmap <-> CGImage conversion QPixmap pixmap(":qtlogo.png"); CGImageRef cgImage = QtMac::toCGImageRef(pixmap); QPixmap pixmap2 = QtMac::fromCGImageRef(cgImage); return app.exec(); }
  • 7. require 'Qt' require './qrc_systray.rb' require './window.rb' app = Qt::Application.new(ARGV) if !Qt::SystemTrayIcon.isSystemTrayAvailable Qt::MessageBox.critical( nil, Qt::Object.tr("Systray"), Qt::Object.tr("I couldn't detect any system tray on this system.") ) exit 1 end window = Window.new window.show app.exec
  • 8.
  • 9. Qt Core Qt GUI Qt Widgets Qt QML and JavaScript Qt Quick Qt Quick Controls Qt Quick Layouts Qt Network Qt Multimedia Qt Multimedia Widgets Qt SQL Qt WebKit Qt WebKit Widgets Qt Test
  • 10. QWindow QWebView QWidget QWebPage QWidget QWebFrame
  • 11. Ariya Hidayat VP of Engineering at @ShapeSecurity Doctorate degree (with great honor) in Electrical Engineering from University of Paderborn (Germany) Master degree from Institute of Technology Bandung (Indonesia) with an exchange program with Technical University Munich (Germany) Bachelor degree (with honor) from Institute of Technology Bandung (Indonesia) Indonesian, English, German Indonesia → Mountain View, California @AriyaHidayat
  • 12. Qt WebKit JavaScript API Engine Web Server Mongoose Ghost Driver Remote Selenium WebDriver (Wire Protocol) JavaScript Engine
  • 13.
  • 14. $ ls -l phantomjs-1.9.7-linux-x86_64/bin total 74896 -rwxr-xr-x@ 1 vassilevsky staff 38346752 26 янв 2014 phantomjs X11 (v1.5+) freetype fontconfig
  • 15. // goodbye_world.js console.log('Goodbye, cruel world!'); phantom.exit(); $ phantomjs goodbye_world.js Goodbye, cruel world!
  • 16. // screenshot.js var page = require('webpage').create(); page.open('http://www.therestartpage.com', function(status) { if (status == 'success') { page.render('restart.png'); } phantom.exit(); }); $ phantomjs screenshot.js $ open restart.png
  • 17. // stealing.js var page = require('webpage').create(); page.open('http://victim.com', function(status) { if (status == 'success') { var usefulValue = page.evaluate(function() { return document.getElementById('secretId').textContent; // runs on page }); console.log('Stolen: ' + usefulValue); } phantom.exit(); }); $ phantomjs stealing.js Stolen: uid123456789
  • 18. Qt WebKit JavaScript API Engine JavaScript Engine function() { return document.getElementById('secretId').textContent; } var page = require('webpage').create(); page.open('http://victim.com', function(status) { if (status == 'success') { var usefulValue = page.evaluate( ); console.log('Stolen: ' + usefulValue); } phantom.exit(); }); Qt WebKit
  • 19. var page = require('webpage').create(); doSomeWork = function(param1, param2, param3) { doSomethingWith(param1); // runs on page useSomehow(param2); // runs on page disregard(param3); // runs on page } page.open('http://example.com', function() { page.evaluate(doSomeWork, value1, value2, value3); phantom.exit(); });
  • 20. var page = require('webpage').create(); Qt WebKit JavaScript API Engine page.open('http://example.com', function() { page.evaluate(doSomeWork, value1, value2, value3); phantom.exit(); }); JavaScript Engine function(param1, param2, param3) { doSomethingWith(param1); useSomehow(param2); disregard(param3); } Qt WebKit
  • 21. var page = require('webpage').create(); Qt WebKit JavaScript API Engine page.open('http://example.com', function() { page.evaluate(doSomeWork, value1, value2, value3); phantom.exit(); }); JavaScript Engine function(param1, param2, param3) { doSomethingWith(param1); useSomehow(param2); disregard(param3); } Qt WebKit J S O N
  • 22. PROPERTIES canGoBack canGoForward clipRect content cookies customHeaders event focusedFrameName frameContent frameName framePlainText frameTitle frameUrl framesCount framesName libraryPath navigationLocked offlineStoragePath offlineStorageQuota ownsPages pages pagesWindowName paperSize plainText scrollPosition settings title url viewportSize windowName zoomFactor METHODS addCookie childFramesCount childFramesName clearCookies close currentFrameName deleteCookie evaluate evaluateAsync evaluateJavaScript getPage go goBack goForward includeJs injectJs open openUrl release reload render renderBase64 sendEvent setContent stop switchToChildFrame switchToFocusedFrame switchToFrame switchToMainFrame switchToParentFrame uploadFile HANDLERS onAlert onCallback onClosing onConfirm onConsoleMessage onError onFilePicker onInitialized onLoadFinished onLoadStarted onNavigationRequested onPageCreated onPrompt onResourceError onResourceReceived onResourceRequested onResourceTimeout onUrlChanged
  • 23. require 'childprocess' def phantomjs(script, timeout) output, input = IO.pipe phantomjs = ChildProcess.new("/usr/local/bin/phantomjs", "--disk-cache=true", script) phantomjs.io.stdout = input phantomjs.io.stderr = input Timeout.timeout(timeout) do phantomjs.start input.close logger.info("Attaching to PhantomJS's STDOUT and STDERR...") output.each_line{|line| logger.info("[PhantomJS] #{line}") } end rescue Timeout::Error logger.warn("PhantomJS is running longer than expected. Shutting it down...") phantomjs.stop end
  • 24. page = require('webpage').create() page.viewportSize = {width, height} prepareTrack = (i) -> track = tracks[i] page.evaluate(drawTrack, track.bounds, track.locations) setTimeout(renderTrack, MAP_LOADING_TIME, i) renderTrack = (i) -> track = tracks[i] page.render(track.imagePath) if i + 1 == tracks.length phantom.exit() else prepareTrack(i + 1) drawTrack = (bounds, locations) -> setBounds(bounds) drawTrackLine(locations) page.open(hostPage) setTimeout(renderTrack, MAP_LOADING_TIME, 0)
  • 25. !!! 5 %html %head %meta{charset: "utf-8"} :css #map_container { position: absolute; left: 0; right: 0; top: 0; bottom: 0 } %body #map_container %script{src: "http://api-maps.yandex.ru/2.1/?lang=ru_RU"} :coffeescript @map = null ymaps.ready => @map = new ymaps.Map 'map_container' @setBounds = (bounds) -> @map.setBounds(bounds) @drawTrackLine = (locations) -> points = (location.point for location in locations) @map.geoObjects.add(new ymaps.Polyline(points))
  • 26. RSpec Cucumber MiniTest Capybara Poltergeist PhantomJS
  • 27. require 'capybara/poltergeist' Capybara.javascript_driver = :poltergeist Capybara.methods += page.evaluate_script page.execute_script page.within_frame page.within_window page.status_code page.response_headers page.save_screenshot page.driver.render_base64(format, options) page.driver.scroll_to(left, top) page.driver.basic_authorize(user, password) element.native.send_keys(*keys)
  • 28. JS API class Poltergeist.Connection constructor: (@owner, @port) -> @socket = new WebSocket "ws://127.0.0.1:#{@port}/" @socket.onmessage = this.commandReceived @socket.onclose = -> phantom.exit() WebKit module Capybara::Poltergeist class Server attr_reader :socket, :fixed_port, :timeout def start @socket = WebSocketServer.new(fixed_port, timeout) end def send(message) @socket.send(message) or raise DeadClient.new(message) end end end
  • 29. class Poltergeist.WebPage onErrorNative: (message, stack) -> stackString = message stack.forEach (frame) -> stackString += "n" stackString += " at #{frame.file}:#{frame.line}" stackString += " in #{frame.function}" if frame.function && frame.function != '' @errors.push(message: message, stack: stackString) class Poltergeist.Browser sendResponse: (response) -> errors = @currentPage.errors @currentPage.clearErrors() if errors.length > 0 && @js_errors @owner.sendError(new Poltergeist.JavascriptError(errors)) else @owner.sendResponse(response)
  • 30. Casper.js Chutzpah Ghostbuster GhostDriver Lotte Poltergeist Capybara pjscrape WebSpecter conjure PhantomJS Google Charts capturejs pageres phantomjs-screenshots screenshot-app screenshot-as-a-service screenshot-service screenshot screenshot-webservice pyshotx node-webshot pageres django-screamshot PHP Screen grabshot basset Compass Magick Confess GhostStory Grover Grunt Guard PhantomJS phridge phantomjs-node node-phantom phantom-proxy phantomas PhantomCSS PhantomFlow phantomjs-maven-plugin grunt-lib-phantomjs grunt-contrib-qunit PhantomLint PhantomXHR shortcut.io Slippy SpookyJS Yeoman