SlideShare a Scribd company logo
Offline applications
Jérôme Van Der Linden - 28/10/2016
jeromevdl @jeromevdl
Jérôme
Van Der
Linden
@OCTOSuisse @OCTOTechnology
AT AW AD
AnyWhere ?
AnyWhere ?
AnyWhere ?
Offline applications
5 questions to ask before creating an offline application
Question #1
What can I do offline ?
READ
CREATE
UPDATE
UPDATE, SURE ?
DELETE
Question #2
How much
data is it and
where can i store it ?
Few kilobytes…
Few
megabytes
Hundred of
megabytes
(maybe few giga)
Several gigabytes (or many more) ?
Storage Solutions
Application Cache
<html manifest="/cache.manifest">
...
</html>
CACHE MANIFEST
# Explicitly cached
CACHE:
/favicon.ico
page.html
stylesheet.css
images/logo.png
scripts/main.js
http://cdn.example.com/scripts/main.js
# Resources that require the user to be online.
NETWORK:
*
# static.html will be served if main.py is inaccessible
# offline.jpg will be served in place of all images in images/large/
FALLBACK:
/main.py /static.html
images/large/ images/offline.jpg
cache.manifest
index.html
http://www.html5rocks.com/en/tutorials/appcache/beginner/
http://alistapart.com/article/application-cache-is-a-douchebag
Application Cache
<html manifest="/cache.manifest">
...
</html>
CACHE MANIFEST
# Explicitly cached
CACHE:
/favicon.ico
page.html
stylesheet.css
images/logo.png
scripts/main.js
http://cdn.example.com/scripts/main.js
# Resources that require the user to be online.
NETWORK:
*
# static.html will be served if main.py is inaccessible
# offline.jpg will be served in place of all images in images/large/
FALLBACK:
/main.py /static.html
images/large/ images/offline.jpg
cache.manifest
index.html
http://www.html5rocks.com/en/tutorials/appcache/beginner/
http://alistapart.com/article/application-cache-is-a-douchebag
Service Workers (Cache API)
this.addEventListener('install', function(event) {
event.waitUntil(
caches.open('v1').then(function(cache) {
return cache.addAll([
'/sw-test/',
'/sw-test/index.html',
'/sw-test/style.css',
'/sw-test/app.js',
'/sw-test/star-wars-logo.jpg',
'/sw-test/gallery/',
'/sw-test/gallery/myLittleVader.jpg'
]);
})
);
});
2. Installation of Service Worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register(‘/sw.js')
.then(function(registration) {
// Registration was successful
}).catch(function(err) {
// registration failed :(
});
}
1. Registration of Service Worker
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request)
.then(function(response) {
// Cache hit - return response
if (response) {
return response;
}
var fetchRequest = event.request.clone();
return fetch(fetchRequest).then(
function(response) {
if (!response || response.status !== 200) {
return response;
}
var responseToCache = response.clone();
caches.open('v1').then(function(cache) {
cache.put(event.request, responseToCache);
});
return response;
}
);
})
);
});
3 . Fetch and Cache requests
Service Workers (Cache API)
44+40+
https://jakearchibald.github.io/isserviceworkerready/
27+
Future of upcoming web development ?
Web storage (local / session)
if (('localStorage' in window) && window['localStorage'] !== null) {
localStorage.setItem(key, value);
}
if (key in localStorage) {
var value = localStorage.getItem(key);
}
1. Store data
2. Retrieve data
if (key in localStorage) {
localStorage.removeItem(key);
}
localStorage.clear();
3. Remove data / clear
Web SQL
var db = openDatabase('mydb', '1.0', 'Test DB', 2 * 1024 * 1024);
var msg;
db.transaction(function (tx) {
tx.executeSql('CREATE TABLE IF NOT EXISTS LOGS (id unique, log)');
tx.executeSql('INSERT INTO LOGS (id, log) VALUES (1, "foobar")');
tx.executeSql('INSERT INTO LOGS (id, log) VALUES (2, "logmsg")');
msg = '<p>Log message created and row inserted.</p>';
document.querySelector('#status').innerHTML = msg;
});
db.transaction(function (tx) {
tx.executeSql('SELECT * FROM LOGS', [], function (tx, results) {
var len = results.rows.length, i;
msg = "<p>Found rows: " + len + "</p>";
document.querySelector('#status').innerHTML += msg;
for (i = 0; i < len; i++) {
msg = "<p><b>" + results.rows.item(i).log + "</b></p>";
document.querySelector('#status').innerHTML += msg;
}
}, null);
});
var db = openDatabase('mydb', '1.0', 'Test DB', 2 * 1024 * 1024);
var msg;
db.transaction(function (tx) {
tx.executeSql('CREATE TABLE IF NOT EXISTS LOGS (id unique, log)');
tx.executeSql('INSERT INTO LOGS (id, log) VALUES (1, "foobar")');
tx.executeSql('INSERT INTO LOGS (id, log) VALUES (2, "logmsg")');
msg = '<p>Log message created and row inserted.</p>';
document.querySelector('#status').innerHTML = msg;
});
db.transaction(function (tx) {
tx.executeSql('SELECT * FROM LOGS', [], function (tx, results) {
var len = results.rows.length, i;
msg = "<p>Found rows: " + len + "</p>";
document.querySelector('#status').innerHTML += msg;
for (i = 0; i < len; i++) {
msg = "<p><b>" + results.rows.item(i).log + "</b></p>";
document.querySelector('#status').innerHTML += msg;
}
}, null);
});
Web SQL
function onInitFs(fs) {
fs.root.getFile('log.txt', {}, function(fileEntry) {
// Get a File object representing the file,
// then use FileReader to read its contents.
fileEntry.file(function(file) {
var reader = new FileReader();
reader.onloadend = function(e) {
var txtArea = document.createElement('textarea');
txtArea.value = this.result;
document.body.appendChild(txtArea);
};
reader.readAsText(file);
}, errorHandler);
}, errorHandler);
}
window.requestFileSystem(window.TEMPORARY, 1024*1024, onInitFs, errorHandler);
FileSystem API
function onInitFs(fs) {
fs.root.getFile('log.txt', {}, function(fileEntry) {
// Get a File object representing the file,
// then use FileReader to read its contents.
fileEntry.file(function(file) {
var reader = new FileReader();
reader.onloadend = function(e) {
var txtArea = document.createElement('textarea');
txtArea.value = this.result;
document.body.appendChild(txtArea);
};
reader.readAsText(file);
}, errorHandler);
}, errorHandler);
}
window.requestFileSystem(window.TEMPORARY, 1024*1024, onInitFs, errorHandler);
FileSystem API
IndexedDB
var db;
function openDb() {
var req = indexedDB.open(DB_NAME, DB_VERSION);
req.onsuccess = function (evt) {
db = this.result;
};
req.onerror = function (evt) {
console.error("openDb:", evt.target.errorCode);
};
req.onupgradeneeded = function (evt) {
var store = evt.currentTarget.result.createObjectStore(
DB_STORE_NAME, { keyPath: 'id', autoIncrement: true });
store.createIndex('title', 'title', { unique: false });
store.createIndex('isbn', 'isbn', { unique: true });
};
}
1. Open Database
IndexedDB
var tx = db.transaction(DB_STORE_NAME, 'readwrite');
var store = tx.objectStore(DB_STORE_NAME);
var obj = { isbn: ‘0062316095’, title: ‘Sapiens: A Brief History of Humankind’, year: 2015 };
var req;
try {
req = store.add(obj);
} catch (e) {
// ...
}
req.onsuccess = function (evt) {
console.log("Insertion in DB successful");
// ...
};
req.onerror = function() {
console.error("Insert error", this.error);
// ...
};
2. Insert data
IndexedDB
var var tx = db.transaction(DB_STORE_NAME, 'readonly');
var store = tx.objectStore(DB_STORE_NAME);
var req = store.openCursor();
req.onsuccess = function (evt) {
var cursor = evt.target.result;
if (cursor) {
alert(cursor.value.title);
cursor.continue();
}
};
3. Retrieve data (cursor)
var var tx = db.transaction(DB_STORE_NAME, 'readonly');
var store = tx.objectStore(DB_STORE_NAME);
var req = store.get(42);
req.onsuccess = function (evt) {
var object = evt.target.result;
alert(object.title);
};
3. Retrieve data (one item)
IndexedDB
var var tx = db.transaction(DB_STORE_NAME, 'readonly');
var store = tx.objectStore(DB_STORE_NAME);
var index = store.index(‘title’);
var req = index.get(‘Sapiens: A Brief History of Humankind’);
req.onsuccess = function (evt) {
var result = evt.target.result;
if (result) {
// ...
}
};
3. Retrieve data (index)
IndexedDB wrappers
• db.js
• joqular
• TaffyDB
• localForage
• IDBWrapper
• YDN
IndexedDB
16+24+ 15+ 10+
8+ 4.4+
Google Gears
HTML 5 Storage Limitations
Quotas
50 %
33 %
20
%
20
%
Free disk space
Space browser can use
Space application (domain) can use
Quotas
Users
https://storage.spec.whatwg.org/
https://developers.google.com/web/updates/2016/06/persistent-storage
if (navigator.storage && navigator.storage.persist)
navigator.storage.persist().then(granted => {
if (granted)
alert("Storage will not be cleared except by explicit user action");
else
alert("Storage may be cleared by the UA under storage pressure.");
});
if (navigator.storage && navigator.storage.persist)
navigator.storage.persisted().then(persistent=>{
if (persistent)
console.log("Storage will not be cleared except by explicit user action");
else
console.log("Storage may be cleared by the UA under storage pressure.");
});
Persistent storage
55+
Question #3
How to handle offline-online
synchronization ?
CONFLICTS
Basic Resolution : based on timestamp
« Last version win »
Optimistic lock
Source : Patterns of Enterprise Application Architecture - Martin Fowler
System transaction
boundaries
Business transaction
boundaries
Pessimistic lock
Source : Patterns of Enterprise Application Architecture - Martin Fowler
System transaction
boundaries
Business transaction
boundaries
Theory is when you
know everything but
nothing works.
Practice is when
everything works but no
one knows why.
In our lab, theory and
practice are combined:
nothing works and no
one knows why!
kinto.js
var db = new Kinto();
var todos = db.collection(‘todos’);
todos.create({
title: ‘buy some bread’),
finished : false
})
.then(function(res){…})
.catch(function(err){…})
todos.list().then(function(res) {
renderTodos(res.data);
})
.catch(function(err) {…});
todos.update(todo)
.then(function(res) {…})
.catch(function(err) {…});
Create, Read, Update, Delete
using IndexedDB
todos.delete(todo.id)
.then(function(res) {…})
.catch(function(err) {…});
var syncOptions = {
remote: "https://host/kintoapi",
headers: {Authorization: …}
};
todos.sync(syncOptions)
.then(function(res){…})
.catch(function(err){…})
Synchronize with remote
kinto.js
var syncOptions = {
remote: "https://host/kintoapi",
headers: {Authorization: …}
};
todos.sync(syncOptions)
.then(function(res){…})
.catch(function(err){…})
{
"ok": true,
"lastModified": 1434617181458,
"errors": [],
"created": [], // created locally
"updated": [], // updated locally
"deleted": [], // deleted locally
"published": [ // published remotely
{
"last_modified": 1434617181458,
"done": false,
"id": "7ca54d89-479a-4201-8494",
"title": "buy some bread",
"_status": "synced"
}
],
"conflicts": [],
"skipped": []
}
{
"ok": true,
"lastModified": 1434617181458,
"errors": [],
"created": [], // created locally
"updated": [], // updated locally
"deleted": [], // deleted locally
"published": [], // published remotely
"conflicts": [
{
"type": "incoming", // or outgoing
"local": {
"last_modified": 1434619634577,
"done": true,
"id": "7ca54d89-479a-4201-8494",
"title": "buy some bread",
"_status": "updated"
},
"remote": {
"last_modified": 1434619745465,
"done": false,
"id": "7ca54d89-479a-4201-8494",
"title": "buy some bread and wine"
}
}
],
"skipped": []
}
OK Conflicts
kinto.js
{
"ok": true,
"lastModified": 1434617181458,
"errors": [],
"created": [], // created locally
"updated": [], // updated locally
"deleted": [], // deleted locally
"published": [], // published remotely
"conflicts": [
{
"type": "incoming", // or outgoing
"local": {
"last_modified": 1434619634577,
"done": true,
"id": "7ca54d89-479a-4201-8494",
"title": "buy some bread",
"_status": "updated"
},
"remote": {
"last_modified": 1434619745465,
"done": false,
"id": "7ca54d89-479a-4201-8494",
"title": "buy some bread and wine"
}
}
],
"skipped": []
}
Conflicts
todos.sync(syncOptions)
.then(function(res){
if (res.conflicts.length) {
return handleConflicts(res.conflicts);
}
})
.catch(function(err){…});
function handleConflicts(conflicts) {
return Promise.all(conflicts.map(function(conflict) {
return todos.resolve(conflict, conflict.remote);
}))
.then(function() {
todos.sync(syncOptions);
});
}
Choose your way to solve the conflict:
• Choose remote or local version
• Choose according last_modified
• Pick the good fields
(need to provide 3-way-merge screen)
var db = new PouchDB(‘todos’);
db.post({ // can use ‘put’ with an _id
title: ‘buy some bread’),
finished : false
})
.then(function(res){…})
.catch(function(err){…})
db.get(‘mysuperid’).then(function(todo) {
// return an object with auto
// generated ‘_rev’ field
// update the full doc (with _rev)
todo.finished = true;
db.put(todo);
// remove the full doc (with _rev)
db.remove(todo);
})
.catch(function(err) {…});
Create, Read, Update, Delete
using IndexedDB
var localDB = new PouchDB(‘todos’);
// Remote CouchDB
var remoteDB
= new PouchDB(‘http://host/todos’);
localDB.replicate.to(remoteDB);
localDB.replicate.from(remoteDB);
// or
localDB.sync(remoteDB, {
live: true,
retry: true
}).on('change', function (change) {
// something changed!
}).on('paused', function (info) {
// replication was paused,
// usually because of a lost connection
}).on('active', function (info) {
// replication was resumed
}).on('error', function (err) {
// unhandled error (shouldn't happen)
});
Synchronize with remote
var myDoc = {
_id: 'someid',
_rev: '1-somerev'
};
db.put(myDoc).then(function () {
// success
}).catch(function (err) {
if (err.name === 'conflict') {
// conflict! Handle it!
} else {
// some other error
}
});
Immediate conflict : error 409
_rev: ‘1-revabc’ _rev: ‘1-revabc’
_rev: ‘2-revcde’ _rev: ‘2-revjkl’
_rev: ‘1-revabc’
_rev: ‘2-revjkl’
_rev: ‘2-revcde’
db.get('someid', {conflicts: true})
.then(function (doc) {
// do something with the object
}).catch(function (err) {
// handle any errors
});
{
"_id": "someid",
"_rev": "2-revjkl",
"_conflicts": ["2-revcde"]
}
==>
Eventual conflict
==> remove
the bad one,
merge, …
it’s up to you
Question #4
How to communicate with users ?
Inform the user …
Save Save locally
Send Send when online
… or not
Outbox (1)Send
Do no display errors !
Do not load indefinitelyyyyyyyyyy
Do not display
an empty screen
Handling conflicts
Question #5
Do I really need offline ?
(2001) (2009) (2020)
« You are not on a f*cking plane and if
you are, it doesn’t matter »
- David Heinemeier Hansson (2007)
https://signalvnoise.com/posts/347-youre-not-on-a-fucking-plane-and-if-you-are-it-doesnt-matter
ATAWAD
Unfortunately
NOT
AnyWhere !
User Experience
matters !
Thank you
Bibliography
• http://diveintohtml5.info/offline.html
• https://github.com/pazguille/offline-first
• https://jakearchibald.com/2014/offline-cookbook/
• https://github.com/offlinefirst/research/blob/master/links.md
• http://www.html5rocks.com/en/tutorials/offline/whats-offline/
• http://offlinefirst.org/
• http://fr.slideshare.net/MarcelKalveram/offline-first-the-painless-way
• https://developer.mozilla.org/en-US/Apps/Fundamentals/Offline
• https://uxdesign.cc/offline-93c2f8396124#.97njk8o5m
• https://www.ibm.com/developerworks/community/blogs/worklight/entry/
offline_patterns?lang=en
• http://apress.jensimmons.com/v5/pro-html5-programming/ch12.html
• http://alistapart.com/article/offline-first
• http://alistapart.com/article/application-cache-is-a-douchebag
• https://logbook.hanno.co/offline-first-matters-developers-know/
• https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/
Using_Service_Workers
• https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API
• https://developer.chrome.com/apps/offline_storage
• http://martinfowler.com/eaaCatalog/index.html
• http://offlinestat.es/
• http://caniuse.com/
Jake Archibald

More Related Content

What's hot

Advanced Hibernate Notes
Advanced Hibernate NotesAdvanced Hibernate Notes
Advanced Hibernate NotesKaniska Mandal
 
Data access 2.0? Please welcome: Spring Data!
Data access 2.0? Please welcome: Spring Data!Data access 2.0? Please welcome: Spring Data!
Data access 2.0? Please welcome: Spring Data!
Oliver Gierke
 
Indexing & Query Optimization
Indexing & Query OptimizationIndexing & Query Optimization
Indexing & Query OptimizationMongoDB
 
Symfony2 from the Trenches
Symfony2 from the TrenchesSymfony2 from the Trenches
Symfony2 from the Trenches
Jonathan Wage
 
Java Persistence Frameworks for MongoDB
Java Persistence Frameworks for MongoDBJava Persistence Frameworks for MongoDB
Java Persistence Frameworks for MongoDBMongoDB
 
Symfony Day 2010 Doctrine MongoDB ODM
Symfony Day 2010 Doctrine MongoDB ODMSymfony Day 2010 Doctrine MongoDB ODM
Symfony Day 2010 Doctrine MongoDB ODMJonathan Wage
 
Doctrine MongoDB Object Document Mapper
Doctrine MongoDB Object Document MapperDoctrine MongoDB Object Document Mapper
Doctrine MongoDB Object Document Mapper
Jonathan Wage
 
Sequelize
SequelizeSequelize
Sequelize
Tarek Raihan
 
Ajax chap 4
Ajax chap 4Ajax chap 4
Ajax chap 4
Mukesh Tekwani
 
Indexing and Query Optimization
Indexing and Query OptimizationIndexing and Query Optimization
Indexing and Query OptimizationMongoDB
 
MongoDB + Java - Everything you need to know
MongoDB + Java - Everything you need to know MongoDB + Java - Everything you need to know
MongoDB + Java - Everything you need to know
Norberto Leite
 
MongoDB Performance Tuning
MongoDB Performance TuningMongoDB Performance Tuning
MongoDB Performance Tuning
Puneet Behl
 
Persistences
PersistencesPersistences
Persistences
Training Guide
 
MySQL flexible schema and JSON for Internet of Things
MySQL flexible schema and JSON for Internet of ThingsMySQL flexible schema and JSON for Internet of Things
MySQL flexible schema and JSON for Internet of Things
Alexander Rubin
 
Ajax chap 5
Ajax chap 5Ajax chap 5
Ajax chap 5
Mukesh Tekwani
 
Mongo db for c# developers
Mongo db for c# developersMongo db for c# developers
Mongo db for c# developers
Simon Elliston Ball
 
Saving Data
Saving DataSaving Data
Saving Data
SV.CO
 
Android Data Persistence
Android Data PersistenceAndroid Data Persistence
Android Data Persistence
Romain Rochegude
 

What's hot (20)

Advanced Hibernate Notes
Advanced Hibernate NotesAdvanced Hibernate Notes
Advanced Hibernate Notes
 
Data access 2.0? Please welcome: Spring Data!
Data access 2.0? Please welcome: Spring Data!Data access 2.0? Please welcome: Spring Data!
Data access 2.0? Please welcome: Spring Data!
 
Indexing & Query Optimization
Indexing & Query OptimizationIndexing & Query Optimization
Indexing & Query Optimization
 
Symfony2 from the Trenches
Symfony2 from the TrenchesSymfony2 from the Trenches
Symfony2 from the Trenches
 
Java Persistence Frameworks for MongoDB
Java Persistence Frameworks for MongoDBJava Persistence Frameworks for MongoDB
Java Persistence Frameworks for MongoDB
 
Symfony Day 2010 Doctrine MongoDB ODM
Symfony Day 2010 Doctrine MongoDB ODMSymfony Day 2010 Doctrine MongoDB ODM
Symfony Day 2010 Doctrine MongoDB ODM
 
Doctrine MongoDB Object Document Mapper
Doctrine MongoDB Object Document MapperDoctrine MongoDB Object Document Mapper
Doctrine MongoDB Object Document Mapper
 
Sequelize
SequelizeSequelize
Sequelize
 
Ajax chap 4
Ajax chap 4Ajax chap 4
Ajax chap 4
 
Indexing and Query Optimization
Indexing and Query OptimizationIndexing and Query Optimization
Indexing and Query Optimization
 
MongoDB + Java - Everything you need to know
MongoDB + Java - Everything you need to know MongoDB + Java - Everything you need to know
MongoDB + Java - Everything you need to know
 
Mongo db for C# Developers
Mongo db for C# DevelopersMongo db for C# Developers
Mongo db for C# Developers
 
MongoDB Performance Tuning
MongoDB Performance TuningMongoDB Performance Tuning
MongoDB Performance Tuning
 
Persistences
PersistencesPersistences
Persistences
 
MySQL flexible schema and JSON for Internet of Things
MySQL flexible schema and JSON for Internet of ThingsMySQL flexible schema and JSON for Internet of Things
MySQL flexible schema and JSON for Internet of Things
 
Ajax chap 5
Ajax chap 5Ajax chap 5
Ajax chap 5
 
Mongo db for c# developers
Mongo db for c# developersMongo db for c# developers
Mongo db for c# developers
 
Saving Data
Saving DataSaving Data
Saving Data
 
Android Data Persistence
Android Data PersistenceAndroid Data Persistence
Android Data Persistence
 
greenDAO
greenDAOgreenDAO
greenDAO
 

Viewers also liked

Home project sc
Home project scHome project sc
Home project sc
sarah Colsenet
 
324.ayuda a las personas de la tercera edad
324.ayuda a las personas de la tercera edad324.ayuda a las personas de la tercera edad
324.ayuda a las personas de la tercera edaddec-admin
 
Bert Savoie Resume
Bert Savoie ResumeBert Savoie Resume
Bert Savoie ResumeBert Savoie
 
Escuela amado nervo
Escuela amado nervoEscuela amado nervo
Escuela amado nervodec-admin
 
Garrtech investment has the answer to hollywood real estate
Garrtech investment has the answer to hollywood real estateGarrtech investment has the answer to hollywood real estate
Garrtech investment has the answer to hollywood real estate
Brandon Jones
 
96. alimentacion sustentable
96. alimentacion sustentable96. alimentacion sustentable
96. alimentacion sustentabledec-admin
 
Just one ... Myles Sullivan's paintings
Just one ... Myles Sullivan's paintingsJust one ... Myles Sullivan's paintings
Just one ... Myles Sullivan's paintings
Makala (D)
 
Volume 24.2
Volume 24.2Volume 24.2
Volume 24.2
aderm
 
The housing market.irkutsk.02.11.2016
The housing market.irkutsk.02.11.2016The housing market.irkutsk.02.11.2016
The housing market.irkutsk.02.11.2016
Татьяна Галущенко
 
Learn to Drift
Learn to DriftLearn to Drift
Learn to Drift
drift101
 
Habilidades del Pensamiento en las TIC
Habilidades del Pensamiento en las TICHabilidades del Pensamiento en las TIC
Habilidades del Pensamiento en las TIC
Liliana Angel
 
220.todos contra el bullyng
220.todos contra el bullyng220.todos contra el bullyng
220.todos contra el bullyngdec-admin
 
Atias Parasitología Médica Cap 3 - El Hospedero
Atias Parasitología Médica Cap 3 - El HospederoAtias Parasitología Médica Cap 3 - El Hospedero
Atias Parasitología Médica Cap 3 - El Hospedero
neljirsh
 
Creencias religiosas en los jóvenes y niños
Creencias religiosas en los jóvenes y niñosCreencias religiosas en los jóvenes y niños
Creencias religiosas en los jóvenes y niños
Ronald'o Cardenas
 
Bases de una educación para la paz.
Bases de una educación para la paz.Bases de una educación para la paz.
Bases de una educación para la paz.
felipe0410
 
Aire Libre
Aire LibreAire Libre
Presentation NWA BIZ Con Event
Presentation NWA BIZ Con EventPresentation NWA BIZ Con Event
Presentation NWA BIZ Con Event
Tom Gazaway
 
163.regio activo
163.regio activo163.regio activo
163.regio activodec-admin
 

Viewers also liked (18)

Home project sc
Home project scHome project sc
Home project sc
 
324.ayuda a las personas de la tercera edad
324.ayuda a las personas de la tercera edad324.ayuda a las personas de la tercera edad
324.ayuda a las personas de la tercera edad
 
Bert Savoie Resume
Bert Savoie ResumeBert Savoie Resume
Bert Savoie Resume
 
Escuela amado nervo
Escuela amado nervoEscuela amado nervo
Escuela amado nervo
 
Garrtech investment has the answer to hollywood real estate
Garrtech investment has the answer to hollywood real estateGarrtech investment has the answer to hollywood real estate
Garrtech investment has the answer to hollywood real estate
 
96. alimentacion sustentable
96. alimentacion sustentable96. alimentacion sustentable
96. alimentacion sustentable
 
Just one ... Myles Sullivan's paintings
Just one ... Myles Sullivan's paintingsJust one ... Myles Sullivan's paintings
Just one ... Myles Sullivan's paintings
 
Volume 24.2
Volume 24.2Volume 24.2
Volume 24.2
 
The housing market.irkutsk.02.11.2016
The housing market.irkutsk.02.11.2016The housing market.irkutsk.02.11.2016
The housing market.irkutsk.02.11.2016
 
Learn to Drift
Learn to DriftLearn to Drift
Learn to Drift
 
Habilidades del Pensamiento en las TIC
Habilidades del Pensamiento en las TICHabilidades del Pensamiento en las TIC
Habilidades del Pensamiento en las TIC
 
220.todos contra el bullyng
220.todos contra el bullyng220.todos contra el bullyng
220.todos contra el bullyng
 
Atias Parasitología Médica Cap 3 - El Hospedero
Atias Parasitología Médica Cap 3 - El HospederoAtias Parasitología Médica Cap 3 - El Hospedero
Atias Parasitología Médica Cap 3 - El Hospedero
 
Creencias religiosas en los jóvenes y niños
Creencias religiosas en los jóvenes y niñosCreencias religiosas en los jóvenes y niños
Creencias religiosas en los jóvenes y niños
 
Bases de una educación para la paz.
Bases de una educación para la paz.Bases de una educación para la paz.
Bases de una educación para la paz.
 
Aire Libre
Aire LibreAire Libre
Aire Libre
 
Presentation NWA BIZ Con Event
Presentation NWA BIZ Con EventPresentation NWA BIZ Con Event
Presentation NWA BIZ Con Event
 
163.regio activo
163.regio activo163.regio activo
163.regio activo
 

Similar to Softshake - Offline applications

Local data storage for mobile apps
Local data storage for mobile appsLocal data storage for mobile apps
Local data storage for mobile apps
Ivano Malavolta
 
Local Storage
Local StorageLocal Storage
Local Storage
Ivano Malavolta
 
React Native Course - Data Storage . pdf
React Native Course - Data Storage . pdfReact Native Course - Data Storage . pdf
React Native Course - Data Storage . pdf
AlvianZachryFaturrah
 
The Magic Revealed: Four Real-World Examples of Using the Client Object Model...
The Magic Revealed: Four Real-World Examples of Using the Client Object Model...The Magic Revealed: Four Real-World Examples of Using the Client Object Model...
The Magic Revealed: Four Real-World Examples of Using the Client Object Model...
SPTechCon
 
Taking Web Apps Offline
Taking Web Apps OfflineTaking Web Apps Offline
Taking Web Apps OfflinePedro Morais
 
Local storage in Web apps
Local storage in Web appsLocal storage in Web apps
Local storage in Web apps
Ivano Malavolta
 
Developing your first application using FI-WARE
Developing your first application using FI-WAREDeveloping your first application using FI-WARE
Developing your first application using FI-WAREFermin Galan
 
Boost Your Environment With XMLDB - UKOUG 2008 - Marco Gralike
Boost Your Environment With XMLDB - UKOUG 2008 - Marco GralikeBoost Your Environment With XMLDB - UKOUG 2008 - Marco Gralike
Boost Your Environment With XMLDB - UKOUG 2008 - Marco GralikeMarco Gralike
 
Fun Teaching MongoDB New Tricks
Fun Teaching MongoDB New TricksFun Teaching MongoDB New Tricks
Fun Teaching MongoDB New Tricks
MongoDB
 
Intro to HTML5 Web Storage
Intro to HTML5 Web StorageIntro to HTML5 Web Storage
Intro to HTML5 Web Storagedylanks
 
Tornadoweb
TornadowebTornadoweb
Tornadoweb
Osman Yuksel
 
Hidden pearls for High-Performance-Persistence
Hidden pearls for High-Performance-PersistenceHidden pearls for High-Performance-Persistence
Hidden pearls for High-Performance-Persistence
Sven Ruppert
 
Jquery dojo slides
Jquery dojo slidesJquery dojo slides
Jquery dojo slideshelenmga
 
Global objects in Node.pdf
Global objects in Node.pdfGlobal objects in Node.pdf
Global objects in Node.pdf
SudhanshiBakre1
 
Cloudbase.io MoSync Reload Course
Cloudbase.io MoSync Reload CourseCloudbase.io MoSync Reload Course
Cloudbase.io MoSync Reload Course
cloudbase.io
 
Saving Time And Effort With QuickBase Api - Sergio Haro
Saving Time And Effort With QuickBase Api - Sergio HaroSaving Time And Effort With QuickBase Api - Sergio Haro
Saving Time And Effort With QuickBase Api - Sergio Haro
QuickBase, Inc.
 
[Srijan Wednesday Webinars] Ruling Drupal 8 with #d8rules
[Srijan Wednesday Webinars] Ruling Drupal 8 with #d8rules[Srijan Wednesday Webinars] Ruling Drupal 8 with #d8rules
[Srijan Wednesday Webinars] Ruling Drupal 8 with #d8rules
Srijan Technologies
 
Paris js extensions
Paris js extensionsParis js extensions
Paris js extensions
erwanl
 
Devoxx08 - Nuxeo Core, JCR 2, CMIS
Devoxx08 - Nuxeo Core, JCR 2, CMIS Devoxx08 - Nuxeo Core, JCR 2, CMIS
Devoxx08 - Nuxeo Core, JCR 2, CMIS
Nuxeo
 

Similar to Softshake - Offline applications (20)

Local data storage for mobile apps
Local data storage for mobile appsLocal data storage for mobile apps
Local data storage for mobile apps
 
Local Storage
Local StorageLocal Storage
Local Storage
 
React Native Course - Data Storage . pdf
React Native Course - Data Storage . pdfReact Native Course - Data Storage . pdf
React Native Course - Data Storage . pdf
 
The Magic Revealed: Four Real-World Examples of Using the Client Object Model...
The Magic Revealed: Four Real-World Examples of Using the Client Object Model...The Magic Revealed: Four Real-World Examples of Using the Client Object Model...
The Magic Revealed: Four Real-World Examples of Using the Client Object Model...
 
Android Data Storagefinal
Android Data StoragefinalAndroid Data Storagefinal
Android Data Storagefinal
 
Taking Web Apps Offline
Taking Web Apps OfflineTaking Web Apps Offline
Taking Web Apps Offline
 
Local storage in Web apps
Local storage in Web appsLocal storage in Web apps
Local storage in Web apps
 
Developing your first application using FI-WARE
Developing your first application using FI-WAREDeveloping your first application using FI-WARE
Developing your first application using FI-WARE
 
Boost Your Environment With XMLDB - UKOUG 2008 - Marco Gralike
Boost Your Environment With XMLDB - UKOUG 2008 - Marco GralikeBoost Your Environment With XMLDB - UKOUG 2008 - Marco Gralike
Boost Your Environment With XMLDB - UKOUG 2008 - Marco Gralike
 
Fun Teaching MongoDB New Tricks
Fun Teaching MongoDB New TricksFun Teaching MongoDB New Tricks
Fun Teaching MongoDB New Tricks
 
Intro to HTML5 Web Storage
Intro to HTML5 Web StorageIntro to HTML5 Web Storage
Intro to HTML5 Web Storage
 
Tornadoweb
TornadowebTornadoweb
Tornadoweb
 
Hidden pearls for High-Performance-Persistence
Hidden pearls for High-Performance-PersistenceHidden pearls for High-Performance-Persistence
Hidden pearls for High-Performance-Persistence
 
Jquery dojo slides
Jquery dojo slidesJquery dojo slides
Jquery dojo slides
 
Global objects in Node.pdf
Global objects in Node.pdfGlobal objects in Node.pdf
Global objects in Node.pdf
 
Cloudbase.io MoSync Reload Course
Cloudbase.io MoSync Reload CourseCloudbase.io MoSync Reload Course
Cloudbase.io MoSync Reload Course
 
Saving Time And Effort With QuickBase Api - Sergio Haro
Saving Time And Effort With QuickBase Api - Sergio HaroSaving Time And Effort With QuickBase Api - Sergio Haro
Saving Time And Effort With QuickBase Api - Sergio Haro
 
[Srijan Wednesday Webinars] Ruling Drupal 8 with #d8rules
[Srijan Wednesday Webinars] Ruling Drupal 8 with #d8rules[Srijan Wednesday Webinars] Ruling Drupal 8 with #d8rules
[Srijan Wednesday Webinars] Ruling Drupal 8 with #d8rules
 
Paris js extensions
Paris js extensionsParis js extensions
Paris js extensions
 
Devoxx08 - Nuxeo Core, JCR 2, CMIS
Devoxx08 - Nuxeo Core, JCR 2, CMIS Devoxx08 - Nuxeo Core, JCR 2, CMIS
Devoxx08 - Nuxeo Core, JCR 2, CMIS
 

More from jeromevdl

Message-Driven Architecture on AWS
Message-Driven Architecture on AWSMessage-Driven Architecture on AWS
Message-Driven Architecture on AWS
jeromevdl
 
Do more with less code in serverless
Do more with less code in serverlessDo more with less code in serverless
Do more with less code in serverless
jeromevdl
 
Do more with less code in a serverless world
Do more with less code in a serverless worldDo more with less code in a serverless world
Do more with less code in a serverless world
jeromevdl
 
DevopsDays Geneva 2020 - Compliance & Governance as Code
DevopsDays Geneva 2020 - Compliance & Governance as CodeDevopsDays Geneva 2020 - Compliance & Governance as Code
DevopsDays Geneva 2020 - Compliance & Governance as Code
jeromevdl
 
Softshake 2017 - Développer un chatbot Alexa
Softshake 2017 - Développer un chatbot AlexaSoftshake 2017 - Développer un chatbot Alexa
Softshake 2017 - Développer un chatbot Alexa
jeromevdl
 
Chatbots buzzword ou nouvel eldorado
Chatbots   buzzword ou nouvel eldoradoChatbots   buzzword ou nouvel eldorado
Chatbots buzzword ou nouvel eldorado
jeromevdl
 
Management projet vs management produit
Management projet vs management produitManagement projet vs management produit
Management projet vs management produit
jeromevdl
 
My Android is not an iPhone like any others (Mdevcon 2014)
My Android is not an iPhone like any others (Mdevcon 2014)My Android is not an iPhone like any others (Mdevcon 2014)
My Android is not an iPhone like any others (Mdevcon 2014)
jeromevdl
 
DroidconUK 2013 : Beef up android apps with java tools
DroidconUK 2013 : Beef up android apps with java toolsDroidconUK 2013 : Beef up android apps with java tools
DroidconUK 2013 : Beef up android apps with java tools
jeromevdl
 
Droidcon Paris 2013 - Musclez vos applications Android avec les outils du mon...
Droidcon Paris 2013 - Musclez vos applications Android avec les outils du mon...Droidcon Paris 2013 - Musclez vos applications Android avec les outils du mon...
Droidcon Paris 2013 - Musclez vos applications Android avec les outils du mon...
jeromevdl
 
Devoxx France 2013 : Musclez vos apps android avec les outils du monde java
Devoxx France 2013 : Musclez vos apps android avec les outils du monde javaDevoxx France 2013 : Musclez vos apps android avec les outils du monde java
Devoxx France 2013 : Musclez vos apps android avec les outils du monde javajeromevdl
 
Jug Lausanne Android Janvier2013
Jug Lausanne Android Janvier2013Jug Lausanne Android Janvier2013
Jug Lausanne Android Janvier2013
jeromevdl
 
Metroide
MetroideMetroide
Metroide
jeromevdl
 

More from jeromevdl (13)

Message-Driven Architecture on AWS
Message-Driven Architecture on AWSMessage-Driven Architecture on AWS
Message-Driven Architecture on AWS
 
Do more with less code in serverless
Do more with less code in serverlessDo more with less code in serverless
Do more with less code in serverless
 
Do more with less code in a serverless world
Do more with less code in a serverless worldDo more with less code in a serverless world
Do more with less code in a serverless world
 
DevopsDays Geneva 2020 - Compliance & Governance as Code
DevopsDays Geneva 2020 - Compliance & Governance as CodeDevopsDays Geneva 2020 - Compliance & Governance as Code
DevopsDays Geneva 2020 - Compliance & Governance as Code
 
Softshake 2017 - Développer un chatbot Alexa
Softshake 2017 - Développer un chatbot AlexaSoftshake 2017 - Développer un chatbot Alexa
Softshake 2017 - Développer un chatbot Alexa
 
Chatbots buzzword ou nouvel eldorado
Chatbots   buzzword ou nouvel eldoradoChatbots   buzzword ou nouvel eldorado
Chatbots buzzword ou nouvel eldorado
 
Management projet vs management produit
Management projet vs management produitManagement projet vs management produit
Management projet vs management produit
 
My Android is not an iPhone like any others (Mdevcon 2014)
My Android is not an iPhone like any others (Mdevcon 2014)My Android is not an iPhone like any others (Mdevcon 2014)
My Android is not an iPhone like any others (Mdevcon 2014)
 
DroidconUK 2013 : Beef up android apps with java tools
DroidconUK 2013 : Beef up android apps with java toolsDroidconUK 2013 : Beef up android apps with java tools
DroidconUK 2013 : Beef up android apps with java tools
 
Droidcon Paris 2013 - Musclez vos applications Android avec les outils du mon...
Droidcon Paris 2013 - Musclez vos applications Android avec les outils du mon...Droidcon Paris 2013 - Musclez vos applications Android avec les outils du mon...
Droidcon Paris 2013 - Musclez vos applications Android avec les outils du mon...
 
Devoxx France 2013 : Musclez vos apps android avec les outils du monde java
Devoxx France 2013 : Musclez vos apps android avec les outils du monde javaDevoxx France 2013 : Musclez vos apps android avec les outils du monde java
Devoxx France 2013 : Musclez vos apps android avec les outils du monde java
 
Jug Lausanne Android Janvier2013
Jug Lausanne Android Janvier2013Jug Lausanne Android Janvier2013
Jug Lausanne Android Janvier2013
 
Metroide
MetroideMetroide
Metroide
 

Recently uploaded

Quality defects in TMT Bars, Possible causes and Potential Solutions.
Quality defects in TMT Bars, Possible causes and Potential Solutions.Quality defects in TMT Bars, Possible causes and Potential Solutions.
Quality defects in TMT Bars, Possible causes and Potential Solutions.
PrashantGoswami42
 
Halogenation process of chemical process industries
Halogenation process of chemical process industriesHalogenation process of chemical process industries
Halogenation process of chemical process industries
MuhammadTufail242431
 
Architectural Portfolio Sean Lockwood
Architectural Portfolio Sean LockwoodArchitectural Portfolio Sean Lockwood
Architectural Portfolio Sean Lockwood
seandesed
 
power quality voltage fluctuation UNIT - I.pptx
power quality voltage fluctuation UNIT - I.pptxpower quality voltage fluctuation UNIT - I.pptx
power quality voltage fluctuation UNIT - I.pptx
ViniHema
 
Cosmetic shop management system project report.pdf
Cosmetic shop management system project report.pdfCosmetic shop management system project report.pdf
Cosmetic shop management system project report.pdf
Kamal Acharya
 
在线办理(ANU毕业证书)澳洲国立大学毕业证录取通知书一模一样
在线办理(ANU毕业证书)澳洲国立大学毕业证录取通知书一模一样在线办理(ANU毕业证书)澳洲国立大学毕业证录取通知书一模一样
在线办理(ANU毕业证书)澳洲国立大学毕业证录取通知书一模一样
obonagu
 
DESIGN A COTTON SEED SEPARATION MACHINE.docx
DESIGN A COTTON SEED SEPARATION MACHINE.docxDESIGN A COTTON SEED SEPARATION MACHINE.docx
DESIGN A COTTON SEED SEPARATION MACHINE.docx
FluxPrime1
 
COLLEGE BUS MANAGEMENT SYSTEM PROJECT REPORT.pdf
COLLEGE BUS MANAGEMENT SYSTEM PROJECT REPORT.pdfCOLLEGE BUS MANAGEMENT SYSTEM PROJECT REPORT.pdf
COLLEGE BUS MANAGEMENT SYSTEM PROJECT REPORT.pdf
Kamal Acharya
 
Immunizing Image Classifiers Against Localized Adversary Attacks
Immunizing Image Classifiers Against Localized Adversary AttacksImmunizing Image Classifiers Against Localized Adversary Attacks
Immunizing Image Classifiers Against Localized Adversary Attacks
gerogepatton
 
Water Industry Process Automation and Control Monthly - May 2024.pdf
Water Industry Process Automation and Control Monthly - May 2024.pdfWater Industry Process Automation and Control Monthly - May 2024.pdf
Water Industry Process Automation and Control Monthly - May 2024.pdf
Water Industry Process Automation & Control
 
Sachpazis:Terzaghi Bearing Capacity Estimation in simple terms with Calculati...
Sachpazis:Terzaghi Bearing Capacity Estimation in simple terms with Calculati...Sachpazis:Terzaghi Bearing Capacity Estimation in simple terms with Calculati...
Sachpazis:Terzaghi Bearing Capacity Estimation in simple terms with Calculati...
Dr.Costas Sachpazis
 
MCQ Soil mechanics questions (Soil shear strength).pdf
MCQ Soil mechanics questions (Soil shear strength).pdfMCQ Soil mechanics questions (Soil shear strength).pdf
MCQ Soil mechanics questions (Soil shear strength).pdf
Osamah Alsalih
 
Forklift Classes Overview by Intella Parts
Forklift Classes Overview by Intella PartsForklift Classes Overview by Intella Parts
Forklift Classes Overview by Intella Parts
Intella Parts
 
LIGA(E)11111111111111111111111111111111111111111.ppt
LIGA(E)11111111111111111111111111111111111111111.pptLIGA(E)11111111111111111111111111111111111111111.ppt
LIGA(E)11111111111111111111111111111111111111111.ppt
ssuser9bd3ba
 
HYDROPOWER - Hydroelectric power generation
HYDROPOWER - Hydroelectric power generationHYDROPOWER - Hydroelectric power generation
HYDROPOWER - Hydroelectric power generation
Robbie Edward Sayers
 
The Benefits and Techniques of Trenchless Pipe Repair.pdf
The Benefits and Techniques of Trenchless Pipe Repair.pdfThe Benefits and Techniques of Trenchless Pipe Repair.pdf
The Benefits and Techniques of Trenchless Pipe Repair.pdf
Pipe Restoration Solutions
 
Gen AI Study Jams _ For the GDSC Leads in India.pdf
Gen AI Study Jams _ For the GDSC Leads in India.pdfGen AI Study Jams _ For the GDSC Leads in India.pdf
Gen AI Study Jams _ For the GDSC Leads in India.pdf
gdsczhcet
 
NO1 Uk best vashikaran specialist in delhi vashikaran baba near me online vas...
NO1 Uk best vashikaran specialist in delhi vashikaran baba near me online vas...NO1 Uk best vashikaran specialist in delhi vashikaran baba near me online vas...
NO1 Uk best vashikaran specialist in delhi vashikaran baba near me online vas...
Amil Baba Dawood bangali
 
addressing modes in computer architecture
addressing modes  in computer architectureaddressing modes  in computer architecture
addressing modes in computer architecture
ShahidSultan24
 
Courier management system project report.pdf
Courier management system project report.pdfCourier management system project report.pdf
Courier management system project report.pdf
Kamal Acharya
 

Recently uploaded (20)

Quality defects in TMT Bars, Possible causes and Potential Solutions.
Quality defects in TMT Bars, Possible causes and Potential Solutions.Quality defects in TMT Bars, Possible causes and Potential Solutions.
Quality defects in TMT Bars, Possible causes and Potential Solutions.
 
Halogenation process of chemical process industries
Halogenation process of chemical process industriesHalogenation process of chemical process industries
Halogenation process of chemical process industries
 
Architectural Portfolio Sean Lockwood
Architectural Portfolio Sean LockwoodArchitectural Portfolio Sean Lockwood
Architectural Portfolio Sean Lockwood
 
power quality voltage fluctuation UNIT - I.pptx
power quality voltage fluctuation UNIT - I.pptxpower quality voltage fluctuation UNIT - I.pptx
power quality voltage fluctuation UNIT - I.pptx
 
Cosmetic shop management system project report.pdf
Cosmetic shop management system project report.pdfCosmetic shop management system project report.pdf
Cosmetic shop management system project report.pdf
 
在线办理(ANU毕业证书)澳洲国立大学毕业证录取通知书一模一样
在线办理(ANU毕业证书)澳洲国立大学毕业证录取通知书一模一样在线办理(ANU毕业证书)澳洲国立大学毕业证录取通知书一模一样
在线办理(ANU毕业证书)澳洲国立大学毕业证录取通知书一模一样
 
DESIGN A COTTON SEED SEPARATION MACHINE.docx
DESIGN A COTTON SEED SEPARATION MACHINE.docxDESIGN A COTTON SEED SEPARATION MACHINE.docx
DESIGN A COTTON SEED SEPARATION MACHINE.docx
 
COLLEGE BUS MANAGEMENT SYSTEM PROJECT REPORT.pdf
COLLEGE BUS MANAGEMENT SYSTEM PROJECT REPORT.pdfCOLLEGE BUS MANAGEMENT SYSTEM PROJECT REPORT.pdf
COLLEGE BUS MANAGEMENT SYSTEM PROJECT REPORT.pdf
 
Immunizing Image Classifiers Against Localized Adversary Attacks
Immunizing Image Classifiers Against Localized Adversary AttacksImmunizing Image Classifiers Against Localized Adversary Attacks
Immunizing Image Classifiers Against Localized Adversary Attacks
 
Water Industry Process Automation and Control Monthly - May 2024.pdf
Water Industry Process Automation and Control Monthly - May 2024.pdfWater Industry Process Automation and Control Monthly - May 2024.pdf
Water Industry Process Automation and Control Monthly - May 2024.pdf
 
Sachpazis:Terzaghi Bearing Capacity Estimation in simple terms with Calculati...
Sachpazis:Terzaghi Bearing Capacity Estimation in simple terms with Calculati...Sachpazis:Terzaghi Bearing Capacity Estimation in simple terms with Calculati...
Sachpazis:Terzaghi Bearing Capacity Estimation in simple terms with Calculati...
 
MCQ Soil mechanics questions (Soil shear strength).pdf
MCQ Soil mechanics questions (Soil shear strength).pdfMCQ Soil mechanics questions (Soil shear strength).pdf
MCQ Soil mechanics questions (Soil shear strength).pdf
 
Forklift Classes Overview by Intella Parts
Forklift Classes Overview by Intella PartsForklift Classes Overview by Intella Parts
Forklift Classes Overview by Intella Parts
 
LIGA(E)11111111111111111111111111111111111111111.ppt
LIGA(E)11111111111111111111111111111111111111111.pptLIGA(E)11111111111111111111111111111111111111111.ppt
LIGA(E)11111111111111111111111111111111111111111.ppt
 
HYDROPOWER - Hydroelectric power generation
HYDROPOWER - Hydroelectric power generationHYDROPOWER - Hydroelectric power generation
HYDROPOWER - Hydroelectric power generation
 
The Benefits and Techniques of Trenchless Pipe Repair.pdf
The Benefits and Techniques of Trenchless Pipe Repair.pdfThe Benefits and Techniques of Trenchless Pipe Repair.pdf
The Benefits and Techniques of Trenchless Pipe Repair.pdf
 
Gen AI Study Jams _ For the GDSC Leads in India.pdf
Gen AI Study Jams _ For the GDSC Leads in India.pdfGen AI Study Jams _ For the GDSC Leads in India.pdf
Gen AI Study Jams _ For the GDSC Leads in India.pdf
 
NO1 Uk best vashikaran specialist in delhi vashikaran baba near me online vas...
NO1 Uk best vashikaran specialist in delhi vashikaran baba near me online vas...NO1 Uk best vashikaran specialist in delhi vashikaran baba near me online vas...
NO1 Uk best vashikaran specialist in delhi vashikaran baba near me online vas...
 
addressing modes in computer architecture
addressing modes  in computer architectureaddressing modes  in computer architecture
addressing modes in computer architecture
 
Courier management system project report.pdf
Courier management system project report.pdfCourier management system project report.pdf
Courier management system project report.pdf
 

Softshake - Offline applications

  • 1. Offline applications Jérôme Van Der Linden - 28/10/2016
  • 7. Offline applications 5 questions to ask before creating an offline application
  • 8. Question #1 What can I do offline ?
  • 14. Question #2 How much data is it and where can i store it ?
  • 17. Several gigabytes (or many more) ?
  • 19. Application Cache <html manifest="/cache.manifest"> ... </html> CACHE MANIFEST # Explicitly cached CACHE: /favicon.ico page.html stylesheet.css images/logo.png scripts/main.js http://cdn.example.com/scripts/main.js # Resources that require the user to be online. NETWORK: * # static.html will be served if main.py is inaccessible # offline.jpg will be served in place of all images in images/large/ FALLBACK: /main.py /static.html images/large/ images/offline.jpg cache.manifest index.html http://www.html5rocks.com/en/tutorials/appcache/beginner/ http://alistapart.com/article/application-cache-is-a-douchebag
  • 20. Application Cache <html manifest="/cache.manifest"> ... </html> CACHE MANIFEST # Explicitly cached CACHE: /favicon.ico page.html stylesheet.css images/logo.png scripts/main.js http://cdn.example.com/scripts/main.js # Resources that require the user to be online. NETWORK: * # static.html will be served if main.py is inaccessible # offline.jpg will be served in place of all images in images/large/ FALLBACK: /main.py /static.html images/large/ images/offline.jpg cache.manifest index.html http://www.html5rocks.com/en/tutorials/appcache/beginner/ http://alistapart.com/article/application-cache-is-a-douchebag
  • 21. Service Workers (Cache API) this.addEventListener('install', function(event) { event.waitUntil( caches.open('v1').then(function(cache) { return cache.addAll([ '/sw-test/', '/sw-test/index.html', '/sw-test/style.css', '/sw-test/app.js', '/sw-test/star-wars-logo.jpg', '/sw-test/gallery/', '/sw-test/gallery/myLittleVader.jpg' ]); }) ); }); 2. Installation of Service Worker if ('serviceWorker' in navigator) { navigator.serviceWorker.register(‘/sw.js') .then(function(registration) { // Registration was successful }).catch(function(err) { // registration failed :( }); } 1. Registration of Service Worker self.addEventListener('fetch', function(event) { event.respondWith( caches.match(event.request) .then(function(response) { // Cache hit - return response if (response) { return response; } var fetchRequest = event.request.clone(); return fetch(fetchRequest).then( function(response) { if (!response || response.status !== 200) { return response; } var responseToCache = response.clone(); caches.open('v1').then(function(cache) { cache.put(event.request, responseToCache); }); return response; } ); }) ); }); 3 . Fetch and Cache requests
  • 22. Service Workers (Cache API) 44+40+ https://jakearchibald.github.io/isserviceworkerready/ 27+
  • 23. Future of upcoming web development ?
  • 24. Web storage (local / session) if (('localStorage' in window) && window['localStorage'] !== null) { localStorage.setItem(key, value); } if (key in localStorage) { var value = localStorage.getItem(key); } 1. Store data 2. Retrieve data if (key in localStorage) { localStorage.removeItem(key); } localStorage.clear(); 3. Remove data / clear
  • 25. Web SQL var db = openDatabase('mydb', '1.0', 'Test DB', 2 * 1024 * 1024); var msg; db.transaction(function (tx) { tx.executeSql('CREATE TABLE IF NOT EXISTS LOGS (id unique, log)'); tx.executeSql('INSERT INTO LOGS (id, log) VALUES (1, "foobar")'); tx.executeSql('INSERT INTO LOGS (id, log) VALUES (2, "logmsg")'); msg = '<p>Log message created and row inserted.</p>'; document.querySelector('#status').innerHTML = msg; }); db.transaction(function (tx) { tx.executeSql('SELECT * FROM LOGS', [], function (tx, results) { var len = results.rows.length, i; msg = "<p>Found rows: " + len + "</p>"; document.querySelector('#status').innerHTML += msg; for (i = 0; i < len; i++) { msg = "<p><b>" + results.rows.item(i).log + "</b></p>"; document.querySelector('#status').innerHTML += msg; } }, null); });
  • 26. var db = openDatabase('mydb', '1.0', 'Test DB', 2 * 1024 * 1024); var msg; db.transaction(function (tx) { tx.executeSql('CREATE TABLE IF NOT EXISTS LOGS (id unique, log)'); tx.executeSql('INSERT INTO LOGS (id, log) VALUES (1, "foobar")'); tx.executeSql('INSERT INTO LOGS (id, log) VALUES (2, "logmsg")'); msg = '<p>Log message created and row inserted.</p>'; document.querySelector('#status').innerHTML = msg; }); db.transaction(function (tx) { tx.executeSql('SELECT * FROM LOGS', [], function (tx, results) { var len = results.rows.length, i; msg = "<p>Found rows: " + len + "</p>"; document.querySelector('#status').innerHTML += msg; for (i = 0; i < len; i++) { msg = "<p><b>" + results.rows.item(i).log + "</b></p>"; document.querySelector('#status').innerHTML += msg; } }, null); }); Web SQL
  • 27. function onInitFs(fs) { fs.root.getFile('log.txt', {}, function(fileEntry) { // Get a File object representing the file, // then use FileReader to read its contents. fileEntry.file(function(file) { var reader = new FileReader(); reader.onloadend = function(e) { var txtArea = document.createElement('textarea'); txtArea.value = this.result; document.body.appendChild(txtArea); }; reader.readAsText(file); }, errorHandler); }, errorHandler); } window.requestFileSystem(window.TEMPORARY, 1024*1024, onInitFs, errorHandler); FileSystem API
  • 28. function onInitFs(fs) { fs.root.getFile('log.txt', {}, function(fileEntry) { // Get a File object representing the file, // then use FileReader to read its contents. fileEntry.file(function(file) { var reader = new FileReader(); reader.onloadend = function(e) { var txtArea = document.createElement('textarea'); txtArea.value = this.result; document.body.appendChild(txtArea); }; reader.readAsText(file); }, errorHandler); }, errorHandler); } window.requestFileSystem(window.TEMPORARY, 1024*1024, onInitFs, errorHandler); FileSystem API
  • 29. IndexedDB var db; function openDb() { var req = indexedDB.open(DB_NAME, DB_VERSION); req.onsuccess = function (evt) { db = this.result; }; req.onerror = function (evt) { console.error("openDb:", evt.target.errorCode); }; req.onupgradeneeded = function (evt) { var store = evt.currentTarget.result.createObjectStore( DB_STORE_NAME, { keyPath: 'id', autoIncrement: true }); store.createIndex('title', 'title', { unique: false }); store.createIndex('isbn', 'isbn', { unique: true }); }; } 1. Open Database
  • 30. IndexedDB var tx = db.transaction(DB_STORE_NAME, 'readwrite'); var store = tx.objectStore(DB_STORE_NAME); var obj = { isbn: ‘0062316095’, title: ‘Sapiens: A Brief History of Humankind’, year: 2015 }; var req; try { req = store.add(obj); } catch (e) { // ... } req.onsuccess = function (evt) { console.log("Insertion in DB successful"); // ... }; req.onerror = function() { console.error("Insert error", this.error); // ... }; 2. Insert data
  • 31. IndexedDB var var tx = db.transaction(DB_STORE_NAME, 'readonly'); var store = tx.objectStore(DB_STORE_NAME); var req = store.openCursor(); req.onsuccess = function (evt) { var cursor = evt.target.result; if (cursor) { alert(cursor.value.title); cursor.continue(); } }; 3. Retrieve data (cursor) var var tx = db.transaction(DB_STORE_NAME, 'readonly'); var store = tx.objectStore(DB_STORE_NAME); var req = store.get(42); req.onsuccess = function (evt) { var object = evt.target.result; alert(object.title); }; 3. Retrieve data (one item)
  • 32. IndexedDB var var tx = db.transaction(DB_STORE_NAME, 'readonly'); var store = tx.objectStore(DB_STORE_NAME); var index = store.index(‘title’); var req = index.get(‘Sapiens: A Brief History of Humankind’); req.onsuccess = function (evt) { var result = evt.target.result; if (result) { // ... } }; 3. Retrieve data (index)
  • 33. IndexedDB wrappers • db.js • joqular • TaffyDB • localForage • IDBWrapper • YDN
  • 36. HTML 5 Storage Limitations
  • 37. Quotas 50 % 33 % 20 % 20 % Free disk space Space browser can use Space application (domain) can use
  • 39. Users
  • 40. https://storage.spec.whatwg.org/ https://developers.google.com/web/updates/2016/06/persistent-storage if (navigator.storage && navigator.storage.persist) navigator.storage.persist().then(granted => { if (granted) alert("Storage will not be cleared except by explicit user action"); else alert("Storage may be cleared by the UA under storage pressure."); }); if (navigator.storage && navigator.storage.persist) navigator.storage.persisted().then(persistent=>{ if (persistent) console.log("Storage will not be cleared except by explicit user action"); else console.log("Storage may be cleared by the UA under storage pressure."); }); Persistent storage 55+
  • 41. Question #3 How to handle offline-online synchronization ?
  • 43. Basic Resolution : based on timestamp « Last version win »
  • 44. Optimistic lock Source : Patterns of Enterprise Application Architecture - Martin Fowler System transaction boundaries Business transaction boundaries
  • 45. Pessimistic lock Source : Patterns of Enterprise Application Architecture - Martin Fowler System transaction boundaries Business transaction boundaries
  • 46. Theory is when you know everything but nothing works. Practice is when everything works but no one knows why. In our lab, theory and practice are combined: nothing works and no one knows why!
  • 47.
  • 48. kinto.js var db = new Kinto(); var todos = db.collection(‘todos’); todos.create({ title: ‘buy some bread’), finished : false }) .then(function(res){…}) .catch(function(err){…}) todos.list().then(function(res) { renderTodos(res.data); }) .catch(function(err) {…}); todos.update(todo) .then(function(res) {…}) .catch(function(err) {…}); Create, Read, Update, Delete using IndexedDB todos.delete(todo.id) .then(function(res) {…}) .catch(function(err) {…}); var syncOptions = { remote: "https://host/kintoapi", headers: {Authorization: …} }; todos.sync(syncOptions) .then(function(res){…}) .catch(function(err){…}) Synchronize with remote
  • 49. kinto.js var syncOptions = { remote: "https://host/kintoapi", headers: {Authorization: …} }; todos.sync(syncOptions) .then(function(res){…}) .catch(function(err){…}) { "ok": true, "lastModified": 1434617181458, "errors": [], "created": [], // created locally "updated": [], // updated locally "deleted": [], // deleted locally "published": [ // published remotely { "last_modified": 1434617181458, "done": false, "id": "7ca54d89-479a-4201-8494", "title": "buy some bread", "_status": "synced" } ], "conflicts": [], "skipped": [] } { "ok": true, "lastModified": 1434617181458, "errors": [], "created": [], // created locally "updated": [], // updated locally "deleted": [], // deleted locally "published": [], // published remotely "conflicts": [ { "type": "incoming", // or outgoing "local": { "last_modified": 1434619634577, "done": true, "id": "7ca54d89-479a-4201-8494", "title": "buy some bread", "_status": "updated" }, "remote": { "last_modified": 1434619745465, "done": false, "id": "7ca54d89-479a-4201-8494", "title": "buy some bread and wine" } } ], "skipped": [] } OK Conflicts
  • 50. kinto.js { "ok": true, "lastModified": 1434617181458, "errors": [], "created": [], // created locally "updated": [], // updated locally "deleted": [], // deleted locally "published": [], // published remotely "conflicts": [ { "type": "incoming", // or outgoing "local": { "last_modified": 1434619634577, "done": true, "id": "7ca54d89-479a-4201-8494", "title": "buy some bread", "_status": "updated" }, "remote": { "last_modified": 1434619745465, "done": false, "id": "7ca54d89-479a-4201-8494", "title": "buy some bread and wine" } } ], "skipped": [] } Conflicts todos.sync(syncOptions) .then(function(res){ if (res.conflicts.length) { return handleConflicts(res.conflicts); } }) .catch(function(err){…}); function handleConflicts(conflicts) { return Promise.all(conflicts.map(function(conflict) { return todos.resolve(conflict, conflict.remote); })) .then(function() { todos.sync(syncOptions); }); } Choose your way to solve the conflict: • Choose remote or local version • Choose according last_modified • Pick the good fields (need to provide 3-way-merge screen)
  • 51. var db = new PouchDB(‘todos’); db.post({ // can use ‘put’ with an _id title: ‘buy some bread’), finished : false }) .then(function(res){…}) .catch(function(err){…}) db.get(‘mysuperid’).then(function(todo) { // return an object with auto // generated ‘_rev’ field // update the full doc (with _rev) todo.finished = true; db.put(todo); // remove the full doc (with _rev) db.remove(todo); }) .catch(function(err) {…}); Create, Read, Update, Delete using IndexedDB var localDB = new PouchDB(‘todos’); // Remote CouchDB var remoteDB = new PouchDB(‘http://host/todos’); localDB.replicate.to(remoteDB); localDB.replicate.from(remoteDB); // or localDB.sync(remoteDB, { live: true, retry: true }).on('change', function (change) { // something changed! }).on('paused', function (info) { // replication was paused, // usually because of a lost connection }).on('active', function (info) { // replication was resumed }).on('error', function (err) { // unhandled error (shouldn't happen) }); Synchronize with remote
  • 52. var myDoc = { _id: 'someid', _rev: '1-somerev' }; db.put(myDoc).then(function () { // success }).catch(function (err) { if (err.name === 'conflict') { // conflict! Handle it! } else { // some other error } }); Immediate conflict : error 409 _rev: ‘1-revabc’ _rev: ‘1-revabc’ _rev: ‘2-revcde’ _rev: ‘2-revjkl’ _rev: ‘1-revabc’ _rev: ‘2-revjkl’ _rev: ‘2-revcde’ db.get('someid', {conflicts: true}) .then(function (doc) { // do something with the object }).catch(function (err) { // handle any errors }); { "_id": "someid", "_rev": "2-revjkl", "_conflicts": ["2-revcde"] } ==> Eventual conflict ==> remove the bad one, merge, … it’s up to you
  • 53.
  • 54. Question #4 How to communicate with users ?
  • 55. Inform the user … Save Save locally Send Send when online
  • 56. … or not Outbox (1)Send
  • 57. Do no display errors !
  • 58. Do not load indefinitelyyyyyyyyyy
  • 59. Do not display an empty screen
  • 60.
  • 62. Question #5 Do I really need offline ?
  • 64.
  • 65. « You are not on a f*cking plane and if you are, it doesn’t matter » - David Heinemeier Hansson (2007) https://signalvnoise.com/posts/347-youre-not-on-a-fucking-plane-and-if-you-are-it-doesnt-matter
  • 69. Bibliography • http://diveintohtml5.info/offline.html • https://github.com/pazguille/offline-first • https://jakearchibald.com/2014/offline-cookbook/ • https://github.com/offlinefirst/research/blob/master/links.md • http://www.html5rocks.com/en/tutorials/offline/whats-offline/ • http://offlinefirst.org/ • http://fr.slideshare.net/MarcelKalveram/offline-first-the-painless-way • https://developer.mozilla.org/en-US/Apps/Fundamentals/Offline • https://uxdesign.cc/offline-93c2f8396124#.97njk8o5m • https://www.ibm.com/developerworks/community/blogs/worklight/entry/ offline_patterns?lang=en • http://apress.jensimmons.com/v5/pro-html5-programming/ch12.html • http://alistapart.com/article/offline-first • http://alistapart.com/article/application-cache-is-a-douchebag • https://logbook.hanno.co/offline-first-matters-developers-know/ • https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/ Using_Service_Workers • https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API • https://developer.chrome.com/apps/offline_storage • http://martinfowler.com/eaaCatalog/index.html • http://offlinestat.es/ • http://caniuse.com/ Jake Archibald