Using NoSQL MongoDB with ColdFusion

I
NoSQL with ColdFusion
       Using MongoDB


           Indy Nagpal
      CFObjective, Melbourne, 2011
About me
About me
✴   Straker Translations, New Zealand
✴   Been working with CF for a while now
✴   Cloud-based applications using Railo
✴   Love CFWheels
✴   nagpals.com/blog, @indynagpal
NoSQL?
NoSQL?

✴   Different things to different people
✴   Non-Relational rather than NoSQL
✴   System for storage/retrieval of data
✴   Persistence layer is not a responsibility of a
    single system
Why NoSQL?
Why NoSQL?


✴   100s of millions of items in a big table
Why NoSQL?


✴   100s of millions of items in a big table
✴   Dynamic data structure
Using NoSQL MongoDB with ColdFusion
SQL                           NoSQL

     Static Data Structure        Dynamic Data Structure

       Dynamic Query              Static Query (generally)

         Consistency                Eventual consistency

         Transactions               Limited Transactions

     Difficult to distribute       Distributed, fault-tolerant

Limited performance under load Optimized for heavy read-write
SQL                           NoSQL

     Static Data Structure        Dynamic Data Structure

       Dynamic Query              Static Query (generally)

         Consistency                Eventual consistency

         Transactions               Limited Transactions

     Difficult to distribute       Distributed, fault-tolerant

Limited performance under load Optimized for heavy read-write
SQL                           NoSQL

     Static Data Structure        Dynamic Data Structure

       Dynamic Query              Static Query (generally)

         Consistency                Eventual consistency

         Transactions               Limited Transactions

     Difficult to distribute       Distributed, fault-tolerant

Limited performance under load Optimized for heavy read-write
SQL                           NoSQL

     Static Data Structure        Dynamic Data Structure

       Dynamic Query              Static Query (generally)

         Consistency                Eventual consistency

         Transactions               Limited Transactions

     Difficult to distribute       Distributed, fault-tolerant

Limited performance under load Optimized for heavy read-write
SQL                           NoSQL

     Static Data Structure        Dynamic Data Structure

       Dynamic Query              Static Query (generally)

         Consistency                Eventual consistency

         Transactions               Limited Transactions

     Difficult to distribute       Distributed, fault-tolerant

Limited performance under load Optimized for heavy read-write
SQL                           NoSQL

     Static Data Structure        Dynamic Data Structure

       Dynamic Query              Static Query (generally)

         Consistency                Eventual consistency

         Transactions               Limited Transactions

     Difficult to distribute       Distributed, fault-tolerant

Limited performance under load Optimized for heavy read-write
SQL                           NoSQL

     Static Data Structure        Dynamic Data Structure

       Dynamic Query              Static Query (generally)

         Consistency                Eventual consistency

         Transactions               Limited Transactions

     Difficult to distribute       Distributed, fault-tolerant

Limited performance under load Optimized for heavy read-write
NoSQL DBs
NoSQL DBs
✴   Used with CF
    ✴   Apache CouchDB
    ✴   MongoDB
    ✴   Amazon SimpleDB


✴   CF/Java Wrappers available
What is MongoDB
What is MongoDB
✴   A Document-oriented database
✴   “Humongous”
✴   Scalable, high-performance, open-source
✴   An alternative to relational databases
✴   One of the NoSQL technologies
Key Difference
Key Difference
✴   Most No-SQL databases
    ✴   dynamic data
    ✴   static queries
✴   MongoDB
    ✴   dynamic data
    ✴   dynamic and static queries
Basic Concepts
Basic Concepts
✴   Database
Basic Concepts
✴   Database
✴   Collections (broadly like table)
Basic Concepts
✴   Database
✴   Collections (broadly like table)
✴   Documents (like row)
Basic Concepts
✴   Database
✴   Collections (broadly like table)
✴   Documents (like row)
✴   Fields (like columns)
Basic Concepts
✴   Database
✴   Collections (broadly like table)
✴   Documents (like row)
✴   Fields (like columns)
✴   Collections are indexed
Basic Concepts
✴   Database
✴   Collections (broadly like table)
✴   Documents (like row)
✴   Fields (like columns)
✴   Collections are indexed
✴   Cursors (retrieve data as required)
Concepts
Concepts
✴   New terminology

✴   Similar ideas, but not identical

✴   RDBMS - columns defined for tables

✴   NoSQL - fields defined for documents

✴   Collections are more like containers
Drivers
Drivers
✴   Officially supported drivers
✴   Language-specific drivers (Java, Ruby, etc.)
✴   Framework-specific (MongoMapper)
✴   Wrappers built on top of drivers
    ✴   cfmongodb built on Java drivers
✴   Unlike Apache CouchDB that uses REST
BSON
BSON
✴   Binary JSON format
✴   Supports embedding of documents and
    arrays within other documents and arrays
✴   Lightweight
✴   Traversable
✴   Efficient
✴   bsonspec.org
CF and Mongo
CF and Mongo
✴   cfmongodb (on Github) -- excellent
✴   Wrapper around Java drivers
✴   Most functionality encapsulated
    ✴   Inserts, updates, delete, find
    ✴   Map-reduce, Geospatial
CF and BSON
•   Structs/arrays persisted as they are!


                      people = mongo.getDBCollection(“people”)

                      person = {
                        “fname” : “John”,
                        “lname” : “Doe”
                      }

                      people.save(person)
Init
Init
mongoConfig = createObject(
              'component',
              'cfmongodb.core.MongoConfig').init(dbName="test")
Init
mongoConfig = createObject(
              'component',
              'cfmongodb.core.MongoConfig').init(dbName="test")


mongo = createObject('component',
              'cfmongodb.core.Mongo').init(mongoConfig)
Init
mongoConfig = createObject(
              'component',
              'cfmongodb.core.MongoConfig').init(dbName="test")


mongo = createObject('component',
              'cfmongodb.core.Mongo').init(mongoConfig)

people = mongo.getDBCollection('people')
Add Data
Add Data
// create some data
newPeople = []
Add Data
// create some data
newPeople = []


arrayAppend(newPeople, {‘fname’: ‘John’, ‘email’ : ‘john@doe.com’})
Add Data
// create some data
newPeople = []


arrayAppend(newPeople, {‘fname’: ‘John’, ‘email’ : ‘john@doe.com’})


arrayAppend(newPeople, {‘fname’: ‘Jane’, ‘lname’ : ‘Doe’})
Add Data
// create some data
newPeople = []


arrayAppend(newPeople, {‘fname’: ‘John’, ‘email’ : ‘john@doe.com’})


arrayAppend(newPeople, {‘fname’: ‘Jane’, ‘lname’ : ‘Doe’})


// save everything at once
people.saveAll(newPeople)
Find / Update
Find / Update

person = people.query().$eq("fname", "Jane").find()
Find / Update

person = people.query().$eq("fname", "Jane").find()


// update a record
person[“email”] = “jane@doe.com”
person.update(person)
Tools
Tools
✴   Terminal console
✴   MongoHub (Mac)
✴   MongoExplorer, MongoVision (Windows)


✴   SSH Tunnel to connect
✴   mongohq.com (hosted MongoDB/admin)
MongoDB and Railo
MongoDB and Railo
✴   Railo Extension
✴   Cache CF variables/data
✴   Store key-value pairs
    ✴   cacheGet()
    ✴   cachePut()
Queries and Map-
    reduce
Queries and Map-
         reduce
✴   Queries - rapid development
✴   Map-reduce - advanced querying


✴   Query and Map-reduce together give
    MongoDB an edge over other NoSQL
    alternatives
Data Modeling
Data Modeling

✴   No Joins! Scary?
✴   Embedding documents supported via ID
✴   Big mind shift
✴   ‘Fear’ of duplicate data drives design
    decisions in relational db world
CF ORM
CF ORM
✴   No support in CF ORM frameworks
✴   Other language frameworks more
    advanced
    ✴   Ruby on Rails - mongomapper


✴   Need ORM integration for wider adoption
Asynchronous
Asynchronous

✴   Asynchronous inserts/updates
✴   Journaled


✴   Capped Collections (FIFO)
Time taken to add 20,000 records with 5 words in each record


                                                               30

                                                               25




                                                                     Time in Seconds
                                                               20

                                                               15

                                                               10

                                                               5

                                                               0




mysql (cfquery)       filesystem (cflog)         mongodb (cfmongodb)
Compelling features
Compelling features
✴   On-demand database and collection
    creation
✴   Asynchronous writes
✴   Replication - simple and easy
✴   Large-scale data processing
✴   Sharding - horizontal scaling
✴   Geospatial indexes
When to use?
When to use?

✴   Relational DBs suffice for most projects
    ✴   Abstraction via ORM is very useful
✴   MongoDB -- alternative/add-on
✴   Removes reliance on only one data storage
    mechanism
Learning Curve
Learning Curve
✴   Syntax
✴   Concepts like sharding, replication
✴   Well-documented / blogged
✴   Active mailing list
✴   Being used in production
So...
So...

✴   Another tool to have in one’s kit
✴   Extremely useful and easy to use
✴   Worth spending some time on
Thank you!

        @indynagpal
    indy@nagpals.com
  http://nagpals.com/blog
1 of 72

More Related Content

What's hot(20)

MongoDBMongoDB
MongoDB
SPBRUBY431 views
Mongodb @ vrtMongodb @ vrt
Mongodb @ vrt
JWORKS powered by Ordina411 views
MongoDB WiredTiger InternalsMongoDB WiredTiger Internals
MongoDB WiredTiger Internals
Norberto Leite12.7K views
PostgreSQL and MySQLPostgreSQL and MySQL
PostgreSQL and MySQL
PostgreSQL Experts, Inc.20.6K views
Mongo DBMongo DB
Mongo DB
Karan Kukreja736 views
LokijsLokijs
Lokijs
Joe Minichino511.3K views
WiredTiger OverviewWiredTiger Overview
WiredTiger Overview
WiredTiger6.8K views
Introduction to mongo dbIntroduction to mongo db
Introduction to mongo db
NexThoughts Technologies399 views
MongoDB London PHPMongoDB London PHP
MongoDB London PHP
Mike Dirolf4.4K views
WordPress at Scale WebinarWordPress at Scale Webinar
WordPress at Scale Webinar
Pantheon1.8K views
Intro CouchdbIntro Couchdb
Intro Couchdb
selvamanisampath944 views
The Basics of MongoDBThe Basics of MongoDB
The Basics of MongoDB
valuebound9.2K views
Getting started with postgresqlGetting started with postgresql
Getting started with postgresql
botsplash.com1.6K views
MongoDB and DynamoDBMongoDB and DynamoDB
MongoDB and DynamoDB
Md. Minhazul Haque183 views

Viewers also liked(11)

ColdFusion Features for More Modern CodingColdFusion Features for More Modern Coding
ColdFusion Features for More Modern Coding
ColdFusionConference2.1K views
Apache spark coreApache spark core
Apache spark core
Thành Nguyễn628 views
Building ColdFusion And AngularJS ApplicationsBuilding ColdFusion And AngularJS Applications
Building ColdFusion And AngularJS Applications
ColdFusionConference13.2K views
10 Reasons ColdFusion PDFs should rule the world10 Reasons ColdFusion PDFs should rule the world
10 Reasons ColdFusion PDFs should rule the world
ColdFusionConference2.3K views
Become a Security Rockstar with ColdFusion 2016Become a Security Rockstar with ColdFusion 2016
Become a Security Rockstar with ColdFusion 2016
ColdFusionConference874 views
Api manager preconferenceApi manager preconference
Api manager preconference
ColdFusionConference1.7K views
CommandBox : Free CFMLCommandBox : Free CFML
CommandBox : Free CFML
Ortus Solutions, Corp1.1K views

Similar to Using NoSQL MongoDB with ColdFusion

MongoDB.pptxMongoDB.pptx
MongoDB.pptxSigit52
51 views57 slides

Similar to Using NoSQL MongoDB with ColdFusion(20)

Introduction to MongoDBIntroduction to MongoDB
Introduction to MongoDB
Justin Smestad5.5K views
MongoDB is the MashupDBMongoDB is the MashupDB
MongoDB is the MashupDB
Wynn Netherland5.2K views
MongoDB.pptxMongoDB.pptx
MongoDB.pptx
Sigit5251 views
Nosql seminarNosql seminar
Nosql seminar
Shreyashkumar Nangnurwar3.3K views
NoSQL: Why, When, and HowNoSQL: Why, When, and How
NoSQL: Why, When, and How
BigBlueHat6.2K views
Couchbase - Yet Another IntroductionCouchbase - Yet Another Introduction
Couchbase - Yet Another Introduction
Kelum Senanayake14.1K views
MongoDBMongoDB
MongoDB
fsbrooke1.3K views
JS App ArchitectureJS App Architecture
JS App Architecture
Corey Butler911 views
No sql solutions - 공개용No sql solutions - 공개용
No sql solutions - 공개용
Byeongweon Moon909 views
MyRocks introduction and production deploymentMyRocks introduction and production deployment
MyRocks introduction and production deployment
Yoshinori Matsunobu3.2K views
Why Wordnik went non-relationalWhy Wordnik went non-relational
Why Wordnik went non-relational
Tony Tam2.7K views
DynamoDB Gluecon 2012DynamoDB Gluecon 2012
DynamoDB Gluecon 2012
Appirio738 views
Gluecon 2012 - DynamoDBGluecon 2012 - DynamoDB
Gluecon 2012 - DynamoDB
Jeff Douglas2.9K views
NoSQLNoSQL
NoSQL
dbulic1.4K views

Recently uploaded(20)

Liqid: Composable CXL PreviewLiqid: Composable CXL Preview
Liqid: Composable CXL Preview
CXL Forum118 views
The Research Portal of Catalonia: Growing more (information) & more (services)The Research Portal of Catalonia: Growing more (information) & more (services)
The Research Portal of Catalonia: Growing more (information) & more (services)
CSUC - Consorci de Serveis Universitaris de Catalunya51 views
Java Platform Approach 1.0 - Picnic MeetupJava Platform Approach 1.0 - Picnic Meetup
Java Platform Approach 1.0 - Picnic Meetup
Rick Ossendrijver23 views

Using NoSQL MongoDB with ColdFusion

  • 1. NoSQL with ColdFusion Using MongoDB Indy Nagpal CFObjective, Melbourne, 2011
  • 3. About me ✴ Straker Translations, New Zealand ✴ Been working with CF for a while now ✴ Cloud-based applications using Railo ✴ Love CFWheels ✴ nagpals.com/blog, @indynagpal
  • 5. NoSQL? ✴ Different things to different people ✴ Non-Relational rather than NoSQL ✴ System for storage/retrieval of data ✴ Persistence layer is not a responsibility of a single system
  • 7. Why NoSQL? ✴ 100s of millions of items in a big table
  • 8. Why NoSQL? ✴ 100s of millions of items in a big table ✴ Dynamic data structure
  • 10. SQL NoSQL Static Data Structure Dynamic Data Structure Dynamic Query Static Query (generally) Consistency Eventual consistency Transactions Limited Transactions Difficult to distribute Distributed, fault-tolerant Limited performance under load Optimized for heavy read-write
  • 11. SQL NoSQL Static Data Structure Dynamic Data Structure Dynamic Query Static Query (generally) Consistency Eventual consistency Transactions Limited Transactions Difficult to distribute Distributed, fault-tolerant Limited performance under load Optimized for heavy read-write
  • 12. SQL NoSQL Static Data Structure Dynamic Data Structure Dynamic Query Static Query (generally) Consistency Eventual consistency Transactions Limited Transactions Difficult to distribute Distributed, fault-tolerant Limited performance under load Optimized for heavy read-write
  • 13. SQL NoSQL Static Data Structure Dynamic Data Structure Dynamic Query Static Query (generally) Consistency Eventual consistency Transactions Limited Transactions Difficult to distribute Distributed, fault-tolerant Limited performance under load Optimized for heavy read-write
  • 14. SQL NoSQL Static Data Structure Dynamic Data Structure Dynamic Query Static Query (generally) Consistency Eventual consistency Transactions Limited Transactions Difficult to distribute Distributed, fault-tolerant Limited performance under load Optimized for heavy read-write
  • 15. SQL NoSQL Static Data Structure Dynamic Data Structure Dynamic Query Static Query (generally) Consistency Eventual consistency Transactions Limited Transactions Difficult to distribute Distributed, fault-tolerant Limited performance under load Optimized for heavy read-write
  • 16. SQL NoSQL Static Data Structure Dynamic Data Structure Dynamic Query Static Query (generally) Consistency Eventual consistency Transactions Limited Transactions Difficult to distribute Distributed, fault-tolerant Limited performance under load Optimized for heavy read-write
  • 18. NoSQL DBs ✴ Used with CF ✴ Apache CouchDB ✴ MongoDB ✴ Amazon SimpleDB ✴ CF/Java Wrappers available
  • 20. What is MongoDB ✴ A Document-oriented database ✴ “Humongous” ✴ Scalable, high-performance, open-source ✴ An alternative to relational databases ✴ One of the NoSQL technologies
  • 22. Key Difference ✴ Most No-SQL databases ✴ dynamic data ✴ static queries ✴ MongoDB ✴ dynamic data ✴ dynamic and static queries
  • 24. Basic Concepts ✴ Database
  • 25. Basic Concepts ✴ Database ✴ Collections (broadly like table)
  • 26. Basic Concepts ✴ Database ✴ Collections (broadly like table) ✴ Documents (like row)
  • 27. Basic Concepts ✴ Database ✴ Collections (broadly like table) ✴ Documents (like row) ✴ Fields (like columns)
  • 28. Basic Concepts ✴ Database ✴ Collections (broadly like table) ✴ Documents (like row) ✴ Fields (like columns) ✴ Collections are indexed
  • 29. Basic Concepts ✴ Database ✴ Collections (broadly like table) ✴ Documents (like row) ✴ Fields (like columns) ✴ Collections are indexed ✴ Cursors (retrieve data as required)
  • 31. Concepts ✴ New terminology ✴ Similar ideas, but not identical ✴ RDBMS - columns defined for tables ✴ NoSQL - fields defined for documents ✴ Collections are more like containers
  • 33. Drivers ✴ Officially supported drivers ✴ Language-specific drivers (Java, Ruby, etc.) ✴ Framework-specific (MongoMapper) ✴ Wrappers built on top of drivers ✴ cfmongodb built on Java drivers ✴ Unlike Apache CouchDB that uses REST
  • 34. BSON
  • 35. BSON ✴ Binary JSON format ✴ Supports embedding of documents and arrays within other documents and arrays ✴ Lightweight ✴ Traversable ✴ Efficient ✴ bsonspec.org
  • 37. CF and Mongo ✴ cfmongodb (on Github) -- excellent ✴ Wrapper around Java drivers ✴ Most functionality encapsulated ✴ Inserts, updates, delete, find ✴ Map-reduce, Geospatial
  • 38. CF and BSON • Structs/arrays persisted as they are! people = mongo.getDBCollection(“people”) person = { “fname” : “John”, “lname” : “Doe” } people.save(person)
  • 39. Init
  • 40. Init mongoConfig = createObject( 'component', 'cfmongodb.core.MongoConfig').init(dbName="test")
  • 41. Init mongoConfig = createObject( 'component', 'cfmongodb.core.MongoConfig').init(dbName="test") mongo = createObject('component', 'cfmongodb.core.Mongo').init(mongoConfig)
  • 42. Init mongoConfig = createObject( 'component', 'cfmongodb.core.MongoConfig').init(dbName="test") mongo = createObject('component', 'cfmongodb.core.Mongo').init(mongoConfig) people = mongo.getDBCollection('people')
  • 44. Add Data // create some data newPeople = []
  • 45. Add Data // create some data newPeople = [] arrayAppend(newPeople, {‘fname’: ‘John’, ‘email’ : ‘john@doe.com’})
  • 46. Add Data // create some data newPeople = [] arrayAppend(newPeople, {‘fname’: ‘John’, ‘email’ : ‘john@doe.com’}) arrayAppend(newPeople, {‘fname’: ‘Jane’, ‘lname’ : ‘Doe’})
  • 47. Add Data // create some data newPeople = [] arrayAppend(newPeople, {‘fname’: ‘John’, ‘email’ : ‘john@doe.com’}) arrayAppend(newPeople, {‘fname’: ‘Jane’, ‘lname’ : ‘Doe’}) // save everything at once people.saveAll(newPeople)
  • 49. Find / Update person = people.query().$eq("fname", "Jane").find()
  • 50. Find / Update person = people.query().$eq("fname", "Jane").find() // update a record person[“email”] = “jane@doe.com” person.update(person)
  • 51. Tools
  • 52. Tools ✴ Terminal console ✴ MongoHub (Mac) ✴ MongoExplorer, MongoVision (Windows) ✴ SSH Tunnel to connect ✴ mongohq.com (hosted MongoDB/admin)
  • 54. MongoDB and Railo ✴ Railo Extension ✴ Cache CF variables/data ✴ Store key-value pairs ✴ cacheGet() ✴ cachePut()
  • 56. Queries and Map- reduce ✴ Queries - rapid development ✴ Map-reduce - advanced querying ✴ Query and Map-reduce together give MongoDB an edge over other NoSQL alternatives
  • 58. Data Modeling ✴ No Joins! Scary? ✴ Embedding documents supported via ID ✴ Big mind shift ✴ ‘Fear’ of duplicate data drives design decisions in relational db world
  • 60. CF ORM ✴ No support in CF ORM frameworks ✴ Other language frameworks more advanced ✴ Ruby on Rails - mongomapper ✴ Need ORM integration for wider adoption
  • 62. Asynchronous ✴ Asynchronous inserts/updates ✴ Journaled ✴ Capped Collections (FIFO)
  • 63. Time taken to add 20,000 records with 5 words in each record 30 25 Time in Seconds 20 15 10 5 0 mysql (cfquery) filesystem (cflog) mongodb (cfmongodb)
  • 65. Compelling features ✴ On-demand database and collection creation ✴ Asynchronous writes ✴ Replication - simple and easy ✴ Large-scale data processing ✴ Sharding - horizontal scaling ✴ Geospatial indexes
  • 67. When to use? ✴ Relational DBs suffice for most projects ✴ Abstraction via ORM is very useful ✴ MongoDB -- alternative/add-on ✴ Removes reliance on only one data storage mechanism
  • 69. Learning Curve ✴ Syntax ✴ Concepts like sharding, replication ✴ Well-documented / blogged ✴ Active mailing list ✴ Being used in production
  • 70. So...
  • 71. So... ✴ Another tool to have in one’s kit ✴ Extremely useful and easy to use ✴ Worth spending some time on
  • 72. Thank you! @indynagpal indy@nagpals.com http://nagpals.com/blog

Editor's Notes

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. Two application problems:\n\nApplication 1: \n100s of millions of rows being written in clustered CF app\nSingle table with fixed number of columns\nMysql works, but slows down\nNo replication\n\nApplication 2\nApplication to generate mini applications, where number of columns can differ from each mini application to mini application\nBasic analytics needed\n\n
  12. Two application problems:\n\nApplication 1: \n100s of millions of rows being written in clustered CF app\nSingle table with fixed number of columns\nMysql works, but slows down\nNo replication\n\nApplication 2\nApplication to generate mini applications, where number of columns can differ from each mini application to mini application\nBasic analytics needed\n\n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n
  22. \n
  23. \n
  24. \n
  25. \n
  26. \n
  27. \n
  28. \n
  29. \n
  30. \n
  31. \n
  32. \n
  33. \n
  34. \n
  35. \n
  36. \n
  37. \n
  38. \n
  39. \n
  40. \n
  41. \n
  42. \n
  43. \n
  44. \n
  45. \n
  46. \n
  47. \n
  48. \n
  49. \n
  50. \n
  51. \n
  52. \n
  53. \n
  54. \n
  55. \n
  56. \n
  57. \n
  58. \n
  59. \n
  60. \n
  61. \n
  62. \n
  63. \n
  64. \n
  65. \n
  66. \n
  67. \n
  68. \n
  69. \n
  70. \n
  71. \n
  72. \n
  73. \n
  74. \n
  75. \n
  76. \n
  77. \n
  78. \n
  79. \n
  80. \n
  81. \n
  82. \n
  83. \n
  84. \n
  85. \n
  86. \n
  87. \n
  88. \n
  89. \n
  90. \n
  91. \n
  92. \n
  93. \n
  94. \n
  95. \n
  96. \n
  97. \n
  98. \n
  99. \n
  100. \n
  101. \n
  102. \n
  103. \n
  104. \n
  105. \n
  106. \n
  107. \n
  108. \n
  109. \n
  110. \n
  111. \n
  112. \n
  113. \n
  114. \n
  115. \n
  116. \n
  117. \n
  118. \n