SlideShare una empresa de Scribd logo
1 de 16
Backbone.js
  Simple Tutorial
     by @fallroot
Backbone.js

Backbone supplies structure to JavaScript-heavy applications by

providing models with key-value binding and custom events, collections

with a rich API of enumerable functions, views with declarative event

handling, and connects it all to your existing application over a RESTful

JSON interface.
$ rails new todoapp                                                     Back-end
$ cd todoapp

$ rm public/index.html

$ rails g scaffold todo title:string done:boolean
                                                    •   Ruby on Rails
$ rake db:migrate
                                                        •   3.1.0 RC5
$ rails s
<script type="text/template"></script>         Dependency
<script src="jquery.js / zepto.js"></script>
<script src="underscore.js"></script>
<script src="backbone.js"></script>

<script src="my-scripts.js"></script>
var Item = Backbone.Model.extend({
  urlRoot: '/todos'
                                                                    POST
});

var item = new Item({
  title: 'Create new todo'
});
                                     •   Backbone.Model.extend(properties,
item.save();
                                         [classProperties])
                                     •   model.save([attributes], [options])
                                     •   model.url()
                                     •   model.urlRoot
                                         •   /urlRoot/id
var Item = Backbone.Model.extend({
  urlRoot: '/todos'
                                                                                     PUT
});

var item = new Item({
  title: 'Create another todo'
});
                                                 •   _.bind(function, object, [*arguments])
item.save();                                     •   _.delay(function, wait, [*arguments])
var save = _.bind(item.save, item);
_.delay(save, 5000, {title: 'Title updated'});
var Item = Backbone.Model.extend({
  urlRoot: '/todos'
                                                                    DELETE
});

var item = new Item({
  title: 'This will be deleted'
});
                                             •   model.destroy([options])
item.save();

_.delay(_.bind(item.destroy, item), 5000);
var Item = Backbone.Model.extend({
  urlRoot: '/todos'
                                                                                        GET
});

var ItemView = Backbone.View.extend({
 tagName: 'li',

 initialize: function() {                          •   Backbone.View.extend(properties,
   this.model.bind('change', this.render, this);
                                                       [classProperties])
 },
                                                   •   model.fetch([options])
  render: function() {
    this.el.innerHTML = this.model.get('title');
                                                   •   model.get(attribute)
    return this;                                   •   object.bind(event, callback, [context])
  }
});

var item = new Item({id: 1});
item.fetch();

var itemView = new ItemView({model: item});
$('#todos').append(itemView.el);
var Item = Backbone.Model.extend();                                      Collection
var ItemView = Backbone.View.extend({
 tagName: 'li',

 initialize: function() {
   this.model.bind('change', this.render, this);
 },                                                •   Backbone.Collection.extend(properties,
  render: function() {                                 [classProperties])
    this.el.innerHTML = this.model.get('title');
    return this;
                                                   •   collection.fetch([options])
  }                                                •   collection.model
});
                                                   •   collection.url or collection.url()
var Item = Backbone.Model.extend();
    var List = Backbone.Collection.extend({
                                                                                   Collection
var ItemView = Backbone.View.extend({
      model: Item,
 tagName: 'li',
      url : '/todos'
    });
 initialize: function() {
    var ListView = Backbone.View.extend({
   this.model.bind('change', this.render, this);
 }, el: $('#todos'),                                         •   Backbone.Collection.extend(properties,
       initialize: function() {
  render: function() {
         this.collection.bind('reset', this.render, this);       [classProperties])
    this.el.innerHTML = this.model.get('title');
         this.collection.fetch();                            •   collection.fetch([options])
    return this;
       },
  }                                                          •   collection.model
}); render: function() {
         var el = this.el;                                   •   collection.url or collection.url()
         this.collection.each(function(item) {
           var itemView = new ItemView({model: item});
           el.append(itemView.render().el);
         });
         return this;
       }
     });

   new ListView({collection: new List});
var Router = Backbone.Router.extend({
 routes: {
                                                                                 Router
   '*action': 'actionCallback'
 },

  actionCallback: function(action) {
    document.body.innerHTML = action;
  }                                               •   Backbone.Router.extend(properties,
});                                                   [classProperties])

var router = new Router();                        •   router.navigate(fragment, [triggerRoute])
Backbone.history.start();                         •   Backbone.history.start([options])

router.navigate('started', true);
                                                  •   URL Fragment
var navigate = _.bind(router.navigate, router);
_.delay(navigate, 3000, 'moved', true);           •   history.pushState / popState
                                                  •   window.onhashchange
                                                      •   IE8
                                                  •   polling if not supported
<script type="text/template" id="item-template">
 <p class="done">
                                                                                  Template
  <input type="checkbox" <% if (done) { %>checked<% } %>>
 </p>
 <p class="title"><%= title %></p>
 <p class="commands">
  <button class="edit">Edit</button>
  <button class="remove">Remove</button>
 </p>                                                       •   _.template(templateString, [context])
</script>
                                                            •   model.toJSON()
<script type="text/template" id="item-template">
 <p class="done">
   var Item = Backbone.Model.extend({
                                                                                       Template
  <input type="checkbox" <% if (done) { %>checked<% } %>>
     urlRoot: '/todos'
 </p>
   });
 <p class="title"><%= title %></p>
 <p class="commands">
   var ItemView = Backbone.View.extend({
  <button class="edit">Edit</button>
     tagName: 'li',
  <button class="remove">Remove</button>
 </p>
     template: _.template($('#item-template').html()),
                                                                 •   _.template(templateString, [context])
</script>
     initialize: function() {
                                                                 •   model.toJSON()
      this.model.bind('change', this.render, this);
    },

     render: function() {
       this.el.innerHTML = this.template(this.model.toJSON());
       return this;
     }
   });

   var item = new Item({id: 1});
   item.fetch();

   var itemView = new ItemView({model: item});
   $('#todos').append(itemView.el);
All Together
Conclusion

•   For JavaScript Heavy Application
    •   Single-Page Application
•   Skinny Back-end
    •   RESTful JSON Interface
Backbone.js Simple Tutorial

Más contenido relacionado

La actualidad más candente

Nickolay Shmalenuk.Render api eng.DrupalCamp Kyiv 2011
Nickolay Shmalenuk.Render api eng.DrupalCamp Kyiv 2011Nickolay Shmalenuk.Render api eng.DrupalCamp Kyiv 2011
Nickolay Shmalenuk.Render api eng.DrupalCamp Kyiv 2011
camp_drupal_ua
 
Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)
Fabien Potencier
 
Building Smart Async Functions For Mobile
Building Smart Async Functions For MobileBuilding Smart Async Functions For Mobile
Building Smart Async Functions For Mobile
Glan Thomas
 

La actualidad más candente (20)

Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011
 Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011 Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011
Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011
 
Nickolay Shmalenuk.Render api eng.DrupalCamp Kyiv 2011
Nickolay Shmalenuk.Render api eng.DrupalCamp Kyiv 2011Nickolay Shmalenuk.Render api eng.DrupalCamp Kyiv 2011
Nickolay Shmalenuk.Render api eng.DrupalCamp Kyiv 2011
 
Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)
 
Building Smart Async Functions For Mobile
Building Smart Async Functions For MobileBuilding Smart Async Functions For Mobile
Building Smart Async Functions For Mobile
 
WordPress plugin #3
WordPress plugin #3WordPress plugin #3
WordPress plugin #3
 
Jquery Fundamentals
Jquery FundamentalsJquery Fundamentals
Jquery Fundamentals
 
jQuery Rescue Adventure
jQuery Rescue AdventurejQuery Rescue Adventure
jQuery Rescue Adventure
 
AngularJS Services
AngularJS ServicesAngularJS Services
AngularJS Services
 
[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
 
AngularJS - $http & $resource Services
AngularJS - $http & $resource ServicesAngularJS - $http & $resource Services
AngularJS - $http & $resource Services
 
Viastudy ef core_cheat_sheet
Viastudy ef core_cheat_sheetViastudy ef core_cheat_sheet
Viastudy ef core_cheat_sheet
 
Drupal - dbtng 25th Anniversary Edition
Drupal - dbtng 25th Anniversary EditionDrupal - dbtng 25th Anniversary Edition
Drupal - dbtng 25th Anniversary Edition
 
jQuery Namespace Pattern
jQuery Namespace PatternjQuery Namespace Pattern
jQuery Namespace Pattern
 
jQuery Presentasion
jQuery PresentasionjQuery Presentasion
jQuery Presentasion
 
Upgrade your javascript to drupal 8
Upgrade your javascript to drupal 8Upgrade your javascript to drupal 8
Upgrade your javascript to drupal 8
 
I os 04
I os 04I os 04
I os 04
 
AngularJS $Provide Service
AngularJS $Provide ServiceAngularJS $Provide Service
AngularJS $Provide Service
 
JavaScript in Drupal 7: What developers need to know
JavaScript in Drupal 7: What developers need to knowJavaScript in Drupal 7: What developers need to know
JavaScript in Drupal 7: What developers need to know
 
Backbone js
Backbone jsBackbone js
Backbone js
 
Beyond the DOM: Sane Structure for JS Apps
Beyond the DOM: Sane Structure for JS AppsBeyond the DOM: Sane Structure for JS Apps
Beyond the DOM: Sane Structure for JS Apps
 

Similar a Backbone.js Simple Tutorial

Taming that client side mess with Backbone.js
Taming that client side mess with Backbone.jsTaming that client side mess with Backbone.js
Taming that client side mess with Backbone.js
Jarod Ferguson
 
前端MVC 豆瓣说
前端MVC 豆瓣说前端MVC 豆瓣说
前端MVC 豆瓣说
Ting Lv
 
Django class based views (Dutch Django meeting presentation)
Django class based views (Dutch Django meeting presentation)Django class based views (Dutch Django meeting presentation)
Django class based views (Dutch Django meeting presentation)
Reinout van Rees
 
Javascript MVC & Backbone Tips & Tricks
Javascript MVC & Backbone Tips & TricksJavascript MVC & Backbone Tips & Tricks
Javascript MVC & Backbone Tips & Tricks
Hjörtur Hilmarsson
 
Django Class-based views (Slovenian)
Django Class-based views (Slovenian)Django Class-based views (Slovenian)
Django Class-based views (Slovenian)
Luka Zakrajšek
 

Similar a Backbone.js Simple Tutorial (20)

Understanding backbonejs
Understanding backbonejsUnderstanding backbonejs
Understanding backbonejs
 
Aplicacoes dinamicas Rails com Backbone
Aplicacoes dinamicas Rails com BackboneAplicacoes dinamicas Rails com Backbone
Aplicacoes dinamicas Rails com Backbone
 
Backbone.js
Backbone.jsBackbone.js
Backbone.js
 
Taming that client side mess with Backbone.js
Taming that client side mess with Backbone.jsTaming that client side mess with Backbone.js
Taming that client side mess with Backbone.js
 
前端MVC 豆瓣说
前端MVC 豆瓣说前端MVC 豆瓣说
前端MVC 豆瓣说
 
Client-side MVC with Backbone.js (reloaded)
Client-side MVC with Backbone.js (reloaded)Client-side MVC with Backbone.js (reloaded)
Client-side MVC with Backbone.js (reloaded)
 
Clean Javascript
Clean JavascriptClean Javascript
Clean Javascript
 
Client-side MVC with Backbone.js
Client-side MVC with Backbone.js Client-side MVC with Backbone.js
Client-side MVC with Backbone.js
 
Backbone Basics with Examples
Backbone Basics with ExamplesBackbone Basics with Examples
Backbone Basics with Examples
 
Django class based views (Dutch Django meeting presentation)
Django class based views (Dutch Django meeting presentation)Django class based views (Dutch Django meeting presentation)
Django class based views (Dutch Django meeting presentation)
 
Backbonejs for beginners
Backbonejs for beginnersBackbonejs for beginners
Backbonejs for beginners
 
Backbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVCBackbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVC
 
Javascript MVC & Backbone Tips & Tricks
Javascript MVC & Backbone Tips & TricksJavascript MVC & Backbone Tips & Tricks
Javascript MVC & Backbone Tips & Tricks
 
Django Class-based views (Slovenian)
Django Class-based views (Slovenian)Django Class-based views (Slovenian)
Django Class-based views (Slovenian)
 
laravel tricks in 50minutes
laravel tricks in 50minuteslaravel tricks in 50minutes
laravel tricks in 50minutes
 
Introducing CakeEntity
Introducing CakeEntityIntroducing CakeEntity
Introducing CakeEntity
 
jQuery Data Manipulate API - A source code dissecting journey
jQuery Data Manipulate API - A source code dissecting journeyjQuery Data Manipulate API - A source code dissecting journey
jQuery Data Manipulate API - A source code dissecting journey
 
Django Rest Framework and React and Redux, Oh My!
Django Rest Framework and React and Redux, Oh My!Django Rest Framework and React and Redux, Oh My!
Django Rest Framework and React and Redux, Oh My!
 
Choosing a Javascript Framework
Choosing a Javascript FrameworkChoosing a Javascript Framework
Choosing a Javascript Framework
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ Etsy
 

Último

EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
Earley Information Science
 

Último (20)

Tech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfTech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdf
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Evaluating the top large language models.pdf
Evaluating the top large language models.pdfEvaluating the top large language models.pdf
Evaluating the top large language models.pdf
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 

Backbone.js Simple Tutorial

  • 1. Backbone.js Simple Tutorial by @fallroot
  • 2. Backbone.js Backbone supplies structure to JavaScript-heavy applications by providing models with key-value binding and custom events, collections with a rich API of enumerable functions, views with declarative event handling, and connects it all to your existing application over a RESTful JSON interface.
  • 3. $ rails new todoapp Back-end $ cd todoapp $ rm public/index.html $ rails g scaffold todo title:string done:boolean • Ruby on Rails $ rake db:migrate • 3.1.0 RC5 $ rails s
  • 4. <script type="text/template"></script> Dependency <script src="jquery.js / zepto.js"></script> <script src="underscore.js"></script> <script src="backbone.js"></script> <script src="my-scripts.js"></script>
  • 5. var Item = Backbone.Model.extend({ urlRoot: '/todos' POST }); var item = new Item({ title: 'Create new todo' }); • Backbone.Model.extend(properties, item.save(); [classProperties]) • model.save([attributes], [options]) • model.url() • model.urlRoot • /urlRoot/id
  • 6. var Item = Backbone.Model.extend({ urlRoot: '/todos' PUT }); var item = new Item({ title: 'Create another todo' }); • _.bind(function, object, [*arguments]) item.save(); • _.delay(function, wait, [*arguments]) var save = _.bind(item.save, item); _.delay(save, 5000, {title: 'Title updated'});
  • 7. var Item = Backbone.Model.extend({ urlRoot: '/todos' DELETE }); var item = new Item({ title: 'This will be deleted' }); • model.destroy([options]) item.save(); _.delay(_.bind(item.destroy, item), 5000);
  • 8. var Item = Backbone.Model.extend({ urlRoot: '/todos' GET }); var ItemView = Backbone.View.extend({ tagName: 'li', initialize: function() { • Backbone.View.extend(properties, this.model.bind('change', this.render, this); [classProperties]) }, • model.fetch([options]) render: function() { this.el.innerHTML = this.model.get('title'); • model.get(attribute) return this; • object.bind(event, callback, [context]) } }); var item = new Item({id: 1}); item.fetch(); var itemView = new ItemView({model: item}); $('#todos').append(itemView.el);
  • 9. var Item = Backbone.Model.extend(); Collection var ItemView = Backbone.View.extend({ tagName: 'li', initialize: function() { this.model.bind('change', this.render, this); }, • Backbone.Collection.extend(properties, render: function() { [classProperties]) this.el.innerHTML = this.model.get('title'); return this; • collection.fetch([options]) } • collection.model }); • collection.url or collection.url()
  • 10. var Item = Backbone.Model.extend(); var List = Backbone.Collection.extend({ Collection var ItemView = Backbone.View.extend({ model: Item, tagName: 'li', url : '/todos' }); initialize: function() { var ListView = Backbone.View.extend({ this.model.bind('change', this.render, this); }, el: $('#todos'), • Backbone.Collection.extend(properties, initialize: function() { render: function() { this.collection.bind('reset', this.render, this); [classProperties]) this.el.innerHTML = this.model.get('title'); this.collection.fetch(); • collection.fetch([options]) return this; }, } • collection.model }); render: function() { var el = this.el; • collection.url or collection.url() this.collection.each(function(item) { var itemView = new ItemView({model: item}); el.append(itemView.render().el); }); return this; } }); new ListView({collection: new List});
  • 11. var Router = Backbone.Router.extend({ routes: { Router '*action': 'actionCallback' }, actionCallback: function(action) { document.body.innerHTML = action; } • Backbone.Router.extend(properties, }); [classProperties]) var router = new Router(); • router.navigate(fragment, [triggerRoute]) Backbone.history.start(); • Backbone.history.start([options]) router.navigate('started', true); • URL Fragment var navigate = _.bind(router.navigate, router); _.delay(navigate, 3000, 'moved', true); • history.pushState / popState • window.onhashchange • IE8 • polling if not supported
  • 12. <script type="text/template" id="item-template"> <p class="done"> Template <input type="checkbox" <% if (done) { %>checked<% } %>> </p> <p class="title"><%= title %></p> <p class="commands"> <button class="edit">Edit</button> <button class="remove">Remove</button> </p> • _.template(templateString, [context]) </script> • model.toJSON()
  • 13. <script type="text/template" id="item-template"> <p class="done"> var Item = Backbone.Model.extend({ Template <input type="checkbox" <% if (done) { %>checked<% } %>> urlRoot: '/todos' </p> }); <p class="title"><%= title %></p> <p class="commands"> var ItemView = Backbone.View.extend({ <button class="edit">Edit</button> tagName: 'li', <button class="remove">Remove</button> </p> template: _.template($('#item-template').html()), • _.template(templateString, [context]) </script> initialize: function() { • model.toJSON() this.model.bind('change', this.render, this); }, render: function() { this.el.innerHTML = this.template(this.model.toJSON()); return this; } }); var item = new Item({id: 1}); item.fetch(); var itemView = new ItemView({model: item}); $('#todos').append(itemView.el);
  • 15. Conclusion • For JavaScript Heavy Application • Single-Page Application • Skinny Back-end • RESTful JSON Interface

Notas del editor

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n