WhiskBot Demo App Added + lots of other small changes (#18)

* Issue #3 update with rule and sequence support, also scope to specific target

Update README.md

Update README.md

Update README.md

Update README.md

Update README.md

* Issue 11, Add ability to specify target

remove warnings, unwrap deploy directory name for correct path, update namespace to use default

* Bump up version number

Update CONTRIBUTING.md

* Added WhiskBot Demo App

Removed excess folder

new icon images added

Conversation workspace readded

cleanup, added translation constants to constant list

Removed Carthage, started IBM Constants plist for OW keys

* Seperated OW Credentials into IBMConstants.plist

Create README.md

Create README.md

Update README.md

Update README.md

Update README.md

* Apache IBM License added to all files

Update README.md

Update README.md

Update README.md

New image for documentation

Update README.md

Update README.md

Update README.md

Update README.md

Final Changes

Added demo video
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index fcb1d0e..2c6369f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,4 +1,6 @@
+
 [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](http://www.apache.org/licenses/LICENSE-2.0)
+
 <!--
 #
 # Licensed to the Apache Software Foundation (ASF) under one or more contributor 
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..1b2faf4
--- /dev/null
+++ b/README.md
@@ -0,0 +1,16 @@
+# openwhisk-xcode
+>Collection of OpenWhisk tools for OS X implemented in Swift 3.
+
+Inside this Repo there are three projects.  Click into any directories to see more information about each project.
+
+## OpenWhisk Xcode Extension
+
+The OpenWhisk Xcode Source Editor Extension interfaces directly with OpenWhisk Playgrounds in order to test Swift OpenWhisk functions quickly.  
+
+## WhiskBot - OpenWhisk Watson Conversation Chatbot
+
+An iOS chatbot application that uses OpenWhisk actions as middleware.  WhiskBot has the ability to translate messages, using a translation OpenWhisk Action and post to Slack.  
+
+## WskTools
+
+A CLI tool that allows developers to install OpenWhisk "projects" into the OpenWhisk backend.  A project contains sets of actions (JS and Swift), triggers, and rules which can be installed with a single command `wsktool install`.  You can do the opposite with `wsktool uninstall`.  You can see an [example of an OpenWhisk project here](https://github.com/openwhisk/openwhisk-package-jira/tree/master/src).
diff --git a/whiskbot-demo-app/ConversationWorkspace.json b/whiskbot-demo-app/ConversationWorkspace.json
new file mode 100644
index 0000000..d876b30
--- /dev/null
+++ b/whiskbot-demo-app/ConversationWorkspace.json
@@ -0,0 +1 @@
+{"name":"WhiskBot_Conversation_Workspace","created":"2017-01-17T15:22:47.097Z","intents":[{"intent":"confused","created":"2017-01-18T21:10:58.366Z","updated":"2017-01-23T15:45:39.288Z","examples":[{"text":"I don't know","created":"2017-01-18T21:10:58.366Z","updated":"2017-01-18T21:10:58.366Z"},{"text":"I have no clue","created":"2017-01-18T21:10:58.366Z","updated":"2017-01-18T21:10:58.366Z"},{"text":"I'm not sure","created":"2017-01-18T21:10:58.366Z","updated":"2017-01-18T21:10:58.366Z"},{"text":"Never mind","created":"2017-01-23T15:45:31.675Z","updated":"2017-01-23T15:45:31.675Z"},{"text":"Please cancel","created":"2017-01-23T15:45:39.288Z","updated":"2017-01-23T15:45:39.288Z"},{"text":"What can I say?","created":"2017-01-18T21:10:58.366Z","updated":"2017-01-18T21:10:58.366Z"},{"text":"What can you do?","created":"2017-01-18T21:10:58.366Z","updated":"2017-01-18T21:10:58.366Z"}],"description":null},{"intent":"log_exercise","created":"2017-01-17T16:04:15.058Z","updated":"2017-01-17T18:42:06.000Z","examples":[{"text":"I exercised","created":"2017-01-17T18:42:06.000Z","updated":"2017-01-17T18:42:06.000Z"},{"text":"I just did some exercise","created":"2017-01-17T16:04:15.058Z","updated":"2017-01-17T16:04:15.058Z"},{"text":"I just walked","created":"2017-01-17T16:04:15.058Z","updated":"2017-01-17T16:04:15.058Z"},{"text":"I just went for a run","created":"2017-01-17T16:04:15.058Z","updated":"2017-01-17T16:04:15.058Z"},{"text":"Log my exercise","created":"2017-01-17T16:04:15.058Z","updated":"2017-01-17T16:04:15.058Z"},{"text":"Record some exercise","created":"2017-01-17T16:04:15.058Z","updated":"2017-01-17T16:04:15.058Z"}],"description":null},{"intent":"log_water","created":"2017-01-17T15:49:48.180Z","updated":"2017-01-17T19:10:28.965Z","examples":[{"text":"Add to my health that I just drank water","created":"2017-01-17T15:55:23.395Z","updated":"2017-01-17T15:55:23.395Z"},{"text":"I drank water","created":"2017-01-17T19:10:28.965Z","updated":"2017-01-17T19:10:28.965Z"},{"text":"I just drank a cup","created":"2017-01-17T15:54:47.626Z","updated":"2017-01-17T15:54:47.626Z"},{"text":"I want to record some water","created":"2017-01-17T19:10:24.984Z","updated":"2017-01-17T19:10:24.984Z"},{"text":"Log that I drank some water","created":"2017-01-17T15:55:01.414Z","updated":"2017-01-17T15:55:01.414Z"}],"description":null},{"intent":"reminder","created":"2017-01-17T19:20:00.190Z","updated":"2017-01-17T19:20:00.190Z","examples":[{"text":"Can you remind me of something?","created":"2017-01-17T19:20:00.190Z","updated":"2017-01-17T19:29:57.112Z"},{"text":"Could you remind me to","created":"2017-01-17T19:20:00.190Z","updated":"2017-01-17T19:20:00.190Z"},{"text":"Could you remind me to do something later?","created":"2017-01-17T19:20:00.190Z","updated":"2017-01-17T19:30:59.507Z"},{"text":"Remind me to","created":"2017-01-17T19:20:00.190Z","updated":"2017-01-17T19:31:02.062Z"},{"text":"Set a reminder","created":"2017-01-17T19:20:00.190Z","updated":"2017-01-17T19:20:00.190Z"}],"description":null},{"intent":"slack_post","created":"2017-01-20T20:45:09.828Z","updated":"2017-01-24T14:35:34.781Z","examples":[{"text":"Post to general","created":"2017-01-20T20:45:09.828Z","updated":"2017-01-20T20:45:09.828Z"},{"text":"Post to slack","created":"2017-01-20T20:45:09.828Z","updated":"2017-01-20T20:45:09.828Z"},{"text":"Post to slack that","created":"2017-01-20T20:45:09.828Z","updated":"2017-01-20T20:45:09.828Z"},{"text":"Say on Slack","created":"2017-01-20T20:45:09.828Z","updated":"2017-01-20T20:45:09.828Z"},{"text":"Send a message to slack","created":"2017-01-20T20:45:09.828Z","updated":"2017-01-20T20:45:09.828Z"},{"text":"What channel could I post to?","created":"2017-01-24T14:35:34.781Z","updated":"2017-01-24T14:35:34.781Z"}],"description":null},{"intent":"sleep","created":"2017-01-17T16:06:56.636Z","updated":"2017-01-17T19:10:48.759Z","examples":[{"text":"I went to sleep late yesterday","created":"2017-01-17T16:06:56.636Z","updated":"2017-01-17T16:06:56.636Z"},{"text":"I woke up at 8 pm today","created":"2017-01-17T16:06:56.636Z","updated":"2017-01-17T16:06:56.636Z"},{"text":"Log my sleep","created":"2017-01-17T16:06:56.636Z","updated":"2017-01-17T16:06:56.636Z"},{"text":"Record my sleep","created":"2017-01-17T16:06:56.636Z","updated":"2017-01-17T16:06:56.636Z"},{"text":"Sleep","created":"2017-01-17T19:10:48.759Z","updated":"2017-01-17T19:10:48.759Z"}],"description":null},{"intent":"today_history","created":"2017-01-17T15:55:37.840Z","updated":"2017-01-17T15:57:14.691Z","examples":[{"text":"Did anything happen today in history?","created":"2017-01-17T15:55:49.517Z","updated":"2017-01-17T15:55:49.517Z"},{"text":"Is there anything special today?","created":"2017-01-17T15:55:59.768Z","updated":"2017-01-17T15:55:59.768Z"},{"text":"Is today a significant day?","created":"2017-01-17T15:57:14.691Z","updated":"2017-01-17T15:57:14.691Z"},{"text":"What happened in the past today?","created":"2017-01-17T15:56:05.835Z","updated":"2017-01-17T15:56:05.835Z"}],"description":null},{"intent":"Translate","created":"2017-02-01T14:53:16.202Z","updated":"2017-02-01T14:53:16.202Z","examples":[{"text":"Can you translate something for me?","created":"2017-02-01T14:53:16.202Z","updated":"2017-02-01T14:53:16.202Z"},{"text":"How do I say this in Spanish?","created":"2017-02-01T14:53:16.202Z","updated":"2017-02-01T14:53:16.202Z"},{"text":"Translate","created":"2017-02-01T14:53:16.202Z","updated":"2017-02-01T14:53:16.202Z"},{"text":"Translate for me","created":"2017-02-01T14:53:16.202Z","updated":"2017-02-01T14:53:16.202Z"},{"text":"What does this mean in English?","created":"2017-02-01T14:53:16.202Z","updated":"2017-02-01T14:53:16.202Z"}],"description":null},{"intent":"weather","created":"2017-01-17T15:49:21.306Z","updated":"2017-01-17T15:56:39.751Z","examples":[{"text":"How cold is it?","created":"2017-01-17T15:56:39.751Z","updated":"2017-01-17T15:56:39.751Z"},{"text":"What is the weather like today?","created":"2017-01-17T15:49:21.306Z","updated":"2017-01-17T15:49:21.306Z"},{"text":"What's the weather like?","created":"2017-01-17T15:56:22.557Z","updated":"2017-01-17T15:56:22.557Z"},{"text":"What temperature is it today?","created":"2017-01-17T15:49:21.306Z","updated":"2017-01-17T15:49:21.306Z"},{"text":"Will it rain today?","created":"2017-01-17T15:49:21.306Z","updated":"2017-01-17T15:49:21.306Z"}],"description":null}],"updated":"2017-02-02T18:04:03.862Z","entities":[{"type":null,"entity":"language","source":null,"values":[{"value":"Arabic","created":"2017-02-01T19:23:29.384Z","updated":"2017-02-01T19:54:54.572Z","metadata":null,"synonyms":["Arab"]},{"value":"French","created":"2017-02-01T14:54:08.780Z","updated":"2017-02-01T14:54:08.780Z","metadata":null,"synonyms":["Francais"]},{"value":"Korean","created":"2017-02-01T19:55:23.822Z","updated":"2017-02-01T19:55:23.822Z","metadata":null,"synonyms":["Korea"]},{"value":"Spanish","created":"2017-02-01T14:54:08.780Z","updated":"2017-02-01T14:54:08.780Z","metadata":null,"synonyms":["Espanol"]}],"created":"2017-02-01T14:54:08.780Z","updated":"2017-02-01T14:54:08.780Z","open_list":false,"description":null},{"type":null,"entity":"slack_channels","source":null,"values":[{"value":"general","created":"2017-01-20T20:47:19.395Z","updated":"2017-01-20T20:47:19.395Z","metadata":null,"synonyms":["All","General"]},{"value":"random","created":"2017-01-20T20:47:19.395Z","updated":"2017-01-20T20:47:19.395Z","metadata":null,"synonyms":[]}],"created":"2017-01-20T20:47:19.395Z","updated":"2017-01-20T20:47:19.395Z","open_list":false,"description":null},{"type":null,"entity":"sleep_times","source":null,"values":[{"value":"Slept","created":"2017-01-17T16:33:59.232Z","updated":"2017-01-17T19:01:56.418Z","metadata":null,"synonyms":["asleep","Fell asleep","Went to bed","Went to sleep"]},{"value":"Woke up","created":"2017-01-17T16:33:59.232Z","updated":"2017-01-17T19:01:59.991Z","metadata":null,"synonyms":["Awoke","Got up","Wake up","Woke"]}],"created":"2017-01-17T16:33:59.232Z","updated":"2017-01-17T16:33:59.232Z","open_list":false,"description":null},{"type":null,"entity":"sys-date","source":"system.entities","values":[],"created":"2017-01-17T16:07:42.979Z","updated":"2017-01-17T16:07:42.979Z","open_list":false,"description":null},{"type":null,"entity":"sys-number","source":"system.entities","values":[],"created":"2017-01-17T16:07:48.038Z","updated":"2017-01-17T16:07:48.038Z","open_list":false,"description":null},{"type":null,"entity":"sys-time","source":"system.entities","values":[],"created":"2017-01-17T16:07:40.630Z","updated":"2017-01-17T16:07:40.630Z","open_list":false,"description":null},{"type":null,"entity":"water_amounts","source":null,"values":[{"value":"12 oz","created":"2017-01-17T19:08:03.799Z","updated":"2017-01-17T19:08:15.774Z","metadata":null,"synonyms":["12 ounce","12 ounces","A glass"]},{"value":"16 oz","created":"2017-01-17T16:22:06.620Z","updated":"2017-01-17T19:08:30.995Z","metadata":null,"synonyms":["16 ounce","16 ounces","A water bottle","Two cups"]},{"value":"24 oz","created":"2017-01-17T16:22:27.925Z","updated":"2017-01-17T19:08:31.618Z","metadata":null,"synonyms":["24 ounce","24 ounces","A lot","Three cups"]},{"value":"8 oz","created":"2017-01-17T16:22:06.620Z","updated":"2017-01-17T19:12:15.253Z","metadata":null,"synonyms":["8 ounce","8 ounces","A coffee","Cup","Half a bottle"]}],"created":"2017-01-17T16:22:06.620Z","updated":"2017-01-17T16:22:06.620Z","open_list":false,"description":null},{"type":null,"entity":"weather_type","source":null,"values":[{"value":"Cloudy","created":"2017-01-17T16:14:01.192Z","updated":"2017-01-17T18:53:59.136Z","metadata":null,"synonyms":["Foggy"]},{"value":"Hail","created":"2017-01-17T16:14:01.192Z","updated":"2017-01-17T18:53:58.704Z","metadata":null,"synonyms":["Hailed"]},{"value":"Rain","created":"2017-01-17T16:14:01.192Z","updated":"2017-01-17T18:53:56.123Z","metadata":null,"synonyms":["Rained"]},{"value":"Snow","created":"2017-01-17T16:14:01.192Z","updated":"2017-01-17T18:53:54.230Z","metadata":null,"synonyms":["Snowed"]},{"value":"Sunny","created":"2017-01-17T16:14:01.192Z","updated":"2017-01-17T18:54:01.511Z","metadata":null,"synonyms":["Clear","Sun"]}],"created":"2017-01-17T16:14:01.192Z","updated":"2017-01-17T16:14:01.192Z","open_list":false,"description":null},{"type":null,"entity":"workouts","source":null,"values":[{"value":"Bike","created":"2017-01-17T16:10:52.068Z","updated":"2017-01-17T18:53:33.197Z","metadata":null,"synonyms":["Biked","Cycle","Cycled","Pedal","Pedaled"]},{"value":"Hike","created":"2017-01-17T16:10:25.117Z","updated":"2017-01-17T18:52:54.306Z","metadata":null,"synonyms":["Hiked","Hiking"]},{"value":"Lifting","created":"2017-01-17T16:12:50.011Z","updated":"2017-01-17T18:52:49.809Z","metadata":null,"synonyms":["Benching","Bench Press","Curls","Lifted","Push ups","Sit ups","Weight Training"]},{"value":"Run","created":"2017-01-17T16:10:14.200Z","updated":"2017-01-17T18:54:08.668Z","metadata":null,"synonyms":["Jog","Jogged","Ran"]},{"value":"Walk","created":"2017-01-17T16:10:14.200Z","updated":"2017-01-17T18:52:49.035Z","metadata":null,"synonyms":["Speed walk","Walked"]}],"created":"2017-01-17T16:10:14.200Z","updated":"2017-01-17T16:10:14.200Z","open_list":false,"description":null}],"language":"en","metadata":null,"description":"The Conversation Workspace for the WhiskBot Demo Application","dialog_nodes":[{"go_to":null,"output":{},"parent":null,"context":null,"created":"2017-01-17T16:16:05.321Z","updated":"2017-01-17T18:51:35.486Z","metadata":null,"conditions":"#log_exercise || #log_water || #sleep","description":null,"dialog_node":"Health log","previous_sibling":"Confused"},{"go_to":null,"output":{},"parent":null,"context":null,"created":"2017-01-17T19:28:35.752Z","updated":"2017-01-17T19:31:53.285Z","metadata":null,"conditions":"#reminder","description":null,"dialog_node":"Reminder","previous_sibling":"Health log"},{"go_to":null,"output":{},"parent":null,"context":null,"created":"2017-01-20T20:45:32.984Z","updated":"2017-01-20T20:45:48.196Z","metadata":null,"conditions":"#slack_post","description":null,"dialog_node":"Slack Post","previous_sibling":"Conversation_Start"},{"go_to":null,"output":{},"parent":null,"context":null,"created":"2017-02-01T14:55:39.934Z","updated":"2017-02-01T19:58:50.366Z","metadata":null,"conditions":"#Translate","description":null,"dialog_node":"Translate Start","previous_sibling":"Slack Post"},{"go_to":null,"output":{},"parent":"Exercise Log","context":null,"created":"2017-01-17T18:55:18.221Z","updated":"2017-01-17T18:56:28.425Z","metadata":null,"conditions":"@sys-number || @sys-time","description":null,"dialog_node":"End Exercise","previous_sibling":null},{"go_to":null,"output":{},"parent":"Health log","context":null,"created":"2017-01-17T16:20:30.249Z","updated":"2017-01-17T16:24:52.293Z","metadata":null,"conditions":"@water_amounts","description":null,"dialog_node":"Water amount","previous_sibling":null},{"go_to":null,"output":{},"parent":"Health log","context":null,"created":"2017-01-17T16:25:50.457Z","updated":"2017-01-17T16:26:33.623Z","metadata":null,"conditions":"@workouts","description":null,"dialog_node":"Exercise Log","previous_sibling":"Water amount"},{"go_to":null,"output":{},"parent":"Health log","context":null,"created":"2017-01-17T16:32:02.537Z","updated":"2017-01-17T18:39:20.662Z","metadata":null,"conditions":"@sleep_times","description":null,"dialog_node":"Sleep log","previous_sibling":"Exercise Log"},{"go_to":null,"output":{},"parent":"Slack Channel","context":null,"created":"2017-01-20T20:48:35.485Z","updated":"2017-01-23T15:41:50.350Z","metadata":null,"conditions":"anything_else","description":null,"dialog_node":"Slack Post Text","previous_sibling":null},{"go_to":null,"output":{},"parent":"Slack Post","context":null,"created":"2017-01-20T20:47:29.544Z","updated":"2017-01-23T16:17:54.520Z","metadata":null,"conditions":"@slack_channels","description":null,"dialog_node":"Slack Channel","previous_sibling":null},{"go_to":null,"output":{},"parent":"Sleep log","context":null,"created":"2017-01-17T18:40:26.900Z","updated":"2017-01-17T18:40:51.874Z","metadata":null,"conditions":"@sleep_times","description":null,"dialog_node":"Sleep log followup","previous_sibling":null},{"go_to":null,"output":{},"parent":"Translate Start","context":null,"created":"2017-02-01T14:56:29.371Z","updated":"2017-02-01T14:56:46.739Z","metadata":null,"conditions":"@language","description":null,"dialog_node":"Language Choice","previous_sibling":"node_13_1485979130071"},{"go_to":null,"output":{"text":{"values":["Hello, how may I help you today?"],"selection_policy":"sequential"}},"parent":null,"context":null,"created":"2017-01-17T18:47:54.109Z","updated":"2017-01-17T18:48:46.116Z","metadata":null,"conditions":"conversation_start","description":null,"dialog_node":"Conversation_Start","previous_sibling":null},{"go_to":null,"output":{"text":{"values":["I can help you log data like health data and set reminders for you.  Ask me to record your water intake, your sleep times, or exercises.  Or ask me to set a reminder."],"selection_policy":"sequential"}},"parent":null,"context":null,"created":"2017-01-18T21:11:03.109Z","updated":"2017-01-20T19:57:45.280Z","metadata":null,"conditions":"#confused","description":null,"dialog_node":"Confused","previous_sibling":"Translate Start"},{"go_to":null,"output":{"text":{"values":["No worries.  If you want to schedule a reminder later, just let me know.  Is there anything else you want me to do?"],"selection_policy":"sequential"}},"parent":"Reminder Text","context":null,"created":"2017-01-24T15:40:53.977Z","updated":"2017-01-24T15:47:04.166Z","metadata":null,"conditions":"#confused","description":null,"dialog_node":"Confused Reminder","previous_sibling":"Unknown Time"},{"go_to":null,"output":{"text":{"values":["Okay.  Let me know if you want to do something else"],"selection_policy":"sequential"}},"parent":"Translate Start","context":null,"created":"2017-02-01T14:58:55.703Z","updated":"2017-02-01T15:03:12.577Z","metadata":null,"conditions":"#confused","description":null,"dialog_node":"node_6_1485961136914","previous_sibling":"Unknown Language"},{"go_to":null,"output":{"text":{"values":["Okay.  Let me know if you want to do something else or post to slack some other time"],"selection_policy":"sequential"}},"parent":"Slack Post","context":null,"created":"2017-01-23T15:46:04.218Z","updated":"2017-02-01T14:59:09.202Z","metadata":null,"conditions":"#confused","description":null,"dialog_node":"Cancel Slack Post","previous_sibling":"Unknown Channel"},{"go_to":null,"output":{"text":{"values":["Translation -"],"selection_policy":"sequential"}},"parent":"Language Choice","context":null,"created":"2017-02-01T15:03:37.486Z","updated":"2017-02-01T19:13:46.891Z","metadata":null,"conditions":"true","description":null,"dialog_node":"Translate Text","previous_sibling":null},{"go_to":null,"output":{"text":{"values":["Okay.  I can do that.  When would you like your reminder?","Of course.  When would you like your reminder?"],"selection_policy":"random"}},"parent":"Reminder","context":null,"created":"2017-01-17T19:32:04.791Z","updated":"2017-01-24T15:39:52.582Z","metadata":null,"conditions":"true","description":null,"dialog_node":"Reminder Text","previous_sibling":null},{"go_to":null,"output":{"text":{"values":["Sure thing.  Will do.  Let me know if you would like me to do anything else","Will do.  Is there anything else I can help you with?","Of course.  Is there anything else I can help you with?"],"selection_policy":"random"}},"parent":"Reminder Text","context":null,"created":"2017-01-17T19:32:59.801Z","updated":"2017-01-24T18:53:20.930Z","metadata":null,"conditions":"@sys-time || @sys-date","description":null,"dialog_node":"Reminder Time","previous_sibling":null},{"go_to":{"return":null,"selector":"user_input","dialog_node":"Language Choice"},"output":{"text":{"values":["I am not sure which language that is.  Please tell me a language like Spanish or French."],"selection_policy":"sequential"}},"parent":"Translate Start","context":null,"created":"2017-02-01T14:57:58.800Z","updated":"2017-02-01T15:03:21.597Z","metadata":null,"conditions":"anything_else","description":null,"dialog_node":"Unknown Language","previous_sibling":"Language Choice"},{"go_to":{"return":null,"selector":"user_input","dialog_node":"Reminder Time"},"output":{"text":{"values":["I'm sorry I couldn't pick up a time.  What time would you like your reminder to be scheduled for?"],"selection_policy":"sequential"}},"parent":"Reminder Text","context":null,"created":"2017-01-24T15:40:01.584Z","updated":"2017-01-24T15:47:17.009Z","metadata":null,"conditions":"anything_else","description":null,"dialog_node":"Unknown Time","previous_sibling":"Reminder Time"},{"go_to":{"return":null,"selector":"user_input","dialog_node":"Slack Channel"},"output":{"text":{"values":["I'm sorry I couldn't understand which channel you wanted me to post to.  As of now you can post to general or random.  What channel would you like?"],"selection_policy":"sequential"}},"parent":"Slack Post","context":null,"created":"2017-01-23T15:27:04.182Z","updated":"2017-01-24T14:34:13.797Z","metadata":null,"conditions":"anything_else","description":null,"dialog_node":"Unknown Channel","previous_sibling":"Slack Channel"},{"type":"response_condition","go_to":null,"output":null,"parent":"Translate Start","context":null,"created":"2017-02-01T19:58:50.166Z","updated":"2017-02-01T19:58:50.166Z","metadata":null,"conditions":null,"description":null,"dialog_node":"node_13_1485979130071","previous_sibling":"node_12_1485979129518"},{"type":"response_condition","go_to":null,"output":{"text":{"values":["Great! How long was your run?"],"selection_policy":"sequential"}},"parent":"Exercise Log","context":null,"created":"2017-01-17T16:27:14.118Z","updated":"2017-01-20T19:55:27.117Z","metadata":null,"conditions":" @workouts:Run","description":null,"dialog_node":"node_4_1484670433961","previous_sibling":"node_3_1484670393109"},{"type":"response_condition","go_to":null,"output":{"text":{"values":["Great!  I just posted it for you.  Let me know if you need anything else"],"selection_policy":"sequential"}},"parent":"Slack Post Text","context":null,"created":"2017-01-20T20:49:33.891Z","updated":"2017-01-23T15:41:44.724Z","metadata":null,"conditions":" ","description":null,"dialog_node":"node_7_1484945373717","previous_sibling":null},{"type":"response_condition","go_to":null,"output":{"text":{"values":["Hmm something seems wrong"],"selection_policy":"sequential"}},"parent":"Health log","context":null,"created":"2017-01-17T18:42:45.814Z","updated":"2017-01-17T18:42:54.153Z","metadata":null,"conditions":null,"description":null,"dialog_node":"node_14_1484678565601","previous_sibling":"node_5_1484669949173"},{"type":"response_condition","go_to":null,"output":{"text":{"values":["Lets record how much you drank.  How much did you drink?"],"selection_policy":"sequential"}},"parent":"Health log","context":null,"created":"2017-01-17T16:19:09.326Z","updated":"2017-01-17T19:05:21.625Z","metadata":null,"conditions":"#log_water","description":null,"dialog_node":"node_5_1484669949173","previous_sibling":"node_4_1484669906750"},{"type":"response_condition","go_to":null,"output":{"text":{"values":["Lets record your exercise.  What type of exercise did you do?"],"selection_policy":"sequential"}},"parent":"Health log","context":null,"created":"2017-01-17T16:18:26.935Z","updated":"2017-01-17T16:19:06.716Z","metadata":null,"conditions":"#log_exercise","description":null,"dialog_node":"node_4_1484669906750","previous_sibling":"node_3_1484669828242"},{"type":"response_condition","go_to":null,"output":{"text":{"values":["Of course I can post to general for you.  What would you like me to post?"],"selection_policy":"sequential"}},"parent":"Slack Channel","context":null,"created":"2017-01-20T20:47:37.616Z","updated":"2017-01-20T20:47:59.761Z","metadata":null,"conditions":" @slack_channels:general","description":null,"dialog_node":"node_4_1484945257422","previous_sibling":"Slack Post Text"},{"type":"response_condition","go_to":null,"output":{"text":{"values":["Of course I can post to random for you.  What would you like me to post?"],"selection_policy":"sequential"}},"parent":"Slack Channel","context":null,"created":"2017-01-20T20:48:03.589Z","updated":"2017-01-20T20:48:30.713Z","metadata":null,"conditions":" @slack_channels:random","description":null,"dialog_node":"node_5_1484945283400","previous_sibling":"node_4_1484945257422"},{"type":"response_condition","go_to":null,"output":{"text":{"values":["Of course, I can translate to French.  What would you like to translate?"],"selection_policy":"sequential"}},"parent":"Language Choice","context":null,"created":"2017-02-01T14:57:17.766Z","updated":"2017-02-01T14:57:43.933Z","metadata":null,"conditions":" @language:French","description":null,"dialog_node":"node_4_1485961038948","previous_sibling":"node_3_1485961007468"},{"type":"response_condition","go_to":null,"output":{"text":{"values":["Of course.  Which language do you want to translate to?"],"selection_policy":"sequential"}},"parent":"Translate Start","context":null,"created":"2017-02-01T19:58:49.936Z","updated":"2017-02-01T19:58:50.288Z","metadata":null,"conditions":null,"description":null,"dialog_node":"node_12_1485979129518","previous_sibling":null},{"type":"response_condition","go_to":null,"output":{"text":{"values":["Thank you for recording it.  Let me know if I could help you in any other way"],"selection_policy":"sequential"}},"parent":"End Exercise","context":null,"created":"2017-01-17T18:55:49.804Z","updated":"2017-01-17T18:56:15.100Z","metadata":null,"conditions":" ","description":null,"dialog_node":"node_3_1484679349630","previous_sibling":null},{"type":"response_condition","go_to":null,"output":{"text":{"values":["Yeah sure, I can translate to Arabic for you.  What would you like to say?"],"selection_policy":"sequential"}},"parent":"Language Choice","context":null,"created":"2017-02-01T19:55:40.159Z","updated":"2017-02-01T19:56:06.223Z","metadata":null,"conditions":" @language:Arabic","description":null,"dialog_node":"node_11_1485978940083","previous_sibling":"node_8_1485976455351"},{"type":"response_condition","go_to":null,"output":{"text":{"values":["Yeah sure, I can translate to Korean for you.  What would you like to say?"],"selection_policy":"sequential"}},"parent":"Language Choice","context":null,"created":"2017-02-01T19:14:15.456Z","updated":"2017-02-01T19:55:40.085Z","metadata":null,"conditions":"@language:Korean","description":null,"dialog_node":"node_8_1485976455351","previous_sibling":"node_4_1485961038948"},{"type":"response_condition","go_to":null,"output":{"text":{"values":["Yeah sure, I can translate to Spanish.  What would you like to translate?"],"selection_policy":"sequential"}},"parent":"Language Choice","context":null,"created":"2017-02-01T14:56:46.264Z","updated":"2017-02-01T14:57:15.849Z","metadata":null,"conditions":" @language:Spanish","description":null,"dialog_node":"node_3_1485961007468","previous_sibling":"Translate Text"},{"type":"response_condition","go_to":null,"output":{"text":{"values":["Fantastic Biking!   How long did you bike for?",""],"selection_policy":"random"}},"parent":"Exercise Log","context":null,"created":"2017-01-17T16:26:33.249Z","updated":"2017-01-20T19:52:21.591Z","metadata":null,"conditions":" @workouts:Bike","description":null,"dialog_node":"node_3_1484670393109","previous_sibling":"End Exercise"},{"type":"response_condition","go_to":null,"output":{"text":{"values":["Good job!  How long was your walk?","Great!  How long did you walk for?"],"selection_policy":"random"}},"parent":"Exercise Log","context":null,"created":"2017-01-17T16:30:44.344Z","updated":"2017-01-20T19:52:28.335Z","metadata":null,"conditions":" @workouts:Walk","description":null,"dialog_node":"node_5_1484670644197","previous_sibling":"node_4_1484670433961"},{"type":"response_condition","go_to":null,"output":{"text":{"values":["Great!  Thank you for recording your sleep.  Let me know if there is anything else you would like to do.","Fantastic!  Thank you for recording your sleep.  Let me know if there is anything else you would like to do."],"selection_policy":"random"}},"parent":"Sleep log followup","context":null,"created":"2017-01-17T18:40:51.287Z","updated":"2017-01-17T19:04:44.169Z","metadata":null,"conditions":" @sleep_times:Slept","description":null,"dialog_node":"node_12_1484678451728","previous_sibling":null},{"type":"response_condition","go_to":null,"output":{"text":{"values":["Great!  Thank you for recording your sleep.  Let me know if there is anything else you would like to do.","Fantastic!  Thank you for recording your sleep.  Let me know if there is anything else you would like to do."],"selection_policy":"random"}},"parent":"Sleep log followup","context":null,"created":"2017-01-17T18:40:59.974Z","updated":"2017-01-17T19:04:50.035Z","metadata":null,"conditions":" @sleep_times:(Woke up)","description":null,"dialog_node":"node_13_1484678460421","previous_sibling":"node_12_1484678451728"},{"type":"response_condition","go_to":null,"output":{"text":{"values":["Of course I can remind you of things.  What would you like me to remind you?","Sure.  What would you like me to remind you?"],"selection_policy":"random"}},"parent":"Reminder","context":null,"created":"2017-01-17T19:28:43.188Z","updated":"2017-01-24T15:42:39.929Z","metadata":null,"conditions":" ","description":null,"dialog_node":"node_4_1484681323023","previous_sibling":"Reminder Text"},{"type":"response_condition","go_to":null,"output":{"text":{"values":["Of course, which channel?","Sure, what channel?"],"selection_policy":"sequential"}},"parent":"Slack Post","context":null,"created":"2017-01-20T20:45:47.741Z","updated":"2017-01-20T20:46:08.780Z","metadata":null,"conditions":" #slack_post","description":null,"dialog_node":"node_2_1484945147558","previous_sibling":"Cancel Slack Post"},{"type":"response_condition","go_to":null,"output":{"text":{"values":["Okay, what time did you go to sleep?","Thanks, what time did you go to sleep?"],"selection_policy":"sequential"}},"parent":"Sleep log","context":null,"created":"2017-01-17T18:39:30.165Z","updated":"2017-01-17T18:40:19.354Z","metadata":null,"conditions":" @sleep_times:(Woke up)","description":null,"dialog_node":"node_10_1484678370602","previous_sibling":"node_9_1484678360829"},{"type":"response_condition","go_to":null,"output":{"text":{"values":["Okay.  What time did you wake up?","Thanks.  What time did you wake up?"],"selection_policy":"sequential"}},"parent":"Sleep log","context":null,"created":"2017-01-17T18:39:20.435Z","updated":"2017-01-17T18:39:58.491Z","metadata":null,"conditions":" @sleep_times:Slept","description":null,"dialog_node":"node_9_1484678360829","previous_sibling":"Sleep log followup"},{"type":"response_condition","go_to":null,"output":{"text":{"values":["Good job!  How long was your exercise for?","Fantastic!  How long was the exercise for?","Great! How long did you exercise?"],"selection_policy":"random"}},"parent":"Exercise Log","context":null,"created":"2017-01-17T16:31:17.196Z","updated":"2017-01-17T16:31:50.292Z","metadata":null,"conditions":null,"description":null,"dialog_node":"node_6_1484670677050","previous_sibling":"node_5_1484670644197"},{"type":"response_condition","go_to":null,"output":{"text":{"values":["Great job!  It will be recorded.  Is there anything else you want?","Fantastic!  I will record that for you.  Is there anything else you want?","Keep up the good work!  I will log it for you.  Is there anything else you want?"],"selection_policy":"random"}},"parent":"Water amount","context":null,"created":"2017-01-17T16:24:51.887Z","updated":"2017-01-17T19:15:25.747Z","metadata":null,"conditions":" ","description":null,"dialog_node":"node_1_1484670291747","previous_sibling":null},{"type":"response_condition","go_to":null,"output":{"text":{"values":["Lets record your sleep times.  When did you wake up and go to sleep?","Lets record your sleep times.  When did you wake up today?","Lets record your sleep times.  When did you go to sleep yesterday?"],"selection_policy":"sequential"}},"parent":"Health log","context":null,"created":"2017-01-17T16:17:08.399Z","updated":"2017-01-17T16:18:25.159Z","metadata":null,"conditions":" #sleep","description":null,"dialog_node":"node_3_1484669828242","previous_sibling":"Sleep log"}],"workspace_id":"ba7fb238-bd2d-4cb9-9daf-c33c07469636","counterexamples":[]}
\ No newline at end of file
diff --git a/whiskbot-demo-app/Podfile b/whiskbot-demo-app/Podfile
new file mode 100644
index 0000000..7b004b5
--- /dev/null
+++ b/whiskbot-demo-app/Podfile
@@ -0,0 +1,24 @@
+# Uncomment the next line to define a global platform for your project
+# platform :ios, '9.0'
+
+target 'WhiskBot' do
+  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
+  use_frameworks!
+
+  # Pods for WhiskBot
+
+  pod 'JSQMessagesViewController'
+  pod 'OpenWhisk', :git => 'https://github.com/openwhisk/openwhisk-client-swift.git', :tag => '0.2.2'
+  pod 'SwiftyJSON'
+
+  target 'WhiskBotTests' do
+    inherit! :search_paths
+    # Pods for testing
+  end
+
+  target 'WhiskBotUITests' do
+    inherit! :search_paths
+    # Pods for testing
+  end
+
+end
diff --git a/whiskbot-demo-app/Podfile.lock b/whiskbot-demo-app/Podfile.lock
new file mode 100644
index 0000000..e75c511
--- /dev/null
+++ b/whiskbot-demo-app/Podfile.lock
@@ -0,0 +1,31 @@
+PODS:
+  - JSQMessagesViewController (7.3.4):
+    - JSQSystemSoundPlayer (~> 2.0.1)
+  - JSQSystemSoundPlayer (2.0.1)
+  - OpenWhisk (0.2.2)
+  - SwiftyJSON (3.1.4)
+
+DEPENDENCIES:
+  - JSQMessagesViewController
+  - OpenWhisk (from `https://github.com/openwhisk/openwhisk-client-swift.git`, tag `0.2.2`)
+  - SwiftyJSON
+
+EXTERNAL SOURCES:
+  OpenWhisk:
+    :git: https://github.com/openwhisk/openwhisk-client-swift.git
+    :tag: 0.2.2
+
+CHECKOUT OPTIONS:
+  OpenWhisk:
+    :git: https://github.com/openwhisk/openwhisk-client-swift.git
+    :tag: 0.2.2
+
+SPEC CHECKSUMS:
+  JSQMessagesViewController: 39fed975e3c9f8eba7292071e29eeb541d105e66
+  JSQSystemSoundPlayer: c5850e77a4363ffd374cd851154b9af93264ed8d
+  OpenWhisk: 68be4ee6ca258051ee99323bd736317e550d1cf8
+  SwiftyJSON: c2842d878f95482ffceec5709abc3d05680c0220
+
+PODFILE CHECKSUM: de5a42b3844c628073a98f99a25585bf4c0f8131
+
+COCOAPODS: 1.1.1
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Base.lproj/JSQMessages.strings b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Base.lproj/JSQMessages.strings
new file mode 100644
index 0000000..0e8cae0
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Base.lproj/JSQMessages.strings
@@ -0,0 +1,37 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+//  ********************************
+//  Special thanks to the localization contributors!
+//
+//  https://github.com/jessesquires/JSQMessagesViewController/issues/237
+//  ********************************
+
+"load_earlier_messages" = "Load Earlier Messages";
+
+"send" = "Send";
+
+"new_message" = "New Message";
+
+"text_message_accessibility_label" = "%@: %@";
+
+"media_message_accessibility_label" = "%@: media message";
+
+"accessory_button_accessibility_label" = "Share media";
+
+"new_message_received_accessibility_announcement" = "New message received";
\ No newline at end of file
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min.png b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min.png
new file mode 100644
index 0000000..5e6f444
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min.png
Binary files differ
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min@2x.png b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min@2x.png
new file mode 100644
index 0000000..cdeb1f5
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min@2x.png
Binary files differ
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min@3x.png b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min@3x.png
new file mode 100644
index 0000000..6fd3e90
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min@3x.png
Binary files differ
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min_tailless.png b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min_tailless.png
new file mode 100644
index 0000000..db26034
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min_tailless.png
Binary files differ
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min_tailless@2x.png b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min_tailless@2x.png
new file mode 100644
index 0000000..2bfe432
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min_tailless@2x.png
Binary files differ
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min_tailless@3x.png b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min_tailless@3x.png
new file mode 100644
index 0000000..1811c22
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_min_tailless@3x.png
Binary files differ
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_regular.png b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_regular.png
new file mode 100644
index 0000000..eea6cbe
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_regular.png
Binary files differ
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_regular@2x.png b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_regular@2x.png
new file mode 100644
index 0000000..88baedb
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_regular@2x.png
Binary files differ
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_regular@3x.png b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_regular@3x.png
new file mode 100644
index 0000000..7ab50cf
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_regular@3x.png
Binary files differ
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked.png b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked.png
new file mode 100755
index 0000000..6b0d77f
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked.png
Binary files differ
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked@2x.png b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked@2x.png
new file mode 100755
index 0000000..fdaab00
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked@2x.png
Binary files differ
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked@3x.png b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked@3x.png
new file mode 100644
index 0000000..41ce178
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked@3x.png
Binary files differ
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked_tailless.png b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked_tailless.png
new file mode 100755
index 0000000..67f03a9
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked_tailless.png
Binary files differ
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked_tailless@2x.png b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked_tailless@2x.png
new file mode 100755
index 0000000..158c183
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked_tailless@2x.png
Binary files differ
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked_tailless@3x.png b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked_tailless@3x.png
new file mode 100644
index 0000000..170c164
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_stroked_tailless@3x.png
Binary files differ
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_tailless.png b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_tailless.png
new file mode 100644
index 0000000..9445eec
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_tailless.png
Binary files differ
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_tailless@2x.png b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_tailless@2x.png
new file mode 100644
index 0000000..297764d
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_tailless@2x.png
Binary files differ
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_tailless@3x.png b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_tailless@3x.png
new file mode 100644
index 0000000..c968c39
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/bubble_tailless@3x.png
Binary files differ
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/clip.png b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/clip.png
new file mode 100644
index 0000000..8506bbe
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/clip.png
Binary files differ
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/clip@2x.png b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/clip@2x.png
new file mode 100644
index 0000000..58ba9f5
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/clip@2x.png
Binary files differ
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/clip@3x.png b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/clip@3x.png
new file mode 100644
index 0000000..caba662
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/clip@3x.png
Binary files differ
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/pause.png b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/pause.png
new file mode 100644
index 0000000..487a308
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/pause.png
Binary files differ
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/pause@2x.png b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/pause@2x.png
new file mode 100644
index 0000000..8f5a3c2
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/pause@2x.png
Binary files differ
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/pause@3x.png b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/pause@3x.png
new file mode 100644
index 0000000..a15cadd
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/pause@3x.png
Binary files differ
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/play.png b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/play.png
new file mode 100644
index 0000000..3bd7045
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/play.png
Binary files differ
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/play@2x.png b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/play@2x.png
new file mode 100644
index 0000000..c769e68
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/play@2x.png
Binary files differ
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/play@3x.png b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/play@3x.png
new file mode 100644
index 0000000..53fb82a
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/play@3x.png
Binary files differ
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/typing.png b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/typing.png
new file mode 100644
index 0000000..87e68db
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/typing.png
Binary files differ
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/typing@2x.png b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/typing@2x.png
new file mode 100644
index 0000000..1c8788d
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/typing@2x.png
Binary files differ
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/typing@3x.png b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/typing@3x.png
new file mode 100644
index 0000000..3849eb1
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Images/typing@3x.png
Binary files differ
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Sounds/message_received.aiff b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Sounds/message_received.aiff
new file mode 100644
index 0000000..ab73ce2
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Sounds/message_received.aiff
Binary files differ
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Sounds/message_sent.aiff b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Sounds/message_sent.aiff
new file mode 100644
index 0000000..e46adff
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/Sounds/message_sent.aiff
Binary files differ
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/ar.lproj/JSQMessages.strings b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/ar.lproj/JSQMessages.strings
new file mode 100644
index 0000000..f064e05
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/ar.lproj/JSQMessages.strings
@@ -0,0 +1,29 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+//  ********************************
+//  Special thanks to the localization contributors!
+//
+//  https://github.com/jessesquires/JSQMessagesViewController/issues/237
+//  ********************************
+
+"load_earlier_messages" = "تحميل الرسائل السابقة";
+
+"send" = "أرسال";
+
+"new_message" = "رسالة جديدة";
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/de.lproj/JSQMessages.strings b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/de.lproj/JSQMessages.strings
new file mode 100644
index 0000000..8e4ded2
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/de.lproj/JSQMessages.strings
@@ -0,0 +1,37 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+//  ********************************
+//  Special thanks to the localization contributors!
+//
+//  https://github.com/jessesquires/JSQMessagesViewController/issues/237
+//  ********************************
+
+"load_earlier_messages" = "Ältere Nachrichten laden";
+
+"send" = "Senden";
+
+"new_message" = "Neue Nachricht";
+
+"text_message_accessibility_label" = "%@: %@";
+
+"media_message_accessibility_label" = "%@: media Nachricht";
+
+"accessory_button_accessibility_label" = "Aktien media";
+
+"new_message_received_accessibility_announcement" = "Neue Nachricht empfangen";
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/en.lproj/JSQMessages.strings b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/en.lproj/JSQMessages.strings
new file mode 100644
index 0000000..0e8cae0
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/en.lproj/JSQMessages.strings
@@ -0,0 +1,37 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+//  ********************************
+//  Special thanks to the localization contributors!
+//
+//  https://github.com/jessesquires/JSQMessagesViewController/issues/237
+//  ********************************
+
+"load_earlier_messages" = "Load Earlier Messages";
+
+"send" = "Send";
+
+"new_message" = "New Message";
+
+"text_message_accessibility_label" = "%@: %@";
+
+"media_message_accessibility_label" = "%@: media message";
+
+"accessory_button_accessibility_label" = "Share media";
+
+"new_message_received_accessibility_announcement" = "New message received";
\ No newline at end of file
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/es.lproj/JSQMessages.strings b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/es.lproj/JSQMessages.strings
new file mode 100644
index 0000000..9386beb
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/es.lproj/JSQMessages.strings
@@ -0,0 +1,37 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+//  ********************************
+//  Special thanks to the localization contributors!
+//
+//  https://github.com/jessesquires/JSQMessagesViewController/issues/237
+//  ********************************
+
+"load_earlier_messages" = "Cargar mensajes anteriores";
+
+"send" = "Enviar";
+
+"new_message" = "Nuevo mensaje";
+
+"text_message_accessibility_label" = "%@: %@";
+
+"media_message_accessibility_label" = "%@: imagen";
+
+"accessory_button_accessibility_label" = "Intercambio de archivos";
+
+"new_message_received_accessibility_announcement" = "mensaje recibido";
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/fi.lproj/JSQMessages.strings b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/fi.lproj/JSQMessages.strings
new file mode 100644
index 0000000..889cffb
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/fi.lproj/JSQMessages.strings
@@ -0,0 +1,29 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+//  ********************************
+//  Special thanks to the localization contributors!
+//
+//  https://github.com/jessesquires/JSQMessagesViewController/issues/237
+//  ********************************
+
+"load_earlier_messages" = "Lataa aiempia viestejä";
+
+"send" = "Lähetä";
+
+"new_message" = "Uusi viesti";
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/fr.lproj/JSQMessages.strings b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/fr.lproj/JSQMessages.strings
new file mode 100644
index 0000000..e0933be
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/fr.lproj/JSQMessages.strings
@@ -0,0 +1,37 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+//  ********************************
+//  Special thanks to the localization contributors!
+//
+//  https://github.com/jessesquires/JSQMessagesViewController/issues/237
+//  ********************************
+
+"load_earlier_messages" = "Messages précedents";
+
+"send" = "Envoyer";
+
+"new_message" = "Nouveau message";
+
+"text_message_accessibility_label" = "%@: %@";
+
+"media_message_accessibility_label" = "%@: image";
+
+"accessory_button_accessibility_label" = "Partager fichier";
+
+"new_message_received_accessibility_announcement" = "Nouveau message reçu";
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/he.lproj/JSQMessages.strings b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/he.lproj/JSQMessages.strings
new file mode 100644
index 0000000..95b1dd9
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/he.lproj/JSQMessages.strings
@@ -0,0 +1,29 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+//  ********************************
+//  Special thanks to the localization contributors!
+//
+//  https://github.com/jessesquires/JSQMessagesViewController/issues/237
+//  ********************************
+
+"load_earlier_messages" = "טען הודעות קודמות";
+
+"send" = "שלח";
+
+"new_message" = "הודעה חדשה";
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/id.lproj/JSQMessages.strings b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/id.lproj/JSQMessages.strings
new file mode 100644
index 0000000..5536d5f
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/id.lproj/JSQMessages.strings
@@ -0,0 +1,29 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+//  ********************************
+//  Special thanks to the localization contributors!
+//
+//  https://github.com/jessesquires/JSQMessagesViewController/issues/237
+//  ********************************
+
+"load_earlier_messages" = "Muat Pesan Sebelumnya";
+
+"send" = "Kirim";
+
+"new_message" = "Pesan Baru";
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/it.lproj/JSQMessages.strings b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/it.lproj/JSQMessages.strings
new file mode 100644
index 0000000..5afaeba
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/it.lproj/JSQMessages.strings
@@ -0,0 +1,29 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+//  ********************************
+//  Special thanks to the localization contributors!
+//
+//  https://github.com/jessesquires/JSQMessagesViewController/issues/237
+//  ********************************
+
+"load_earlier_messages" = "Carica messaggi precedenti";
+
+"send" = "Invia";
+
+"new_message" = "Nuovo Messaggio";
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/ja.lproj/JSQMessages.strings b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/ja.lproj/JSQMessages.strings
new file mode 100644
index 0000000..f0073b6
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/ja.lproj/JSQMessages.strings
@@ -0,0 +1,29 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+//  ********************************
+//  Special thanks to the localization contributors!
+//
+//  https://github.com/jessesquires/JSQMessagesViewController/issues/237
+//  ********************************
+
+"load_earlier_messages" = "古いメッセージを読み込む";
+
+"send" = "送信";
+
+"new_message" = "新しいメッセージ";
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/ko.lproj/JSQMessages.strings b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/ko.lproj/JSQMessages.strings
new file mode 100644
index 0000000..5e2727b
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/ko.lproj/JSQMessages.strings
@@ -0,0 +1,29 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+//  ********************************
+//  Special thanks to the localization contributors!
+//
+//  https://github.com/jessesquires/JSQMessagesViewController/issues/237
+//  ********************************
+
+"load_earlier_messages" = "이전 메시지 불러오기";
+
+"send" = "전송";
+
+"new_message" = "새로운 메시지";
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/ms.lproj/JSQMessages.strings b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/ms.lproj/JSQMessages.strings
new file mode 100644
index 0000000..d1e4084
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/ms.lproj/JSQMessages.strings
@@ -0,0 +1,29 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+//  ********************************
+//  Special thanks to the localization contributors!
+//
+//  https://github.com/jessesquires/JSQMessagesViewController/issues/237
+//  ********************************
+
+"load_earlier_messages" = "Muat Turun Mesej Lama";
+
+"send" = "Hantar";
+
+"new_message" = "Mesej Baru";
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/nb.lproj/JSQMessages.strings b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/nb.lproj/JSQMessages.strings
new file mode 100644
index 0000000..e943a55
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/nb.lproj/JSQMessages.strings
@@ -0,0 +1,37 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+//  ********************************
+//  Special thanks to the localization contributors!
+//
+//  https://github.com/jessesquires/JSQMessagesViewController/issues/237
+//  ********************************
+
+"load_earlier_messages" = "Last tidligere beskjeder";
+
+"send" = "Send";
+
+"new_message" = "Ny melding";
+
+"text_message_accessibility_label" = "%@: %@";
+
+"media_message_accessibility_label" = "%@: mediamelding";
+
+"accessory_button_accessibility_label" = "Del media";
+
+"new_message_received_accessibility_announcement" = "Ny melding mottatt";
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/nl.lproj/JSQMessages.strings b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/nl.lproj/JSQMessages.strings
new file mode 100644
index 0000000..616daf5
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/nl.lproj/JSQMessages.strings
@@ -0,0 +1,29 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+//  ********************************
+//  Special thanks to the localization contributors!
+//
+//  https://github.com/jessesquires/JSQMessagesViewController/issues/237
+//  ********************************
+
+"load_earlier_messages" = "Laad eerdere berichten";
+
+"send" = "Stuur";
+
+"new_message" = "Nieuw bericht";
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/pl.lproj/JSQMessages.strings b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/pl.lproj/JSQMessages.strings
new file mode 100644
index 0000000..8cb36c3
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/pl.lproj/JSQMessages.strings
@@ -0,0 +1,29 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+//  ********************************
+//  Special thanks to the localization contributors!
+//
+//  https://github.com/jessesquires/JSQMessagesViewController/issues/237
+//  ********************************
+
+"load_earlier_messages" = "Otwórz wcześniejsze wiadomości";
+
+"send" = "Wyślij";
+
+"new_message" = "Nowa wiadomość";
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/pt.lproj/JSQMessages.strings b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/pt.lproj/JSQMessages.strings
new file mode 100644
index 0000000..d06d434
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/pt.lproj/JSQMessages.strings
@@ -0,0 +1,29 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+//  ********************************
+//  Special thanks to the localization contributors!
+//
+//  https://github.com/jessesquires/JSQMessagesViewController/issues/237
+//  ********************************
+
+"load_earlier_messages" = "Carregar mensagens anteriores";
+
+"send" = "Enviar";
+
+"new_message" = "Nova Mensagem";
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/ro.lproj/JSQMessages.strings b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/ro.lproj/JSQMessages.strings
new file mode 100644
index 0000000..e9add82
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/ro.lproj/JSQMessages.strings
@@ -0,0 +1,29 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+//  ********************************
+//  Special thanks to the localization contributors!
+//
+//  https://github.com/jessesquires/JSQMessagesViewController/issues/237
+//  ********************************
+
+"load_earlier_messages" = "Încărcați mesajele anterioare";
+
+"send" = "Trimiteți";
+
+"new_message" = "Mesaj nou";
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/ru.lproj/JSQMessages.strings b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/ru.lproj/JSQMessages.strings
new file mode 100644
index 0000000..fbc90bf
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/ru.lproj/JSQMessages.strings
@@ -0,0 +1,29 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+//  ********************************
+//  Special thanks to the localization contributors!
+//
+//  https://github.com/jessesquires/JSQMessagesViewController/issues/237
+//  ********************************
+
+"load_earlier_messages" = "Предыдущие сообщения";
+
+"send" = "Отпр";
+
+"new_message" = "Сообщение";
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/th.lproj/JSQMessages.strings b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/th.lproj/JSQMessages.strings
new file mode 100644
index 0000000..bc91419
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/th.lproj/JSQMessages.strings
@@ -0,0 +1,29 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+//  ********************************
+//  Special thanks to the localization contributors!
+//
+//  https://github.com/jessesquires/JSQMessagesViewController/issues/237
+//  ********************************
+
+"load_earlier_messages" = "โหลดข้อความก่อนหน้า";
+
+"send" = "ส่ง";
+
+"new_message" = "ข้อความใหม่";
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/tr.lproj/JSQMessages.strings b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/tr.lproj/JSQMessages.strings
new file mode 100644
index 0000000..44a05ea
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/tr.lproj/JSQMessages.strings
@@ -0,0 +1,29 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+//  ********************************
+//  Special thanks to the localization contributors!
+//
+//  https://github.com/jessesquires/JSQMessagesViewController/issues/237
+//  ********************************
+
+"load_earlier_messages" = "Eski mesajları yükle";
+
+"send" = "Gönder";
+
+"new_message" = "Yeni Mesaj";
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/vi.lproj/JSQMessages.strings b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/vi.lproj/JSQMessages.strings
new file mode 100644
index 0000000..f75e623
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/vi.lproj/JSQMessages.strings
@@ -0,0 +1,29 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+//  ********************************
+//  Special thanks to the localization contributors!
+//
+//  https://github.com/jessesquires/JSQMessagesViewController/issues/237
+//  ********************************
+
+"load_earlier_messages" = "Tải thêm tin nhắn";
+
+"send" = "Gửi";
+
+"new_message" = "Tin nhắn mới";
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/zh-Hans.lproj/JSQMessages.strings b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/zh-Hans.lproj/JSQMessages.strings
new file mode 100644
index 0000000..78af78f
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/zh-Hans.lproj/JSQMessages.strings
@@ -0,0 +1,29 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+//  ********************************
+//  Special thanks to the localization contributors!
+//
+//  https://github.com/jessesquires/JSQMessagesViewController/issues/237
+//  ********************************
+
+"load_earlier_messages" = "载入较早的信息";
+
+"send" = "发送";
+
+"new_message" = "新信息";
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/zh-Hant.lproj/JSQMessages.strings b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/zh-Hant.lproj/JSQMessages.strings
new file mode 100644
index 0000000..924bf6a
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle/zh-Hant.lproj/JSQMessages.strings
@@ -0,0 +1,29 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+//  ********************************
+//  Special thanks to the localization contributors!
+//
+//  https://github.com/jessesquires/JSQMessagesViewController/issues/237
+//  ********************************
+
+"load_earlier_messages" = "載入之前的訊息";
+
+"send" = "傳送";
+
+"new_message" = "新信息";
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/JSQSystemSoundPlayer+JSQMessages.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/JSQSystemSoundPlayer+JSQMessages.h
new file mode 100644
index 0000000..0931b1e
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/JSQSystemSoundPlayer+JSQMessages.h
@@ -0,0 +1,43 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <JSQSystemSoundPlayer/JSQSystemSoundPlayer.h>
+
+@interface JSQSystemSoundPlayer (JSQMessages)
+
+/**
+ *  Plays the default sound for received messages.
+ */
++ (void)jsq_playMessageReceivedSound;
+
+/**
+ *  Plays the default sound for received messages *as an alert*, invoking device vibration if available.
+ */
++ (void)jsq_playMessageReceivedAlert;
+
+/**
+ *  Plays the default sound for sent messages.
+ */
++ (void)jsq_playMessageSentSound;
+
+/**
+ *  Plays the default sound for sent messages *as an alert*, invoking device vibration if available.
+ */
++ (void)jsq_playMessageSentAlert;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/JSQSystemSoundPlayer+JSQMessages.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/JSQSystemSoundPlayer+JSQMessages.m
new file mode 100644
index 0000000..7f87e25
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/JSQSystemSoundPlayer+JSQMessages.m
@@ -0,0 +1,75 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQSystemSoundPlayer+JSQMessages.h"
+
+#import "NSBundle+JSQMessages.h"
+
+
+static NSString * const kJSQMessageReceivedSoundName = @"message_received";
+static NSString * const kJSQMessageSentSoundName = @"message_sent";
+
+
+@implementation JSQSystemSoundPlayer (JSQMessages)
+
+#pragma mark - Public
+
++ (void)jsq_playMessageReceivedSound
+{
+    [self jsq_playSoundFromJSQMessagesBundleWithName:kJSQMessageReceivedSoundName asAlert:NO];
+}
+
++ (void)jsq_playMessageReceivedAlert
+{
+    [self jsq_playSoundFromJSQMessagesBundleWithName:kJSQMessageReceivedSoundName asAlert:YES];
+}
+
++ (void)jsq_playMessageSentSound
+{
+    [self jsq_playSoundFromJSQMessagesBundleWithName:kJSQMessageSentSoundName asAlert:NO];
+}
+
++ (void)jsq_playMessageSentAlert
+{
+    [self jsq_playSoundFromJSQMessagesBundleWithName:kJSQMessageSentSoundName asAlert:YES];
+}
+
+#pragma mark - Private
+
++ (void)jsq_playSoundFromJSQMessagesBundleWithName:(NSString *)soundName asAlert:(BOOL)asAlert
+{
+    //  save sound player original bundle
+    NSString *originalPlayerBundleIdentifier = [JSQSystemSoundPlayer sharedPlayer].bundle.bundleIdentifier;
+    
+    //  search for sounds in this library's bundle
+    [JSQSystemSoundPlayer sharedPlayer].bundle = [NSBundle jsq_messagesBundle];
+    
+    NSString *fileName = [NSString stringWithFormat:@"JSQMessagesAssets.bundle/Sounds/%@", soundName];
+    
+    if (asAlert) {
+        [[JSQSystemSoundPlayer sharedPlayer] playAlertSoundWithFilename:fileName fileExtension:kJSQSystemSoundTypeAIFF];
+    }
+    else {
+        [[JSQSystemSoundPlayer sharedPlayer] playSoundWithFilename:fileName fileExtension:kJSQSystemSoundTypeAIFF];
+    }
+    
+    //  restore original bundle
+    [JSQSystemSoundPlayer sharedPlayer].bundle = [NSBundle bundleWithIdentifier:originalPlayerBundleIdentifier];
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/NSBundle+JSQMessages.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/NSBundle+JSQMessages.h
new file mode 100644
index 0000000..f93be05
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/NSBundle+JSQMessages.h
@@ -0,0 +1,42 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <Foundation/Foundation.h>
+
+@interface NSBundle (JSQMessages)
+
+/**
+ *  @return The bundle for JSQMessagesViewController.
+ */
++ (NSBundle *)jsq_messagesBundle;
+
+/**
+ *  @return The bundle for assets in JSQMessagesViewController.
+ */
++ (NSBundle *)jsq_messagesAssetBundle;
+
+/**
+ *  Returns a localized version of the string designated by the specified key and residing in the JSQMessages table.
+ *
+ *  @param key The key for a string in the JSQMessages table.
+ *
+ *  @return A localized version of the string designated by key in the JSQMessages table.
+ */
++ (NSString *)jsq_localizedStringForKey:(NSString *)key;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/NSBundle+JSQMessages.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/NSBundle+JSQMessages.m
new file mode 100644
index 0000000..97654f7
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/NSBundle+JSQMessages.m
@@ -0,0 +1,42 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "NSBundle+JSQMessages.h"
+
+#import "JSQMessagesViewController.h"
+
+@implementation NSBundle (JSQMessages)
+
++ (NSBundle *)jsq_messagesBundle
+{
+    return [NSBundle bundleForClass:[JSQMessagesViewController class]];
+}
+
++ (NSBundle *)jsq_messagesAssetBundle
+{
+    NSString *bundleResourcePath = [NSBundle jsq_messagesBundle].resourcePath;
+    NSString *assetPath = [bundleResourcePath stringByAppendingPathComponent:@"JSQMessagesAssets.bundle"];
+    return [NSBundle bundleWithPath:assetPath];
+}
+
++ (NSString *)jsq_localizedStringForKey:(NSString *)key
+{
+    return NSLocalizedStringFromTableInBundle(key, @"JSQMessages", [NSBundle jsq_messagesAssetBundle], nil);
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/NSString+JSQMessages.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/NSString+JSQMessages.h
new file mode 100644
index 0000000..ba48672
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/NSString+JSQMessages.h
@@ -0,0 +1,28 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <Foundation/Foundation.h>
+
+@interface NSString (JSQMessages)
+
+/**
+ *  @return A copy of the receiver with all leading and trailing whitespace removed.
+ */
+- (NSString *)jsq_stringByTrimingWhitespace;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/NSString+JSQMessages.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/NSString+JSQMessages.m
new file mode 100644
index 0000000..02c7044
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/NSString+JSQMessages.m
@@ -0,0 +1,28 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "NSString+JSQMessages.h"
+
+@implementation NSString (JSQMessages)
+
+- (NSString *)jsq_stringByTrimingWhitespace
+{
+    return [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/UIColor+JSQMessages.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/UIColor+JSQMessages.h
new file mode 100644
index 0000000..0dc5798
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/UIColor+JSQMessages.h
@@ -0,0 +1,56 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <UIKit/UIKit.h>
+
+@interface UIColor (JSQMessages)
+
+#pragma mark - Message bubble colors
+
+/**
+ *  @return A color object containing HSB values similar to the iOS 7 messages app green bubble color.
+ */
++ (UIColor *)jsq_messageBubbleGreenColor;
+
+/**
+ *  @return A color object containing HSB values similar to the iOS 7 messages app blue bubble color.
+ */
++ (UIColor *)jsq_messageBubbleBlueColor;
+
+/**
+ *  @return A color object containing HSB values similar to the iOS 7 red color.
+ */
++ (UIColor *)jsq_messageBubbleRedColor;
+
+/**
+ *  @return A color object containing HSB values similar to the iOS 7 messages app light gray bubble color.
+ */
++ (UIColor *)jsq_messageBubbleLightGrayColor;
+
+#pragma mark - Utilities
+
+/**
+ *  Creates and returns a new color object whose brightness component is decreased by the given value, using the initial color values of the receiver.
+ *
+ *  @param value A floating point value describing the amount by which to decrease the brightness of the receiver.
+ *
+ *  @return A new color object whose brightness is decreased by the given values. The other color values remain the same as the receiver.
+ */
+- (UIColor *)jsq_colorByDarkeningColorWithValue:(CGFloat)value;
+
+@end
\ No newline at end of file
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/UIColor+JSQMessages.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/UIColor+JSQMessages.m
new file mode 100644
index 0000000..9e254ac
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/UIColor+JSQMessages.m
@@ -0,0 +1,90 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "UIColor+JSQMessages.h"
+
+@implementation UIColor (JSQMessages)
+
+#pragma mark - Message bubble colors
+
++ (UIColor *)jsq_messageBubbleGreenColor
+{
+    return [UIColor colorWithHue:130.0f / 360.0f
+                      saturation:0.68f
+                      brightness:0.84f
+                           alpha:1.0f];
+}
+
++ (UIColor *)jsq_messageBubbleBlueColor
+{
+    return [UIColor colorWithHue:210.0f / 360.0f
+                      saturation:0.94f
+                      brightness:1.0f
+                           alpha:1.0f];
+}
+
++ (UIColor *)jsq_messageBubbleRedColor
+{
+    return [UIColor colorWithHue:0.0f / 360.0f
+                      saturation:0.79f
+                      brightness:1.0f
+                           alpha:1.0f];
+}
+
++ (UIColor *)jsq_messageBubbleLightGrayColor
+{
+    return [UIColor colorWithHue:240.0f / 360.0f
+                      saturation:0.02f
+                      brightness:0.92f
+                           alpha:1.0f];
+}
+
+#pragma mark - Utilities
+
+- (UIColor *)jsq_colorByDarkeningColorWithValue:(CGFloat)value
+{
+    NSUInteger totalComponents = CGColorGetNumberOfComponents(self.CGColor);
+    BOOL isGreyscale = (totalComponents == 2) ? YES : NO;
+    
+    CGFloat *oldComponents = (CGFloat *)CGColorGetComponents(self.CGColor);
+    CGFloat newComponents[4];
+    
+    if (isGreyscale) {
+        newComponents[0] = oldComponents[0] - value < 0.0f ? 0.0f : oldComponents[0] - value;
+        newComponents[1] = oldComponents[0] - value < 0.0f ? 0.0f : oldComponents[0] - value;
+        newComponents[2] = oldComponents[0] - value < 0.0f ? 0.0f : oldComponents[0] - value;
+        newComponents[3] = oldComponents[1];
+    }
+    else {
+        newComponents[0] = oldComponents[0] - value < 0.0f ? 0.0f : oldComponents[0] - value;
+        newComponents[1] = oldComponents[1] - value < 0.0f ? 0.0f : oldComponents[1] - value;
+        newComponents[2] = oldComponents[2] - value < 0.0f ? 0.0f : oldComponents[2] - value;
+        newComponents[3] = oldComponents[3];
+    }
+    
+    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
+	CGColorRef newColor = CGColorCreate(colorSpace, newComponents);
+	CGColorSpaceRelease(colorSpace);
+    
+	UIColor *retColor = [UIColor colorWithCGColor:newColor];
+	CGColorRelease(newColor);
+    
+    return retColor;
+}
+
+@end
\ No newline at end of file
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/UIDevice+JSQMessages.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/UIDevice+JSQMessages.h
new file mode 100644
index 0000000..fa86223
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/UIDevice+JSQMessages.h
@@ -0,0 +1,33 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <UIKit/UIKit.h>
+
+@interface UIDevice (JSQMessages)
+
+/**
+ *  @return Whether or not the current device is running a version of iOS before 8.0.
+ */
++ (BOOL)jsq_isCurrentDeviceBeforeiOS8;
+
+/**
+ *  @return Whether or not the current device is running a version of iOS after 9.0.
+ */
++ (BOOL)jsq_isCurrentDeviceAfteriOS9;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/UIDevice+JSQMessages.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/UIDevice+JSQMessages.m
new file mode 100644
index 0000000..b09336f
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/UIDevice+JSQMessages.m
@@ -0,0 +1,35 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "UIDevice+JSQMessages.h"
+
+@implementation UIDevice (JSQMessages)
+
++ (BOOL)jsq_isCurrentDeviceBeforeiOS8
+{
+    // iOS < 8.0
+    return [[UIDevice currentDevice].systemVersion compare:@"8.0" options:NSNumericSearch] == NSOrderedAscending;
+}
+
++ (BOOL)jsq_isCurrentDeviceAfteriOS9
+{
+    // iOS > 9.0
+    return [[UIDevice currentDevice].systemVersion compare:@"9.0" options:NSNumericSearch] == NSOrderedDescending;
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/UIImage+JSQMessages.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/UIImage+JSQMessages.h
new file mode 100644
index 0000000..6d57c0e
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/UIImage+JSQMessages.h
@@ -0,0 +1,84 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <UIKit/UIKit.h>
+
+@interface UIImage (JSQMessages)
+
+/**
+ *  Creates and returns a new image object that is masked with the specified mask color.
+ *
+ *  @param maskColor The color value for the mask. This value must not be `nil`.
+ *
+ *  @return A new image object masked with the specified color.
+ */
+- (UIImage *)jsq_imageMaskedWithColor:(UIColor *)maskColor;
+
+/**
+ *  @return The regular message bubble image.
+ */
++ (UIImage *)jsq_bubbleRegularImage;
+
+/**
+ *  @return The regular message bubble image without a tail.
+ */
++ (UIImage *)jsq_bubbleRegularTaillessImage;
+
+/**
+ *  @return The regular message bubble image stroked, not filled.
+ */
++ (UIImage *)jsq_bubbleRegularStrokedImage;
+
+/**
+ *  @return The regular message bubble image stroked, not filled and without a tail.
+ */
++ (UIImage *)jsq_bubbleRegularStrokedTaillessImage;
+
+/**
+ *  @return The compact message bubble image. 
+ *
+ *  @discussion This is the default bubble image used by `JSQMessagesBubbleImageFactory`.
+ */
++ (UIImage *)jsq_bubbleCompactImage;
+
+/**
+ *  @return The compact message bubble image without a tail.
+ */
++ (UIImage *)jsq_bubbleCompactTaillessImage;
+
+/**
+ *  @return The default input toolbar accessory image.
+ */
++ (UIImage *)jsq_defaultAccessoryImage;
+
+/**
+ *  @return The default typing indicator image.
+ */
++ (UIImage *)jsq_defaultTypingIndicatorImage;
+
+/**
+ *  @return The default play icon image.
+ */
++ (UIImage *)jsq_defaultPlayImage;
+
+/**
+ *  @return The default pause icon image.
+ */
++ (UIImage *)jsq_defaultPauseImage;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/UIImage+JSQMessages.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/UIImage+JSQMessages.m
new file mode 100644
index 0000000..f3f3e09
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/UIImage+JSQMessages.m
@@ -0,0 +1,108 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "UIImage+JSQMessages.h"
+
+#import "NSBundle+JSQMessages.h"
+
+
+@implementation UIImage (JSQMessages)
+
+- (UIImage *)jsq_imageMaskedWithColor:(UIColor *)maskColor
+{
+    NSParameterAssert(maskColor != nil);
+    
+    CGRect imageRect = CGRectMake(0.0f, 0.0f, self.size.width, self.size.height);
+    UIImage *newImage = nil;
+    
+    UIGraphicsBeginImageContextWithOptions(imageRect.size, NO, self.scale);
+    {
+        CGContextRef context = UIGraphicsGetCurrentContext();
+        
+        CGContextScaleCTM(context, 1.0f, -1.0f);
+        CGContextTranslateCTM(context, 0.0f, -(imageRect.size.height));
+        
+        CGContextClipToMask(context, imageRect, self.CGImage);
+        CGContextSetFillColorWithColor(context, maskColor.CGColor);
+        CGContextFillRect(context, imageRect);
+        
+        newImage = UIGraphicsGetImageFromCurrentImageContext();
+    }
+    UIGraphicsEndImageContext();
+    
+    return newImage;
+}
+
++ (UIImage *)jsq_bubbleImageFromBundleWithName:(NSString *)name
+{
+    NSBundle *bundle = [NSBundle jsq_messagesAssetBundle];
+    NSString *path = [bundle pathForResource:name ofType:@"png" inDirectory:@"Images"];
+    return [UIImage imageWithContentsOfFile:path];
+}
+
++ (UIImage *)jsq_bubbleRegularImage
+{
+    return [UIImage jsq_bubbleImageFromBundleWithName:@"bubble_regular"];
+}
+
++ (UIImage *)jsq_bubbleRegularTaillessImage
+{
+    return [UIImage jsq_bubbleImageFromBundleWithName:@"bubble_tailless"];
+}
+
++ (UIImage *)jsq_bubbleRegularStrokedImage
+{
+    return [UIImage jsq_bubbleImageFromBundleWithName:@"bubble_stroked"];
+}
+
++ (UIImage *)jsq_bubbleRegularStrokedTaillessImage
+{
+    return [UIImage jsq_bubbleImageFromBundleWithName:@"bubble_stroked_tailless"];
+}
+
++ (UIImage *)jsq_bubbleCompactImage
+{
+    return [UIImage jsq_bubbleImageFromBundleWithName:@"bubble_min"];
+}
+
++ (UIImage *)jsq_bubbleCompactTaillessImage
+{
+    return [UIImage jsq_bubbleImageFromBundleWithName:@"bubble_min_tailless"];
+}
+
++ (UIImage *)jsq_defaultAccessoryImage
+{
+    return [UIImage jsq_bubbleImageFromBundleWithName:@"clip"];
+}
+
++ (UIImage *)jsq_defaultTypingIndicatorImage
+{
+    return [UIImage jsq_bubbleImageFromBundleWithName:@"typing"];
+}
+
++ (UIImage *)jsq_defaultPlayImage
+{
+    return [UIImage jsq_bubbleImageFromBundleWithName:@"play"];
+}
+
++ (UIImage *)jsq_defaultPauseImage
+{
+    return [UIImage jsq_bubbleImageFromBundleWithName:@"pause"];
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/UIView+JSQMessages.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/UIView+JSQMessages.h
new file mode 100644
index 0000000..2001010
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/UIView+JSQMessages.h
@@ -0,0 +1,38 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <UIKit/UIKit.h>
+
+@interface UIView (JSQMessages)
+
+/**
+ *  Pins the subview of the receiver to the edge of its frame, as specified by the given attribute, by adding a layout constraint.
+ *
+ *  @param subview   The subview to which the receiver will be pinned.
+ *  @param attribute The layout constraint attribute specifying one of `NSLayoutAttributeBottom`, `NSLayoutAttributeTop`, `NSLayoutAttributeLeading`, `NSLayoutAttributeTrailing`.
+ */
+- (void)jsq_pinSubview:(UIView *)subview toEdge:(NSLayoutAttribute)attribute;
+
+/**
+ *  Pins all edges of the specified subview to the receiver.
+ *
+ *  @param subview The subview to which the receiver will be pinned.
+ */
+- (void)jsq_pinAllEdgesOfSubview:(UIView *)subview;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/UIView+JSQMessages.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/UIView+JSQMessages.m
new file mode 100644
index 0000000..300f76e
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Categories/UIView+JSQMessages.m
@@ -0,0 +1,42 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "UIView+JSQMessages.h"
+
+@implementation UIView (JSQMessages)
+
+- (void)jsq_pinSubview:(UIView *)subview toEdge:(NSLayoutAttribute)attribute
+{
+    [self addConstraint:[NSLayoutConstraint constraintWithItem:self
+                                                     attribute:attribute
+                                                     relatedBy:NSLayoutRelationEqual
+                                                        toItem:subview
+                                                     attribute:attribute
+                                                    multiplier:1.0f
+                                                      constant:0.0f]];
+}
+
+- (void)jsq_pinAllEdgesOfSubview:(UIView *)subview
+{
+    [self jsq_pinSubview:subview toEdge:NSLayoutAttributeBottom];
+    [self jsq_pinSubview:subview toEdge:NSLayoutAttributeTop];
+    [self jsq_pinSubview:subview toEdge:NSLayoutAttributeLeading];
+    [self jsq_pinSubview:subview toEdge:NSLayoutAttributeTrailing];
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Controllers/JSQMessagesKeyboardController.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Controllers/JSQMessagesKeyboardController.h
new file mode 100644
index 0000000..81c0c02
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Controllers/JSQMessagesKeyboardController.h
@@ -0,0 +1,143 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+//
+//  Ideas for keyboard controller taken from Daniel Amitay
+//  DAKeyboardControl
+//  https://github.com/danielamitay/DAKeyboardControl
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+@class JSQMessagesKeyboardController;
+
+/**
+ *  Posted when the system keyboard frame changes.
+ *  The object of the notification is the `JSQMessagesKeyboardController` object. 
+ *  The `userInfo` dictionary contains the new keyboard frame for key
+ *  `JSQMessagesKeyboardControllerUserInfoKeyKeyboardDidChangeFrame`.
+ */
+FOUNDATION_EXPORT NSString * const JSQMessagesKeyboardControllerNotificationKeyboardDidChangeFrame;
+
+/**
+ *  Contains the new keyboard frame wrapped in an `NSValue` object.
+ */
+FOUNDATION_EXPORT NSString * const JSQMessagesKeyboardControllerUserInfoKeyKeyboardDidChangeFrame;
+
+
+/**
+ *  The `JSQMessagesKeyboardControllerDelegate` protocol defines methods that 
+ *  allow you to respond to the frame change events of the system keyboard.
+ *
+ *  A `JSQMessagesKeyboardController` object also posts the `JSQMessagesKeyboardControllerNotificationKeyboardDidChangeFrame`
+ *  in response to frame change events of the system keyboard.
+ */
+@protocol JSQMessagesKeyboardControllerDelegate <NSObject>
+
+@required
+
+/**
+ *  Tells the delegate that the keyboard frame has changed.
+ *
+ *  @param keyboardController The keyboard controller that is notifying the delegate.
+ *  @param keyboardFrame      The new frame of the keyboard in the coordinate system of the `contextView`.
+ */
+- (void)keyboardController:(JSQMessagesKeyboardController *)keyboardController keyboardDidChangeFrame:(CGRect)keyboardFrame;
+
+@end
+
+
+/**
+ *  An instance of `JSQMessagesKeyboardController` manages responding to the hiding and showing 
+ *  of the system keyboard for editing its `textView` within its specified `contextView`. 
+ *  It also controls user interaction with the system keyboard via its `panGestureRecognizer`, 
+ *  allow the user to interactively pan the keyboard up and down in the `contextView`.
+ *  
+ *  When the system keyboard frame changes, it posts the `JSQMessagesKeyboardControllerNotificationKeyboardDidChangeFrame`.
+ */
+@interface JSQMessagesKeyboardController : NSObject
+
+/**
+ *  The object that acts as the delegate of the keyboard controller.
+ */
+@property (weak, nonatomic) id<JSQMessagesKeyboardControllerDelegate> delegate;
+
+/**
+ *  The text view in which the user is editing with the system keyboard.
+ */
+@property (weak, nonatomic, readonly) UITextView *textView;
+
+/**
+ *  The view in which the keyboard will be shown. This should be the parent or a sibling of `textView`.
+ */
+@property (weak, nonatomic, readonly) UIView *contextView;
+
+/**
+ *  The pan gesture recognizer responsible for handling user interaction with the system keyboard.
+ */
+@property (weak, nonatomic, readonly) UIPanGestureRecognizer *panGestureRecognizer;
+
+/**
+ *  Specifies the distance from the keyboard at which the `panGestureRecognizer`
+ *  should trigger user interaction with the keyboard by panning.
+ *
+ *  @discussion The x value of the point is not used.
+ */
+@property (assign, nonatomic) CGPoint keyboardTriggerPoint;
+
+/**
+ *  Returns `YES` if the keyboard is currently visible, `NO` otherwise.
+ */
+@property (assign, nonatomic, readonly) BOOL keyboardIsVisible;
+
+/**
+ *  Returns the current frame of the keyboard if it is visible, otherwise `CGRectNull`.
+ */
+@property (assign, nonatomic, readonly) CGRect currentKeyboardFrame;
+
+/**
+ *  Not a valid initializer.
+ */
+- (id)init NS_UNAVAILABLE;
+
+/**
+ *  Creates a new keyboard controller object with the specified textView, contextView, panGestureRecognizer, and delegate.
+ *
+ *  @param textView             The text view in which the user is editing with the system keyboard. This value must not be `nil`.
+ *  @param contextView          The view in which the keyboard will be shown. This should be the parent or a sibling of `textView`. This value must not be `nil`.
+ *  @param panGestureRecognizer The pan gesture recognizer responsible for handling user interaction with the system keyboard. This value must not be `nil`.
+ *  @param delegate             The object that acts as the delegate of the keyboard controller.
+ *
+ *  @return An initialized `JSQMessagesKeyboardController` if created successfully, `nil` otherwise.
+ */
+- (instancetype)initWithTextView:(UITextView *)textView
+                     contextView:(UIView *)contextView
+            panGestureRecognizer:(UIPanGestureRecognizer *)panGestureRecognizer
+                        delegate:(id<JSQMessagesKeyboardControllerDelegate>)delegate NS_DESIGNATED_INITIALIZER;
+
+/**
+ *  Tells the keyboard controller that it should begin listening for system keyboard notifications.
+ */
+- (void)beginListeningForKeyboard;
+
+/**
+ *  Tells the keyboard controller that it should end listening for system keyboard notifications.
+ */
+- (void)endListeningForKeyboard;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Controllers/JSQMessagesKeyboardController.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Controllers/JSQMessagesKeyboardController.m
new file mode 100644
index 0000000..0b20fbd
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Controllers/JSQMessagesKeyboardController.m
@@ -0,0 +1,393 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+//
+//  Ideas for keyboard controller taken from Daniel Amitay
+//  DAKeyboardControl
+//  https://github.com/danielamitay/DAKeyboardControl
+//
+
+#import "JSQMessagesKeyboardController.h"
+
+#import "UIDevice+JSQMessages.h"
+
+
+NSString * const JSQMessagesKeyboardControllerNotificationKeyboardDidChangeFrame = @"JSQMessagesKeyboardControllerNotificationKeyboardDidChangeFrame";
+NSString * const JSQMessagesKeyboardControllerUserInfoKeyKeyboardDidChangeFrame = @"JSQMessagesKeyboardControllerUserInfoKeyKeyboardDidChangeFrame";
+
+static void * kJSQMessagesKeyboardControllerKeyValueObservingContext = &kJSQMessagesKeyboardControllerKeyValueObservingContext;
+
+typedef void (^JSQAnimationCompletionBlock)(BOOL finished);
+
+
+
+@interface JSQMessagesKeyboardController () <UIGestureRecognizerDelegate>
+
+@property (assign, nonatomic) BOOL jsq_isObserving;
+
+@property (strong, nonatomic) UIView *keyboardView;
+
+@end
+
+
+
+@implementation JSQMessagesKeyboardController
+
+#pragma mark - Initialization
+
+- (instancetype)initWithTextView:(UITextView *)textView
+                     contextView:(UIView *)contextView
+            panGestureRecognizer:(UIPanGestureRecognizer *)panGestureRecognizer
+                        delegate:(id<JSQMessagesKeyboardControllerDelegate>)delegate
+
+{
+    NSParameterAssert(textView != nil);
+    NSParameterAssert(contextView != nil);
+    NSParameterAssert(panGestureRecognizer != nil);
+
+    self = [super init];
+    if (self) {
+        _textView = textView;
+        _contextView = contextView;
+        _panGestureRecognizer = panGestureRecognizer;
+        _delegate = delegate;
+        _jsq_isObserving = NO;
+    }
+    return self;
+}
+
+- (void)dealloc
+{
+    [self jsq_removeKeyboardFrameObserver];
+    [self jsq_unregisterForNotifications];
+    _panGestureRecognizer = nil;
+    _delegate = nil;
+}
+
+#pragma mark - Setters
+
+- (void)setKeyboardView:(UIView *)keyboardView
+{
+    if (_keyboardView) {
+        [self jsq_removeKeyboardFrameObserver];
+    }
+
+    _keyboardView = keyboardView;
+
+    if (keyboardView && !_jsq_isObserving) {
+        [_keyboardView addObserver:self
+                        forKeyPath:NSStringFromSelector(@selector(frame))
+                           options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew)
+                           context:kJSQMessagesKeyboardControllerKeyValueObservingContext];
+
+        _jsq_isObserving = YES;
+    }
+}
+
+#pragma mark - Getters
+
+- (BOOL)keyboardIsVisible
+{
+    return self.keyboardView != nil;
+}
+
+- (CGRect)currentKeyboardFrame
+{
+    if (!self.keyboardIsVisible) {
+        return CGRectNull;
+    }
+
+    return self.keyboardView.frame;
+}
+
+#pragma mark - Keyboard controller
+
+- (void)beginListeningForKeyboard
+{
+    if (self.textView.inputAccessoryView == nil) {
+        self.textView.inputAccessoryView = [[UIView alloc] init];
+    }
+
+    [self jsq_registerForNotifications];
+}
+
+- (void)endListeningForKeyboard
+{
+    [self jsq_unregisterForNotifications];
+
+    [self jsq_setKeyboardViewHidden:NO];
+    self.keyboardView = nil;
+}
+
+#pragma mark - Notifications
+
+- (void)jsq_registerForNotifications
+{
+    [self jsq_unregisterForNotifications];
+
+    [[NSNotificationCenter defaultCenter] addObserver:self
+                                             selector:@selector(jsq_didReceiveKeyboardDidShowNotification:)
+                                                 name:UIKeyboardDidShowNotification
+                                               object:nil];
+
+    [[NSNotificationCenter defaultCenter] addObserver:self
+                                             selector:@selector(jsq_didReceiveKeyboardWillChangeFrameNotification:)
+                                                 name:UIKeyboardWillChangeFrameNotification
+                                               object:nil];
+
+    [[NSNotificationCenter defaultCenter] addObserver:self
+                                             selector:@selector(jsq_didReceiveKeyboardDidChangeFrameNotification:)
+                                                 name:UIKeyboardDidChangeFrameNotification
+                                               object:nil];
+
+    [[NSNotificationCenter defaultCenter] addObserver:self
+                                             selector:@selector(jsq_didReceiveKeyboardDidHideNotification:)
+                                                 name:UIKeyboardDidHideNotification
+                                               object:nil];
+}
+
+- (void)jsq_unregisterForNotifications
+{
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+- (void)jsq_didReceiveKeyboardDidShowNotification:(NSNotification *)notification
+{
+    UIView *keyboardViewProxy = self.textView.inputAccessoryView.superview;
+    if ([UIDevice jsq_isCurrentDeviceAfteriOS9]) {
+        NSPredicate *windowPredicate = [NSPredicate predicateWithFormat:@"self isMemberOfClass: %@", NSClassFromString(@"UIRemoteKeyboardWindow")];
+        UIWindow *keyboardWindow = [[UIApplication sharedApplication].windows filteredArrayUsingPredicate:windowPredicate].firstObject;
+
+        for (UIView *subview in keyboardWindow.subviews) {
+            for (UIView *hostview in subview.subviews) {
+                if ([hostview isMemberOfClass:NSClassFromString(@"UIInputSetHostView")]) {
+                    keyboardViewProxy = hostview;
+                    break;
+                }
+            }
+        }
+        self.keyboardView = keyboardViewProxy;
+    }
+
+    [self jsq_setKeyboardViewHidden:NO];
+
+    [self jsq_handleKeyboardNotification:notification completion:^(BOOL finished) {
+        [self.panGestureRecognizer addTarget:self action:@selector(jsq_handlePanGestureRecognizer:)];
+    }];
+}
+
+- (void)jsq_didReceiveKeyboardWillChangeFrameNotification:(NSNotification *)notification
+{
+    [self jsq_handleKeyboardNotification:notification completion:nil];
+}
+
+- (void)jsq_didReceiveKeyboardDidChangeFrameNotification:(NSNotification *)notification
+{
+    [self jsq_setKeyboardViewHidden:NO];
+
+    [self jsq_handleKeyboardNotification:notification completion:nil];
+}
+
+- (void)jsq_didReceiveKeyboardDidHideNotification:(NSNotification *)notification
+{
+    self.keyboardView = nil;
+
+    [self jsq_handleKeyboardNotification:notification completion:^(BOOL finished) {
+        [self.panGestureRecognizer removeTarget:self action:NULL];
+    }];
+}
+
+- (void)jsq_handleKeyboardNotification:(NSNotification *)notification completion:(JSQAnimationCompletionBlock)completion
+{
+    NSDictionary *userInfo = [notification userInfo];
+
+    CGRect keyboardEndFrame = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
+
+    if (CGRectIsNull(keyboardEndFrame)) {
+        return;
+    }
+
+    UIViewAnimationCurve animationCurve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue];
+    NSInteger animationCurveOption = (animationCurve << 16);
+
+    double animationDuration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
+
+    CGRect keyboardEndFrameConverted = [self.contextView convertRect:keyboardEndFrame fromView:nil];
+
+    [UIView animateWithDuration:animationDuration
+                          delay:0.0
+                        options:animationCurveOption
+                     animations:^{
+                         [self jsq_notifyKeyboardFrameNotificationForFrame:keyboardEndFrameConverted];
+                     }
+                     completion:^(BOOL finished) {
+                         if (completion) {
+                             completion(finished);
+                         }
+                     }];
+}
+
+#pragma mark - Utilities
+
+- (void)jsq_setKeyboardViewHidden:(BOOL)hidden
+{
+    self.keyboardView.hidden = hidden;
+    self.keyboardView.userInteractionEnabled = !hidden;
+}
+
+- (void)jsq_notifyKeyboardFrameNotificationForFrame:(CGRect)frame
+{
+    [self.delegate keyboardController:self keyboardDidChangeFrame:frame];
+
+    [[NSNotificationCenter defaultCenter] postNotificationName:JSQMessagesKeyboardControllerNotificationKeyboardDidChangeFrame
+                                                        object:self
+                                                      userInfo:@{ JSQMessagesKeyboardControllerUserInfoKeyKeyboardDidChangeFrame : [NSValue valueWithCGRect:frame] }];
+}
+
+- (void)jsq_resetKeyboardAndTextView
+{
+    [self jsq_setKeyboardViewHidden:YES];
+    [self jsq_removeKeyboardFrameObserver];
+    [self.textView resignFirstResponder];
+}
+
+#pragma mark - Key-value observing
+
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
+{
+    if (context == kJSQMessagesKeyboardControllerKeyValueObservingContext) {
+
+        if (object == self.keyboardView && [keyPath isEqualToString:NSStringFromSelector(@selector(frame))]) {
+
+            CGRect oldKeyboardFrame = [[change objectForKey:NSKeyValueChangeOldKey] CGRectValue];
+            CGRect newKeyboardFrame = [[change objectForKey:NSKeyValueChangeNewKey] CGRectValue];
+
+            if (CGRectEqualToRect(newKeyboardFrame, oldKeyboardFrame) || CGRectIsNull(newKeyboardFrame)) {
+                return;
+            }
+
+            CGRect keyboardEndFrameConverted = [self.contextView convertRect:newKeyboardFrame
+                                                                    fromView:self.keyboardView.superview];
+            [self jsq_notifyKeyboardFrameNotificationForFrame:keyboardEndFrameConverted];
+        }
+    }
+}
+
+- (void)jsq_removeKeyboardFrameObserver
+{
+    if (!_jsq_isObserving) {
+        return;
+    }
+
+    @try {
+        [_keyboardView removeObserver:self
+                           forKeyPath:NSStringFromSelector(@selector(frame))
+                              context:kJSQMessagesKeyboardControllerKeyValueObservingContext];
+    }
+    @catch (NSException * __unused exception) { }
+
+    _jsq_isObserving = NO;
+}
+
+#pragma mark - Pan gesture recognizer
+
+- (void)jsq_handlePanGestureRecognizer:(UIPanGestureRecognizer *)pan
+{
+    CGPoint touch = [pan locationInView:self.contextView.window];
+
+    //  system keyboard is added to a new UIWindow, need to operate in window coordinates
+    //  also, keyboard always slides from bottom of screen, not the bottom of a view
+    CGFloat contextViewWindowHeight = CGRectGetHeight(self.contextView.window.frame);
+
+    if ([UIDevice jsq_isCurrentDeviceBeforeiOS8]) {
+        //  handle iOS 7 bug when rotating to landscape
+        if (UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) {
+            contextViewWindowHeight = CGRectGetWidth(self.contextView.window.frame);
+        }
+    }
+
+    CGFloat keyboardViewHeight = CGRectGetHeight(self.keyboardView.frame);
+
+    CGFloat dragThresholdY = (contextViewWindowHeight - keyboardViewHeight - self.keyboardTriggerPoint.y);
+
+    CGRect newKeyboardViewFrame = self.keyboardView.frame;
+
+    BOOL userIsDraggingNearThresholdForDismissing = (touch.y > dragThresholdY);
+
+    self.keyboardView.userInteractionEnabled = !userIsDraggingNearThresholdForDismissing;
+
+    switch (pan.state) {
+        case UIGestureRecognizerStateChanged:
+        {
+            newKeyboardViewFrame.origin.y = touch.y + self.keyboardTriggerPoint.y;
+
+            //  bound frame between bottom of view and height of keyboard
+            newKeyboardViewFrame.origin.y = MIN(newKeyboardViewFrame.origin.y, contextViewWindowHeight);
+            newKeyboardViewFrame.origin.y = MAX(newKeyboardViewFrame.origin.y, contextViewWindowHeight - keyboardViewHeight);
+
+            if (CGRectGetMinY(newKeyboardViewFrame) == CGRectGetMinY(self.keyboardView.frame)) {
+                return;
+            }
+
+            [UIView animateWithDuration:0.0
+                                  delay:0.0
+                                options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionTransitionNone
+                             animations:^{
+                                 self.keyboardView.frame = newKeyboardViewFrame;
+                             }
+                             completion:nil];
+        }
+            break;
+
+        case UIGestureRecognizerStateEnded:
+        case UIGestureRecognizerStateCancelled:
+        case UIGestureRecognizerStateFailed:
+        {
+            BOOL keyboardViewIsHidden = (CGRectGetMinY(self.keyboardView.frame) >= contextViewWindowHeight);
+            if (keyboardViewIsHidden) {
+                [self jsq_resetKeyboardAndTextView];
+                return;
+            }
+
+            CGPoint velocity = [pan velocityInView:self.contextView];
+            BOOL userIsScrollingDown = (velocity.y > 0.0f);
+            BOOL shouldHide = (userIsScrollingDown && userIsDraggingNearThresholdForDismissing);
+
+            newKeyboardViewFrame.origin.y = shouldHide ? contextViewWindowHeight : (contextViewWindowHeight - keyboardViewHeight);
+
+            [UIView animateWithDuration:0.25
+                                  delay:0.0
+                                options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationCurveEaseOut
+                             animations:^{
+                                 self.keyboardView.frame = newKeyboardViewFrame;
+                             }
+                             completion:^(BOOL finished) {
+                                 self.keyboardView.userInteractionEnabled = !shouldHide;
+
+                                 if (shouldHide) {
+                                     [self jsq_resetKeyboardAndTextView];
+                                 }
+                             }];
+        }
+            break;
+            
+        default:
+            break;
+    }
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Controllers/JSQMessagesViewController.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Controllers/JSQMessagesViewController.h
new file mode 100644
index 0000000..6cf0320
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Controllers/JSQMessagesViewController.h
@@ -0,0 +1,327 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <UIKit/UIKit.h>
+
+#import "JSQMessagesCollectionView.h"
+#import "JSQMessagesCollectionViewFlowLayout.h"
+#import "JSQMessagesInputToolbar.h"
+#import "JSQMessagesKeyboardController.h"
+
+/**
+ *  The `JSQMessagesViewController` class is an abstract class that represents a view controller whose content consists of
+ *  a `JSQMessagesCollectionView` and `JSQMessagesInputToolbar` and is specialized to display a messaging interface.
+ *
+ *  @warning This class is intended to be subclassed. You should not use it directly.
+ */
+@interface JSQMessagesViewController : UIViewController <JSQMessagesCollectionViewDataSource,
+                                                         JSQMessagesCollectionViewDelegateFlowLayout,
+                                                         UITextViewDelegate>
+
+/**
+ *  Returns the collection view object managed by this view controller.
+ *  This view controller is the collection view's data source and delegate.
+ */
+@property (weak, nonatomic, readonly) JSQMessagesCollectionView *collectionView;
+
+/**
+ *  Returns the input toolbar view object managed by this view controller.
+ *  This view controller is the toolbar's delegate.
+ */
+@property (weak, nonatomic, readonly) JSQMessagesInputToolbar *inputToolbar;
+
+/**
+ *  Returns the keyboard controller object used to manage the software keyboard.
+ */
+@property (strong, nonatomic) JSQMessagesKeyboardController *keyboardController;
+
+/**
+ *  The display name of the current user who is sending messages.
+ *
+ *  @discussion This value does not have to be unique. This value must not be `nil`.
+ */
+@property (copy, nonatomic) NSString *senderDisplayName;
+
+/**
+ *  The string identifier that uniquely identifies the current user sending messages.
+ *
+ *  @discussion This property is used to determine if a message is incoming or outgoing.
+ *  All message data objects returned by `collectionView:messageDataForItemAtIndexPath:` are
+ *  checked against this identifier. This value must not be `nil`.
+ */
+@property (copy, nonatomic) NSString *senderId;
+
+/**
+ *  Specifies whether or not the view controller should automatically scroll to the most recent message
+ *  when the view appears and when sending, receiving, and composing a new message.
+ *
+ *  @discussion The default value is `YES`, which allows the view controller to scroll automatically to the most recent message.
+ *  Set to `NO` if you want to manage scrolling yourself.
+ */
+@property (assign, nonatomic) BOOL automaticallyScrollsToMostRecentMessage;
+
+/**
+ *  The collection view cell identifier to use for dequeuing outgoing message collection view cells 
+ *  in the collectionView for text messages.
+ *
+ *  @discussion This cell identifier is used for outgoing text message data items.
+ *  The default value is the string returned by `[JSQMessagesCollectionViewCellOutgoing cellReuseIdentifier]`.
+ *  This value must not be `nil`.
+ *
+ *  @see JSQMessagesCollectionViewCellOutgoing.
+ *
+ *  @warning Overriding this property's default value is *not* recommended. 
+ *  You should only override this property's default value if you are proividing your own cell prototypes.
+ *  These prototypes must be registered with the collectionView for reuse and you are then responsible for 
+ *  completely overriding many delegate and data source methods for the collectionView, 
+ *  including `collectionView:cellForItemAtIndexPath:`.
+ */
+@property (copy, nonatomic) NSString *outgoingCellIdentifier;
+
+/**
+ *  The collection view cell identifier to use for dequeuing outgoing message collection view cells
+ *  in the collectionView for media messages.
+ *
+ *  @discussion This cell identifier is used for outgoing media message data items.
+ *  The default value is the string returned by `[JSQMessagesCollectionViewCellOutgoing mediaCellReuseIdentifier]`.
+ *  This value must not be `nil`.
+ *
+ *  @see JSQMessagesCollectionViewCellOutgoing.
+ *
+ *  @warning Overriding this property's default value is *not* recommended.
+ *  You should only override this property's default value if you are proividing your own cell prototypes.
+ *  These prototypes must be registered with the collectionView for reuse and you are then responsible for
+ *  completely overriding many delegate and data source methods for the collectionView,
+ *  including `collectionView:cellForItemAtIndexPath:`.
+ */
+@property (copy, nonatomic) NSString *outgoingMediaCellIdentifier;
+
+/**
+ *  The collection view cell identifier to use for dequeuing incoming message collection view cells 
+ *  in the collectionView for text messages.
+ *
+ *  @discussion This cell identifier is used for incoming text message data items.
+ *  The default value is the string returned by `[JSQMessagesCollectionViewCellIncoming cellReuseIdentifier]`.
+ *  This value must not be `nil`.
+ *
+ *  @see JSQMessagesCollectionViewCellIncoming.
+ *
+ *  @warning Overriding this property's default value is *not* recommended. 
+ *  You should only override this property's default value if you are proividing your own cell prototypes. 
+ *  These prototypes must be registered with the collectionView for reuse and you are then responsible for 
+ *  completely overriding many delegate and data source methods for the collectionView, 
+ *  including `collectionView:cellForItemAtIndexPath:`.
+ */
+@property (copy, nonatomic) NSString *incomingCellIdentifier;
+
+/**
+ *  The collection view cell identifier to use for dequeuing incoming message collection view cells 
+ *  in the collectionView for media messages.
+ *
+ *  @discussion This cell identifier is used for incoming media message data items.
+ *  The default value is the string returned by `[JSQMessagesCollectionViewCellIncoming mediaCellReuseIdentifier]`.
+ *  This value must not be `nil`.
+ *
+ *  @see JSQMessagesCollectionViewCellIncoming.
+ *
+ *  @warning Overriding this property's default value is *not* recommended.
+ *  You should only override this property's default value if you are proividing your own cell prototypes.
+ *  These prototypes must be registered with the collectionView for reuse and you are then responsible for
+ *  completely overriding many delegate and data source methods for the collectionView,
+ *  including `collectionView:cellForItemAtIndexPath:`.
+ */
+@property (copy, nonatomic) NSString *incomingMediaCellIdentifier;
+
+/**
+ *  Specifies whether or not the view controller should show the typing indicator for an incoming message.
+ *
+ *  @discussion Setting this property to `YES` will animate showing the typing indicator immediately.
+ *  Setting this property to `NO` will animate hiding the typing indicator immediately. You will need to scroll
+ *  to the bottom of the collection view in order to see the typing indicator. You may use `scrollToBottomAnimated:` for this.
+ */
+@property (assign, nonatomic) BOOL showTypingIndicator;
+
+/**
+ *  Specifies whether or not the view controller should show the "load earlier messages" header view.
+ *
+ *  @discussion Setting this property to `YES` will show the header view immediately.
+ *  Settings this property to `NO` will hide the header view immediately. You will need to scroll to
+ *  the top of the collection view in order to see the header.
+ */
+@property (assign, nonatomic) BOOL showLoadEarlierMessagesHeader;
+
+/**
+ *  Specifies an additional inset amount to be added to the collectionView's contentInsets.top value.
+ *
+ *  @discussion Use this property to adjust the top content inset to account for a custom subview at the top of your view controller.
+ */
+@property (assign, nonatomic) CGFloat topContentAdditionalInset;
+
+#pragma mark - Class methods
+
+/**
+ *  Returns the `UINib` object initialized for a `JSQMessagesViewController`.
+ *
+ *  @return The initialized `UINib` object or `nil` if there were errors during initialization
+ *  or the nib file could not be located.
+ *
+ *  @discussion You may override this method to provide a customized nib. If you do,
+ *  you should also override `messagesViewController` to return your
+ *  view controller loaded from your custom nib.
+ */
++ (UINib *)nib;
+
+/**
+ *  Creates and returns a new `JSQMessagesViewController` object.
+ *
+ *  @discussion This is the designated initializer for programmatic instantiation.
+ *
+ *  @return An initialized `JSQMessagesViewController` object if successful, `nil` otherwise.
+ */
++ (instancetype)messagesViewController;
+
+#pragma mark - Messages view controller
+
+/**
+ *  This method is called when the user taps the send button on the inputToolbar
+ *  after composing a message with the specified data.
+ *
+ *  @param button            The send button that was pressed by the user.
+ *  @param text              The message text.
+ *  @param senderId          The message sender identifier.
+ *  @param senderDisplayName The message sender display name.
+ *  @param date              The message date.
+ */
+- (void)didPressSendButton:(UIButton *)button
+           withMessageText:(NSString *)text
+                  senderId:(NSString *)senderId
+         senderDisplayName:(NSString *)senderDisplayName
+                      date:(NSDate *)date;
+
+/**
+ *  This method is called when the user taps the accessory button on the `inputToolbar`.
+ *
+ *  @param sender The accessory button that was pressed by the user.
+ */
+- (void)didPressAccessoryButton:(UIButton *)sender;
+
+/**
+ *  Animates the sending of a new message. See `finishSendingMessageAnimated:` for more details.
+ *
+ *  @see `finishSendingMessageAnimated:`.
+ */
+- (void)finishSendingMessage;
+
+/**
+ *  Completes the "sending" of a new message by resetting the `inputToolbar`, adding a new collection view cell in the collection view,
+ *  reloading the collection view, and scrolling to the newly sent message as specified by `automaticallyScrollsToMostRecentMessage`.
+ *  Scrolling to the new message can be animated as specified by the animated parameter.
+ *
+ *  @param animated Specifies whether the sending of a message should be animated or not. Pass `YES` to animate changes, `NO` otherwise.
+ *
+ *  @discussion You should call this method at the end of `didPressSendButton: withMessageText: senderId: senderDisplayName: date`
+ *  after adding the new message to your data source and performing any related tasks.
+ *
+ *  @see `automaticallyScrollsToMostRecentMessage`.
+ */
+- (void)finishSendingMessageAnimated:(BOOL)animated;
+
+/**
+ *  Animates the receiving of a new message. See `finishReceivingMessageAnimated:` for more details.
+ *
+ *  @see `finishReceivingMessageAnimated:`.
+ */
+- (void)finishReceivingMessage;
+
+/**
+ *  Completes the "receiving" of a new message by showing the typing indicator, adding a new collection view cell in the collection view,
+ *  reloading the collection view, and scrolling to the newly sent message as specified by `automaticallyScrollsToMostRecentMessage`.
+ *  Scrolling to the new message can be animated as specified by the animated parameter.
+ *
+ *  @param animated Specifies whether the receiving of a message should be animated or not. Pass `YES` to animate changes, `NO` otherwise.
+ *
+ *  @discussion You should call this method after adding a new "received" message to your data source and performing any related tasks.
+ *
+ *  @see `automaticallyScrollsToMostRecentMessage`.
+ */
+- (void)finishReceivingMessageAnimated:(BOOL)animated;
+
+/**
+ *  Scrolls the collection view such that the bottom most cell is completely visible, above the `inputToolbar`.
+ *
+ *  @param animated Pass `YES` if you want to animate scrolling, `NO` if it should be immediate.
+ */
+- (void)scrollToBottomAnimated:(BOOL)animated;
+
+/**
+ * Used to decide if a message is incoming or outgoing.
+ *
+ * @discussion The default implementation of this method compares the `senderId` of the message to the
+ * value of the `senderId` property and returns `YES` if they are equal. Subclasses can override
+ * this method to specialize the decision logic.
+ */
+- (BOOL)isOutgoingMessage:(id<JSQMessageData>)messageItem;
+
+/**
+ * Scrolls the collection view so that the cell at the specified indexPath is completely visible above the `inputToolbar`.
+ *
+ * @param indexPath The indexPath for the cell that will be visible.
+ * @param animated Pass `YES` if you want to animate scrolling, `NO` otherwise.
+ */
+- (void)scrollToIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated;
+
+/**
+ Call to super required.
+ */
+- (void)viewDidLoad NS_REQUIRES_SUPER;
+
+/**
+ Call to super required.
+ */
+- (void)viewWillAppear:(BOOL)animated NS_REQUIRES_SUPER;
+
+/**
+ Call to super required.
+ */
+- (void)viewDidAppear:(BOOL)animated NS_REQUIRES_SUPER;
+
+/**
+ Call to super required.
+ */
+- (void)viewWillDisappear:(BOOL)animated NS_REQUIRES_SUPER;
+
+/**
+ Call to super required.
+ */
+- (void)viewDidDisappear:(BOOL)animated NS_REQUIRES_SUPER;
+
+/**
+ Called when `UIMenuControllerWillShowMenuNotification` is posted.
+
+ @param notification The posted notification.
+ */
+- (void)didReceiveMenuWillShowNotification:(NSNotification *)notification;
+
+/**
+ Called when `UIMenuControllerWillHideMenuNotification` is posted.
+
+ @param notification The posted notification.
+ */
+- (void)didReceiveMenuWillHideNotification:(NSNotification *)notification;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Controllers/JSQMessagesViewController.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Controllers/JSQMessagesViewController.m
new file mode 100644
index 0000000..945efc3
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Controllers/JSQMessagesViewController.m
@@ -0,0 +1,1155 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQMessagesViewController.h"
+
+#import "JSQMessagesCollectionViewFlowLayoutInvalidationContext.h"
+
+#import "JSQMessageData.h"
+#import "JSQMessageBubbleImageDataSource.h"
+#import "JSQMessageAvatarImageDataSource.h"
+
+#import "JSQMessagesCollectionViewCellIncoming.h"
+#import "JSQMessagesCollectionViewCellOutgoing.h"
+
+#import "JSQMessagesTypingIndicatorFooterView.h"
+#import "JSQMessagesLoadEarlierHeaderView.h"
+
+#import "JSQMessagesToolbarContentView.h"
+#import "JSQMessagesInputToolbar.h"
+#import "JSQMessagesComposerTextView.h"
+
+#import "NSString+JSQMessages.h"
+#import "UIColor+JSQMessages.h"
+#import "UIDevice+JSQMessages.h"
+#import "NSBundle+JSQMessages.h"
+
+#import <objc/runtime.h>
+
+
+// Fixes rdar://26295020
+// See issue #1247 and Peter Steinberger's comment:
+// https://github.com/jessesquires/JSQMessagesViewController/issues/1247#issuecomment-219386199
+// Gist with workaround: https://gist.github.com/steipete/b00fc02aa9f1c66c11d0f996b1ba1265
+// Forgive me
+static IMP JSQReplaceMethodWithBlock(Class c, SEL origSEL, id block) {
+    NSCParameterAssert(block);
+
+    // get original method
+    Method origMethod = class_getInstanceMethod(c, origSEL);
+    NSCParameterAssert(origMethod);
+
+    // convert block to IMP trampoline and replace method implementation
+    IMP newIMP = imp_implementationWithBlock(block);
+
+    // Try adding the method if not yet in the current class
+    if (!class_addMethod(c, origSEL, newIMP, method_getTypeEncoding(origMethod))) {
+        return method_setImplementation(origMethod, newIMP);
+    } else {
+        return method_getImplementation(origMethod);
+    }
+}
+
+static void JSQInstallWorkaroundForSheetPresentationIssue26295020(void) {
+    __block void (^removeWorkaround)(void) = ^{};
+    const void (^installWorkaround)(void) = ^{
+        const SEL presentSEL = @selector(presentViewController:animated:completion:);
+        __block IMP origIMP = JSQReplaceMethodWithBlock(UIViewController.class, presentSEL, ^(UIViewController *self, id vC, BOOL animated, id completion) {
+            UIViewController *targetVC = self;
+            while (targetVC.presentedViewController) {
+                targetVC = targetVC.presentedViewController;
+            }
+            ((void (*)(id, SEL, id, BOOL, id))origIMP)(targetVC, presentSEL, vC, animated, completion);
+        });
+        removeWorkaround = ^{
+            Method origMethod = class_getInstanceMethod(UIViewController.class, presentSEL);
+            NSCParameterAssert(origMethod);
+            class_replaceMethod(UIViewController.class,
+                                presentSEL,
+                                origIMP,
+                                method_getTypeEncoding(origMethod));
+        };
+    };
+
+    const SEL presentSheetSEL = NSSelectorFromString(@"presentSheetFromRect:");
+    const void (^swizzleOnClass)(Class k) = ^(Class klass) {
+        const __block IMP origIMP = JSQReplaceMethodWithBlock(klass, presentSheetSEL, ^(id self, CGRect rect) {
+            // Before calling the original implementation, we swizzle the presentation logic on UIViewController
+            installWorkaround();
+            // UIKit later presents the sheet on [view.window rootViewController];
+            // See https://github.com/WebKit/webkit/blob/1aceb9ed7a42d0a5ed11558c72bcd57068b642e7/Source/WebKit2/UIProcess/ios/WKActionSheet.mm#L102
+            // Our workaround forwards this to the topmost presentedViewController instead.
+            ((void (*)(id, SEL, CGRect))origIMP)(self, presentSheetSEL, rect);
+            // Cleaning up again - this workaround would swallow bugs if we let it be there.
+            removeWorkaround();
+        });
+    };
+
+    // _UIRotatingAlertController
+    Class alertClass = NSClassFromString([NSString stringWithFormat:@"%@%@%@", @"_U", @"IRotat", @"ingAlertController"]);
+    if (alertClass) {
+        swizzleOnClass(alertClass);
+    }
+
+    // WKActionSheet
+    Class actionSheetClass = NSClassFromString([NSString stringWithFormat:@"%@%@%@", @"W", @"KActio", @"nSheet"]);
+    if (actionSheetClass) {
+        swizzleOnClass(actionSheetClass);
+    }
+}
+
+
+
+static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObservingContext;
+
+
+
+@interface JSQMessagesViewController () <JSQMessagesInputToolbarDelegate,
+JSQMessagesKeyboardControllerDelegate>
+
+@property (weak, nonatomic) IBOutlet JSQMessagesCollectionView *collectionView;
+@property (weak, nonatomic) IBOutlet JSQMessagesInputToolbar *inputToolbar;
+
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *toolbarHeightConstraint;
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *toolbarBottomLayoutGuide;
+
+@property (weak, nonatomic) UIView *snapshotView;
+
+@property (assign, nonatomic) BOOL jsq_isObserving;
+
+@property (strong, nonatomic) NSIndexPath *selectedIndexPathForMenu;
+
+@property (weak, nonatomic) UIGestureRecognizer *currentInteractivePopGestureRecognizer;
+
+@property (assign, nonatomic) BOOL textViewWasFirstResponderDuringInteractivePop;
+
+@end
+
+
+
+@implementation JSQMessagesViewController
+
+#pragma mark - Class methods
+
++ (UINib *)nib
+{
+    return [UINib nibWithNibName:NSStringFromClass([JSQMessagesViewController class])
+                          bundle:[NSBundle bundleForClass:[JSQMessagesViewController class]]];
+}
+
++ (instancetype)messagesViewController
+{
+    return [[[self class] alloc] initWithNibName:NSStringFromClass([JSQMessagesViewController class])
+                                          bundle:[NSBundle bundleForClass:[JSQMessagesViewController class]]];
+}
+
++ (void)initialize {
+    [super initialize];
+    if (self == [JSQMessagesViewController self]) {
+        JSQInstallWorkaroundForSheetPresentationIssue26295020();
+    }
+}
+
+#pragma mark - Initialization
+
+- (void)jsq_configureMessagesViewController
+{
+    self.view.backgroundColor = [UIColor whiteColor];
+
+    self.jsq_isObserving = NO;
+
+    self.toolbarHeightConstraint.constant = self.inputToolbar.preferredDefaultHeight;
+
+    self.collectionView.dataSource = self;
+    self.collectionView.delegate = self;
+
+    self.inputToolbar.delegate = self;
+    self.inputToolbar.contentView.textView.placeHolder = [NSBundle jsq_localizedStringForKey:@"new_message"];
+
+    self.inputToolbar.contentView.textView.accessibilityLabel = [NSBundle jsq_localizedStringForKey:@"new_message"];
+
+    self.inputToolbar.contentView.textView.delegate = self;
+
+    self.automaticallyScrollsToMostRecentMessage = YES;
+
+    self.outgoingCellIdentifier = [JSQMessagesCollectionViewCellOutgoing cellReuseIdentifier];
+    self.outgoingMediaCellIdentifier = [JSQMessagesCollectionViewCellOutgoing mediaCellReuseIdentifier];
+
+    self.incomingCellIdentifier = [JSQMessagesCollectionViewCellIncoming cellReuseIdentifier];
+    self.incomingMediaCellIdentifier = [JSQMessagesCollectionViewCellIncoming mediaCellReuseIdentifier];
+
+    // NOTE: let this behavior be opt-in for now
+    // [JSQMessagesCollectionViewCell registerMenuAction:@selector(delete:)];
+
+    self.showTypingIndicator = NO;
+
+    self.showLoadEarlierMessagesHeader = NO;
+
+    self.topContentAdditionalInset = 0.0f;
+
+    [self jsq_updateCollectionViewInsets];
+
+    // Don't set keyboardController if client creates custom content view via -loadToolbarContentView
+    if (self.inputToolbar.contentView.textView != nil) {
+        self.keyboardController = [[JSQMessagesKeyboardController alloc] initWithTextView:self.inputToolbar.contentView.textView
+                                                                              contextView:self.view
+                                                                     panGestureRecognizer:self.collectionView.panGestureRecognizer
+                                                                                 delegate:self];
+    }
+}
+
+- (void)dealloc
+{
+    [self jsq_registerForNotifications:NO];
+    [self jsq_removeObservers];
+
+    _collectionView.dataSource = nil;
+    _collectionView.delegate = nil;
+
+    _inputToolbar.contentView.textView.delegate = nil;
+    _inputToolbar.delegate = nil;
+
+    [_keyboardController endListeningForKeyboard];
+    _keyboardController = nil;
+}
+
+#pragma mark - Setters
+
+- (void)setShowTypingIndicator:(BOOL)showTypingIndicator
+{
+    if (_showTypingIndicator == showTypingIndicator) {
+        return;
+    }
+
+    _showTypingIndicator = showTypingIndicator;
+    [self.collectionView.collectionViewLayout invalidateLayoutWithContext:[JSQMessagesCollectionViewFlowLayoutInvalidationContext context]];
+    [self.collectionView.collectionViewLayout invalidateLayout];
+}
+
+- (void)setShowLoadEarlierMessagesHeader:(BOOL)showLoadEarlierMessagesHeader
+{
+    if (_showLoadEarlierMessagesHeader == showLoadEarlierMessagesHeader) {
+        return;
+    }
+
+    _showLoadEarlierMessagesHeader = showLoadEarlierMessagesHeader;
+    [self.collectionView.collectionViewLayout invalidateLayoutWithContext:[JSQMessagesCollectionViewFlowLayoutInvalidationContext context]];
+    [self.collectionView.collectionViewLayout invalidateLayout];
+    [self.collectionView reloadData];
+}
+
+- (void)setTopContentAdditionalInset:(CGFloat)topContentAdditionalInset
+{
+    _topContentAdditionalInset = topContentAdditionalInset;
+    [self jsq_updateCollectionViewInsets];
+}
+
+#pragma mark - View lifecycle
+
+- (void)viewDidLoad
+{
+    [super viewDidLoad];
+
+    [[[self class] nib] instantiateWithOwner:self options:nil];
+
+    [self jsq_configureMessagesViewController];
+    [self jsq_registerForNotifications:YES];
+}
+
+- (void)viewWillAppear:(BOOL)animated
+{
+    NSParameterAssert(self.senderId != nil);
+    NSParameterAssert(self.senderDisplayName != nil);
+
+    [super viewWillAppear:animated];
+    self.toolbarHeightConstraint.constant = self.inputToolbar.preferredDefaultHeight;
+    [self.view layoutIfNeeded];
+    [self.collectionView.collectionViewLayout invalidateLayout];
+
+    if (self.automaticallyScrollsToMostRecentMessage) {
+        dispatch_async(dispatch_get_main_queue(), ^{
+            [self scrollToBottomAnimated:NO];
+            [self.collectionView.collectionViewLayout invalidateLayoutWithContext:[JSQMessagesCollectionViewFlowLayoutInvalidationContext context]];
+        });
+    }
+
+    [self jsq_updateKeyboardTriggerPoint];
+}
+
+- (void)viewDidAppear:(BOOL)animated
+{
+    [super viewDidAppear:animated];
+    [self jsq_addObservers];
+    [self jsq_addActionToInteractivePopGestureRecognizer:YES];
+    [self.keyboardController beginListeningForKeyboard];
+
+    if ([UIDevice jsq_isCurrentDeviceBeforeiOS8]) {
+        [self.snapshotView removeFromSuperview];
+    }
+}
+
+- (void)viewWillDisappear:(BOOL)animated
+{
+    [super viewWillDisappear:animated];
+    self.collectionView.collectionViewLayout.springinessEnabled = NO;
+}
+
+- (void)viewDidDisappear:(BOOL)animated
+{
+    [super viewDidDisappear:animated];
+    [self jsq_addActionToInteractivePopGestureRecognizer:NO];
+    [self jsq_removeObservers];
+    [self.keyboardController endListeningForKeyboard];
+}
+
+
+#pragma mark - View rotation
+
+- (BOOL)shouldAutorotate
+{
+    return YES;
+}
+
+- (UIInterfaceOrientationMask)supportedInterfaceOrientations
+{
+    if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone) {
+        return UIInterfaceOrientationMaskAllButUpsideDown;
+    }
+    return UIInterfaceOrientationMaskAll;
+}
+
+- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
+{
+    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
+    [self.collectionView.collectionViewLayout invalidateLayoutWithContext:[JSQMessagesCollectionViewFlowLayoutInvalidationContext context]];
+}
+
+- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
+{
+    [super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
+    if (self.showTypingIndicator) {
+        self.showTypingIndicator = NO;
+        self.showTypingIndicator = YES;
+        [self.collectionView reloadData];
+    }
+}
+
+- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
+    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
+    [self jsq_resetLayoutAndCaches];
+}
+
+- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
+    [super traitCollectionDidChange:previousTraitCollection];
+    [self jsq_resetLayoutAndCaches];
+}
+
+- (void)jsq_resetLayoutAndCaches
+{
+    JSQMessagesCollectionViewFlowLayoutInvalidationContext *context = [JSQMessagesCollectionViewFlowLayoutInvalidationContext context];
+    context.invalidateFlowLayoutMessagesCache = YES;
+    [self.collectionView.collectionViewLayout invalidateLayoutWithContext:context];
+}
+
+#pragma mark - Messages view controller
+
+- (void)didPressSendButton:(UIButton *)button
+           withMessageText:(NSString *)text
+                  senderId:(NSString *)senderId
+         senderDisplayName:(NSString *)senderDisplayName
+                      date:(NSDate *)date
+{
+    NSAssert(NO, @"Error! required method not implemented in subclass. Need to implement %s", __PRETTY_FUNCTION__);
+}
+
+- (void)didPressAccessoryButton:(UIButton *)sender
+{
+    NSAssert(NO, @"Error! required method not implemented in subclass. Need to implement %s", __PRETTY_FUNCTION__);
+}
+
+- (void)finishSendingMessage
+{
+    [self finishSendingMessageAnimated:YES];
+}
+
+- (void)finishSendingMessageAnimated:(BOOL)animated {
+
+    UITextView *textView = self.inputToolbar.contentView.textView;
+    textView.text = nil;
+    [textView.undoManager removeAllActions];
+
+    [self.inputToolbar toggleSendButtonEnabled];
+
+    [[NSNotificationCenter defaultCenter] postNotificationName:UITextViewTextDidChangeNotification object:textView];
+
+    [self.collectionView.collectionViewLayout invalidateLayoutWithContext:[JSQMessagesCollectionViewFlowLayoutInvalidationContext context]];
+    [self.collectionView reloadData];
+
+    if (self.automaticallyScrollsToMostRecentMessage) {
+        [self scrollToBottomAnimated:animated];
+    }
+}
+
+- (void)finishReceivingMessage
+{
+    [self finishReceivingMessageAnimated:YES];
+}
+
+- (void)finishReceivingMessageAnimated:(BOOL)animated {
+
+    self.showTypingIndicator = NO;
+
+    [self.collectionView.collectionViewLayout invalidateLayoutWithContext:[JSQMessagesCollectionViewFlowLayoutInvalidationContext context]];
+    [self.collectionView reloadData];
+
+    if (self.automaticallyScrollsToMostRecentMessage && ![self jsq_isMenuVisible]) {
+        [self scrollToBottomAnimated:animated];
+    }
+
+    UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, [NSBundle jsq_localizedStringForKey:@"new_message_received_accessibility_announcement"]);
+}
+
+- (void)scrollToBottomAnimated:(BOOL)animated
+{
+    if ([self.collectionView numberOfSections] == 0) {
+        return;
+    }
+
+    NSIndexPath *lastCell = [NSIndexPath indexPathForItem:([self.collectionView numberOfItemsInSection:0] - 1) inSection:0];
+    [self scrollToIndexPath:lastCell animated:animated];
+}
+
+
+- (void)scrollToIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated
+{
+    if ([self.collectionView numberOfSections] <= indexPath.section) {
+        return;
+    }
+
+    NSInteger numberOfItems = [self.collectionView numberOfItemsInSection:indexPath.section];
+    if (numberOfItems == 0) {
+        return;
+    }
+
+    CGFloat collectionViewContentHeight = [self.collectionView.collectionViewLayout collectionViewContentSize].height;
+    BOOL isContentTooSmall = (collectionViewContentHeight < CGRectGetHeight(self.collectionView.bounds));
+
+    if (isContentTooSmall) {
+        //  workaround for the first few messages not scrolling
+        //  when the collection view content size is too small, `scrollToItemAtIndexPath:` doesn't work properly
+        //  this seems to be a UIKit bug, see #256 on GitHub
+        [self.collectionView scrollRectToVisible:CGRectMake(0.0, collectionViewContentHeight - 1.0f, 1.0f, 1.0f)
+                                        animated:animated];
+        return;
+    }
+
+    NSInteger item = MAX(MIN(indexPath.item, numberOfItems - 1), 0);
+    indexPath = [NSIndexPath indexPathForItem:item inSection:0];
+
+    //  workaround for really long messages not scrolling
+    //  if last message is too long, use scroll position bottom for better appearance, else use top
+    //  possibly a UIKit bug, see #480 on GitHub
+    CGSize cellSize = [self.collectionView.collectionViewLayout sizeForItemAtIndexPath:indexPath];
+    CGFloat maxHeightForVisibleMessage = CGRectGetHeight(self.collectionView.bounds)
+                                         - self.collectionView.contentInset.top
+                                         - self.collectionView.contentInset.bottom
+                                         - CGRectGetHeight(self.inputToolbar.bounds);
+    UICollectionViewScrollPosition scrollPosition = (cellSize.height > maxHeightForVisibleMessage) ? UICollectionViewScrollPositionBottom : UICollectionViewScrollPositionTop;
+
+    [self.collectionView scrollToItemAtIndexPath:indexPath
+                                atScrollPosition:scrollPosition
+                                        animated:animated];
+}
+
+- (BOOL)isOutgoingMessage:(id<JSQMessageData>)messageItem
+{
+    NSString *messageSenderId = [messageItem senderId];
+    NSParameterAssert(messageSenderId != nil);
+
+    return [messageSenderId isEqualToString:self.senderId];
+}
+
+#pragma mark - JSQMessages collection view data source
+
+- (id<JSQMessageData>)collectionView:(JSQMessagesCollectionView *)collectionView messageDataForItemAtIndexPath:(NSIndexPath *)indexPath
+{
+    NSAssert(NO, @"ERROR: required method not implemented: %s", __PRETTY_FUNCTION__);
+    return nil;
+}
+
+- (void)collectionView:(JSQMessagesCollectionView *)collectionView didDeleteMessageAtIndexPath:(NSIndexPath *)indexPath
+{
+    NSAssert(NO, @"ERROR: required method not implemented: %s", __PRETTY_FUNCTION__);
+}
+
+- (id<JSQMessageBubbleImageDataSource>)collectionView:(JSQMessagesCollectionView *)collectionView messageBubbleImageDataForItemAtIndexPath:(NSIndexPath *)indexPath
+{
+    NSAssert(NO, @"ERROR: required method not implemented: %s", __PRETTY_FUNCTION__);
+    return nil;
+}
+
+- (id<JSQMessageAvatarImageDataSource>)collectionView:(JSQMessagesCollectionView *)collectionView avatarImageDataForItemAtIndexPath:(NSIndexPath *)indexPath
+{
+    NSAssert(NO, @"ERROR: required method not implemented: %s", __PRETTY_FUNCTION__);
+    return nil;
+}
+
+- (NSAttributedString *)collectionView:(JSQMessagesCollectionView *)collectionView attributedTextForCellTopLabelAtIndexPath:(NSIndexPath *)indexPath
+{
+    return nil;
+}
+
+- (NSAttributedString *)collectionView:(JSQMessagesCollectionView *)collectionView attributedTextForMessageBubbleTopLabelAtIndexPath:(NSIndexPath *)indexPath
+{
+    return nil;
+}
+
+- (NSAttributedString *)collectionView:(JSQMessagesCollectionView *)collectionView attributedTextForCellBottomLabelAtIndexPath:(NSIndexPath *)indexPath
+{
+    return nil;
+}
+
+#pragma mark - Collection view data source
+
+- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
+{
+    return 0;
+}
+
+- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
+{
+    return 1;
+}
+
+- (UICollectionViewCell *)collectionView:(JSQMessagesCollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
+{
+    id<JSQMessageData> messageItem = [collectionView.dataSource collectionView:collectionView messageDataForItemAtIndexPath:indexPath];
+    NSParameterAssert(messageItem != nil);
+
+    BOOL isOutgoingMessage = [self isOutgoingMessage:messageItem];
+    BOOL isMediaMessage = [messageItem isMediaMessage];
+
+    NSString *cellIdentifier = nil;
+    if (isMediaMessage) {
+        cellIdentifier = isOutgoingMessage ? self.outgoingMediaCellIdentifier : self.incomingMediaCellIdentifier;
+    }
+    else {
+        cellIdentifier = isOutgoingMessage ? self.outgoingCellIdentifier : self.incomingCellIdentifier;
+    }
+
+    JSQMessagesCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
+    cell.delegate = collectionView;
+
+    if (!isMediaMessage) {
+        cell.textView.text = [messageItem text];
+
+        if ([UIDevice jsq_isCurrentDeviceBeforeiOS8]) {
+            //  workaround for iOS 7 textView data detectors bug
+            cell.textView.text = nil;
+            cell.textView.attributedText = [[NSAttributedString alloc] initWithString:[messageItem text]
+                                                                           attributes:@{ NSFontAttributeName : collectionView.collectionViewLayout.messageBubbleFont }];
+        }
+
+        NSParameterAssert(cell.textView.text != nil);
+
+        id<JSQMessageBubbleImageDataSource> bubbleImageDataSource = [collectionView.dataSource collectionView:collectionView messageBubbleImageDataForItemAtIndexPath:indexPath];
+        cell.messageBubbleImageView.image = [bubbleImageDataSource messageBubbleImage];
+        cell.messageBubbleImageView.highlightedImage = [bubbleImageDataSource messageBubbleHighlightedImage];
+    }
+    else {
+        id<JSQMessageMediaData> messageMedia = [messageItem media];
+        cell.mediaView = [messageMedia mediaView] ?: [messageMedia mediaPlaceholderView];
+        NSParameterAssert(cell.mediaView != nil);
+    }
+
+    BOOL needsAvatar = YES;
+    if (isOutgoingMessage && CGSizeEqualToSize(collectionView.collectionViewLayout.outgoingAvatarViewSize, CGSizeZero)) {
+        needsAvatar = NO;
+    }
+    else if (!isOutgoingMessage && CGSizeEqualToSize(collectionView.collectionViewLayout.incomingAvatarViewSize, CGSizeZero)) {
+        needsAvatar = NO;
+    }
+
+    id<JSQMessageAvatarImageDataSource> avatarImageDataSource = nil;
+    if (needsAvatar) {
+        avatarImageDataSource = [collectionView.dataSource collectionView:collectionView avatarImageDataForItemAtIndexPath:indexPath];
+        if (avatarImageDataSource != nil) {
+
+            UIImage *avatarImage = [avatarImageDataSource avatarImage];
+            if (avatarImage == nil) {
+                cell.avatarImageView.image = [avatarImageDataSource avatarPlaceholderImage];
+                cell.avatarImageView.highlightedImage = nil;
+            }
+            else {
+                cell.avatarImageView.image = avatarImage;
+                cell.avatarImageView.highlightedImage = [avatarImageDataSource avatarHighlightedImage];
+            }
+        }
+    }
+
+    cell.cellTopLabel.attributedText = [collectionView.dataSource collectionView:collectionView attributedTextForCellTopLabelAtIndexPath:indexPath];
+    cell.messageBubbleTopLabel.attributedText = [collectionView.dataSource collectionView:collectionView attributedTextForMessageBubbleTopLabelAtIndexPath:indexPath];
+    cell.cellBottomLabel.attributedText = [collectionView.dataSource collectionView:collectionView attributedTextForCellBottomLabelAtIndexPath:indexPath];
+
+    CGFloat bubbleTopLabelInset = (avatarImageDataSource != nil) ? 60.0f : 15.0f;
+
+    if (isOutgoingMessage) {
+        cell.messageBubbleTopLabel.textInsets = UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, bubbleTopLabelInset);
+    }
+    else {
+        cell.messageBubbleTopLabel.textInsets = UIEdgeInsetsMake(0.0f, bubbleTopLabelInset, 0.0f, 0.0f);
+    }
+
+    cell.textView.dataDetectorTypes = UIDataDetectorTypeAll;
+
+    cell.backgroundColor = [UIColor clearColor];
+    cell.layer.rasterizationScale = [UIScreen mainScreen].scale;
+    cell.layer.shouldRasterize = YES;
+    [self collectionView:collectionView accessibilityForCell:cell indexPath:indexPath message:messageItem];
+
+    return cell;
+}
+
+- (void)collectionView:(JSQMessagesCollectionView *)collectionView
+  accessibilityForCell:(JSQMessagesCollectionViewCell*)cell
+             indexPath:(NSIndexPath *)indexPath
+               message:(id<JSQMessageData>)messageItem
+{
+    const BOOL isMediaMessage = [messageItem isMediaMessage];
+    cell.isAccessibilityElement = YES;
+    if (!isMediaMessage) {
+        cell.accessibilityLabel = [NSString stringWithFormat:[NSBundle jsq_localizedStringForKey:@"text_message_accessibility_label"],
+                                   [messageItem senderDisplayName],
+                                   [messageItem text]];
+    }
+    else {
+        cell.accessibilityLabel = [NSString stringWithFormat:[NSBundle jsq_localizedStringForKey:@"media_message_accessibility_label"],
+                                   [messageItem senderDisplayName]];
+    }
+}
+
+- (UICollectionReusableView *)collectionView:(JSQMessagesCollectionView *)collectionView
+           viewForSupplementaryElementOfKind:(NSString *)kind
+                                 atIndexPath:(NSIndexPath *)indexPath
+{
+    if (self.showTypingIndicator && [kind isEqualToString:UICollectionElementKindSectionFooter]) {
+        return [collectionView dequeueTypingIndicatorFooterViewForIndexPath:indexPath];
+    }
+    else if (self.showLoadEarlierMessagesHeader && [kind isEqualToString:UICollectionElementKindSectionHeader]) {
+        return [collectionView dequeueLoadEarlierMessagesViewHeaderForIndexPath:indexPath];
+    }
+
+    return nil;
+}
+
+- (CGSize)collectionView:(UICollectionView *)collectionView
+                  layout:(JSQMessagesCollectionViewFlowLayout *)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section
+{
+    if (!self.showTypingIndicator) {
+        return CGSizeZero;
+    }
+
+    return CGSizeMake([collectionViewLayout itemWidth], kJSQMessagesTypingIndicatorFooterViewHeight);
+}
+
+- (CGSize)collectionView:(UICollectionView *)collectionView
+                  layout:(JSQMessagesCollectionViewFlowLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section
+{
+    if (!self.showLoadEarlierMessagesHeader) {
+        return CGSizeZero;
+    }
+
+    return CGSizeMake([collectionViewLayout itemWidth], kJSQMessagesLoadEarlierHeaderViewHeight);
+}
+
+#pragma mark - Collection view delegate
+
+- (BOOL)collectionView:(JSQMessagesCollectionView *)collectionView shouldShowMenuForItemAtIndexPath:(NSIndexPath *)indexPath
+{
+    //  disable menu for media messages
+    id<JSQMessageData> messageItem = [collectionView.dataSource collectionView:collectionView messageDataForItemAtIndexPath:indexPath];
+    if ([messageItem isMediaMessage]) {
+        return NO;
+    }
+
+    self.selectedIndexPathForMenu = indexPath;
+
+    //  textviews are selectable to allow data detectors
+    //  however, this allows the 'copy, define, select' UIMenuController to show
+    //  which conflicts with the collection view's UIMenuController
+    //  temporarily disable 'selectable' to prevent this issue
+    JSQMessagesCollectionViewCell *selectedCell = (JSQMessagesCollectionViewCell *)[collectionView cellForItemAtIndexPath:indexPath];
+    selectedCell.textView.selectable = NO;
+
+    return YES;
+}
+
+- (BOOL)collectionView:(UICollectionView *)collectionView canPerformAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender
+{
+    if (action == @selector(copy:) || action == @selector(delete:)) {
+        return YES;
+    }
+
+    return NO;
+}
+
+- (void)collectionView:(JSQMessagesCollectionView *)collectionView performAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender
+{
+    if (action == @selector(copy:)) {
+        id<JSQMessageData> messageData = [collectionView.dataSource collectionView:collectionView messageDataForItemAtIndexPath:indexPath];
+        [[UIPasteboard generalPasteboard] setString:[messageData text]];
+    }
+    else if (action == @selector(delete:)) {
+        [collectionView.dataSource collectionView:collectionView didDeleteMessageAtIndexPath:indexPath];
+
+        [collectionView deleteItemsAtIndexPaths:@[indexPath]];
+        [collectionView.collectionViewLayout invalidateLayout];
+    }
+}
+
+#pragma mark - Collection view delegate flow layout
+
+- (CGSize)collectionView:(JSQMessagesCollectionView *)collectionView
+                  layout:(JSQMessagesCollectionViewFlowLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
+{
+    return [collectionViewLayout sizeForItemAtIndexPath:indexPath];
+}
+
+- (CGFloat)collectionView:(JSQMessagesCollectionView *)collectionView
+                   layout:(JSQMessagesCollectionViewFlowLayout *)collectionViewLayout heightForCellTopLabelAtIndexPath:(NSIndexPath *)indexPath
+{
+    return 0.0f;
+}
+
+- (CGFloat)collectionView:(JSQMessagesCollectionView *)collectionView
+                   layout:(JSQMessagesCollectionViewFlowLayout *)collectionViewLayout heightForMessageBubbleTopLabelAtIndexPath:(NSIndexPath *)indexPath
+{
+    return 0.0f;
+}
+
+- (CGFloat)collectionView:(JSQMessagesCollectionView *)collectionView
+                   layout:(JSQMessagesCollectionViewFlowLayout *)collectionViewLayout heightForCellBottomLabelAtIndexPath:(NSIndexPath *)indexPath
+{
+    return 0.0f;
+}
+
+- (void)collectionView:(JSQMessagesCollectionView *)collectionView
+ didTapAvatarImageView:(UIImageView *)avatarImageView
+           atIndexPath:(NSIndexPath *)indexPath { }
+
+- (void)collectionView:(JSQMessagesCollectionView *)collectionView didTapMessageBubbleAtIndexPath:(NSIndexPath *)indexPath { }
+
+- (void)collectionView:(JSQMessagesCollectionView *)collectionView
+ didTapCellAtIndexPath:(NSIndexPath *)indexPath
+         touchLocation:(CGPoint)touchLocation { }
+
+#pragma mark - Input toolbar delegate
+
+- (void)messagesInputToolbar:(JSQMessagesInputToolbar *)toolbar didPressLeftBarButton:(UIButton *)sender
+{
+    if (toolbar.sendButtonOnRight) {
+        [self didPressAccessoryButton:sender];
+    }
+    else {
+        [self didPressSendButton:sender
+                 withMessageText:[self jsq_currentlyComposedMessageText]
+                        senderId:self.senderId
+               senderDisplayName:self.senderDisplayName
+                            date:[NSDate date]];
+    }
+}
+
+- (void)messagesInputToolbar:(JSQMessagesInputToolbar *)toolbar didPressRightBarButton:(UIButton *)sender
+{
+    if (toolbar.sendButtonOnRight) {
+        [self didPressSendButton:sender
+                 withMessageText:[self jsq_currentlyComposedMessageText]
+                        senderId:self.senderId
+               senderDisplayName:self.senderDisplayName
+                            date:[NSDate date]];
+    }
+    else {
+        [self didPressAccessoryButton:sender];
+    }
+}
+
+- (NSString *)jsq_currentlyComposedMessageText
+{
+    //  auto-accept any auto-correct suggestions
+    [self.inputToolbar.contentView.textView.inputDelegate selectionWillChange:self.inputToolbar.contentView.textView];
+    [self.inputToolbar.contentView.textView.inputDelegate selectionDidChange:self.inputToolbar.contentView.textView];
+
+    return [self.inputToolbar.contentView.textView.text jsq_stringByTrimingWhitespace];
+}
+
+#pragma mark - Text view delegate
+
+- (void)textViewDidBeginEditing:(UITextView *)textView
+{
+    if (textView != self.inputToolbar.contentView.textView) {
+        return;
+    }
+
+    [textView becomeFirstResponder];
+
+    if (self.automaticallyScrollsToMostRecentMessage) {
+        [self scrollToBottomAnimated:YES];
+    }
+}
+
+- (void)textViewDidChange:(UITextView *)textView
+{
+    if (textView != self.inputToolbar.contentView.textView) {
+        return;
+    }
+
+    [self.inputToolbar toggleSendButtonEnabled];
+}
+
+- (void)textViewDidEndEditing:(UITextView *)textView
+{
+    if (textView != self.inputToolbar.contentView.textView) {
+        return;
+    }
+
+    [textView resignFirstResponder];
+}
+
+#pragma mark - Notifications
+
+- (void)jsq_handleDidChangeStatusBarFrameNotification:(NSNotification *)notification
+{
+    if (self.keyboardController.keyboardIsVisible) {
+        [self jsq_setToolbarBottomLayoutGuideConstant:CGRectGetHeight(self.keyboardController.currentKeyboardFrame)];
+    }
+}
+
+- (void)didReceiveMenuWillShowNotification:(NSNotification *)notification
+{
+    if (!self.selectedIndexPathForMenu) {
+        return;
+    }
+
+    [[NSNotificationCenter defaultCenter] removeObserver:self
+                                                    name:UIMenuControllerWillShowMenuNotification
+                                                  object:nil];
+
+    UIMenuController *menu = [notification object];
+    [menu setMenuVisible:NO animated:NO];
+
+    JSQMessagesCollectionViewCell *selectedCell = (JSQMessagesCollectionViewCell *)[self.collectionView cellForItemAtIndexPath:self.selectedIndexPathForMenu];
+    CGRect selectedCellMessageBubbleFrame = [selectedCell convertRect:selectedCell.messageBubbleContainerView.frame toView:self.view];
+
+    [menu setTargetRect:selectedCellMessageBubbleFrame inView:self.view];
+    [menu setMenuVisible:YES animated:YES];
+
+    [[NSNotificationCenter defaultCenter] addObserver:self
+                                             selector:@selector(didReceiveMenuWillShowNotification:)
+                                                 name:UIMenuControllerWillShowMenuNotification
+                                               object:nil];
+}
+
+- (void)didReceiveMenuWillHideNotification:(NSNotification *)notification
+{
+    if (!self.selectedIndexPathForMenu) {
+        return;
+    }
+
+    //  per comment above in 'shouldShowMenuForItemAtIndexPath:'
+    //  re-enable 'selectable', thus re-enabling data detectors if present
+    JSQMessagesCollectionViewCell *selectedCell = (JSQMessagesCollectionViewCell *)[self.collectionView cellForItemAtIndexPath:self.selectedIndexPathForMenu];
+    selectedCell.textView.selectable = YES;
+    self.selectedIndexPathForMenu = nil;
+}
+
+#pragma mark - Key-value observing
+
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
+{
+    if (context == kJSQMessagesKeyValueObservingContext) {
+
+        if (object == self.inputToolbar.contentView.textView
+            && [keyPath isEqualToString:NSStringFromSelector(@selector(contentSize))]) {
+
+            CGSize oldContentSize = [[change objectForKey:NSKeyValueChangeOldKey] CGSizeValue];
+            CGSize newContentSize = [[change objectForKey:NSKeyValueChangeNewKey] CGSizeValue];
+
+            CGFloat dy = newContentSize.height - oldContentSize.height;
+
+            [self jsq_adjustInputToolbarForComposerTextViewContentSizeChange:dy];
+            [self jsq_updateCollectionViewInsets];
+            if (self.automaticallyScrollsToMostRecentMessage) {
+                [self scrollToBottomAnimated:NO];
+            }
+        }
+    }
+}
+
+#pragma mark - Keyboard controller delegate
+
+- (void)keyboardController:(JSQMessagesKeyboardController *)keyboardController keyboardDidChangeFrame:(CGRect)keyboardFrame
+{
+    if (![self.inputToolbar.contentView.textView isFirstResponder] && self.toolbarBottomLayoutGuide.constant == 0.0) {
+        return;
+    }
+
+    CGFloat heightFromBottom = CGRectGetMaxY(self.collectionView.frame) - CGRectGetMinY(keyboardFrame);
+
+    heightFromBottom = MAX(0.0, heightFromBottom);
+
+    [self jsq_setToolbarBottomLayoutGuideConstant:heightFromBottom];
+}
+
+- (void)jsq_setToolbarBottomLayoutGuideConstant:(CGFloat)constant
+{
+    self.toolbarBottomLayoutGuide.constant = constant;
+    [self.view setNeedsUpdateConstraints];
+    [self.view layoutIfNeeded];
+
+    [self jsq_updateCollectionViewInsets];
+}
+
+- (void)jsq_updateKeyboardTriggerPoint
+{
+    self.keyboardController.keyboardTriggerPoint = CGPointMake(0.0f, CGRectGetHeight(self.inputToolbar.bounds));
+}
+
+#pragma mark - Gesture recognizers
+
+- (void)jsq_handleInteractivePopGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
+{
+    switch (gestureRecognizer.state) {
+        case UIGestureRecognizerStateBegan:
+        {
+            if ([UIDevice jsq_isCurrentDeviceBeforeiOS8]) {
+                [self.snapshotView removeFromSuperview];
+            }
+
+            self.textViewWasFirstResponderDuringInteractivePop = [self.inputToolbar.contentView.textView isFirstResponder];
+
+            [self.keyboardController endListeningForKeyboard];
+
+            if ([UIDevice jsq_isCurrentDeviceBeforeiOS8]) {
+                [self.inputToolbar.contentView.textView resignFirstResponder];
+                [UIView animateWithDuration:0.0
+                                 animations:^{
+                                     [self jsq_setToolbarBottomLayoutGuideConstant:0.0];
+                                 }];
+
+                UIView *snapshot = [self.view snapshotViewAfterScreenUpdates:YES];
+                [self.view addSubview:snapshot];
+                self.snapshotView = snapshot;
+            }
+        }
+            break;
+        case UIGestureRecognizerStateChanged:
+            break;
+        case UIGestureRecognizerStateCancelled:
+        case UIGestureRecognizerStateEnded:
+        case UIGestureRecognizerStateFailed:
+            [self.keyboardController beginListeningForKeyboard];
+            if (self.textViewWasFirstResponderDuringInteractivePop) {
+                [self.inputToolbar.contentView.textView becomeFirstResponder];
+            }
+
+            if ([UIDevice jsq_isCurrentDeviceBeforeiOS8]) {
+                [self.snapshotView removeFromSuperview];
+            }
+            break;
+        default:
+            break;
+    }
+}
+
+#pragma mark - Input toolbar utilities
+
+- (BOOL)jsq_inputToolbarHasReachedMaximumHeight
+{
+    return CGRectGetMinY(self.inputToolbar.frame) == (self.topLayoutGuide.length + self.topContentAdditionalInset);
+}
+
+- (void)jsq_adjustInputToolbarForComposerTextViewContentSizeChange:(CGFloat)dy
+{
+    BOOL contentSizeIsIncreasing = (dy > 0);
+
+    if ([self jsq_inputToolbarHasReachedMaximumHeight]) {
+        BOOL contentOffsetIsPositive = (self.inputToolbar.contentView.textView.contentOffset.y > 0);
+
+        if (contentSizeIsIncreasing || contentOffsetIsPositive) {
+            [self jsq_scrollComposerTextViewToBottomAnimated:YES];
+            return;
+        }
+    }
+
+    CGFloat toolbarOriginY = CGRectGetMinY(self.inputToolbar.frame);
+    CGFloat newToolbarOriginY = toolbarOriginY - dy;
+
+    //  attempted to increase origin.Y above topLayoutGuide
+    if (newToolbarOriginY <= self.topLayoutGuide.length + self.topContentAdditionalInset) {
+        dy = toolbarOriginY - (self.topLayoutGuide.length + self.topContentAdditionalInset);
+        [self jsq_scrollComposerTextViewToBottomAnimated:YES];
+    }
+
+    [self jsq_adjustInputToolbarHeightConstraintByDelta:dy];
+
+    [self jsq_updateKeyboardTriggerPoint];
+
+    if (dy < 0) {
+        [self jsq_scrollComposerTextViewToBottomAnimated:NO];
+    }
+}
+
+- (void)jsq_adjustInputToolbarHeightConstraintByDelta:(CGFloat)dy
+{
+    CGFloat proposedHeight = self.toolbarHeightConstraint.constant + dy;
+
+    CGFloat finalHeight = MAX(proposedHeight, self.inputToolbar.preferredDefaultHeight);
+
+    if (self.inputToolbar.maximumHeight != NSNotFound) {
+        finalHeight = MIN(finalHeight, self.inputToolbar.maximumHeight);
+    }
+
+    if (self.toolbarHeightConstraint.constant != finalHeight) {
+        self.toolbarHeightConstraint.constant = finalHeight;
+        [self.view setNeedsUpdateConstraints];
+        [self.view layoutIfNeeded];
+    }
+}
+
+- (void)jsq_scrollComposerTextViewToBottomAnimated:(BOOL)animated
+{
+    UITextView *textView = self.inputToolbar.contentView.textView;
+    CGPoint contentOffsetToShowLastLine = CGPointMake(0.0f, textView.contentSize.height - CGRectGetHeight(textView.bounds));
+
+    if (!animated) {
+        textView.contentOffset = contentOffsetToShowLastLine;
+        return;
+    }
+
+    [UIView animateWithDuration:0.01
+                          delay:0.01
+                        options:UIViewAnimationOptionCurveLinear
+                     animations:^{
+                         textView.contentOffset = contentOffsetToShowLastLine;
+                     }
+                     completion:nil];
+}
+
+#pragma mark - Collection view utilities
+
+- (void)jsq_updateCollectionViewInsets
+{
+    [self jsq_setCollectionViewInsetsTopValue:self.topLayoutGuide.length + self.topContentAdditionalInset
+                                  bottomValue:CGRectGetMaxY(self.collectionView.frame) - CGRectGetMinY(self.inputToolbar.frame)];
+}
+
+- (void)jsq_setCollectionViewInsetsTopValue:(CGFloat)top bottomValue:(CGFloat)bottom
+{
+    UIEdgeInsets insets = UIEdgeInsetsMake(top, 0.0f, bottom, 0.0f);
+    self.collectionView.contentInset = insets;
+    self.collectionView.scrollIndicatorInsets = insets;
+}
+
+- (BOOL)jsq_isMenuVisible
+{
+    //  check if cell copy menu is showing
+    //  it is only our menu if `selectedIndexPathForMenu` is not `nil`
+    return self.selectedIndexPathForMenu != nil && [[UIMenuController sharedMenuController] isMenuVisible];
+}
+
+#pragma mark - Utilities
+
+- (void)jsq_addObservers
+{
+    if (self.jsq_isObserving) {
+        return;
+    }
+
+    [self.inputToolbar.contentView.textView addObserver:self
+                                             forKeyPath:NSStringFromSelector(@selector(contentSize))
+                                                options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew
+                                                context:kJSQMessagesKeyValueObservingContext];
+
+    self.jsq_isObserving = YES;
+}
+
+- (void)jsq_removeObservers
+{
+    if (!_jsq_isObserving) {
+        return;
+    }
+
+    @try {
+        [_inputToolbar.contentView.textView removeObserver:self
+                                                forKeyPath:NSStringFromSelector(@selector(contentSize))
+                                                   context:kJSQMessagesKeyValueObservingContext];
+    }
+    @catch (NSException * __unused exception) { }
+
+    _jsq_isObserving = NO;
+}
+
+- (void)jsq_registerForNotifications:(BOOL)registerForNotifications
+{
+    if (registerForNotifications) {
+        [[NSNotificationCenter defaultCenter] addObserver:self
+                                                 selector:@selector(jsq_handleDidChangeStatusBarFrameNotification:)
+                                                     name:UIApplicationDidChangeStatusBarFrameNotification
+                                                   object:nil];
+
+        [[NSNotificationCenter defaultCenter] addObserver:self
+                                                 selector:@selector(didReceiveMenuWillShowNotification:)
+                                                     name:UIMenuControllerWillShowMenuNotification
+                                                   object:nil];
+
+        [[NSNotificationCenter defaultCenter] addObserver:self
+                                                 selector:@selector(didReceiveMenuWillHideNotification:)
+                                                     name:UIMenuControllerWillHideMenuNotification
+                                                   object:nil];
+    }
+    else {
+        [[NSNotificationCenter defaultCenter] removeObserver:self
+                                                        name:UIApplicationDidChangeStatusBarFrameNotification
+                                                      object:nil];
+
+        [[NSNotificationCenter defaultCenter] removeObserver:self
+                                                        name:UIMenuControllerWillShowMenuNotification
+                                                      object:nil];
+
+        [[NSNotificationCenter defaultCenter] removeObserver:self
+                                                        name:UIMenuControllerWillHideMenuNotification
+                                                      object:nil];
+    }
+}
+
+- (void)jsq_addActionToInteractivePopGestureRecognizer:(BOOL)addAction
+{
+    if (self.currentInteractivePopGestureRecognizer != nil) {
+        [self.currentInteractivePopGestureRecognizer removeTarget:nil
+                                                           action:@selector(jsq_handleInteractivePopGestureRecognizer:)];
+        self.currentInteractivePopGestureRecognizer = nil;
+    }
+    
+    if (addAction) {
+        [self.navigationController.interactivePopGestureRecognizer addTarget:self
+                                                                      action:@selector(jsq_handleInteractivePopGestureRecognizer:)];
+        self.currentInteractivePopGestureRecognizer = self.navigationController.interactivePopGestureRecognizer;
+    }
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Controllers/JSQMessagesViewController.xib b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Controllers/JSQMessagesViewController.xib
new file mode 100644
index 0000000..c866be2
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Controllers/JSQMessagesViewController.xib
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9531" systemVersion="15C50" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES">
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9529"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="JSQMessagesViewController">
+            <connections>
+                <outlet property="collectionView" destination="l9u-2b-4LK" id="bLP-6g-CkO"/>
+                <outlet property="inputToolbar" destination="BoD-Az-3DM" id="w74-g9-1qA"/>
+                <outlet property="toolbarBottomLayoutGuide" destination="rHs-6q-NX4" id="d6h-iu-VMX"/>
+                <outlet property="toolbarHeightConstraint" destination="HIk-02-qcW" id="jE8-xC-1eD"/>
+                <outlet property="view" destination="mUa-cS-ru4" id="nki-T1-RTI"/>
+            </connections>
+        </placeholder>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <view contentMode="scaleToFill" id="mUa-cS-ru4">
+            <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
+            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+            <subviews>
+                <collectionView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" minimumZoomScale="0.0" maximumZoomScale="0.0" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="l9u-2b-4LK" customClass="JSQMessagesCollectionView">
+                    <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
+                    <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                    <collectionViewLayout key="collectionViewLayout" id="dZl-7C-LHR" customClass="JSQMessagesCollectionViewFlowLayout"/>
+                    <cells/>
+                </collectionView>
+                <toolbar opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="BoD-Az-3DM" customClass="JSQMessagesInputToolbar">
+                    <rect key="frame" x="0.0" y="524" width="320" height="44"/>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="44" id="HIk-02-qcW"/>
+                    </constraints>
+                    <items/>
+                </toolbar>
+            </subviews>
+            <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+            <constraints>
+                <constraint firstAttribute="trailing" secondItem="BoD-Az-3DM" secondAttribute="trailing" id="7xc-Ha-asg"/>
+                <constraint firstItem="l9u-2b-4LK" firstAttribute="leading" secondItem="mUa-cS-ru4" secondAttribute="leading" id="MmF-oh-Y75"/>
+                <constraint firstAttribute="trailing" secondItem="l9u-2b-4LK" secondAttribute="trailing" id="O9u-TA-A0e"/>
+                <constraint firstAttribute="bottom" secondItem="l9u-2b-4LK" secondAttribute="bottom" id="Re7-WW-UmS"/>
+                <constraint firstItem="l9u-2b-4LK" firstAttribute="top" secondItem="mUa-cS-ru4" secondAttribute="top" id="dCQ-DM-Wdj"/>
+                <constraint firstAttribute="bottom" secondItem="BoD-Az-3DM" secondAttribute="bottom" id="rHs-6q-NX4"/>
+                <constraint firstItem="BoD-Az-3DM" firstAttribute="leading" secondItem="mUa-cS-ru4" secondAttribute="leading" id="ts7-8f-0lH"/>
+            </constraints>
+            <nil key="simulatedStatusBarMetrics"/>
+        </view>
+    </objects>
+</document>
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Factories/JSQMessagesAvatarImageFactory.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Factories/JSQMessagesAvatarImageFactory.h
new file mode 100644
index 0000000..759cd53
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Factories/JSQMessagesAvatarImageFactory.h
@@ -0,0 +1,99 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+#import "JSQMessagesAvatarImage.h"
+
+/**
+ *  `JSQMessagesAvatarImageFactory` is a factory that provides a means for creating and styling
+ *  `JSQMessagesAvatarImage` objects to be displayed in a `JSQMessagesCollectionViewCell` of a `JSQMessagesCollectionView`.
+ */
+@interface JSQMessagesAvatarImageFactory : NSObject
+
+/**
+*  Creates and returns a `JSQMessagesAvatarImage` object with the specified placeholderImage that is
+*  cropped to a circle of the given diameter.
+*
+*  @param placeholderImage An image object that represents a placeholder avatar image. This value must not be `nil`.
+*  @param diameter         An integer value specifying the diameter size of the avatar in points. This value must be greater than `0`.
+*
+*  @return An initialized `JSQMessagesAvatarImage` object if created successfully, `nil` otherwise.
+*/
++ (JSQMessagesAvatarImage *)avatarImageWithPlaceholder:(UIImage *)placeholderImage diameter:(NSUInteger)diameter;
+
+/**
+ *  Creates and returns a `JSQMessagesAvatarImage` object with the specified image that is
+ *  cropped to a circle of the given diameter and used for the `avatarImage` and `avatarPlaceholderImage` properties
+ *  of the returned `JSQMessagesAvatarImage` object. This image is then copied and has a transparent black mask applied to it, 
+ *  which is used for the `avatarHighlightedImage` property of the returned `JSQMessagesAvatarImage` object.
+ *
+ *  @param image    An image object that represents an avatar image. This value must not be `nil`.
+ *  @param diameter An integer value specifying the diameter size of the avatar in points. This value must be greater than `0`.
+ *
+ *  @return An initialized `JSQMessagesAvatarImage` object if created successfully, `nil` otherwise.
+ */
++ (JSQMessagesAvatarImage *)avatarImageWithImage:(UIImage *)image diameter:(NSUInteger)diameter;
+
+/**
+ *  Returns a copy of the specified image that is cropped to a circle with the given diameter.
+ *
+ *  @param image    The image to crop. This value must not be `nil`.
+ *  @param diameter An integer value specifying the diameter size of the image in points. This value must be greater than `0`.
+ *
+ *  @return A new image object if successful, `nil` otherwise.
+ */
++ (UIImage *)circularAvatarImage:(UIImage *)image withDiameter:(NSUInteger)diameter;
+
+/**
+ *  Returns a copy of the specified image that is cropped to a circle with the given diameter.
+ *  Additionally, a transparent overlay is applied to the image to represent a pressed or highlighted state.
+ *
+ *  @param image    The image to crop. This value must not be `nil`.
+ *  @param diameter An integer value specifying the diameter size of the image in points. This value must be greater than `0`.
+ *
+ *  @return A new image object if successful, `nil` otherwise.
+ */
++ (UIImage *)circularAvatarHighlightedImage:(UIImage *)image withDiameter:(NSUInteger)diameter;
+
+/**
+ *  Creates and returns a `JSQMessagesAvatarImage` object with a circular shape that displays the specified userInitials
+ *  with the given backgroundColor, textColor, font, and diameter.
+ *
+ *  @param userInitials    The user initials to display in the avatar image. This value must not be `nil`.
+ *  @param backgroundColor The background color of the avatar. This value must not be `nil`.
+ *  @param textColor       The color of the text of the userInitials. This value must not be `nil`.
+ *  @param font            The font applied to userInitials. This value must not be `nil`.
+ *  @param diameter        The diameter of the avatar image. This value must be greater than `0`.
+ *
+ *  @return An initialized `JSQMessagesAvatarImage` object if created successfully, `nil` otherwise.
+ *
+ *  @discussion This method does not attempt to detect or correct incompatible parameters. 
+ *  That is to say, you are responsible for providing a font size and diameter that make sense.
+ *  For example, a font size of `14.0f` and a diameter of `34.0f` will result in an avatar similar to Messages in iOS 7. 
+ *  However, a font size `30.0f` and diameter of `10.0f` will not produce a desirable image.
+ *  Further, this method does not check the length of userInitials. It is recommended that you pass a string of length `2` or `3`.
+ */
++ (JSQMessagesAvatarImage *)avatarImageWithUserInitials:(NSString *)userInitials
+                                        backgroundColor:(UIColor *)backgroundColor
+                                              textColor:(UIColor *)textColor
+                                                   font:(UIFont *)font
+                                               diameter:(NSUInteger)diameter;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Factories/JSQMessagesAvatarImageFactory.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Factories/JSQMessagesAvatarImageFactory.m
new file mode 100644
index 0000000..222c2c8
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Factories/JSQMessagesAvatarImageFactory.m
@@ -0,0 +1,159 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQMessagesAvatarImageFactory.h"
+
+#import "UIColor+JSQMessages.h"
+
+
+@implementation JSQMessagesAvatarImageFactory
+
+#pragma mark - Public
+
++ (JSQMessagesAvatarImage *)avatarImageWithPlaceholder:(UIImage *)placeholderImage diameter:(NSUInteger)diameter
+{
+    UIImage *circlePlaceholderImage = [JSQMessagesAvatarImageFactory jsq_circularImage:placeholderImage
+                                                                          withDiameter:diameter
+                                                                      highlightedColor:nil];
+
+    return [JSQMessagesAvatarImage avatarImageWithPlaceholder:circlePlaceholderImage];
+}
+
++ (JSQMessagesAvatarImage *)avatarImageWithImage:(UIImage *)image diameter:(NSUInteger)diameter
+{
+    UIImage *avatar = [JSQMessagesAvatarImageFactory circularAvatarImage:image withDiameter:diameter];
+    UIImage *highlightedAvatar = [JSQMessagesAvatarImageFactory circularAvatarHighlightedImage:image withDiameter:diameter];
+
+    return [[JSQMessagesAvatarImage alloc] initWithAvatarImage:avatar
+                                              highlightedImage:highlightedAvatar
+                                              placeholderImage:avatar];
+}
+
++ (UIImage *)circularAvatarImage:(UIImage *)image withDiameter:(NSUInteger)diameter
+{
+    return [JSQMessagesAvatarImageFactory jsq_circularImage:image
+                                               withDiameter:diameter
+                                           highlightedColor:nil];
+}
+
++ (UIImage *)circularAvatarHighlightedImage:(UIImage *)image withDiameter:(NSUInteger)diameter
+{
+    return [JSQMessagesAvatarImageFactory jsq_circularImage:image
+                                               withDiameter:diameter
+                                           highlightedColor:[UIColor colorWithWhite:0.1f alpha:0.3f]];
+}
+
++ (JSQMessagesAvatarImage *)avatarImageWithUserInitials:(NSString *)userInitials
+                                        backgroundColor:(UIColor *)backgroundColor
+                                              textColor:(UIColor *)textColor
+                                                   font:(UIFont *)font
+                                               diameter:(NSUInteger)diameter
+{
+    UIImage *avatarImage = [JSQMessagesAvatarImageFactory jsq_imageWitInitials:userInitials
+                                                               backgroundColor:backgroundColor
+                                                                     textColor:textColor
+                                                                          font:font
+                                                                      diameter:diameter];
+
+    UIImage *avatarHighlightedImage = [JSQMessagesAvatarImageFactory jsq_circularImage:avatarImage
+                                                                          withDiameter:diameter
+                                                                      highlightedColor:[UIColor colorWithWhite:0.1f alpha:0.3f]];
+
+    return [[JSQMessagesAvatarImage alloc] initWithAvatarImage:avatarImage
+                                              highlightedImage:avatarHighlightedImage
+                                              placeholderImage:avatarImage];
+}
+
+#pragma mark - Private
+
++ (UIImage *)jsq_imageWitInitials:(NSString *)initials
+                  backgroundColor:(UIColor *)backgroundColor
+                        textColor:(UIColor *)textColor
+                             font:(UIFont *)font
+                         diameter:(NSUInteger)diameter
+{
+    NSParameterAssert(initials != nil);
+    NSParameterAssert(backgroundColor != nil);
+    NSParameterAssert(textColor != nil);
+    NSParameterAssert(font != nil);
+    NSParameterAssert(diameter > 0);
+
+    CGRect frame = CGRectMake(0.0f, 0.0f, diameter, diameter);
+
+    NSDictionary *attributes = @{ NSFontAttributeName : font,
+                                  NSForegroundColorAttributeName : textColor };
+
+    CGRect textFrame = [initials boundingRectWithSize:frame.size
+                                              options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
+                                           attributes:attributes
+                                              context:nil];
+
+    CGPoint frameMidPoint = CGPointMake(CGRectGetMidX(frame), CGRectGetMidY(frame));
+    CGPoint textFrameMidPoint = CGPointMake(CGRectGetMidX(textFrame), CGRectGetMidY(textFrame));
+
+    CGFloat dx = frameMidPoint.x - textFrameMidPoint.x;
+    CGFloat dy = frameMidPoint.y - textFrameMidPoint.y;
+    CGPoint drawPoint = CGPointMake(dx, dy);
+    UIImage *image = nil;
+
+    UIGraphicsBeginImageContextWithOptions(frame.size, NO, [UIScreen mainScreen].scale);
+    {
+        CGContextRef context = UIGraphicsGetCurrentContext();
+
+        CGContextSetFillColorWithColor(context, backgroundColor.CGColor);
+        CGContextFillRect(context, frame);
+        [initials drawAtPoint:drawPoint withAttributes:attributes];
+
+        image = UIGraphicsGetImageFromCurrentImageContext();
+
+    }
+    UIGraphicsEndImageContext();
+
+    return [JSQMessagesAvatarImageFactory jsq_circularImage:image withDiameter:diameter highlightedColor:nil];
+}
+
++ (UIImage *)jsq_circularImage:(UIImage *)image withDiameter:(NSUInteger)diameter highlightedColor:(UIColor *)highlightedColor
+{
+    NSParameterAssert(image != nil);
+    NSParameterAssert(diameter > 0);
+
+    CGRect frame = CGRectMake(0.0f, 0.0f, diameter, diameter);
+    UIImage *newImage = nil;
+
+    UIGraphicsBeginImageContextWithOptions(frame.size, NO, [UIScreen mainScreen].scale);
+    {
+        CGContextRef context = UIGraphicsGetCurrentContext();
+
+        UIBezierPath *imgPath = [UIBezierPath bezierPathWithOvalInRect:frame];
+        [imgPath addClip];
+        [image drawInRect:frame];
+
+        if (highlightedColor != nil) {
+            CGContextSetFillColorWithColor(context, highlightedColor.CGColor);
+            CGContextFillEllipseInRect(context, frame);
+        }
+
+        newImage = UIGraphicsGetImageFromCurrentImageContext();
+        
+    }
+    UIGraphicsEndImageContext();
+    
+    return newImage;
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Factories/JSQMessagesBubbleImageFactory.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Factories/JSQMessagesBubbleImageFactory.h
new file mode 100644
index 0000000..d883a12
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Factories/JSQMessagesBubbleImageFactory.h
@@ -0,0 +1,76 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+#import "JSQMessagesBubbleImage.h"
+
+/**
+ *  `JSQMessagesBubbleImageFactory` is a factory that provides a means for creating and styling 
+ *  `JSQMessagesBubbleImage` objects to be displayed in a `JSQMessagesCollectionViewCell` of a `JSQMessagesCollectionView`.
+ */
+@interface JSQMessagesBubbleImageFactory : NSObject
+
+/**
+ *  Creates and returns a new instance of `JSQMessagesBubbleImageFactory` that uses the
+ *  default bubble image assets and cap insets.
+ *
+ *  @return An initialized `JSQMessagesBubbleImageFactory` object if created successfully, `nil` otherwise.
+ */
+- (instancetype)init;
+
+/**
+ *  Creates and returns a new instance of `JSQMessagesBubbleImageFactory` having the specified
+ *  bubbleImage and capInsets. These values are used internally in the factory to produce
+ *  `JSQMessagesBubbleImage` objects.
+ *
+ *  @param bubbleImage A template bubble image from which all images will be generated.
+ *  The image should represent the *outgoing* message bubble image, which will be flipped
+ *  horizontally for generating the corresponding *incoming* message bubble images. This value must not be `nil`.
+ *
+ *  @param capInsets   The values to use for the cap insets that define the unstretchable regions of the image.
+ *  Specify `UIEdgeInsetsZero` to have the factory create insets that allow the image to stretch from its center point.
+ *
+ *  @return An initialized `JSQMessagesBubbleImageFactory` object if created successfully, `nil` otherwise.
+ */
+- (instancetype)initWithBubbleImage:(UIImage *)bubbleImage capInsets:(UIEdgeInsets)capInsets;
+
+/**
+ *  Creates and returns a `JSQMessagesBubbleImage` object with the specified color for *outgoing* message image bubbles.
+ *  The `messageBubbleImage` property of the `JSQMessagesBubbleImage` is configured with a flat bubble image, masked to the given color.
+ *  The `messageBubbleHighlightedImage` property is configured similarly, but with a darkened version of the given color.
+ *
+ *  @param color The color of the bubble image in the image view. This value must not be `nil`.
+ *
+ *  @return An initialized `JSQMessagesBubbleImage` object if created successfully, `nil` otherwise.
+ */
+- (JSQMessagesBubbleImage *)outgoingMessagesBubbleImageWithColor:(UIColor *)color;
+
+/**
+ *  Creates and returns a `JSQMessagesBubbleImage` object with the specified color for *incoming* message image bubbles.
+ *  The `messageBubbleImage` property of the `JSQMessagesBubbleImage` is configured with a flat bubble image, masked to the given color.
+ *  The `messageBubbleHighlightedImage` property is configured similarly, but with a darkened version of the given color.
+ *
+ *  @param color The color of the bubble image in the image view. This value must not be `nil`.
+ *
+ *  @return An initialized `JSQMessagesBubbleImage` object if created successfully, `nil` otherwise.
+ */
+- (JSQMessagesBubbleImage *)incomingMessagesBubbleImageWithColor:(UIColor *)color;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Factories/JSQMessagesBubbleImageFactory.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Factories/JSQMessagesBubbleImageFactory.m
new file mode 100644
index 0000000..2270759
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Factories/JSQMessagesBubbleImageFactory.m
@@ -0,0 +1,112 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQMessagesBubbleImageFactory.h"
+
+#import "UIImage+JSQMessages.h"
+#import "UIColor+JSQMessages.h"
+
+
+@interface JSQMessagesBubbleImageFactory ()
+
+@property (strong, nonatomic, readonly) UIImage *bubbleImage;
+@property (assign, nonatomic, readonly) UIEdgeInsets capInsets;
+
+@end
+
+
+
+@implementation JSQMessagesBubbleImageFactory
+
+#pragma mark - Initialization
+
+- (instancetype)initWithBubbleImage:(UIImage *)bubbleImage capInsets:(UIEdgeInsets)capInsets
+{
+	NSParameterAssert(bubbleImage != nil);
+    
+	self = [super init];
+	if (self) {
+		_bubbleImage = bubbleImage;
+        
+        if (UIEdgeInsetsEqualToEdgeInsets(capInsets, UIEdgeInsetsZero)) {
+            _capInsets = [self jsq_centerPointEdgeInsetsForImageSize:bubbleImage.size];
+        }
+        else {
+            _capInsets = capInsets;
+        }
+	}
+	return self;
+}
+
+- (instancetype)init
+{
+    return [self initWithBubbleImage:[UIImage jsq_bubbleCompactImage] capInsets:UIEdgeInsetsZero];
+}
+
+#pragma mark - Public
+
+- (JSQMessagesBubbleImage *)outgoingMessagesBubbleImageWithColor:(UIColor *)color
+{
+    return [self jsq_messagesBubbleImageWithColor:color flippedForIncoming:NO];
+}
+
+- (JSQMessagesBubbleImage *)incomingMessagesBubbleImageWithColor:(UIColor *)color
+{
+    return [self jsq_messagesBubbleImageWithColor:color flippedForIncoming:YES];
+}
+
+#pragma mark - Private
+
+- (UIEdgeInsets)jsq_centerPointEdgeInsetsForImageSize:(CGSize)bubbleImageSize
+{
+    // make image stretchable from center point
+    CGPoint center = CGPointMake(bubbleImageSize.width / 2.0f, bubbleImageSize.height / 2.0f);
+    return UIEdgeInsetsMake(center.y, center.x, center.y, center.x);
+}
+
+- (JSQMessagesBubbleImage *)jsq_messagesBubbleImageWithColor:(UIColor *)color flippedForIncoming:(BOOL)flippedForIncoming
+{
+    NSParameterAssert(color != nil);
+    
+    UIImage *normalBubble = [self.bubbleImage jsq_imageMaskedWithColor:color];
+    UIImage *highlightedBubble = [self.bubbleImage jsq_imageMaskedWithColor:[color jsq_colorByDarkeningColorWithValue:0.12f]];
+    
+    if (flippedForIncoming) {
+        normalBubble = [self jsq_horizontallyFlippedImageFromImage:normalBubble];
+        highlightedBubble = [self jsq_horizontallyFlippedImageFromImage:highlightedBubble];
+    }
+    
+    normalBubble = [self jsq_stretchableImageFromImage:normalBubble withCapInsets:self.capInsets];
+    highlightedBubble = [self jsq_stretchableImageFromImage:highlightedBubble withCapInsets:self.capInsets];
+    
+    return [[JSQMessagesBubbleImage alloc] initWithMessageBubbleImage:normalBubble highlightedImage:highlightedBubble];
+}
+
+- (UIImage *)jsq_horizontallyFlippedImageFromImage:(UIImage *)image
+{
+    return [UIImage imageWithCGImage:image.CGImage
+                               scale:image.scale
+                         orientation:UIImageOrientationUpMirrored];
+}
+
+- (UIImage *)jsq_stretchableImageFromImage:(UIImage *)image withCapInsets:(UIEdgeInsets)capInsets
+{
+    return [image resizableImageWithCapInsets:capInsets resizingMode:UIImageResizingModeStretch];
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Factories/JSQMessagesMediaViewBubbleImageMasker.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Factories/JSQMessagesMediaViewBubbleImageMasker.h
new file mode 100644
index 0000000..44b929c
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Factories/JSQMessagesMediaViewBubbleImageMasker.h
@@ -0,0 +1,90 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+@class JSQMessagesBubbleImageFactory;
+
+/**
+ *  An instance of `JSQMessagesMediaViewBubbleImageMasker` is an object that masks
+ *  media views for a `JSQMessageMediaData` object. Given a view, it will mask the view
+ *  with a bubble image for an outgoing or incoming media view.
+ *
+ *  @see JSQMessageMediaData.
+ *  @see JSQMessagesBubbleImageFactory.
+ *  @see JSQMessagesBubbleImage.
+ */
+@interface JSQMessagesMediaViewBubbleImageMasker : NSObject
+
+/**
+ *  Returns the bubble image factory that the masker uses to mask media views.
+ */
+@property (strong, nonatomic, readonly) JSQMessagesBubbleImageFactory *bubbleImageFactory;
+
+/**
+ *  Creates and returns a new instance of `JSQMessagesMediaViewBubbleImageMasker`
+ *  that uses a default instance of `JSQMessagesBubbleImageFactory`. The masker uses the `JSQMessagesBubbleImage`
+ *  objects returned by the factory to mask media views.
+ *
+ *  @return An initialized `JSQMessagesMediaViewBubbleImageMasker` object if created successfully, `nil` otherwise.
+ *
+ *  @see JSQMessagesBubbleImageFactory.
+ *  @see JSQMessagesBubbleImage.
+ */
+- (instancetype)init;
+
+/**
+ *  Creates and returns a new instance of `JSQMessagesMediaViewBubbleImageMasker`
+ *  having the specified bubbleImageFactory. The masker uses the `JSQMessagesBubbleImage`
+ *  objects returned by the factory to mask media views.
+ *
+ *  @param bubbleImageFactory An initialized `JSQMessagesBubbleImageFactory` object to use for masking media views. This value must not be `nil`.
+ *
+ *  @return An initialized `JSQMessagesMediaViewBubbleImageMasker` object if created successfully, `nil` otherwise.
+ *
+ *  @see JSQMessagesBubbleImageFactory.
+ *  @see JSQMessagesBubbleImage.
+ */
+- (instancetype)initWithBubbleImageFactory:(JSQMessagesBubbleImageFactory *)bubbleImageFactory NS_DESIGNATED_INITIALIZER;
+
+/**
+ *  Applies an outgoing bubble image mask to the specified mediaView.
+ *
+ *  @param mediaView The media view to mask.
+ */
+- (void)applyOutgoingBubbleImageMaskToMediaView:(UIView *)mediaView;
+
+/**
+ *  Applies an incoming bubble image mask to the specified mediaView.
+ *
+ *  @param mediaView The media view to mask.
+ */
+- (void)applyIncomingBubbleImageMaskToMediaView:(UIView *)mediaView;
+
+/**
+ *  A convenience method for applying a bubble image mask to the specified mediaView.
+ *  This method uses the default instance of `JSQMessagesBubbleImageFactory`.
+ *
+ *  @param mediaView  The media view to mask.
+ *  @param isOutgoing A boolean value specifiying whether or not the mask should be for an outgoing or incoming view.
+ *  Specify `YES` for outgoing and `NO` for incoming.
+ */
++ (void)applyBubbleImageMaskToMediaView:(UIView *)mediaView isOutgoing:(BOOL)isOutgoing;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Factories/JSQMessagesMediaViewBubbleImageMasker.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Factories/JSQMessagesMediaViewBubbleImageMasker.m
new file mode 100644
index 0000000..155b391
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Factories/JSQMessagesMediaViewBubbleImageMasker.m
@@ -0,0 +1,83 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQMessagesMediaViewBubbleImageMasker.h"
+
+#import "JSQMessagesBubbleImageFactory.h"
+
+
+@implementation JSQMessagesMediaViewBubbleImageMasker
+
+#pragma mark - Initialization
+
+- (instancetype)init
+{
+    return [self initWithBubbleImageFactory:[[JSQMessagesBubbleImageFactory alloc] init]];
+}
+
+- (instancetype)initWithBubbleImageFactory:(JSQMessagesBubbleImageFactory *)bubbleImageFactory
+{
+    NSParameterAssert(bubbleImageFactory != nil);
+    
+    self = [super init];
+    if (self) {
+        _bubbleImageFactory = bubbleImageFactory;
+    }
+    return self;
+}
+
+#pragma mark - View masking
+
+- (void)applyOutgoingBubbleImageMaskToMediaView:(UIView *)mediaView
+{
+    JSQMessagesBubbleImage *bubbleImageData = [self.bubbleImageFactory outgoingMessagesBubbleImageWithColor:[UIColor whiteColor]];
+    [self jsq_maskView:mediaView withImage:[bubbleImageData messageBubbleImage]];
+}
+
+- (void)applyIncomingBubbleImageMaskToMediaView:(UIView *)mediaView
+{
+    JSQMessagesBubbleImage *bubbleImageData = [self.bubbleImageFactory incomingMessagesBubbleImageWithColor:[UIColor whiteColor]];
+    [self jsq_maskView:mediaView withImage:[bubbleImageData messageBubbleImage]];
+}
+
++ (void)applyBubbleImageMaskToMediaView:(UIView *)mediaView isOutgoing:(BOOL)isOutgoing
+{
+    JSQMessagesMediaViewBubbleImageMasker *masker = [[JSQMessagesMediaViewBubbleImageMasker alloc] init];
+    
+    if (isOutgoing) {
+        [masker applyOutgoingBubbleImageMaskToMediaView:mediaView];
+    }
+    else {
+        [masker applyIncomingBubbleImageMaskToMediaView:mediaView];
+    }
+}
+
+#pragma mark - Private
+
+- (void)jsq_maskView:(UIView *)view withImage:(UIImage *)image
+{
+    NSParameterAssert(view != nil);
+    NSParameterAssert(image != nil);
+    
+    UIImageView *imageViewMask = [[UIImageView alloc] initWithImage:image];
+    imageViewMask.frame = CGRectInset(view.frame, 2.0f, 2.0f);
+    
+    view.layer.mask = imageViewMask.layer;
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Factories/JSQMessagesTimestampFormatter.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Factories/JSQMessagesTimestampFormatter.h
new file mode 100644
index 0000000..c7d48c2
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Factories/JSQMessagesTimestampFormatter.h
@@ -0,0 +1,95 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+/**
+ *  An instance of `JSQMessagesTimestampFormatter` is a singleton object that provides an efficient means 
+ *  for creating attributed and non-attributed string representations of `NSDate` objects. 
+ *  It is intended to be used as the method by which you display timestamps in a `JSQMessagesCollectionView`.
+ */
+@interface JSQMessagesTimestampFormatter : NSObject
+
+/**
+ *  Returns the cached date formatter object used by the `JSQMessagesTimestampFormatter` shared instance.
+ */
+@property (strong, nonatomic, readonly) NSDateFormatter *dateFormatter;
+
+/**
+ *  The text attributes to apply to the day, month, and year components of the string representation of a given date. 
+ *  The default value is a dictionary containing attributes that specify centered, light gray text and the bold system font at size `12.0f`.
+ */
+@property (copy, nonatomic) NSDictionary *dateTextAttributes;
+
+/**
+ *  The text attributes to apply to the minute and hour componenents of the string representation of a given date. 
+ *  The default value is a dictionary containing attributes that specify centered, light gray text and the system font at size `12.0f`.
+ */
+@property (copy, nonatomic) NSDictionary *timeTextAttributes;
+
+/**
+ *  Returns the shared timestamp formatter object.
+ *
+ *  @return The shared timestamp formatter object.
+ */
++ (JSQMessagesTimestampFormatter *)sharedFormatter;
+
+/**
+ *  Returns a string representation of the given date formatted in the current locale using `NSDateFormatterMediumStyle` for the date style 
+ *  and `NSDateFormatterShortStyle` for the time style. It uses relative date formatting where possible.
+ *
+ *  @param date The date to format.
+ *
+ *  @return A formatted string representation of date.
+ */
+- (NSString *)timestampForDate:(NSDate *)date;
+
+/**
+ *  Returns an attributed string representation of the given date formatted as described in `timestampForDate:`. 
+ *  It applies the attributes in `dateTextAttributes` and `timeTextAttributes`, respectively.
+ *
+ *  @param date The date to format.
+ *
+ *  @return A formatted, attributed string representation of date.
+ *
+ *  @see `timestampForDate:`.
+ *  @see `dateTextAttributes`.
+ *  @see `timeTextAttributes`.
+ */
+- (NSAttributedString *)attributedTimestampForDate:(NSDate *)date;
+
+/**
+ *  Returns a string representation of *only* the minute and hour components of the given date formatted in the current locale styled using `NSDateFormatterShortStyle`.
+ *
+ *  @param date The date to format.
+ *
+ *  @return A formatted string representation of the minute and hour components of date.
+ */
+- (NSString *)timeForDate:(NSDate *)date;
+
+/**
+ *  Returns a string representation of *only* the day, month, and year components of the given date formatted in the current locale styled using `NSDateFormatterMediumStyle`.
+ *
+ *  @param date The date to format.
+ *
+ *  @return A formatted string representation of the day, month, and year components of date.
+ */
+- (NSString *)relativeDateForDate:(NSDate *)date;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Factories/JSQMessagesTimestampFormatter.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Factories/JSQMessagesTimestampFormatter.m
new file mode 100644
index 0000000..04bcda2
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Factories/JSQMessagesTimestampFormatter.m
@@ -0,0 +1,124 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQMessagesTimestampFormatter.h"
+
+@interface JSQMessagesTimestampFormatter ()
+
+@property (strong, nonatomic, readwrite) NSDateFormatter *dateFormatter;
+
+@end
+
+
+
+@implementation JSQMessagesTimestampFormatter
+
+#pragma mark - Initialization
+
++ (JSQMessagesTimestampFormatter *)sharedFormatter
+{
+    static JSQMessagesTimestampFormatter *_sharedFormatter = nil;
+    
+    static dispatch_once_t onceToken = 0;
+    dispatch_once(&onceToken, ^{
+        _sharedFormatter = [[JSQMessagesTimestampFormatter alloc] init];
+    });
+    
+    return _sharedFormatter;
+}
+
+- (instancetype)init
+{
+    self = [super init];
+    if (self) {
+        _dateFormatter = [[NSDateFormatter alloc] init];
+        [_dateFormatter setLocale:[NSLocale currentLocale]];
+        [_dateFormatter setDoesRelativeDateFormatting:YES];
+        
+        UIColor *color = [UIColor lightGrayColor];
+        
+        NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
+        paragraphStyle.alignment = NSTextAlignmentCenter;
+        
+        _dateTextAttributes = @{ NSFontAttributeName : [UIFont boldSystemFontOfSize:12.0f],
+                                 NSForegroundColorAttributeName : color,
+                                 NSParagraphStyleAttributeName : paragraphStyle };
+        
+        _timeTextAttributes = @{ NSFontAttributeName : [UIFont systemFontOfSize:12.0f],
+                                 NSForegroundColorAttributeName : color,
+                                 NSParagraphStyleAttributeName : paragraphStyle };
+    }
+    return self;
+}
+
+#pragma mark - Formatter
+
+- (NSString *)timestampForDate:(NSDate *)date
+{
+    if (!date) {
+        return nil;
+    }
+    
+    [self.dateFormatter setDateStyle:NSDateFormatterMediumStyle];
+    [self.dateFormatter setTimeStyle:NSDateFormatterShortStyle];
+    return [self.dateFormatter stringFromDate:date];
+}
+
+- (NSAttributedString *)attributedTimestampForDate:(NSDate *)date
+{
+    if (!date) {
+        return nil;
+    }
+    
+    NSString *relativeDate = [self relativeDateForDate:date];
+    NSString *time = [self timeForDate:date];
+    
+    NSMutableAttributedString *timestamp = [[NSMutableAttributedString alloc] initWithString:relativeDate
+                                                                                  attributes:self.dateTextAttributes];
+    
+    [timestamp appendAttributedString:[[NSAttributedString alloc] initWithString:@" "]];
+    
+    [timestamp appendAttributedString:[[NSAttributedString alloc] initWithString:time
+                                                                      attributes:self.timeTextAttributes]];
+    
+    return [[NSAttributedString alloc] initWithAttributedString:timestamp];
+}
+
+- (NSString *)timeForDate:(NSDate *)date
+{
+    if (!date) {
+        return nil;
+    }
+    
+    [self.dateFormatter setDateStyle:NSDateFormatterNoStyle];
+    [self.dateFormatter setTimeStyle:NSDateFormatterShortStyle];
+    return [self.dateFormatter stringFromDate:date];
+}
+
+- (NSString *)relativeDateForDate:(NSDate *)date
+{
+    if (!date) {
+        return nil;
+    }
+    
+    [self.dateFormatter setDateStyle:NSDateFormatterMediumStyle];
+    [self.dateFormatter setTimeStyle:NSDateFormatterNoStyle];
+    return [self.dateFormatter stringFromDate:date];
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Factories/JSQMessagesToolbarButtonFactory.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Factories/JSQMessagesToolbarButtonFactory.h
new file mode 100644
index 0000000..5659e4d
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Factories/JSQMessagesToolbarButtonFactory.h
@@ -0,0 +1,44 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+/**
+ *  `JSQMessagesToolbarButtonFactory` is a factory that provides a means for creating the default
+ *  toolbar button items to be displayed in the content view of a `JSQMessagesInputToolbar`.
+ */
+@interface JSQMessagesToolbarButtonFactory : NSObject
+
+/**
+ *  Creates and returns a new button that is styled as the default accessory button. 
+ *  The button has a paper clip icon image and no text.
+ *
+ *  @return A newly created button.
+ */
++ (UIButton *)defaultAccessoryButtonItem;
+
+/**
+ *  Creates and returns a new button that is styled as the default send button. 
+ *  The button has title text `@"Send"` and no image.
+ *
+ *  @return A newly created button.
+ */
++ (UIButton *)defaultSendButtonItem;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Factories/JSQMessagesToolbarButtonFactory.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Factories/JSQMessagesToolbarButtonFactory.m
new file mode 100644
index 0000000..357adb8
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Factories/JSQMessagesToolbarButtonFactory.m
@@ -0,0 +1,79 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQMessagesToolbarButtonFactory.h"
+
+#import "UIColor+JSQMessages.h"
+#import "UIImage+JSQMessages.h"
+#import "NSBundle+JSQMessages.h"
+
+
+@implementation JSQMessagesToolbarButtonFactory
+
++ (UIButton *)defaultAccessoryButtonItem
+{
+    UIImage *accessoryImage = [UIImage jsq_defaultAccessoryImage];
+    UIImage *normalImage = [accessoryImage jsq_imageMaskedWithColor:[UIColor lightGrayColor]];
+    UIImage *highlightedImage = [accessoryImage jsq_imageMaskedWithColor:[UIColor darkGrayColor]];
+
+    UIButton *accessoryButton = [[UIButton alloc] initWithFrame:CGRectMake(0.0f, 0.0f, accessoryImage.size.width, 32.0f)];
+    [accessoryButton setImage:normalImage forState:UIControlStateNormal];
+    [accessoryButton setImage:highlightedImage forState:UIControlStateHighlighted];
+
+    accessoryButton.contentMode = UIViewContentModeScaleAspectFit;
+    accessoryButton.backgroundColor = [UIColor clearColor];
+    accessoryButton.tintColor = [UIColor lightGrayColor];
+    
+    accessoryButton.accessibilityLabel = [NSBundle jsq_localizedStringForKey:@"accessory_button_accessibility_label"];
+
+    return accessoryButton;
+}
+
++ (UIButton *)defaultSendButtonItem
+{
+    NSString *sendTitle = [NSBundle jsq_localizedStringForKey:@"send"];
+
+    UIButton *sendButton = [[UIButton alloc] initWithFrame:CGRectZero];
+    [sendButton setTitle:sendTitle forState:UIControlStateNormal];
+    [sendButton setTitleColor:[UIColor jsq_messageBubbleBlueColor] forState:UIControlStateNormal];
+    [sendButton setTitleColor:[[UIColor jsq_messageBubbleBlueColor] jsq_colorByDarkeningColorWithValue:0.1f] forState:UIControlStateHighlighted];
+    [sendButton setTitleColor:[UIColor lightGrayColor] forState:UIControlStateDisabled];
+
+    sendButton.titleLabel.font = [UIFont boldSystemFontOfSize:17.0f];
+    sendButton.titleLabel.adjustsFontSizeToFitWidth = YES;
+    sendButton.titleLabel.minimumScaleFactor = 0.85f;
+    sendButton.contentMode = UIViewContentModeCenter;
+    sendButton.backgroundColor = [UIColor clearColor];
+    sendButton.tintColor = [UIColor jsq_messageBubbleBlueColor];
+
+    CGFloat maxHeight = 32.0f;
+
+    CGRect sendTitleRect = [sendTitle boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, maxHeight)
+                                                   options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
+                                                attributes:@{ NSFontAttributeName : sendButton.titleLabel.font }
+                                                   context:nil];
+
+    sendButton.frame = CGRectMake(0.0f,
+                                  0.0f,
+                                  CGRectGetWidth(CGRectIntegral(sendTitleRect)),
+                                  maxHeight);
+
+    return sendButton;
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/JSQMessages.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/JSQMessages.h
new file mode 100644
index 0000000..862acbf
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/JSQMessages.h
@@ -0,0 +1,81 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#ifndef JSQMessages_JSQMessages_h
+#define JSQMessages_JSQMessages_h
+
+#import "JSQMessagesViewController.h"
+
+//  Views
+#import "JSQMessagesCollectionView.h"
+#import "JSQMessagesCollectionViewCellIncoming.h"
+#import "JSQMessagesCollectionViewCellOutgoing.h"
+#import "JSQMessagesTypingIndicatorFooterView.h"
+#import "JSQMessagesLoadEarlierHeaderView.h"
+
+//  Layout
+#import "JSQMessagesBubbleSizeCalculating.h"
+#import "JSQMessagesBubblesSizeCalculator.h"
+#import "JSQMessagesCollectionViewFlowLayout.h"
+#import "JSQMessagesCollectionViewLayoutAttributes.h"
+#import "JSQMessagesCollectionViewFlowLayoutInvalidationContext.h"
+#import "JSQAudioMediaViewAttributes.h"
+
+//  Toolbar
+#import "JSQMessagesComposerTextView.h"
+#import "JSQMessagesInputToolbar.h"
+#import "JSQMessagesToolbarContentView.h"
+
+//  Model
+#import "JSQMessage.h"
+
+#import "JSQMediaItem.h"
+#import "JSQAudioMediaItem.h"
+#import "JSQPhotoMediaItem.h"
+#import "JSQLocationMediaItem.h"
+#import "JSQVideoMediaItem.h"
+
+#import "JSQMessagesBubbleImage.h"
+#import "JSQMessagesAvatarImage.h"
+
+#import "JSQAudioMediaViewAttributes.h"
+
+//  Protocols
+#import "JSQMessageData.h"
+#import "JSQMessageMediaData.h"
+#import "JSQMessageAvatarImageDataSource.h"
+#import "JSQMessageBubbleImageDataSource.h"
+#import "JSQMessagesCollectionViewDataSource.h"
+#import "JSQMessagesCollectionViewDelegateFlowLayout.h"
+
+//  Factories
+#import "JSQMessagesAvatarImageFactory.h"
+#import "JSQMessagesBubbleImageFactory.h"
+#import "JSQMessagesMediaViewBubbleImageMasker.h"
+#import "JSQMessagesTimestampFormatter.h"
+#import "JSQMessagesToolbarButtonFactory.h"
+
+//  Categories
+#import "JSQSystemSoundPlayer+JSQMessages.h"
+#import "NSString+JSQMessages.h"
+#import "UIColor+JSQMessages.h"
+#import "UIImage+JSQMessages.h"
+#import "UIView+JSQMessages.h"
+#import "NSBundle+JSQMessages.h"
+
+#endif
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Layout/JSQAudioMediaViewAttributes.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Layout/JSQAudioMediaViewAttributes.h
new file mode 100644
index 0000000..03ce402
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Layout/JSQAudioMediaViewAttributes.h
@@ -0,0 +1,117 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <Foundation/Foundation.h>
+#import <AVFoundation/AVFoundation.h>
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ An instance of `JSQAudioMediaViewAttributes` specifies the appearance configuration of a `JSQAudioMediaItem`.
+ Use this class to customize the appearance of `JSQAudioMediaItem`.
+ */
+@interface JSQAudioMediaViewAttributes : NSObject
+
+/**
+ *  The image for the play button. The default is a play icon.
+ */
+@property (nonatomic, strong) UIImage *playButtonImage;
+
+/**
+ *  The image for the pause button. The default is a pause icon.
+ */
+@property (nonatomic, strong) UIImage *pauseButtonImage;
+
+/**
+ *  The font for the elapsed time label. The default is a system font.
+ */
+@property (strong, nonatomic) UIFont *labelFont;
+
+/**
+ *  Specifies whether to show fractions of a second for audio files with a duration of less than 1 minute.
+ */
+@property (nonatomic, assign) BOOL showFractionalSeconds;
+
+/**
+ *  The background color for the player.
+ */
+@property (nonatomic, strong) UIColor *backgroundColor;
+
+/**
+ *  The tint color for the player.
+ */
+@property (nonatomic, strong) UIColor *tintColor;
+
+/**
+ *  Insets that sepcify the padding around the play/pause button and time label.
+ */
+@property (nonatomic, assign) UIEdgeInsets controlInsets;
+
+/**
+ *  Specifies the padding between the button, progress bar, and label.
+ */
+@property (nonatomic, assign) CGFloat controlPadding;
+
+/**
+ *  Specifies the audio category set prior to playback.
+ */
+@property (nonatomic, copy) NSString *audioCategory;
+
+/**
+ *  Specifies the audio category options set prior to playback.
+ */
+@property (nonatomic) AVAudioSessionCategoryOptions audioCategoryOptions;
+
+/**
+ Initializes and returns a `JSQAudioMediaViewAttributes` instance having the specified attributes.
+
+ @param playButtonImage        The image for the play button.
+ @param pauseButtonImage      The image for the pause button.
+ @param labelFont             The font for the elapsed time label.
+ @param showFractionalSeconds Specifies whether to show fractions of a second for audio files with a duration of less than 1 minute.
+ @param backgroundColor       The background color for the player.
+ @param tintColor             The tint color for the player.
+ @param controlInsets         Insets that sepcify the padding around the play/pause button and time label.
+ @param controlPadding        Specifies the padding between the button, progress bar, and label.
+ @param audioCategory         Specifies the audio category set prior to playback.
+ @param audioCategoryOptions  Specifies the audio category options set prior to playback.
+
+ @return A new `JSQAudioMediaViewAttributes` instance
+ */
+- (instancetype)initWithPlayButtonImage:(UIImage *)playButtonImage
+                       pauseButtonImage:(UIImage *)pauseButtonImage
+                              labelFont:(UIFont *)labelFont
+                  showFractionalSecodns:(BOOL)showFractionalSeconds
+                        backgroundColor:(UIColor *)backgroundColor
+                              tintColor:(UIColor *)tintColor
+                          controlInsets:(UIEdgeInsets)controlInsets
+                         controlPadding:(CGFloat)controlPadding
+                          audioCategory:(NSString *)audioCategory
+                   audioCategoryOptions:(AVAudioSessionCategoryOptions)audioCategoryOptions NS_DESIGNATED_INITIALIZER;
+
+/**
+ Initializes and returns a default `JSQAudioMediaViewAttributes` instance.
+
+ @return A new `JSQAudioMediaViewAttributes` instance
+ */
+- (instancetype)init;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Layout/JSQAudioMediaViewAttributes.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Layout/JSQAudioMediaViewAttributes.m
new file mode 100644
index 0000000..f0d732f
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Layout/JSQAudioMediaViewAttributes.m
@@ -0,0 +1,114 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQAudioMediaViewAttributes.h"
+
+#import "UIImage+JSQMessages.h"
+#import "UIColor+JSQMessages.h"
+
+@implementation JSQAudioMediaViewAttributes
+
+- (instancetype)initWithPlayButtonImage:(UIImage *)playButtonImage
+                       pauseButtonImage:(UIImage *)pauseButtonImage
+                              labelFont:(UIFont *)labelFont
+                  showFractionalSecodns:(BOOL)showFractionalSeconds
+                        backgroundColor:(UIColor *)backgroundColor
+                              tintColor:(UIColor *)tintColor
+                          controlInsets:(UIEdgeInsets)controlInsets
+                         controlPadding:(CGFloat)controlPadding
+                          audioCategory:(NSString *)audioCategory
+                   audioCategoryOptions:(AVAudioSessionCategoryOptions)audioCategoryOptions {
+    NSParameterAssert(playButtonImage != nil);
+    NSParameterAssert(pauseButtonImage != nil);
+    NSParameterAssert(labelFont != nil);
+    NSParameterAssert(backgroundColor != nil);
+    NSParameterAssert(tintColor != nil);
+    NSParameterAssert(audioCategory != nil);
+
+    self = [super init];
+    if (self) {
+        _playButtonImage = playButtonImage;
+        _pauseButtonImage = pauseButtonImage;
+        _labelFont = labelFont;
+        _showFractionalSeconds = showFractionalSeconds;
+        _backgroundColor = backgroundColor;
+        _tintColor = tintColor;
+        _controlInsets = controlInsets;
+        _controlPadding = controlPadding;
+        _audioCategory = audioCategory;
+        _audioCategoryOptions = audioCategoryOptions;
+    }
+    return self;
+}
+
+- (instancetype)init
+{
+    UIColor *tintColor = [UIColor jsq_messageBubbleBlueColor];
+    AVAudioSessionCategoryOptions options = AVAudioSessionCategoryOptionDuckOthers
+    | AVAudioSessionCategoryOptionDefaultToSpeaker
+    | AVAudioSessionCategoryOptionAllowBluetooth;
+
+    return [self initWithPlayButtonImage:[[UIImage jsq_defaultPlayImage] jsq_imageMaskedWithColor:tintColor]
+                        pauseButtonImage:[[UIImage jsq_defaultPauseImage] jsq_imageMaskedWithColor:tintColor]
+                               labelFont:[UIFont systemFontOfSize:12]
+                   showFractionalSecodns:NO
+                         backgroundColor:[UIColor jsq_messageBubbleLightGrayColor]
+                               tintColor:tintColor
+                           controlInsets:UIEdgeInsetsMake(6, 6, 6, 18)
+                          controlPadding:6
+                           audioCategory:@"AVAudioSessionCategoryPlayback"
+                    audioCategoryOptions:options];
+}
+
+- (void)setPlayButtonImage:(UIImage *)playButtonImage
+{
+    NSParameterAssert(playButtonImage != nil);
+    _playButtonImage = playButtonImage;
+}
+
+- (void)setPauseButtonImage:(UIImage *)pauseButtonImage
+{
+    NSParameterAssert(pauseButtonImage != nil);
+    _pauseButtonImage = pauseButtonImage;
+}
+
+- (void)setLabelFont:(UIFont *)labelFont
+{
+    NSParameterAssert(labelFont != nil);
+    _labelFont = labelFont;
+}
+
+- (void)setBackgroundColor:(UIColor *)backgroundColor
+{
+    NSParameterAssert(backgroundColor != nil);
+    _backgroundColor = backgroundColor;
+}
+
+- (void)setTintColor:(UIColor *)tintColor
+{
+    NSParameterAssert(tintColor != nil);
+    _tintColor = tintColor;
+}
+
+- (void)setAudioCategory:(NSString *)audioCategory
+{
+    NSParameterAssert(audioCategory != nil);
+    _audioCategory = audioCategory;
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Layout/JSQMessagesBubbleSizeCalculating.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Layout/JSQMessagesBubbleSizeCalculating.h
new file mode 100644
index 0000000..fc4f816
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Layout/JSQMessagesBubbleSizeCalculating.h
@@ -0,0 +1,57 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+@class JSQMessagesCollectionViewFlowLayout;
+@protocol JSQMessageData;
+
+/**
+ *  The `JSQMessagesBubbleSizeCalculating` protocol defines the common interface through which
+ *  an object provides layout information to an instance of `JSQMessagesCollectionViewFlowLayout`.
+ *
+ *  A concrete class that conforms to this protocol is provided in the library.
+ *  See `JSQMessagesBubbleSizeCalculator`.
+ */
+@protocol JSQMessagesBubbleSizeCalculating <NSObject>
+
+/**
+ *  Computes and returns the size of the `messageBubbleImageView` property 
+ *  of a `JSQMessagesCollectionViewCell` for the specified messageData at indexPath.
+ *
+ *  @param messageData A message data object.
+ *  @param indexPath   The index path at which messageData is located.
+ *  @param layout      The layout object asking for this information.
+ *
+ *  @return A sizes that specifies the required dimensions to display the entire message contents.
+ *  Note, this is *not* the entire cell, but only its message bubble.
+ */
+- (CGSize)messageBubbleSizeForMessageData:(id<JSQMessageData>)messageData
+                              atIndexPath:(NSIndexPath *)indexPath
+                               withLayout:(JSQMessagesCollectionViewFlowLayout *)layout;
+
+/**
+ *  Notifies the receiver that the layout will be reset. 
+ *  Use this method to clear any cached layout information, if necessary.
+ *
+ *  @param layout The layout object notifying the receiver.
+ */
+- (void)prepareForResettingLayout:(JSQMessagesCollectionViewFlowLayout *)layout;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Layout/JSQMessagesBubblesSizeCalculator.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Layout/JSQMessagesBubblesSizeCalculator.h
new file mode 100644
index 0000000..4f88ac7
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Layout/JSQMessagesBubblesSizeCalculator.h
@@ -0,0 +1,43 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <Foundation/Foundation.h>
+
+#import "JSQMessagesBubbleSizeCalculating.h"
+
+/**
+ *  An instance of `JSQMessagesBubblesSizeCalculator` is responsible for calculating
+ *  message bubble sizes for an instance of `JSQMessagesCollectionViewFlowLayout`.
+ */
+@interface JSQMessagesBubblesSizeCalculator : NSObject <JSQMessagesBubbleSizeCalculating>
+
+/**
+ *  Initializes and returns a bubble size calculator with the given cache and minimumBubbleWidth.
+ *
+ *  @param cache                 A cache object used to store layout information.
+ *  @param minimumBubbleWidth    The minimum width for any given message bubble.
+ *  @param usesFixedWidthBubbles Specifies whether or not to use fixed-width bubbles.
+ *  If `NO` (the default), then bubbles will resize when rotating to landscape.
+ *
+ *  @return An initialized `JSQMessagesBubblesSizeCalculator` object if successful, `nil` otherwise.
+ */
+- (instancetype)initWithCache:(NSCache *)cache
+           minimumBubbleWidth:(NSUInteger)minimumBubbleWidth
+        usesFixedWidthBubbles:(BOOL)usesFixedWidthBubbles NS_DESIGNATED_INITIALIZER;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Layout/JSQMessagesBubblesSizeCalculator.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Layout/JSQMessagesBubblesSizeCalculator.m
new file mode 100644
index 0000000..6b60387
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Layout/JSQMessagesBubblesSizeCalculator.m
@@ -0,0 +1,179 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQMessagesBubblesSizeCalculator.h"
+
+#import "JSQMessagesCollectionView.h"
+#import "JSQMessagesCollectionViewDataSource.h"
+#import "JSQMessagesCollectionViewFlowLayout.h"
+#import "JSQMessageData.h"
+
+#import "UIImage+JSQMessages.h"
+
+
+@interface JSQMessagesBubblesSizeCalculator ()
+
+@property (strong, nonatomic, readonly) NSCache *cache;
+
+@property (assign, nonatomic, readonly) NSUInteger minimumBubbleWidth;
+
+@property (assign, nonatomic, readonly) BOOL usesFixedWidthBubbles;
+
+@property (assign, nonatomic, readonly) NSInteger additionalInset;
+
+@property (assign, nonatomic) CGFloat layoutWidthForFixedWidthBubbles;
+
+@end
+
+
+@implementation JSQMessagesBubblesSizeCalculator
+
+#pragma mark - Init
+
+- (instancetype)initWithCache:(NSCache *)cache
+           minimumBubbleWidth:(NSUInteger)minimumBubbleWidth
+        usesFixedWidthBubbles:(BOOL)usesFixedWidthBubbles
+{
+    NSParameterAssert(cache != nil);
+    NSParameterAssert(minimumBubbleWidth > 0);
+
+    self = [super init];
+    if (self) {
+        _cache = cache;
+        _minimumBubbleWidth = minimumBubbleWidth;
+        _usesFixedWidthBubbles = usesFixedWidthBubbles;
+        _layoutWidthForFixedWidthBubbles = 0.0f;
+
+        // this extra inset value is needed because `boundingRectWithSize:` is slightly off
+        // see comment below
+        _additionalInset = 2;
+    }
+    return self;
+}
+
+- (instancetype)init
+{
+    NSCache *cache = [NSCache new];
+    cache.name = @"JSQMessagesBubblesSizeCalculator.cache";
+    cache.countLimit = 200;
+    return [self initWithCache:cache
+            minimumBubbleWidth:[UIImage jsq_bubbleCompactImage].size.width
+         usesFixedWidthBubbles:NO];
+}
+
+#pragma mark - NSObject
+
+- (NSString *)description
+{
+    return [NSString stringWithFormat:@"<%@: cache=%@, minimumBubbleWidth=%@ usesFixedWidthBubbles=%@>",
+            [self class], self.cache, @(self.minimumBubbleWidth), @(self.usesFixedWidthBubbles)];
+}
+
+#pragma mark - JSQMessagesBubbleSizeCalculating
+
+- (void)prepareForResettingLayout:(JSQMessagesCollectionViewFlowLayout *)layout
+{
+    [self.cache removeAllObjects];
+}
+
+- (CGSize)messageBubbleSizeForMessageData:(id<JSQMessageData>)messageData
+                              atIndexPath:(NSIndexPath *)indexPath
+                               withLayout:(JSQMessagesCollectionViewFlowLayout *)layout
+{
+    NSValue *cachedSize = [self.cache objectForKey:@([messageData messageHash])];
+    if (cachedSize != nil) {
+        return [cachedSize CGSizeValue];
+    }
+
+    CGSize finalSize = CGSizeZero;
+
+    if ([messageData isMediaMessage]) {
+        finalSize = [[messageData media] mediaViewDisplaySize];
+    }
+    else {
+        CGSize avatarSize = [self jsq_avatarSizeForMessageData:messageData withLayout:layout];
+
+        //  from the cell xibs, there is a 2 point space between avatar and bubble
+        CGFloat spacingBetweenAvatarAndBubble = 2.0f;
+        CGFloat horizontalContainerInsets = layout.messageBubbleTextViewTextContainerInsets.left + layout.messageBubbleTextViewTextContainerInsets.right;
+        CGFloat horizontalFrameInsets = layout.messageBubbleTextViewFrameInsets.left + layout.messageBubbleTextViewFrameInsets.right;
+
+        CGFloat horizontalInsetsTotal = horizontalContainerInsets + horizontalFrameInsets + spacingBetweenAvatarAndBubble;
+        CGFloat maximumTextWidth = [self textBubbleWidthForLayout:layout] - avatarSize.width - layout.messageBubbleLeftRightMargin - horizontalInsetsTotal;
+
+        CGRect stringRect = [[messageData text] boundingRectWithSize:CGSizeMake(maximumTextWidth, CGFLOAT_MAX)
+                                                             options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
+                                                          attributes:@{ NSFontAttributeName : layout.messageBubbleFont }
+                                                             context:nil];
+
+        CGSize stringSize = CGRectIntegral(stringRect).size;
+
+        CGFloat verticalContainerInsets = layout.messageBubbleTextViewTextContainerInsets.top + layout.messageBubbleTextViewTextContainerInsets.bottom;
+        CGFloat verticalFrameInsets = layout.messageBubbleTextViewFrameInsets.top + layout.messageBubbleTextViewFrameInsets.bottom;
+
+        //  add extra 2 points of space (`self.additionalInset`), because `boundingRectWithSize:` is slightly off
+        //  not sure why. magix. (shrug) if you know, submit a PR
+        CGFloat verticalInsets = verticalContainerInsets + verticalFrameInsets + self.additionalInset;
+
+        //  same as above, an extra 2 points of magix
+        CGFloat finalWidth = MAX(stringSize.width + horizontalInsetsTotal, self.minimumBubbleWidth) + self.additionalInset;
+
+        finalSize = CGSizeMake(finalWidth, stringSize.height + verticalInsets);
+    }
+
+    [self.cache setObject:[NSValue valueWithCGSize:finalSize] forKey:@([messageData messageHash])];
+
+    return finalSize;
+}
+
+- (CGSize)jsq_avatarSizeForMessageData:(id<JSQMessageData>)messageData
+                            withLayout:(JSQMessagesCollectionViewFlowLayout *)layout
+{
+    NSString *messageSender = [messageData senderId];
+
+    if ([messageSender isEqualToString:[layout.collectionView.dataSource senderId]]) {
+        return layout.outgoingAvatarViewSize;
+    }
+
+    return layout.incomingAvatarViewSize;
+}
+
+- (CGFloat)textBubbleWidthForLayout:(JSQMessagesCollectionViewFlowLayout *)layout
+{
+    if (self.usesFixedWidthBubbles) {
+        return [self widthForFixedWidthBubblesWithLayout:layout];
+    }
+
+    return layout.itemWidth;
+}
+
+- (CGFloat)widthForFixedWidthBubblesWithLayout:(JSQMessagesCollectionViewFlowLayout *)layout {
+    if (self.layoutWidthForFixedWidthBubbles > 0.0f) {
+        return self.layoutWidthForFixedWidthBubbles;
+    }
+
+    // also need to add `self.additionalInset` here, see comment above
+    NSInteger horizontalInsets = layout.sectionInset.left + layout.sectionInset.right + self.additionalInset;
+    CGFloat width = CGRectGetWidth(layout.collectionView.bounds) - horizontalInsets;
+    CGFloat height = CGRectGetHeight(layout.collectionView.bounds) - horizontalInsets;
+    self.layoutWidthForFixedWidthBubbles = MIN(width, height);
+    
+    return self.layoutWidthForFixedWidthBubbles;
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Layout/JSQMessagesCollectionViewFlowLayout.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Layout/JSQMessagesCollectionViewFlowLayout.h
new file mode 100644
index 0000000..021d385
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Layout/JSQMessagesCollectionViewFlowLayout.h
@@ -0,0 +1,213 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+//
+//  Ideas for springy collection view layout taken from Ash Furrow
+//  ASHSpringyCollectionView
+//  https://github.com/AshFurrow/ASHSpringyCollectionView
+//
+
+#import <UIKit/UIKit.h>
+
+#import "JSQMessagesBubbleSizeCalculating.h"
+
+@class JSQMessagesCollectionView;
+
+
+/**
+ *  A constant that describes the default height for all label subviews in a `JSQMessagesCollectionViewCell`.
+ *
+ *  @see JSQMessagesCollectionViewCell.
+ */
+FOUNDATION_EXPORT const CGFloat kJSQMessagesCollectionViewCellLabelHeightDefault;
+
+/**
+ *  A constant that describes the default size for avatar images in a `JSQMessagesCollectionViewFlowLayout`.
+ */
+FOUNDATION_EXPORT const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault;
+
+
+
+/**
+ *  The `JSQMessagesCollectionViewFlowLayout` is a concrete layout object that inherits 
+ *  from `UICollectionViewFlowLayout` and organizes message items in a vertical list.
+ *  Each `JSQMessagesCollectionViewCell` in the layout can display messages of arbitrary sizes and avatar images, 
+ *  as well as metadata such as a timestamp and sender.
+ *  You can easily customize the layout via its properties or its delegate methods 
+ *  defined in `JSQMessagesCollectionViewDelegateFlowLayout`.
+ *
+ *  @see JSQMessagesCollectionViewDelegateFlowLayout.
+ *  @see JSQMessagesCollectionViewCell.
+ */
+@interface JSQMessagesCollectionViewFlowLayout : UICollectionViewFlowLayout
+
+/**
+ *  The collection view object currently using this layout object.
+ */
+
+// TODO: fix, rename "messagesCollectionView", see #920
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wincompatible-property-type"
+@property (readonly, nonatomic) JSQMessagesCollectionView *collectionView;
+#pragma clang diagnostic pop
+
+/**
+ *  The object that the layout uses to calculate bubble sizes.
+ *  The default value is an instance of `JSQMessagesBubblesSizeCalculator`.
+ */
+@property (strong, nonatomic) id<JSQMessagesBubbleSizeCalculating> bubbleSizeCalculator;
+
+/**
+ *  Specifies whether or not the layout should enable spring behavior dynamics for its items using `UIDynamics`.
+ *
+ *  @discussion The default value is `NO`, which disables "springy" or "bouncy" items in the layout. 
+ *  Set to `YES` if you want items to have spring behavior dynamics. You *must* set this property from `viewDidAppear:`
+ *  in your `JSQMessagesViewController` subclass.
+ *
+ *  @warning Though this feature is mostly stable, it is still considered an experimental feature.
+ */
+@property (assign, nonatomic) BOOL springinessEnabled;
+
+/**
+ *  Specifies the degree of resistence for the "springiness" of items in the layout. 
+ *  This property has no effect if `springinessEnabled` is set to `NO`.
+ *
+ *  @discussion The default value is `1000`. Increasing this value increases the resistance, that is, items become less "bouncy". 
+ *  Decrease this value in order to make items more "bouncy".
+ */
+@property (assign, nonatomic) NSUInteger springResistanceFactor;
+
+/**
+ *  Returns the width of items in the layout.
+ */
+@property (readonly, nonatomic) CGFloat itemWidth;
+
+/**
+ *  The font used to display the body a text message in the message bubble of each 
+ *  `JSQMessagesCollectionViewCell` in the collectionView. 
+ *  
+ *  @discussion The default value is the preferred system font for `UIFontTextStyleBody`. This value must not be `nil`.
+ */
+@property (strong, nonatomic) UIFont *messageBubbleFont;
+
+/**
+ *  The horizontal spacing used to lay out the `messageBubbleContainerView` frame within each `JSQMessagesCollectionViewCell`.
+ *  This container view holds the message bubble image and message contents of a cell.
+ *
+ *  This value specifies the horizontal spacing between the `messageBubbleContainerView` and
+ *  the edge of the collection view cell in which it is displayed. That is, the edge that is opposite the avatar image.
+ *
+ *  @discussion The default value is `40.0f` on iPhone and `240.0f` on iPad. This value must be positive.
+ *  For *outgoing* messages, this value specifies the amount of spacing from the left most 
+ *  edge of the collectionView to the left most edge of a message bubble within a cell.
+ *
+ *  For *incoming* messages, this value specifies the amount of spacing from the right most 
+ *  edge of the collectionView to the right most edge of a message bubble within a cell.
+ *
+ *  @warning This value may not be exact when the layout object finishes laying out its items, due to the constraints it must satisfy. 
+ *  This value should be considered more of a recommendation or suggestion to the layout, not an exact value.
+ *
+ *  @see JSQMessagesCollectionViewCellIncoming.
+ *  @see JSQMessagesCollectionViewCellOutgoing.
+ */
+@property (assign, nonatomic) CGFloat messageBubbleLeftRightMargin;
+
+/**
+ *  The inset of the frame of the text view within the `messageBubbleContainerView` of each `JSQMessagesCollectionViewCell`.
+ *  The inset values should be positive and are applied in the following ways:
+ *  
+ *  1. The right value insets the text view frame on the side adjacent to the avatar image 
+ *      (or where the avatar would normally appear). For outgoing messages this is the right side, 
+ *      for incoming messages this is the left side.
+ *
+ *  2. The left value insets the text view frame on the side opposite the avatar image 
+ *      (or where the avatar would normally appear). For outgoing messages this is the left side, 
+ *      for incoming messages this is the right side.
+ *
+ *  3. The top value insets the top of the frame.
+ *
+ *  4. The bottom value insets the bottom of the frame.
+ *
+ *  @discussion The default value is `{0.0f, 0.0f, 0.0f, 6.0f}`.
+ *
+ *  @warning Adjusting this value is an advanced endeavour and not recommended. 
+ *  You will only need to adjust this value should you choose to provide your own bubble image assets.
+ *  Changing this value may also require you to manually calculate the itemSize for each cell 
+ *  in the layout by overriding the delegate method `collectionView:layout:sizeForItemAtIndexPath:`
+ */
+@property (assign, nonatomic) UIEdgeInsets messageBubbleTextViewFrameInsets;
+
+/**
+ *  The inset of the text container's layout area within the text view's content area in each `JSQMessagesCollectionViewCell`. 
+ *  The specified inset values should be positive.
+ *
+ *  @discussion The default value is `{7.0f, 14.0f, 7.0f, 14.0f}`.
+ *
+ *  @warning Adjusting this value is an advanced endeavour and not recommended. 
+ *  You will only need to adjust this value should you choose to provide your own bubble image assets.
+ *  Changing this value may also require you to manually calculate the itemSize for each cell
+ *  in the layout by overriding the delegate method `collectionView:layout:sizeForItemAtIndexPath:`
+ */
+@property (assign, nonatomic) UIEdgeInsets messageBubbleTextViewTextContainerInsets;
+
+/**
+ *  The size of the avatar image view for incoming messages.
+ *
+ *  @discussion The default value is `(30.0f, 30.0f)`. Set to `CGSizeZero` to remove incoming avatars.
+ *  You may use `kJSQMessagesCollectionViewAvatarSizeDefault` to size your avatars to the default value.
+ */
+@property (assign, nonatomic) CGSize incomingAvatarViewSize;
+
+/**
+ *  The size of the avatar image view for outgoing messages.
+ *
+ *  @discussion The default value is `(30.0f, 30.0f)`. Set to `CGSizeZero` to remove outgoing avatars.
+ *  You may use `kJSQMessagesCollectionViewAvatarSizeDefault` to size your avatars to the default value.
+ */
+@property (assign, nonatomic) CGSize outgoingAvatarViewSize;
+
+/**
+ *  The maximum number of items that the layout should keep in its cache of layout information.
+ *
+ *  @discussion The default value is `200`. A limit of `0` means no limit. This is not a strict limit.
+ */
+@property (assign, nonatomic) NSUInteger cacheLimit;
+
+/**
+ *  Computes and returns the size of the `messageBubbleImageView` property of a `JSQMessagesCollectionViewCell`
+ *  at the specified indexPath.
+ *
+ *  @param indexPath The index path of the item to be displayed.
+ *
+ *  @return The size of the message bubble for the item displayed at indexPath.
+ *
+ *  @discussion The layout uses its `bubbleSizeCalculator` object to perform this computation.
+ *  The returned size contains the required dimensions to display the entire message contents.
+ *  Note, this is *not* the entire cell, but only its message bubble.
+ */
+- (CGSize)messageBubbleSizeForItemAtIndexPath:(NSIndexPath *)indexPath;
+
+/**
+ *  Computes and returns the size of the item specified by indexPath.
+ *
+ *  @param indexPath The index path of the item to be displayed.
+ *
+ *  @return The size of the item displayed at indexPath.
+ */
+- (CGSize)sizeForItemAtIndexPath:(NSIndexPath *)indexPath;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Layout/JSQMessagesCollectionViewFlowLayout.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Layout/JSQMessagesCollectionViewFlowLayout.m
new file mode 100644
index 0000000..b430d62
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Layout/JSQMessagesCollectionViewFlowLayout.m
@@ -0,0 +1,532 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+//
+//  Ideas for springy collection view layout taken from Ash Furrow
+//  ASHSpringyCollectionView
+//  https://github.com/AshFurrow/ASHSpringyCollectionView
+//
+
+#import "JSQMessagesCollectionViewFlowLayout.h"
+
+#import "JSQMessageData.h"
+
+#import "JSQMessagesCollectionView.h"
+#import "JSQMessagesCollectionViewCell.h"
+
+#import "JSQMessagesCollectionViewLayoutAttributes.h"
+#import "JSQMessagesCollectionViewFlowLayoutInvalidationContext.h"
+#import "JSQMessagesBubblesSizeCalculator.h"
+
+#import "UIImage+JSQMessages.h"
+
+
+const CGFloat kJSQMessagesCollectionViewCellLabelHeightDefault = 20.0f;
+const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
+
+
+@interface JSQMessagesCollectionViewFlowLayout ()
+
+@property (strong, nonatomic) UIDynamicAnimator *dynamicAnimator;
+@property (strong, nonatomic) NSMutableSet *visibleIndexPaths;
+
+@property (assign, nonatomic) CGFloat latestDelta;
+
+@end
+
+
+
+@implementation JSQMessagesCollectionViewFlowLayout
+
+@dynamic collectionView;
+
+@synthesize bubbleSizeCalculator = _bubbleSizeCalculator;
+
+#pragma mark - Initialization
+
+- (void)jsq_configureFlowLayout
+{
+    self.scrollDirection = UICollectionViewScrollDirectionVertical;
+    self.sectionInset = UIEdgeInsetsMake(10.0f, 4.0f, 10.0f, 4.0f);
+    self.minimumLineSpacing = 4.0f;
+    
+    _messageBubbleFont = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
+    
+    if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
+        _messageBubbleLeftRightMargin = 240.0f;
+    }
+    else {
+        _messageBubbleLeftRightMargin = 50.0f;
+    }
+    
+    _messageBubbleTextViewFrameInsets = UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 6.0f);
+    _messageBubbleTextViewTextContainerInsets = UIEdgeInsetsMake(7.0f, 14.0f, 7.0f, 14.0f);
+    
+    CGSize defaultAvatarSize = CGSizeMake(kJSQMessagesCollectionViewAvatarSizeDefault, kJSQMessagesCollectionViewAvatarSizeDefault);
+    _incomingAvatarViewSize = defaultAvatarSize;
+    _outgoingAvatarViewSize = defaultAvatarSize;
+    
+    _springinessEnabled = NO;
+    _springResistanceFactor = 1000;
+    
+    [[NSNotificationCenter defaultCenter] addObserver:self
+                                             selector:@selector(jsq_didReceiveApplicationMemoryWarningNotification:)
+                                                 name:UIApplicationDidReceiveMemoryWarningNotification
+                                               object:nil];
+    
+    [[NSNotificationCenter defaultCenter] addObserver:self
+                                             selector:@selector(jsq_didReceiveDeviceOrientationDidChangeNotification:)
+                                                 name:UIDeviceOrientationDidChangeNotification
+                                               object:nil];
+}
+
+- (instancetype)init
+{
+    self = [super init];
+    if (self) {
+        [self jsq_configureFlowLayout];
+    }
+    return self;
+}
+
+- (void)awakeFromNib
+{
+    [super awakeFromNib];
+    [self jsq_configureFlowLayout];
+}
+
++ (Class)layoutAttributesClass
+{
+    return [JSQMessagesCollectionViewLayoutAttributes class];
+}
+
++ (Class)invalidationContextClass
+{
+    return [JSQMessagesCollectionViewFlowLayoutInvalidationContext class];
+}
+
+- (void)dealloc
+{
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+#pragma mark - Setters
+
+- (void)setBubbleSizeCalculator:(id<JSQMessagesBubbleSizeCalculating>)bubbleSizeCalculator
+{
+    NSParameterAssert(bubbleSizeCalculator != nil);
+    _bubbleSizeCalculator = bubbleSizeCalculator;
+}
+
+- (void)setSpringinessEnabled:(BOOL)springinessEnabled
+{
+    if (_springinessEnabled == springinessEnabled) {
+        return;
+    }
+    
+    _springinessEnabled = springinessEnabled;
+    
+    if (!springinessEnabled) {
+        [_dynamicAnimator removeAllBehaviors];
+        [_visibleIndexPaths removeAllObjects];
+    }
+    [self invalidateLayoutWithContext:[JSQMessagesCollectionViewFlowLayoutInvalidationContext context]];
+}
+
+- (void)setMessageBubbleFont:(UIFont *)messageBubbleFont
+{
+    if ([_messageBubbleFont isEqual:messageBubbleFont]) {
+        return;
+    }
+    
+    NSParameterAssert(messageBubbleFont != nil);
+    _messageBubbleFont = messageBubbleFont;
+    [self invalidateLayoutWithContext:[JSQMessagesCollectionViewFlowLayoutInvalidationContext context]];
+}
+
+- (void)setMessageBubbleLeftRightMargin:(CGFloat)messageBubbleLeftRightMargin
+{
+    NSParameterAssert(messageBubbleLeftRightMargin >= 0.0f);
+    _messageBubbleLeftRightMargin = ceilf(messageBubbleLeftRightMargin);
+    [self invalidateLayoutWithContext:[JSQMessagesCollectionViewFlowLayoutInvalidationContext context]];
+}
+
+- (void)setMessageBubbleTextViewTextContainerInsets:(UIEdgeInsets)messageBubbleTextContainerInsets
+{
+    if (UIEdgeInsetsEqualToEdgeInsets(_messageBubbleTextViewTextContainerInsets, messageBubbleTextContainerInsets)) {
+        return;
+    }
+    
+    _messageBubbleTextViewTextContainerInsets = messageBubbleTextContainerInsets;
+    [self invalidateLayoutWithContext:[JSQMessagesCollectionViewFlowLayoutInvalidationContext context]];
+}
+
+- (void)setIncomingAvatarViewSize:(CGSize)incomingAvatarViewSize
+{
+    if (CGSizeEqualToSize(_incomingAvatarViewSize, incomingAvatarViewSize)) {
+        return;
+    }
+    
+    _incomingAvatarViewSize = incomingAvatarViewSize;
+    [self invalidateLayoutWithContext:[JSQMessagesCollectionViewFlowLayoutInvalidationContext context]];
+}
+
+- (void)setOutgoingAvatarViewSize:(CGSize)outgoingAvatarViewSize
+{
+    if (CGSizeEqualToSize(_outgoingAvatarViewSize, outgoingAvatarViewSize)) {
+        return;
+    }
+    
+    _outgoingAvatarViewSize = outgoingAvatarViewSize;
+    [self invalidateLayoutWithContext:[JSQMessagesCollectionViewFlowLayoutInvalidationContext context]];
+}
+
+#pragma mark - Getters
+
+- (CGFloat)itemWidth
+{
+    return CGRectGetWidth(self.collectionView.frame) - self.sectionInset.left - self.sectionInset.right;
+}
+
+- (UIDynamicAnimator *)dynamicAnimator
+{
+    if (!_dynamicAnimator) {
+        _dynamicAnimator = [[UIDynamicAnimator alloc] initWithCollectionViewLayout:self];
+    }
+    return _dynamicAnimator;
+}
+
+- (NSMutableSet *)visibleIndexPaths
+{
+    if (!_visibleIndexPaths) {
+        _visibleIndexPaths = [NSMutableSet new];
+    }
+    return _visibleIndexPaths;
+}
+
+- (id<JSQMessagesBubbleSizeCalculating>)bubbleSizeCalculator
+{
+    if (_bubbleSizeCalculator == nil) {
+        _bubbleSizeCalculator = [JSQMessagesBubblesSizeCalculator new];
+    }
+
+    return _bubbleSizeCalculator;
+}
+
+#pragma mark - Notifications
+
+- (void)jsq_didReceiveApplicationMemoryWarningNotification:(NSNotification *)notification
+{
+    [self jsq_resetLayout];
+}
+
+- (void)jsq_didReceiveDeviceOrientationDidChangeNotification:(NSNotification *)notification
+{
+    [self jsq_resetLayout];
+    [self invalidateLayoutWithContext:[JSQMessagesCollectionViewFlowLayoutInvalidationContext context]];
+}
+
+#pragma mark - Collection view flow layout
+
+- (void)invalidateLayoutWithContext:(JSQMessagesCollectionViewFlowLayoutInvalidationContext *)context
+{
+    if (context.invalidateDataSourceCounts) {
+        context.invalidateFlowLayoutAttributes = YES;
+        context.invalidateFlowLayoutDelegateMetrics = YES;
+    }
+    
+    if (context.invalidateFlowLayoutAttributes
+        || context.invalidateFlowLayoutDelegateMetrics) {
+        [self jsq_resetDynamicAnimator];
+    }
+    
+    if (context.invalidateFlowLayoutMessagesCache) {
+        [self jsq_resetLayout];
+    }
+    
+    [super invalidateLayoutWithContext:context];
+}
+
+- (void)prepareLayout
+{
+    [super prepareLayout];
+    
+    if (self.springinessEnabled) {
+        //  pad rect to avoid flickering
+        CGFloat padding = -100.0f;
+        CGRect visibleRect = CGRectInset(self.collectionView.bounds, padding, padding);
+        
+        NSArray *visibleItems = [super layoutAttributesForElementsInRect:visibleRect];
+        NSSet *visibleItemsIndexPaths = [NSSet setWithArray:[visibleItems valueForKey:NSStringFromSelector(@selector(indexPath))]];
+        
+        [self jsq_removeNoLongerVisibleBehaviorsFromVisibleItemsIndexPaths:visibleItemsIndexPaths];
+        
+        [self jsq_addNewlyVisibleBehaviorsFromVisibleItems:visibleItems];
+    }
+}
+
+- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
+{
+    NSArray *attributesInRect = [[super layoutAttributesForElementsInRect:rect] copy];
+    
+    if (self.springinessEnabled) {
+        NSMutableArray *attributesInRectCopy = [attributesInRect mutableCopy];
+        NSArray *dynamicAttributes = [self.dynamicAnimator itemsInRect:rect];
+        
+        //  avoid duplicate attributes
+        //  use dynamic animator attribute item instead of regular item, if it exists
+        for (UICollectionViewLayoutAttributes *eachItem in attributesInRect) {
+            
+            for (UICollectionViewLayoutAttributes *eachDynamicItem in dynamicAttributes) {
+                if ([eachItem.indexPath isEqual:eachDynamicItem.indexPath]
+                    && eachItem.representedElementCategory == eachDynamicItem.representedElementCategory) {
+                    
+                    [attributesInRectCopy removeObject:eachItem];
+                    [attributesInRectCopy addObject:eachDynamicItem];
+                    continue;
+                }
+            }
+        }
+        
+        attributesInRect = [attributesInRectCopy copy];
+    }
+    
+    [attributesInRect enumerateObjectsUsingBlock:^(JSQMessagesCollectionViewLayoutAttributes *attributesItem, NSUInteger idx, BOOL *stop) {
+        if (attributesItem.representedElementCategory == UICollectionElementCategoryCell) {
+            [self jsq_configureMessageCellLayoutAttributes:attributesItem];
+        }
+        else {
+            attributesItem.zIndex = -1;
+        }
+    }];
+    
+    return attributesInRect;
+}
+
+- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
+{
+    JSQMessagesCollectionViewLayoutAttributes *customAttributes = (JSQMessagesCollectionViewLayoutAttributes *)[[super layoutAttributesForItemAtIndexPath:indexPath] copy];
+    
+    if (customAttributes.representedElementCategory == UICollectionElementCategoryCell) {
+        [self jsq_configureMessageCellLayoutAttributes:customAttributes];
+    }
+    
+    return customAttributes;
+}
+
+- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
+{
+    if (self.springinessEnabled) {
+        UIScrollView *scrollView = self.collectionView;
+        CGFloat delta = newBounds.origin.y - scrollView.bounds.origin.y;
+        
+        self.latestDelta = delta;
+        
+        CGPoint touchLocation = [self.collectionView.panGestureRecognizer locationInView:self.collectionView];
+        
+        [self.dynamicAnimator.behaviors enumerateObjectsUsingBlock:^(UIAttachmentBehavior *springBehaviour, NSUInteger idx, BOOL *stop) {
+            [self jsq_adjustSpringBehavior:springBehaviour forTouchLocation:touchLocation];
+            [self.dynamicAnimator updateItemUsingCurrentState:[springBehaviour.items firstObject]];
+        }];
+    }
+    
+    CGRect oldBounds = self.collectionView.bounds;
+    if (CGRectGetWidth(newBounds) != CGRectGetWidth(oldBounds)) {
+        return YES;
+    }
+    
+    return NO;
+}
+
+- (void)prepareForCollectionViewUpdates:(NSArray *)updateItems
+{
+    [super prepareForCollectionViewUpdates:updateItems];
+    
+    [updateItems enumerateObjectsUsingBlock:^(UICollectionViewUpdateItem *updateItem, NSUInteger index, BOOL *stop) {
+        if (updateItem.updateAction == UICollectionUpdateActionInsert) {
+            
+            if (self.springinessEnabled && [self.dynamicAnimator layoutAttributesForCellAtIndexPath:updateItem.indexPathAfterUpdate]) {
+                *stop = YES;
+            }
+            
+            CGFloat collectionViewHeight = CGRectGetHeight(self.collectionView.bounds);
+            
+            JSQMessagesCollectionViewLayoutAttributes *attributes = [JSQMessagesCollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:updateItem.indexPathAfterUpdate];
+            
+            if (attributes.representedElementCategory == UICollectionElementCategoryCell) {
+                [self jsq_configureMessageCellLayoutAttributes:attributes];
+            }
+            
+            attributes.frame = CGRectMake(0.0f,
+                                          collectionViewHeight + CGRectGetHeight(attributes.frame),
+                                          CGRectGetWidth(attributes.frame),
+                                          CGRectGetHeight(attributes.frame));
+            
+            if (self.springinessEnabled) {
+                UIAttachmentBehavior *springBehaviour = [self jsq_springBehaviorWithLayoutAttributesItem:attributes];
+                [self.dynamicAnimator addBehavior:springBehaviour];
+            }
+        }
+    }];
+}
+
+#pragma mark - Invalidation utilities
+
+- (void)jsq_resetLayout
+{
+    [self.bubbleSizeCalculator prepareForResettingLayout:self];
+    [self jsq_resetDynamicAnimator];
+}
+
+- (void)jsq_resetDynamicAnimator
+{
+    if (self.springinessEnabled) {
+        [self.dynamicAnimator removeAllBehaviors];
+        [self.visibleIndexPaths removeAllObjects];
+    }
+}
+
+#pragma mark - Message cell layout utilities
+
+- (CGSize)messageBubbleSizeForItemAtIndexPath:(NSIndexPath *)indexPath
+{
+    id<JSQMessageData> messageItem = [self.collectionView.dataSource collectionView:self.collectionView
+                                                      messageDataForItemAtIndexPath:indexPath];
+
+    return [self.bubbleSizeCalculator messageBubbleSizeForMessageData:messageItem
+                                                          atIndexPath:indexPath
+                                                           withLayout:self];
+}
+
+- (CGSize)sizeForItemAtIndexPath:(NSIndexPath *)indexPath
+{
+    CGSize messageBubbleSize = [self messageBubbleSizeForItemAtIndexPath:indexPath];
+    JSQMessagesCollectionViewLayoutAttributes *attributes = (JSQMessagesCollectionViewLayoutAttributes *)[self layoutAttributesForItemAtIndexPath:indexPath];
+    
+    CGFloat finalHeight = messageBubbleSize.height;
+    finalHeight += attributes.cellTopLabelHeight;
+    finalHeight += attributes.messageBubbleTopLabelHeight;
+    finalHeight += attributes.cellBottomLabelHeight;
+    
+    return CGSizeMake(self.itemWidth, ceilf(finalHeight));
+}
+
+- (void)jsq_configureMessageCellLayoutAttributes:(JSQMessagesCollectionViewLayoutAttributes *)layoutAttributes
+{
+    NSIndexPath *indexPath = layoutAttributes.indexPath;
+    
+    CGSize messageBubbleSize = [self messageBubbleSizeForItemAtIndexPath:indexPath];
+    
+    layoutAttributes.messageBubbleContainerViewWidth = messageBubbleSize.width;
+    
+    layoutAttributes.textViewFrameInsets = self.messageBubbleTextViewFrameInsets;
+    
+    layoutAttributes.textViewTextContainerInsets = self.messageBubbleTextViewTextContainerInsets;
+    
+    layoutAttributes.messageBubbleFont = self.messageBubbleFont;
+    
+    layoutAttributes.incomingAvatarViewSize = self.incomingAvatarViewSize;
+    
+    layoutAttributes.outgoingAvatarViewSize = self.outgoingAvatarViewSize;
+    
+    layoutAttributes.cellTopLabelHeight = [self.collectionView.delegate collectionView:self.collectionView
+                                                                                layout:self
+                                                      heightForCellTopLabelAtIndexPath:indexPath];
+    
+    layoutAttributes.messageBubbleTopLabelHeight = [self.collectionView.delegate collectionView:self.collectionView
+                                                                                         layout:self
+                                                      heightForMessageBubbleTopLabelAtIndexPath:indexPath];
+    
+    layoutAttributes.cellBottomLabelHeight = [self.collectionView.delegate collectionView:self.collectionView
+                                                                                   layout:self
+                                                      heightForCellBottomLabelAtIndexPath:indexPath];
+}
+
+#pragma mark - Spring behavior utilities
+
+- (UIAttachmentBehavior *)jsq_springBehaviorWithLayoutAttributesItem:(UICollectionViewLayoutAttributes *)item
+{
+    if (CGSizeEqualToSize(item.frame.size, CGSizeZero)) {
+        // adding a spring behavior with zero size will fail in in -prepareForCollectionViewUpdates:
+        return nil;
+    }
+    
+    UIAttachmentBehavior *springBehavior = [[UIAttachmentBehavior alloc] initWithItem:item attachedToAnchor:item.center];
+    springBehavior.length = 1.0f;
+    springBehavior.damping = 1.0f;
+    springBehavior.frequency = 1.0f;
+    return springBehavior;
+}
+
+- (void)jsq_addNewlyVisibleBehaviorsFromVisibleItems:(NSArray *)visibleItems
+{
+    //  a "newly visible" item is in `visibleItems` but not in `self.visibleIndexPaths`
+    NSIndexSet *indexSet = [visibleItems indexesOfObjectsPassingTest:^BOOL(UICollectionViewLayoutAttributes *item, NSUInteger index, BOOL *stop) {
+        return ![self.visibleIndexPaths containsObject:item.indexPath];
+    }];
+    
+    NSArray *newlyVisibleItems = [visibleItems objectsAtIndexes:indexSet];
+    
+    CGPoint touchLocation = [self.collectionView.panGestureRecognizer locationInView:self.collectionView];
+    
+    [newlyVisibleItems enumerateObjectsUsingBlock:^(UICollectionViewLayoutAttributes *item, NSUInteger index, BOOL *stop) {
+        UIAttachmentBehavior *springBehaviour = [self jsq_springBehaviorWithLayoutAttributesItem:item];
+        [self jsq_adjustSpringBehavior:springBehaviour forTouchLocation:touchLocation];
+        [self.dynamicAnimator addBehavior:springBehaviour];
+        [self.visibleIndexPaths addObject:item.indexPath];
+    }];
+}
+
+- (void)jsq_removeNoLongerVisibleBehaviorsFromVisibleItemsIndexPaths:(NSSet *)visibleItemsIndexPaths
+{
+    NSArray *behaviors = self.dynamicAnimator.behaviors;
+    
+    NSIndexSet *indexSet = [behaviors indexesOfObjectsPassingTest:^BOOL(UIAttachmentBehavior *springBehaviour, NSUInteger index, BOOL *stop) {
+        UICollectionViewLayoutAttributes *layoutAttributes = (UICollectionViewLayoutAttributes *)[springBehaviour.items firstObject];
+        return ![visibleItemsIndexPaths containsObject:layoutAttributes.indexPath];
+    }];
+    
+    NSArray *behaviorsToRemove = [self.dynamicAnimator.behaviors objectsAtIndexes:indexSet];
+    
+    [behaviorsToRemove enumerateObjectsUsingBlock:^(UIAttachmentBehavior *springBehaviour, NSUInteger index, BOOL *stop) {
+        UICollectionViewLayoutAttributes *layoutAttributes = (UICollectionViewLayoutAttributes *)[springBehaviour.items firstObject];
+        [self.dynamicAnimator removeBehavior:springBehaviour];
+        [self.visibleIndexPaths removeObject:layoutAttributes.indexPath];
+    }];
+}
+
+- (void)jsq_adjustSpringBehavior:(UIAttachmentBehavior *)springBehavior forTouchLocation:(CGPoint)touchLocation
+{
+    UICollectionViewLayoutAttributes *item = (UICollectionViewLayoutAttributes *)[springBehavior.items firstObject];
+    CGPoint center = item.center;
+    
+    //  if touch is not (0,0) -- adjust item center "in flight"
+    if (!CGPointEqualToPoint(CGPointZero, touchLocation)) {
+        CGFloat distanceFromTouch = fabs(touchLocation.y - springBehavior.anchorPoint.y);
+        CGFloat scrollResistance = distanceFromTouch / self.springResistanceFactor;
+        
+        if (self.latestDelta < 0.0f) {
+            center.y += MAX(self.latestDelta, self.latestDelta * scrollResistance);
+        }
+        else {
+            center.y += MIN(self.latestDelta, self.latestDelta * scrollResistance);
+        }
+        item.center = center;
+    }
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Layout/JSQMessagesCollectionViewFlowLayoutInvalidationContext.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Layout/JSQMessagesCollectionViewFlowLayoutInvalidationContext.h
new file mode 100644
index 0000000..b15c46f
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Layout/JSQMessagesCollectionViewFlowLayoutInvalidationContext.h
@@ -0,0 +1,47 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <UIKit/UIKit.h>
+
+/**
+ *  A `JSQMessagesCollectionViewFlowLayoutInvalidationContext` object specifies properties for 
+ *  determining whether to recompute the size of items or their position in the layout. 
+ *  The flow layout object creates instances of this class when it needs to invalidate its contents 
+ *  in response to changes. You can also create instances when invalidating the flow layout manually.
+ *
+ */
+@interface JSQMessagesCollectionViewFlowLayoutInvalidationContext : UICollectionViewFlowLayoutInvalidationContext
+
+/**
+ *  A boolean indicating whether to empty the messages layout information cache for items and views in the layout.
+ *  The default value is `NO`.
+ */
+@property (nonatomic, assign) BOOL invalidateFlowLayoutMessagesCache;
+
+/**
+ *  Creates and returns a new `JSQMessagesCollectionViewFlowLayoutInvalidationContext` object.
+ *
+ *  @discussion When you need to invalidate the `JSQMessagesCollectionViewFlowLayout` object for your
+ *  `JSQMessagesViewController` subclass, you should use this method to instantiate a new invalidation 
+ *  context and pass this object to `invalidateLayoutWithContext:`.
+ *
+ *  @return An initialized invalidation context object if successful, otherwise `nil`.
+ */
++ (instancetype)context;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Layout/JSQMessagesCollectionViewFlowLayoutInvalidationContext.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Layout/JSQMessagesCollectionViewFlowLayoutInvalidationContext.m
new file mode 100644
index 0000000..696596d
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Layout/JSQMessagesCollectionViewFlowLayoutInvalidationContext.m
@@ -0,0 +1,52 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQMessagesCollectionViewFlowLayoutInvalidationContext.h"
+
+@implementation JSQMessagesCollectionViewFlowLayoutInvalidationContext
+
+#pragma mark - Initialization
+
+- (instancetype)init
+{
+    self = [super init];
+    if (self) {
+        self.invalidateFlowLayoutDelegateMetrics = NO;
+        self.invalidateFlowLayoutAttributes = NO;
+        _invalidateFlowLayoutMessagesCache = NO;
+    }
+    return self;
+}
+
++ (instancetype)context
+{
+    JSQMessagesCollectionViewFlowLayoutInvalidationContext *context = [[JSQMessagesCollectionViewFlowLayoutInvalidationContext alloc] init];
+    context.invalidateFlowLayoutDelegateMetrics = YES;
+    context.invalidateFlowLayoutAttributes = YES;
+    return context;
+}
+
+#pragma mark - NSObject
+
+- (NSString *)description
+{
+    return [NSString stringWithFormat:@"<%@: invalidateFlowLayoutDelegateMetrics=%@, invalidateFlowLayoutAttributes=%@, invalidateDataSourceCounts=%@, invalidateFlowLayoutMessagesCache=%@>",
+            [self class], @(self.invalidateFlowLayoutDelegateMetrics), @(self.invalidateFlowLayoutAttributes), @(self.invalidateDataSourceCounts), @(self.invalidateFlowLayoutMessagesCache)];
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Layout/JSQMessagesCollectionViewLayoutAttributes.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Layout/JSQMessagesCollectionViewLayoutAttributes.h
new file mode 100644
index 0000000..6b41418
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Layout/JSQMessagesCollectionViewLayoutAttributes.h
@@ -0,0 +1,106 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <UIKit/UIKit.h>
+
+/**
+ *  A `JSQMessagesCollectionViewLayoutAttributes` is an object that manages the layout-related attributes
+ *  for a given `JSQMessagesCollectionViewCell` in a `JSQMessagesCollectionView`.
+ */
+@interface JSQMessagesCollectionViewLayoutAttributes : UICollectionViewLayoutAttributes <NSCopying>
+
+/**
+ *  The font used to display the body of a text message in a message bubble within a `JSQMessagesCollectionViewCell`.
+ *  This value must not be `nil`.
+ */
+@property (strong, nonatomic) UIFont *messageBubbleFont;
+
+/**
+ *  The width of the `messageBubbleContainerView` of a `JSQMessagesCollectionViewCell`.
+ *  This value should be greater than `0.0`.
+ *
+ *  @see JSQMessagesCollectionViewCell.
+ */
+@property (assign, nonatomic) CGFloat messageBubbleContainerViewWidth;
+
+/**
+ *  The inset of the text container's layout area within the text view's content area in a `JSQMessagesCollectionViewCell`. 
+ *  The specified inset values should be greater than or equal to `0.0`.
+ */
+@property (assign, nonatomic) UIEdgeInsets textViewTextContainerInsets;
+
+/**
+ *  The inset of the frame of the text view within a `JSQMessagesCollectionViewCell`. 
+ *  
+ *  @discussion The inset values should be greater than or equal to `0.0` and are applied in the following ways:
+ *
+ *  1. The right value insets the text view frame on the side adjacent to the avatar image 
+ *  (or where the avatar would normally appear). For outgoing messages this is the right side, 
+ *  for incoming messages this is the left side.
+ *
+ *  2. The left value insets the text view frame on the side opposite the avatar image 
+ *  (or where the avatar would normally appear). For outgoing messages this is the left side, 
+ *  for incoming messages this is the right side.
+ *
+ *  3. The top value insets the top of the frame.
+ *
+ *  4. The bottom value insets the bottom of the frame.
+ */
+@property (assign, nonatomic) UIEdgeInsets textViewFrameInsets;
+
+/**
+ *  The size of the `avatarImageView` of a `JSQMessagesCollectionViewCellIncoming`.
+ *  The size values should be greater than or equal to `0.0`.
+ *
+ *  @see JSQMessagesCollectionViewCellIncoming.
+ */
+@property (assign, nonatomic) CGSize incomingAvatarViewSize;
+
+/**
+ *  The size of the `avatarImageView` of a `JSQMessagesCollectionViewCellOutgoing`.
+ *  The size values should be greater than or equal to `0.0`.
+ *
+ *  @see `JSQMessagesCollectionViewCellOutgoing`.
+ */
+@property (assign, nonatomic) CGSize outgoingAvatarViewSize;
+
+/**
+ *  The height of the `cellTopLabel` of a `JSQMessagesCollectionViewCell`.
+ *  This value should be greater than or equal to `0.0`.
+ *
+ *  @see JSQMessagesCollectionViewCell.
+ */
+@property (assign, nonatomic) CGFloat cellTopLabelHeight;
+
+/**
+ *  The height of the `messageBubbleTopLabel` of a `JSQMessagesCollectionViewCell`.
+ *  This value should be greater than or equal to `0.0`.
+ *
+ *  @see JSQMessagesCollectionViewCell.
+ */
+@property (assign, nonatomic) CGFloat messageBubbleTopLabelHeight;
+
+/**
+ *  The height of the `cellBottomLabel` of a `JSQMessagesCollectionViewCell`.
+ *  This value should be greater than or equal to `0.0`.
+ *
+ *  @see JSQMessagesCollectionViewCell.
+ */
+@property (assign, nonatomic) CGFloat cellBottomLabelHeight;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Layout/JSQMessagesCollectionViewLayoutAttributes.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Layout/JSQMessagesCollectionViewLayoutAttributes.m
new file mode 100644
index 0000000..9dcbbba
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Layout/JSQMessagesCollectionViewLayoutAttributes.m
@@ -0,0 +1,149 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQMessagesCollectionViewLayoutAttributes.h"
+
+@implementation JSQMessagesCollectionViewLayoutAttributes
+
+#pragma mark - Init
+
+- (instancetype)init {
+    self = [super init];
+    if (self) {
+        _messageBubbleFont = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
+        _messageBubbleContainerViewWidth = 320.0f;
+    }
+    return self;
+}
+
+#pragma mark - Setters
+
+- (void)setMessageBubbleFont:(UIFont *)messageBubbleFont
+{
+    NSParameterAssert(messageBubbleFont != nil);
+    _messageBubbleFont = messageBubbleFont;
+}
+
+- (void)setMessageBubbleContainerViewWidth:(CGFloat)messageBubbleContainerViewWidth
+{
+    NSParameterAssert(messageBubbleContainerViewWidth > 0.0f);
+    _messageBubbleContainerViewWidth = ceilf(messageBubbleContainerViewWidth);
+}
+
+- (void)setIncomingAvatarViewSize:(CGSize)incomingAvatarViewSize
+{
+    NSParameterAssert(incomingAvatarViewSize.width >= 0.0f && incomingAvatarViewSize.height >= 0.0f);
+    _incomingAvatarViewSize = [self jsq_correctedAvatarSizeFromSize:incomingAvatarViewSize];
+}
+
+- (void)setOutgoingAvatarViewSize:(CGSize)outgoingAvatarViewSize
+{
+    NSParameterAssert(outgoingAvatarViewSize.width >= 0.0f && outgoingAvatarViewSize.height >= 0.0f);
+    _outgoingAvatarViewSize = [self jsq_correctedAvatarSizeFromSize:outgoingAvatarViewSize];
+}
+
+- (void)setCellTopLabelHeight:(CGFloat)cellTopLabelHeight
+{
+    NSParameterAssert(cellTopLabelHeight >= 0.0f);
+    _cellTopLabelHeight = [self jsq_correctedLabelHeightForHeight:cellTopLabelHeight];
+}
+
+- (void)setMessageBubbleTopLabelHeight:(CGFloat)messageBubbleTopLabelHeight
+{
+    NSParameterAssert(messageBubbleTopLabelHeight >= 0.0f);
+    _messageBubbleTopLabelHeight = [self jsq_correctedLabelHeightForHeight:messageBubbleTopLabelHeight];
+}
+
+- (void)setCellBottomLabelHeight:(CGFloat)cellBottomLabelHeight
+{
+    NSParameterAssert(cellBottomLabelHeight >= 0.0f);
+    _cellBottomLabelHeight = [self jsq_correctedLabelHeightForHeight:cellBottomLabelHeight];
+}
+
+#pragma mark - Utilities
+
+- (CGSize)jsq_correctedAvatarSizeFromSize:(CGSize)size
+{
+    return CGSizeMake(ceilf(size.width), ceilf(size.height));
+}
+
+- (CGFloat)jsq_correctedLabelHeightForHeight:(CGFloat)height
+{
+    return ceilf(height);
+}
+
+#pragma mark - NSObject
+
+- (BOOL)isEqual:(id)object
+{
+    if (self == object) {
+        return YES;
+    }
+    
+    if (![object isKindOfClass:[self class]]) {
+        return NO;
+    }
+    
+    if (self.representedElementCategory == UICollectionElementCategoryCell) {
+        JSQMessagesCollectionViewLayoutAttributes *layoutAttributes = (JSQMessagesCollectionViewLayoutAttributes *)object;
+        
+        if (![layoutAttributes.messageBubbleFont isEqual:self.messageBubbleFont]
+            || !UIEdgeInsetsEqualToEdgeInsets(layoutAttributes.textViewFrameInsets, self.textViewFrameInsets)
+            || !UIEdgeInsetsEqualToEdgeInsets(layoutAttributes.textViewTextContainerInsets, self.textViewTextContainerInsets)
+            || !CGSizeEqualToSize(layoutAttributes.incomingAvatarViewSize, self.incomingAvatarViewSize)
+            || !CGSizeEqualToSize(layoutAttributes.outgoingAvatarViewSize, self.outgoingAvatarViewSize)
+            || (int)layoutAttributes.messageBubbleContainerViewWidth != (int)self.messageBubbleContainerViewWidth
+            || (int)layoutAttributes.cellTopLabelHeight != (int)self.cellTopLabelHeight
+            || (int)layoutAttributes.messageBubbleTopLabelHeight != (int)self.messageBubbleTopLabelHeight
+            || (int)layoutAttributes.cellBottomLabelHeight != (int)self.cellBottomLabelHeight) {
+            return NO;
+        }
+    }
+    
+    return [super isEqual:object];
+}
+
+- (NSUInteger)hash
+{
+    return [self.indexPath hash];
+}
+
+#pragma mark - NSCopying
+
+- (instancetype)copyWithZone:(NSZone *)zone
+{
+    JSQMessagesCollectionViewLayoutAttributes *copy = [super copyWithZone:zone];
+    
+    if (copy.representedElementCategory != UICollectionElementCategoryCell) {
+        return copy;
+    }
+    
+    copy.messageBubbleFont = self.messageBubbleFont;
+    copy.messageBubbleContainerViewWidth = self.messageBubbleContainerViewWidth;
+    copy.textViewFrameInsets = self.textViewFrameInsets;
+    copy.textViewTextContainerInsets = self.textViewTextContainerInsets;
+    copy.incomingAvatarViewSize = self.incomingAvatarViewSize;
+    copy.outgoingAvatarViewSize = self.outgoingAvatarViewSize;
+    copy.cellTopLabelHeight = self.cellTopLabelHeight;
+    copy.messageBubbleTopLabelHeight = self.messageBubbleTopLabelHeight;
+    copy.cellBottomLabelHeight = self.cellBottomLabelHeight;
+    
+    return copy;
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQAudioMediaItem.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQAudioMediaItem.h
new file mode 100644
index 0000000..3534ec7
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQAudioMediaItem.h
@@ -0,0 +1,119 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQMediaItem.h"
+#import "JSQAudioMediaViewAttributes.h"
+
+#import <AVFoundation/AVFoundation.h>
+
+@class JSQAudioMediaItem;
+
+NS_ASSUME_NONNULL_BEGIN
+
+@protocol JSQAudioMediaItemDelegate <NSObject>
+
+/**
+ *  Tells the delegate if the specified `JSQAudioMediaItem` changes the sound category or categoryOptions, or if an error occurs.
+ */
+- (void)audioMediaItem:(JSQAudioMediaItem *)audioMediaItem
+didChangeAudioCategory:(NSString *)category
+               options:(AVAudioSessionCategoryOptions)options
+                 error:(nullable NSError *)error;
+
+@end
+
+
+/**
+ *  The `JSQAudioMediaItem` class is a concrete `JSQMediaItem` subclass that implements the `JSQMessageMediaData` protocol
+ *  and represents an audio media message. An initialized `JSQAudioMediaItem` object can be passed
+ *  to a `JSQMediaMessage` object during its initialization to construct a valid media message object.
+ *  You may wish to subclass `JSQAudioMediaItem` to provide additional functionality or behavior.
+ */
+@interface JSQAudioMediaItem : JSQMediaItem <JSQMessageMediaData, AVAudioPlayerDelegate, NSCoding, NSCopying>
+
+/**
+ *  The delegate object for audio event notifications.
+ */
+@property (nonatomic, weak, nullable) id<JSQAudioMediaItemDelegate> delegate;
+
+/**
+ *  The view attributes to configure the appearance of the audio media view.
+ */
+@property (nonatomic, strong, readonly) JSQAudioMediaViewAttributes *audioViewAttributes;
+
+/**
+ *  A data object that contains an audio resource.
+ */
+@property (nonatomic, strong, nullable) NSData *audioData;
+
+/**
+ *  Initializes and returns a audio media item having the given audioData.
+ *
+ *  @param audioData              The data object that contains the audio resource.
+ *  @param audioViewConfiguration The view attributes to configure the appearance of the audio media view.
+ *
+ *  @return An initialized `JSQAudioMediaItem`.
+ *
+ *  @discussion If the audio must be downloaded from the network,
+ *  you may initialize a `JSQVideoMediaItem` with a `nil` audioData.
+ *  Once the audio is available you can set the `audioData` property.
+ */
+- (instancetype)initWithData:(nullable NSData *)audioData
+         audioViewAttributes:(JSQAudioMediaViewAttributes *)audioViewAttributes NS_DESIGNATED_INITIALIZER;
+
+/**
+ *  Initializes and returns a default audio media item.
+ *
+ *  @return An initialized `JSQAudioMediaItem`.
+ *
+ *  @discussion You must set `audioData` to enable the play button.
+ */
+- (instancetype)init;
+
+/**
+ Initializes and returns a default audio media using the specified view attributes.
+
+ @param audioViewAttributes The view attributes to configure the appearance of the audio media view.
+
+ @return  An initialized `JSQAudioMediaItem`.
+ */
+- (instancetype)initWithAudioViewAttributes:(JSQAudioMediaViewAttributes *)audioViewAttributes;
+
+/**
+ *  Initializes and returns an audio media item having the given audioData.
+ *
+ *  @param audioData The data object that contains the audio resource.
+ *
+ *  @return An initialized `JSQAudioMediaItem`.
+ *
+ *  @discussion If the audio must be downloaded from the network,
+ *  you may initialize a `JSQAudioMediaItem` with a `nil` audioData.
+ *  Once the audio is available you can set the `audioData` property.
+ */
+- (instancetype)initWithData:(nullable NSData *)audioData;
+
+/**
+ *  Sets or updates the data object in an audio media item with the data specified at audioURL.
+ *
+ *  @param audioURL A File URL containing the location of the audio data.
+ */
+- (void)setAudioDataWithUrl:(nonnull NSURL *)audioURL;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQAudioMediaItem.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQAudioMediaItem.m
new file mode 100644
index 0000000..91dad9e
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQAudioMediaItem.m
@@ -0,0 +1,374 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQAudioMediaItem.h"
+
+#import "JSQMessagesMediaPlaceholderView.h"
+#import "JSQMessagesMediaViewBubbleImageMasker.h"
+
+#import "UIImage+JSQMessages.h"
+#import "UIColor+JSQMessages.h"
+
+
+@interface JSQAudioMediaItem ()
+
+@property (strong, nonatomic) UIView *cachedMediaView;
+
+@property (strong, nonatomic) UIButton *playButton;
+
+@property (strong, nonatomic) UIProgressView *progressView;
+@property (strong, nonatomic) UILabel *progressLabel;
+@property (strong, nonatomic) NSTimer *progressTimer;
+
+@property (strong, nonatomic) AVAudioPlayer *audioPlayer;
+
+@end
+
+
+@implementation JSQAudioMediaItem
+
+#pragma mark - Initialization
+
+- (instancetype)initWithData:(NSData *)audioData audioViewAttributes:(JSQAudioMediaViewAttributes *)audioViewAttributes
+{
+    NSParameterAssert(audioViewAttributes != nil);
+
+    self = [super init];
+    if (self) {
+        _cachedMediaView = nil;
+        _audioData = [audioData copy];
+        _audioViewAttributes = audioViewAttributes;
+    }
+    return self;
+}
+
+- (instancetype)initWithData:(NSData *)audioData
+{
+    return [self initWithData:audioData audioViewAttributes:[[JSQAudioMediaViewAttributes alloc] init]];
+}
+
+- (instancetype)initWithAudioViewAttributes:(JSQAudioMediaViewAttributes *)audioViewAttributes
+{
+    return [self initWithData:nil audioViewAttributes:audioViewAttributes];
+}
+
+- (instancetype)init
+{
+    return [self initWithData:nil audioViewAttributes:[[JSQAudioMediaViewAttributes alloc] init]];
+}
+
+- (void)dealloc
+{
+    _audioData = nil;
+    [self clearCachedMediaViews];
+}
+
+- (void)clearCachedMediaViews
+{
+    [_audioPlayer stop];
+    _audioPlayer = nil;
+
+    _playButton = nil;
+    _progressView = nil;
+    _progressLabel = nil;
+    [self stopProgressTimer];
+
+    _cachedMediaView = nil;
+    [super clearCachedMediaViews];
+}
+
+#pragma mark - Setters
+
+- (void)setAudioData:(NSData *)audioData
+{
+    _audioData = [audioData copy];
+    [self clearCachedMediaViews];
+}
+
+- (void)setAudioDataWithUrl:(NSURL *)audioURL
+{
+    _audioData = [NSData dataWithContentsOfURL:audioURL];
+    [self clearCachedMediaViews];
+}
+
+- (void)setAppliesMediaViewMaskAsOutgoing:(BOOL)appliesMediaViewMaskAsOutgoing
+{
+    [super setAppliesMediaViewMaskAsOutgoing:appliesMediaViewMaskAsOutgoing];
+    _cachedMediaView = nil;
+}
+
+#pragma mark - Private
+
+- (void)startProgressTimer
+{
+    self.progressTimer = [NSTimer scheduledTimerWithTimeInterval:0.1
+                                                          target:self
+                                                        selector:@selector(updateProgressTimer:)
+                                                        userInfo:nil
+                                                         repeats:YES];
+}
+
+- (void)stopProgressTimer
+{
+    [_progressTimer invalidate];
+    _progressTimer = nil;
+}
+
+- (void)updateProgressTimer:(NSTimer *)sender
+{
+    if (self.audioPlayer.playing) {
+        self.progressView.progress = self.audioPlayer.currentTime / self.audioPlayer.duration;
+        self.progressLabel.text = [self timestampString:self.audioPlayer.currentTime
+                                            forDuration:self.audioPlayer.duration];
+    }
+}
+
+- (NSString *)timestampString:(NSTimeInterval)currentTime forDuration:(NSTimeInterval)duration
+{
+    // print the time as 0:ss or ss.x up to 59 seconds
+    // print the time as m:ss up to 59:59 seconds
+    // print the time as h:mm:ss for anything longer
+    if (duration < 60) {
+        if (self.audioViewAttributes.showFractionalSeconds) {
+            return [NSString stringWithFormat:@"%.01f", currentTime];
+        }
+        else if (currentTime < duration) {
+            return [NSString stringWithFormat:@"0:%02d", (int)round(currentTime)];
+        }
+        return [NSString stringWithFormat:@"0:%02d", (int)ceil(currentTime)];
+    }
+    else if (duration < 3600) {
+        return [NSString stringWithFormat:@"%d:%02d", (int)currentTime / 60, (int)currentTime % 60];
+    }
+
+    return [NSString stringWithFormat:@"%d:%02d:%02d", (int)currentTime / 3600, (int)currentTime / 60, (int)currentTime % 60];
+}
+
+- (void)onPlayButton:(UIButton *)sender
+{
+    NSString *category = [AVAudioSession sharedInstance].category;
+    AVAudioSessionCategoryOptions options = [AVAudioSession sharedInstance].categoryOptions;
+
+    if (category != self.audioViewAttributes.audioCategory || options != self.audioViewAttributes.audioCategoryOptions) {
+        NSError *error = nil;
+        [[AVAudioSession sharedInstance] setCategory:self.audioViewAttributes.audioCategory
+                                         withOptions:self.audioViewAttributes.audioCategoryOptions
+                                               error:&error];
+        if (self.delegate) {
+            [self.delegate audioMediaItem:self didChangeAudioCategory:category options:options error:error];
+        }
+    }
+
+    if (self.audioPlayer.playing) {
+        self.playButton.selected = NO;
+        [self stopProgressTimer];
+        [self.audioPlayer stop];
+    }
+    else {
+        // fade the button from play to pause
+        [UIView transitionWithView:self.playButton
+                          duration:.2
+                           options:UIViewAnimationOptionTransitionCrossDissolve
+                        animations:^{
+                            self.playButton.selected = YES;
+                        }
+                        completion:nil];
+
+        [self startProgressTimer];
+        [self.audioPlayer play];
+    }
+}
+
+#pragma mark - AVAudioPlayerDelegate
+
+- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player
+                       successfully:(BOOL)flag {
+
+    // set progress to full, then fade back to the default state
+    [self stopProgressTimer];
+    self.progressView.progress = 1;
+    [UIView transitionWithView:self.cachedMediaView
+                      duration:.2
+                       options:UIViewAnimationOptionTransitionCrossDissolve
+                    animations:^{
+                        self.progressView.progress = 0;
+                        self.playButton.selected = NO;
+                        self.progressLabel.text = [self timestampString:self.audioPlayer.duration
+                                                            forDuration:self.audioPlayer.duration];
+                    }
+                    completion:nil];
+}
+
+#pragma mark - JSQMessageMediaData protocol
+
+- (CGSize)mediaViewDisplaySize
+{
+    return CGSizeMake(160.0f,
+                      self.audioViewAttributes.controlInsets.top +
+                      self.audioViewAttributes.controlInsets.bottom +
+                      self.audioViewAttributes.playButtonImage.size.height);
+}
+
+- (UIView *)mediaView
+{
+    if (self.audioData && self.cachedMediaView == nil) {
+        if (self.audioData) {
+            self.audioPlayer = [[AVAudioPlayer alloc] initWithData:self.audioData error:nil];
+            self.audioPlayer.delegate = self;
+        }
+
+        // reverse the insets based on the message direction
+        CGFloat leftInset, rightInset;
+        if (self.appliesMediaViewMaskAsOutgoing) {
+            leftInset = self.audioViewAttributes.controlInsets.left;
+            rightInset = self.audioViewAttributes.controlInsets.right;
+        } else {
+            leftInset = self.audioViewAttributes.controlInsets.right;
+            rightInset = self.audioViewAttributes.controlInsets.left;
+        }
+        
+        // create container view for the various controls
+        CGSize size = [self mediaViewDisplaySize];
+        UIView * playView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, size.width, size.height)];
+        playView.backgroundColor = self.audioViewAttributes.backgroundColor;
+        playView.contentMode = UIViewContentModeCenter;
+        playView.clipsToBounds = YES;
+
+        // create the play button
+        CGRect buttonFrame = CGRectMake(leftInset,
+                                        self.audioViewAttributes.controlInsets.top,
+                                        self.audioViewAttributes.playButtonImage.size.width,
+                                        self.audioViewAttributes.playButtonImage.size.height);
+        
+        self.playButton = [[UIButton alloc] initWithFrame:buttonFrame];
+        [self.playButton setImage:self.audioViewAttributes.playButtonImage forState:UIControlStateNormal];
+        [self.playButton setImage:self.audioViewAttributes.pauseButtonImage forState:UIControlStateSelected];
+        [self.playButton addTarget:self action:@selector(onPlayButton:) forControlEvents:UIControlEventTouchUpInside];
+        [playView addSubview:self.playButton];
+
+        // create a label to show the duration / elapsed time
+        NSString *durationString = [self timestampString:self.audioPlayer.duration
+                                             forDuration:self.audioPlayer.duration];
+        NSString *maxWidthString = [@"" stringByPaddingToLength:[durationString length] withString:@"0" startingAtIndex:0];
+
+        // this is cheesy, but it centers the progress bar without extra space and
+        // without causing it to wiggle from side to side as the label text changes
+        CGSize labelSize = CGSizeMake(36, 18);
+        if ([durationString length] < 4) {
+            labelSize = CGSizeMake(18,18);
+        }
+        else if ([durationString length] < 5) {
+            labelSize = CGSizeMake(24,18);
+        }
+        else if ([durationString length] < 6) {
+            labelSize = CGSizeMake(30, 18);
+        }
+
+        CGRect labelFrame = CGRectMake(size.width - labelSize.width - rightInset,
+                                       self.audioViewAttributes.controlInsets.top, labelSize.width, labelSize.height);
+        self.progressLabel = [[UILabel alloc] initWithFrame:labelFrame];
+        self.progressLabel.textAlignment = NSTextAlignmentLeft;
+        self.progressLabel.adjustsFontSizeToFitWidth = YES;
+        self.progressLabel.textColor = self.audioViewAttributes.tintColor;
+        self.progressLabel.font = self.audioViewAttributes.labelFont;
+        self.progressLabel.text = maxWidthString;
+
+        // sizeToFit adjusts the frame's height to the font
+        [self.progressLabel sizeToFit];
+        labelFrame.origin.x = size.width - self.progressLabel.frame.size.width - rightInset;
+        labelFrame.origin.y =  ((size.height - self.progressLabel.frame.size.height) / 2);
+        labelFrame.size.width = self.progressLabel.frame.size.width;
+        labelFrame.size.height =  self.progressLabel.frame.size.height;
+        self.progressLabel.frame = labelFrame;
+        self.progressLabel.text = durationString;
+        [playView addSubview:self.progressLabel];
+
+        // create a progress bar
+        self.progressView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
+        CGFloat xOffset = self.playButton.frame.origin.x + self.playButton.frame.size.width + self.audioViewAttributes.controlPadding;
+        CGFloat width = labelFrame.origin.x - xOffset - self.audioViewAttributes.controlPadding;
+        self.progressView.frame = CGRectMake(xOffset, (size.height - self.progressView.frame.size.height) / 2,
+                                             width, self.progressView.frame.size.height);
+        self.progressView.tintColor = self.audioViewAttributes.tintColor;
+        [playView addSubview:self.progressView];
+
+        [JSQMessagesMediaViewBubbleImageMasker applyBubbleImageMaskToMediaView:playView isOutgoing:self.appliesMediaViewMaskAsOutgoing];
+        self.cachedMediaView = playView;
+    }
+
+    return self.cachedMediaView;
+}
+
+- (NSUInteger)mediaHash
+{
+    return self.hash;
+}
+
+#pragma mark - NSObject
+
+- (BOOL)isEqual:(id)object
+{
+    if (![super isEqual:object]) {
+        return NO;
+    }
+
+    JSQAudioMediaItem *audioItem = (JSQAudioMediaItem *)object;
+    if (self.audioData && ![self.audioData isEqualToData:audioItem.audioData]) {
+        return NO;
+    }
+
+    return YES;
+}
+
+- (NSUInteger)hash
+{
+    return super.hash ^ self.audioData.hash;
+}
+
+- (NSString *)description
+{
+    return [NSString stringWithFormat:@"<%@: audioData=%ld bytes, appliesMediaViewMaskAsOutgoing=%@>",
+            [self class], (unsigned long)[self.audioData length],
+            @(self.appliesMediaViewMaskAsOutgoing)];
+}
+
+#pragma mark - NSCoding
+
+- (instancetype)initWithCoder:(NSCoder *)aDecoder
+{
+    NSData *data = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(audioData))];
+    return [self initWithData:data];
+}
+
+- (void)encodeWithCoder:(NSCoder *)aCoder
+{
+    [super encodeWithCoder:aCoder];
+    [aCoder encodeObject:self.audioData forKey:NSStringFromSelector(@selector(audioData))];
+}
+
+#pragma mark - NSCopying
+
+- (instancetype)copyWithZone:(NSZone *)zone
+{
+    JSQAudioMediaItem *copy = [[[self class] allocWithZone:zone] initWithData:self.audioData
+                                                          audioViewAttributes:self.audioViewAttributes];
+    copy.appliesMediaViewMaskAsOutgoing = self.appliesMediaViewMaskAsOutgoing;
+    return copy;
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQLocationMediaItem.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQLocationMediaItem.h
new file mode 100644
index 0000000..83b563e
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQLocationMediaItem.h
@@ -0,0 +1,86 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <CoreLocation/CoreLocation.h>
+#import <MapKit/MapKit.h>
+
+/**
+ *  A completion handler block for a `JSQLocationMediaItem`. See `setLocation: withCompletionHandler:`.
+ */
+typedef void (^JSQLocationMediaItemCompletionBlock)(void);
+
+
+#import "JSQMediaItem.h"
+
+/**
+ *  The `JSQLocationMediaItem` class is a concrete `JSQMediaItem` subclass that implements the `JSQMessageMediaData` protocol
+ *  and represents a location media message. An initialized `JSQLocationMediaItem` object can be passed
+ *  to a `JSQMediaMessage` object during its initialization to construct a valid media message object.
+ *  You may wish to subclass `JSQLocationMediaItem` to provide additional functionality or behavior.
+ */
+@interface JSQLocationMediaItem : JSQMediaItem <JSQMessageMediaData, MKAnnotation, NSCoding, NSCopying>
+
+/**
+ *  The location for the media item. The default value is `nil`.
+ */
+@property (copy, nonatomic) CLLocation *location;
+
+/**
+ *  The coordinate of the location property.
+ */
+@property (readonly, nonatomic) CLLocationCoordinate2D coordinate;
+
+/**
+ *  Initializes and returns a location media item object having the given location.
+ *
+ *  @param location The location for the media item. This value may be `nil`.
+ *
+ *  @return An initialized `JSQLocationMediaItem` if successful, `nil` otherwise.
+ *
+ *  @discussion If the location data must be dowloaded from the network,
+ *  you may initialize a `JSQLocationMediaItem` object with a `nil` location.
+ *  Once the location data has been retrieved, you can then set the location property
+ *  using `setLocation: withCompletionHandler:`
+ */
+- (instancetype)initWithLocation:(CLLocation *)location;
+
+/**
+ *  Sets the specified location for the location media item and immediately begins creating
+ *  a map view snapshot image on a background thread. The map view zooms to a default region whose center point 
+ *  is the location coordinate and whose span is 500 meters for both the latitudinal and longitudinal meters.
+ *
+ *  The specified block is executed upon completion of creating the snapshot image and is executed on the app’s main thread.
+ *
+ *  @param location   The location for the media item.
+ *  @param completion The block to call after the map view snapshot for the given location has been created.
+ */
+- (void)setLocation:(CLLocation *)location withCompletionHandler:(JSQLocationMediaItemCompletionBlock)completion;
+
+/**
+ *  Sets the specified location for the location media item and immediately begins creating
+ *  a map view snapshot image on a background thread.
+ *
+ *  The specified block is executed upon completion of creating the snapshot image and is executed on the app’s main thread.
+ *
+ *  @param location   The location for the media item.
+ *  @param region     The map region that you want to capture.
+ *  @param completion The block to call after the map view snapshot for the given location has been created.
+ */
+- (void)setLocation:(CLLocation *)location
+             region:(MKCoordinateRegion)region withCompletionHandler:(JSQLocationMediaItemCompletionBlock)completion;
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQLocationMediaItem.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQLocationMediaItem.m
new file mode 100644
index 0000000..611dc3a
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQLocationMediaItem.m
@@ -0,0 +1,212 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQLocationMediaItem.h"
+
+#import "JSQMessagesMediaPlaceholderView.h"
+#import "JSQMessagesMediaViewBubbleImageMasker.h"
+
+
+@interface JSQLocationMediaItem ()
+
+@property (strong, nonatomic) UIImage *cachedMapSnapshotImage;
+
+@property (strong, nonatomic) UIImageView *cachedMapImageView;
+
+@end
+
+
+@implementation JSQLocationMediaItem
+
+#pragma mark - Initialization
+
+- (instancetype)initWithLocation:(CLLocation *)location
+{
+    self = [super init];
+    if (self) {
+        [self setLocation:location withCompletionHandler:nil];
+    }
+    return self;
+}
+
+- (void)clearCachedMediaViews
+{
+    [super clearCachedMediaViews];
+    _cachedMapImageView = nil;
+}
+
+#pragma mark - Setters
+
+- (void)setLocation:(CLLocation *)location
+{
+    [self setLocation:location withCompletionHandler:nil];
+}
+
+- (void)setAppliesMediaViewMaskAsOutgoing:(BOOL)appliesMediaViewMaskAsOutgoing
+{
+    [super setAppliesMediaViewMaskAsOutgoing:appliesMediaViewMaskAsOutgoing];
+    _cachedMapSnapshotImage = nil;
+    _cachedMapImageView = nil;
+}
+
+#pragma mark - Map snapshot
+
+- (void)setLocation:(CLLocation *)location withCompletionHandler:(JSQLocationMediaItemCompletionBlock)completion
+{
+    [self setLocation:location region:MKCoordinateRegionMakeWithDistance(location.coordinate, 500.0, 500.0) withCompletionHandler:completion];
+}
+
+- (void)setLocation:(CLLocation *)location region:(MKCoordinateRegion)region withCompletionHandler:(JSQLocationMediaItemCompletionBlock)completion
+{
+    _location = [location copy];
+    _cachedMapSnapshotImage = nil;
+    _cachedMapImageView = nil;
+    
+    if (_location == nil) {
+        return;
+    }
+    
+    [self createMapViewSnapshotForLocation:_location
+                          coordinateRegion:region
+                     withCompletionHandler:completion];
+}
+
+- (void)createMapViewSnapshotForLocation:(CLLocation *)location
+                        coordinateRegion:(MKCoordinateRegion)region
+                   withCompletionHandler:(JSQLocationMediaItemCompletionBlock)completion
+{
+    NSParameterAssert(location != nil);
+    
+    MKMapSnapshotOptions *options = [[MKMapSnapshotOptions alloc] init];
+    options.region = region;
+    options.size = [self mediaViewDisplaySize];
+    options.scale = [UIScreen mainScreen].scale;
+    
+    MKMapSnapshotter *snapShotter = [[MKMapSnapshotter alloc] initWithOptions:options];
+    
+    [snapShotter startWithQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
+              completionHandler:^(MKMapSnapshot *snapshot, NSError *error) {
+                  if (snapshot == nil) {
+                      NSLog(@"%s Error creating map snapshot: %@", __PRETTY_FUNCTION__, error);
+                      return;
+                  }
+                  
+                  MKAnnotationView *pin = [[MKPinAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:nil];
+                  CGPoint coordinatePoint = [snapshot pointForCoordinate:location.coordinate];
+                  UIImage *image = snapshot.image;
+                  
+                  coordinatePoint.x += pin.centerOffset.x - (CGRectGetWidth(pin.bounds) / 2.0);
+                  coordinatePoint.y += pin.centerOffset.y - (CGRectGetHeight(pin.bounds) / 2.0);
+                  
+                  UIGraphicsBeginImageContextWithOptions(image.size, YES, image.scale);
+                  {
+                      [image drawAtPoint:CGPointZero];
+                      [pin.image drawAtPoint:coordinatePoint];
+                      self.cachedMapSnapshotImage = UIGraphicsGetImageFromCurrentImageContext();
+                  }
+                  UIGraphicsEndImageContext();
+                  
+                  if (completion) {
+                      dispatch_async(dispatch_get_main_queue(), completion);
+                  }
+              }];
+}
+
+#pragma mark - MKAnnotation
+
+- (CLLocationCoordinate2D)coordinate
+{
+    return self.location.coordinate;
+}
+
+#pragma mark - JSQMessageMediaData protocol
+
+- (UIView *)mediaView
+{
+    if (self.location == nil || self.cachedMapSnapshotImage == nil) {
+        return nil;
+    }
+    
+    if (self.cachedMapImageView == nil) {
+        UIImageView *imageView = [[UIImageView alloc] initWithImage:self.cachedMapSnapshotImage];
+        imageView.contentMode = UIViewContentModeScaleAspectFill;
+        imageView.clipsToBounds = YES;
+        [JSQMessagesMediaViewBubbleImageMasker applyBubbleImageMaskToMediaView:imageView isOutgoing:self.appliesMediaViewMaskAsOutgoing];
+        self.cachedMapImageView = imageView;
+    }
+    
+    return self.cachedMapImageView;
+}
+
+- (NSUInteger)mediaHash
+{
+    return self.hash;
+}
+
+#pragma mark - NSObject
+
+- (BOOL)isEqual:(id)object
+{
+    if (![super isEqual:object]) {
+        return NO;
+    }
+    
+    JSQLocationMediaItem *locationItem = (JSQLocationMediaItem *)object;
+    
+    return [self.location isEqual:locationItem.location];
+}
+
+- (NSUInteger)hash
+{
+    return super.hash ^ self.location.hash;
+}
+
+- (NSString *)description
+{
+    return [NSString stringWithFormat:@"<%@: location=%@, appliesMediaViewMaskAsOutgoing=%@>",
+            [self class], self.location, @(self.appliesMediaViewMaskAsOutgoing)];
+}
+
+#pragma mark - NSCoding
+
+- (instancetype)initWithCoder:(NSCoder *)aDecoder
+{
+    self = [super initWithCoder:aDecoder];
+    if (self) {
+        CLLocation *location = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(location))];
+        [self setLocation:location withCompletionHandler:nil];
+    }
+    return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)aCoder
+{
+    [super encodeWithCoder:aCoder];
+    [aCoder encodeObject:self.location forKey:NSStringFromSelector(@selector(location))];
+}
+
+#pragma mark - NSCopying
+
+- (instancetype)copyWithZone:(NSZone *)zone
+{
+    JSQLocationMediaItem *copy = [[[self class] allocWithZone:zone] initWithLocation:self.location];
+    copy.appliesMediaViewMaskAsOutgoing = self.appliesMediaViewMaskAsOutgoing;
+    return copy;
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMediaItem.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMediaItem.h
new file mode 100644
index 0000000..f38756c
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMediaItem.h
@@ -0,0 +1,58 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQMessageMediaData.h"
+
+/**
+ *  The `JSQMediaItem` class is an abstract base class for media item model objects that represents
+ *  a single media attachment for a user message. It provides some default behavior for media items,
+ *  including a default mediaViewDisplaySize, a default mediaPlaceholderView, and view masking as
+ *  specified by appliesMediaViewMaskAsOutgoing. 
+ *
+ *  @warning This class is intended to be subclassed. You should not use it directly.
+ *
+ *  @see JSQLocationMediaItem.
+ *  @see JSQPhotoMediaItem.
+ *  @see JSQVideoMediaItem.
+ */
+@interface JSQMediaItem : NSObject <JSQMessageMediaData, NSCoding, NSCopying>
+
+/**
+ *  A boolean value indicating whether this media item should apply
+ *  an outgoing or incoming bubble image mask to its media views.
+ *  Specify `YES` for an outgoing mask, and `NO` for an incoming mask.
+ *  The default value is `YES`.
+ */
+@property (assign, nonatomic) BOOL appliesMediaViewMaskAsOutgoing;
+
+/**
+ *  Initializes and returns a media item with the specified value for maskAsOutgoing.
+ *
+ *  @param maskAsOutgoing A boolean value indicating whether this media item should apply
+ *  an outgoing or incoming bubble image mask to its media views.
+ *
+ *  @return An initialized `JSQMediaItem` object if successful, `nil` otherwise.
+ */
+- (instancetype)initWithMaskAsOutgoing:(BOOL)maskAsOutgoing;
+
+/**
+ *  Clears any media view or media placeholder view that the item has cached.
+ */
+- (void)clearCachedMediaViews;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMediaItem.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMediaItem.m
new file mode 100644
index 0000000..32e3adc
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMediaItem.m
@@ -0,0 +1,169 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQMediaItem.h"
+
+#import "JSQMessagesMediaPlaceholderView.h"
+#import "JSQMessagesMediaViewBubbleImageMasker.h"
+
+
+@interface JSQMediaItem ()
+
+@property (strong, nonatomic) UIView *cachedPlaceholderView;
+
+@end
+
+
+@implementation JSQMediaItem
+
+#pragma mark - Initialization
+
+- (instancetype)init
+{
+    return [self initWithMaskAsOutgoing:YES];
+}
+
+- (instancetype)initWithMaskAsOutgoing:(BOOL)maskAsOutgoing
+{
+    self = [super init];
+    if (self) {
+        _appliesMediaViewMaskAsOutgoing = maskAsOutgoing;
+        _cachedPlaceholderView = nil;
+        [[NSNotificationCenter defaultCenter] addObserver:self
+                                                 selector:@selector(didReceiveMemoryWarningNotification:)
+                                                     name:UIApplicationDidReceiveMemoryWarningNotification
+                                                   object:nil];
+    }
+    return self;
+}
+
+- (void)dealloc
+{
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+- (void)setAppliesMediaViewMaskAsOutgoing:(BOOL)appliesMediaViewMaskAsOutgoing
+{
+    _appliesMediaViewMaskAsOutgoing = appliesMediaViewMaskAsOutgoing;
+    _cachedPlaceholderView = nil;
+}
+
+- (void)clearCachedMediaViews
+{
+    _cachedPlaceholderView = nil;
+}
+
+#pragma mark - Notifications
+
+- (void)didReceiveMemoryWarningNotification:(NSNotification *)notification
+{
+    [self clearCachedMediaViews];
+}
+
+#pragma mark - JSQMessageMediaData protocol
+
+- (UIView *)mediaView
+{
+    NSAssert(NO, @"Error! required method not implemented in subclass. Need to implement %s", __PRETTY_FUNCTION__);
+    return nil;
+}
+
+- (CGSize)mediaViewDisplaySize
+{
+    if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
+        return CGSizeMake(315.0f, 225.0f);
+    }
+    
+    return CGSizeMake(210.0f, 150.0f);
+}
+
+- (UIView *)mediaPlaceholderView
+{
+    if (self.cachedPlaceholderView == nil) {
+        CGSize size = [self mediaViewDisplaySize];
+        UIView *view = [JSQMessagesMediaPlaceholderView viewWithActivityIndicator];
+        view.frame = CGRectMake(0.0f, 0.0f, size.width, size.height);
+        [JSQMessagesMediaViewBubbleImageMasker applyBubbleImageMaskToMediaView:view isOutgoing:self.appliesMediaViewMaskAsOutgoing];
+        self.cachedPlaceholderView = view;
+    }
+    
+    return self.cachedPlaceholderView;
+}
+
+- (NSUInteger)mediaHash
+{
+    return self.hash;
+}
+
+#pragma mark - NSObject
+
+- (BOOL)isEqual:(id)object
+{
+    if (self == object) {
+        return YES;
+    }
+    
+    if (![object isKindOfClass:[self class]]) {
+        return NO;
+    }
+    
+    JSQMediaItem *item = (JSQMediaItem *)object;
+    
+    return self.appliesMediaViewMaskAsOutgoing == item.appliesMediaViewMaskAsOutgoing;
+}
+
+- (NSUInteger)hash
+{
+    return [NSNumber numberWithBool:self.appliesMediaViewMaskAsOutgoing].hash;
+}
+
+- (NSString *)description
+{
+    return [NSString stringWithFormat:@"<%@: appliesMediaViewMaskAsOutgoing=%@>",
+            [self class], @(self.appliesMediaViewMaskAsOutgoing)];
+}
+
+- (id)debugQuickLookObject
+{
+    return [self mediaView] ?: [self mediaPlaceholderView];
+}
+
+#pragma mark - NSCoding
+
+- (instancetype)initWithCoder:(NSCoder *)aDecoder
+{
+    self = [super init];
+    if (self) {
+        _appliesMediaViewMaskAsOutgoing = [aDecoder decodeBoolForKey:NSStringFromSelector(@selector(appliesMediaViewMaskAsOutgoing))];
+    }
+    return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)aCoder
+{
+    [aCoder encodeBool:self.appliesMediaViewMaskAsOutgoing forKey:NSStringFromSelector(@selector(appliesMediaViewMaskAsOutgoing))];
+}
+
+#pragma mark - NSCopying
+
+- (instancetype)copyWithZone:(NSZone *)zone
+{
+    return [[[self class] allocWithZone:zone] initWithMaskAsOutgoing:self.appliesMediaViewMaskAsOutgoing];
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessage.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessage.h
new file mode 100644
index 0000000..3f1a19c
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessage.h
@@ -0,0 +1,139 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <Foundation/Foundation.h>
+
+#import "JSQMessageData.h"
+
+/**
+ *  The `JSQMessage` class is a concrete class for message model objects that represents a single user message.
+ *  The message can be a text message or media message, depending on how it is initialized.
+ *  It implements the `JSQMessageData` protocol and it contains the senderId, senderDisplayName,
+ *  and the date that the message was sent. If initialized as a media message it also contains a media attachment,
+ *  otherwise it contains the message text.
+ */
+@interface JSQMessage : NSObject <JSQMessageData, NSCoding, NSCopying>
+
+/**
+ *  Returns the string identifier that uniquely identifies the user who sent the message. 
+ */
+@property (copy, nonatomic, readonly) NSString *senderId;
+
+/**
+ *  Returns the display name for the user who sent the message. This value does not have to be unique.
+ */
+@property (copy, nonatomic, readonly) NSString *senderDisplayName;
+
+/**
+ *  Returns the date that the message was sent.
+ */
+@property (copy, nonatomic, readonly) NSDate *date;
+
+/**
+ *  Returns a boolean value specifying whether or not the message contains media.
+ *  If `NO`, the message contains text. If `YES`, the message contains media.
+ *  The value of this property depends on how the object was initialized.
+ */
+@property (assign, nonatomic, readonly) BOOL isMediaMessage;
+
+/**
+ *  Returns the body text of the message, or `nil` if the message is a media message.
+ *  That is, if `isMediaMessage` is equal to `YES` then this value will be `nil`.
+ */
+@property (copy, nonatomic, readonly) NSString *text;
+
+/**
+ *  Returns the media item attachment of the message, or `nil` if the message is not a media message.
+ *  That is, if `isMediaMessage` is equal to `NO` then this value will be `nil`.
+ */
+@property (copy, nonatomic, readonly) id<JSQMessageMediaData> media;
+
+
+#pragma mark - Initialization
+
+/**
+ *  Initializes and returns a message object having the given senderId, displayName, text,
+ *  and current system date.
+ *
+ *  @param senderId    The unique identifier for the user who sent the message. This value must not be `nil`.
+ *  @param displayName The display name for the user who sent the message. This value must not be `nil`.
+ *  @param text        The body text of the message. This value must not be `nil`.
+ *
+ *  @discussion Initializing a `JSQMessage` with this method will set `isMediaMessage` to `NO`.
+ *
+ *  @return An initialized `JSQMessage` object if successful, `nil` otherwise.
+ */
++ (instancetype)messageWithSenderId:(NSString *)senderId
+                        displayName:(NSString *)displayName
+                               text:(NSString *)text;
+
+/**
+ *  Initializes and returns a message object having the given senderId, senderDisplayName, date, and text.
+ *
+ *  @param senderId          The unique identifier for the user who sent the message. This value must not be `nil`.
+ *  @param senderDisplayName The display name for the user who sent the message. This value must not be `nil`.
+ *  @param date              The date that the message was sent. This value must not be `nil`.
+ *  @param text              The body text of the message. This value must not be `nil`.
+ *
+ *  @discussion Initializing a `JSQMessage` with this method will set `isMediaMessage` to `NO`.
+ *
+ *  @return An initialized `JSQMessage` object if successful, `nil` otherwise.
+ */
+- (instancetype)initWithSenderId:(NSString *)senderId
+               senderDisplayName:(NSString *)senderDisplayName
+                            date:(NSDate *)date
+                            text:(NSString *)text;
+/**
+ *  Initializes and returns a message object having the given senderId, displayName, media,
+ *  and current system date.
+ *
+ *  @param senderId    The unique identifier for the user who sent the message. This value must not be `nil`.
+ *  @param displayName The display name for the user who sent the message. This value must not be `nil`.
+ *  @param media       The media data for the message. This value must not be `nil`.
+ *
+ *  @discussion Initializing a `JSQMessage` with this method will set `isMediaMessage` to `YES`.
+ *
+ *  @return An initialized `JSQMessage` object if successful, `nil` otherwise.
+ */
++ (instancetype)messageWithSenderId:(NSString *)senderId
+                        displayName:(NSString *)displayName
+                              media:(id<JSQMessageMediaData>)media;
+
+/**
+ *  Initializes and returns a message object having the given senderId, displayName, date, and media.
+ *
+ *  @param senderId          The unique identifier for the user who sent the message. This value must not be `nil`.
+ *  @param senderDisplayName The display name for the user who sent the message. This value must not be `nil`.
+ *  @param date              The date that the message was sent. This value must not be `nil`.
+ *  @param media             The media data for the message. This value must not be `nil`.
+ *
+ *  @discussion Initializing a `JSQMessage` with this method will set `isMediaMessage` to `YES`.
+ *
+ *  @return An initialized `JSQMessage` object if successful, `nil` otherwise.
+ */
+- (instancetype)initWithSenderId:(NSString *)senderId
+               senderDisplayName:(NSString *)senderDisplayName
+                            date:(NSDate *)date
+                           media:(id<JSQMessageMediaData>)media;
+
+/**
+ *  Not a valid initializer.
+ */
+- (id)init NS_UNAVAILABLE;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessage.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessage.m
new file mode 100644
index 0000000..b326fdd
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessage.m
@@ -0,0 +1,187 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQMessage.h"
+
+
+@implementation JSQMessage
+
+#pragma mark - Initialization
+
++ (instancetype)messageWithSenderId:(NSString *)senderId
+                        displayName:(NSString *)displayName
+                               text:(NSString *)text
+{
+    return [[self alloc] initWithSenderId:senderId
+                        senderDisplayName:displayName
+                                     date:[NSDate date]
+                                     text:text];
+}
+
+- (instancetype)initWithSenderId:(NSString *)senderId
+               senderDisplayName:(NSString *)senderDisplayName
+                            date:(NSDate *)date
+                            text:(NSString *)text
+{
+    NSParameterAssert(text != nil);
+
+    self = [self initWithSenderId:senderId senderDisplayName:senderDisplayName date:date isMedia:NO];
+    if (self) {
+        _text = [text copy];
+    }
+    return self;
+}
+
++ (instancetype)messageWithSenderId:(NSString *)senderId
+                        displayName:(NSString *)displayName
+                              media:(id<JSQMessageMediaData>)media
+{
+    return [[self alloc] initWithSenderId:senderId
+                        senderDisplayName:displayName
+                                     date:[NSDate date]
+                                    media:media];
+}
+
+- (instancetype)initWithSenderId:(NSString *)senderId
+               senderDisplayName:(NSString *)senderDisplayName
+                            date:(NSDate *)date
+                           media:(id<JSQMessageMediaData>)media
+{
+    NSParameterAssert(media != nil);
+
+    self = [self initWithSenderId:senderId senderDisplayName:senderDisplayName date:date isMedia:YES];
+    if (self) {
+        _media = media;
+    }
+    return self;
+}
+
+- (instancetype)initWithSenderId:(NSString *)senderId
+               senderDisplayName:(NSString *)senderDisplayName
+                            date:(NSDate *)date
+                         isMedia:(BOOL)isMedia
+{
+    NSParameterAssert(senderId != nil);
+    NSParameterAssert(senderDisplayName != nil);
+    NSParameterAssert(date != nil);
+
+    self = [super init];
+    if (self) {
+        _senderId = [senderId copy];
+        _senderDisplayName = [senderDisplayName copy];
+        _date = [date copy];
+        _isMediaMessage = isMedia;
+    }
+    return self;
+}
+
+- (NSUInteger)messageHash
+{
+    return self.hash;
+}
+
+#pragma mark - NSObject
+
+- (BOOL)isEqual:(id)object
+{
+    if (self == object) {
+        return YES;
+    }
+
+    if (![object isKindOfClass:[self class]]) {
+        return NO;
+    }
+
+    JSQMessage *aMessage = (JSQMessage *)object;
+
+    if (self.isMediaMessage != aMessage.isMediaMessage) {
+        return NO;
+    }
+
+    BOOL hasEqualContent = self.isMediaMessage ? [self.media isEqual:aMessage.media] : [self.text isEqualToString:aMessage.text];
+
+    return [self.senderId isEqualToString:aMessage.senderId]
+    && [self.senderDisplayName isEqualToString:aMessage.senderDisplayName]
+    && ([self.date compare:aMessage.date] == NSOrderedSame)
+    && hasEqualContent;
+}
+
+- (NSUInteger)hash
+{
+    NSUInteger contentHash = self.isMediaMessage ? [self.media mediaHash] : self.text.hash;
+    return self.senderId.hash ^ self.date.hash ^ contentHash;
+}
+
+- (NSString *)description
+{
+    return [NSString stringWithFormat:@"<%@: senderId=%@, senderDisplayName=%@, date=%@, isMediaMessage=%@, text=%@, media=%@>",
+            [self class], self.senderId, self.senderDisplayName, self.date, @(self.isMediaMessage), self.text, self.media];
+}
+
+- (id)debugQuickLookObject
+{
+    return [self.media mediaView] ?: [self.media mediaPlaceholderView];
+}
+
+#pragma mark - NSCoding
+
+- (instancetype)initWithCoder:(NSCoder *)aDecoder
+{
+    self = [super init];
+    if (self) {
+        _senderId = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(senderId))];
+        _senderDisplayName = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(senderDisplayName))];
+        _date = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(date))];
+        _isMediaMessage = [aDecoder decodeBoolForKey:NSStringFromSelector(@selector(isMediaMessage))];
+        _text = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(text))];
+        _media = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(media))];
+    }
+    return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)aCoder
+{
+    [aCoder encodeObject:self.senderId forKey:NSStringFromSelector(@selector(senderId))];
+    [aCoder encodeObject:self.senderDisplayName forKey:NSStringFromSelector(@selector(senderDisplayName))];
+    [aCoder encodeObject:self.date forKey:NSStringFromSelector(@selector(date))];
+    [aCoder encodeBool:self.isMediaMessage forKey:NSStringFromSelector(@selector(isMediaMessage))];
+    [aCoder encodeObject:self.text forKey:NSStringFromSelector(@selector(text))];
+
+    if ([self.media conformsToProtocol:@protocol(NSCoding)]) {
+        [aCoder encodeObject:self.media forKey:NSStringFromSelector(@selector(media))];
+    }
+}
+
+#pragma mark - NSCopying
+
+- (instancetype)copyWithZone:(NSZone *)zone
+{
+    if (self.isMediaMessage) {
+        return [[[self class] allocWithZone:zone] initWithSenderId:self.senderId
+                                                 senderDisplayName:self.senderDisplayName
+                                                              date:self.date
+                                                             media:self.media];
+    }
+
+    return [[[self class] allocWithZone:zone] initWithSenderId:self.senderId
+                                             senderDisplayName:self.senderDisplayName
+                                                          date:self.date
+                                                          text:self.text];
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessageAvatarImageDataSource.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessageAvatarImageDataSource.h
new file mode 100644
index 0000000..fc31072
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessageAvatarImageDataSource.h
@@ -0,0 +1,63 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+/**
+ *  The `JSQMessageAvatarImageDataSource` protocol defines the common interface through which
+ *  a `JSQMessagesViewController` and `JSQMessagesCollectionView` interact with avatar image model objects.
+ *
+ *  It declares the required and optional methods that a class must implement so that instances
+ *  of that class can be display properly within a `JSQMessagesCollectionViewCell`.
+ *
+ *  A concrete class that conforms to this protocol is provided in the library. See `JSQMessagesAvatarImage`.
+ *
+ *  @see JSQMessagesAvatarImage.
+ */
+@protocol JSQMessageAvatarImageDataSource <NSObject>
+
+@required
+
+/**
+ *  @return The avatar image for a regular display state.
+ *  
+ *  @discussion You may return `nil` from this method while the image is being downloaded.
+ */
+- (UIImage *)avatarImage;
+
+/**
+ *  @return The avatar image for a highlighted display state. 
+ *  
+ *  @discussion You may return `nil` from this method if this does not apply.
+ */
+- (UIImage *)avatarHighlightedImage;
+
+/**
+ *  @return A placeholder avatar image to be displayed if avatarImage is not yet available, or `nil`.
+ *  For example, if avatarImage needs to be downloaded, this placeholder image
+ *  will be used until avatarImage is not `nil`.
+ *
+ *  @discussion If you do not need support for a placeholder image, that is, your images 
+ *  are stored locally on the device, then you may simply return the same value as avatarImage here.
+ *
+ *  @warning You must not return `nil` from this method.
+ */
+- (UIImage *)avatarPlaceholderImage;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessageBubbleImageDataSource.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessageBubbleImageDataSource.h
new file mode 100644
index 0000000..26d4afd
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessageBubbleImageDataSource.h
@@ -0,0 +1,52 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+/**
+ *  The `JSQMessageBubbleImageDataSource` protocol defines the common interface through which
+ *  a `JSQMessagesViewController` and `JSQMessagesCollectionView` interact with 
+ *  message bubble image model objects.
+ *
+ *  It declares the required and optional methods that a class must implement so that instances
+ *  of that class can be display properly within a `JSQMessagesCollectionViewCell`.
+ *
+ *  A concrete class that conforms to this protocol is provided in the library. See `JSQMessagesBubbleImage`.
+ *
+ *  @see JSQMessagesBubbleImage.
+ */
+@protocol JSQMessageBubbleImageDataSource <NSObject>
+
+@required
+
+/**
+ *  @return The message bubble image for a regular display state.
+ *
+ *  @warning You must not return `nil` from this method.
+ */
+- (UIImage *)messageBubbleImage;
+
+/**
+ *  @return The message bubble image for a highlighted display state.
+ *
+ *  @warning You must not return `nil` from this method.
+ */
+- (UIImage *)messageBubbleHighlightedImage;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessageData.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessageData.h
new file mode 100644
index 0000000..41cd912
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessageData.h
@@ -0,0 +1,100 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <Foundation/Foundation.h>
+
+#import "JSQMessageMediaData.h"
+
+/**
+ *  The `JSQMessageData` protocol defines the common interface through which 
+ *  a `JSQMessagesViewController` and `JSQMessagesCollectionView` interact with message model objects.
+ *
+ *  It declares the required and optional methods that a class must implement so that instances of that class 
+ *  can be displayed properly within a `JSQMessagesCollectionViewCell`.
+ *
+ *  The class that conforms to this protocol is provided in the library. See `JSQMessage`.
+ *
+ *  @see JSQMessage.
+ */
+@protocol JSQMessageData <NSObject>
+
+@required
+
+/**
+ *  @return A string identifier that uniquely identifies the user who sent the message.
+ *
+ *  @discussion If you need to generate a unique identifier, consider using 
+ *  `[[NSProcessInfo processInfo] globallyUniqueString]`
+ *
+ *  @warning You must not return `nil` from this method. This value must be unique.
+ */
+- (NSString *)senderId;
+
+/**
+ *  @return The display name for the user who sent the message.
+ *
+ *  @warning You must not return `nil` from this method.
+ */
+- (NSString *)senderDisplayName;
+
+/**
+ *  @return The date that the message was sent.
+ *
+ *  @warning You must not return `nil` from this method.
+ */
+- (NSDate *)date;
+
+/**
+ *  This method is used to determine if the message data item contains text or media.
+ *  If this method returns `YES`, an instance of `JSQMessagesViewController` will ignore 
+ *  the `text` method of this protocol when dequeuing a `JSQMessagesCollectionViewCell`
+ *  and only call the `media` method. 
+ *
+ *  Similarly, if this method returns `NO` then the `media` method will be ignored and
+ *  and only the `text` method will be called.
+ *
+ *  @return A boolean value specifying whether or not this is a media message or a text message.
+ *  Return `YES` if this item is a media message, and `NO` if it is a text message.
+ */
+- (BOOL)isMediaMessage;
+
+/**
+ *  @return An integer that can be used as a table address in a hash table structure.
+ *
+ *  @discussion This value must be unique for each message with distinct contents. 
+ *  This value is used to cache layout information in the collection view.
+ */
+- (NSUInteger)messageHash;
+
+@optional
+
+/**
+ *  @return The body text of the message.
+ *
+ *  @warning You must not return `nil` from this method.
+ */
+- (NSString *)text;
+
+/**
+ *  @return The media item of the message.
+ *  
+ *  @warning You must not return `nil` from this method.
+ */
+- (id<JSQMessageMediaData>)media;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessageMediaData.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessageMediaData.h
new file mode 100644
index 0000000..4c8ab63
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessageMediaData.h
@@ -0,0 +1,81 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+/**
+ *  The `JSQMessageMediaData` protocol defines the common interface through which
+ *  a `JSQMessagesViewController` and `JSQMessagesCollectionView` interact with media message model objects.
+ *
+ *  It declares the required and optional methods that a class must implement so that instances of that class
+ *  can be displayed properly within a `JSQMessagesCollectionViewCell`.
+ *
+ *  This library provides a few concrete classes that conform to this protocol. You may use them as-is,
+ *  but they will likely require some modifications or extensions to conform to your particular data models.
+ *  These concrete media items are: `JSQPhotoMediaItem`, `JSQLocationMediaItem`, `JSQVideoMediaItem`.
+ *
+ *  @see JSQPhotoMediaItem.
+ *  @see JSQLocationMediaItem.
+ *  @see JSQVideoMediaItem.
+ */
+@protocol JSQMessageMediaData <NSObject>
+
+@required
+
+/**
+ *  @return An initialized `UIView` object that represents the data for this media object.
+ *
+ *  @discussion You may return `nil` from this method while the media data is being downloaded.
+ */
+- (UIView *)mediaView;
+
+/**
+ *  @return The frame size for the mediaView when displayed in a `JSQMessagesCollectionViewCell`. 
+ *
+ *  @discussion You should return an appropriate size value to be set for the mediaView's frame
+ *  based on the contents of the view, and the frame and layout of the `JSQMessagesCollectionViewCell`
+ *  in which mediaView will be displayed.
+ *
+ *  @warning You must return a size with non-zero, positive width and height values.
+ */
+- (CGSize)mediaViewDisplaySize;
+
+/**
+ *  @return A placeholder media view to be displayed if mediaView is not yet available, or `nil`.
+ *  For example, if mediaView will be constructed based on media data that must be downloaded,
+ *  this placeholder view will be used until mediaView is not `nil`.
+ *
+ *  @discussion If you do not need support for a placeholder view, then you may simply return the
+ *  same value here as mediaView. Otherwise, consider using `JSQMessagesMediaPlaceholderView`.
+ *
+ *  @warning You must not return `nil` from this method.
+ *
+ *  @see JSQMessagesMediaPlaceholderView.
+ */
+- (UIView *)mediaPlaceholderView;
+
+/**
+ *  @return An integer that can be used as a table address in a hash table structure.
+ *
+ *  @discussion This value must be unique for each media item with distinct contents.
+ *  This value is used to cache layout information in the collection view.
+ */
+- (NSUInteger)mediaHash;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessagesAvatarImage.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessagesAvatarImage.h
new file mode 100644
index 0000000..6d40fb4
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessagesAvatarImage.h
@@ -0,0 +1,86 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+#import "JSQMessageAvatarImageDataSource.h"
+
+/**
+ *  A `JSQMessagesAvatarImage` model object represents an avatar image.
+ *  This is a concrete class that implements the `JSQMessageAvatarImageDataSource` protocol.
+ *  It contains a regular avatar image, a highlighted avatar image, and a placeholder avatar image.
+ *
+ *  @see JSQMessagesAvatarImageFactory.
+ */
+@interface JSQMessagesAvatarImage : NSObject <JSQMessageAvatarImageDataSource, NSCopying>
+
+/**
+ *  The avatar image for a regular display state.
+ */
+@property (nonatomic, strong) UIImage *avatarImage;
+
+/**
+ *  The avatar image for a highlighted display state.
+ */
+@property (nonatomic, strong) UIImage *avatarHighlightedImage;
+
+/**
+ *  Returns the placeholder image for an avatar to display if avatarImage is `nil`.
+ */
+@property (nonatomic, strong, readonly) UIImage *avatarPlaceholderImage;
+
+/**
+ *  Initializes and returns an avatar image object having the specified image.
+ *
+ *  @param image The image for this avatar image. This image will be used for the all of the following
+ *  properties: avatarImage, avatarHighlightedImage, avatarPlaceholderImage;
+ *  This value must not be `nil`.
+ *
+ *  @return An initialized `JSQMessagesAvatarImage` object if successful, `nil` otherwise.
+ */
++ (instancetype)avatarWithImage:(UIImage *)image;
+
+/**
+ *  Initializes and returns an avatar image object having the specified placeholder image.
+ *
+ *  @param placeholderImage The placeholder image for this avatar image. This value must not be `nil`.
+ *
+ *  @return An initialized `JSQMessagesAvatarImage` object if successful, `nil` otherwise.
+ */
++ (instancetype)avatarImageWithPlaceholder:(UIImage *)placeholderImage;
+
+/**
+ *  Initializes and returns an avatar image object having the specified regular, highlighed, and placeholder images.
+ *
+ *  @param avatarImage      The avatar image for a regular display state.
+ *  @param highlightedImage The avatar image for a highlighted display state.
+ *  @param placeholderImage The placeholder image for this avatar image. This value must not be `nil`.
+ *
+ *  @return An initialized `JSQMessagesAvatarImage` object if successful, `nil` otherwise.
+ */
+- (instancetype)initWithAvatarImage:(UIImage *)avatarImage
+                   highlightedImage:(UIImage *)highlightedImage
+                   placeholderImage:(UIImage *)placeholderImage NS_DESIGNATED_INITIALIZER;
+
+/**
+ *  Not a valid initializer.
+ */
+- (id)init NS_UNAVAILABLE;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessagesAvatarImage.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessagesAvatarImage.m
new file mode 100644
index 0000000..2082861
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessagesAvatarImage.m
@@ -0,0 +1,78 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQMessagesAvatarImage.h"
+
+@implementation JSQMessagesAvatarImage 
+
+#pragma mark - Initialization
+
++ (instancetype)avatarWithImage:(UIImage *)image
+{
+    NSParameterAssert(image != nil);
+    
+    return [[JSQMessagesAvatarImage alloc] initWithAvatarImage:image
+                                              highlightedImage:image
+                                              placeholderImage:image];
+}
+
++ (instancetype)avatarImageWithPlaceholder:(UIImage *)placeholderImage
+{
+    return [[JSQMessagesAvatarImage alloc] initWithAvatarImage:nil
+                                              highlightedImage:nil
+                                              placeholderImage:placeholderImage];
+}
+
+- (instancetype)initWithAvatarImage:(UIImage *)avatarImage
+                   highlightedImage:(UIImage *)highlightedImage
+                   placeholderImage:(UIImage *)placeholderImage
+{
+    NSParameterAssert(placeholderImage != nil);
+    
+    self = [super init];
+    if (self) {
+        _avatarImage = avatarImage;
+        _avatarHighlightedImage = highlightedImage;
+        _avatarPlaceholderImage = placeholderImage;
+    }
+    return self;
+}
+
+#pragma mark - NSObject
+
+- (NSString *)description
+{
+    return [NSString stringWithFormat:@"<%@: avatarImage=%@, avatarHighlightedImage=%@, avatarPlaceholderImage=%@>",
+            [self class], self.avatarImage, self.avatarHighlightedImage, self.avatarPlaceholderImage];
+}
+
+- (id)debugQuickLookObject
+{
+    return [[UIImageView alloc] initWithImage:self.avatarImage ?: self.avatarPlaceholderImage];
+}
+
+#pragma mark - NSCopying
+
+- (instancetype)copyWithZone:(NSZone *)zone
+{
+    return [[[self class] allocWithZone:zone] initWithAvatarImage:[UIImage imageWithCGImage:self.avatarImage.CGImage]
+                                                 highlightedImage:[UIImage imageWithCGImage:self.avatarHighlightedImage.CGImage]
+                                                 placeholderImage:[UIImage imageWithCGImage:self.avatarPlaceholderImage.CGImage]];
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessagesBubbleImage.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessagesBubbleImage.h
new file mode 100644
index 0000000..137c48e
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessagesBubbleImage.h
@@ -0,0 +1,60 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+#import "JSQMessageBubbleImageDataSource.h"
+
+/**
+ *  A `JSQMessagesBubbleImage` model object represents a message bubble image, and is immutable. 
+ *  This is a concrete class that implements the `JSQMessageBubbleImageDataSource` protocol.
+ *  It contains a regular message bubble image and a highlighted message bubble image.
+ *
+ *  @see JSQMessagesBubbleImageFactory.
+ */
+@interface JSQMessagesBubbleImage : NSObject <JSQMessageBubbleImageDataSource, NSCopying>
+
+/**
+ *  Returns the message bubble image for a regular display state.
+ */
+@property (strong, nonatomic, readonly) UIImage *messageBubbleImage;
+
+/**
+ *  Returns the message bubble image for a highlighted display state.
+ */
+@property (strong, nonatomic, readonly) UIImage *messageBubbleHighlightedImage;
+
+/**
+ *  Initializes and returns a message bubble image object having the specified regular image and highlighted image.
+ *
+ *  @param image            The regular message bubble image. This value must not be `nil`.
+ *  @param highlightedImage The highlighted message bubble image. This value must not be `nil`.
+ *
+ *  @return An initialized `JSQMessagesBubbleImage` object if successful, `nil` otherwise.
+ *
+ *  @see JSQMessagesBubbleImageFactory.
+ */
+- (instancetype)initWithMessageBubbleImage:(UIImage *)image highlightedImage:(UIImage *)highlightedImage NS_DESIGNATED_INITIALIZER;
+
+/**
+ *  Not a valid initializer.
+ */
+- (id)init NS_UNAVAILABLE;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessagesBubbleImage.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessagesBubbleImage.m
new file mode 100644
index 0000000..047b9c0
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessagesBubbleImage.m
@@ -0,0 +1,59 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQMessagesBubbleImage.h"
+
+@implementation JSQMessagesBubbleImage
+
+#pragma mark - Initialization
+
+- (instancetype)initWithMessageBubbleImage:(UIImage *)image highlightedImage:(UIImage *)highlightedImage
+{
+    NSParameterAssert(image != nil);
+    NSParameterAssert(highlightedImage != nil);
+    
+    self = [super init];
+    if (self) {
+        _messageBubbleImage = image;
+        _messageBubbleHighlightedImage = highlightedImage;
+    }
+    return self;
+}
+
+#pragma mark - NSObject
+
+- (NSString *)description
+{
+    return [NSString stringWithFormat:@"<%@: messageBubbleImage=%@, messageBubbleHighlightedImage=%@>",
+            [self class], self.messageBubbleImage, self.messageBubbleHighlightedImage];
+}
+
+- (id)debugQuickLookObject
+{
+    return [[UIImageView alloc] initWithImage:self.messageBubbleImage highlightedImage:self.messageBubbleHighlightedImage];
+}
+
+#pragma mark - NSCopying
+
+- (instancetype)copyWithZone:(NSZone *)zone
+{
+    return [[[self class] allocWithZone:zone] initWithMessageBubbleImage:[UIImage imageWithCGImage:self.messageBubbleImage.CGImage]
+                                                        highlightedImage:[UIImage imageWithCGImage:self.messageBubbleHighlightedImage.CGImage]];
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessagesCollectionViewDataSource.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessagesCollectionViewDataSource.h
new file mode 100644
index 0000000..363f42c
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessagesCollectionViewDataSource.h
@@ -0,0 +1,155 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+@class JSQMessagesCollectionView;
+@protocol JSQMessageData;
+@protocol JSQMessageBubbleImageDataSource;
+@protocol JSQMessageAvatarImageDataSource;
+
+
+/**
+ *  An object that adopts the `JSQMessagesCollectionViewDataSource` protocol is responsible for providing the data and views
+ *  required by a `JSQMessagesCollectionView`. The data source object represents your app’s messaging data model
+ *  and vends information to the collection view as needed.
+ */
+@protocol JSQMessagesCollectionViewDataSource <UICollectionViewDataSource>
+
+@required
+
+/**
+ *  Asks the data source for the current sender's display name, that is, the current user who is sending messages.
+ *
+ *  @return An initialized string describing the current sender to display in a `JSQMessagesCollectionViewCell`.
+ *  
+ *  @warning You must not return `nil` from this method. This value does not need to be unique.
+ */
+- (NSString *)senderDisplayName;
+
+/**
+ *  Asks the data source for the current sender's unique identifier, that is, the current user who is sending messages.
+ *
+ *  @return An initialized string identifier that uniquely identifies the current sender.
+ *
+ *  @warning You must not return `nil` from this method. This value must be unique.
+ */
+- (NSString *)senderId;
+
+/**
+ *  Asks the data source for the message data that corresponds to the specified item at indexPath in the collectionView.
+ *
+ *  @param collectionView The collection view requesting this information.
+ *  @param indexPath      The index path that specifies the location of the item.
+ *
+ *  @return An initialized object that conforms to the `JSQMessageData` protocol. You must not return `nil` from this method.
+ */
+- (id<JSQMessageData>)collectionView:(JSQMessagesCollectionView *)collectionView messageDataForItemAtIndexPath:(NSIndexPath *)indexPath;
+
+/**
+ *  Notifies the data source that the item at indexPath has been deleted. 
+ *  Implementations of this method should remove the item from the data source.
+ *
+ *  @param collectionView The collection view requesting this information.
+ *  @param indexPath      The index path that specifies the location of the item.
+ */
+- (void)collectionView:(JSQMessagesCollectionView *)collectionView didDeleteMessageAtIndexPath:(NSIndexPath *)indexPath;
+
+/**
+ *  Asks the data source for the message bubble image data that corresponds to the specified message data item at indexPath in the collectionView.
+ *
+ *  @param collectionView The collection view requesting this information.
+ *  @param indexPath      The index path that specifies the location of the item.
+ *
+ *  @return An initialized object that conforms to the `JSQMessageBubbleImageDataSource` protocol. You may return `nil` from this method if you do not
+ *  want the specified item to display a message bubble image.
+ *
+ *  @discussion It is recommended that you utilize `JSQMessagesBubbleImageFactory` to return valid `JSQMessagesBubbleImage` objects.
+ *  However, you may provide your own data source object as long as it conforms to the `JSQMessageBubbleImageDataSource` protocol.
+ *  
+ *  @warning Note that providing your own bubble image data source objects may require additional 
+ *  configuration of the collectionView layout object, specifically regarding its `messageBubbleTextViewFrameInsets` and `messageBubbleTextViewTextContainerInsets`.
+ *
+ *  @see JSQMessagesBubbleImageFactory.
+ *  @see JSQMessagesCollectionViewFlowLayout.
+ */
+- (id<JSQMessageBubbleImageDataSource>)collectionView:(JSQMessagesCollectionView *)collectionView messageBubbleImageDataForItemAtIndexPath:(NSIndexPath *)indexPath;
+
+/**
+ *  Asks the data source for the avatar image data that corresponds to the specified message data item at indexPath in the collectionView.
+ *
+ *  @param collectionView The collection view requesting this information.
+ *  @param indexPath      The index path that specifies the location of the item.
+ *
+ *  @return A initialized object that conforms to the `JSQMessageAvatarImageDataSource` protocol. You may return `nil` from this method if you do not want
+ *  the specified item to display an avatar.
+ *
+ *  @discussion It is recommended that you utilize `JSQMessagesAvatarImageFactory` to return valid `JSQMessagesAvatarImage` objects.
+ *  However, you may provide your own data source object as long as it conforms to the `JSQMessageAvatarImageDataSource` protocol.
+ *
+ *  @see JSQMessagesAvatarImageFactory.
+ *  @see JSQMessagesCollectionViewFlowLayout.
+ */
+- (id<JSQMessageAvatarImageDataSource>)collectionView:(JSQMessagesCollectionView *)collectionView avatarImageDataForItemAtIndexPath:(NSIndexPath *)indexPath;
+
+@optional
+
+/**
+ *  Asks the data source for the text to display in the `cellTopLabel` for the specified
+ *  message data item at indexPath in the collectionView.
+ *
+ *  @param collectionView The collection view requesting this information.
+ *  @param indexPath      The index path that specifies the location of the item.
+ *
+ *  @return A configured attributed string or `nil` if you do not want text displayed for the item at indexPath.
+ *  Return an attributed string with `nil` attributes to use the default attributes.
+ *
+ *  @see JSQMessagesCollectionViewCell.
+ */
+- (NSAttributedString *)collectionView:(JSQMessagesCollectionView *)collectionView attributedTextForCellTopLabelAtIndexPath:(NSIndexPath *)indexPath;
+
+/**
+ *  Asks the data source for the text to display in the `messageBubbleTopLabel` for the specified
+ *  message data item at indexPath in the collectionView.
+ *
+ *  @param collectionView The collection view requesting this information.
+ *  @param indexPath      The index path that specifies the location of the item.
+ *
+ *  @return A configured attributed string or `nil` if you do not want text displayed for the item at indexPath.
+ *  Return an attributed string with `nil` attributes to use the default attributes.
+ *
+ *  @see JSQMessagesCollectionViewCell.
+ */
+- (NSAttributedString *)collectionView:(JSQMessagesCollectionView *)collectionView attributedTextForMessageBubbleTopLabelAtIndexPath:(NSIndexPath *)indexPath;
+
+/**
+ *  Asks the data source for the text to display in the `cellBottomLabel` for the the specified
+ *  message data item at indexPath in the collectionView.
+ *
+ *  @param collectionView The collection view requesting this information.
+ *  @param indexPath      The index path that specifies the location of the item.
+ *
+ *  @return A configured attributed string or `nil` if you do not want text displayed for the item at indexPath.
+ *  Return an attributed string with `nil` attributes to use the default attributes.
+ *
+ *  @see JSQMessagesCollectionViewCell.
+ */
+- (NSAttributedString *)collectionView:(JSQMessagesCollectionView *)collectionView attributedTextForCellBottomLabelAtIndexPath:(NSIndexPath *)indexPath;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessagesCollectionViewDelegateFlowLayout.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessagesCollectionViewDelegateFlowLayout.h
new file mode 100644
index 0000000..6e9217a
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQMessagesCollectionViewDelegateFlowLayout.h
@@ -0,0 +1,122 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+@class JSQMessagesCollectionView;
+@class JSQMessagesCollectionViewFlowLayout;
+@class JSQMessagesCollectionViewCell;
+@class JSQMessagesLoadEarlierHeaderView;
+
+
+/**
+*  The `JSQMessagesCollectionViewDelegateFlowLayout` protocol defines methods that allow you to
+*  manage additional layout information for the collection view and respond to additional actions on its items.
+*  The methods of this protocol are all optional.
+*/
+@protocol JSQMessagesCollectionViewDelegateFlowLayout <UICollectionViewDelegateFlowLayout>
+
+@optional
+
+/**
+ *  Asks the delegate for the height of the `cellTopLabel` for the item at the specified indexPath.
+ *
+ *  @param collectionView       The collection view object displaying the flow layout.
+ *  @param collectionViewLayout The layout object requesting the information.
+ *  @param indexPath            The index path of the item.
+ *
+ *  @return The height of the `cellTopLabel` for the item at indexPath.
+ *
+ *  @see JSQMessagesCollectionViewCell.
+ */
+- (CGFloat)collectionView:(JSQMessagesCollectionView *)collectionView
+                   layout:(JSQMessagesCollectionViewFlowLayout *)collectionViewLayout heightForCellTopLabelAtIndexPath:(NSIndexPath *)indexPath;
+
+/**
+ *  Asks the delegate for the height of the `messageBubbleTopLabel` for the item at the specified indexPath.
+ *
+ *  @param collectionView       The collection view object displaying the flow layout.
+ *  @param collectionViewLayout The layout object requesting the information.
+ *  @param indexPath            The index path of the item.
+ *
+ *  @return The height of the `messageBubbleTopLabel` for the item at indexPath.
+ *
+ *  @see JSQMessagesCollectionViewCell.
+ */
+- (CGFloat)collectionView:(JSQMessagesCollectionView *)collectionView
+                   layout:(JSQMessagesCollectionViewFlowLayout *)collectionViewLayout heightForMessageBubbleTopLabelAtIndexPath:(NSIndexPath *)indexPath;
+
+/**
+ *  Asks the delegate for the height of the `cellBottomLabel` for the item at the specified indexPath.
+ *
+ *  @param collectionView       The collection view object displaying the flow layout.
+ *  @param collectionViewLayout The layout object requesting the information.
+ *  @param indexPath            The index path of the item.
+ *
+ *  @return The height of the `cellBottomLabel` for the item at indexPath.
+ *
+ *  @see JSQMessagesCollectionViewCell.
+ */
+- (CGFloat)collectionView:(JSQMessagesCollectionView *)collectionView
+                   layout:(JSQMessagesCollectionViewFlowLayout *)collectionViewLayout heightForCellBottomLabelAtIndexPath:(NSIndexPath *)indexPath;
+
+/**
+ *  Notifies the delegate that the avatar image view at the specified indexPath did receive a tap event.
+ *
+ *  @param collectionView  The collection view object that is notifying the delegate of the tap event.
+ *  @param avatarImageView The avatar image view that was tapped.
+ *  @param indexPath       The index path of the item for which the avatar was tapped.
+ */
+- (void)collectionView:(JSQMessagesCollectionView *)collectionView didTapAvatarImageView:(UIImageView *)avatarImageView atIndexPath:(NSIndexPath *)indexPath;
+
+/**
+ *  Notifies the delegate that the message bubble at the specified indexPath did receive a tap event.
+ *
+ *  @param collectionView The collection view object that is notifying the delegate of the tap event.
+ *  @param indexPath      The index path of the item for which the message bubble was tapped.
+ */
+- (void)collectionView:(JSQMessagesCollectionView *)collectionView didTapMessageBubbleAtIndexPath:(NSIndexPath *)indexPath;
+
+/**
+ *  Notifies the delegate that the cell at the specified indexPath did receive a tap event at the specified touchLocation.
+ *
+ *  @param collectionView The collection view object that is notifying the delegate of the tap event.
+ *  @param indexPath      The index path of the item for which the message bubble was tapped.
+ *  @param touchLocation  The location of the touch event in the cell's coordinate system.
+ *
+ *  @warning This method is *only* called if position is *not* within the bounds of the cell's
+ *  avatar image view or message bubble image view. In other words, this method is *not* called when the cell's
+ *  avatar or message bubble are tapped. There are separate delegate methods for these two cases.
+ *
+ *  @see `collectionView:didTapAvatarImageView:atIndexPath:`
+ *  @see `collectionView:didTapMessageBubbleAtIndexPath:atIndexPath:`
+ */
+- (void)collectionView:(JSQMessagesCollectionView *)collectionView didTapCellAtIndexPath:(NSIndexPath *)indexPath touchLocation:(CGPoint)touchLocation;
+
+/**
+ *  Notifies the delegate that the collection view's header did receive a tap event.
+ *
+ *  @param collectionView The collection view object that is notifying the delegate of the tap event.
+ *  @param headerView     The header view in the collection view.
+ *  @param sender         The button that was tapped.
+ */
+- (void)collectionView:(JSQMessagesCollectionView *)collectionView
+                header:(JSQMessagesLoadEarlierHeaderView *)headerView didTapLoadEarlierMessagesButton:(UIButton *)sender;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQPhotoMediaItem.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQPhotoMediaItem.h
new file mode 100644
index 0000000..e0f112d
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQPhotoMediaItem.h
@@ -0,0 +1,47 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQMediaItem.h"
+
+/**
+ *  The `JSQPhotoMediaItem` class is a concrete `JSQMediaItem` subclass that implements the `JSQMessageMediaData` protocol
+ *  and represents a photo media message. An initialized `JSQPhotoMediaItem` object can be passed 
+ *  to a `JSQMediaMessage` object during its initialization to construct a valid media message object.
+ *  You may wish to subclass `JSQPhotoMediaItem` to provide additional functionality or behavior.
+ */
+@interface JSQPhotoMediaItem : JSQMediaItem <JSQMessageMediaData, NSCoding, NSCopying>
+
+/**
+ *  The image for the photo media item. The default value is `nil`.
+ */
+@property (copy, nonatomic) UIImage *image;
+
+/**
+ *  Initializes and returns a photo media item object having the given image.
+ *
+ *  @param image The image for the photo media item. This value may be `nil`.
+ *
+ *  @return An initialized `JSQPhotoMediaItem` if successful, `nil` otherwise.
+ *
+ *  @discussion If the image must be dowloaded from the network, 
+ *  you may initialize a `JSQPhotoMediaItem` object with a `nil` image. 
+ *  Once the image has been retrieved, you can then set the image property.
+ */
+- (instancetype)initWithImage:(UIImage *)image;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQPhotoMediaItem.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQPhotoMediaItem.m
new file mode 100644
index 0000000..1752fd1
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQPhotoMediaItem.m
@@ -0,0 +1,131 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQPhotoMediaItem.h"
+
+#import "JSQMessagesMediaPlaceholderView.h"
+#import "JSQMessagesMediaViewBubbleImageMasker.h"
+
+
+@interface JSQPhotoMediaItem ()
+
+@property (strong, nonatomic) UIImageView *cachedImageView;
+
+@end
+
+
+@implementation JSQPhotoMediaItem
+
+#pragma mark - Initialization
+
+- (instancetype)initWithImage:(UIImage *)image
+{
+    self = [super init];
+    if (self) {
+        _image = [image copy];
+        _cachedImageView = nil;
+    }
+    return self;
+}
+
+- (void)clearCachedMediaViews
+{
+    [super clearCachedMediaViews];
+    _cachedImageView = nil;
+}
+
+#pragma mark - Setters
+
+- (void)setImage:(UIImage *)image
+{
+    _image = [image copy];
+    _cachedImageView = nil;
+}
+
+- (void)setAppliesMediaViewMaskAsOutgoing:(BOOL)appliesMediaViewMaskAsOutgoing
+{
+    [super setAppliesMediaViewMaskAsOutgoing:appliesMediaViewMaskAsOutgoing];
+    _cachedImageView = nil;
+}
+
+#pragma mark - JSQMessageMediaData protocol
+
+- (UIView *)mediaView
+{
+    if (self.image == nil) {
+        return nil;
+    }
+    
+    if (self.cachedImageView == nil) {
+        CGSize size = [self mediaViewDisplaySize];
+        UIImageView *imageView = [[UIImageView alloc] initWithImage:self.image];
+        imageView.frame = CGRectMake(0.0f, 0.0f, size.width, size.height);
+        imageView.contentMode = UIViewContentModeScaleAspectFill;
+        imageView.clipsToBounds = YES;
+        [JSQMessagesMediaViewBubbleImageMasker applyBubbleImageMaskToMediaView:imageView isOutgoing:self.appliesMediaViewMaskAsOutgoing];
+        self.cachedImageView = imageView;
+    }
+    
+    return self.cachedImageView;
+}
+
+- (NSUInteger)mediaHash
+{
+    return self.hash;
+}
+
+#pragma mark - NSObject
+
+- (NSUInteger)hash
+{
+    return super.hash ^ self.image.hash;
+}
+
+- (NSString *)description
+{
+    return [NSString stringWithFormat:@"<%@: image=%@, appliesMediaViewMaskAsOutgoing=%@>",
+            [self class], self.image, @(self.appliesMediaViewMaskAsOutgoing)];
+}
+
+#pragma mark - NSCoding
+
+- (instancetype)initWithCoder:(NSCoder *)aDecoder
+{
+    self = [super initWithCoder:aDecoder];
+    if (self) {
+        _image = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(image))];
+    }
+    return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)aCoder
+{
+    [super encodeWithCoder:aCoder];
+    [aCoder encodeObject:self.image forKey:NSStringFromSelector(@selector(image))];
+}
+
+#pragma mark - NSCopying
+
+- (instancetype)copyWithZone:(NSZone *)zone
+{
+    JSQPhotoMediaItem *copy = [[JSQPhotoMediaItem allocWithZone:zone] initWithImage:self.image];
+    copy.appliesMediaViewMaskAsOutgoing = self.appliesMediaViewMaskAsOutgoing;
+    return copy;
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQVideoMediaItem.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQVideoMediaItem.h
new file mode 100644
index 0000000..362f41e
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQVideoMediaItem.h
@@ -0,0 +1,56 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQMediaItem.h"
+
+/**
+ *  The `JSQVideoMediaItem` class is a concrete `JSQMediaItem` subclass that implements the `JSQMessageMediaData` protocol
+ *  and represents a video media message. An initialized `JSQVideoMediaItem` object can be passed
+ *  to a `JSQMediaMessage` object during its initialization to construct a valid media message object.
+ *  You may wish to subclass `JSQVideoMediaItem` to provide additional functionality or behavior.
+ */
+@interface JSQVideoMediaItem : JSQMediaItem <JSQMessageMediaData, NSCoding, NSCopying>
+
+/**
+ *  The URL that identifies a video resource.
+ */
+@property (nonatomic, strong) NSURL *fileURL;
+
+/**
+ *  A boolean value that specifies whether or not the video is ready to be played.
+ * 
+ *  @discussion When set to `YES`, the video is ready. When set to `NO` it is not ready.
+ */
+@property (nonatomic, assign) BOOL isReadyToPlay;
+
+/**
+ *  Initializes and returns a video media item having the given fileURL.
+ *
+ *  @param fileURL       The URL that identifies the video resource.
+ *  @param isReadyToPlay A boolean value that specifies if the video is ready to play.
+ *
+ *  @return An initialized `JSQVideoMediaItem` if successful, `nil` otherwise.
+ *
+ *  @discussion If the video must be downloaded from the network,
+ *  you may initialize a `JSQVideoMediaItem` with a `nil` fileURL or specify `NO` for
+ *  isReadyToPlay. Once the video has been saved to disk, or is ready to stream, you can
+ *  set the fileURL property or isReadyToPlay property, respectively.
+ */
+- (instancetype)initWithFileURL:(NSURL *)fileURL isReadyToPlay:(BOOL)isReadyToPlay;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQVideoMediaItem.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQVideoMediaItem.m
new file mode 100644
index 0000000..d499acb
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Model/JSQVideoMediaItem.m
@@ -0,0 +1,158 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQVideoMediaItem.h"
+
+#import "JSQMessagesMediaPlaceholderView.h"
+#import "JSQMessagesMediaViewBubbleImageMasker.h"
+
+#import "UIImage+JSQMessages.h"
+
+
+@interface JSQVideoMediaItem ()
+
+@property (strong, nonatomic) UIImageView *cachedVideoImageView;
+
+@end
+
+
+@implementation JSQVideoMediaItem
+
+#pragma mark - Initialization
+
+- (instancetype)initWithFileURL:(NSURL *)fileURL isReadyToPlay:(BOOL)isReadyToPlay
+{
+    self = [super init];
+    if (self) {
+        _fileURL = [fileURL copy];
+        _isReadyToPlay = isReadyToPlay;
+        _cachedVideoImageView = nil;
+    }
+    return self;
+}
+
+- (void)clearCachedMediaViews
+{
+    [super clearCachedMediaViews];
+    _cachedVideoImageView = nil;
+}
+
+#pragma mark - Setters
+
+- (void)setFileURL:(NSURL *)fileURL
+{
+    _fileURL = [fileURL copy];
+    _cachedVideoImageView = nil;
+}
+
+- (void)setIsReadyToPlay:(BOOL)isReadyToPlay
+{
+    _isReadyToPlay = isReadyToPlay;
+    _cachedVideoImageView = nil;
+}
+
+- (void)setAppliesMediaViewMaskAsOutgoing:(BOOL)appliesMediaViewMaskAsOutgoing
+{
+    [super setAppliesMediaViewMaskAsOutgoing:appliesMediaViewMaskAsOutgoing];
+    _cachedVideoImageView = nil;
+}
+
+#pragma mark - JSQMessageMediaData protocol
+
+- (UIView *)mediaView
+{
+    if (self.fileURL == nil || !self.isReadyToPlay) {
+        return nil;
+    }
+    
+    if (self.cachedVideoImageView == nil) {
+        CGSize size = [self mediaViewDisplaySize];
+        UIImage *playIcon = [[UIImage jsq_defaultPlayImage] jsq_imageMaskedWithColor:[UIColor lightGrayColor]];
+        
+        UIImageView *imageView = [[UIImageView alloc] initWithImage:playIcon];
+        imageView.backgroundColor = [UIColor blackColor];
+        imageView.frame = CGRectMake(0.0f, 0.0f, size.width, size.height);
+        imageView.contentMode = UIViewContentModeCenter;
+        imageView.clipsToBounds = YES;
+        [JSQMessagesMediaViewBubbleImageMasker applyBubbleImageMaskToMediaView:imageView isOutgoing:self.appliesMediaViewMaskAsOutgoing];
+        self.cachedVideoImageView = imageView;
+    }
+    
+    return self.cachedVideoImageView;
+}
+
+- (NSUInteger)mediaHash
+{
+    return self.hash;
+}
+
+#pragma mark - NSObject
+
+- (BOOL)isEqual:(id)object
+{
+    if (![super isEqual:object]) {
+        return NO;
+    }
+    
+    JSQVideoMediaItem *videoItem = (JSQVideoMediaItem *)object;
+    
+    return [self.fileURL isEqual:videoItem.fileURL]
+            && self.isReadyToPlay == videoItem.isReadyToPlay;
+}
+
+- (NSUInteger)hash
+{
+    return super.hash ^ self.fileURL.hash;
+}
+
+- (NSString *)description
+{
+    return [NSString stringWithFormat:@"<%@: fileURL=%@, isReadyToPlay=%@, appliesMediaViewMaskAsOutgoing=%@>",
+            [self class], self.fileURL, @(self.isReadyToPlay), @(self.appliesMediaViewMaskAsOutgoing)];
+}
+
+#pragma mark - NSCoding
+
+- (instancetype)initWithCoder:(NSCoder *)aDecoder
+{
+    self = [super initWithCoder:aDecoder];
+    if (self) {
+        _fileURL = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(fileURL))];
+        _isReadyToPlay = [aDecoder decodeBoolForKey:NSStringFromSelector(@selector(isReadyToPlay))];
+    }
+    return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)aCoder
+{
+    [super encodeWithCoder:aCoder];
+    [aCoder encodeObject:self.fileURL forKey:NSStringFromSelector(@selector(fileURL))];
+    [aCoder encodeBool:self.isReadyToPlay forKey:NSStringFromSelector(@selector(isReadyToPlay))];
+}
+
+#pragma mark - NSCopying
+
+- (instancetype)copyWithZone:(NSZone *)zone
+{
+    JSQVideoMediaItem *copy = [[[self class] allocWithZone:zone] initWithFileURL:self.fileURL
+                                                                   isReadyToPlay:self.isReadyToPlay];
+    copy.appliesMediaViewMaskAsOutgoing = self.appliesMediaViewMaskAsOutgoing;
+    return copy;
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCellTextView.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCellTextView.h
new file mode 100644
index 0000000..43f1c6e
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCellTextView.h
@@ -0,0 +1,27 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <UIKit/UIKit.h>
+
+/**
+ *  `JSQMessagesCellTextView` is a subclass of `UITextView` that is used to display text
+ *  in a `JSQMessagesCollectionViewCell`.
+ */
+@interface JSQMessagesCellTextView : UITextView
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCellTextView.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCellTextView.m
new file mode 100644
index 0000000..ff8a5ec
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCellTextView.m
@@ -0,0 +1,83 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQMessagesCellTextView.h"
+
+@implementation JSQMessagesCellTextView
+
+- (void)awakeFromNib
+{
+    [super awakeFromNib];
+    
+    self.textColor = [UIColor whiteColor];
+    self.editable = NO;
+    self.selectable = YES;
+    self.userInteractionEnabled = YES;
+    self.dataDetectorTypes = UIDataDetectorTypeNone;
+    self.showsHorizontalScrollIndicator = NO;
+    self.showsVerticalScrollIndicator = NO;
+    self.scrollEnabled = NO;
+    self.backgroundColor = [UIColor clearColor];
+    self.contentInset = UIEdgeInsetsZero;
+    self.scrollIndicatorInsets = UIEdgeInsetsZero;
+    self.contentOffset = CGPointZero;
+    self.textContainerInset = UIEdgeInsetsZero;
+    self.textContainer.lineFragmentPadding = 0;
+    self.linkTextAttributes = @{ NSForegroundColorAttributeName : [UIColor whiteColor],
+                                 NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle | NSUnderlinePatternSolid) };
+}
+
+- (void)setSelectedRange:(NSRange)selectedRange
+{
+    //  attempt to prevent selecting text
+    [super setSelectedRange:NSMakeRange(NSNotFound, 0)];
+}
+
+- (NSRange)selectedRange
+{
+    //  attempt to prevent selecting text
+    return NSMakeRange(NSNotFound, NSNotFound);
+}
+
+- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
+{
+    //  ignore double-tap to prevent copy/define/etc. menu from showing
+    if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) {
+        UITapGestureRecognizer *tap = (UITapGestureRecognizer *)gestureRecognizer;
+        if (tap.numberOfTapsRequired == 2) {
+            return NO;
+        }
+    }
+    
+    return YES;
+}
+
+- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
+{
+    //  ignore double-tap to prevent copy/define/etc. menu from showing
+    if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) {
+        UITapGestureRecognizer *tap = (UITapGestureRecognizer *)gestureRecognizer;
+        if (tap.numberOfTapsRequired == 2) {
+            return NO;
+        }
+    }
+    
+    return YES;
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCollectionView.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCollectionView.h
new file mode 100644
index 0000000..918151e
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCollectionView.h
@@ -0,0 +1,101 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <UIKit/UIKit.h>
+
+#import "JSQMessagesCollectionViewFlowLayout.h"
+#import "JSQMessagesCollectionViewDelegateFlowLayout.h"
+#import "JSQMessagesCollectionViewDataSource.h"
+#import "JSQMessagesCollectionViewCell.h"
+
+@class JSQMessagesTypingIndicatorFooterView;
+@class JSQMessagesLoadEarlierHeaderView;
+
+
+/**
+ *  The `JSQMessagesCollectionView` class manages an ordered collection of message data items and presents
+ *  them using a specialized layout for messages.
+ */
+@interface JSQMessagesCollectionView : UICollectionView <JSQMessagesCollectionViewCellDelegate>
+
+/**
+ *  The object that provides the data for the collection view.
+ *  The data source must adopt the `JSQMessagesCollectionViewDataSource` protocol.
+ */
+@property (weak, nonatomic) id<JSQMessagesCollectionViewDataSource> dataSource;
+
+/**
+ *  The object that acts as the delegate of the collection view. 
+ *  The delegate must adopt the `JSQMessagesCollectionViewDelegateFlowLayout` protocol.
+ */
+@property (weak, nonatomic) id<JSQMessagesCollectionViewDelegateFlowLayout> delegate;
+
+/**
+ *  The layout used to organize the collection view’s items.
+ */
+@property (strong, nonatomic) JSQMessagesCollectionViewFlowLayout *collectionViewLayout;
+
+/**
+ *  Specifies whether the typing indicator displays on the left or right side of the collection view
+ *  when shown. That is, whether it displays for an "incoming" or "outgoing" message.
+ *  The default value is `YES`, meaning that the typing indicator will display on the left side of the
+ *  collection view for incoming messages.
+ *
+ *  @discussion If your `JSQMessagesViewController` subclass displays messages for right-to-left
+ *  languages, such as Arabic, set this property to `NO`.
+ *
+ */
+@property (assign, nonatomic) BOOL typingIndicatorDisplaysOnLeft;
+
+/**
+ *  The color of the typing indicator message bubble. The default value is a light gray color.
+ */
+@property (strong, nonatomic) UIColor *typingIndicatorMessageBubbleColor;
+
+/**
+ *  The color of the typing indicator ellipsis. The default value is a dark gray color.
+ */
+@property (strong, nonatomic) UIColor *typingIndicatorEllipsisColor;
+
+/**
+ *  The color of the text in the load earlier messages header. The default value is a bright blue color.
+ */
+@property (strong, nonatomic) UIColor *loadEarlierMessagesHeaderTextColor;
+
+/**
+ *  Returns a `JSQMessagesTypingIndicatorFooterView` object for the specified index path
+ *  that is configured using the collection view's properties:
+ *  typingIndicatorDisplaysOnLeft, typingIndicatorMessageBubbleColor, typingIndicatorEllipsisColor.
+ *
+ *  @param indexPath The index path specifying the location of the supplementary view in the collection view. This value must not be `nil`.
+ *
+ *  @return A valid `JSQMessagesTypingIndicatorFooterView` object.
+ */
+- (JSQMessagesTypingIndicatorFooterView *)dequeueTypingIndicatorFooterViewForIndexPath:(NSIndexPath *)indexPath;
+
+/**
+ *  Returns a `JSQMessagesLoadEarlierHeaderView` object for the specified index path
+ *  that is configured using the collection view's loadEarlierMessagesHeaderTextColor property.
+ *
+ *  @param indexPath The index path specifying the location of the supplementary view in the collection view. This value must not be `nil`.
+ *
+ *  @return A valid `JSQMessagesLoadEarlierHeaderView` object.
+ */
+- (JSQMessagesLoadEarlierHeaderView *)dequeueLoadEarlierMessagesViewHeaderForIndexPath:(NSIndexPath *)indexPath;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCollectionView.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCollectionView.m
new file mode 100644
index 0000000..527d268
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCollectionView.m
@@ -0,0 +1,185 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQMessagesCollectionView.h"
+
+#import "JSQMessagesCollectionViewFlowLayout.h"
+#import "JSQMessagesCollectionViewCellIncoming.h"
+#import "JSQMessagesCollectionViewCellOutgoing.h"
+
+#import "JSQMessagesTypingIndicatorFooterView.h"
+#import "JSQMessagesLoadEarlierHeaderView.h"
+
+#import "UIColor+JSQMessages.h"
+
+
+@interface JSQMessagesCollectionView () <JSQMessagesLoadEarlierHeaderViewDelegate>
+
+- (void)jsq_configureCollectionView;
+
+@end
+
+
+@implementation JSQMessagesCollectionView
+
+@dynamic dataSource;
+@dynamic delegate;
+@dynamic collectionViewLayout;
+
+#pragma mark - Initialization
+
+- (void)jsq_configureCollectionView
+{
+    [self setTranslatesAutoresizingMaskIntoConstraints:NO];
+
+    self.backgroundColor = [UIColor whiteColor];
+    self.keyboardDismissMode = UIScrollViewKeyboardDismissModeNone;
+    self.alwaysBounceVertical = YES;
+    self.bounces = YES;
+    
+    [self registerNib:[JSQMessagesCollectionViewCellIncoming nib]
+          forCellWithReuseIdentifier:[JSQMessagesCollectionViewCellIncoming cellReuseIdentifier]];
+    
+    [self registerNib:[JSQMessagesCollectionViewCellOutgoing nib]
+          forCellWithReuseIdentifier:[JSQMessagesCollectionViewCellOutgoing cellReuseIdentifier]];
+    
+    [self registerNib:[JSQMessagesCollectionViewCellIncoming nib]
+          forCellWithReuseIdentifier:[JSQMessagesCollectionViewCellIncoming mediaCellReuseIdentifier]];
+    
+    [self registerNib:[JSQMessagesCollectionViewCellOutgoing nib]
+          forCellWithReuseIdentifier:[JSQMessagesCollectionViewCellOutgoing mediaCellReuseIdentifier]];
+    
+    [self registerNib:[JSQMessagesTypingIndicatorFooterView nib]
+          forSupplementaryViewOfKind:UICollectionElementKindSectionFooter
+          withReuseIdentifier:[JSQMessagesTypingIndicatorFooterView footerReuseIdentifier]];
+    
+    [self registerNib:[JSQMessagesLoadEarlierHeaderView nib]
+          forSupplementaryViewOfKind:UICollectionElementKindSectionHeader
+          withReuseIdentifier:[JSQMessagesLoadEarlierHeaderView headerReuseIdentifier]];
+
+    _typingIndicatorDisplaysOnLeft = YES;
+    _typingIndicatorMessageBubbleColor = [UIColor jsq_messageBubbleLightGrayColor];
+    _typingIndicatorEllipsisColor = [_typingIndicatorMessageBubbleColor jsq_colorByDarkeningColorWithValue:0.3f];
+
+    _loadEarlierMessagesHeaderTextColor = [UIColor jsq_messageBubbleBlueColor];
+}
+
+- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout
+{
+    self = [super initWithFrame:frame collectionViewLayout:layout];
+    if (self) {
+        [self jsq_configureCollectionView];
+    }
+    return self;
+}
+
+- (void)awakeFromNib
+{
+    [super awakeFromNib];
+    [self jsq_configureCollectionView];
+}
+
+#pragma mark - Typing indicator
+
+- (JSQMessagesTypingIndicatorFooterView *)dequeueTypingIndicatorFooterViewForIndexPath:(NSIndexPath *)indexPath
+{
+    JSQMessagesTypingIndicatorFooterView *footerView = [super dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter
+                                                                                 withReuseIdentifier:[JSQMessagesTypingIndicatorFooterView footerReuseIdentifier]
+                                                                                        forIndexPath:indexPath];
+
+    [footerView configureWithEllipsisColor:self.typingIndicatorEllipsisColor
+                        messageBubbleColor:self.typingIndicatorMessageBubbleColor
+                       shouldDisplayOnLeft:self.typingIndicatorDisplaysOnLeft
+                         forCollectionView:self];
+
+    return footerView;
+}
+
+#pragma mark - Load earlier messages header
+
+- (JSQMessagesLoadEarlierHeaderView *)dequeueLoadEarlierMessagesViewHeaderForIndexPath:(NSIndexPath *)indexPath
+{
+    JSQMessagesLoadEarlierHeaderView *headerView = [super dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader
+                                                                             withReuseIdentifier:[JSQMessagesLoadEarlierHeaderView headerReuseIdentifier]
+                                                                                    forIndexPath:indexPath];
+
+    headerView.loadButton.tintColor = self.loadEarlierMessagesHeaderTextColor;
+    headerView.delegate = self;
+
+    return headerView;
+}
+
+#pragma mark - Load earlier messages header delegate
+
+- (void)headerView:(JSQMessagesLoadEarlierHeaderView *)headerView didPressLoadButton:(UIButton *)sender
+{
+    if ([self.delegate respondsToSelector:@selector(collectionView:header:didTapLoadEarlierMessagesButton:)]) {
+        [self.delegate collectionView:self header:headerView didTapLoadEarlierMessagesButton:sender];
+    }
+}
+
+#pragma mark - Messages collection view cell delegate
+
+- (void)messagesCollectionViewCellDidTapAvatar:(JSQMessagesCollectionViewCell *)cell
+{
+    NSIndexPath *indexPath = [self indexPathForCell:cell];
+    if (indexPath == nil) {
+        return;
+    }
+
+    [self.delegate collectionView:self
+            didTapAvatarImageView:cell.avatarImageView
+                      atIndexPath:indexPath];
+}
+
+- (void)messagesCollectionViewCellDidTapMessageBubble:(JSQMessagesCollectionViewCell *)cell
+{
+    NSIndexPath *indexPath = [self indexPathForCell:cell];
+    if (indexPath == nil) {
+        return;
+    }
+
+    [self.delegate collectionView:self didTapMessageBubbleAtIndexPath:indexPath];
+}
+
+- (void)messagesCollectionViewCellDidTapCell:(JSQMessagesCollectionViewCell *)cell atPosition:(CGPoint)position
+{
+    NSIndexPath *indexPath = [self indexPathForCell:cell];
+    if (indexPath == nil) {
+        return;
+    }
+
+    [self.delegate collectionView:self
+            didTapCellAtIndexPath:indexPath
+                    touchLocation:position];
+}
+
+- (void)messagesCollectionViewCell:(JSQMessagesCollectionViewCell *)cell didPerformAction:(SEL)action withSender:(id)sender
+{
+    NSIndexPath *indexPath = [self indexPathForCell:cell];
+    if (indexPath == nil) {
+        return;
+    }
+
+    [self.delegate collectionView:self
+                    performAction:action
+               forItemAtIndexPath:indexPath
+                       withSender:sender];
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCollectionViewCell.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCollectionViewCell.h
new file mode 100644
index 0000000..c1124cb
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCollectionViewCell.h
@@ -0,0 +1,206 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <UIKit/UIKit.h>
+
+#import "JSQMessagesLabel.h"
+#import "JSQMessagesCellTextView.h"
+
+@class JSQMessagesCollectionViewCell;
+
+/**
+ *  The `JSQMessagesCollectionViewCellDelegate` protocol defines methods that allow you to manage
+ *  additional interactions within the collection view cell.
+ */
+@protocol JSQMessagesCollectionViewCellDelegate <NSObject>
+
+@required
+
+/**
+ *  Tells the delegate that the avatarImageView of the cell has been tapped.
+ *
+ *  @param cell The cell that received the tap touch event.
+ */
+- (void)messagesCollectionViewCellDidTapAvatar:(JSQMessagesCollectionViewCell *)cell;
+
+/**
+ *  Tells the delegate that the message bubble of the cell has been tapped.
+ *
+ *  @param cell The cell that received the tap touch event.
+ */
+- (void)messagesCollectionViewCellDidTapMessageBubble:(JSQMessagesCollectionViewCell *)cell;
+
+/**
+ *  Tells the delegate that the cell has been tapped at the point specified by position.
+ *
+ *  @param cell The cell that received the tap touch event.
+ *  @param position The location of the received touch in the cell's coordinate system.
+ *
+ *  @discussion This method is *only* called if position is *not* within the bounds of the cell's
+ *  avatar image view or message bubble image view. In other words, this method is *not* called when the cell's
+ *  avatar or message bubble are tapped.
+ *
+ *  @see `messagesCollectionViewCellDidTapAvatar:`
+ *  @see `messagesCollectionViewCellDidTapMessageBubble:`
+ */
+- (void)messagesCollectionViewCellDidTapCell:(JSQMessagesCollectionViewCell *)cell atPosition:(CGPoint)position;
+
+/**
+ *  Tells the delegate that an actions has been selected from the menu of this cell.
+ *  This method is automatically called for any registered actions.
+ *
+ *  @param cell The cell that displayed the menu.
+ *  @param action The action that has been performed.
+ *  @param sender The object that initiated the action.
+ *
+ *  @see `JSQMessagesCollectionViewCell`
+ */
+- (void)messagesCollectionViewCell:(JSQMessagesCollectionViewCell *)cell didPerformAction:(SEL)action withSender:(id)sender;
+
+@end
+
+
+/**
+ *  The `JSQMessagesCollectionViewCell` is an abstract base class that presents the content for
+ *  a single message data item when that item is within the collection view’s visible bounds.
+ *  The layout and presentation of cells is managed by the collection view and its corresponding layout object.
+ *
+ *  @warning This class is intended to be subclassed. You should not use it directly.
+ *
+ *  @see JSQMessagesCollectionViewCellIncoming.
+ *  @see JSQMessagesCollectionViewCellOutgoing.
+ */
+@interface JSQMessagesCollectionViewCell : UICollectionViewCell
+
+/**
+ *  The object that acts as the delegate for the cell.
+ */
+@property (weak, nonatomic) id<JSQMessagesCollectionViewCellDelegate> delegate;
+
+/**
+ *  Returns the label that is pinned to the top of the cell.
+ *  This label is most commonly used to display message timestamps.
+ */
+@property (weak, nonatomic, readonly) JSQMessagesLabel *cellTopLabel;
+
+/**
+ *  Returns the label that is pinned just above the messageBubbleImageView, and below the cellTopLabel.
+ *  This label is most commonly used to display the message sender.
+ */
+@property (weak, nonatomic, readonly) JSQMessagesLabel *messageBubbleTopLabel;
+
+/**
+ *  Returns the label that is pinned to the bottom of the cell.
+ *  This label is most commonly used to display message delivery status.
+ */
+@property (weak, nonatomic, readonly) JSQMessagesLabel *cellBottomLabel;
+
+/**
+ *  Returns the text view of the cell. This text view contains the message body text.
+ *
+ *  @warning If mediaView returns a non-nil view, then this value will be `nil`.
+ */
+@property (weak, nonatomic, readonly) JSQMessagesCellTextView *textView;
+
+/**
+ *  Returns the bubble image view of the cell that is responsible for displaying message bubble images.
+ *
+ *  @warning If mediaView returns a non-nil view, then this value will be `nil`.
+ */
+@property (weak, nonatomic, readonly) UIImageView *messageBubbleImageView;
+
+/**
+ *  Returns the message bubble container view of the cell. This view is the superview of
+ *  the cell's textView and messageBubbleImageView.
+ *
+ *  @discussion You may customize the cell by adding custom views to this container view.
+ *  To do so, override `collectionView:cellForItemAtIndexPath:`
+ *
+ *  @warning You should not try to manipulate any properties of this view, for example adjusting
+ *  its frame, nor should you remove this view from the cell or remove any of its subviews.
+ *  Doing so could result in unexpected behavior.
+ */
+@property (weak, nonatomic, readonly) UIView *messageBubbleContainerView;
+
+/**
+ *  Returns the avatar image view of the cell that is responsible for displaying avatar images.
+ */
+@property (weak, nonatomic, readonly) UIImageView *avatarImageView;
+
+/**
+ *  Returns the avatar container view of the cell. This view is the superview of the cell's avatarImageView.
+ *
+ *  @discussion You may customize the cell by adding custom views to this container view.
+ *  To do so, override `collectionView:cellForItemAtIndexPath:`
+ *
+ *  @warning You should not try to manipulate any properties of this view, for example adjusting
+ *  its frame, nor should you remove this view from the cell or remove any of its subviews.
+ *  Doing so could result in unexpected behavior.
+ */
+@property (weak, nonatomic, readonly) UIView *avatarContainerView;
+
+/**
+ *  The media view of the cell. This view displays the contents of a media message.
+ *
+ *  @warning If this value is non-nil, then textView and messageBubbleImageView will both be `nil`.
+ */
+@property (weak, nonatomic) UIView *mediaView;
+
+/**
+ *  Returns the underlying gesture recognizer for tap gestures in the avatarImageView of the cell.
+ *  This gesture handles the tap event for the avatarImageView and notifies the cell's delegate.
+ */
+@property (weak, nonatomic, readonly) UITapGestureRecognizer *tapGestureRecognizer;
+
+#pragma mark - Class methods
+
+/**
+ *  Returns the `UINib` object initialized for the cell.
+ *
+ *  @return The initialized `UINib` object or `nil` if there were errors during
+ *  initialization or the nib file could not be located.
+ */
++ (UINib *)nib;
+
+/**
+ *  Returns the default string used to identify a reusable cell for text message items.
+ *
+ *  @return The string used to identify a reusable cell.
+ */
++ (NSString *)cellReuseIdentifier;
+
+/**
+ *  Returns the default string used to identify a reusable cell for media message items.
+ *
+ *  @return The string used to identify a reusable cell.
+ */
++ (NSString *)mediaCellReuseIdentifier;
+
+/**
+ *  Registers an action to be available in the cell's menu.
+ *
+ *  @param action The selector to register with the cell.
+ *
+ *  @discussion Non-standard or non-system actions must be added to the `UIMenuController` manually.
+ *  You can do this by creating a new `UIMenuItem` and adding it via the controller's `menuItems` property.
+ *
+ *  @warning Note that all message cells share the all actions registered here.
+ */
++ (void)registerMenuAction:(SEL)action;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCollectionViewCell.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCollectionViewCell.m
new file mode 100644
index 0000000..f44bac2
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCollectionViewCell.m
@@ -0,0 +1,394 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQMessagesCollectionViewCell.h"
+
+#import "JSQMessagesCollectionViewCellIncoming.h"
+#import "JSQMessagesCollectionViewCellOutgoing.h"
+#import "JSQMessagesCollectionViewLayoutAttributes.h"
+
+#import "UIView+JSQMessages.h"
+#import "UIDevice+JSQMessages.h"
+
+
+static NSMutableSet *jsqMessagesCollectionViewCellActions = nil;
+
+
+@interface JSQMessagesCollectionViewCell ()
+
+@property (weak, nonatomic) IBOutlet JSQMessagesLabel *cellTopLabel;
+@property (weak, nonatomic) IBOutlet JSQMessagesLabel *messageBubbleTopLabel;
+@property (weak, nonatomic) IBOutlet JSQMessagesLabel *cellBottomLabel;
+
+@property (weak, nonatomic) IBOutlet UIView *messageBubbleContainerView;
+@property (weak, nonatomic) IBOutlet UIImageView *messageBubbleImageView;
+@property (weak, nonatomic) IBOutlet JSQMessagesCellTextView *textView;
+
+@property (weak, nonatomic) IBOutlet UIImageView *avatarImageView;
+@property (weak, nonatomic) IBOutlet UIView *avatarContainerView;
+
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *messageBubbleContainerWidthConstraint;
+
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *textViewTopVerticalSpaceConstraint;
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *textViewBottomVerticalSpaceConstraint;
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *textViewAvatarHorizontalSpaceConstraint;
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *textViewMarginHorizontalSpaceConstraint;
+
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *cellTopLabelHeightConstraint;
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *messageBubbleTopLabelHeightConstraint;
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *cellBottomLabelHeightConstraint;
+
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *avatarContainerViewWidthConstraint;
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *avatarContainerViewHeightConstraint;
+
+@property (assign, nonatomic) UIEdgeInsets textViewFrameInsets;
+
+@property (assign, nonatomic) CGSize avatarViewSize;
+
+@property (weak, nonatomic, readwrite) UITapGestureRecognizer *tapGestureRecognizer;
+
+- (void)jsq_handleTapGesture:(UITapGestureRecognizer *)tap;
+
+- (void)jsq_updateConstraint:(NSLayoutConstraint *)constraint withConstant:(CGFloat)constant;
+
+@end
+
+
+@implementation JSQMessagesCollectionViewCell
+
+#pragma mark - Class methods
+
++ (void)initialize
+{
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        jsqMessagesCollectionViewCellActions = [NSMutableSet new];
+    });
+}
+
++ (UINib *)nib
+{
+    return [UINib nibWithNibName:NSStringFromClass([self class]) bundle:[NSBundle bundleForClass:[self class]]];
+}
+
++ (NSString *)cellReuseIdentifier
+{
+    return NSStringFromClass([self class]);
+}
+
++ (NSString *)mediaCellReuseIdentifier
+{
+    return [NSString stringWithFormat:@"%@_JSQMedia", NSStringFromClass([self class])];
+}
+
++ (void)registerMenuAction:(SEL)action
+{
+    [jsqMessagesCollectionViewCellActions addObject:NSStringFromSelector(action)];
+}
+
+#pragma mark - Initialization
+
+- (void)awakeFromNib
+{
+    [super awakeFromNib];
+
+    [self setTranslatesAutoresizingMaskIntoConstraints:NO];
+
+    self.backgroundColor = [UIColor whiteColor];
+
+    self.cellTopLabelHeightConstraint.constant = 0.0f;
+    self.messageBubbleTopLabelHeightConstraint.constant = 0.0f;
+    self.cellBottomLabelHeightConstraint.constant = 0.0f;
+
+    self.avatarViewSize = CGSizeZero;
+
+    self.cellTopLabel.textAlignment = NSTextAlignmentCenter;
+    self.cellTopLabel.font = [UIFont boldSystemFontOfSize:12.0f];
+    self.cellTopLabel.textColor = [UIColor lightGrayColor];
+
+    self.messageBubbleTopLabel.font = [UIFont systemFontOfSize:12.0f];
+    self.messageBubbleTopLabel.textColor = [UIColor lightGrayColor];
+
+    self.cellBottomLabel.font = [UIFont systemFontOfSize:11.0f];
+    self.cellBottomLabel.textColor = [UIColor lightGrayColor];
+
+    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(jsq_handleTapGesture:)];
+    [self addGestureRecognizer:tap];
+    self.tapGestureRecognizer = tap;
+}
+
+- (void)dealloc
+{
+    _delegate = nil;
+
+    _cellTopLabel = nil;
+    _messageBubbleTopLabel = nil;
+    _cellBottomLabel = nil;
+
+    _textView = nil;
+    _messageBubbleImageView = nil;
+    _mediaView = nil;
+
+    _avatarImageView = nil;
+
+    [_tapGestureRecognizer removeTarget:nil action:NULL];
+    _tapGestureRecognizer = nil;
+}
+
+#pragma mark - Collection view cell
+
+- (void)prepareForReuse
+{
+    [super prepareForReuse];
+
+    self.cellTopLabel.text = nil;
+    self.messageBubbleTopLabel.text = nil;
+    self.cellBottomLabel.text = nil;
+
+    self.textView.dataDetectorTypes = UIDataDetectorTypeNone;
+    self.textView.text = nil;
+    self.textView.attributedText = nil;
+
+    self.avatarImageView.image = nil;
+    self.avatarImageView.highlightedImage = nil;
+}
+
+- (UICollectionViewLayoutAttributes *)preferredLayoutAttributesFittingAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes
+{
+    return layoutAttributes;
+}
+
+- (void)applyLayoutAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes
+{
+    [super applyLayoutAttributes:layoutAttributes];
+
+    JSQMessagesCollectionViewLayoutAttributes *customAttributes = (JSQMessagesCollectionViewLayoutAttributes *)layoutAttributes;
+
+    if (self.textView.font != customAttributes.messageBubbleFont) {
+        self.textView.font = customAttributes.messageBubbleFont;
+    }
+
+    if (!UIEdgeInsetsEqualToEdgeInsets(self.textView.textContainerInset, customAttributes.textViewTextContainerInsets)) {
+        self.textView.textContainerInset = customAttributes.textViewTextContainerInsets;
+    }
+
+    self.textViewFrameInsets = customAttributes.textViewFrameInsets;
+
+    [self jsq_updateConstraint:self.messageBubbleContainerWidthConstraint
+                  withConstant:customAttributes.messageBubbleContainerViewWidth];
+
+    [self jsq_updateConstraint:self.cellTopLabelHeightConstraint
+                  withConstant:customAttributes.cellTopLabelHeight];
+
+    [self jsq_updateConstraint:self.messageBubbleTopLabelHeightConstraint
+                  withConstant:customAttributes.messageBubbleTopLabelHeight];
+
+    [self jsq_updateConstraint:self.cellBottomLabelHeightConstraint
+                  withConstant:customAttributes.cellBottomLabelHeight];
+
+    if ([self isKindOfClass:[JSQMessagesCollectionViewCellIncoming class]]) {
+        self.avatarViewSize = customAttributes.incomingAvatarViewSize;
+    }
+    else if ([self isKindOfClass:[JSQMessagesCollectionViewCellOutgoing class]]) {
+        self.avatarViewSize = customAttributes.outgoingAvatarViewSize;
+    }
+}
+
+- (void)setHighlighted:(BOOL)highlighted
+{
+    [super setHighlighted:highlighted];
+    self.avatarImageView.highlighted = highlighted;
+    self.messageBubbleImageView.highlighted = highlighted;
+}
+
+- (void)setSelected:(BOOL)selected
+{
+    [super setSelected:selected];
+    self.avatarImageView.highlighted = selected;
+    self.messageBubbleImageView.highlighted = selected;
+}
+
+//  FIXME: radar 18326340
+//         remove when fixed
+//         hack for Xcode6 / iOS 8 SDK rendering bug that occurs on iOS 7.x
+//         see issue #484
+//         https://github.com/jessesquires/JSQMessagesViewController/issues/484
+//
+- (void)setBounds:(CGRect)bounds
+{
+    [super setBounds:bounds];
+
+    if ([UIDevice jsq_isCurrentDeviceBeforeiOS8]) {
+        self.contentView.frame = bounds;
+    }
+}
+
+#pragma mark - Menu actions
+
+- (BOOL)respondsToSelector:(SEL)aSelector
+{
+    if ([jsqMessagesCollectionViewCellActions containsObject:NSStringFromSelector(aSelector)]) {
+        return YES;
+    }
+
+    return [super respondsToSelector:aSelector];
+}
+
+-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
+}
+
+- (void)forwardInvocation:(NSInvocation *)anInvocation
+{
+    if ([jsqMessagesCollectionViewCellActions containsObject:NSStringFromSelector(anInvocation.selector)]) {
+        __unsafe_unretained id sender;
+        [anInvocation getArgument:&sender atIndex:0];
+        [self.delegate messagesCollectionViewCell:self didPerformAction:anInvocation.selector withSender:sender];
+    }
+    else {
+        [super forwardInvocation:anInvocation];
+    }
+}
+
+- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
+{
+    if ([jsqMessagesCollectionViewCellActions containsObject:NSStringFromSelector(aSelector)]) {
+        return [NSMethodSignature signatureWithObjCTypes:"v@:@"];
+    }
+
+    return [super methodSignatureForSelector:aSelector];
+}
+
+#pragma mark - Setters
+
+- (void)setBackgroundColor:(UIColor *)backgroundColor
+{
+    [super setBackgroundColor:backgroundColor];
+
+    self.cellTopLabel.backgroundColor = backgroundColor;
+    self.messageBubbleTopLabel.backgroundColor = backgroundColor;
+    self.cellBottomLabel.backgroundColor = backgroundColor;
+
+    self.messageBubbleImageView.backgroundColor = backgroundColor;
+    self.avatarImageView.backgroundColor = backgroundColor;
+
+    self.messageBubbleContainerView.backgroundColor = backgroundColor;
+    self.avatarContainerView.backgroundColor = backgroundColor;
+}
+
+- (void)setAvatarViewSize:(CGSize)avatarViewSize
+{
+    if (CGSizeEqualToSize(avatarViewSize, self.avatarViewSize)) {
+        return;
+    }
+
+    [self jsq_updateConstraint:self.avatarContainerViewWidthConstraint withConstant:avatarViewSize.width];
+    [self jsq_updateConstraint:self.avatarContainerViewHeightConstraint withConstant:avatarViewSize.height];
+}
+
+- (void)setTextViewFrameInsets:(UIEdgeInsets)textViewFrameInsets
+{
+    if (UIEdgeInsetsEqualToEdgeInsets(textViewFrameInsets, self.textViewFrameInsets)) {
+        return;
+    }
+
+    [self jsq_updateConstraint:self.textViewTopVerticalSpaceConstraint withConstant:textViewFrameInsets.top];
+    [self jsq_updateConstraint:self.textViewBottomVerticalSpaceConstraint withConstant:textViewFrameInsets.bottom];
+    [self jsq_updateConstraint:self.textViewAvatarHorizontalSpaceConstraint withConstant:textViewFrameInsets.right];
+    [self jsq_updateConstraint:self.textViewMarginHorizontalSpaceConstraint withConstant:textViewFrameInsets.left];
+}
+
+- (void)setMediaView:(UIView *)mediaView
+{
+    [self.messageBubbleImageView removeFromSuperview];
+    [self.textView removeFromSuperview];
+
+    [mediaView setTranslatesAutoresizingMaskIntoConstraints:NO];
+    mediaView.frame = self.messageBubbleContainerView.bounds;
+
+    [self.messageBubbleContainerView addSubview:mediaView];
+    [self.messageBubbleContainerView jsq_pinAllEdgesOfSubview:mediaView];
+    _mediaView = mediaView;
+
+    //  because of cell re-use (and caching media views, if using built-in library media item)
+    //  we may have dequeued a cell with a media view and add this one on top
+    //  thus, remove any additional subviews hidden behind the new media view
+    dispatch_async(dispatch_get_main_queue(), ^{
+        for (NSUInteger i = 0; i < self.messageBubbleContainerView.subviews.count; i++) {
+            if (self.messageBubbleContainerView.subviews[i] != _mediaView) {
+                [self.messageBubbleContainerView.subviews[i] removeFromSuperview];
+            }
+        }
+    });
+}
+
+#pragma mark - Getters
+
+- (CGSize)avatarViewSize
+{
+    return CGSizeMake(self.avatarContainerViewWidthConstraint.constant,
+                      self.avatarContainerViewHeightConstraint.constant);
+}
+
+- (UIEdgeInsets)textViewFrameInsets
+{
+    return UIEdgeInsetsMake(self.textViewTopVerticalSpaceConstraint.constant,
+                            self.textViewMarginHorizontalSpaceConstraint.constant,
+                            self.textViewBottomVerticalSpaceConstraint.constant,
+                            self.textViewAvatarHorizontalSpaceConstraint.constant);
+}
+
+#pragma mark - Utilities
+
+- (void)jsq_updateConstraint:(NSLayoutConstraint *)constraint withConstant:(CGFloat)constant
+{
+    if (constraint.constant == constant) {
+        return;
+    }
+
+    constraint.constant = constant;
+}
+
+#pragma mark - Gesture recognizers
+
+- (void)jsq_handleTapGesture:(UITapGestureRecognizer *)tap
+{
+    CGPoint touchPt = [tap locationInView:self];
+
+    if (CGRectContainsPoint(self.avatarContainerView.frame, touchPt)) {
+        [self.delegate messagesCollectionViewCellDidTapAvatar:self];
+    }
+    else if (CGRectContainsPoint(self.messageBubbleContainerView.frame, touchPt)) {
+        [self.delegate messagesCollectionViewCellDidTapMessageBubble:self];
+    }
+    else {
+        [self.delegate messagesCollectionViewCellDidTapCell:self atPosition:touchPt];
+    }
+}
+
+- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
+{
+    CGPoint touchPt = [touch locationInView:self];
+
+    if ([gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]]) {
+        return CGRectContainsPoint(self.messageBubbleContainerView.frame, touchPt);
+    }
+    
+    return NO;
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCollectionViewCellIncoming.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCollectionViewCellIncoming.h
new file mode 100644
index 0000000..e774569
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCollectionViewCellIncoming.h
@@ -0,0 +1,27 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQMessagesCollectionViewCell.h"
+
+/**
+ *  A `JSQMessagesCollectionViewCellIncoming` object is a concrete instance 
+ *  of `JSQMessagesCollectionViewCell` that represents an incoming message data item.
+ */
+@interface JSQMessagesCollectionViewCellIncoming : JSQMessagesCollectionViewCell
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCollectionViewCellIncoming.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCollectionViewCellIncoming.m
new file mode 100644
index 0000000..12fa71a
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCollectionViewCellIncoming.m
@@ -0,0 +1,32 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQMessagesCollectionViewCellIncoming.h"
+
+@implementation JSQMessagesCollectionViewCellIncoming
+
+#pragma mark - Overrides
+
+- (void)awakeFromNib
+{
+    [super awakeFromNib];
+    self.messageBubbleTopLabel.textAlignment = NSTextAlignmentLeft;
+    self.cellBottomLabel.textAlignment = NSTextAlignmentLeft;
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCollectionViewCellIncoming.xib b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCollectionViewCellIncoming.xib
new file mode 100644
index 0000000..76e771b
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCollectionViewCellIncoming.xib
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9531" systemVersion="15C50" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES">
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9529"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="" id="4lh-CK-yVn" customClass="JSQMessagesCollectionViewCellIncoming">
+            <rect key="frame" x="0.0" y="0.0" width="320" height="154"/>
+            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
+            <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
+                <rect key="frame" x="0.0" y="0.0" width="320" height="154"/>
+                <autoresizingMask key="autoresizingMask"/>
+                <subviews>
+                    <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="cell top label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="afj-rd-iNv" userLabel="Cell top label" customClass="JSQMessagesLabel">
+                        <rect key="frame" x="0.0" y="0.0" width="320" height="20"/>
+                        <color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
+                        <constraints>
+                            <constraint firstAttribute="height" constant="20" id="fKS-MR-YPI"/>
+                        </constraints>
+                        <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                        <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
+                        <nil key="highlightedColor"/>
+                    </label>
+                    <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="bubble top label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ufa-bF-l1Y" userLabel="Bubble top label" customClass="JSQMessagesLabel">
+                        <rect key="frame" x="0.0" y="20" width="320" height="20"/>
+                        <color key="backgroundColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
+                        <constraints>
+                            <constraint firstAttribute="height" constant="20" id="fal-sy-hrK"/>
+                        </constraints>
+                        <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                        <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
+                        <nil key="highlightedColor"/>
+                    </label>
+                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="btS-p8-B7Z" userLabel="Bubble container">
+                        <rect key="frame" x="36" y="40" width="244" height="94"/>
+                        <subviews>
+                            <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="OCS-Fu-acq" userLabel="Bubble Image View">
+                                <rect key="frame" x="0.0" y="0.0" width="244" height="94"/>
+                            </imageView>
+                            <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="KYU-B8-cUW" customClass="JSQMessagesCellTextView">
+                                <rect key="frame" x="6" y="0.0" width="238" height="94"/>
+                                <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
+                                <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                <textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
+                            </textView>
+                        </subviews>
+                        <color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
+                        <constraints>
+                            <constraint firstAttribute="trailing" secondItem="KYU-B8-cUW" secondAttribute="trailing" id="4qS-03-PFO"/>
+                            <constraint firstAttribute="bottom" secondItem="KYU-B8-cUW" secondAttribute="bottom" id="B2v-Gq-Y1L"/>
+                            <constraint firstAttribute="trailing" secondItem="OCS-Fu-acq" secondAttribute="trailing" id="TdB-8V-aUc"/>
+                            <constraint firstItem="KYU-B8-cUW" firstAttribute="leading" secondItem="btS-p8-B7Z" secondAttribute="leading" constant="6" id="Tg9-9l-vr8"/>
+                            <constraint firstItem="KYU-B8-cUW" firstAttribute="top" secondItem="btS-p8-B7Z" secondAttribute="top" id="aEL-yH-N1p"/>
+                            <constraint firstAttribute="bottom" secondItem="OCS-Fu-acq" secondAttribute="bottom" id="aJ4-ZD-tk9"/>
+                            <constraint firstItem="OCS-Fu-acq" firstAttribute="leading" secondItem="btS-p8-B7Z" secondAttribute="leading" id="qpQ-dc-2V5"/>
+                            <constraint firstAttribute="width" constant="244" id="stE-iz-VHo"/>
+                            <constraint firstItem="OCS-Fu-acq" firstAttribute="top" secondItem="btS-p8-B7Z" secondAttribute="top" id="zTa-8g-VY4"/>
+                        </constraints>
+                    </view>
+                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Da1-09-wR4" userLabel="Avatar container">
+                        <rect key="frame" x="0.0" y="100" width="34" height="34"/>
+                        <subviews>
+                            <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="w23-sL-0Rh" userLabel="Avatar Image View">
+                                <rect key="frame" x="0.0" y="0.0" width="34" height="34"/>
+                            </imageView>
+                        </subviews>
+                        <color key="backgroundColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
+                        <constraints>
+                            <constraint firstItem="w23-sL-0Rh" firstAttribute="leading" secondItem="Da1-09-wR4" secondAttribute="leading" id="6zm-sH-cOT"/>
+                            <constraint firstAttribute="trailing" secondItem="w23-sL-0Rh" secondAttribute="trailing" id="JgK-7W-L10"/>
+                            <constraint firstAttribute="bottom" secondItem="w23-sL-0Rh" secondAttribute="bottom" id="U39-Ze-JZ6"/>
+                            <constraint firstAttribute="width" constant="34" id="YwX-fW-Me6"/>
+                            <constraint firstItem="w23-sL-0Rh" firstAttribute="top" secondItem="Da1-09-wR4" secondAttribute="top" id="hxb-KR-hNK"/>
+                            <constraint firstAttribute="height" constant="34" id="tZk-AK-JFa"/>
+                        </constraints>
+                    </view>
+                    <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="cell bottom label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="UPz-5x-c1T" userLabel="Cell bottom label" customClass="JSQMessagesLabel">
+                        <rect key="frame" x="0.0" y="134" width="320" height="20"/>
+                        <color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
+                        <constraints>
+                            <constraint firstAttribute="height" constant="20" id="xPR-Ph-Ze9"/>
+                        </constraints>
+                        <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                        <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
+                        <nil key="highlightedColor"/>
+                    </label>
+                </subviews>
+                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+            </view>
+            <constraints>
+                <constraint firstItem="UPz-5x-c1T" firstAttribute="leading" secondItem="4lh-CK-yVn" secondAttribute="leading" id="54r-MX-MGW"/>
+                <constraint firstAttribute="trailing" secondItem="UPz-5x-c1T" secondAttribute="trailing" id="G3U-h0-DWS"/>
+                <constraint firstAttribute="trailing" secondItem="afj-rd-iNv" secondAttribute="trailing" id="Ka4-Dy-jCS"/>
+                <constraint firstItem="afj-rd-iNv" firstAttribute="leading" secondItem="4lh-CK-yVn" secondAttribute="leading" id="OnD-mZ-QtR"/>
+                <constraint firstItem="Ufa-bF-l1Y" firstAttribute="leading" secondItem="4lh-CK-yVn" secondAttribute="leading" id="Z5z-m3-8Ne"/>
+                <constraint firstItem="afj-rd-iNv" firstAttribute="top" secondItem="4lh-CK-yVn" secondAttribute="top" id="ZG9-2M-N52"/>
+                <constraint firstAttribute="trailing" secondItem="Ufa-bF-l1Y" secondAttribute="trailing" id="cWQ-1Q-xOA"/>
+                <constraint firstItem="UPz-5x-c1T" firstAttribute="top" secondItem="Da1-09-wR4" secondAttribute="bottom" id="dDB-B0-c6J"/>
+                <constraint firstItem="Ufa-bF-l1Y" firstAttribute="top" secondItem="afj-rd-iNv" secondAttribute="bottom" id="i9Y-sV-v6b"/>
+                <constraint firstItem="btS-p8-B7Z" firstAttribute="leading" secondItem="Da1-09-wR4" secondAttribute="trailing" constant="2" id="j0I-pm-eex"/>
+                <constraint firstItem="btS-p8-B7Z" firstAttribute="top" secondItem="Ufa-bF-l1Y" secondAttribute="bottom" id="jAu-Dn-7rN"/>
+                <constraint firstItem="Da1-09-wR4" firstAttribute="leading" secondItem="4lh-CK-yVn" secondAttribute="leading" id="jiu-B4-TSD"/>
+                <constraint firstAttribute="bottom" secondItem="UPz-5x-c1T" secondAttribute="bottom" id="nsK-Gh-M3Z"/>
+                <constraint firstItem="UPz-5x-c1T" firstAttribute="top" secondItem="btS-p8-B7Z" secondAttribute="bottom" id="s8G-Je-7GA"/>
+            </constraints>
+            <size key="customSize" width="317" height="245"/>
+            <connections>
+                <outlet property="avatarContainerView" destination="Da1-09-wR4" id="tpM-P4-qUR"/>
+                <outlet property="avatarContainerViewHeightConstraint" destination="tZk-AK-JFa" id="tPu-mC-ITh"/>
+                <outlet property="avatarContainerViewWidthConstraint" destination="YwX-fW-Me6" id="5PN-NL-hEP"/>
+                <outlet property="avatarImageView" destination="w23-sL-0Rh" id="Yf4-UR-VRC"/>
+                <outlet property="cellBottomLabel" destination="UPz-5x-c1T" id="MKm-hp-T6v"/>
+                <outlet property="cellBottomLabelHeightConstraint" destination="xPR-Ph-Ze9" id="nvV-Tk-AIs"/>
+                <outlet property="cellTopLabel" destination="afj-rd-iNv" id="bTd-4q-U7e"/>
+                <outlet property="cellTopLabelHeightConstraint" destination="fKS-MR-YPI" id="YWd-Rd-qSL"/>
+                <outlet property="messageBubbleContainerView" destination="btS-p8-B7Z" id="2sk-5p-NEd"/>
+                <outlet property="messageBubbleContainerWidthConstraint" destination="stE-iz-VHo" id="lle-iT-67d"/>
+                <outlet property="messageBubbleImageView" destination="OCS-Fu-acq" id="OuN-5t-30g"/>
+                <outlet property="messageBubbleTopLabel" destination="Ufa-bF-l1Y" id="VtH-te-blR"/>
+                <outlet property="messageBubbleTopLabelHeightConstraint" destination="fal-sy-hrK" id="kgv-NO-Gud"/>
+                <outlet property="textView" destination="KYU-B8-cUW" id="1Yv-ln-EUZ"/>
+                <outlet property="textViewAvatarHorizontalSpaceConstraint" destination="Tg9-9l-vr8" id="HWn-aO-NbR"/>
+                <outlet property="textViewBottomVerticalSpaceConstraint" destination="B2v-Gq-Y1L" id="oKV-Ti-Oci"/>
+                <outlet property="textViewMarginHorizontalSpaceConstraint" destination="4qS-03-PFO" id="1Qe-Ee-fUO"/>
+                <outlet property="textViewTopVerticalSpaceConstraint" destination="aEL-yH-N1p" id="WPl-0b-tf1"/>
+            </connections>
+            <point key="canvasLocation" x="255" y="202"/>
+        </collectionViewCell>
+    </objects>
+</document>
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCollectionViewCellOutgoing.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCollectionViewCellOutgoing.h
new file mode 100644
index 0000000..43dd545
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCollectionViewCellOutgoing.h
@@ -0,0 +1,27 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQMessagesCollectionViewCell.h"
+
+/**
+ *  A `JSQMessagesCollectionViewCellOutgoing` object is a concrete instance 
+ *  of `JSQMessagesCollectionViewCell` that represents an outgoing message data item.
+ */
+@interface JSQMessagesCollectionViewCellOutgoing : JSQMessagesCollectionViewCell
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCollectionViewCellOutgoing.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCollectionViewCellOutgoing.m
new file mode 100644
index 0000000..d395075
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCollectionViewCellOutgoing.m
@@ -0,0 +1,32 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQMessagesCollectionViewCellOutgoing.h"
+
+@implementation JSQMessagesCollectionViewCellOutgoing
+
+#pragma mark - Overrides
+
+- (void)awakeFromNib
+{
+    [super awakeFromNib];
+    self.messageBubbleTopLabel.textAlignment = NSTextAlignmentRight;
+    self.cellBottomLabel.textAlignment = NSTextAlignmentRight;
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCollectionViewCellOutgoing.xib b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCollectionViewCellOutgoing.xib
new file mode 100644
index 0000000..f3a48c0
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCollectionViewCellOutgoing.xib
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9531" systemVersion="15C50" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES">
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9529"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="" id="23f-xH-rkY" customClass="JSQMessagesCollectionViewCellOutgoing">
+            <rect key="frame" x="0.0" y="0.0" width="320" height="154"/>
+            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
+            <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
+                <rect key="frame" x="0.0" y="0.0" width="320" height="154"/>
+                <autoresizingMask key="autoresizingMask"/>
+                <subviews>
+                    <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="cell top label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jxM-YD-sVG" userLabel="Cell top label" customClass="JSQMessagesLabel">
+                        <rect key="frame" x="0.0" y="0.0" width="320" height="20"/>
+                        <color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
+                        <constraints>
+                            <constraint firstAttribute="height" constant="20" id="9oK-E7-iXA"/>
+                        </constraints>
+                        <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                        <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
+                        <nil key="highlightedColor"/>
+                    </label>
+                    <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="bubble top label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="p52-YN-yLu" userLabel="Bubble top label" customClass="JSQMessagesLabel">
+                        <rect key="frame" x="0.0" y="20" width="320" height="20"/>
+                        <color key="backgroundColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
+                        <constraints>
+                            <constraint firstAttribute="height" constant="20" id="8TB-va-f8L"/>
+                        </constraints>
+                        <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                        <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
+                        <nil key="highlightedColor"/>
+                    </label>
+                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="2zh-vR-QJW" userLabel="Bubble container">
+                        <rect key="frame" x="40" y="40" width="244" height="94"/>
+                        <subviews>
+                            <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="2qm-c6-OZf" userLabel="Bubble Image View">
+                                <rect key="frame" x="0.0" y="0.0" width="244" height="94"/>
+                            </imageView>
+                            <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="vLY-aM-0Dr" customClass="JSQMessagesCellTextView">
+                                <rect key="frame" x="0.0" y="0.0" width="238" height="94"/>
+                                <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
+                                <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                <textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
+                            </textView>
+                        </subviews>
+                        <color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
+                        <constraints>
+                            <constraint firstItem="vLY-aM-0Dr" firstAttribute="leading" secondItem="2zh-vR-QJW" secondAttribute="leading" id="7rI-Nc-AK3"/>
+                            <constraint firstAttribute="trailing" secondItem="2qm-c6-OZf" secondAttribute="trailing" id="AEu-1l-tqh"/>
+                            <constraint firstItem="2qm-c6-OZf" firstAttribute="top" secondItem="2zh-vR-QJW" secondAttribute="top" id="DbW-Cx-zOW"/>
+                            <constraint firstItem="2qm-c6-OZf" firstAttribute="leading" secondItem="2zh-vR-QJW" secondAttribute="leading" id="H1H-yn-Raq"/>
+                            <constraint firstItem="vLY-aM-0Dr" firstAttribute="top" secondItem="2zh-vR-QJW" secondAttribute="top" id="RiG-21-Bqc"/>
+                            <constraint firstAttribute="bottom" secondItem="vLY-aM-0Dr" secondAttribute="bottom" id="UbF-Bl-Q7v"/>
+                            <constraint firstAttribute="trailing" secondItem="vLY-aM-0Dr" secondAttribute="trailing" constant="6" id="aVg-yy-8K7"/>
+                            <constraint firstAttribute="width" constant="244" id="imD-52-K45"/>
+                            <constraint firstAttribute="bottom" secondItem="2qm-c6-OZf" secondAttribute="bottom" id="lts-Ve-wSh"/>
+                        </constraints>
+                    </view>
+                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="X89-B1-aAd" userLabel="Avatar container">
+                        <rect key="frame" x="286" y="100" width="34" height="34"/>
+                        <subviews>
+                            <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="y9b-D9-Q7W" userLabel="Avatar Image View">
+                                <rect key="frame" x="0.0" y="0.0" width="34" height="34"/>
+                            </imageView>
+                        </subviews>
+                        <color key="backgroundColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
+                        <constraints>
+                            <constraint firstAttribute="bottom" secondItem="y9b-D9-Q7W" secondAttribute="bottom" id="7SX-4t-GAr"/>
+                            <constraint firstAttribute="width" constant="34" id="Pkm-tW-k4z"/>
+                            <constraint firstItem="y9b-D9-Q7W" firstAttribute="leading" secondItem="X89-B1-aAd" secondAttribute="leading" id="Pya-tL-FjE"/>
+                            <constraint firstItem="y9b-D9-Q7W" firstAttribute="top" secondItem="X89-B1-aAd" secondAttribute="top" id="e5w-hn-mre"/>
+                            <constraint firstAttribute="height" constant="34" id="tgw-aN-JJu"/>
+                            <constraint firstAttribute="trailing" secondItem="y9b-D9-Q7W" secondAttribute="trailing" id="w9X-3u-BNY"/>
+                        </constraints>
+                    </view>
+                    <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="cell bottom label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7Uc-dI-YDD" userLabel="Cell bottom label" customClass="JSQMessagesLabel">
+                        <rect key="frame" x="0.0" y="134" width="320" height="20"/>
+                        <color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
+                        <constraints>
+                            <constraint firstAttribute="height" constant="20" id="cPs-M4-tjX"/>
+                        </constraints>
+                        <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                        <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
+                        <nil key="highlightedColor"/>
+                    </label>
+                </subviews>
+                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+            </view>
+            <constraints>
+                <constraint firstAttribute="trailing" secondItem="7Uc-dI-YDD" secondAttribute="trailing" id="1v4-5s-XmK"/>
+                <constraint firstItem="2zh-vR-QJW" firstAttribute="top" secondItem="p52-YN-yLu" secondAttribute="bottom" id="3Wx-g0-fTc"/>
+                <constraint firstAttribute="trailing" secondItem="jxM-YD-sVG" secondAttribute="trailing" id="AwY-g7-f1T"/>
+                <constraint firstItem="jxM-YD-sVG" firstAttribute="top" secondItem="23f-xH-rkY" secondAttribute="top" id="HYT-Tw-whz"/>
+                <constraint firstAttribute="trailing" secondItem="X89-B1-aAd" secondAttribute="trailing" id="KLt-Ix-wDa"/>
+                <constraint firstItem="7Uc-dI-YDD" firstAttribute="top" secondItem="2zh-vR-QJW" secondAttribute="bottom" id="Ngq-ew-t2K"/>
+                <constraint firstItem="7Uc-dI-YDD" firstAttribute="leading" secondItem="23f-xH-rkY" secondAttribute="leading" id="fiS-g3-X16"/>
+                <constraint firstAttribute="bottom" secondItem="7Uc-dI-YDD" secondAttribute="bottom" id="gXo-9b-b1W"/>
+                <constraint firstAttribute="trailing" secondItem="p52-YN-yLu" secondAttribute="trailing" id="gen-N0-uZj"/>
+                <constraint firstItem="7Uc-dI-YDD" firstAttribute="top" secondItem="X89-B1-aAd" secondAttribute="bottom" id="iiF-tn-5Ir"/>
+                <constraint firstItem="p52-YN-yLu" firstAttribute="top" secondItem="jxM-YD-sVG" secondAttribute="bottom" id="jBD-JV-AWk"/>
+                <constraint firstItem="jxM-YD-sVG" firstAttribute="leading" secondItem="23f-xH-rkY" secondAttribute="leading" id="qeB-G5-1Wq"/>
+                <constraint firstItem="p52-YN-yLu" firstAttribute="leading" secondItem="23f-xH-rkY" secondAttribute="leading" id="tTj-Mp-0va"/>
+                <constraint firstItem="X89-B1-aAd" firstAttribute="leading" secondItem="2zh-vR-QJW" secondAttribute="trailing" constant="2" id="vMz-Yi-B0w"/>
+            </constraints>
+            <size key="customSize" width="317" height="245"/>
+            <connections>
+                <outlet property="avatarContainerView" destination="X89-B1-aAd" id="WSI-Zc-qIE"/>
+                <outlet property="avatarContainerViewHeightConstraint" destination="tgw-aN-JJu" id="pgV-tY-5Cm"/>
+                <outlet property="avatarContainerViewWidthConstraint" destination="Pkm-tW-k4z" id="Cpe-d3-yiq"/>
+                <outlet property="avatarImageView" destination="y9b-D9-Q7W" id="cZo-SR-S9h"/>
+                <outlet property="cellBottomLabel" destination="7Uc-dI-YDD" id="gVD-C2-UcZ"/>
+                <outlet property="cellBottomLabelHeightConstraint" destination="cPs-M4-tjX" id="b5k-6e-iA8"/>
+                <outlet property="cellTopLabel" destination="jxM-YD-sVG" id="acH-pr-spx"/>
+                <outlet property="cellTopLabelHeightConstraint" destination="9oK-E7-iXA" id="MZM-kV-2dI"/>
+                <outlet property="messageBubbleContainerView" destination="2zh-vR-QJW" id="pu0-GU-eZl"/>
+                <outlet property="messageBubbleContainerWidthConstraint" destination="imD-52-K45" id="Xld-Pa-yJw"/>
+                <outlet property="messageBubbleImageView" destination="2qm-c6-OZf" id="bpy-Gv-jSh"/>
+                <outlet property="messageBubbleTopLabel" destination="p52-YN-yLu" id="SLH-sA-Chu"/>
+                <outlet property="messageBubbleTopLabelHeightConstraint" destination="8TB-va-f8L" id="FNt-BS-Wxi"/>
+                <outlet property="textView" destination="vLY-aM-0Dr" id="YEp-mW-xIY"/>
+                <outlet property="textViewAvatarHorizontalSpaceConstraint" destination="aVg-yy-8K7" id="CIe-Bi-eng"/>
+                <outlet property="textViewBottomVerticalSpaceConstraint" destination="UbF-Bl-Q7v" id="KHP-49-3u4"/>
+                <outlet property="textViewMarginHorizontalSpaceConstraint" destination="7rI-Nc-AK3" id="ciu-j6-IpH"/>
+                <outlet property="textViewTopVerticalSpaceConstraint" destination="RiG-21-Bqc" id="i3j-z0-feE"/>
+            </connections>
+            <point key="canvasLocation" x="371" y="145"/>
+        </collectionViewCell>
+    </objects>
+</document>
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesComposerTextView.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesComposerTextView.h
new file mode 100644
index 0000000..98d8d1c
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesComposerTextView.h
@@ -0,0 +1,68 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <UIKit/UIKit.h>
+
+@class JSQMessagesComposerTextView;
+
+/**
+ *  A delegate object used to notify the receiver of paste events from a `JSQMessagesComposerTextView`.
+ */
+@protocol JSQMessagesComposerTextViewPasteDelegate <NSObject>
+
+/**
+ *  Asks the delegate whether or not the `textView` should use the original implementation of `-[UITextView paste]`.
+ *
+ *  @discussion Use this delegate method to implement custom pasting behavior. 
+ *  You should return `NO` when you want to handle pasting. 
+ *  Return `YES` to defer functionality to the `textView`.
+ */
+- (BOOL)composerTextView:(JSQMessagesComposerTextView *)textView shouldPasteWithSender:(id)sender;
+
+@end
+
+/**
+ *  An instance of `JSQMessagesComposerTextView` is a subclass of `UITextView` that is styled and used 
+ *  for composing messages in a `JSQMessagesViewController`. It is a subview of a `JSQMessagesToolbarContentView`.
+ */
+@interface JSQMessagesComposerTextView : UITextView
+
+/**
+ *  The text to be displayed when the text view is empty. The default value is `nil`.
+ */
+@property (copy, nonatomic) NSString *placeHolder;
+
+/**
+ *  The color of the place holder text. The default value is `[UIColor lightGrayColor]`.
+ */
+@property (strong, nonatomic) UIColor *placeHolderTextColor;
+
+/**
+ *  The object that acts as the paste delegate of the text view.
+ */
+@property (weak, nonatomic) id<JSQMessagesComposerTextViewPasteDelegate> pasteDelegate;
+
+/**
+ *  Determines whether or not the text view contains text after trimming white space 
+ *  from the front and back of its string.
+ *
+ *  @return `YES` if the text view contains text, `NO` otherwise.
+ */
+- (BOOL)hasText;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesComposerTextView.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesComposerTextView.m
new file mode 100644
index 0000000..6a3471e
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesComposerTextView.m
@@ -0,0 +1,233 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQMessagesComposerTextView.h"
+
+#import <QuartzCore/QuartzCore.h>
+
+#import "NSString+JSQMessages.h"
+
+
+@implementation JSQMessagesComposerTextView
+
+#pragma mark - Initialization
+
+- (void)jsq_configureTextView
+{
+    [self setTranslatesAutoresizingMaskIntoConstraints:NO];
+
+    CGFloat cornerRadius = 6.0f;
+
+    self.backgroundColor = [UIColor whiteColor];
+    self.layer.borderWidth = 0.5f;
+    self.layer.borderColor = [UIColor lightGrayColor].CGColor;
+    self.layer.cornerRadius = cornerRadius;
+
+    self.scrollIndicatorInsets = UIEdgeInsetsMake(cornerRadius, 0.0f, cornerRadius, 0.0f);
+
+    self.textContainerInset = UIEdgeInsetsMake(4.0f, 2.0f, 4.0f, 2.0f);
+    self.contentInset = UIEdgeInsetsMake(1.0f, 0.0f, 1.0f, 0.0f);
+
+    self.scrollEnabled = YES;
+    self.scrollsToTop = NO;
+    self.userInteractionEnabled = YES;
+
+    self.font = [UIFont systemFontOfSize:16.0f];
+    self.textColor = [UIColor blackColor];
+    self.textAlignment = NSTextAlignmentNatural;
+
+    self.contentMode = UIViewContentModeRedraw;
+    self.dataDetectorTypes = UIDataDetectorTypeNone;
+    self.keyboardAppearance = UIKeyboardAppearanceDefault;
+    self.keyboardType = UIKeyboardTypeDefault;
+    self.returnKeyType = UIReturnKeyDefault;
+
+    self.text = nil;
+
+    _placeHolder = nil;
+    _placeHolderTextColor = [UIColor lightGrayColor];
+
+    [self jsq_addTextViewNotificationObservers];
+}
+
+- (instancetype)initWithFrame:(CGRect)frame textContainer:(NSTextContainer *)textContainer
+{
+    self = [super initWithFrame:frame textContainer:textContainer];
+    if (self) {
+        [self jsq_configureTextView];
+    }
+    return self;
+}
+
+- (void)awakeFromNib
+{
+    [super awakeFromNib];
+    [self jsq_configureTextView];
+}
+
+- (void)dealloc
+{
+    [self jsq_removeTextViewNotificationObservers];
+}
+
+#pragma mark - Composer text view
+
+- (BOOL)hasText
+{
+    return ([[self.text jsq_stringByTrimingWhitespace] length] > 0);
+}
+
+#pragma mark - Setters
+
+- (void)setPlaceHolder:(NSString *)placeHolder
+{
+    if ([placeHolder isEqualToString:_placeHolder]) {
+        return;
+    }
+
+    _placeHolder = [placeHolder copy];
+    [self setNeedsDisplay];
+}
+
+- (void)setPlaceHolderTextColor:(UIColor *)placeHolderTextColor
+{
+    if ([placeHolderTextColor isEqual:_placeHolderTextColor]) {
+        return;
+    }
+
+    _placeHolderTextColor = placeHolderTextColor;
+    [self setNeedsDisplay];
+}
+
+#pragma mark - UITextView overrides
+
+- (void)setText:(NSString *)text
+{
+    [super setText:text];
+    [self setNeedsDisplay];
+}
+
+- (void)setAttributedText:(NSAttributedString *)attributedText
+{
+    [super setAttributedText:attributedText];
+    [self setNeedsDisplay];
+}
+
+- (void)setFont:(UIFont *)font
+{
+    [super setFont:font];
+    [self setNeedsDisplay];
+}
+
+- (void)setTextAlignment:(NSTextAlignment)textAlignment
+{
+    [super setTextAlignment:textAlignment];
+    [self setNeedsDisplay];
+}
+
+- (void)paste:(id)sender
+{
+    if (!self.pasteDelegate || [self.pasteDelegate composerTextView:self shouldPasteWithSender:sender]) {
+        [super paste:sender];
+    }
+}
+
+#pragma mark - Drawing
+
+- (void)drawRect:(CGRect)rect
+{
+    [super drawRect:rect];
+
+    if ([self.text length] == 0 && self.placeHolder) {
+        [self.placeHolderTextColor set];
+
+        [self.placeHolder drawInRect:CGRectInset(rect, 7.0f, 5.0f)
+                      withAttributes:[self jsq_placeholderTextAttributes]];
+    }
+}
+
+#pragma mark - Notifications
+
+- (void)jsq_addTextViewNotificationObservers
+{
+    [[NSNotificationCenter defaultCenter] addObserver:self
+                                             selector:@selector(jsq_didReceiveTextViewNotification:)
+                                                 name:UITextViewTextDidChangeNotification
+                                               object:self];
+
+    [[NSNotificationCenter defaultCenter] addObserver:self
+                                             selector:@selector(jsq_didReceiveTextViewNotification:)
+                                                 name:UITextViewTextDidBeginEditingNotification
+                                               object:self];
+
+    [[NSNotificationCenter defaultCenter] addObserver:self
+                                             selector:@selector(jsq_didReceiveTextViewNotification:)
+                                                 name:UITextViewTextDidEndEditingNotification
+                                               object:self];
+}
+
+- (void)jsq_removeTextViewNotificationObservers
+{
+    [[NSNotificationCenter defaultCenter] removeObserver:self
+                                                    name:UITextViewTextDidChangeNotification
+                                                  object:self];
+
+    [[NSNotificationCenter defaultCenter] removeObserver:self
+                                                    name:UITextViewTextDidBeginEditingNotification
+                                                  object:self];
+
+    [[NSNotificationCenter defaultCenter] removeObserver:self
+                                                    name:UITextViewTextDidEndEditingNotification
+                                                  object:self];
+}
+
+- (void)jsq_didReceiveTextViewNotification:(NSNotification *)notification
+{
+    [self setNeedsDisplay];
+}
+
+#pragma mark - Utilities
+
+- (NSDictionary *)jsq_placeholderTextAttributes
+{
+    NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
+    paragraphStyle.lineBreakMode = NSLineBreakByTruncatingTail;
+    paragraphStyle.alignment = self.textAlignment;
+
+    return @{ NSFontAttributeName : self.font,
+              NSForegroundColorAttributeName : self.placeHolderTextColor,
+              NSParagraphStyleAttributeName : paragraphStyle };
+}
+
+#pragma mark - UIMenuController
+
+- (BOOL)canBecomeFirstResponder
+{
+    return [super canBecomeFirstResponder];
+}
+
+- (BOOL)becomeFirstResponder
+{
+    return [super becomeFirstResponder];
+}
+
+- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
+    [UIMenuController sharedMenuController].menuItems = nil;
+    return [super canPerformAction:action withSender:sender];
+}
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesInputToolbar.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesInputToolbar.h
new file mode 100644
index 0000000..f14790e
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesInputToolbar.h
@@ -0,0 +1,110 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+#import "JSQMessagesToolbarContentView.h"
+
+@class JSQMessagesInputToolbar;
+
+
+/**
+ *  The `JSQMessagesInputToolbarDelegate` protocol defines methods for interacting with
+ *  a `JSQMessagesInputToolbar` object.
+ */
+@protocol JSQMessagesInputToolbarDelegate <UIToolbarDelegate>
+
+@required
+
+/**
+ *  Tells the delegate that the toolbar's `rightBarButtonItem` has been pressed.
+ *
+ *  @param toolbar The object representing the toolbar sending this information.
+ *  @param sender  The button that received the touch event.
+ */
+- (void)messagesInputToolbar:(JSQMessagesInputToolbar *)toolbar
+      didPressRightBarButton:(UIButton *)sender;
+
+/**
+ *  Tells the delegate that the toolbar's `leftBarButtonItem` has been pressed.
+ *
+ *  @param toolbar The object representing the toolbar sending this information.
+ *  @param sender  The button that received the touch event.
+ */
+- (void)messagesInputToolbar:(JSQMessagesInputToolbar *)toolbar
+       didPressLeftBarButton:(UIButton *)sender;
+
+@end
+
+
+/**
+ *  An instance of `JSQMessagesInputToolbar` defines the input toolbar for
+ *  composing a new message. It is displayed above and follow the movement of the system keyboard.
+ */
+@interface JSQMessagesInputToolbar : UIToolbar
+
+/**
+ *  The object that acts as the delegate of the toolbar.
+ */
+@property (weak, nonatomic) id<JSQMessagesInputToolbarDelegate> delegate;
+
+/**
+ *  Returns the content view of the toolbar. This view contains all subviews of the toolbar.
+ */
+@property (weak, nonatomic, readonly) JSQMessagesToolbarContentView *contentView;
+
+/**
+ *  A boolean value indicating whether the send button is on the right side of the toolbar or not.
+ *
+ *  @discussion The default value is `YES`, which indicates that the send button is the right-most subview of
+ *  the toolbar's `contentView`. Set to `NO` to specify that the send button is on the left. This
+ *  property is used to determine which touch events correspond to which actions.
+ *
+ *  @warning Note, this property *does not* change the positions of buttons in the toolbar's content view.
+ *  It only specifies whether the `rightBarButtonItem `or the `leftBarButtonItem` is the send button.
+ *  The other button then acts as the accessory button.
+ */
+@property (assign, nonatomic) BOOL sendButtonOnRight;
+
+/**
+ *  Specifies the default (minimum) height for the toolbar. The default value is `44.0f`. This value must be positive.
+ */
+@property (assign, nonatomic) CGFloat preferredDefaultHeight;
+
+/**
+ *  Specifies the maximum height for the toolbar. The default value is `NSNotFound`, which specifies no maximum height.
+ */
+@property (assign, nonatomic) NSUInteger maximumHeight;
+
+/**
+ *  Enables or disables the send button based on whether or not its `textView` has text.
+ *  That is, the send button will be enabled if there is text in the `textView`, and disabled otherwise.
+ */
+- (void)toggleSendButtonEnabled;
+
+/**
+ *  Loads the content view for the toolbar.
+ *
+ *  @discussion Override this method to provide a custom content view for the toolbar.
+ *
+ *  @return An initialized `JSQMessagesToolbarContentView` if successful, otherwise `nil`.
+ */
+- (JSQMessagesToolbarContentView *)loadToolbarContentView;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesInputToolbar.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesInputToolbar.m
new file mode 100644
index 0000000..cd5d80a
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesInputToolbar.m
@@ -0,0 +1,191 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQMessagesInputToolbar.h"
+
+#import "JSQMessagesComposerTextView.h"
+
+#import "JSQMessagesToolbarButtonFactory.h"
+
+#import "UIColor+JSQMessages.h"
+#import "UIImage+JSQMessages.h"
+#import "UIView+JSQMessages.h"
+
+static void * kJSQMessagesInputToolbarKeyValueObservingContext = &kJSQMessagesInputToolbarKeyValueObservingContext;
+
+
+@interface JSQMessagesInputToolbar ()
+
+@property (assign, nonatomic) BOOL jsq_isObserving;
+
+@end
+
+
+
+@implementation JSQMessagesInputToolbar
+
+@dynamic delegate;
+
+#pragma mark - Initialization
+
+- (void)awakeFromNib
+{
+    [super awakeFromNib];
+    [self setTranslatesAutoresizingMaskIntoConstraints:NO];
+
+    self.jsq_isObserving = NO;
+    self.sendButtonOnRight = YES;
+
+    self.preferredDefaultHeight = 44.0f;
+    self.maximumHeight = NSNotFound;
+
+    JSQMessagesToolbarContentView *toolbarContentView = [self loadToolbarContentView];
+    toolbarContentView.frame = self.frame;
+    [self addSubview:toolbarContentView];
+    [self jsq_pinAllEdgesOfSubview:toolbarContentView];
+    [self setNeedsUpdateConstraints];
+    _contentView = toolbarContentView;
+
+    [self jsq_addObservers];
+
+    self.contentView.leftBarButtonItem = [JSQMessagesToolbarButtonFactory defaultAccessoryButtonItem];
+    self.contentView.rightBarButtonItem = [JSQMessagesToolbarButtonFactory defaultSendButtonItem];
+
+    [self toggleSendButtonEnabled];
+}
+
+- (JSQMessagesToolbarContentView *)loadToolbarContentView
+{
+    NSArray *nibViews = [[NSBundle bundleForClass:[JSQMessagesInputToolbar class]] loadNibNamed:NSStringFromClass([JSQMessagesToolbarContentView class])
+                                                                                          owner:nil
+                                                                                        options:nil];
+    return nibViews.firstObject;
+}
+
+- (void)dealloc
+{
+    [self jsq_removeObservers];
+}
+
+#pragma mark - Setters
+
+- (void)setPreferredDefaultHeight:(CGFloat)preferredDefaultHeight
+{
+    NSParameterAssert(preferredDefaultHeight > 0.0f);
+    _preferredDefaultHeight = preferredDefaultHeight;
+}
+
+#pragma mark - Actions
+
+- (void)jsq_leftBarButtonPressed:(UIButton *)sender
+{
+    [self.delegate messagesInputToolbar:self didPressLeftBarButton:sender];
+}
+
+- (void)jsq_rightBarButtonPressed:(UIButton *)sender
+{
+    [self.delegate messagesInputToolbar:self didPressRightBarButton:sender];
+}
+
+#pragma mark - Input toolbar
+
+- (void)toggleSendButtonEnabled
+{
+    BOOL hasText = [self.contentView.textView hasText];
+
+    if (self.sendButtonOnRight) {
+        self.contentView.rightBarButtonItem.enabled = hasText;
+    }
+    else {
+        self.contentView.leftBarButtonItem.enabled = hasText;
+    }
+}
+
+#pragma mark - Key-value observing
+
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
+{
+    if (context == kJSQMessagesInputToolbarKeyValueObservingContext) {
+        if (object == self.contentView) {
+
+            if ([keyPath isEqualToString:NSStringFromSelector(@selector(leftBarButtonItem))]) {
+
+                [self.contentView.leftBarButtonItem removeTarget:self
+                                                          action:NULL
+                                                forControlEvents:UIControlEventTouchUpInside];
+
+                [self.contentView.leftBarButtonItem addTarget:self
+                                                       action:@selector(jsq_leftBarButtonPressed:)
+                                             forControlEvents:UIControlEventTouchUpInside];
+            }
+            else if ([keyPath isEqualToString:NSStringFromSelector(@selector(rightBarButtonItem))]) {
+
+                [self.contentView.rightBarButtonItem removeTarget:self
+                                                           action:NULL
+                                                 forControlEvents:UIControlEventTouchUpInside];
+
+                [self.contentView.rightBarButtonItem addTarget:self
+                                                        action:@selector(jsq_rightBarButtonPressed:)
+                                              forControlEvents:UIControlEventTouchUpInside];
+            }
+
+            [self toggleSendButtonEnabled];
+        }
+    }
+}
+
+- (void)jsq_addObservers
+{
+    if (self.jsq_isObserving) {
+        return;
+    }
+
+    [self.contentView addObserver:self
+                       forKeyPath:NSStringFromSelector(@selector(leftBarButtonItem))
+                          options:0
+                          context:kJSQMessagesInputToolbarKeyValueObservingContext];
+
+    [self.contentView addObserver:self
+                       forKeyPath:NSStringFromSelector(@selector(rightBarButtonItem))
+                          options:0
+                          context:kJSQMessagesInputToolbarKeyValueObservingContext];
+
+    self.jsq_isObserving = YES;
+}
+
+- (void)jsq_removeObservers
+{
+    if (!_jsq_isObserving) {
+        return;
+    }
+
+    @try {
+        [_contentView removeObserver:self
+                          forKeyPath:NSStringFromSelector(@selector(leftBarButtonItem))
+                             context:kJSQMessagesInputToolbarKeyValueObservingContext];
+
+        [_contentView removeObserver:self
+                          forKeyPath:NSStringFromSelector(@selector(rightBarButtonItem))
+                             context:kJSQMessagesInputToolbarKeyValueObservingContext];
+    }
+    @catch (NSException *__unused exception) { }
+    
+    _jsq_isObserving = NO;
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesLabel.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesLabel.h
new file mode 100644
index 0000000..9395ac7
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesLabel.h
@@ -0,0 +1,35 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <UIKit/UIKit.h>
+
+/**
+ *  `JSQMessagesLabel` is a subclass of `UILabel` that adds support for a `textInsets` property,
+ *  which is similar to the `textContainerInset` property of `UITextView`.
+ */
+@interface JSQMessagesLabel : UILabel
+
+/**
+ *  The inset of the text layout area within the label's content area. The default value is `UIEdgeInsetsZero`.
+ *
+ *  @discussion This property provides text margins for the text laid out in the label.
+ *  The inset values provided must be greater than or equal to `0.0f`.
+ */
+@property (assign, nonatomic) UIEdgeInsets textInsets;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesLabel.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesLabel.m
new file mode 100644
index 0000000..0992105
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesLabel.m
@@ -0,0 +1,68 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQMessagesLabel.h"
+
+@implementation JSQMessagesLabel
+
+#pragma mark - Initialization
+
+- (void)jsq_configureLabel
+{
+    [self setTranslatesAutoresizingMaskIntoConstraints:NO];
+    self.textInsets = UIEdgeInsetsZero;
+}
+
+- (instancetype)initWithFrame:(CGRect)frame
+{
+    self = [super initWithFrame:frame];
+    if (self) {
+        [self jsq_configureLabel];
+    }
+    return self;
+}
+
+- (void)awakeFromNib
+{
+    [super awakeFromNib];
+    [self jsq_configureLabel];
+}
+
+#pragma mark - Setters
+
+- (void)setTextInsets:(UIEdgeInsets)textInsets
+{
+    if (UIEdgeInsetsEqualToEdgeInsets(_textInsets, textInsets)) {
+        return;
+    }
+    
+    _textInsets = textInsets;
+    [self setNeedsDisplay];
+}
+
+#pragma mark - Drawing
+
+- (void)drawTextInRect:(CGRect)rect
+{
+    [super drawTextInRect:CGRectMake(CGRectGetMinX(rect) + self.textInsets.left,
+                                     CGRectGetMinY(rect) + self.textInsets.top,
+                                     CGRectGetWidth(rect) - self.textInsets.right,
+                                     CGRectGetHeight(rect) - self.textInsets.bottom)];
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesLoadEarlierHeaderView.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesLoadEarlierHeaderView.h
new file mode 100644
index 0000000..1bf3c99
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesLoadEarlierHeaderView.h
@@ -0,0 +1,81 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <UIKit/UIKit.h>
+
+@class JSQMessagesLoadEarlierHeaderView;
+
+/**
+ *  A constant defining the default height of a `JSQMessagesLoadEarlierHeaderView`.
+ */
+FOUNDATION_EXPORT const CGFloat kJSQMessagesLoadEarlierHeaderViewHeight;
+
+/**
+ *  The `JSQMessagesLoadEarlierHeaderViewDelegate` defines methods that allow you to
+ *  respond to interactions within the header view.
+ */
+@protocol JSQMessagesLoadEarlierHeaderViewDelegate <NSObject>
+
+@required
+
+/**
+ *  Tells the delegate that the loadButton has received a touch event.
+ *
+ *  @param headerView The header view that contains the sender.
+ *  @param sender     The button that received the touch.
+ */
+- (void)headerView:(JSQMessagesLoadEarlierHeaderView *)headerView didPressLoadButton:(UIButton *)sender;
+
+@end
+
+
+/**
+ *  The `JSQMessagesLoadEarlierHeaderView` class implements a reusable view that can be placed
+ *  at the top of a `JSQMessagesCollectionView`. This view contains a "load earlier messages" button
+ *  and can be used as a way for the user to load previously sent messages.
+ */
+@interface JSQMessagesLoadEarlierHeaderView : UICollectionReusableView
+
+/**
+ *  The object that acts as the delegate of the header view.
+ */
+@property (weak, nonatomic) id<JSQMessagesLoadEarlierHeaderViewDelegate> delegate;
+
+/**
+ *  Returns the load button of the header view.
+ */
+@property (weak, nonatomic, readonly) UIButton *loadButton;
+
+#pragma mark - Class methods
+
+/**
+ *  Returns the `UINib` object initialized for the collection reusable view.
+ *
+ *  @return The initialized `UINib` object or `nil` if there were errors during
+ *  initialization or the nib file could not be located.
+ */
++ (UINib *)nib;
+
+/**
+ *  Returns the default string used to identify the reusable header view.
+ *
+ *  @return The string used to identify the reusable header view.
+ */
++ (NSString *)headerReuseIdentifier;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesLoadEarlierHeaderView.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesLoadEarlierHeaderView.m
new file mode 100644
index 0000000..f88ebab
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesLoadEarlierHeaderView.m
@@ -0,0 +1,85 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+
+#import "JSQMessagesLoadEarlierHeaderView.h"
+
+#import "NSBundle+JSQMessages.h"
+
+
+const CGFloat kJSQMessagesLoadEarlierHeaderViewHeight = 32.0f;
+
+
+@interface JSQMessagesLoadEarlierHeaderView ()
+
+@property (weak, nonatomic) IBOutlet UIButton *loadButton;
+
+@end
+
+
+
+@implementation JSQMessagesLoadEarlierHeaderView
+
+#pragma mark - Class methods
+
++ (UINib *)nib
+{
+    return [UINib nibWithNibName:NSStringFromClass([JSQMessagesLoadEarlierHeaderView class])
+                          bundle:[NSBundle bundleForClass:[JSQMessagesLoadEarlierHeaderView class]]];
+}
+
++ (NSString *)headerReuseIdentifier
+{
+    return NSStringFromClass([JSQMessagesLoadEarlierHeaderView class]);
+}
+
+#pragma mark - Initialization
+
+- (void)awakeFromNib
+{
+    [super awakeFromNib];
+    [self setTranslatesAutoresizingMaskIntoConstraints:NO];
+
+    self.backgroundColor = [UIColor clearColor];
+
+    [self.loadButton setTitle:[NSBundle jsq_localizedStringForKey:@"load_earlier_messages"] forState:UIControlStateNormal];
+    self.loadButton.titleLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
+}
+
+- (void)dealloc
+{
+    _loadButton = nil;
+    _delegate = nil;
+}
+
+#pragma mark - Reusable view
+
+- (void)setBackgroundColor:(UIColor *)backgroundColor
+{
+    [super setBackgroundColor:backgroundColor];
+    self.loadButton.backgroundColor = backgroundColor;
+}
+
+#pragma mark - Actions
+
+- (IBAction)loadButtonPressed:(UIButton *)sender
+{
+    [self.delegate headerView:self didPressLoadButton:sender];
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesLoadEarlierHeaderView.xib b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesLoadEarlierHeaderView.xib
new file mode 100644
index 0000000..e705e46
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesLoadEarlierHeaderView.xib
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9531" systemVersion="15C50" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES">
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9529"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <collectionReusableView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="JSQMessagesLoadEarlierHeaderView" id="0Ms-a6-YUP" customClass="JSQMessagesLoadEarlierHeaderView">
+            <rect key="frame" x="0.0" y="0.0" width="320" height="32"/>
+            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
+            <subviews>
+                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="kM4-IZ-dgW">
+                    <rect key="frame" x="0.0" y="0.0" width="320" height="32"/>
+                    <state key="normal" title="Button">
+                        <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
+                    </state>
+                    <connections>
+                        <action selector="loadButtonPressed:" destination="0Ms-a6-YUP" eventType="touchUpInside" id="TLB-Fi-7pI"/>
+                    </connections>
+                </button>
+            </subviews>
+            <constraints>
+                <constraint firstAttribute="bottom" secondItem="kM4-IZ-dgW" secondAttribute="bottom" id="HWq-c5-fxo"/>
+                <constraint firstItem="kM4-IZ-dgW" firstAttribute="leading" secondItem="0Ms-a6-YUP" secondAttribute="leading" id="OEX-iw-1Sy"/>
+                <constraint firstAttribute="trailing" secondItem="kM4-IZ-dgW" secondAttribute="trailing" id="Ori-kw-SaU"/>
+                <constraint firstItem="kM4-IZ-dgW" firstAttribute="top" secondItem="0Ms-a6-YUP" secondAttribute="top" id="zUW-1v-N5P"/>
+            </constraints>
+            <connections>
+                <outlet property="loadButton" destination="kM4-IZ-dgW" id="86m-Lw-zNd"/>
+            </connections>
+        </collectionReusableView>
+    </objects>
+</document>
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesMediaPlaceholderView.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesMediaPlaceholderView.h
new file mode 100644
index 0000000..81425f2
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesMediaPlaceholderView.h
@@ -0,0 +1,92 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+/**
+ *  A `JSQMessagesMediaPlaceholderView` object represents a loading or placeholder
+ *  view for media message objects whose media attachments are not yet available. 
+ *  When sending or receiving media messages that must be uploaded or downloaded from the network,
+ *  you may display this view temporarily until the media attachement is available.
+ *  You should return an instance of this class from the `mediaPlaceholderView` method in
+ *  the `JSQMessageMediaData` protocol.
+ *
+ *  @see JSQMessageMediaData.
+ */
+@interface JSQMessagesMediaPlaceholderView : UIView
+
+/**
+ *  Returns the activity indicator view for this placeholder view, or `nil` if it does not exist.
+ */
+@property (nonatomic, weak, readonly) UIActivityIndicatorView *activityIndicatorView;
+
+/**
+ *  Returns the image view for this placeholder view, or `nil` if it does not exist.
+ */
+@property (nonatomic, weak, readonly) UIImageView *imageView;
+
+/**
+ *  Creates a media placeholder view object with a light gray background and
+ *  a centered activity indicator.
+ *
+ *  @discussion When initializing a `JSQMessagesMediaPlaceholderView` with this method,
+ *  its imageView property will be nil.
+ *
+ *  @return An initialized `JSQMessagesMediaPlaceholderView` object if successful, `nil` otherwise.
+ */
++ (instancetype)viewWithActivityIndicator;
+
+/**
+ *  Creates a media placeholder view object with a light gray background and
+ *  a centered paperclip attachment icon.
+ *
+ *  @discussion When initializing a `JSQMessagesMediaPlaceholderView` with this method,
+ *  its activityIndicatorView property will be nil.
+ *
+ *  @return An initialized `JSQMessagesMediaPlaceholderView` object if successful, `nil` otherwise.
+ */
++ (instancetype)viewWithAttachmentIcon;
+
+/**
+ *  Creates a media placeholder view having the given frame, backgroundColor, and activityIndicatorView.
+ *
+ *  @param frame                 A rectangle defining the frame of the view. This value must be a non-zero, non-null rectangle.
+ *  @param backgroundColor       The background color of the view. This value must not be `nil`.
+ *  @param activityIndicatorView An initialized activity indicator to be added and centered in the view. This value must not be `nil`.
+ *
+ *  @return An initialized `JSQMessagesMediaPlaceholderView` object if successful, `nil` otherwise.
+ */
+- (instancetype)initWithFrame:(CGRect)frame
+              backgroundColor:(UIColor *)backgroundColor
+        activityIndicatorView:(UIActivityIndicatorView *)activityIndicatorView;
+
+/**
+ *  Creates a media placeholder view having the given frame, backgroundColor, and imageView.
+ *
+ *  @param frame           A rectangle defining the frame of the view. This value must be a non-zero, non-null rectangle.
+ *  @param backgroundColor The background color of the view. This value must not be `nil`.
+ *  @param imageView       An initialized image view to be added and centered in the view. This value must not be `nil`.
+ *
+ *  @return An initialized `JSQMessagesMediaPlaceholderView` object if successful, `nil` otherwise.
+ */
+- (instancetype)initWithFrame:(CGRect)frame
+              backgroundColor:(UIColor *)backgroundColor
+                    imageView:(UIImageView *)imageView;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesMediaPlaceholderView.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesMediaPlaceholderView.m
new file mode 100644
index 0000000..fb9354b
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesMediaPlaceholderView.m
@@ -0,0 +1,116 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQMessagesMediaPlaceholderView.h"
+
+#import "UIColor+JSQMessages.h"
+#import "UIImage+JSQMessages.h"
+
+
+@implementation JSQMessagesMediaPlaceholderView
+
+#pragma mark - Init
+
++ (instancetype)viewWithActivityIndicator
+{
+    UIColor *lightGrayColor = [UIColor jsq_messageBubbleLightGrayColor];
+    UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
+    spinner.color = [lightGrayColor jsq_colorByDarkeningColorWithValue:0.4f];
+    
+    JSQMessagesMediaPlaceholderView *view = [[JSQMessagesMediaPlaceholderView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 200.0f, 120.0f)
+                                                                                   backgroundColor:lightGrayColor
+                                                                             activityIndicatorView:spinner];
+    return view;
+}
+
++ (instancetype)viewWithAttachmentIcon
+{
+    UIColor *lightGrayColor = [UIColor jsq_messageBubbleLightGrayColor];
+    UIImage *paperclip = [[UIImage jsq_defaultAccessoryImage] jsq_imageMaskedWithColor:[lightGrayColor jsq_colorByDarkeningColorWithValue:0.4f]];
+    UIImageView *imageView = [[UIImageView alloc] initWithImage:paperclip];
+    
+    JSQMessagesMediaPlaceholderView *view =[[JSQMessagesMediaPlaceholderView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 200.0f, 120.0f)
+                                                                                  backgroundColor:lightGrayColor
+                                                                                        imageView:imageView];
+    return view;
+}
+
+- (instancetype)initWithFrame:(CGRect)frame
+              backgroundColor:(UIColor *)backgroundColor
+        activityIndicatorView:(UIActivityIndicatorView *)activityIndicatorView
+{
+    NSParameterAssert(activityIndicatorView != nil);
+    
+    self = [self initWithFrame:frame backgroundColor:backgroundColor];
+    if (self) {
+        [self addSubview:activityIndicatorView];
+        _activityIndicatorView = activityIndicatorView;
+        _activityIndicatorView.center = self.center;
+        [_activityIndicatorView startAnimating];
+        _imageView = nil;
+    }
+    return self;
+}
+
+- (instancetype)initWithFrame:(CGRect)frame
+              backgroundColor:(UIColor *)backgroundColor
+                    imageView:(UIImageView *)imageView
+{
+    NSParameterAssert(imageView != nil);
+    
+    self = [self initWithFrame:frame backgroundColor:backgroundColor];
+    if (self) {
+        [self addSubview:imageView];
+        _imageView = imageView;
+        _imageView.center = self.center;
+        _activityIndicatorView = nil;
+    }
+    return self;
+}
+
+- (instancetype)initWithFrame:(CGRect)frame backgroundColor:(UIColor *)backgroundColor
+{
+    NSParameterAssert(!CGRectEqualToRect(frame, CGRectNull));
+    NSParameterAssert(!CGRectEqualToRect(frame, CGRectZero));
+    NSParameterAssert(backgroundColor != nil);
+    
+    self = [super initWithFrame:frame];
+    if (self) {
+        self.backgroundColor = backgroundColor;
+        self.userInteractionEnabled = NO;
+        self.clipsToBounds = YES;
+        self.contentMode = UIViewContentModeScaleAspectFill;
+    }
+    return self;
+}
+
+#pragma mark - Layout
+
+- (void)layoutSubviews
+{
+    [super layoutSubviews];
+    
+    if (self.activityIndicatorView) {
+        self.activityIndicatorView.center = self.center;
+    }
+    else if (self.imageView) {
+        self.imageView.center = self.center;
+    }
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesToolbarContentView.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesToolbarContentView.h
new file mode 100644
index 0000000..94d6c81
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesToolbarContentView.h
@@ -0,0 +1,124 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+#import "JSQMessagesComposerTextView.h"
+
+/**
+ *  A constant value representing the default spacing to use for the left and right edges 
+ *  of the toolbar content view.
+ */
+FOUNDATION_EXPORT const CGFloat kJSQMessagesToolbarContentViewHorizontalSpacingDefault;
+
+/**
+ *  A `JSQMessagesToolbarContentView` represents the content displayed in a `JSQMessagesInputToolbar`.
+ *  These subviews consist of a left button, a text view, and a right button. One button is used as
+ *  the send button, and the other as the accessory button. The text view is used for composing messages.
+ */
+@interface JSQMessagesToolbarContentView : UIView
+
+/**
+ *  Returns the text view in which the user composes a message.
+ */
+@property (weak, nonatomic, readonly) JSQMessagesComposerTextView *textView;
+
+/**
+ *  A custom button item displayed on the left of the toolbar content view.
+ *
+ *  @discussion The frame height of this button is ignored. When you set this property, the button
+ *  is fitted within a pre-defined default content view, the leftBarButtonContainerView,
+ *  whose height is determined by the height of the toolbar. However, the width of this button
+ *  will be preserved. You may specify a new width using `leftBarButtonItemWidth`.
+ *  If the frame of this button is equal to `CGRectZero` when set, then a default frame size will be used.
+ *  Set this value to `nil` to remove the button.
+ */
+@property (weak, nonatomic) UIButton *leftBarButtonItem;
+
+/**
+ *  Specifies the width of the leftBarButtonItem.
+ *
+ *  @discussion This property modifies the width of the leftBarButtonContainerView.
+ */
+@property (assign, nonatomic) CGFloat leftBarButtonItemWidth;
+
+/**
+ *  Specifies the amount of spacing between the content view and the leading edge of leftBarButtonItem.
+ *
+ *  @discussion The default value is `8.0f`.
+ */
+@property (assign, nonatomic) CGFloat leftContentPadding;
+
+/**
+ *  The container view for the leftBarButtonItem.
+ *
+ *  @discussion
+ *  You may use this property to add additional button items to the left side of the toolbar content view.
+ *  However, you will be completely responsible for responding to all touch events for these buttons
+ *  in your `JSQMessagesViewController` subclass.
+ */
+@property (weak, nonatomic, readonly) UIView *leftBarButtonContainerView;
+
+/**
+ *  A custom button item displayed on the right of the toolbar content view.
+ *
+ *  @discussion The frame height of this button is ignored. When you set this property, the button
+ *  is fitted within a pre-defined default content view, the rightBarButtonContainerView,
+ *  whose height is determined by the height of the toolbar. However, the width of this button
+ *  will be preserved. You may specify a new width using `rightBarButtonItemWidth`.
+ *  If the frame of this button is equal to `CGRectZero` when set, then a default frame size will be used.
+ *  Set this value to `nil` to remove the button.
+ */
+@property (weak, nonatomic) UIButton *rightBarButtonItem;
+
+/**
+ *  Specifies the width of the rightBarButtonItem.
+ *
+ *  @discussion This property modifies the width of the rightBarButtonContainerView.
+ */
+@property (assign, nonatomic) CGFloat rightBarButtonItemWidth;
+
+/**
+ *  Specifies the amount of spacing between the content view and the trailing edge of rightBarButtonItem.
+ *
+ *  @discussion The default value is `8.0f`.
+ */
+@property (assign, nonatomic) CGFloat rightContentPadding;
+
+/**
+ *  The container view for the rightBarButtonItem.
+ *
+ *  @discussion 
+ *  You may use this property to add additional button items to the right side of the toolbar content view.
+ *  However, you will be completely responsible for responding to all touch events for these buttons
+ *  in your `JSQMessagesViewController` subclass.
+ */
+@property (weak, nonatomic, readonly) UIView *rightBarButtonContainerView;
+
+#pragma mark - Class methods
+
+/**
+ *  Returns the `UINib` object initialized for a `JSQMessagesToolbarContentView`.
+ *
+ *  @return The initialized `UINib` object or `nil` if there were errors during
+ *  initialization or the nib file could not be located.
+ */
++ (UINib *)nib;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesToolbarContentView.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesToolbarContentView.m
new file mode 100644
index 0000000..1a7bb48
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesToolbarContentView.m
@@ -0,0 +1,192 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQMessagesToolbarContentView.h"
+
+#import "UIView+JSQMessages.h"
+
+const CGFloat kJSQMessagesToolbarContentViewHorizontalSpacingDefault = 8.0f;
+
+
+@interface JSQMessagesToolbarContentView ()
+
+@property (weak, nonatomic) IBOutlet JSQMessagesComposerTextView *textView;
+
+@property (weak, nonatomic) IBOutlet UIView *leftBarButtonContainerView;
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *leftBarButtonContainerViewWidthConstraint;
+
+@property (weak, nonatomic) IBOutlet UIView *rightBarButtonContainerView;
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *rightBarButtonContainerViewWidthConstraint;
+
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *leftHorizontalSpacingConstraint;
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *rightHorizontalSpacingConstraint;
+
+@end
+
+
+
+@implementation JSQMessagesToolbarContentView
+
+#pragma mark - Class methods
+
++ (UINib *)nib
+{
+    return [UINib nibWithNibName:NSStringFromClass([JSQMessagesToolbarContentView class])
+                          bundle:[NSBundle bundleForClass:[JSQMessagesToolbarContentView class]]];
+}
+
+#pragma mark - Initialization
+
+- (void)awakeFromNib
+{
+    [super awakeFromNib];
+
+    [self setTranslatesAutoresizingMaskIntoConstraints:NO];
+
+    self.leftHorizontalSpacingConstraint.constant = kJSQMessagesToolbarContentViewHorizontalSpacingDefault;
+    self.rightHorizontalSpacingConstraint.constant = kJSQMessagesToolbarContentViewHorizontalSpacingDefault;
+
+    self.backgroundColor = [UIColor clearColor];
+}
+
+#pragma mark - Setters
+
+- (void)setBackgroundColor:(UIColor *)backgroundColor
+{
+    [super setBackgroundColor:backgroundColor];
+    self.leftBarButtonContainerView.backgroundColor = backgroundColor;
+    self.rightBarButtonContainerView.backgroundColor = backgroundColor;
+}
+
+- (void)setLeftBarButtonItem:(UIButton *)leftBarButtonItem
+{
+    if (_leftBarButtonItem) {
+        [_leftBarButtonItem removeFromSuperview];
+    }
+
+    if (!leftBarButtonItem) {
+        _leftBarButtonItem = nil;
+        self.leftHorizontalSpacingConstraint.constant = 0.0f;
+        self.leftBarButtonItemWidth = 0.0f;
+        self.leftBarButtonContainerView.hidden = YES;
+        return;
+    }
+
+    if (CGRectEqualToRect(leftBarButtonItem.frame, CGRectZero)) {
+        leftBarButtonItem.frame = self.leftBarButtonContainerView.bounds;
+    }
+
+    self.leftBarButtonContainerView.hidden = NO;
+    self.leftHorizontalSpacingConstraint.constant = kJSQMessagesToolbarContentViewHorizontalSpacingDefault;
+    self.leftBarButtonItemWidth = CGRectGetWidth(leftBarButtonItem.frame);
+
+    [leftBarButtonItem setTranslatesAutoresizingMaskIntoConstraints:NO];
+
+    [self.leftBarButtonContainerView addSubview:leftBarButtonItem];
+    [self.leftBarButtonContainerView jsq_pinAllEdgesOfSubview:leftBarButtonItem];
+    [self setNeedsUpdateConstraints];
+
+    _leftBarButtonItem = leftBarButtonItem;
+}
+
+- (void)setLeftBarButtonItemWidth:(CGFloat)leftBarButtonItemWidth
+{
+    self.leftBarButtonContainerViewWidthConstraint.constant = leftBarButtonItemWidth;
+    [self setNeedsUpdateConstraints];
+}
+
+- (void)setRightBarButtonItem:(UIButton *)rightBarButtonItem
+{
+    if (_rightBarButtonItem) {
+        [_rightBarButtonItem removeFromSuperview];
+    }
+
+    if (!rightBarButtonItem) {
+        _rightBarButtonItem = nil;
+        self.rightHorizontalSpacingConstraint.constant = 0.0f;
+        self.rightBarButtonItemWidth = 0.0f;
+        self.rightBarButtonContainerView.hidden = YES;
+        return;
+    }
+
+    if (CGRectEqualToRect(rightBarButtonItem.frame, CGRectZero)) {
+        rightBarButtonItem.frame = self.rightBarButtonContainerView.bounds;
+    }
+
+    self.rightBarButtonContainerView.hidden = NO;
+    self.rightHorizontalSpacingConstraint.constant = kJSQMessagesToolbarContentViewHorizontalSpacingDefault;
+    self.rightBarButtonItemWidth = CGRectGetWidth(rightBarButtonItem.frame);
+
+    [rightBarButtonItem setTranslatesAutoresizingMaskIntoConstraints:NO];
+
+    [self.rightBarButtonContainerView addSubview:rightBarButtonItem];
+    [self.rightBarButtonContainerView jsq_pinAllEdgesOfSubview:rightBarButtonItem];
+    [self setNeedsUpdateConstraints];
+
+    _rightBarButtonItem = rightBarButtonItem;
+}
+
+- (void)setRightBarButtonItemWidth:(CGFloat)rightBarButtonItemWidth
+{
+    self.rightBarButtonContainerViewWidthConstraint.constant = rightBarButtonItemWidth;
+    [self setNeedsUpdateConstraints];
+}
+
+- (void)setRightContentPadding:(CGFloat)rightContentPadding
+{
+    self.rightHorizontalSpacingConstraint.constant = rightContentPadding;
+    [self setNeedsUpdateConstraints];
+}
+
+- (void)setLeftContentPadding:(CGFloat)leftContentPadding
+{
+    self.leftHorizontalSpacingConstraint.constant = leftContentPadding;
+    [self setNeedsUpdateConstraints];
+}
+
+#pragma mark - Getters
+
+- (CGFloat)leftBarButtonItemWidth
+{
+    return self.leftBarButtonContainerViewWidthConstraint.constant;
+}
+
+- (CGFloat)rightBarButtonItemWidth
+{
+    return self.rightBarButtonContainerViewWidthConstraint.constant;
+}
+
+- (CGFloat)rightContentPadding
+{
+    return self.rightHorizontalSpacingConstraint.constant;
+}
+
+- (CGFloat)leftContentPadding
+{
+    return self.leftHorizontalSpacingConstraint.constant;
+}
+
+#pragma mark - UIView overrides
+
+- (void)setNeedsDisplay
+{
+    [super setNeedsDisplay];
+    [self.textView setNeedsDisplay];
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesToolbarContentView.xib b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesToolbarContentView.xib
new file mode 100644
index 0000000..500a0a8
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesToolbarContentView.xib
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9531" systemVersion="15C50" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES">
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9529"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <view contentMode="scaleToFill" id="1" customClass="JSQMessagesToolbarContentView">
+            <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
+            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+            <subviews>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="LEq-G7-jGt" userLabel="Left button container">
+                    <rect key="frame" x="8" y="6" width="34" height="32"/>
+                    <color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="32" id="0sE-GV-joM"/>
+                        <constraint firstAttribute="width" constant="34" id="eMy-Af-wwH"/>
+                    </constraints>
+                </view>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Myo-1S-Vg1" userLabel="Right button container">
+                    <rect key="frame" x="262" y="6" width="50" height="32"/>
+                    <color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="32" id="NaR-re-dJ4"/>
+                        <constraint firstAttribute="width" constant="50" id="yde-S9-dHe"/>
+                    </constraints>
+                </view>
+                <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="dm4-NT-mvr" customClass="JSQMessagesComposerTextView">
+                    <rect key="frame" x="50" y="7" width="204" height="30"/>
+                    <color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
+                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                    <textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
+                </textView>
+            </subviews>
+            <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+            <constraints>
+                <constraint firstItem="Myo-1S-Vg1" firstAttribute="leading" secondItem="dm4-NT-mvr" secondAttribute="trailing" constant="8" id="7Ld-5r-Hp3"/>
+                <constraint firstItem="dm4-NT-mvr" firstAttribute="top" secondItem="1" secondAttribute="top" constant="7" id="9Tz-Wq-xIf"/>
+                <constraint firstAttribute="bottom" secondItem="dm4-NT-mvr" secondAttribute="bottom" constant="7" id="CCb-V7-yek"/>
+                <constraint firstAttribute="bottom" secondItem="Myo-1S-Vg1" secondAttribute="bottom" constant="6" id="EaS-Oq-Qp5"/>
+                <constraint firstItem="LEq-G7-jGt" firstAttribute="leading" secondItem="1" secondAttribute="leading" constant="8" id="LAU-fo-GJJ"/>
+                <constraint firstAttribute="trailing" secondItem="Myo-1S-Vg1" secondAttribute="trailing" constant="8" id="ds6-61-GNv"/>
+                <constraint firstAttribute="bottom" secondItem="LEq-G7-jGt" secondAttribute="bottom" constant="6" id="oG2-YD-ZZI"/>
+                <constraint firstItem="dm4-NT-mvr" firstAttribute="leading" secondItem="LEq-G7-jGt" secondAttribute="trailing" constant="8" id="owo-gB-gyR"/>
+            </constraints>
+            <nil key="simulatedStatusBarMetrics"/>
+            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+            <connections>
+                <outlet property="leftBarButtonContainerView" destination="LEq-G7-jGt" id="F0V-4N-1Mo"/>
+                <outlet property="leftBarButtonContainerViewWidthConstraint" destination="eMy-Af-wwH" id="FI9-F2-2bN"/>
+                <outlet property="leftHorizontalSpacingConstraint" destination="LAU-fo-GJJ" id="X2c-BI-0Q4"/>
+                <outlet property="rightBarButtonContainerView" destination="Myo-1S-Vg1" id="0SR-cw-EkD"/>
+                <outlet property="rightBarButtonContainerViewWidthConstraint" destination="yde-S9-dHe" id="WGu-df-M3L"/>
+                <outlet property="rightHorizontalSpacingConstraint" destination="ds6-61-GNv" id="ZQh-8M-QFs"/>
+                <outlet property="textView" destination="dm4-NT-mvr" id="PFw-HO-oT8"/>
+            </connections>
+            <point key="canvasLocation" x="268" y="548"/>
+        </view>
+    </objects>
+</document>
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesTypingIndicatorFooterView.h b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesTypingIndicatorFooterView.h
new file mode 100644
index 0000000..dcd1bb8
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesTypingIndicatorFooterView.h
@@ -0,0 +1,67 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+/**
+ *  A constant defining the default height of a `JSQMessagesTypingIndicatorFooterView`.
+ */
+FOUNDATION_EXPORT const CGFloat kJSQMessagesTypingIndicatorFooterViewHeight;
+
+/**
+ *  The `JSQMessagesTypingIndicatorFooterView` class implements a reusable view that can be placed
+ *  at the bottom of a `JSQMessagesCollectionView`. This view represents a typing indicator 
+ *  for incoming messages.
+ */
+@interface JSQMessagesTypingIndicatorFooterView : UICollectionReusableView
+
+#pragma mark - Class methods
+
+/**
+ *  Returns the `UINib` object initialized for the collection reusable view.
+ *
+ *  @return The initialized `UINib` object or `nil` if there were errors during
+ *  initialization or the nib file could not be located.
+ */
++ (UINib *)nib;
+
+/**
+ *  Returns the default string used to identify the reusable footer view.
+ *
+ *  @return The string used to identify the reusable footer view.
+ */
++ (NSString *)footerReuseIdentifier;
+
+#pragma mark - Typing indicator
+
+/**
+ *  Configures the receiver with the specified attributes for the given collection view. 
+ *  Call this method after dequeuing the footer view.
+ *
+ *  @param ellipsisColor       The color of the typing indicator ellipsis. This value must not be `nil`.
+ *  @param messageBubbleColor  The color of the typing indicator message bubble. This value must not be `nil`.
+ *  @param shouldDisplayOnLeft Specifies whether the typing indicator displays on the left or right side of the collection view when displayed.
+ *  @param collectionView      The collection view in which the footer view will appear. This value must not be `nil`.
+ */
+- (void)configureWithEllipsisColor:(UIColor *)ellipsisColor
+                messageBubbleColor:(UIColor *)messageBubbleColor
+               shouldDisplayOnLeft:(BOOL)shouldDisplayOnLeft
+                 forCollectionView:(UICollectionView *)collectionView;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesTypingIndicatorFooterView.m b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesTypingIndicatorFooterView.m
new file mode 100644
index 0000000..0f0a1a3
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesTypingIndicatorFooterView.m
@@ -0,0 +1,115 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQMessagesViewController
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQMessagesViewController
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQMessagesTypingIndicatorFooterView.h"
+
+#import "JSQMessagesBubbleImageFactory.h"
+
+#import "UIImage+JSQMessages.h"
+
+const CGFloat kJSQMessagesTypingIndicatorFooterViewHeight = 46.0f;
+
+
+@interface JSQMessagesTypingIndicatorFooterView ()
+
+@property (weak, nonatomic) IBOutlet UIImageView *bubbleImageView;
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *bubbleImageViewRightHorizontalConstraint;
+
+@property (weak, nonatomic) IBOutlet UIImageView *typingIndicatorImageView;
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *typingIndicatorImageViewRightHorizontalConstraint;
+
+@end
+
+
+
+@implementation JSQMessagesTypingIndicatorFooterView
+
+#pragma mark - Class methods
+
++ (UINib *)nib
+{
+    return [UINib nibWithNibName:NSStringFromClass([JSQMessagesTypingIndicatorFooterView class])
+                          bundle:[NSBundle bundleForClass:[JSQMessagesTypingIndicatorFooterView class]]];
+}
+
++ (NSString *)footerReuseIdentifier
+{
+    return NSStringFromClass([JSQMessagesTypingIndicatorFooterView class]);
+}
+
+#pragma mark - Initialization
+
+- (void)awakeFromNib
+{
+    [super awakeFromNib];
+    [self setTranslatesAutoresizingMaskIntoConstraints:NO];
+    self.backgroundColor = [UIColor clearColor];
+    self.userInteractionEnabled = NO;
+    self.typingIndicatorImageView.contentMode = UIViewContentModeScaleAspectFit;
+}
+
+#pragma mark - Reusable view
+
+- (void)setBackgroundColor:(UIColor *)backgroundColor
+{
+    [super setBackgroundColor:backgroundColor];
+    self.bubbleImageView.backgroundColor = backgroundColor;
+}
+
+#pragma mark - Typing indicator
+
+- (void)configureWithEllipsisColor:(UIColor *)ellipsisColor
+                messageBubbleColor:(UIColor *)messageBubbleColor
+               shouldDisplayOnLeft:(BOOL)shouldDisplayOnLeft
+                 forCollectionView:(UICollectionView *)collectionView
+{
+    NSParameterAssert(ellipsisColor != nil);
+    NSParameterAssert(messageBubbleColor != nil);
+    NSParameterAssert(collectionView != nil);
+    
+    CGFloat bubbleMarginMinimumSpacing = 6.0f;
+    CGFloat indicatorMarginMinimumSpacing = 26.0f;
+    
+    JSQMessagesBubbleImageFactory *bubbleImageFactory = [[JSQMessagesBubbleImageFactory alloc] init];
+    
+    if (shouldDisplayOnLeft) {
+        self.bubbleImageView.image = [bubbleImageFactory incomingMessagesBubbleImageWithColor:messageBubbleColor].messageBubbleImage;
+        
+        CGFloat collectionViewWidth = CGRectGetWidth(collectionView.frame);
+        CGFloat bubbleWidth = CGRectGetWidth(self.bubbleImageView.frame);
+        CGFloat indicatorWidth = CGRectGetWidth(self.typingIndicatorImageView.frame);
+        
+        CGFloat bubbleMarginMaximumSpacing = collectionViewWidth - bubbleWidth - bubbleMarginMinimumSpacing;
+        CGFloat indicatorMarginMaximumSpacing = collectionViewWidth - indicatorWidth - indicatorMarginMinimumSpacing;
+        
+        self.bubbleImageViewRightHorizontalConstraint.constant = bubbleMarginMaximumSpacing;
+        self.typingIndicatorImageViewRightHorizontalConstraint.constant = indicatorMarginMaximumSpacing;
+    }
+    else {
+        self.bubbleImageView.image = [bubbleImageFactory outgoingMessagesBubbleImageWithColor:messageBubbleColor].messageBubbleImage;
+        
+        self.bubbleImageViewRightHorizontalConstraint.constant = bubbleMarginMinimumSpacing;
+        self.typingIndicatorImageViewRightHorizontalConstraint.constant = indicatorMarginMinimumSpacing;
+    }
+    
+    [self setNeedsUpdateConstraints];
+    
+    self.typingIndicatorImageView.image = [[UIImage jsq_defaultTypingIndicatorImage] jsq_imageMaskedWithColor:ellipsisColor];
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesTypingIndicatorFooterView.xib b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesTypingIndicatorFooterView.xib
new file mode 100644
index 0000000..3df3b41
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesTypingIndicatorFooterView.xib
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9531" systemVersion="15C50" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES">
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9529"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <collectionReusableView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="JSQMessagesTypingIndicatorFooterView" id="ajJ-uk-b04" customClass="JSQMessagesTypingIndicatorFooterView">
+            <rect key="frame" x="0.0" y="0.0" width="320" height="46"/>
+            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
+            <subviews>
+                <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Z1D-Tr-HPK" userLabel="Bubble Image View">
+                    <rect key="frame" x="6" y="6" width="68" height="34"/>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="34" id="365-TI-0fL"/>
+                        <constraint firstAttribute="width" constant="68" id="nS4-br-DxL"/>
+                    </constraints>
+                </imageView>
+                <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Vwf-dy-PS6" userLabel="Ellipsis Image View">
+                    <rect key="frame" x="26" y="6" width="34" height="34"/>
+                    <constraints>
+                        <constraint firstAttribute="width" constant="34" id="CMT-z0-hca"/>
+                        <constraint firstAttribute="height" constant="34" id="j0C-FV-2gV"/>
+                    </constraints>
+                </imageView>
+            </subviews>
+            <constraints>
+                <constraint firstAttribute="trailing" secondItem="Vwf-dy-PS6" secondAttribute="trailing" constant="260" id="1Tm-qD-wIK"/>
+                <constraint firstAttribute="bottom" secondItem="Z1D-Tr-HPK" secondAttribute="bottom" constant="6" id="EVf-Sx-8mX"/>
+                <constraint firstAttribute="bottom" secondItem="Vwf-dy-PS6" secondAttribute="bottom" constant="6" id="Hik-Wl-aK2"/>
+                <constraint firstAttribute="trailing" secondItem="Z1D-Tr-HPK" secondAttribute="trailing" constant="246" id="YMl-ej-UZl"/>
+            </constraints>
+            <connections>
+                <outlet property="bubbleImageView" destination="Z1D-Tr-HPK" id="WpE-rP-oYB"/>
+                <outlet property="bubbleImageViewRightHorizontalConstraint" destination="YMl-ej-UZl" id="Thu-7D-dhU"/>
+                <outlet property="typingIndicatorImageView" destination="Vwf-dy-PS6" id="wQA-Pe-rx6"/>
+                <outlet property="typingIndicatorImageViewRightHorizontalConstraint" destination="1Tm-qD-wIK" id="FUp-oC-c0I"/>
+            </connections>
+        </collectionReusableView>
+    </objects>
+</document>
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/LICENSE b/whiskbot-demo-app/Pods/JSQMessagesViewController/LICENSE
new file mode 100644
index 0000000..e7a4b01
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/LICENSE
@@ -0,0 +1,20 @@
+
+MIT License
+Copyright (c) 2013-present Jesse Squires
+
+http://www.jessesquires.com
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
+following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
+LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/whiskbot-demo-app/Pods/JSQMessagesViewController/README.md b/whiskbot-demo-app/Pods/JSQMessagesViewController/README.md
new file mode 100644
index 0000000..4d699c3
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQMessagesViewController/README.md
@@ -0,0 +1,104 @@
+![JSQMessagesViewController banner](https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Assets/jsq_messages_banner.png)
+
+[![Build Status](https://secure.travis-ci.org/jessesquires/JSQMessagesViewController.svg)](https://travis-ci.org/jessesquires/JSQMessagesViewController) [![Version Status](https://img.shields.io/cocoapods/v/JSQMessagesViewController.svg)][podLink] [![license MIT](https://img.shields.io/cocoapods/l/JSQMessagesViewController.svg)][mitLink] [![codecov](https://codecov.io/gh/jessesquires/JSQMessagesViewController/branch/develop/graph/badge.svg)](https://codecov.io/gh/jessesquires/JSQMessagesViewController) [![Platform](https://img.shields.io/cocoapods/p/JSQMessagesViewController.svg)][docsLink]
+
+![Screenshot0][img0] &nbsp;&nbsp; ![Screenshot1][img1] &nbsp;&nbsp;
+
+![Screenshot2][img2] &nbsp;&nbsp; ![Screenshot3][img3]
+
+> More screenshots available at [CocoaControls](https://www.cocoacontrols.com/controls/jsqmessagesviewcontroller)
+
+## Features
+
+See the [website](http://www.jessesquires.com/JSQMessagesViewController/) for the list of features.
+
+## Design Goals
+
+- Closely mimic the [iOS Messages](http://www.apple.com/ios/messages/) style and behavior
+- [SOLID](https://en.wikipedia.org/wiki/SOLID_(object-oriented_design)) design
+- Easy customization and extension for clients
+
+## Dependencies
+
+* [JSQSystemSoundPlayer][playerLink]
+
+## Requirements
+
+* iOS 7.0+
+* ARC
+
+## Installation
+
+### [CocoaPods](https://cocoapods.org/) (recommended)
+
+````ruby
+# For latest release in cocoapods
+pod 'JSQMessagesViewController'
+
+# Latest on develop
+pod 'JSQMessagesViewController', :git => 'https://github.com/jessesquires/JSQMessagesViewController.git', :branch => 'develop'
+
+# For version 5.3.2
+pod 'JSQMessagesViewController', :git => 'https://github.com/jessesquires/JSQMessagesViewController', :branch => 'version_5.3.2_patch'
+````
+
+## Getting Started
+
+See the [Getting Started](https://github.com/jessesquires/JSQMessagesViewController/blob/develop/Documentation/getting_started.md) guide!
+
+## Questions & Help
+
+* Review the [FAQ](https://github.com/jessesquires/JSQMessagesViewController/blob/develop/Documentation/faq.md).
+* Search issues for previous and current [questions](https://github.com/jessesquires/JSQMessagesViewController/issues?utf8=✓&q=label%3A%22questions+%26+help%22+). *Do not open duplicates.*
+* [StackOverflow](http://stackoverflow.com/questions/tagged/jsqmessagesviewcontroller) is often the most appropriate place for questions and help. We have our own tag, `jsqmessagesviewcontroller`.
+* See the [Migration Guide](https://github.com/jessesquires/JSQMessagesViewController/blob/develop/Documentation/migration.md) for migrating between major versions of the library.
+* **Only ask questions that are _specific_ to this library.**
+* **Please avoid emailing questions.** I prefer to keep questions and their answers open-source.
+
+## Documentation
+
+Read the docs, [available here][docsLink] via [@CocoaDocs](https://twitter.com/CocoaDocs).
+
+## Core team
+
+- Jesse Squires ([**@jesse_squires**](https://twitter.com/jesse_squires))
+- Harlan Haskans ([**@harlanhaskins**](https://github.com/harlanhaskins))
+- Eli Burke ([**@eliburke**](https://github.com/eliburke))
+
+## Contributing
+
+Please follow these sweet [contribution guidelines](https://github.com/jessesquires/JSQMessagesViewController/blob/develop/.github/CONTRIBUTING.md).
+
+> **Interested in becoming a core contributor with push access? See our [onboarding guide](https://github.com/jessesquires/JSQMessagesViewController/blob/develop/Documentation/contributor_onboarding.md) for details.**
+
+## Donate
+
+Support the development of this **free** library! **[Donate](https://cash.me/$jsq)** via [Square Cash](https://cash.me/).
+
+## Credits
+
+* Created and maintained by [**@jesse_squires**](https://twitter.com/jesse_squires).
+* Many thanks to [**the contributors**](https://github.com/jessesquires/JSQMessagesViewController/graphs/contributors) of this project.
+* iOS assets extracted using [**@0xced**](https://github.com/0xced) / [iOS-Artwork-Extractor](https://github.com/0xced/iOS-Artwork-Extractor).
+
+## Apps using this library
+
+According to [CocoaPods stats](https://cocoapods.org/pods/JSQMessagesViewController), over **9,000 apps** are using `JSQMessagesViewController`. [Here are the ones](https://github.com/jessesquires/JSQMessagesViewController/blob/develop/Documentation/apps_using_this_library.md) that we know about. Please submit a [pull request](https://github.com/jessesquires/JSQMessagesViewController/compare) to add your app! :smile:
+
+## License
+
+`JSQMessagesViewController` is released under an [MIT License][mitLink]. See `LICENSE` for details.
+
+>**Copyright &copy; 2013-present Jesse Squires.**
+
+*Please provide attribution, it is greatly appreciated.*
+
+[docsLink]:http://cocoadocs.org/docsets/JSQMessagesViewController/
+[podLink]:https://cocoapods.org/pods/JSQMessagesViewController
+[mitLink]:http://opensource.org/licenses/MIT
+[playerLink]:https://github.com/jessesquires/JSQSystemSoundPlayer
+
+[img0]:https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot0.png
+[img1]:https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot1.png
+[img2]:https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot2.png
+[img3]:https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot3.png
diff --git a/whiskbot-demo-app/Pods/JSQSystemSoundPlayer/JSQSystemSoundPlayer/Classes/JSQSystemSoundPlayer.h b/whiskbot-demo-app/Pods/JSQSystemSoundPlayer/JSQSystemSoundPlayer/Classes/JSQSystemSoundPlayer.h
new file mode 100755
index 0000000..7d4c0d2
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQSystemSoundPlayer/JSQSystemSoundPlayer/Classes/JSQSystemSoundPlayer.h
@@ -0,0 +1,192 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQSystemSoundPlayer
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQSystemSoundPlayer
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import <Foundation/Foundation.h>
+
+/**
+ *  String constant for .caf audio file extension.
+ */
+FOUNDATION_EXPORT NSString * const kJSQSystemSoundTypeCAF;
+
+/**
+ *  String constant for .aif audio file extension.
+ */
+FOUNDATION_EXPORT NSString * const kJSQSystemSoundTypeAIF;
+
+/**
+ *  String constant for .aiff audio file extension.
+ */
+FOUNDATION_EXPORT NSString * const kJSQSystemSoundTypeAIFF;
+
+/**
+ *  String constant for .wav audio file extension.
+ */
+FOUNDATION_EXPORT NSString * const kJSQSystemSoundTypeWAV;
+
+/**
+ *  A completion block to be called after a system sound has finished playing.
+ */
+typedef void(^JSQSystemSoundPlayerCompletionBlock)(void);
+
+/**
+ *  The `JSQSystemSoundPlayer` class enables you to play sound effects, alert sounds, or other short sounds.
+ *  It lazily loads and caches all `SystemSoundID` objects and purges them upon
+ *  receiving the `UIApplicationDidReceiveMemoryWarningNotification` notification.
+ */
+@interface JSQSystemSoundPlayer : NSObject
+
+/**
+ *  Returns whether or not the sound player is on.
+ *  That is, whether the sound player is enabled or disabled.
+ *  If disabled, it will not play sounds.
+ *
+ *  @see `toggleSoundPlayerOn:`
+ */
+@property (assign, nonatomic, readonly) BOOL on;
+
+/**
+ *  The bundle in which the sound player uses to search for sound file resources. You may change this property as needed.
+ *  The default value is the main bundle. This value must not be `nil`.
+ */
+@property (strong, nonatomic) NSBundle *bundle;
+
+/**
+ *  Returns the shared `JSQSystemSoundPlayer` object. This method always returns the same sound system player object.
+ *
+ *  @return An initialized `JSQSystemSoundPlayer` object if successful, `nil` otherwise.
+ */
++ (JSQSystemSoundPlayer *)sharedPlayer;
+
+/**
+ *  Toggles the sound player on or off by setting the `kJSQSystemSoundPlayerUserDefaultsKey` key in `NSUserDefaults` to the given value.
+ *  This will enable or disable the playing of sounds via `JSQSystemSoundPlayer` globally.
+ *  This setting is persisted across application launches.
+ *
+ *  @param on A boolean indicating whether or not to enable or disable the sound player settings.
+ *  Pass `YES` to turn sounds on, and `NO` to turn sounds off.
+ *
+ *  @warning Disabling the sound player (passing a value of `NO`) will invoke the `stopAllSounds` method.
+ */
+- (void)toggleSoundPlayerOn:(BOOL)on;
+
+/**
+ *  Plays a system sound object corresponding to an audio file with the given filename and extension.
+ *  The system sound player will lazily initialize and load the file before playing it, and then cache its corresponding `SystemSoundID`.
+ *  If this file has previously been played, it will be loaded from cache and played immediately.
+ *
+ *  @param filename      A string containing the base name of the audio file to play.
+ *  @param fileExtension A string containing the extension of the audio file to play.
+ *  This parameter must be one of `kJSQSystemSoundTypeCAF`, `kJSQSystemSoundTypeAIF`, `kJSQSystemSoundTypeAIFF`, or `kJSQSystemSoundTypeWAV`.
+ *
+ *  @warning If the system sound object cannot be created, this method does nothing.
+ */
+- (void)playSoundWithFilename:(NSString *)filename fileExtension:(NSString *)fileExtension;
+
+/**
+ *  Plays a system sound object corresponding to an audio file with the given filename and extension,
+ *  and excutes completionBlock when the sound has stopped playing.
+ *  The system sound player will lazily initialize and load the file before playing it, and then cache its corresponding `SystemSoundID`.
+ *  If this file has previously been played, it will be loaded from cache and played immediately.
+ *
+ *  @param filename      A string containing the base name of the audio file to play.
+ *  @param fileExtension A string containing the extension of the audio file to play.
+ *  This parameter must be one of `kJSQSystemSoundTypeCAF`, `kJSQSystemSoundTypeAIF`, `kJSQSystemSoundTypeAIFF`, or `kJSQSystemSoundTypeWAV`.
+ *
+ *  @param completionBlock A block called after the sound has stopped playing.
+ *  This block is retained by `JSQSystemSoundPlayer`, temporarily cached, and released after its execution.
+ *
+ *  @warning If the system sound object cannot be created, this method does nothing.
+ */
+- (void)playSoundWithFilename:(NSString *)filename
+                fileExtension:(NSString *)fileExtension
+                   completion:(JSQSystemSoundPlayerCompletionBlock)completionBlock;
+
+/**
+ *  Plays a system sound object *as an alert* corresponding to an audio file with the given filename and extension.
+ *  The system sound player will lazily initialize and load the file before playing it, and then cache its corresponding `SystemSoundID`.
+ *  If this file has previously been played, it will be loaded from cache and played immediately.
+ *
+ *  @param filename      A string containing the base name of the audio file to play.
+ *  @param fileExtension A string containing the extension of the audio file to play.
+ *  This parameter must be one of `kJSQSystemSoundTypeCAF`, `kJSQSystemSoundTypeAIF`, `kJSQSystemSoundTypeAIFF`, or `kJSQSystemSoundTypeWAV`.
+ *
+ *  @warning If the system sound object cannot be created, this method does nothing.
+ *
+ *  @warning This method performs the same functions as `playSoundWithName: extension:`, with the excepion that,
+ *  depending on the particular iOS device, this method may invoke vibration.
+ */
+- (void)playAlertSoundWithFilename:(NSString *)filename fileExtension:(NSString *)fileExtension;
+
+/**
+ *  Plays a system sound object *as an alert* corresponding to an audio file with the given filename and extension,
+ *  and and excutes completionBlock when the sound has stopped playing.
+ *  The system sound player will lazily initialize and load the file before playing it, and then cache its corresponding `SystemSoundID`.
+ *  If this file has previously been played, it will be loaded from cache and played immediately.
+ *
+ *  @param filename      A string containing the base name of the audio file to play.
+ *  @param fileExtension A string containing the extension of the audio file to play.
+ *  This parameter must be one of `kJSQSystemSoundTypeCAF`, `kJSQSystemSoundTypeAIF`, `kJSQSystemSoundTypeAIFF`, or `kJSQSystemSoundTypeWAV`.
+ *
+ *  @param completionBlock A block called after the sound has stopped playing.
+ *  This block is retained by `JSQSystemSoundPlayer`, temporarily cached, and released after its execution.
+ *
+ *  @warning If the system sound object cannot be created, this method does nothing.
+ *
+ *  @warning This method performs the same functions as `playSoundWithName: extension: completion:`,
+ *  with the excepion that, depending on the particular iOS device, this method may invoke vibration.
+ */
+- (void)playAlertSoundWithFilename:(NSString *)filename
+                     fileExtension:(NSString *)fileExtension
+                        completion:(JSQSystemSoundPlayerCompletionBlock)completionBlock;
+
+/**
+ *  On some iOS devices, you can call this method to invoke vibration.
+ *  On other iOS devices this functionaly is not available, and calling this method does nothing.
+ */
+- (void)playVibrateSound;
+
+/**
+ *  Stops playing all sounds immediately.
+ *
+ *  @warning Any completion blocks attached to any currently playing sound will *not* be executed.
+ *  Also, calling this method will purge all `SystemSoundID` objects from cache, regardless of whether or not they were currently playing.
+ */
+- (void)stopAllSounds;
+
+/**
+ *  Stops playing the sound with the given filename immediately.
+ *
+ *  @param filename The filename of the sound to stop playing.
+ *
+ *  @warning If a completion block is attached to the given sound, it will *not* be executed.
+ *  Also, calling this method will purge the `SystemSoundID` object for this file from cache, regardless of whether or not it was currently playing.
+ */
+- (void)stopSoundWithFilename:(NSString *)filename;
+
+/**
+ *  Preloads a system sound object corresponding to an audio file with the given filename and extension.
+ *  The system sound player will initialize, load, and cache the corresponding `SystemSoundID`.
+ *
+ *  @param filename      A string containing the base name of the audio file to play.
+ *  @param fileExtension A string containing the extension of the audio file to play.
+ *  This parameter must be one of `kJSQSystemSoundTypeCAF`, `kJSQSystemSoundTypeAIF`, `kJSQSystemSoundTypeAIFF`, or `kJSQSystemSoundTypeWAV`.
+ *
+ */
+- (void)preloadSoundWithFilename:(NSString *)filename fileExtension:(NSString *)fileExtension;
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQSystemSoundPlayer/JSQSystemSoundPlayer/Classes/JSQSystemSoundPlayer.m b/whiskbot-demo-app/Pods/JSQSystemSoundPlayer/JSQSystemSoundPlayer/Classes/JSQSystemSoundPlayer.m
new file mode 100755
index 0000000..55e6aa6
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQSystemSoundPlayer/JSQSystemSoundPlayer/Classes/JSQSystemSoundPlayer.m
@@ -0,0 +1,400 @@
+//
+//  Created by Jesse Squires
+//  http://www.jessesquires.com
+//
+//
+//  Documentation
+//  http://cocoadocs.org/docsets/JSQSystemSoundPlayer
+//
+//
+//  GitHub
+//  https://github.com/jessesquires/JSQSystemSoundPlayer
+//
+//
+//  License
+//  Copyright (c) 2014 Jesse Squires
+//  Released under an MIT license: http://opensource.org/licenses/MIT
+//
+
+#import "JSQSystemSoundPlayer.h"
+
+#import <AudioToolbox/AudioToolbox.h>
+#import <UIKit/UIKit.h>
+
+
+static NSString * const kJSQSystemSoundPlayerUserDefaultsKey = @"kJSQSystemSoundPlayerUserDefaultsKey";
+
+NSString * const kJSQSystemSoundTypeCAF = @"caf";
+NSString * const kJSQSystemSoundTypeAIF = @"aif";
+NSString * const kJSQSystemSoundTypeAIFF = @"aiff";
+NSString * const kJSQSystemSoundTypeWAV = @"wav";
+
+@interface JSQSystemSoundPlayer ()
+
+@property (strong, nonatomic) NSMutableDictionary *sounds;
+@property (strong, nonatomic) NSMutableDictionary *completionBlocks;
+
+- (void)playSoundWithName:(NSString *)filename
+                extension:(NSString *)extension
+                  isAlert:(BOOL)isAlert
+          completionBlock:(JSQSystemSoundPlayerCompletionBlock)completionBlock;
+
+- (BOOL)readSoundPlayerOnFromUserDefaults;
+
+- (NSData *)dataWithSoundID:(SystemSoundID)soundID;
+- (SystemSoundID)soundIDFromData:(NSData *)data;
+
+- (SystemSoundID)soundIDForFilename:(NSString *)filenameKey;
+- (void)addSoundIDForAudioFileWithName:(NSString *)filename
+                             extension:(NSString *)extension;
+
+- (JSQSystemSoundPlayerCompletionBlock)completionBlockForSoundID:(SystemSoundID)soundID;
+- (void)addCompletionBlock:(JSQSystemSoundPlayerCompletionBlock)block
+                 toSoundID:(SystemSoundID)soundID;
+- (void)removeCompletionBlockForSoundID:(SystemSoundID)soundID;
+
+- (SystemSoundID)createSoundIDWithName:(NSString *)filename
+                             extension:(NSString *)extension;
+
+- (void)unloadSoundIDs;
+- (void)unloadSoundIDForFileNamed:(NSString *)filename;
+
+- (void)logError:(OSStatus)error withMessage:(NSString *)message;
+
+- (void)didReceiveMemoryWarningNotification:(NSNotification *)notification;
+
+@end
+
+
+
+static void systemServicesSoundCompletion(SystemSoundID  soundID, void *data)
+{
+    JSQSystemSoundPlayer *player = [JSQSystemSoundPlayer sharedPlayer];
+    
+    JSQSystemSoundPlayerCompletionBlock block = [player completionBlockForSoundID:soundID];
+    if (block) {
+        block();
+        [player removeCompletionBlockForSoundID:soundID];
+    }
+}
+
+
+
+@implementation JSQSystemSoundPlayer
+
+#pragma mark - Init
+
++ (JSQSystemSoundPlayer *)sharedPlayer
+{
+    static JSQSystemSoundPlayer *sharedPlayer;
+    
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        sharedPlayer = [[JSQSystemSoundPlayer alloc] init];
+    });
+    
+    return sharedPlayer;
+}
+
+- (instancetype)init
+{
+    self = [super init];
+    if (self) {
+        _bundle = [NSBundle mainBundle];
+        _on = [self readSoundPlayerOnFromUserDefaults];
+        _sounds = [[NSMutableDictionary alloc] init];
+        _completionBlocks = [[NSMutableDictionary alloc] init];
+        [[NSNotificationCenter defaultCenter] addObserver:self
+                                                 selector:@selector(didReceiveMemoryWarningNotification:)
+                                                     name:UIApplicationDidReceiveMemoryWarningNotification
+                                                   object:nil];
+    }
+    return self;
+}
+
+- (void)dealloc
+{
+    [self unloadSoundIDs];
+    _sounds = nil;
+    _completionBlocks = nil;
+    [[NSNotificationCenter defaultCenter] removeObserver:self
+                                                    name:UIApplicationDidReceiveMemoryWarningNotification
+                                                  object:nil];
+}
+
+#pragma mark - Playing sounds
+
+- (void)playSoundWithName:(NSString *)filename
+                extension:(NSString *)extension
+                  isAlert:(BOOL)isAlert
+          completionBlock:(JSQSystemSoundPlayerCompletionBlock)completionBlock
+{
+    if (!self.on) {
+        return;
+    }
+    
+    if (!filename || !extension) {
+        return;
+    }
+    
+    if (![self.sounds objectForKey:filename]) {
+        [self addSoundIDForAudioFileWithName:filename extension:extension];
+    }
+    
+    SystemSoundID soundID = [self soundIDForFilename:filename];
+    if (soundID) {
+        if (completionBlock) {
+            OSStatus error = AudioServicesAddSystemSoundCompletion(soundID,
+                                                                   NULL,
+                                                                   NULL,
+                                                                   systemServicesSoundCompletion,
+                                                                   NULL);
+            
+            if (error) {
+                [self logError:error withMessage:@"Warning! Completion block could not be added to SystemSoundID."];
+            }
+            else {
+                [self addCompletionBlock:completionBlock toSoundID:soundID];
+            }
+        }
+        
+        if (isAlert) {
+            AudioServicesPlayAlertSound(soundID);
+        }
+        else {
+            AudioServicesPlaySystemSound(soundID);
+        }
+    }
+}
+
+- (BOOL)readSoundPlayerOnFromUserDefaults
+{
+    NSNumber *setting = [[NSUserDefaults standardUserDefaults] objectForKey:kJSQSystemSoundPlayerUserDefaultsKey];
+    
+    if (!setting) {
+        [self toggleSoundPlayerOn:YES];
+        return YES;
+    }
+    
+    return [setting boolValue];
+}
+
+#pragma mark - Public API
+
+- (void)toggleSoundPlayerOn:(BOOL)on
+{
+    _on = on;
+    
+    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
+    [userDefaults setObject:[NSNumber numberWithBool:on] forKey:kJSQSystemSoundPlayerUserDefaultsKey];
+    [userDefaults synchronize];
+    
+    if (!on) {
+        [self stopAllSounds];
+    }
+}
+
+- (void)playSoundWithFilename:(NSString *)filename fileExtension:(NSString *)extension
+{
+    [self playSoundWithFilename:filename
+                  fileExtension:extension
+                     completion:nil];
+}
+
+- (void)playSoundWithFilename:(NSString *)filename
+                fileExtension:(NSString *)extension
+                   completion:(JSQSystemSoundPlayerCompletionBlock)completionBlock
+{
+    [self playSoundWithName:filename
+                  extension:extension
+                    isAlert:NO
+            completionBlock:completionBlock];
+}
+
+- (void)playAlertSoundWithFilename:(NSString *)filename
+                     fileExtension:(NSString *)extension
+                        completion:(JSQSystemSoundPlayerCompletionBlock)completionBlock
+{
+    [self playSoundWithName:filename
+                  extension:extension
+                    isAlert:YES
+            completionBlock:completionBlock];
+}
+
+- (void)playAlertSoundWithFilename:(NSString *)filename fileExtension:(NSString *)extension
+{
+    [self playAlertSoundWithFilename:filename
+                       fileExtension:extension
+                          completion:nil];
+}
+
+- (void)playVibrateSound
+{
+    if (self.on) {
+        AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
+    }
+}
+
+- (void)stopAllSounds
+{
+    [self unloadSoundIDs];
+}
+
+- (void)stopSoundWithFilename:(NSString *)filename
+{
+    SystemSoundID soundID = [self soundIDForFilename:filename];
+    NSData *data = [self dataWithSoundID:soundID];
+    
+    [self unloadSoundIDForFileNamed:filename];
+    
+    [_sounds removeObjectForKey:filename];
+    [_completionBlocks removeObjectForKey:data];
+}
+
+- (void)preloadSoundWithFilename:(NSString *)filename fileExtension:(NSString *)extension
+{
+    if (![self.sounds objectForKey:filename]) {
+        [self addSoundIDForAudioFileWithName:filename extension:extension];
+    }
+}
+
+#pragma mark - Sound data
+
+- (NSData *)dataWithSoundID:(SystemSoundID)soundID
+{
+    return [NSData dataWithBytes:&soundID length:sizeof(SystemSoundID)];
+}
+
+- (SystemSoundID)soundIDFromData:(NSData *)data
+{
+    if (data == nil) {
+        return 0;
+    }
+    
+    SystemSoundID soundID;
+    [data getBytes:&soundID length:sizeof(SystemSoundID)];
+    return soundID;
+}
+
+#pragma mark - Sound files
+
+- (SystemSoundID)soundIDForFilename:(NSString *)filenameKey
+{
+    NSData *soundData = [self.sounds objectForKey:filenameKey];
+    return [self soundIDFromData:soundData];
+}
+
+- (void)addSoundIDForAudioFileWithName:(NSString *)filename
+                             extension:(NSString *)extension
+{
+    SystemSoundID soundID = [self createSoundIDWithName:filename
+                                              extension:extension];
+    if (soundID) {
+        NSData *data = [self dataWithSoundID:soundID];
+        [self.sounds setObject:data forKey:filename];
+    }
+}
+
+#pragma mark - Sound completion blocks
+
+- (JSQSystemSoundPlayerCompletionBlock)completionBlockForSoundID:(SystemSoundID)soundID
+{
+    NSData *data = [self dataWithSoundID:soundID];
+    return [self.completionBlocks objectForKey:data];
+}
+
+- (void)addCompletionBlock:(JSQSystemSoundPlayerCompletionBlock)block
+                 toSoundID:(SystemSoundID)soundID
+{
+    NSData *data = [self dataWithSoundID:soundID];
+    [self.completionBlocks setObject:block forKey:data];
+}
+
+- (void)removeCompletionBlockForSoundID:(SystemSoundID)soundID
+{
+    NSData *key = [self dataWithSoundID:soundID];
+    [self.completionBlocks removeObjectForKey:key];
+    AudioServicesRemoveSystemSoundCompletion(soundID);
+}
+
+#pragma mark - Managing sounds
+
+- (SystemSoundID)createSoundIDWithName:(NSString *)filename
+                             extension:(NSString *)extension
+{
+    NSURL *fileURL = [self.bundle URLForResource:filename withExtension:extension];
+    
+    if ([[NSFileManager defaultManager] fileExistsAtPath:[fileURL path]]) {
+        SystemSoundID soundID;
+        OSStatus error = AudioServicesCreateSystemSoundID((__bridge CFURLRef)fileURL, &soundID);
+        
+        if (error) {
+            [self logError:error withMessage:@"Warning! SystemSoundID could not be created."];
+            return 0;
+        }
+        else {
+            return soundID;
+        }
+    }
+    
+    NSLog(@"[%@] Error: audio file not found at URL: %@", [self class], fileURL);
+    return 0;
+}
+
+- (void)unloadSoundIDs
+{
+    for(NSString *eachFilename in [_sounds allKeys]) {
+        [self unloadSoundIDForFileNamed:eachFilename];
+    }
+    
+    [_sounds removeAllObjects];
+    [_completionBlocks removeAllObjects];
+}
+
+- (void)unloadSoundIDForFileNamed:(NSString *)filename
+{
+    SystemSoundID soundID = [self soundIDForFilename:filename];
+    
+    if (soundID) {
+        AudioServicesRemoveSystemSoundCompletion(soundID);
+        
+        OSStatus error = AudioServicesDisposeSystemSoundID(soundID);
+        if (error) {
+            [self logError:error withMessage:@"Warning! SystemSoundID could not be disposed."];
+        }
+    }
+}
+
+- (void)logError:(OSStatus)error withMessage:(NSString *)message
+{
+    NSString *errorMessage = nil;
+    
+    switch (error) {
+        case kAudioServicesUnsupportedPropertyError:
+            errorMessage = @"The property is not supported.";
+            break;
+        case kAudioServicesBadPropertySizeError:
+            errorMessage = @"The size of the property data was not correct.";
+            break;
+        case kAudioServicesBadSpecifierSizeError:
+            errorMessage = @"The size of the specifier data was not correct.";
+            break;
+        case kAudioServicesSystemSoundUnspecifiedError:
+            errorMessage = @"An unspecified error has occurred.";
+            break;
+        case kAudioServicesSystemSoundClientTimedOutError:
+            errorMessage = @"System sound client message timed out.";
+            break;
+    }
+    
+    NSLog(@"[%@] %@ Error: (code %d) %@", [self class], message, (int)error, errorMessage);
+}
+
+#pragma mark - Notifications
+
+- (void)didReceiveMemoryWarningNotification:(NSNotification *)notification
+{
+    [self unloadSoundIDs];
+}
+
+@end
diff --git a/whiskbot-demo-app/Pods/JSQSystemSoundPlayer/LICENSE b/whiskbot-demo-app/Pods/JSQSystemSoundPlayer/LICENSE
new file mode 100644
index 0000000..e39fc6b
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQSystemSoundPlayer/LICENSE
@@ -0,0 +1,20 @@
+
+MIT License
+Copyright (c) 2013 Jesse Squires
+
+http://www.hexedbits.com
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
+following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
+LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/whiskbot-demo-app/Pods/JSQSystemSoundPlayer/README.md b/whiskbot-demo-app/Pods/JSQSystemSoundPlayer/README.md
new file mode 100644
index 0000000..52df42a
--- /dev/null
+++ b/whiskbot-demo-app/Pods/JSQSystemSoundPlayer/README.md
@@ -0,0 +1,139 @@
+# JSQSystemSoundPlayer 
+[![Build Status](https://secure.travis-ci.org/jessesquires/JSQSystemSoundPlayer.svg)](http://travis-ci.org/jessesquires/JSQSystemSoundPlayer) [![Version Status](http://img.shields.io/cocoapods/v/JSQSystemSoundPlayer.png)][docsLink] [![license MIT](http://img.shields.io/badge/license-MIT-orange.png)][mitLink]
+
+A fancy Obj-C wrapper for iOS [System Sound Services](https://developer.apple.com/library/ios/documentation/AudioToolbox/Reference/SystemSoundServicesReference/Reference/reference.html).
+
+This class is a light-weight, drop-in component to play sound effects, or other short sounds in your iOS app. 
+To determine your audio needs, see [Best Practices for iOS Audio](https://developer.apple.com/library/ios/DOCUMENTATION/AudioVideo/Conceptual/MultimediaPG/UsingAudio/UsingAudio.html#//apple_ref/doc/uid/TP40009767-CH2-SW10).
+Or, read the tl;dr version:
+
+>*When your sole audio need is to play alerts and user-interface sound effects, use Core Audio’s System Sound Services.*
+>
+>Your sound files must be:
+>
+>* No longer than 30 seconds in duration
+>* In linear PCM or IMA4 (IMA/ADPCM) format
+>* Packaged in a `.caf`, `.aif`, or `.wav` file
+
+If this does not fit your needs, then this control is not for you! 
+See [AVAudioPlayer](https://developer.apple.com/library/ios/DOCUMENTATION/AVFoundation/Reference/AVAudioPlayerClassReference/Reference/Reference.html), instead.
+
+![JSQSystemSoundPlayer Screenshot][imgLink] 
+
+## Features
+
+* Play sound effects and alert sounds with a single line of code
+* "Play" vibration (if available on device)
+* Block-based completion handlers
+* Integration with `NSUserDefaults` to globally toggle sound effects in your app
+* Sweet and efficient memory management
+* Caches sounds (`SystemSoundID` instances) and purges on memory warning
+* Works with Swift! (v2.0.0 and above)
+
+## Requirements
+
+* iOS 6.0+ 
+* ARC
+
+## Installation
+
+````
+pod 'JSQSystemSoundPlayer'
+````
+Otherwise, drag the `JSQSystemSoundPlayer/` folder to your project, and add `AudioToolbox.framework`.
+
+## Getting Started
+
+#### Playing sounds
+
+````objective-c
+[[JSQSystemSoundPlayer sharedPlayer] playSoundWithFilename:@"mySoundFile"
+                                             fileExtension:kJSQSystemSoundTypeAIF
+                                                completion:^{
+                                                   // completion block code
+                                                }];
+````
+
+And that's all! 
+
+String constants for file extensions provided for you: 
+* `kJSQSystemSoundTypeCAF`
+* `kJSQSystemSoundTypeAIF`
+* `kJSQSystemSoundTypeAIFF`
+* `kJSQSystemSoundTypeWAV`
+
+#### Toggle sounds effects settings on/off
+
+Need a setting in your app's preferences to toggle sound effects on/off? `JSQSystemSoundPlayer` can do that, too! There's no need to ever check the saved settings (`[JSQSystemSoundPlayer sharedPlayer].on`) before you play a sound effect. Just play a sound like in the example above. `JSQSystemSoundPlayer` respects whatever setting has been previously saved.
+
+````objective-c
+[[JSQSystemSoundPlayer sharedPlayer] toggleSoundPlayerOn:YES];
+````
+
+#### Specifying a bundle
+
+Need to load your audio resources from a specific bundle? `JSQSystemSoundPlayer` uses the main bundle by default, but you can specify another. 
+
+**NOTE:** for each sound that is played `JSQSystemSoundPlayer` will **always** search the **last specified bundle**. If you are playing sound effects from multiple bundles, you will need to specify the bundle before playing each sound.
+
+````objective-c
+[JSQSystemSoundPlayer sharedPlayer].bundle = [NSBundle mainBundle];
+````
+
+#### Demo
+
+Also see the included demo project: `SoundPlayerDemo.xcodeproj`
+
+#### For a good time
+
+````objective-c
+while (1) {
+    [[JSQSystemSoundPlayer sharedPlayer] playVibrateSound];
+}
+````
+
+## Documentation
+
+Read the fucking docs, [available here][docsLink] via [@CocoaDocs](https://twitter.com/CocoaDocs).
+
+## Contribute
+
+Please follow these sweet [contribution guidelines](https://github.com/jessesquires/HowToContribute).
+
+## Design
+
+Why is this a [Singleton](http://en.wikipedia.org/wiki/Singleton_pattern)? Singletons are [garbage](https://twitter.com/jesse_squires/status/532800746656239616). I agree! But here's why this is a valid use case:
+
+1. This library manages the use of audio resources. Semantically, you only have 1 sound asset per sound effect. This is akin to `[NSFileManager defaultManager]`. You only have file system from which to read data. 
+2. The singleton allows the caching of `SystemSoundID` instances.
+
+## Donate
+
+Support the development of this **free**, open-source library! 
+
+> *Donations made via [Square Cash](https://square.com/cash)*
+> <h4><a href="mailto:jesse.squires.developer@gmail.com?cc=cash@square.com&subject=$1&body=Thanks for developing JSQSystemSoundPlayer!">Send $1</a> <em>Just saying thanks!</em></h4>
+> <h4><a href="mailto:jesse.squires.developer@gmail.com?cc=cash@square.com&subject=$5&body=Thanks for developing JSQSystemSoundPlayer!">Send $5</a> <em>This control is great!</em></h4>
+> <h4><a href="mailto:jesse.squires.developer@gmail.com?cc=cash@square.com&subject=$10&body=Thanks for developing JSQSystemSoundPlayer!">Send $10</a> <em>This totally saved me time!</em></h4>
+
+## Credits
+
+Created by [**@jesse_squires**](https://twitter.com/jesse_squires), a [programming-motherfucker](http://programming-motherfucker.com).
+
+## Apps using this library
+
+* [Hemoglobe](http://bit.ly/hemoglobeapp)
+* [iPaint uPaint](http://bit.ly/ipupappstr)
+* [MUDRammer](https://itunes.apple.com/us/app/mudrammer-a-modern-mud-client/id597157072?mt=8)
+
+## License
+
+`JSQSystemSoundPlayer` is released under an [MIT License][mitLink]. See `LICENSE` for details.
+
+>**Copyright &copy; 2014 Jesse Squires.**
+
+*Please provide attribution, it is greatly appreciated.*
+
+[docsLink]:http://cocoadocs.org/docsets/JSQSystemSoundPlayer
+[mitLink]:http://opensource.org/licenses/MIT
+[imgLink]:https://raw.github.com/jessesquires/JSQSystemSoundPlayer/master/Screenshots/screenshot.png
diff --git a/whiskbot-demo-app/Pods/Local Podspecs/OpenWhisk.podspec.json b/whiskbot-demo-app/Pods/Local Podspecs/OpenWhisk.podspec.json
new file mode 100644
index 0000000..25c5ac8
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Local Podspecs/OpenWhisk.podspec.json
@@ -0,0 +1,32 @@
+{
+  "name": "OpenWhisk",
+  "version": "0.2.2",
+  "summary": "Mobile SDK to use OpenWhisk server-less environment",
+  "homepage": "http://www.ibm.com/mobilefirst/us/en/",
+  "license": {
+    "type": "Apache License, Version 2.0"
+  },
+  "authors": "IBM",
+  "description": "OpenWhisk is a cloud-first distributed event-based programming service. OpenWhisk provides a programming model to upload event handlers to a cloud service, and register the handlers to respond to various events.",
+  "platforms": {
+    "ios": "9.0",
+    "watchos": "3.0"
+  },
+  "source": {
+    "git": "https://github.com/openwhisk/openwhisk-client-swift.git",
+    "tag": "0.2.2"
+  },
+  "source_files": "OpenWhisk/*.{swift,h}",
+  "watchos": {
+    "exclude_files": "OpenWhisk/OpenWhiskButton.swift"
+  },
+  "frameworks": [
+    "Foundation",
+    "WatchConnectivity"
+  ],
+  "resource_bundles": {
+    "OpenWhiskResources": [
+      "OpenWhisk/OpenWhiskConfig.plist"
+    ]
+  }
+}
diff --git a/whiskbot-demo-app/Pods/Manifest.lock b/whiskbot-demo-app/Pods/Manifest.lock
new file mode 100644
index 0000000..e75c511
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Manifest.lock
@@ -0,0 +1,31 @@
+PODS:
+  - JSQMessagesViewController (7.3.4):
+    - JSQSystemSoundPlayer (~> 2.0.1)
+  - JSQSystemSoundPlayer (2.0.1)
+  - OpenWhisk (0.2.2)
+  - SwiftyJSON (3.1.4)
+
+DEPENDENCIES:
+  - JSQMessagesViewController
+  - OpenWhisk (from `https://github.com/openwhisk/openwhisk-client-swift.git`, tag `0.2.2`)
+  - SwiftyJSON
+
+EXTERNAL SOURCES:
+  OpenWhisk:
+    :git: https://github.com/openwhisk/openwhisk-client-swift.git
+    :tag: 0.2.2
+
+CHECKOUT OPTIONS:
+  OpenWhisk:
+    :git: https://github.com/openwhisk/openwhisk-client-swift.git
+    :tag: 0.2.2
+
+SPEC CHECKSUMS:
+  JSQMessagesViewController: 39fed975e3c9f8eba7292071e29eeb541d105e66
+  JSQSystemSoundPlayer: c5850e77a4363ffd374cd851154b9af93264ed8d
+  OpenWhisk: 68be4ee6ca258051ee99323bd736317e550d1cf8
+  SwiftyJSON: c2842d878f95482ffceec5709abc3d05680c0220
+
+PODFILE CHECKSUM: de5a42b3844c628073a98f99a25585bf4c0f8131
+
+COCOAPODS: 1.1.1
diff --git a/whiskbot-demo-app/Pods/OpenWhisk/LICENSE.txt b/whiskbot-demo-app/Pods/OpenWhisk/LICENSE.txt
new file mode 100644
index 0000000..7e7d55d
--- /dev/null
+++ b/whiskbot-demo-app/Pods/OpenWhisk/LICENSE.txt
@@ -0,0 +1,14 @@
+
+Copyright 2015-2016 IBM Corporation
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/whiskbot-demo-app/Pods/OpenWhisk/OpenWhisk/Config.swift b/whiskbot-demo-app/Pods/OpenWhisk/OpenWhisk/Config.swift
new file mode 100644
index 0000000..90d620f
--- /dev/null
+++ b/whiskbot-demo-app/Pods/OpenWhisk/OpenWhisk/Config.swift
@@ -0,0 +1,98 @@
+/*
+* Copyright 2015-2016 IBM Corporation
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import Foundation
+
+/*
+ Retrieves basic configuration information for the SDK specified in WhiskConfig.plist or environment variables
+*/
+public class Config {
+    
+
+     class func getHostAndPath(type:String) -> String? {
+        var url: String? = nil
+        if let dict = getConfigDictionary() {
+            url = dict.value(forKey: type) as? String
+        } else {
+            print("Configuration file missing, cannot config network call")
+        }
+        
+        return url
+    }
+    
+    
+    private class func getConfigDictionary() -> NSDictionary? {
+        
+        // Attempt 1, load the bundle from a local reference to this classes bundle
+        // I'am assuming the WhiskResources bundle is in the framework's root bundle
+        let frameworkBundle = Bundle(for: Config.self)
+        
+        if let bundlePath = frameworkBundle.path(forResource: "OpenWhiskResources", ofType: "bundle") {
+            if let bundle = Bundle(path: bundlePath) {
+                let configFile = bundle.path(forResource: "OpenWhiskConfig", ofType: "plist")
+                
+                if let configFile = configFile {
+                    let config = NSDictionary(contentsOfFile: configFile) as? [String: AnyObject]
+                    if let config = config {
+                        let urlConfig = config["Locations"] as? [String: String]
+                        return urlConfig as NSDictionary?
+                    }
+                }
+            }
+        } else if let bundlePath = frameworkBundle.path(forResource: "OpenWhiskWatchResources", ofType: "bundle") {
+            if let bundle = Bundle(path: bundlePath) {
+                let configFile = bundle.path(forResource: "OpenWhiskConfig", ofType: "plist")
+                
+                if let configFile = configFile {
+                    let config = NSDictionary(contentsOfFile: configFile) as? [String: AnyObject]
+                    if let config = config {
+                        let urlConfig = config["Locations"] as? [String: String]
+                        return urlConfig as NSDictionary?
+                    }
+                }
+            }
+        } else {
+            if let configFile = frameworkBundle.path(forResource: "OpenWhiskConfig", ofType: "plist") {
+                let config = NSDictionary(contentsOfFile: configFile) as? [String: AnyObject]
+                if let config = config {
+                    let urlConfig = config["Locations"] as? [String: String]
+                    return urlConfig as NSDictionary?
+                }
+            } else {
+                print("Can't find configuration information")
+            }
+        }
+        
+        return nil
+        
+    }
+    
+    
+    
+    /*
+     Can be used to read authentication credentials from env variables.  Useful for unit tests and maybe some build tasks
+     but not much else?
+    */
+    public class func getAuthToken() -> (apiKey: String?, apiSecret: String?)? {
+        
+        let dict = ProcessInfo.processInfo.environment
+        let key = dict["OPENWHISK_TESTAPIKEY"]
+        let secret = dict["OPENWHISK_TESTAPISECRET"]
+        
+        return(key, secret)
+    }
+    
+}
diff --git a/whiskbot-demo-app/Pods/OpenWhisk/OpenWhisk/OpenWhisk.h b/whiskbot-demo-app/Pods/OpenWhisk/OpenWhisk/OpenWhisk.h
new file mode 100644
index 0000000..6b134c6
--- /dev/null
+++ b/whiskbot-demo-app/Pods/OpenWhisk/OpenWhisk/OpenWhisk.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2015-2016 IBM Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@import Foundation;
+
+//! Project version number for OpenWhisk.
+FOUNDATION_EXPORT double OpenWhiskVersionNumber;
+
+//! Project version string for OpenWhisk.
+FOUNDATION_EXPORT const unsigned char OpenWhiskVersionString[];
+
+// In this header, you should import all the public headers of your framework using statements like #import <OpenWhisk/PublicHeader.h>
+
+
diff --git a/whiskbot-demo-app/Pods/OpenWhisk/OpenWhisk/OpenWhiskButton.swift b/whiskbot-demo-app/Pods/OpenWhisk/OpenWhisk/OpenWhiskButton.swift
new file mode 100644
index 0000000..9808d56
--- /dev/null
+++ b/whiskbot-demo-app/Pods/OpenWhisk/OpenWhisk/OpenWhiskButton.swift
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2015-2016 IBM Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import UIKit
+
+/*
+ 
+ Convenience UI element that allows you to invoke whisk actions.  You can use like a normal UIButton and handle all the press events yourself, or you can have the button "self-contained".  If you set listenForPressEvents = true it will listen for its own press events and invoke the the configured action.
+ 
+ */
+@objc(WhiskButton) public class WhiskButton: UIButton {
+    
+    var whisk: Whisk?
+    var urlSession: URLSession?
+    
+    var actionParameters: Dictionary<String,AnyObject>?
+    var actionHasResult: Bool = false
+    var actionName: String?
+    var actionPackage: String?
+    var actionNamespace: String?
+    var isListeningToSelf: Bool?
+    
+    public required init?(coder aDecoder: NSCoder) {
+        super.init(coder: aDecoder)
+    }
+    
+    public override init(frame: CGRect) {
+        super.init(frame: frame)
+    }
+    
+    public var listenForPressEvents: Bool? {
+        get {
+            return isListeningToSelf
+        }
+        
+        set {
+            if newValue == true {
+                self.addTarget(self, action: #selector(WhiskButton.buttonPressed), for: .touchUpInside)
+            } else {
+                self.removeTarget(self, action: #selector(WhiskButton.buttonPressed), for: .touchUpInside)
+            }
+            
+            isListeningToSelf = newValue
+        }
+    }
+    public var actionButtonCallback: ((Dictionary<String,AnyObject>?, WhiskError?) -> Void)?
+    
+    
+    func buttonPressed() {
+        invokeAction(parameters: nil, actionCallback: actionButtonCallback)
+    }
+    
+    public func setupWhiskAction(qualifiedName qName:String, credentials: WhiskCredentials, hasResult: Bool = false,parameters: Dictionary<String, AnyObject>? = nil, urlSession: URLSession? = nil, baseUrl: String? = nil) throws {
+        
+        let pathParts = try Whisk.processQualifiedName(qName)
+        
+        setupWhiskAction(pathParts.name, package: pathParts.package, namespace: pathParts.namespace, credentials: credentials, hasResult: hasResult, parameters: parameters, urlSession: urlSession, baseUrl: baseUrl)
+    }
+    
+    public func setupWhiskAction(_ name: String, package: String? = nil, namespace: String = "_", credentials: WhiskCredentials, hasResult: Bool = false,parameters: Dictionary<String, AnyObject>? = nil, urlSession: URLSession? = nil, baseUrl: String? = nil) {
+        
+        whisk = Whisk(credentials: credentials)
+        
+        if let session = urlSession {
+            whisk?.urlSession = session
+        }
+        
+        if let baseUrl = baseUrl {
+            whisk?.baseURL = baseUrl
+        }
+        
+        actionParameters = parameters
+        actionName = name
+        actionPackage = package
+        actionNamespace = namespace
+        actionHasResult = hasResult
+    }
+    
+    public func invokeAction(parameters: [String:AnyObject]? = nil, actionCallback: ((Dictionary<String,AnyObject>?, WhiskError?) -> Void)?) {
+        
+        if let whisk = whisk, let actionName = actionName, let actionNamespace = actionNamespace {
+            
+            let queue = DispatchQueue(label:"com.ibm.mobilefirst.openwhisk.invokeAction")
+            queue.async(qos: .userInitiated) {
+                do {
+                    
+                    var params:[String:AnyObject]?
+                    
+                    if let parameters = parameters {
+                        params = parameters
+                    } else {
+                        params = self.actionParameters
+                    }
+                    
+                    try whisk.invokeAction(name: actionName, package: self.actionPackage, namespace: actionNamespace, parameters: params as AnyObject?, hasResult: self.actionHasResult, callback: {(reply, error) in
+                        
+                        
+                        // note callback is in main queue already we should be on the UI thread
+                        if let actionCallback = actionCallback {
+                            actionCallback(reply, error)
+                        }
+                        
+                        
+                    })
+                } catch {
+                    print("Error invoking action: \(error)")
+                }
+            }
+        } else {
+            print("WhiskButton action not initialized")
+        }
+        
+    }
+    
+}
diff --git a/whiskbot-demo-app/Pods/OpenWhisk/OpenWhisk/OpenWhiskConfig.plist b/whiskbot-demo-app/Pods/OpenWhisk/OpenWhisk/OpenWhiskConfig.plist
new file mode 100644
index 0000000..282d66c
--- /dev/null
+++ b/whiskbot-demo-app/Pods/OpenWhisk/OpenWhisk/OpenWhiskConfig.plist
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>Locations</key>
+	<dict>
+		<key>actions</key>
+		<string>https://openwhisk.ng.bluemix.net/api/v1/</string>
+		<key>triggers</key>
+		<string>https://openwhisk.ng.bluemix.net/api/v1/</string>
+	</dict>
+</dict>
+</plist>
diff --git a/whiskbot-demo-app/Pods/OpenWhisk/OpenWhisk/OpenWhiskSDK.swift b/whiskbot-demo-app/Pods/OpenWhisk/OpenWhisk/OpenWhiskSDK.swift
new file mode 100644
index 0000000..2fbd582
--- /dev/null
+++ b/whiskbot-demo-app/Pods/OpenWhisk/OpenWhisk/OpenWhiskSDK.swift
@@ -0,0 +1,465 @@
+/*
+* Copyright 2015-2016 IBM Corporation
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import Foundation
+
+/*
+
+Hold the Whisk access key and access token.  The session token and jwtToken can be used to implement
+custom authentication flows
+
+*/
+public struct WhiskCredentials {
+    public init(accessKey: String?, accessToken: String?, sessionToken:String? = nil, jwtToken: String? = nil) {
+        self.accessToken = accessToken
+        self.accessKey = accessKey
+        self.sessionToken = sessionToken
+        self.jwtToken = jwtToken
+    }
+    
+    // whisk credentials
+    public var accessKey: String?
+    public var accessToken: String?
+    public var sessionToken: String?
+    
+    // optional app credentials
+    public var appKey: String?
+    public var appSecret: String?
+    
+    // optional token for custom authentication flow
+    public var jwtToken: String?
+}
+
+/* Error types for Whisk calls */
+public enum WhiskError: Error {
+    case httpError(description: String, statusCode: Int) // something went wrong with the http call
+    case jsonError(description: String) // json wasn't right
+    case credentialError(description: String) // something is wrong with the whisk credentials
+    case qualifiedNameFormat(description: String) // something is wrong in qualified name
+    case whiskProcessingError(description: String, errorCode: Int) // something went wrong on the whisk side.
+}
+
+/* Type of Whisk operation requested */
+enum WhiskType {
+    case action
+    case trigger
+}
+
+/* Main class to hold the calls to invoke Actions and fire Triggers */
+public class Whisk {
+    
+    // Secrets needed to call Whisk API
+    let AccessKey: String? // Whisk key
+    let AccessToken: String? // Whisk token
+    let AppKey: String? // application Key (currently not used)
+    let AppSecret: String? // application Secret (curently not used)
+    
+    // api Host for Whisk backend
+    public var whiskBaseURL: String?
+    
+    // set to non-nil if using a custom session
+    public var urlSession: URLSession?
+    
+    public var verboseReplies: Bool = false
+    
+    // Set these if you want to run unit tests and mock
+    // calls to Whisk backend.
+    public var useMock: Bool = false
+    public var mockReply: [String: AnyObject]?
+    public var mockError: WhiskError?
+    
+    
+    // return base URL of backend including common path for all API calls
+    public var baseURL: String? {
+        set {
+            if let url = newValue {
+                
+                let c = url.characters.last
+                
+                let separater =  c == "/" ? "" : "/"
+                
+                whiskBaseURL = url + separater + "api/v1/"
+                
+            } else {
+                whiskBaseURL = nil
+            }
+        }
+        get {
+            return whiskBaseURL
+        }
+    }
+    
+    // Initialize with credentials, region currently not used
+    public init(credentials: WhiskCredentials, region: String = "US-East-1") {
+        // initialize
+        AccessKey = credentials.accessKey
+        AccessToken = credentials.accessToken
+        AppKey = credentials.appKey
+        AppSecret = credentials.appSecret
+        
+    }
+    
+    
+    /* Base function to fire Whisk Trigger identified by qualified name */
+    public func fireTrigger(qualifiedName: String, parameters: AnyObject? = nil, callback: @escaping (Dictionary<String,AnyObject>?, WhiskError?)->Void) throws {
+        
+        let pathParts = try Whisk.processQualifiedName(qualifiedName)
+        try fireTrigger(name: pathParts.name, package: pathParts.package, namespace: pathParts.namespace, parameters: parameters, callback: callback)
+    }
+    
+    /* Base function to invoke Whisk Action identified by qualified name */
+    public func invokeAction(qualifiedName: String, parameters: AnyObject?, hasResult: Bool = false, callback: @escaping (Dictionary<String,AnyObject>?, WhiskError?)->Void) throws {
+        
+        let pathParts = try Whisk.processQualifiedName(qualifiedName)
+        try invokeAction(name: pathParts.name, package: pathParts.package, namespace: pathParts.namespace, parameters: parameters, hasResult: hasResult, callback: callback)
+    }
+    
+    
+    /* Base function to fire Whisk Trigger identified by components */
+    public func fireTrigger(name: String, package: String? = nil, namespace: String = "_", parameters: AnyObject? = nil, callback: @escaping (Dictionary<String,AnyObject>?, WhiskError?)->Void) throws {
+        
+        if let accessKey = AccessKey, let accessToken = AccessToken {
+            try httpRequestWhiskAPI(accessKey: accessKey, accessToken: accessToken, namespace: namespace, verb: "POST", type: .trigger, package: package, name:name, parameters: parameters, isSync: false, callback: { (jsonArray, error) in
+                if let error = error {
+                    callback(nil, error)
+                } else {
+                    callback(jsonArray, nil)
+                }
+            })
+        } else {
+            throw WhiskError.credentialError(description: "Access key and token not set")
+        }
+        
+        
+    }
+    
+    /* Base function to invoke Whisk Action identified by components */
+    public func invokeAction(name: String, package: String? = nil, namespace: String = "_", parameters: AnyObject?, hasResult:Bool = false, callback: @escaping (Dictionary<String,AnyObject>?, WhiskError?)-> Void) throws {
+        if let accessKey = AccessKey, let accessToken = AccessToken {
+            
+            try httpRequestWhiskAPI(accessKey: accessKey, accessToken: accessToken, namespace: namespace, verb: "POST", type: .action, package: package, name: name, parameters: parameters, isSync: hasResult, callback: {(jsonDict, error) in
+                if let error = error {
+                    callback(nil, error)
+                } else {
+                    callback(jsonDict, nil)
+                }
+                
+            })
+        } else {
+            throw WhiskError.credentialError(description: "Access key and token not set")
+        }
+        
+    }
+    
+    /* can redirect call here, e.g. if mocking */
+    func httpRequestWhiskAPI(accessKey: String, accessToken: String, namespace: String, verb: String, type: WhiskType, package: String?, name: String, parameters: AnyObject?, isSync: Bool, callback: @escaping (Dictionary<String,AnyObject>?, WhiskError?) ->Void) throws {
+        
+        if useMock {
+            callback(mockReply, mockError)
+            
+        } else {
+            try whiskAPI(accessKey: accessKey, accessToken: accessToken, namespace: namespace, verb: verb, type: type, package: package, name: name, parameters: parameters, isSync: isSync, callback: callback)
+        }
+    }
+    
+    
+    /* Network call */
+    func whiskAPI(accessKey: String, accessToken: String, namespace: String, verb: String, type: WhiskType, package: String?, name: String, parameters: AnyObject?, isSync: Bool, callback:  @escaping (Dictionary<String,AnyObject>?,WhiskError?) ->Void) throws {
+        
+        // set parameters
+        var paramsIsDict = false
+        if let parameters = parameters {
+            if parameters is Dictionary<String, AnyObject> {
+                paramsIsDict = true
+            }
+        }
+        
+        // set authorization string
+        let loginString = NSString(format: "%@:%@", accessKey, accessToken)
+        let loginData: Data = loginString.data(using: String.Encoding.utf8.rawValue)!
+        let base64LoginString = loginData.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0))
+        
+        let typeStr: String!
+        
+        // set type
+        switch type {
+        case .action:
+            typeStr = "actions"
+        case .trigger:
+            typeStr = "triggers"
+        }
+        
+        // get base URL
+        guard let actionURL = baseURL != nil ? baseURL : Config.getHostAndPath(type: typeStr) else {
+            callback(nil, WhiskError.httpError(description: "Base URL not set, try using whisk.baseUrl setting", statusCode: 400))
+            return
+        }
+        
+        // append namespace and trigger/action path
+        var syncName = "namespaces/"
+        
+        var namespaceStr = namespace
+        
+        if namespace.characters.count == 0 {
+            namespaceStr = "_"
+        }
+        
+        if let package = package {
+            if package.characters.count == 0 {
+                syncName = syncName + namespaceStr+"/"+typeStr+"/"+name
+            } else {
+                syncName = syncName + namespaceStr+"/"+typeStr+"/"+package+"/"+name
+            }
+        } else {
+            syncName = syncName + namespaceStr+"/"+typeStr+"/"+name
+        }
+        
+        // if action has results, specify as blocking
+        if isSync == true {
+            syncName += "?blocking=true"
+        }
+        
+        // use this for verbose replies
+        let restCall = actionURL+syncName
+        
+        guard let encodedPath = syncName.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) else {
+            callback(nil, WhiskError.httpError(description: "URL Encode error \(syncName)", statusCode: 400))
+            return
+        }
+        
+        syncName = encodedPath
+        
+        // create request
+        guard let url = URL(string:actionURL+syncName) else {
+            // send back error on main queue
+            
+            callback(nil, WhiskError.httpError(description: "Malformed url \(actionURL+syncName)", statusCode: 400))
+            
+            return
+            
+        }
+        
+        var request = URLRequest(url: url)
+        request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
+        request.addValue("Basic \(base64LoginString)", forHTTPHeaderField: "Authorization")
+        request.httpMethod = verb
+        
+        // create JSON from parameters dictionary
+        do {
+            
+            if let parameters = parameters {
+                if paramsIsDict {
+                    request.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: JSONSerialization.WritingOptions())
+                } else {
+                    if parameters is String {
+                        let str = "{\"payload\":\"\(parameters as! String)\"}"
+                        request.httpBody = str.data(using: String.Encoding.utf8)
+                    } else {
+                        let str = "{\"payload\": \(parameters)}"
+                        request.httpBody = str.data(using: String.Encoding.utf8)
+                    }
+                }
+            }
+            
+        } catch {
+            print("Error parsing JSON in Whisk request: \(error)")
+        }
+        
+        
+        // retrieve session as default or use developer specified session
+        let sess: URLSession!
+        if let _ = urlSession {
+            sess = urlSession
+        } else {
+            let sessConfig = URLSessionConfiguration.default
+            sess = URLSession(configuration: sessConfig)
+        }
+        
+        // perform network request
+        let task = sess.dataTask(with: request) {
+            data, response, error in
+            let statusCode: Int!
+            
+            if let error = error {
+                
+                if let httpResponse = response as? HTTPURLResponse {
+                    statusCode = httpResponse.statusCode
+                } else {
+                    statusCode = -1
+                }
+                // return network transport error call on main queue
+                DispatchQueue.main.async {
+                    callback(nil, WhiskError.httpError(description: "\(error.localizedDescription)", statusCode: statusCode))
+                }
+                
+                return
+                
+            } else {
+                
+                if let httpResponse = response as? HTTPURLResponse {
+                    statusCode = httpResponse.statusCode
+                    do {
+                        // success
+                        if statusCode < 300 {
+                            
+                            switch verb {
+                                // is an action invocation
+                            case "POST":
+                                var jsonDict = [String:AnyObject]()
+                                
+                                let respDict = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as! Dictionary<String, AnyObject>
+                                jsonDict = respDict
+                                
+                                
+                                if let whiskError = jsonDict["error"] as? String {
+                                    
+                                    var errorCode = -1
+                                    if let code = jsonDict["code"] as? Int {
+                                        errorCode = code
+                                    }
+                                    // send back error on main queue
+                                    DispatchQueue.main.async {
+                                        callback(nil, WhiskError.whiskProcessingError(description: "errorCode:\(errorCode), \(whiskError)", errorCode: errorCode))
+                                    }
+                                    
+                                } else {
+                                    
+                                    var whiskReply = [String:AnyObject]()
+                                    
+                                    if self.verboseReplies == true {
+                                        whiskReply = jsonDict
+                                        
+                                        // add the rest call made to verbose replies for debugging
+                                        switch type {
+                                        case .action:
+                                            whiskReply["actionUrl"] = restCall as AnyObject?
+                                        case .trigger:
+                                            whiskReply["triggerUrl"] = restCall as AnyObject?
+                                        }
+                                        
+                                    } else {
+                                        let reply = jsonDict
+                                        whiskReply["activationId"] = reply["activationId"]
+                                        
+                                        if isSync == true {
+                                            if let whiskResponse = reply["response"] as? [String:AnyObject] {
+                                                
+                                                if let actionResult = whiskResponse["result"] {
+                                                    
+                                                    //if let payload = actionResult["payload"] {
+                                                    
+                                                    let payload:AnyObject? = actionResult
+                                                    if payload is String {
+                                                        do {
+                                                            
+                                                           let payloadObj =  try JSONSerialization.jsonObject(with: (payload as! String).data(using: String.Encoding.utf8)!, options: [])
+                                                           
+                                                            whiskReply["result"] = payloadObj as AnyObject
+                                                        } catch {
+                                                            print("Error parsing payload into JSON, defaulting to string")
+                                                            whiskReply = ["result" : "\(payload!)" as AnyObject]
+                                                        }
+                                                    } else {
+                                                        whiskReply["result"] = payload as AnyObject
+                                                    }
+                                                    //}
+                                                }
+                                            }
+                                        }
+                                    }
+                                    
+                                    // send back successful response on main queue
+                                    DispatchQueue.main.async {
+                                        callback(whiskReply, nil)
+                                    }
+                                }
+                                
+                                // get info about actions/triggers
+                                // not used right now
+                            case "GET":
+                                let jsonArray = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as! NSArray
+                                let jsonDict:Dictionary<String, AnyObject> = ["array":jsonArray]
+                                
+                                DispatchQueue.main.async {
+                                    callback(jsonDict, nil)
+                                }
+                                
+                            default:
+                                break
+                                
+                            }
+                        } else {
+                            DispatchQueue.main.async {
+                                callback(nil, WhiskError.httpError(description: "Whisk returned HTTP error code", statusCode: statusCode))
+                            }
+                        }
+                        
+                    } catch {
+                        print("Error parsing JSON from Whisk response: \(error)")
+                        DispatchQueue.main.async {
+                            callback(nil, WhiskError.jsonError(description: "\(error)"))
+                        }
+                    }
+                }
+            }
+        }
+        
+        task.resume()
+        
+        
+    }
+    
+    /* Convert qualified name string into component parts of action or trigger call */
+    class func processQualifiedName(_ qName: String) throws -> (namespace:String, package: String?, name: String) {
+        var namespace = "_"
+        var package: String? = nil
+        var name = ""
+        var doesSpecifyNamespace = false
+        
+        if qName.characters.first == "/" {
+            doesSpecifyNamespace = true
+        }
+        
+        let pathParts = qName.characters.split { $0 == "/" }.map(String.init)
+        
+        if doesSpecifyNamespace == true {
+            if pathParts.count == 2 {
+                namespace = pathParts[0]
+                name = pathParts[1]
+            } else if pathParts.count == 3 {
+                namespace = pathParts[0]
+                package = pathParts[1]
+                name = pathParts[2]
+            } else {
+                throw WhiskError.qualifiedNameFormat(description: "Cannot parse \(qName)")
+            }
+        } else {
+            if pathParts.count == 1 {
+                name = pathParts[0]
+            } else if pathParts.count == 2 {
+                package = pathParts[0]
+                name = pathParts[1]
+            } else {
+                throw WhiskError.qualifiedNameFormat(description: "Cannot parse \(qName)")
+            }
+        }
+        
+        return (namespace, package, name)
+    }
+    
+}
+
+
diff --git a/whiskbot-demo-app/Pods/OpenWhisk/README.md b/whiskbot-demo-app/Pods/OpenWhisk/README.md
new file mode 100644
index 0000000..dc124c3
--- /dev/null
+++ b/whiskbot-demo-app/Pods/OpenWhisk/README.md
@@ -0,0 +1,252 @@
+# Swift Client SDK for OpenWhisk
+This is a Swift-based client SDK for OpenWhisk. You can use it to connect to the [IBM Bluemix OpenWhisk service](http://www.ibm.com/cloud-computing/bluemix/openwhisk/), or you own installation of [OpenWhisk](https://github.com/openwhisk/openwhisk).  It partially implements the OpenWhisk [REST API](https://github.com/openwhisk/openwhisk/blob/master/docs/reference.md#rest-api) and allows you to invoke actions and fire triggers. The client SDK is compatible with Swift 3.x and runs on iOS 9 & 10, WatchOS 3, and Darwin.  Since this code uses classes like URLSession, Linux support is linked to the current status of [Foundation on Linux](https://github.com/apple/swift-corelibs-foundation). 
+
+## Installation
+You can install the SDK using the source code in this repo, as a Cocoapod for iOS and WatchOS apps, Carthage, and as a package using the Swift Package Manager for Darwin CLI apps.
+
+### Source Code Installation
+To build the source code:
+- Clone this repo.
+- Open the `OpenWhisk.xcodeproj` file in Xcode 8.0
+- Build the OpenWhisk target for an iOS app or the OpenWhiskWatch target for a WatchOS app.
+- Locate the binary framework file (usually in `debug` or `release` directories at `~/Library/Developer/Xcode/DerivedData/$projectName-*`) and add it to the "Embedded Binaries" list in the General settings of your apps' target.
+
+### CocoaPods Installation
+The [official CocoaPods website](http://cocoapods.org) has detailed instructions on how to install and use CocoaPods.
+
+The following lines in a Podfile will install the SDK for an iOS app with a watch OS extension: 
+
+```
+install! 'cocoapods', :deterministic_uuids => false
+use_frameworks!
+
+target 'MyApp' do
+     pod 'OpenWhisk', :git => 'https://github.com/openwhisk/openwhisk-client-swift.git', :tag => '0.2.2'
+end
+
+target 'MyApp WatchKit Extension' do 
+     pod 'OpenWhisk', :git => 'https://github.com/openwhisk/openwhisk-client-swift.git', :tag => '0.2.2'
+end
+```
+You may get the warning 'target overrides the `EMBEDDED_CONTENT_CONTAINS_SWIFT` ' when you have a watch target.  You can eliminate this warning by changing this setting in "Build Settings" to the value '$(inherited)'.
+
+After installation, open your project workspace.  You may get the following warning when building:
+`Use Legacy Swift Language Version” (SWIFT_VERSION) is required to be configured correctly for targets which use Swift. Use the [Edit > Convert > To Current Swift Syntax…] menu to choose a Swift version or use the Build Settings editor to configure the build setting directly.`
+This is caused if Cocoapods does not update the Swift version in the Pods project.  To fix, select the Pods project and the OpenWhisk target.  Go to Build Settings and change the setting `Use Legacy Swift Language Version` to `no`. You can also add the following post installation instructions at the end of you Podfile:
+
+```
+post_install do |installer|
+  installer.pods_project.targets.each do |target|
+    target.build_configurations.each do |config|
+      config.build_settings['SWIFT_VERSION'] = '3.0'
+    end
+  end
+end
+```
+
+### Carthage Installation
+
+Visit the [official Carthage site on Github](https://github.com/Carthage/Carthage) for detailed instructions on installing and using Carthage.
+
+Here is an example Cartfile for iOS installation using Carthage:  
+
+```
+github "openwhisk/openwhisk-client-swift.git" ~> 0.2.2 # Or latest version
+
+```
+
+### Swift Package Manager
+Use the Swift Package Manager to install into a Darwin CLI app.  Below is an example Package.swift manifest file you can use:
+
+```
+import PackageDescription
+
+let package = Package(
+  name:  "PackageTest",
+  dependencies: [
+    .Package(url:  "https://github.com/openwhisk/openwhisk-client-swift.git", versions: Version(0,0,0)..<Version(1,0,0)),
+  ]
+)
+```
+
+## Usage
+
+To get up and running quickly, create a WhiskCredentials object with your OpenWhisk API credentials and create a Whisk instance from that.
+
+You create a credentials object as:
+
+```
+let credentialsConfiguration = WhiskCredentials(accessKey: "myKey", accessToken: "myToken")
+
+let whisk = Whisk(credentials: credentialsConfiguration!)
+```
+
+You can retrieve the key and token with the following CLI command:
+
+```
+wsk property get --auth
+```
+
+```
+whisk auth              kkkkkkkk-kkkk-kkkk-kkkk-kkkkkkkkkkkk:tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt
+```
+
+The strings before and after the colon are your key and token, respectively.
+
+### Invoke an OpenWhisk Action
+Call "invokeAction" with the action name to invoke a remote action. You can specify the namespace the action belongs to, or just leave it blank to accept the default namespace.  Use a dictionary to pass parameters to the action as required.
+
+```swift
+// In this example, we are invoking an action to print a message to the OpenWhisk Console
+var params = Dictionary<String, String>()
+params["payload"] = "Hi from mobile"
+
+do {
+    try whisk.invokeAction(name: "helloConsole", package: "mypackage", namespace: "mynamespace", parameters: params, hasResult: false, callback: {(reply, error) -> Void in 
+        if let error = error {
+            //do something
+            print("Error invoking action \(error.localizedDescription)")
+        } else {
+            print("Action invoked!")
+        }
+        
+    })
+} catch {
+    print("Error \(error)")
+}
+```
+
+In the above example, we are invoking the "helloConsole" action using the default namespace. 
+
+### Fire an OpenWhisk Trigger
+To fire a remote OpenWhisk trigger, call the "fireTrigger" method.  Pass in parameters as required using a dictionary.
+
+```swift
+// In this example we are firing a trigger when our location has changed by a certain amount
+
+var locationParams = Dictionary<String, String>()
+locationParams["payload"] = "{\"lat\":41.27093, \"lon\":-73.77763}"
+
+do {
+    try whisk.fireTrigger(name: "locationChanged", package: "mypackage", namespace: "mynamespace", parameters: locationParams, callback: {(reply, error) -> Void in
+        
+        if let error = error {
+            print("Error firing trigger \(error.localizedDescription)")
+        } else {
+            print("Trigger fired!")
+        }
+    })
+} catch {
+    print("Error \(error)")
+}
+```
+In the above example, we are firing a trigger "locationChanged".
+
+### Actions that return a result
+If the action returns a result, set hasResult to true in the invokeAction call. The result of the action is returned in the reply dictionary, for example:
+
+```swift
+do {
+    try whisk.invokeAction(name: "actionWithResult", package: "mypackage", namespace: "mynamespace", parameters: params, hasResult: true, callback: {(reply, error) -> Void in
+        
+        if let error = error {
+            //do something
+            print("Error invoking action \(error.localizedDescription)")
+            
+        } else {
+            var result = reply["result"]
+            print("Got result \(result)")
+        }
+        
+        
+    })
+} catch {
+    print("Error \(error)")
+}
+```
+By default, the SDK will only return the activationId and any result produced by the invoked action.  To get metadata of the entire response object, which includes the HTTP response status code and the REST API URL the SDK tried to call, use this setting:
+
+```
+whisk.verboseReplies = true
+```
+
+The REST API URL called will be in the actionUrl/triggerUrl fields of the response.
+
+## SDK configuration
+
+You can configure the SDK to work with different installations of OpenWhisk using the baseURL parameter. For instance:
+
+```swift
+whisk.baseURL = "http://localhost:8080"
+```
+will use an OpenWhisk running at localhost:8080.  If you do not specify the baseUrl, the Mobile SDK will use the instance running at https://openwhisk.ng.bluemix.net
+
+You can pass in a custom URLSession in case you require special network handling.  For example, you may have your own OpenWhisk installation that uses self-signed certificates:
+
+```swift
+
+// create a network delegate that trusts everything
+class NetworkUtilsDelegate: NSObject, URLSessionDelegate {
+    func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
+        
+        completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))
+    }
+}
+
+// create an URLSession that uses the trusting delegate
+let session = URLSession(configuration: URLSessionConfiguration.default, delegate: NetworkUtilsDelegate(), delegateQueue:OperationQueue.main)
+
+// set the SDK to use this urlSession instead of the default shared one
+whisk.urlSession = session
+```
+#### Support for Qualified Names
+All actions and triggers have a fully qualified name which is made up of a namespace, a package, and an action/trigger name. The SDK can accept these as parameters when invoking an action or firing a trigger. The SDK also provides a function that accepts a fully qualified name that looks like "/mynamespace/mypackage/nameOfActionOrTrigger". The qualified name string supports unnamed default values for namespaces and packages that all OpenWhisk users have, so the following parsing rules apply:
+
+1. qName = "foo" will result in namespace = default, package = default, action/trigger = "foo"
+2. qName = "mypackage/foo" will result in namespace = default, package = mypackage, action/trigger = "foo"
+3. qName = "/mynamespace/foo" will result in namespace = mynamespace, package = default, action/trigger = "foo"
+4. qName = "/mynamespace/mypackage/foo will result in namespace = mynamespace, package = mypackage, action/trigger = "foo" 
+
+All other combinations will throw a WhiskError.QualifiedName error. When using qualified names, you must wrap the call in a do/try/catch block.
+
+#### SDK Button
+For convenience, the iOS version of the SDK includes a WhiskButton, which extends the UIButton to allow it to invoke OpenWhisk actions.  To use this:
+
+```swift
+var whiskButton = WhiskButton(frame: CGRectMake(0,0,20,20))
+
+whiskButton.setupWhiskAction("helloConsole", package: "mypackage", namespace: "_", credentials: credentialsConfiguration!, hasResult: false, parameters: nil, urlSession: nil)
+
+let myParams = ["name":"value"]
+
+// Call this when you detect a press event, e.g. in an IBAction, to invoke the action 
+whiskButton.invokeAction(parameters: myParams, callback: { reply, error in
+    if let error = error {
+        print("Oh no, error: \(error)")
+    } else {
+        print("Success: \(reply)")
+    }
+})
+
+// or alternatively you can setup a "self contained" button that listens for press events on itself and invokes an action
+
+var whiskButtonSelfContained = WhiskButton(frame: CGRectMake(0,0,20,20))
+whiskButtonSelfContained.listenForPressEvents = true
+do { 
+
+   // use qualified name API which requires do/try/catch
+   try whiskButtonSelfContained.setupWhiskAction("mypackage/helloConsole", credentials: credentialsConfiguration!, hasResult: false, parameters: nil, urlSession: nil)
+   whiskButtonSelfContained.actionButtonCallback = { reply, error in
+
+       if let error = error {
+           print("Oh no, error: \(error)")
+       } else {
+           print("Success: \(reply)")
+       }
+   }
+} catch {
+   print("Error setting up button \(error)")
+}
+
+```
+
diff --git a/whiskbot-demo-app/Pods/Pods.xcodeproj/project.pbxproj b/whiskbot-demo-app/Pods/Pods.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..36dde94
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Pods.xcodeproj/project.pbxproj
@@ -0,0 +1,1924 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 46;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		002CFBE7E95979BE7DC143EF5A3817A6 /* OpenWhiskConfig.plist in Resources */ = {isa = PBXBuildFile; fileRef = 08A19369CBAF450999400FF04093F9F6 /* OpenWhiskConfig.plist */; };
+		0258A1B465E4F0F23E354076BDAA6361 /* JSQMessagesToolbarButtonFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = B2022CCF86504DEE4212F5088EB85C0D /* JSQMessagesToolbarButtonFactory.m */; };
+		04113425D6044E3BB06BEC9D4C631EAF /* JSQVideoMediaItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 523ADBF605FF49D24C108258E415995A /* JSQVideoMediaItem.m */; };
+		048D02CBD0A8636E6830140C4D48CA32 /* JSQMessagesCollectionViewCellOutgoing.xib in Resources */ = {isa = PBXBuildFile; fileRef = 839B00C0162E241008D63F99291CB733 /* JSQMessagesCollectionViewCellOutgoing.xib */; };
+		04C9F27D8BD6D02BCD9A4A4086C2ED41 /* SwiftyJSON-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = AA8A93E04C1104374D776C16471FAD4A /* SwiftyJSON-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		06B20D9837A06A4D524D3F66E029D468 /* JSQMessagesKeyboardController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A774AFBF8AD1F7A08544FF69FE5D9AC /* JSQMessagesKeyboardController.m */; };
+		0FC068A6DD03CACA24535E284B60FD71 /* JSQMessagesComposerTextView.h in Headers */ = {isa = PBXBuildFile; fileRef = 24EA3A1C0EEEFB702BDDF549F827B4B9 /* JSQMessagesComposerTextView.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		104E8110FE9622F86FC8BB1E3075ED21 /* UIView+JSQMessages.m in Sources */ = {isa = PBXBuildFile; fileRef = 12B8F59ED02DA476D7FDF55B6400132F /* UIView+JSQMessages.m */; };
+		18E6DE6A5C5196F931759B4D545DE975 /* JSQMessagesCollectionViewCellIncoming.xib in Resources */ = {isa = PBXBuildFile; fileRef = 78D378A9010E603FB2DF71D8C9411203 /* JSQMessagesCollectionViewCellIncoming.xib */; };
+		1D175A520B3D6B2B3134593270CF4C3B /* JSQPhotoMediaItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 27B56560D5AF134F0C119D1A72AF6245 /* JSQPhotoMediaItem.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		1EA2E6DFBE4AC13642F05FDAA29C2C50 /* JSQMessagesInputToolbar.h in Headers */ = {isa = PBXBuildFile; fileRef = 81EFE896FEBF3830AA892C77434B3104 /* JSQMessagesInputToolbar.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		200AE7D9FF81A5659D02E515B85D4B23 /* JSQMessagesToolbarButtonFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = C335EF8EB1B73539DA51195895FE5E9C /* JSQMessagesToolbarButtonFactory.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		2219255BCD9D285E7B23E2DBA4D7B9C1 /* NSBundle+JSQMessages.m in Sources */ = {isa = PBXBuildFile; fileRef = D951390938AEA8F708B45789ED5233FC /* NSBundle+JSQMessages.m */; };
+		2367C9536DABA06DEAA798CC180ED67C /* JSQMessagesBubbleImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 5632C7586BC13E17EEB1DA29A2DB0897 /* JSQMessagesBubbleImage.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		23B31DAECE298E56760B53206971C6E0 /* JSQMessagesCollectionView.h in Headers */ = {isa = PBXBuildFile; fileRef = 137633D209338CFE262D55234D544673 /* JSQMessagesCollectionView.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		242D23D0EB67922D7A2DF72154DFBB6F /* JSQMessageAvatarImageDataSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 0A7FF38F1A28A29DF3551820C1183DD8 /* JSQMessageAvatarImageDataSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		28F54EA3F7D44B2EB87871CCF142BF9A /* OpenWhiskResources.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 5439BCE9F884F5B855E14A1106428F65 /* OpenWhiskResources.bundle */; };
+		29B73968F1BA2987FEF099C812351349 /* JSQMessagesToolbarContentView.m in Sources */ = {isa = PBXBuildFile; fileRef = B74329AD8B58F50A6EA020362A120339 /* JSQMessagesToolbarContentView.m */; };
+		2BEEF86EA54921FB3C49742F41015BE1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F3A9D7DDA636949F4A572BF11C945894 /* Foundation.framework */; };
+		2C9F7C1DABBFB9CB281783A5DB445C44 /* JSQMessagesCollectionViewLayoutAttributes.h in Headers */ = {isa = PBXBuildFile; fileRef = F2A6BB68756E33B1783CEDB7C2FC7D0F /* JSQMessagesCollectionViewLayoutAttributes.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		2D1D88CBBF20C68BAC3D0904888B9DB8 /* OpenWhiskSDK.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C43D91D112DEA50800B76415F1DD556 /* OpenWhiskSDK.swift */; };
+		319E1BA9E6B38CE41234EDABD73C4C38 /* NSBundle+JSQMessages.h in Headers */ = {isa = PBXBuildFile; fileRef = EF640E189547B049B93373748A3EEE3E /* NSBundle+JSQMessages.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		33BB9AD3741F3ECF75411A4E3C82B74D /* JSQSystemSoundPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 82F7B578958269C5258FC7E8F30522A8 /* JSQSystemSoundPlayer.m */; };
+		39D7C670879E236D85F82657BB4DAD2A /* UIDevice+JSQMessages.h in Headers */ = {isa = PBXBuildFile; fileRef = ACF793F7B931AC1744C1A32CA52FAEB5 /* UIDevice+JSQMessages.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		3AE5C5C51ADABC338D7AEF33F46596D0 /* JSQMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A0218030BDA7A668945C17B377CDE8F /* JSQMessage.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		3BB813F15A688BB4041390038DFCAE9C /* Pods-WhiskBotUITests-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = D9CE9CBB798554FF607F2083552E9B0C /* Pods-WhiskBotUITests-dummy.m */; };
+		4181D69DD3D5967E508669254DFC85C3 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F3A9D7DDA636949F4A572BF11C945894 /* Foundation.framework */; };
+		41D50BBEA635DAD4E95FF71D4DD1D8AA /* JSQMessagesAssets.bundle in Resources */ = {isa = PBXBuildFile; fileRef = E487F3F9735AE5FE5718C483467DF2C3 /* JSQMessagesAssets.bundle */; };
+		43DD24A70EA8929B76F71D84B536DE1F /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 996355680669F249B21242C877FC2E3D /* AVFoundation.framework */; };
+		453C72A633A06CC9D3FB02BCCFD62F83 /* OpenWhisk.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B1E768DBF7A64002D7DBCEB6241D2B1 /* OpenWhisk.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		45BBCE2ECEC4891384F0F0D45BD2499A /* JSQSystemSoundPlayer+JSQMessages.h in Headers */ = {isa = PBXBuildFile; fileRef = EE2281E9EEF131DE52FDD3D6334CE413 /* JSQSystemSoundPlayer+JSQMessages.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		49FBC73695AB31538136416D8C16E401 /* UIColor+JSQMessages.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F16AAC39A31F790E65324FAF4F8AF86 /* UIColor+JSQMessages.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		4A0B511C1EE50388FD1640B3A4F3C27D /* UIDevice+JSQMessages.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E820F8DA32722BA55B55D1555F68224 /* UIDevice+JSQMessages.m */; };
+		4BB4FDF8AC4FC772F11D5E20A6F50CCA /* JSQLocationMediaItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B49B05639D369C1E0B261A45BA9AF09 /* JSQLocationMediaItem.m */; };
+		4CCBF4DC98798CF31A907A6271104368 /* JSQMessagesTypingIndicatorFooterView.m in Sources */ = {isa = PBXBuildFile; fileRef = FB1542B93BC9FC63800ACB01B665B489 /* JSQMessagesTypingIndicatorFooterView.m */; };
+		4DA12AA1089FFF8B526DE898A9B8DC39 /* OpenWhiskButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = A06ACEAA91EF5AC2362C5617236E41CA /* OpenWhiskButton.swift */; };
+		51800A4F3F65CB87DC667860D7DCDF66 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F3A9D7DDA636949F4A572BF11C945894 /* Foundation.framework */; };
+		523985DCBCFF0F95DA244BA5BD0C3780 /* JSQVideoMediaItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 7FA142E76A0AB287CBDF5828D3A8A2FA /* JSQVideoMediaItem.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		54B4C7E82F92DD998C63F9EC869C20C9 /* JSQMessagesBubbleImageFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B2410B2A66933193F786BCAB7EF6F5B /* JSQMessagesBubbleImageFactory.m */; };
+		55D190B2A2B2B5BE0F8B320BDA5A439A /* JSQMediaItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 008CD56D2A9D887C6CA89AB42B893A38 /* JSQMediaItem.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		561D081EAB6F263BD3FA0B444C395030 /* JSQMessagesCellTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = D1CF40A047117C82290A1058941EDB5B /* JSQMessagesCellTextView.m */; };
+		56EE115614D32FF57180D7683412D915 /* UIColor+JSQMessages.m in Sources */ = {isa = PBXBuildFile; fileRef = 2048485DCDC18ABC17382421C9766DAC /* UIColor+JSQMessages.m */; };
+		579F5B08F5D8299F4BB0A9AB44C84FA7 /* JSQMessageData.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FB063200C27A97F7268EC4FAB0FA47D /* JSQMessageData.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		597DCDBBC3F2A87D7BE4BBAB00D90385 /* JSQSystemSoundPlayer.h in Headers */ = {isa = PBXBuildFile; fileRef = F704CA3647F8168CB674CA6A0F13D0A6 /* JSQSystemSoundPlayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		5E3CD934B1911134558C5CB7FF0BA1B4 /* JSQMessagesCollectionViewFlowLayoutInvalidationContext.h in Headers */ = {isa = PBXBuildFile; fileRef = CD5472B819970B89BD631D8924D36F61 /* JSQMessagesCollectionViewFlowLayoutInvalidationContext.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		5E7C3EBEDD021CD5B54E9D40EC2B0AA2 /* Pods-WhiskBot-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 562798E79FEF0FAA25FC84ABBE019ABA /* Pods-WhiskBot-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		5E7C46E9368070A9FE5150F7CFAE82D1 /* JSQMessagesCollectionViewFlowLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 6BED8305BB403CD646B6671E983F6E77 /* JSQMessagesCollectionViewFlowLayout.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		60F1422BB7B9420A6DA85D3671052B4B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F3A9D7DDA636949F4A572BF11C945894 /* Foundation.framework */; };
+		64812729D8DE634B9524C5319F72E932 /* JSQMessagesCollectionViewFlowLayoutInvalidationContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 669DFA429490E99312D2AF9176726683 /* JSQMessagesCollectionViewFlowLayoutInvalidationContext.m */; };
+		67AF387C8C6EBB766FD33141E8E072E6 /* Pods-WhiskBot-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F04F54DFFF7FA4F939A1CD34C8CA0C2 /* Pods-WhiskBot-dummy.m */; };
+		6923138460C4EEDB05974A333D3976D8 /* SwiftyJSON-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = E22C8E19DB0D55A41A0003A9137C306C /* SwiftyJSON-dummy.m */; };
+		6B3E1EF3C0A0280C1E99603DFC2966F0 /* JSQMessagesViewController-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = B6FD760E0F2CBD1D05957092DEEBC4E4 /* JSQMessagesViewController-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		6CCE35C0E52AD7C8175B08C75B325049 /* JSQMessagesLabel.h in Headers */ = {isa = PBXBuildFile; fileRef = F6C1E24A90012EB6BEBFE7FFDAFABAFD /* JSQMessagesLabel.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		6CFA0C1B6E580D5EC5F8B4E36ACDE892 /* UIImage+JSQMessages.h in Headers */ = {isa = PBXBuildFile; fileRef = 5338AF82B5DF605A76C25FD68FD5CAAC /* UIImage+JSQMessages.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		6D5671FAD658E09E2E03A7B935F50010 /* JSQMessagesLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ED60225EB1B1523C892FD30E0AE52BF /* JSQMessagesLabel.m */; };
+		6E68CD04C09B3F0359FF672A2AE6F90D /* JSQMessagesComposerTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 29D4AB4B8989FFBEB0ECC0A220095917 /* JSQMessagesComposerTextView.m */; };
+		712931D97B07F23295FABC8FAA89505D /* NSString+JSQMessages.m in Sources */ = {isa = PBXBuildFile; fileRef = C1BDCB2545982BC887E50DE30DB51474 /* NSString+JSQMessages.m */; };
+		733E8CA810F0F437C9C7FDE6DA60B9E9 /* JSQMessagesInputToolbar.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FA229F8BAF0897BF479EE12044E675B /* JSQMessagesInputToolbar.m */; };
+		74EAADDADC835AE371509AF4BC19EED7 /* JSQMessagesKeyboardController.h in Headers */ = {isa = PBXBuildFile; fileRef = DD5D81E33CBDAFA3E824F492E5C72298 /* JSQMessagesKeyboardController.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		768F1DE7CA5E754BE0F06A52066B3544 /* JSQMessages.h in Headers */ = {isa = PBXBuildFile; fileRef = E91F4B9A0BC720BEC72EBBA95D2CF07A /* JSQMessages.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		78BA75223D5CBFB27AC98092DA67839B /* JSQMessagesBubblesSizeCalculator.h in Headers */ = {isa = PBXBuildFile; fileRef = F3622E44030FA7D10F5B1122B214265A /* JSQMessagesBubblesSizeCalculator.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		7A16F2A86CB1A5D66DDBCFEE7B6BAA20 /* JSQMessagesMediaPlaceholderView.m in Sources */ = {isa = PBXBuildFile; fileRef = B2568859A31454E85D0DDB53E81052AA /* JSQMessagesMediaPlaceholderView.m */; };
+		80AC20A5B7B098AEB98604C320BAD232 /* JSQMessagesBubbleImage.m in Sources */ = {isa = PBXBuildFile; fileRef = E56651EE83581E7015971470565D5A33 /* JSQMessagesBubbleImage.m */; };
+		81480EB7934E94B4BE172527B6EC8F79 /* JSQMessagesCollectionViewCellIncoming.h in Headers */ = {isa = PBXBuildFile; fileRef = 1D18904915E4E168CBA8F1789FF6D6F6 /* JSQMessagesCollectionViewCellIncoming.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		843166B023307AD37F03434FAC558E4F /* JSQMessagesCollectionViewCellOutgoing.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C36EC8238E174F1DABA3B3632E03CB7 /* JSQMessagesCollectionViewCellOutgoing.m */; };
+		850324C28282E0D219E54071A5A86F49 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9CE638AAEFF7B8D9906628BC54CDA28 /* AudioToolbox.framework */; };
+		867CA269771C0C2939021BAED4A96C39 /* JSQMessagesTimestampFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 85E80E91A69378812DE1457F6A22336B /* JSQMessagesTimestampFormatter.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		87A792E3DD909716060338A8D718681F /* JSQMessagesTypingIndicatorFooterView.h in Headers */ = {isa = PBXBuildFile; fileRef = A6AC92966BD107195AEDD210A6613CD8 /* JSQMessagesTypingIndicatorFooterView.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		89D842477092AE8F70A518FB11893B8E /* UIImage+JSQMessages.m in Sources */ = {isa = PBXBuildFile; fileRef = 158EBD0C78A350D4D575E66E0D27D1FC /* UIImage+JSQMessages.m */; };
+		8CF27DDD56556F901EA411AF3261639E /* JSQMessagesMediaViewBubbleImageMasker.m in Sources */ = {isa = PBXBuildFile; fileRef = 09FA42C91BAB4F76F257950DADB4AC9D /* JSQMessagesMediaViewBubbleImageMasker.m */; };
+		8DBCD01CAC80EABF1EB242ACE7787C8A /* JSQMessagesLoadEarlierHeaderView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B1E60FC29ACF2A4F1209F40003D15805 /* JSQMessagesLoadEarlierHeaderView.xib */; };
+		8EE602132538049A7F1C7FDF2D092500 /* WatchConnectivity.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ECCE05562EE8259BD66A4D8549F45D7D /* WatchConnectivity.framework */; };
+		8FF808C38E2A1978A476C0C1D72C9F97 /* JSQAudioMediaItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 09537B783BB7AF6836A80E566BD96D7E /* JSQAudioMediaItem.m */; };
+		9022B43E902DFE27B8107A37AC8B3726 /* JSQMessagesCollectionViewLayoutAttributes.m in Sources */ = {isa = PBXBuildFile; fileRef = 0E939CA94972407B11A07F1662A0F1A6 /* JSQMessagesCollectionViewLayoutAttributes.m */; };
+		906CF49EA6116446BBEBAE24B677171A /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 76727AD97A82910125E01CA59AE3AE45 /* MapKit.framework */; };
+		92BEF1647B36808EB1ECD72C59E453FF /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 471580DB2F88EC3FFF50E724050771C8 /* QuartzCore.framework */; };
+		97566BA16346218BCCD0F0E38EB70E0C /* OpenWhisk-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 837686D24EF3C59E97AD747B8E42FE59 /* OpenWhisk-dummy.m */; };
+		980C43DE877CCD4131F0D6EFB68249F5 /* JSQMessagesViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A69233DE37E9CC07726584F755CCAC77 /* JSQMessagesViewController.m */; };
+		98175010AA1363461D0DBD6A8F79C6F6 /* Pods-WhiskBotUITests-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = BFF9546A1A360A1C9AE34E84403854FF /* Pods-WhiskBotUITests-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		997BD5E794C0947A7183BBC413D53D43 /* JSQSystemSoundPlayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1E518923D3703D9F802F3486A14A04C6 /* JSQSystemSoundPlayer.framework */; };
+		9C847E9CB58D21A0D6CA6E1E6EF45114 /* NSString+JSQMessages.h in Headers */ = {isa = PBXBuildFile; fileRef = FC563929A1E1F988ECD8AA0E3778761C /* NSString+JSQMessages.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		9CC971CE0EA48027B893A8AA5F2C452C /* JSQMessagesBubbleImageFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = 52948C9E932454C58519EE359B6D752A /* JSQMessagesBubbleImageFactory.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		9F80FD930EFABE333171E6812AFFFF89 /* UIView+JSQMessages.h in Headers */ = {isa = PBXBuildFile; fileRef = C50A7C871EF8856E5A9BF5D9F9657ED6 /* UIView+JSQMessages.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		A159C0A3164478623E459164250E45C4 /* JSQSystemSoundPlayer+JSQMessages.m in Sources */ = {isa = PBXBuildFile; fileRef = 27B8106C4458685FE4A67C6F21BC3AB5 /* JSQSystemSoundPlayer+JSQMessages.m */; };
+		A243D6BE06DC9AF7C7A5A3806E39F6ED /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F3A9D7DDA636949F4A572BF11C945894 /* Foundation.framework */; };
+		A4F6DA7C20CC4B16DF0BBD943991108D /* JSQMessageBubbleImageDataSource.h in Headers */ = {isa = PBXBuildFile; fileRef = F5C3902474460BCF24DC302F56D77759 /* JSQMessageBubbleImageDataSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		B01BCEA53EAD2B9D468DA470ACE25399 /* JSQMessagesViewController-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 2EF73E06EB317BD3823B5B9E7179A31D /* JSQMessagesViewController-dummy.m */; };
+		B29D907250856963C8C41CEC8336CF3B /* JSQMessagesAvatarImage.m in Sources */ = {isa = PBXBuildFile; fileRef = C8C844EB7121934D0F720F7A531FCD13 /* JSQMessagesAvatarImage.m */; };
+		B4E2F424298D517511F47AFBCE7877D1 /* JSQMessagesViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = C1F40AE792ECE3FA2020F5DD8D61A78C /* JSQMessagesViewController.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		B74724F4DE7AF477390ABC79AAD35BAE /* JSQMessagesCollectionViewCellIncoming.m in Sources */ = {isa = PBXBuildFile; fileRef = CCA4141FEAAD0D67C33FBA939E405624 /* JSQMessagesCollectionViewCellIncoming.m */; };
+		B7F1D9E14737FA7269D75A6D01BBB5A9 /* JSQMessagesCollectionViewDataSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C134BBF26C9AB247794E86D7F27ADBC /* JSQMessagesCollectionViewDataSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		B87FE02FA7A0A8F226501245ADC88D3D /* JSQMessagesToolbarContentView.h in Headers */ = {isa = PBXBuildFile; fileRef = 3EB23AA1AC111C55B1D41522697C7145 /* JSQMessagesToolbarContentView.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		B9C946F65F417847AFF6D5C24587E091 /* JSQMessagesBubbleSizeCalculating.h in Headers */ = {isa = PBXBuildFile; fileRef = FD3E0B32AC160ACC001DBF5E651FB7AF /* JSQMessagesBubbleSizeCalculating.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		BB6FF60A541DD5C3E58F806470690041 /* JSQMessagesCollectionViewDelegateFlowLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = CDCA653F2D59221364A7ECCECED0DA1E /* JSQMessagesCollectionViewDelegateFlowLayout.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		BF0E34A09822C4909CEB31F59BE7501D /* JSQAudioMediaItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 38A60B05D3B97467DF11564D3D6AC59A /* JSQAudioMediaItem.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		BFC12801804825AE4228285DC2FC11DF /* JSQAudioMediaViewAttributes.m in Sources */ = {isa = PBXBuildFile; fileRef = C8F98294D1983BEA4FE3F457A8C4989B /* JSQAudioMediaViewAttributes.m */; };
+		C1AC507D95B47716673A6E2C8C115ECD /* JSQMessagesTimestampFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = ED28BDD59A966699C7C9A72F7639ACBC /* JSQMessagesTimestampFormatter.m */; };
+		C65DCBDD4FAF45D8BDDB686C7453083E /* JSQMessageMediaData.h in Headers */ = {isa = PBXBuildFile; fileRef = F6835C72593775C52D26B5DA131D4ED1 /* JSQMessageMediaData.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		C72B319F3B855F71D31C0ABF4EC7C543 /* JSQMessagesLoadEarlierHeaderView.h in Headers */ = {isa = PBXBuildFile; fileRef = D38E67C0D8AD1E842511C1041E0DA670 /* JSQMessagesLoadEarlierHeaderView.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		C9A7BF29CFB2EB284506526C409DCE56 /* JSQMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C096913A44638C9FF06389F47E88BC18 /* JSQMessage.m */; };
+		D1E0D269EAD4B6FB01948F7780BD5469 /* JSQLocationMediaItem.h in Headers */ = {isa = PBXBuildFile; fileRef = C0B65DC86A880F922CEBC9F3E5CC3AF6 /* JSQLocationMediaItem.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		D3567A0612E42452CFAB03E8B1340304 /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7EFF1DFA240127D69DE6486EACFA6CA5 /* CoreLocation.framework */; };
+		D3606896B42830A11DDCD11445D58346 /* JSQMediaItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 819E17543E4A28081E442AF1F5B8045E /* JSQMediaItem.m */; };
+		D41B237B5DBDA6D59088BE1ABA4596D3 /* Pods-WhiskBotTests-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 17BDBB489B4BA34A42740765706DCCF1 /* Pods-WhiskBotTests-dummy.m */; };
+		D5B81490C9275F3ED06D80AD8D56C22C /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0BA2E44C99F5FF8F3E0B076513D6AA04 /* CoreGraphics.framework */; };
+		D5EDF701474637548017366D85DC162B /* JSQSystemSoundPlayer-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = FF17B4389A252DB6AF8FC536E082A284 /* JSQSystemSoundPlayer-dummy.m */; };
+		D687858C00D384EE419E0AD92032CE67 /* JSQMessagesCollectionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A51FBA9CAA64F939B8DA7384EE17892 /* JSQMessagesCollectionView.m */; };
+		D789A642D4D8D3E2E99D2143408C2FDE /* JSQMessagesCellTextView.h in Headers */ = {isa = PBXBuildFile; fileRef = 70F782DA8A82FE5FC81F2885FA386E22 /* JSQMessagesCellTextView.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		D7EDBB9EB9B04876ED0EE483F3912554 /* JSQAudioMediaViewAttributes.h in Headers */ = {isa = PBXBuildFile; fileRef = 86F90D5E1CF5FF38F9EC08899B857F34 /* JSQAudioMediaViewAttributes.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		D98DE2E729D20CA6B3B8A65BF804DE1C /* SwiftyJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 869E5C9330F8AB896BDE11D91CA5A00C /* SwiftyJSON.swift */; };
+		DCEDDC81694661E52029E4AB6F5503A4 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F3A9D7DDA636949F4A572BF11C945894 /* Foundation.framework */; };
+		DD2A2BCB72C62F2F32B3D2DA324636FE /* JSQMessagesViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 14204B4BBB6CB361B545CC9D098ED079 /* JSQMessagesViewController.xib */; };
+		DDC94334FF57682689F2BFEBCB52597E /* JSQMessagesAvatarImageFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = 44F4D90CD5DC9FFDEC1B30B6CB4CF5CA /* JSQMessagesAvatarImageFactory.m */; };
+		E205C0F77B94CAD08E1191486CFA314E /* JSQMessagesToolbarContentView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 84D19FA1ED51AE56090168F529E67722 /* JSQMessagesToolbarContentView.xib */; };
+		E3A1194D92818EA1B4A6F05836E04256 /* JSQMessagesCollectionViewFlowLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 54E1820B9CD67C29A2BB00B0D75FCDEA /* JSQMessagesCollectionViewFlowLayout.m */; };
+		E43F5C2A5260C8F5C3DE4D42D1588D10 /* OpenWhisk-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 8735697439CFAA992245A33FCD92FE33 /* OpenWhisk-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		E529FEE5379F6E8CA6B442FE25F59AB1 /* JSQPhotoMediaItem.m in Sources */ = {isa = PBXBuildFile; fileRef = E20915CFBF2792634B0A5C570BDB557B /* JSQPhotoMediaItem.m */; };
+		E5CC09AD78DFFD452C6EF1F1E6EC3532 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F3A9D7DDA636949F4A572BF11C945894 /* Foundation.framework */; };
+		EAC4E8296D47BC3806FAFCA254D9B02B /* JSQMessagesMediaPlaceholderView.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A2628E557A53E7A8D94F55FD10463AA /* JSQMessagesMediaPlaceholderView.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		EC0993DEAE73EDFA1E42B92454D53096 /* JSQMessagesAvatarImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 5B8C6B186209FCAE9D391888B99EEB6C /* JSQMessagesAvatarImage.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		EF01C1164030F88E748AC5D9AB8C07DC /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 39F5D414BB0D3DB75AD9E790F19CE7D9 /* UIKit.framework */; };
+		F0AAAFE8E84ECF9A6CBCCBBA96B16A29 /* JSQSystemSoundPlayer-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = CC1A9750FC63FD5C5803D47ED94D74FB /* JSQSystemSoundPlayer-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		F28CEFF02311DDB81E5DB68B295E067D /* JSQMessagesCollectionViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = A691440B4B7C1FC17992013A0F3E3C69 /* JSQMessagesCollectionViewCell.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		F38E75F1F613396092B4083EF8F80A15 /* Config.swift in Sources */ = {isa = PBXBuildFile; fileRef = 694FAE07DC5AB847E958D2A4B54B34F7 /* Config.swift */; };
+		F3D3406B798B94A35C7F26504C44ADC9 /* JSQMessagesTypingIndicatorFooterView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 93246B602F8E677A5C3DCE7969986D77 /* JSQMessagesTypingIndicatorFooterView.xib */; };
+		F4E9E5BF69FAFDCDA5E2F60C2523220F /* JSQMessagesCollectionViewCellOutgoing.h in Headers */ = {isa = PBXBuildFile; fileRef = 8811FCBBEC0220FA1A53A7C107E2E2DC /* JSQMessagesCollectionViewCellOutgoing.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		FC1DFCD7AE1E5A781EB5E43CA6AABDA4 /* JSQMessagesBubblesSizeCalculator.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CDB3D3465606AE4E3C126B3FD679D5A /* JSQMessagesBubblesSizeCalculator.m */; };
+		FC82748F1DB8B5C127C9D94C9EE10323 /* JSQMessagesMediaViewBubbleImageMasker.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D8EF51DE15722891CA0E226F61321EA /* JSQMessagesMediaViewBubbleImageMasker.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		FD435B4361EA18F8CFD1FD2C237F47A2 /* JSQMessagesCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 002DBFAF8722DFAD3F6A513268095099 /* JSQMessagesCollectionViewCell.m */; };
+		FD83ACAE9094227EE3F99B6D50FA37DE /* Pods-WhiskBotTests-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 3C3A075C0977DFC12CA7DFF55B48173C /* Pods-WhiskBotTests-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		FDD63C5749F1E20C7AA2E2D079282117 /* JSQMessagesAvatarImageFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = 5E37FC4863B0BDD655077FF394FBF902 /* JSQMessagesAvatarImageFactory.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		FEAE161C5872A47553E1F76AB1C33F93 /* JSQMessagesLoadEarlierHeaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = F3606765C0D54047515AB590ED1545B6 /* JSQMessagesLoadEarlierHeaderView.m */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+		61164EA705E7F0300CF5C3E57AD1321D /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = E9F7495D838404B103ADD79427CA9320;
+			remoteInfo = "OpenWhisk-OpenWhiskResources";
+		};
+		BF03284A54D288F18C8C95E8229C78CA /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = DAF887453904739967DA9E16B68AD96E;
+			remoteInfo = OpenWhisk;
+		};
+		C10A60E444C404E0967413316E725A2F /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = C7DCF2B547F7871B9BFD74DE93B0E173;
+			remoteInfo = JSQSystemSoundPlayer;
+		};
+		C202DFB61C4E1CF8A6D812B2F242EDAE /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = C7DCF2B547F7871B9BFD74DE93B0E173;
+			remoteInfo = JSQSystemSoundPlayer;
+		};
+		E5F485F562A6E6626A53F7C045B56853 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = D0581AF7BF4A6DA140D280B19ECC7BFF;
+			remoteInfo = JSQMessagesViewController;
+		};
+		FB4D609DB85C1E7E009DFFC2F8FEA1FE /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 54D9E87F2717881BD1F94F4A65434708;
+			remoteInfo = SwiftyJSON;
+		};
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+		002DBFAF8722DFAD3F6A513268095099 /* JSQMessagesCollectionViewCell.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = JSQMessagesCollectionViewCell.m; path = JSQMessagesViewController/Views/JSQMessagesCollectionViewCell.m; sourceTree = "<group>"; };
+		008CD56D2A9D887C6CA89AB42B893A38 /* JSQMediaItem.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQMediaItem.h; path = JSQMessagesViewController/Model/JSQMediaItem.h; sourceTree = "<group>"; };
+		01D2F7404794BB33AB2DC2BE0AB21B39 /* Pods-WhiskBotUITests-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-WhiskBotUITests-acknowledgements.markdown"; sourceTree = "<group>"; };
+		08A19369CBAF450999400FF04093F9F6 /* OpenWhiskConfig.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = OpenWhiskConfig.plist; path = OpenWhisk/OpenWhiskConfig.plist; sourceTree = "<group>"; };
+		09537B783BB7AF6836A80E566BD96D7E /* JSQAudioMediaItem.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = JSQAudioMediaItem.m; path = JSQMessagesViewController/Model/JSQAudioMediaItem.m; sourceTree = "<group>"; };
+		09FA42C91BAB4F76F257950DADB4AC9D /* JSQMessagesMediaViewBubbleImageMasker.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = JSQMessagesMediaViewBubbleImageMasker.m; path = JSQMessagesViewController/Factories/JSQMessagesMediaViewBubbleImageMasker.m; sourceTree = "<group>"; };
+		0A7FF38F1A28A29DF3551820C1183DD8 /* JSQMessageAvatarImageDataSource.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQMessageAvatarImageDataSource.h; path = JSQMessagesViewController/Model/JSQMessageAvatarImageDataSource.h; sourceTree = "<group>"; };
+		0BA2E44C99F5FF8F3E0B076513D6AA04 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.0.sdk/System/Library/Frameworks/CoreGraphics.framework; sourceTree = DEVELOPER_DIR; };
+		0C36EC8238E174F1DABA3B3632E03CB7 /* JSQMessagesCollectionViewCellOutgoing.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = JSQMessagesCollectionViewCellOutgoing.m; path = JSQMessagesViewController/Views/JSQMessagesCollectionViewCellOutgoing.m; sourceTree = "<group>"; };
+		0CD22AE59F55893A567B5EFF54022481 /* Pods-WhiskBotTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-WhiskBotTests.release.xcconfig"; sourceTree = "<group>"; };
+		0E939CA94972407B11A07F1662A0F1A6 /* JSQMessagesCollectionViewLayoutAttributes.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = JSQMessagesCollectionViewLayoutAttributes.m; path = JSQMessagesViewController/Layout/JSQMessagesCollectionViewLayoutAttributes.m; sourceTree = "<group>"; };
+		0F6CA7B1E7A7E55AB93AE91F93CC8581 /* Pods_WhiskBotUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_WhiskBotUITests.framework; path = "Pods-WhiskBotUITests.framework"; sourceTree = BUILT_PRODUCTS_DIR; };
+		0FC783F6EFCE0BA1DA5E47B30A0BF885 /* JSQSystemSoundPlayer-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "JSQSystemSoundPlayer-prefix.pch"; sourceTree = "<group>"; };
+		12B8F59ED02DA476D7FDF55B6400132F /* UIView+JSQMessages.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIView+JSQMessages.m"; path = "JSQMessagesViewController/Categories/UIView+JSQMessages.m"; sourceTree = "<group>"; };
+		137633D209338CFE262D55234D544673 /* JSQMessagesCollectionView.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQMessagesCollectionView.h; path = JSQMessagesViewController/Views/JSQMessagesCollectionView.h; sourceTree = "<group>"; };
+		14204B4BBB6CB361B545CC9D098ED079 /* JSQMessagesViewController.xib */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = file.xib; name = JSQMessagesViewController.xib; path = JSQMessagesViewController/Controllers/JSQMessagesViewController.xib; sourceTree = "<group>"; };
+		158EBD0C78A350D4D575E66E0D27D1FC /* UIImage+JSQMessages.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIImage+JSQMessages.m"; path = "JSQMessagesViewController/Categories/UIImage+JSQMessages.m"; sourceTree = "<group>"; };
+		17BDBB489B4BA34A42740765706DCCF1 /* Pods-WhiskBotTests-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-WhiskBotTests-dummy.m"; sourceTree = "<group>"; };
+		1A0218030BDA7A668945C17B377CDE8F /* JSQMessage.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQMessage.h; path = JSQMessagesViewController/Model/JSQMessage.h; sourceTree = "<group>"; };
+		1A509411156D95A98D50167105B77EAE /* OpenWhisk.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = OpenWhisk.xcconfig; sourceTree = "<group>"; };
+		1B2410B2A66933193F786BCAB7EF6F5B /* JSQMessagesBubbleImageFactory.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = JSQMessagesBubbleImageFactory.m; path = JSQMessagesViewController/Factories/JSQMessagesBubbleImageFactory.m; sourceTree = "<group>"; };
+		1D18904915E4E168CBA8F1789FF6D6F6 /* JSQMessagesCollectionViewCellIncoming.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQMessagesCollectionViewCellIncoming.h; path = JSQMessagesViewController/Views/JSQMessagesCollectionViewCellIncoming.h; sourceTree = "<group>"; };
+		1E518923D3703D9F802F3486A14A04C6 /* JSQSystemSoundPlayer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = JSQSystemSoundPlayer.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+		1E820F8DA32722BA55B55D1555F68224 /* UIDevice+JSQMessages.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIDevice+JSQMessages.m"; path = "JSQMessagesViewController/Categories/UIDevice+JSQMessages.m"; sourceTree = "<group>"; };
+		1ED60225EB1B1523C892FD30E0AE52BF /* JSQMessagesLabel.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = JSQMessagesLabel.m; path = JSQMessagesViewController/Views/JSQMessagesLabel.m; sourceTree = "<group>"; };
+		2048485DCDC18ABC17382421C9766DAC /* UIColor+JSQMessages.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIColor+JSQMessages.m"; path = "JSQMessagesViewController/Categories/UIColor+JSQMessages.m"; sourceTree = "<group>"; };
+		24EA3A1C0EEEFB702BDDF549F827B4B9 /* JSQMessagesComposerTextView.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQMessagesComposerTextView.h; path = JSQMessagesViewController/Views/JSQMessagesComposerTextView.h; sourceTree = "<group>"; };
+		27B56560D5AF134F0C119D1A72AF6245 /* JSQPhotoMediaItem.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQPhotoMediaItem.h; path = JSQMessagesViewController/Model/JSQPhotoMediaItem.h; sourceTree = "<group>"; };
+		27B8106C4458685FE4A67C6F21BC3AB5 /* JSQSystemSoundPlayer+JSQMessages.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "JSQSystemSoundPlayer+JSQMessages.m"; path = "JSQMessagesViewController/Categories/JSQSystemSoundPlayer+JSQMessages.m"; sourceTree = "<group>"; };
+		29D4AB4B8989FFBEB0ECC0A220095917 /* JSQMessagesComposerTextView.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = JSQMessagesComposerTextView.m; path = JSQMessagesViewController/Views/JSQMessagesComposerTextView.m; sourceTree = "<group>"; };
+		2D8EF51DE15722891CA0E226F61321EA /* JSQMessagesMediaViewBubbleImageMasker.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQMessagesMediaViewBubbleImageMasker.h; path = JSQMessagesViewController/Factories/JSQMessagesMediaViewBubbleImageMasker.h; sourceTree = "<group>"; };
+		2EF73E06EB317BD3823B5B9E7179A31D /* JSQMessagesViewController-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "JSQMessagesViewController-dummy.m"; sourceTree = "<group>"; };
+		309C2FE1DAC71CFED05CF3E81ABBEFA7 /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		34665CA684DF54FE684B80706C2372B4 /* Pods-WhiskBot-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-WhiskBot-acknowledgements.plist"; sourceTree = "<group>"; };
+		36105D6BFA5F5AB6ABE70E71EE8228C4 /* Pods-WhiskBot.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-WhiskBot.debug.xcconfig"; sourceTree = "<group>"; };
+		38A60B05D3B97467DF11564D3D6AC59A /* JSQAudioMediaItem.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQAudioMediaItem.h; path = JSQMessagesViewController/Model/JSQAudioMediaItem.h; sourceTree = "<group>"; };
+		39F5D414BB0D3DB75AD9E790F19CE7D9 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.0.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; };
+		3A2628E557A53E7A8D94F55FD10463AA /* JSQMessagesMediaPlaceholderView.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQMessagesMediaPlaceholderView.h; path = JSQMessagesViewController/Views/JSQMessagesMediaPlaceholderView.h; sourceTree = "<group>"; };
+		3A51FBA9CAA64F939B8DA7384EE17892 /* JSQMessagesCollectionView.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = JSQMessagesCollectionView.m; path = JSQMessagesViewController/Views/JSQMessagesCollectionView.m; sourceTree = "<group>"; };
+		3C3A075C0977DFC12CA7DFF55B48173C /* Pods-WhiskBotTests-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-WhiskBotTests-umbrella.h"; sourceTree = "<group>"; };
+		3E59C121D88BCBE218B2135B87F3752E /* Pods-WhiskBotTests.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; path = "Pods-WhiskBotTests.modulemap"; sourceTree = "<group>"; };
+		3EB23AA1AC111C55B1D41522697C7145 /* JSQMessagesToolbarContentView.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQMessagesToolbarContentView.h; path = JSQMessagesViewController/Views/JSQMessagesToolbarContentView.h; sourceTree = "<group>"; };
+		3F16AAC39A31F790E65324FAF4F8AF86 /* UIColor+JSQMessages.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIColor+JSQMessages.h"; path = "JSQMessagesViewController/Categories/UIColor+JSQMessages.h"; sourceTree = "<group>"; };
+		3FB063200C27A97F7268EC4FAB0FA47D /* JSQMessageData.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQMessageData.h; path = JSQMessagesViewController/Model/JSQMessageData.h; sourceTree = "<group>"; };
+		42396F238671FFF118C7ADF194465EE6 /* Pods-WhiskBotUITests.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; path = "Pods-WhiskBotUITests.modulemap"; sourceTree = "<group>"; };
+		44F4D90CD5DC9FFDEC1B30B6CB4CF5CA /* JSQMessagesAvatarImageFactory.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = JSQMessagesAvatarImageFactory.m; path = JSQMessagesViewController/Factories/JSQMessagesAvatarImageFactory.m; sourceTree = "<group>"; };
+		471580DB2F88EC3FFF50E724050771C8 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.0.sdk/System/Library/Frameworks/QuartzCore.framework; sourceTree = DEVELOPER_DIR; };
+		49E1B6692BA8BBFC6B9A45C7216CEEAA /* OpenWhisk-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "OpenWhisk-prefix.pch"; sourceTree = "<group>"; };
+		4CDB3D3465606AE4E3C126B3FD679D5A /* JSQMessagesBubblesSizeCalculator.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = JSQMessagesBubblesSizeCalculator.m; path = JSQMessagesViewController/Layout/JSQMessagesBubblesSizeCalculator.m; sourceTree = "<group>"; };
+		523ADBF605FF49D24C108258E415995A /* JSQVideoMediaItem.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = JSQVideoMediaItem.m; path = JSQMessagesViewController/Model/JSQVideoMediaItem.m; sourceTree = "<group>"; };
+		52948C9E932454C58519EE359B6D752A /* JSQMessagesBubbleImageFactory.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQMessagesBubbleImageFactory.h; path = JSQMessagesViewController/Factories/JSQMessagesBubbleImageFactory.h; sourceTree = "<group>"; };
+		5338AF82B5DF605A76C25FD68FD5CAAC /* UIImage+JSQMessages.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIImage+JSQMessages.h"; path = "JSQMessagesViewController/Categories/UIImage+JSQMessages.h"; sourceTree = "<group>"; };
+		5393EAF83B4BC397AA0E38197BEFFEA2 /* Pods-WhiskBotTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-WhiskBotTests.debug.xcconfig"; sourceTree = "<group>"; };
+		5416324B801B367B951A02A8FC6688C2 /* Pods-WhiskBotTests-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-WhiskBotTests-frameworks.sh"; sourceTree = "<group>"; };
+		5439BCE9F884F5B855E14A1106428F65 /* OpenWhiskResources.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; name = OpenWhiskResources.bundle; path = OpenWhiskResources.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
+		54E1820B9CD67C29A2BB00B0D75FCDEA /* JSQMessagesCollectionViewFlowLayout.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = JSQMessagesCollectionViewFlowLayout.m; path = JSQMessagesViewController/Layout/JSQMessagesCollectionViewFlowLayout.m; sourceTree = "<group>"; };
+		562798E79FEF0FAA25FC84ABBE019ABA /* Pods-WhiskBot-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-WhiskBot-umbrella.h"; sourceTree = "<group>"; };
+		5632C7586BC13E17EEB1DA29A2DB0897 /* JSQMessagesBubbleImage.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQMessagesBubbleImage.h; path = JSQMessagesViewController/Model/JSQMessagesBubbleImage.h; sourceTree = "<group>"; };
+		591893BD9779F8D04A28A2FDE5C20562 /* JSQSystemSoundPlayer.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = JSQSystemSoundPlayer.xcconfig; sourceTree = "<group>"; };
+		5B8C6B186209FCAE9D391888B99EEB6C /* JSQMessagesAvatarImage.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQMessagesAvatarImage.h; path = JSQMessagesViewController/Model/JSQMessagesAvatarImage.h; sourceTree = "<group>"; };
+		5E37FC4863B0BDD655077FF394FBF902 /* JSQMessagesAvatarImageFactory.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQMessagesAvatarImageFactory.h; path = JSQMessagesViewController/Factories/JSQMessagesAvatarImageFactory.h; sourceTree = "<group>"; };
+		5F04F54DFFF7FA4F939A1CD34C8CA0C2 /* Pods-WhiskBot-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-WhiskBot-dummy.m"; sourceTree = "<group>"; };
+		62D801F74C63E4AF2AC31300AC59517D /* Pods-WhiskBot.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-WhiskBot.release.xcconfig"; sourceTree = "<group>"; };
+		65CBE1C4D4BEE40A0E2685AC3154D481 /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		669DFA429490E99312D2AF9176726683 /* JSQMessagesCollectionViewFlowLayoutInvalidationContext.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = JSQMessagesCollectionViewFlowLayoutInvalidationContext.m; path = JSQMessagesViewController/Layout/JSQMessagesCollectionViewFlowLayoutInvalidationContext.m; sourceTree = "<group>"; };
+		694FAE07DC5AB847E958D2A4B54B34F7 /* Config.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Config.swift; path = OpenWhisk/Config.swift; sourceTree = "<group>"; };
+		6A774AFBF8AD1F7A08544FF69FE5D9AC /* JSQMessagesKeyboardController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = JSQMessagesKeyboardController.m; path = JSQMessagesViewController/Controllers/JSQMessagesKeyboardController.m; sourceTree = "<group>"; };
+		6BED8305BB403CD646B6671E983F6E77 /* JSQMessagesCollectionViewFlowLayout.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQMessagesCollectionViewFlowLayout.h; path = JSQMessagesViewController/Layout/JSQMessagesCollectionViewFlowLayout.h; sourceTree = "<group>"; };
+		6C43D91D112DEA50800B76415F1DD556 /* OpenWhiskSDK.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = OpenWhiskSDK.swift; path = OpenWhisk/OpenWhiskSDK.swift; sourceTree = "<group>"; };
+		6E2487F53A3F4E2E57ACE0A8726037F2 /* Pods_WhiskBotTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_WhiskBotTests.framework; path = "Pods-WhiskBotTests.framework"; sourceTree = BUILT_PRODUCTS_DIR; };
+		6FA229F8BAF0897BF479EE12044E675B /* JSQMessagesInputToolbar.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = JSQMessagesInputToolbar.m; path = JSQMessagesViewController/Views/JSQMessagesInputToolbar.m; sourceTree = "<group>"; };
+		70F782DA8A82FE5FC81F2885FA386E22 /* JSQMessagesCellTextView.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQMessagesCellTextView.h; path = JSQMessagesViewController/Views/JSQMessagesCellTextView.h; sourceTree = "<group>"; };
+		72A5C96522803FF5746288E2D4BF7BCB /* JSQSystemSoundPlayer.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; path = JSQSystemSoundPlayer.modulemap; sourceTree = "<group>"; };
+		7314249DE86B4A4A274E818FA095ACDF /* Pods-WhiskBot-resources.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-WhiskBot-resources.sh"; sourceTree = "<group>"; };
+		76727AD97A82910125E01CA59AE3AE45 /* MapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MapKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.0.sdk/System/Library/Frameworks/MapKit.framework; sourceTree = DEVELOPER_DIR; };
+		78C2F6C14B4C102ECD25D29DD8B71F07 /* Pods_WhiskBot.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_WhiskBot.framework; path = "Pods-WhiskBot.framework"; sourceTree = BUILT_PRODUCTS_DIR; };
+		78CB398B7917F42026966FEC8CC10F21 /* JSQMessagesViewController-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "JSQMessagesViewController-prefix.pch"; sourceTree = "<group>"; };
+		78D378A9010E603FB2DF71D8C9411203 /* JSQMessagesCollectionViewCellIncoming.xib */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = file.xib; name = JSQMessagesCollectionViewCellIncoming.xib; path = JSQMessagesViewController/Views/JSQMessagesCollectionViewCellIncoming.xib; sourceTree = "<group>"; };
+		7B000E56A23ADB1C2BAE337A4DC76C75 /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		7B49B05639D369C1E0B261A45BA9AF09 /* JSQLocationMediaItem.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = JSQLocationMediaItem.m; path = JSQMessagesViewController/Model/JSQLocationMediaItem.m; sourceTree = "<group>"; };
+		7D920E76A0AE87F8142333C9B1BC3BB8 /* Pods-WhiskBotUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-WhiskBotUITests.release.xcconfig"; sourceTree = "<group>"; };
+		7E628F43052995CF85AFA41F67178C02 /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		7EFF1DFA240127D69DE6486EACFA6CA5 /* CoreLocation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreLocation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.0.sdk/System/Library/Frameworks/CoreLocation.framework; sourceTree = DEVELOPER_DIR; };
+		7FA142E76A0AB287CBDF5828D3A8A2FA /* JSQVideoMediaItem.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQVideoMediaItem.h; path = JSQMessagesViewController/Model/JSQVideoMediaItem.h; sourceTree = "<group>"; };
+		819E17543E4A28081E442AF1F5B8045E /* JSQMediaItem.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = JSQMediaItem.m; path = JSQMessagesViewController/Model/JSQMediaItem.m; sourceTree = "<group>"; };
+		81EFE896FEBF3830AA892C77434B3104 /* JSQMessagesInputToolbar.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQMessagesInputToolbar.h; path = JSQMessagesViewController/Views/JSQMessagesInputToolbar.h; sourceTree = "<group>"; };
+		82F7B578958269C5258FC7E8F30522A8 /* JSQSystemSoundPlayer.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = JSQSystemSoundPlayer.m; path = JSQSystemSoundPlayer/Classes/JSQSystemSoundPlayer.m; sourceTree = "<group>"; };
+		837686D24EF3C59E97AD747B8E42FE59 /* OpenWhisk-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "OpenWhisk-dummy.m"; sourceTree = "<group>"; };
+		839B00C0162E241008D63F99291CB733 /* JSQMessagesCollectionViewCellOutgoing.xib */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = file.xib; name = JSQMessagesCollectionViewCellOutgoing.xib; path = JSQMessagesViewController/Views/JSQMessagesCollectionViewCellOutgoing.xib; sourceTree = "<group>"; };
+		84D19FA1ED51AE56090168F529E67722 /* JSQMessagesToolbarContentView.xib */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = file.xib; name = JSQMessagesToolbarContentView.xib; path = JSQMessagesViewController/Views/JSQMessagesToolbarContentView.xib; sourceTree = "<group>"; };
+		85E80E91A69378812DE1457F6A22336B /* JSQMessagesTimestampFormatter.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQMessagesTimestampFormatter.h; path = JSQMessagesViewController/Factories/JSQMessagesTimestampFormatter.h; sourceTree = "<group>"; };
+		869E5C9330F8AB896BDE11D91CA5A00C /* SwiftyJSON.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SwiftyJSON.swift; path = Source/SwiftyJSON.swift; sourceTree = "<group>"; };
+		86F90D5E1CF5FF38F9EC08899B857F34 /* JSQAudioMediaViewAttributes.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQAudioMediaViewAttributes.h; path = JSQMessagesViewController/Layout/JSQAudioMediaViewAttributes.h; sourceTree = "<group>"; };
+		8735697439CFAA992245A33FCD92FE33 /* OpenWhisk-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "OpenWhisk-umbrella.h"; sourceTree = "<group>"; };
+		8811FCBBEC0220FA1A53A7C107E2E2DC /* JSQMessagesCollectionViewCellOutgoing.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQMessagesCollectionViewCellOutgoing.h; path = JSQMessagesViewController/Views/JSQMessagesCollectionViewCellOutgoing.h; sourceTree = "<group>"; };
+		88F3EEAEADC461B8E52D90E294BD9618 /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		8C134BBF26C9AB247794E86D7F27ADBC /* JSQMessagesCollectionViewDataSource.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQMessagesCollectionViewDataSource.h; path = JSQMessagesViewController/Model/JSQMessagesCollectionViewDataSource.h; sourceTree = "<group>"; };
+		93246B602F8E677A5C3DCE7969986D77 /* JSQMessagesTypingIndicatorFooterView.xib */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = file.xib; name = JSQMessagesTypingIndicatorFooterView.xib; path = JSQMessagesViewController/Views/JSQMessagesTypingIndicatorFooterView.xib; sourceTree = "<group>"; };
+		93A4A3777CF96A4AAC1D13BA6DCCEA73 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
+		996355680669F249B21242C877FC2E3D /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.0.sdk/System/Library/Frameworks/AVFoundation.framework; sourceTree = DEVELOPER_DIR; };
+		99C9BFC4E35F3109BC1EB296BC1954BB /* OpenWhisk.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; path = OpenWhisk.modulemap; sourceTree = "<group>"; };
+		9B1E768DBF7A64002D7DBCEB6241D2B1 /* OpenWhisk.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = OpenWhisk.h; path = OpenWhisk/OpenWhisk.h; sourceTree = "<group>"; };
+		9F6EFADCC4D6786370D365B3B99C88E2 /* Pods-WhiskBotTests-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-WhiskBotTests-acknowledgements.markdown"; sourceTree = "<group>"; };
+		A06ACEAA91EF5AC2362C5617236E41CA /* OpenWhiskButton.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = OpenWhiskButton.swift; path = OpenWhisk/OpenWhiskButton.swift; sourceTree = "<group>"; };
+		A20FA82DA1AA5214F869ACD683D8E4F8 /* JSQMessagesViewController.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = JSQMessagesViewController.xcconfig; sourceTree = "<group>"; };
+		A2D6C6AFC72922469AD789453F9C993E /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		A691440B4B7C1FC17992013A0F3E3C69 /* JSQMessagesCollectionViewCell.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQMessagesCollectionViewCell.h; path = JSQMessagesViewController/Views/JSQMessagesCollectionViewCell.h; sourceTree = "<group>"; };
+		A69233DE37E9CC07726584F755CCAC77 /* JSQMessagesViewController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = JSQMessagesViewController.m; path = JSQMessagesViewController/Controllers/JSQMessagesViewController.m; sourceTree = "<group>"; };
+		A6AC92966BD107195AEDD210A6613CD8 /* JSQMessagesTypingIndicatorFooterView.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQMessagesTypingIndicatorFooterView.h; path = JSQMessagesViewController/Views/JSQMessagesTypingIndicatorFooterView.h; sourceTree = "<group>"; };
+		A928AF548AC527539369052D443208F4 /* ResourceBundle-OpenWhiskResources-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "ResourceBundle-OpenWhiskResources-Info.plist"; sourceTree = "<group>"; };
+		AA8A93E04C1104374D776C16471FAD4A /* SwiftyJSON-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SwiftyJSON-umbrella.h"; sourceTree = "<group>"; };
+		ACF793F7B931AC1744C1A32CA52FAEB5 /* UIDevice+JSQMessages.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIDevice+JSQMessages.h"; path = "JSQMessagesViewController/Categories/UIDevice+JSQMessages.h"; sourceTree = "<group>"; };
+		AD4C022F84D40A1AB9C7A6F46838251D /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		B1E60FC29ACF2A4F1209F40003D15805 /* JSQMessagesLoadEarlierHeaderView.xib */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = file.xib; name = JSQMessagesLoadEarlierHeaderView.xib; path = JSQMessagesViewController/Views/JSQMessagesLoadEarlierHeaderView.xib; sourceTree = "<group>"; };
+		B2022CCF86504DEE4212F5088EB85C0D /* JSQMessagesToolbarButtonFactory.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = JSQMessagesToolbarButtonFactory.m; path = JSQMessagesViewController/Factories/JSQMessagesToolbarButtonFactory.m; sourceTree = "<group>"; };
+		B2568859A31454E85D0DDB53E81052AA /* JSQMessagesMediaPlaceholderView.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = JSQMessagesMediaPlaceholderView.m; path = JSQMessagesViewController/Views/JSQMessagesMediaPlaceholderView.m; sourceTree = "<group>"; };
+		B3AAEB152147C4CE1D36097EA0F42117 /* Pods-WhiskBotUITests-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-WhiskBotUITests-acknowledgements.plist"; sourceTree = "<group>"; };
+		B6FD760E0F2CBD1D05957092DEEBC4E4 /* JSQMessagesViewController-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "JSQMessagesViewController-umbrella.h"; sourceTree = "<group>"; };
+		B74329AD8B58F50A6EA020362A120339 /* JSQMessagesToolbarContentView.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = JSQMessagesToolbarContentView.m; path = JSQMessagesViewController/Views/JSQMessagesToolbarContentView.m; sourceTree = "<group>"; };
+		B7A0E5AE755BC3DFEE7E1AE32CBB449F /* Pods-WhiskBotTests-resources.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-WhiskBotTests-resources.sh"; sourceTree = "<group>"; };
+		BD1734D5878E207B7E20F9F6ED1000A3 /* JSQMessagesViewController.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = JSQMessagesViewController.framework; path = JSQMessagesViewController.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+		BFF9546A1A360A1C9AE34E84403854FF /* Pods-WhiskBotUITests-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-WhiskBotUITests-umbrella.h"; sourceTree = "<group>"; };
+		C096913A44638C9FF06389F47E88BC18 /* JSQMessage.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = JSQMessage.m; path = JSQMessagesViewController/Model/JSQMessage.m; sourceTree = "<group>"; };
+		C0B65DC86A880F922CEBC9F3E5CC3AF6 /* JSQLocationMediaItem.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQLocationMediaItem.h; path = JSQMessagesViewController/Model/JSQLocationMediaItem.h; sourceTree = "<group>"; };
+		C1BDCB2545982BC887E50DE30DB51474 /* NSString+JSQMessages.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "NSString+JSQMessages.m"; path = "JSQMessagesViewController/Categories/NSString+JSQMessages.m"; sourceTree = "<group>"; };
+		C1F40AE792ECE3FA2020F5DD8D61A78C /* JSQMessagesViewController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQMessagesViewController.h; path = JSQMessagesViewController/Controllers/JSQMessagesViewController.h; sourceTree = "<group>"; };
+		C335EF8EB1B73539DA51195895FE5E9C /* JSQMessagesToolbarButtonFactory.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQMessagesToolbarButtonFactory.h; path = JSQMessagesViewController/Factories/JSQMessagesToolbarButtonFactory.h; sourceTree = "<group>"; };
+		C50A7C871EF8856E5A9BF5D9F9657ED6 /* UIView+JSQMessages.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIView+JSQMessages.h"; path = "JSQMessagesViewController/Categories/UIView+JSQMessages.h"; sourceTree = "<group>"; };
+		C8C844EB7121934D0F720F7A531FCD13 /* JSQMessagesAvatarImage.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = JSQMessagesAvatarImage.m; path = JSQMessagesViewController/Model/JSQMessagesAvatarImage.m; sourceTree = "<group>"; };
+		C8F98294D1983BEA4FE3F457A8C4989B /* JSQAudioMediaViewAttributes.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = JSQAudioMediaViewAttributes.m; path = JSQMessagesViewController/Layout/JSQAudioMediaViewAttributes.m; sourceTree = "<group>"; };
+		CC1A9750FC63FD5C5803D47ED94D74FB /* JSQSystemSoundPlayer-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "JSQSystemSoundPlayer-umbrella.h"; sourceTree = "<group>"; };
+		CCA4141FEAAD0D67C33FBA939E405624 /* JSQMessagesCollectionViewCellIncoming.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = JSQMessagesCollectionViewCellIncoming.m; path = JSQMessagesViewController/Views/JSQMessagesCollectionViewCellIncoming.m; sourceTree = "<group>"; };
+		CD5472B819970B89BD631D8924D36F61 /* JSQMessagesCollectionViewFlowLayoutInvalidationContext.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQMessagesCollectionViewFlowLayoutInvalidationContext.h; path = JSQMessagesViewController/Layout/JSQMessagesCollectionViewFlowLayoutInvalidationContext.h; sourceTree = "<group>"; };
+		CDCA653F2D59221364A7ECCECED0DA1E /* JSQMessagesCollectionViewDelegateFlowLayout.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQMessagesCollectionViewDelegateFlowLayout.h; path = JSQMessagesViewController/Model/JSQMessagesCollectionViewDelegateFlowLayout.h; sourceTree = "<group>"; };
+		D04BEADFBC76C37B342CAE1B8ACF4446 /* Pods-WhiskBotUITests-resources.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-WhiskBotUITests-resources.sh"; sourceTree = "<group>"; };
+		D1CF40A047117C82290A1058941EDB5B /* JSQMessagesCellTextView.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = JSQMessagesCellTextView.m; path = JSQMessagesViewController/Views/JSQMessagesCellTextView.m; sourceTree = "<group>"; };
+		D2296E7EA273F26956339019F8765298 /* Pods-WhiskBotTests-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-WhiskBotTests-acknowledgements.plist"; sourceTree = "<group>"; };
+		D38E67C0D8AD1E842511C1041E0DA670 /* JSQMessagesLoadEarlierHeaderView.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQMessagesLoadEarlierHeaderView.h; path = JSQMessagesViewController/Views/JSQMessagesLoadEarlierHeaderView.h; sourceTree = "<group>"; };
+		D3DBE1A39662FA96A93017B47E7B2905 /* Pods-WhiskBotUITests-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-WhiskBotUITests-frameworks.sh"; sourceTree = "<group>"; };
+		D491E264123B228014D36E70F7B76EC7 /* OpenWhisk.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = OpenWhisk.framework; path = OpenWhisk.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+		D5FC255319BB50D4F88F06350E7B4844 /* JSQMessagesViewController.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; path = JSQMessagesViewController.modulemap; sourceTree = "<group>"; };
+		D750919FF4676B26827A551941A73B6F /* Pods-WhiskBot-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-WhiskBot-frameworks.sh"; sourceTree = "<group>"; };
+		D951390938AEA8F708B45789ED5233FC /* NSBundle+JSQMessages.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "NSBundle+JSQMessages.m"; path = "JSQMessagesViewController/Categories/NSBundle+JSQMessages.m"; sourceTree = "<group>"; };
+		D9CE638AAEFF7B8D9906628BC54CDA28 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.0.sdk/System/Library/Frameworks/AudioToolbox.framework; sourceTree = DEVELOPER_DIR; };
+		D9CE9CBB798554FF607F2083552E9B0C /* Pods-WhiskBotUITests-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-WhiskBotUITests-dummy.m"; sourceTree = "<group>"; };
+		DA301EE341F1E07F58CAF2F6190CE900 /* Pods-WhiskBot.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; path = "Pods-WhiskBot.modulemap"; sourceTree = "<group>"; };
+		DBFDAA0565A3919568B2B69EE389CC1C /* Pods-WhiskBotUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-WhiskBotUITests.debug.xcconfig"; sourceTree = "<group>"; };
+		DD5D81E33CBDAFA3E824F492E5C72298 /* JSQMessagesKeyboardController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQMessagesKeyboardController.h; path = JSQMessagesViewController/Controllers/JSQMessagesKeyboardController.h; sourceTree = "<group>"; };
+		DF6736E88E7AA9CED546E39D441EE925 /* SwiftyJSON-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SwiftyJSON-prefix.pch"; sourceTree = "<group>"; };
+		E20915CFBF2792634B0A5C570BDB557B /* JSQPhotoMediaItem.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = JSQPhotoMediaItem.m; path = JSQMessagesViewController/Model/JSQPhotoMediaItem.m; sourceTree = "<group>"; };
+		E22C8E19DB0D55A41A0003A9137C306C /* SwiftyJSON-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "SwiftyJSON-dummy.m"; sourceTree = "<group>"; };
+		E487F3F9735AE5FE5718C483467DF2C3 /* JSQMessagesAssets.bundle */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = "wrapper.plug-in"; name = JSQMessagesAssets.bundle; path = JSQMessagesViewController/Assets/JSQMessagesAssets.bundle; sourceTree = "<group>"; };
+		E56651EE83581E7015971470565D5A33 /* JSQMessagesBubbleImage.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = JSQMessagesBubbleImage.m; path = JSQMessagesViewController/Model/JSQMessagesBubbleImage.m; sourceTree = "<group>"; };
+		E814D96AD1A17F06CE577C508B3F0548 /* JSQSystemSoundPlayer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = JSQSystemSoundPlayer.framework; path = JSQSystemSoundPlayer.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+		E91F4B9A0BC720BEC72EBBA95D2CF07A /* JSQMessages.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQMessages.h; path = JSQMessagesViewController/JSQMessages.h; sourceTree = "<group>"; };
+		ECCE05562EE8259BD66A4D8549F45D7D /* WatchConnectivity.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WatchConnectivity.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.0.sdk/System/Library/Frameworks/WatchConnectivity.framework; sourceTree = DEVELOPER_DIR; };
+		ED28BDD59A966699C7C9A72F7639ACBC /* JSQMessagesTimestampFormatter.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = JSQMessagesTimestampFormatter.m; path = JSQMessagesViewController/Factories/JSQMessagesTimestampFormatter.m; sourceTree = "<group>"; };
+		EE2281E9EEF131DE52FDD3D6334CE413 /* JSQSystemSoundPlayer+JSQMessages.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "JSQSystemSoundPlayer+JSQMessages.h"; path = "JSQMessagesViewController/Categories/JSQSystemSoundPlayer+JSQMessages.h"; sourceTree = "<group>"; };
+		EF3BE07AAAE2B939C8A40C336C06670A /* SwiftyJSON.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SwiftyJSON.xcconfig; sourceTree = "<group>"; };
+		EF640E189547B049B93373748A3EEE3E /* NSBundle+JSQMessages.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "NSBundle+JSQMessages.h"; path = "JSQMessagesViewController/Categories/NSBundle+JSQMessages.h"; sourceTree = "<group>"; };
+		F2A6BB68756E33B1783CEDB7C2FC7D0F /* JSQMessagesCollectionViewLayoutAttributes.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQMessagesCollectionViewLayoutAttributes.h; path = JSQMessagesViewController/Layout/JSQMessagesCollectionViewLayoutAttributes.h; sourceTree = "<group>"; };
+		F3606765C0D54047515AB590ED1545B6 /* JSQMessagesLoadEarlierHeaderView.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = JSQMessagesLoadEarlierHeaderView.m; path = JSQMessagesViewController/Views/JSQMessagesLoadEarlierHeaderView.m; sourceTree = "<group>"; };
+		F3622E44030FA7D10F5B1122B214265A /* JSQMessagesBubblesSizeCalculator.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQMessagesBubblesSizeCalculator.h; path = JSQMessagesViewController/Layout/JSQMessagesBubblesSizeCalculator.h; sourceTree = "<group>"; };
+		F3A9D7DDA636949F4A572BF11C945894 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; };
+		F5C3902474460BCF24DC302F56D77759 /* JSQMessageBubbleImageDataSource.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQMessageBubbleImageDataSource.h; path = JSQMessagesViewController/Model/JSQMessageBubbleImageDataSource.h; sourceTree = "<group>"; };
+		F6835C72593775C52D26B5DA131D4ED1 /* JSQMessageMediaData.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQMessageMediaData.h; path = JSQMessagesViewController/Model/JSQMessageMediaData.h; sourceTree = "<group>"; };
+		F6C1E24A90012EB6BEBFE7FFDAFABAFD /* JSQMessagesLabel.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQMessagesLabel.h; path = JSQMessagesViewController/Views/JSQMessagesLabel.h; sourceTree = "<group>"; };
+		F704CA3647F8168CB674CA6A0F13D0A6 /* JSQSystemSoundPlayer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQSystemSoundPlayer.h; path = JSQSystemSoundPlayer/Classes/JSQSystemSoundPlayer.h; sourceTree = "<group>"; };
+		FA368FEB97439C24E38850A7DF5CBCAA /* SwiftyJSON.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = SwiftyJSON.framework; path = SwiftyJSON.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+		FB1542B93BC9FC63800ACB01B665B489 /* JSQMessagesTypingIndicatorFooterView.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = JSQMessagesTypingIndicatorFooterView.m; path = JSQMessagesViewController/Views/JSQMessagesTypingIndicatorFooterView.m; sourceTree = "<group>"; };
+		FC563929A1E1F988ECD8AA0E3778761C /* NSString+JSQMessages.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "NSString+JSQMessages.h"; path = "JSQMessagesViewController/Categories/NSString+JSQMessages.h"; sourceTree = "<group>"; };
+		FD3E0B32AC160ACC001DBF5E651FB7AF /* JSQMessagesBubbleSizeCalculating.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = JSQMessagesBubbleSizeCalculating.h; path = JSQMessagesViewController/Layout/JSQMessagesBubbleSizeCalculating.h; sourceTree = "<group>"; };
+		FD67E33372F19B2EAEF6EA009D8B9025 /* Pods-WhiskBot-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-WhiskBot-acknowledgements.markdown"; sourceTree = "<group>"; };
+		FD7504CC96BD99423F5A3619FD901535 /* SwiftyJSON.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; path = SwiftyJSON.modulemap; sourceTree = "<group>"; };
+		FF17B4389A252DB6AF8FC536E082A284 /* JSQSystemSoundPlayer-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "JSQSystemSoundPlayer-dummy.m"; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		040C2507C3340E681F3CBA134A3B988C /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				850324C28282E0D219E54071A5A86F49 /* AudioToolbox.framework in Frameworks */,
+				51800A4F3F65CB87DC667860D7DCDF66 /* Foundation.framework in Frameworks */,
+				EF01C1164030F88E748AC5D9AB8C07DC /* UIKit.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		04AA5AA42986F232B48554D8B61218D6 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				A243D6BE06DC9AF7C7A5A3806E39F6ED /* Foundation.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		11CB2C2CE1C75B2DE57CDD8F41264112 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				4181D69DD3D5967E508669254DFC85C3 /* Foundation.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		277B91F16F533170BC66571D168A14BB /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				60F1422BB7B9420A6DA85D3671052B4B /* Foundation.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		4E84ECB59116333EA452CC15E3772FD1 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		9382450C8A42AC3528F8F2E841E880D4 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				E5CC09AD78DFFD452C6EF1F1E6EC3532 /* Foundation.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		D2F108FFB11F430009AB0413A1436E45 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				43DD24A70EA8929B76F71D84B536DE1F /* AVFoundation.framework in Frameworks */,
+				D5B81490C9275F3ED06D80AD8D56C22C /* CoreGraphics.framework in Frameworks */,
+				D3567A0612E42452CFAB03E8B1340304 /* CoreLocation.framework in Frameworks */,
+				2BEEF86EA54921FB3C49742F41015BE1 /* Foundation.framework in Frameworks */,
+				997BD5E794C0947A7183BBC413D53D43 /* JSQSystemSoundPlayer.framework in Frameworks */,
+				906CF49EA6116446BBEBAE24B677171A /* MapKit.framework in Frameworks */,
+				92BEF1647B36808EB1ECD72C59E453FF /* QuartzCore.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F0020D3F2D7CCEBAD802161C1AB507EB /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				DCEDDC81694661E52029E4AB6F5503A4 /* Foundation.framework in Frameworks */,
+				8EE602132538049A7F1C7FDF2D092500 /* WatchConnectivity.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		0447656BA1BB1C8835FFD8FC5F653C94 /* Support Files */ = {
+			isa = PBXGroup;
+			children = (
+				7E628F43052995CF85AFA41F67178C02 /* Info.plist */,
+				D5FC255319BB50D4F88F06350E7B4844 /* JSQMessagesViewController.modulemap */,
+				A20FA82DA1AA5214F869ACD683D8E4F8 /* JSQMessagesViewController.xcconfig */,
+				2EF73E06EB317BD3823B5B9E7179A31D /* JSQMessagesViewController-dummy.m */,
+				78CB398B7917F42026966FEC8CC10F21 /* JSQMessagesViewController-prefix.pch */,
+				B6FD760E0F2CBD1D05957092DEEBC4E4 /* JSQMessagesViewController-umbrella.h */,
+			);
+			name = "Support Files";
+			path = "../Target Support Files/JSQMessagesViewController";
+			sourceTree = "<group>";
+		};
+		0AA4917E81B9EF2C4D870956CFCA1ADD /* Support Files */ = {
+			isa = PBXGroup;
+			children = (
+				A2D6C6AFC72922469AD789453F9C993E /* Info.plist */,
+				FD7504CC96BD99423F5A3619FD901535 /* SwiftyJSON.modulemap */,
+				EF3BE07AAAE2B939C8A40C336C06670A /* SwiftyJSON.xcconfig */,
+				E22C8E19DB0D55A41A0003A9137C306C /* SwiftyJSON-dummy.m */,
+				DF6736E88E7AA9CED546E39D441EE925 /* SwiftyJSON-prefix.pch */,
+				AA8A93E04C1104374D776C16471FAD4A /* SwiftyJSON-umbrella.h */,
+			);
+			name = "Support Files";
+			path = "../Target Support Files/SwiftyJSON";
+			sourceTree = "<group>";
+		};
+		2678BD089EB5A23C471415A54EE2ED45 /* Pods-WhiskBotUITests */ = {
+			isa = PBXGroup;
+			children = (
+				309C2FE1DAC71CFED05CF3E81ABBEFA7 /* Info.plist */,
+				42396F238671FFF118C7ADF194465EE6 /* Pods-WhiskBotUITests.modulemap */,
+				01D2F7404794BB33AB2DC2BE0AB21B39 /* Pods-WhiskBotUITests-acknowledgements.markdown */,
+				B3AAEB152147C4CE1D36097EA0F42117 /* Pods-WhiskBotUITests-acknowledgements.plist */,
+				D9CE9CBB798554FF607F2083552E9B0C /* Pods-WhiskBotUITests-dummy.m */,
+				D3DBE1A39662FA96A93017B47E7B2905 /* Pods-WhiskBotUITests-frameworks.sh */,
+				D04BEADFBC76C37B342CAE1B8ACF4446 /* Pods-WhiskBotUITests-resources.sh */,
+				BFF9546A1A360A1C9AE34E84403854FF /* Pods-WhiskBotUITests-umbrella.h */,
+				DBFDAA0565A3919568B2B69EE389CC1C /* Pods-WhiskBotUITests.debug.xcconfig */,
+				7D920E76A0AE87F8142333C9B1BC3BB8 /* Pods-WhiskBotUITests.release.xcconfig */,
+			);
+			name = "Pods-WhiskBotUITests";
+			path = "Target Support Files/Pods-WhiskBotUITests";
+			sourceTree = "<group>";
+		};
+		2F0E6FA5B39BC3AC82652CE2E20BD80F /* Pods-WhiskBotTests */ = {
+			isa = PBXGroup;
+			children = (
+				7B000E56A23ADB1C2BAE337A4DC76C75 /* Info.plist */,
+				3E59C121D88BCBE218B2135B87F3752E /* Pods-WhiskBotTests.modulemap */,
+				9F6EFADCC4D6786370D365B3B99C88E2 /* Pods-WhiskBotTests-acknowledgements.markdown */,
+				D2296E7EA273F26956339019F8765298 /* Pods-WhiskBotTests-acknowledgements.plist */,
+				17BDBB489B4BA34A42740765706DCCF1 /* Pods-WhiskBotTests-dummy.m */,
+				5416324B801B367B951A02A8FC6688C2 /* Pods-WhiskBotTests-frameworks.sh */,
+				B7A0E5AE755BC3DFEE7E1AE32CBB449F /* Pods-WhiskBotTests-resources.sh */,
+				3C3A075C0977DFC12CA7DFF55B48173C /* Pods-WhiskBotTests-umbrella.h */,
+				5393EAF83B4BC397AA0E38197BEFFEA2 /* Pods-WhiskBotTests.debug.xcconfig */,
+				0CD22AE59F55893A567B5EFF54022481 /* Pods-WhiskBotTests.release.xcconfig */,
+			);
+			name = "Pods-WhiskBotTests";
+			path = "Target Support Files/Pods-WhiskBotTests";
+			sourceTree = "<group>";
+		};
+		354359BA860F39BBDE9C8884364FF588 /* SwiftyJSON */ = {
+			isa = PBXGroup;
+			children = (
+				869E5C9330F8AB896BDE11D91CA5A00C /* SwiftyJSON.swift */,
+				0AA4917E81B9EF2C4D870956CFCA1ADD /* Support Files */,
+			);
+			name = SwiftyJSON;
+			path = SwiftyJSON;
+			sourceTree = "<group>";
+		};
+		386470E9C2DA0751E99D22C4FB37A201 /* iOS */ = {
+			isa = PBXGroup;
+			children = (
+				D9CE638AAEFF7B8D9906628BC54CDA28 /* AudioToolbox.framework */,
+				996355680669F249B21242C877FC2E3D /* AVFoundation.framework */,
+				0BA2E44C99F5FF8F3E0B076513D6AA04 /* CoreGraphics.framework */,
+				7EFF1DFA240127D69DE6486EACFA6CA5 /* CoreLocation.framework */,
+				F3A9D7DDA636949F4A572BF11C945894 /* Foundation.framework */,
+				76727AD97A82910125E01CA59AE3AE45 /* MapKit.framework */,
+				471580DB2F88EC3FFF50E724050771C8 /* QuartzCore.framework */,
+				39F5D414BB0D3DB75AD9E790F19CE7D9 /* UIKit.framework */,
+				ECCE05562EE8259BD66A4D8549F45D7D /* WatchConnectivity.framework */,
+			);
+			name = iOS;
+			sourceTree = "<group>";
+		};
+		4C8E5059F6522B6774365C8E45F34479 /* Resources */ = {
+			isa = PBXGroup;
+			children = (
+				08A19369CBAF450999400FF04093F9F6 /* OpenWhiskConfig.plist */,
+			);
+			name = Resources;
+			sourceTree = "<group>";
+		};
+		5F88CDB57301ABD87E1C552F7351EB1E /* Support Files */ = {
+			isa = PBXGroup;
+			children = (
+				88F3EEAEADC461B8E52D90E294BD9618 /* Info.plist */,
+				99C9BFC4E35F3109BC1EB296BC1954BB /* OpenWhisk.modulemap */,
+				1A509411156D95A98D50167105B77EAE /* OpenWhisk.xcconfig */,
+				837686D24EF3C59E97AD747B8E42FE59 /* OpenWhisk-dummy.m */,
+				49E1B6692BA8BBFC6B9A45C7216CEEAA /* OpenWhisk-prefix.pch */,
+				8735697439CFAA992245A33FCD92FE33 /* OpenWhisk-umbrella.h */,
+				A928AF548AC527539369052D443208F4 /* ResourceBundle-OpenWhiskResources-Info.plist */,
+			);
+			name = "Support Files";
+			path = "../Target Support Files/OpenWhisk";
+			sourceTree = "<group>";
+		};
+		688E60A7AF108DA91928105A90B73D5B /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				1E518923D3703D9F802F3486A14A04C6 /* JSQSystemSoundPlayer.framework */,
+				386470E9C2DA0751E99D22C4FB37A201 /* iOS */,
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
+		6A455ED444C10A2AAD191FBBF29515D7 /* Pods */ = {
+			isa = PBXGroup;
+			children = (
+				7E289D1CA1DE1655A89F2FF9F1F458C6 /* JSQMessagesViewController */,
+				D8624B10076AF1E2924B2295455C0F32 /* JSQSystemSoundPlayer */,
+				91E3F6E525B1B8DB1F10CEFB129ECDD5 /* OpenWhisk */,
+				354359BA860F39BBDE9C8884364FF588 /* SwiftyJSON */,
+			);
+			name = Pods;
+			sourceTree = "<group>";
+		};
+		6A7DD9A5CA2667AD0DC6CE46A4119ABB /* Targets Support Files */ = {
+			isa = PBXGroup;
+			children = (
+				CCECAB395DB7EBA55D38C85DA79FC10F /* Pods-WhiskBot */,
+				2F0E6FA5B39BC3AC82652CE2E20BD80F /* Pods-WhiskBotTests */,
+				2678BD089EB5A23C471415A54EE2ED45 /* Pods-WhiskBotUITests */,
+			);
+			name = "Targets Support Files";
+			sourceTree = "<group>";
+		};
+		7DB346D0F39D3F0E887471402A8071AB = {
+			isa = PBXGroup;
+			children = (
+				93A4A3777CF96A4AAC1D13BA6DCCEA73 /* Podfile */,
+				688E60A7AF108DA91928105A90B73D5B /* Frameworks */,
+				6A455ED444C10A2AAD191FBBF29515D7 /* Pods */,
+				C5E1BC056907A259F09535120921F915 /* Products */,
+				6A7DD9A5CA2667AD0DC6CE46A4119ABB /* Targets Support Files */,
+			);
+			sourceTree = "<group>";
+		};
+		7E289D1CA1DE1655A89F2FF9F1F458C6 /* JSQMessagesViewController */ = {
+			isa = PBXGroup;
+			children = (
+				38A60B05D3B97467DF11564D3D6AC59A /* JSQAudioMediaItem.h */,
+				09537B783BB7AF6836A80E566BD96D7E /* JSQAudioMediaItem.m */,
+				86F90D5E1CF5FF38F9EC08899B857F34 /* JSQAudioMediaViewAttributes.h */,
+				C8F98294D1983BEA4FE3F457A8C4989B /* JSQAudioMediaViewAttributes.m */,
+				C0B65DC86A880F922CEBC9F3E5CC3AF6 /* JSQLocationMediaItem.h */,
+				7B49B05639D369C1E0B261A45BA9AF09 /* JSQLocationMediaItem.m */,
+				008CD56D2A9D887C6CA89AB42B893A38 /* JSQMediaItem.h */,
+				819E17543E4A28081E442AF1F5B8045E /* JSQMediaItem.m */,
+				1A0218030BDA7A668945C17B377CDE8F /* JSQMessage.h */,
+				C096913A44638C9FF06389F47E88BC18 /* JSQMessage.m */,
+				0A7FF38F1A28A29DF3551820C1183DD8 /* JSQMessageAvatarImageDataSource.h */,
+				F5C3902474460BCF24DC302F56D77759 /* JSQMessageBubbleImageDataSource.h */,
+				3FB063200C27A97F7268EC4FAB0FA47D /* JSQMessageData.h */,
+				F6835C72593775C52D26B5DA131D4ED1 /* JSQMessageMediaData.h */,
+				E91F4B9A0BC720BEC72EBBA95D2CF07A /* JSQMessages.h */,
+				5B8C6B186209FCAE9D391888B99EEB6C /* JSQMessagesAvatarImage.h */,
+				C8C844EB7121934D0F720F7A531FCD13 /* JSQMessagesAvatarImage.m */,
+				5E37FC4863B0BDD655077FF394FBF902 /* JSQMessagesAvatarImageFactory.h */,
+				44F4D90CD5DC9FFDEC1B30B6CB4CF5CA /* JSQMessagesAvatarImageFactory.m */,
+				5632C7586BC13E17EEB1DA29A2DB0897 /* JSQMessagesBubbleImage.h */,
+				E56651EE83581E7015971470565D5A33 /* JSQMessagesBubbleImage.m */,
+				52948C9E932454C58519EE359B6D752A /* JSQMessagesBubbleImageFactory.h */,
+				1B2410B2A66933193F786BCAB7EF6F5B /* JSQMessagesBubbleImageFactory.m */,
+				FD3E0B32AC160ACC001DBF5E651FB7AF /* JSQMessagesBubbleSizeCalculating.h */,
+				F3622E44030FA7D10F5B1122B214265A /* JSQMessagesBubblesSizeCalculator.h */,
+				4CDB3D3465606AE4E3C126B3FD679D5A /* JSQMessagesBubblesSizeCalculator.m */,
+				70F782DA8A82FE5FC81F2885FA386E22 /* JSQMessagesCellTextView.h */,
+				D1CF40A047117C82290A1058941EDB5B /* JSQMessagesCellTextView.m */,
+				137633D209338CFE262D55234D544673 /* JSQMessagesCollectionView.h */,
+				3A51FBA9CAA64F939B8DA7384EE17892 /* JSQMessagesCollectionView.m */,
+				A691440B4B7C1FC17992013A0F3E3C69 /* JSQMessagesCollectionViewCell.h */,
+				002DBFAF8722DFAD3F6A513268095099 /* JSQMessagesCollectionViewCell.m */,
+				1D18904915E4E168CBA8F1789FF6D6F6 /* JSQMessagesCollectionViewCellIncoming.h */,
+				CCA4141FEAAD0D67C33FBA939E405624 /* JSQMessagesCollectionViewCellIncoming.m */,
+				8811FCBBEC0220FA1A53A7C107E2E2DC /* JSQMessagesCollectionViewCellOutgoing.h */,
+				0C36EC8238E174F1DABA3B3632E03CB7 /* JSQMessagesCollectionViewCellOutgoing.m */,
+				8C134BBF26C9AB247794E86D7F27ADBC /* JSQMessagesCollectionViewDataSource.h */,
+				CDCA653F2D59221364A7ECCECED0DA1E /* JSQMessagesCollectionViewDelegateFlowLayout.h */,
+				6BED8305BB403CD646B6671E983F6E77 /* JSQMessagesCollectionViewFlowLayout.h */,
+				54E1820B9CD67C29A2BB00B0D75FCDEA /* JSQMessagesCollectionViewFlowLayout.m */,
+				CD5472B819970B89BD631D8924D36F61 /* JSQMessagesCollectionViewFlowLayoutInvalidationContext.h */,
+				669DFA429490E99312D2AF9176726683 /* JSQMessagesCollectionViewFlowLayoutInvalidationContext.m */,
+				F2A6BB68756E33B1783CEDB7C2FC7D0F /* JSQMessagesCollectionViewLayoutAttributes.h */,
+				0E939CA94972407B11A07F1662A0F1A6 /* JSQMessagesCollectionViewLayoutAttributes.m */,
+				24EA3A1C0EEEFB702BDDF549F827B4B9 /* JSQMessagesComposerTextView.h */,
+				29D4AB4B8989FFBEB0ECC0A220095917 /* JSQMessagesComposerTextView.m */,
+				81EFE896FEBF3830AA892C77434B3104 /* JSQMessagesInputToolbar.h */,
+				6FA229F8BAF0897BF479EE12044E675B /* JSQMessagesInputToolbar.m */,
+				DD5D81E33CBDAFA3E824F492E5C72298 /* JSQMessagesKeyboardController.h */,
+				6A774AFBF8AD1F7A08544FF69FE5D9AC /* JSQMessagesKeyboardController.m */,
+				F6C1E24A90012EB6BEBFE7FFDAFABAFD /* JSQMessagesLabel.h */,
+				1ED60225EB1B1523C892FD30E0AE52BF /* JSQMessagesLabel.m */,
+				D38E67C0D8AD1E842511C1041E0DA670 /* JSQMessagesLoadEarlierHeaderView.h */,
+				F3606765C0D54047515AB590ED1545B6 /* JSQMessagesLoadEarlierHeaderView.m */,
+				3A2628E557A53E7A8D94F55FD10463AA /* JSQMessagesMediaPlaceholderView.h */,
+				B2568859A31454E85D0DDB53E81052AA /* JSQMessagesMediaPlaceholderView.m */,
+				2D8EF51DE15722891CA0E226F61321EA /* JSQMessagesMediaViewBubbleImageMasker.h */,
+				09FA42C91BAB4F76F257950DADB4AC9D /* JSQMessagesMediaViewBubbleImageMasker.m */,
+				85E80E91A69378812DE1457F6A22336B /* JSQMessagesTimestampFormatter.h */,
+				ED28BDD59A966699C7C9A72F7639ACBC /* JSQMessagesTimestampFormatter.m */,
+				C335EF8EB1B73539DA51195895FE5E9C /* JSQMessagesToolbarButtonFactory.h */,
+				B2022CCF86504DEE4212F5088EB85C0D /* JSQMessagesToolbarButtonFactory.m */,
+				3EB23AA1AC111C55B1D41522697C7145 /* JSQMessagesToolbarContentView.h */,
+				B74329AD8B58F50A6EA020362A120339 /* JSQMessagesToolbarContentView.m */,
+				A6AC92966BD107195AEDD210A6613CD8 /* JSQMessagesTypingIndicatorFooterView.h */,
+				FB1542B93BC9FC63800ACB01B665B489 /* JSQMessagesTypingIndicatorFooterView.m */,
+				C1F40AE792ECE3FA2020F5DD8D61A78C /* JSQMessagesViewController.h */,
+				A69233DE37E9CC07726584F755CCAC77 /* JSQMessagesViewController.m */,
+				27B56560D5AF134F0C119D1A72AF6245 /* JSQPhotoMediaItem.h */,
+				E20915CFBF2792634B0A5C570BDB557B /* JSQPhotoMediaItem.m */,
+				EE2281E9EEF131DE52FDD3D6334CE413 /* JSQSystemSoundPlayer+JSQMessages.h */,
+				27B8106C4458685FE4A67C6F21BC3AB5 /* JSQSystemSoundPlayer+JSQMessages.m */,
+				7FA142E76A0AB287CBDF5828D3A8A2FA /* JSQVideoMediaItem.h */,
+				523ADBF605FF49D24C108258E415995A /* JSQVideoMediaItem.m */,
+				EF640E189547B049B93373748A3EEE3E /* NSBundle+JSQMessages.h */,
+				D951390938AEA8F708B45789ED5233FC /* NSBundle+JSQMessages.m */,
+				FC563929A1E1F988ECD8AA0E3778761C /* NSString+JSQMessages.h */,
+				C1BDCB2545982BC887E50DE30DB51474 /* NSString+JSQMessages.m */,
+				3F16AAC39A31F790E65324FAF4F8AF86 /* UIColor+JSQMessages.h */,
+				2048485DCDC18ABC17382421C9766DAC /* UIColor+JSQMessages.m */,
+				ACF793F7B931AC1744C1A32CA52FAEB5 /* UIDevice+JSQMessages.h */,
+				1E820F8DA32722BA55B55D1555F68224 /* UIDevice+JSQMessages.m */,
+				5338AF82B5DF605A76C25FD68FD5CAAC /* UIImage+JSQMessages.h */,
+				158EBD0C78A350D4D575E66E0D27D1FC /* UIImage+JSQMessages.m */,
+				C50A7C871EF8856E5A9BF5D9F9657ED6 /* UIView+JSQMessages.h */,
+				12B8F59ED02DA476D7FDF55B6400132F /* UIView+JSQMessages.m */,
+				B5A102D9B810E8164C242FA296C464BA /* Resources */,
+				0447656BA1BB1C8835FFD8FC5F653C94 /* Support Files */,
+			);
+			name = JSQMessagesViewController;
+			path = JSQMessagesViewController;
+			sourceTree = "<group>";
+		};
+		91E3F6E525B1B8DB1F10CEFB129ECDD5 /* OpenWhisk */ = {
+			isa = PBXGroup;
+			children = (
+				694FAE07DC5AB847E958D2A4B54B34F7 /* Config.swift */,
+				9B1E768DBF7A64002D7DBCEB6241D2B1 /* OpenWhisk.h */,
+				A06ACEAA91EF5AC2362C5617236E41CA /* OpenWhiskButton.swift */,
+				6C43D91D112DEA50800B76415F1DD556 /* OpenWhiskSDK.swift */,
+				4C8E5059F6522B6774365C8E45F34479 /* Resources */,
+				5F88CDB57301ABD87E1C552F7351EB1E /* Support Files */,
+			);
+			name = OpenWhisk;
+			path = OpenWhisk;
+			sourceTree = "<group>";
+		};
+		AA44B1738BABEFA79AD549F2B1A35BFA /* Support Files */ = {
+			isa = PBXGroup;
+			children = (
+				AD4C022F84D40A1AB9C7A6F46838251D /* Info.plist */,
+				72A5C96522803FF5746288E2D4BF7BCB /* JSQSystemSoundPlayer.modulemap */,
+				591893BD9779F8D04A28A2FDE5C20562 /* JSQSystemSoundPlayer.xcconfig */,
+				FF17B4389A252DB6AF8FC536E082A284 /* JSQSystemSoundPlayer-dummy.m */,
+				0FC783F6EFCE0BA1DA5E47B30A0BF885 /* JSQSystemSoundPlayer-prefix.pch */,
+				CC1A9750FC63FD5C5803D47ED94D74FB /* JSQSystemSoundPlayer-umbrella.h */,
+			);
+			name = "Support Files";
+			path = "../Target Support Files/JSQSystemSoundPlayer";
+			sourceTree = "<group>";
+		};
+		B5A102D9B810E8164C242FA296C464BA /* Resources */ = {
+			isa = PBXGroup;
+			children = (
+				E487F3F9735AE5FE5718C483467DF2C3 /* JSQMessagesAssets.bundle */,
+				78D378A9010E603FB2DF71D8C9411203 /* JSQMessagesCollectionViewCellIncoming.xib */,
+				839B00C0162E241008D63F99291CB733 /* JSQMessagesCollectionViewCellOutgoing.xib */,
+				B1E60FC29ACF2A4F1209F40003D15805 /* JSQMessagesLoadEarlierHeaderView.xib */,
+				84D19FA1ED51AE56090168F529E67722 /* JSQMessagesToolbarContentView.xib */,
+				93246B602F8E677A5C3DCE7969986D77 /* JSQMessagesTypingIndicatorFooterView.xib */,
+				14204B4BBB6CB361B545CC9D098ED079 /* JSQMessagesViewController.xib */,
+			);
+			name = Resources;
+			sourceTree = "<group>";
+		};
+		C5E1BC056907A259F09535120921F915 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				BD1734D5878E207B7E20F9F6ED1000A3 /* JSQMessagesViewController.framework */,
+				E814D96AD1A17F06CE577C508B3F0548 /* JSQSystemSoundPlayer.framework */,
+				D491E264123B228014D36E70F7B76EC7 /* OpenWhisk.framework */,
+				5439BCE9F884F5B855E14A1106428F65 /* OpenWhiskResources.bundle */,
+				78C2F6C14B4C102ECD25D29DD8B71F07 /* Pods_WhiskBot.framework */,
+				6E2487F53A3F4E2E57ACE0A8726037F2 /* Pods_WhiskBotTests.framework */,
+				0F6CA7B1E7A7E55AB93AE91F93CC8581 /* Pods_WhiskBotUITests.framework */,
+				FA368FEB97439C24E38850A7DF5CBCAA /* SwiftyJSON.framework */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		CCECAB395DB7EBA55D38C85DA79FC10F /* Pods-WhiskBot */ = {
+			isa = PBXGroup;
+			children = (
+				65CBE1C4D4BEE40A0E2685AC3154D481 /* Info.plist */,
+				DA301EE341F1E07F58CAF2F6190CE900 /* Pods-WhiskBot.modulemap */,
+				FD67E33372F19B2EAEF6EA009D8B9025 /* Pods-WhiskBot-acknowledgements.markdown */,
+				34665CA684DF54FE684B80706C2372B4 /* Pods-WhiskBot-acknowledgements.plist */,
+				5F04F54DFFF7FA4F939A1CD34C8CA0C2 /* Pods-WhiskBot-dummy.m */,
+				D750919FF4676B26827A551941A73B6F /* Pods-WhiskBot-frameworks.sh */,
+				7314249DE86B4A4A274E818FA095ACDF /* Pods-WhiskBot-resources.sh */,
+				562798E79FEF0FAA25FC84ABBE019ABA /* Pods-WhiskBot-umbrella.h */,
+				36105D6BFA5F5AB6ABE70E71EE8228C4 /* Pods-WhiskBot.debug.xcconfig */,
+				62D801F74C63E4AF2AC31300AC59517D /* Pods-WhiskBot.release.xcconfig */,
+			);
+			name = "Pods-WhiskBot";
+			path = "Target Support Files/Pods-WhiskBot";
+			sourceTree = "<group>";
+		};
+		D8624B10076AF1E2924B2295455C0F32 /* JSQSystemSoundPlayer */ = {
+			isa = PBXGroup;
+			children = (
+				F704CA3647F8168CB674CA6A0F13D0A6 /* JSQSystemSoundPlayer.h */,
+				82F7B578958269C5258FC7E8F30522A8 /* JSQSystemSoundPlayer.m */,
+				AA44B1738BABEFA79AD549F2B1A35BFA /* Support Files */,
+			);
+			name = JSQSystemSoundPlayer;
+			path = JSQSystemSoundPlayer;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+		56D54E97E2747AA591F16066AE673C02 /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				E43F5C2A5260C8F5C3DE4D42D1588D10 /* OpenWhisk-umbrella.h in Headers */,
+				453C72A633A06CC9D3FB02BCCFD62F83 /* OpenWhisk.h in Headers */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		ADD676BFE689D3BB1C5A34AA26A95BA8 /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				BF0E34A09822C4909CEB31F59BE7501D /* JSQAudioMediaItem.h in Headers */,
+				D7EDBB9EB9B04876ED0EE483F3912554 /* JSQAudioMediaViewAttributes.h in Headers */,
+				D1E0D269EAD4B6FB01948F7780BD5469 /* JSQLocationMediaItem.h in Headers */,
+				55D190B2A2B2B5BE0F8B320BDA5A439A /* JSQMediaItem.h in Headers */,
+				3AE5C5C51ADABC338D7AEF33F46596D0 /* JSQMessage.h in Headers */,
+				242D23D0EB67922D7A2DF72154DFBB6F /* JSQMessageAvatarImageDataSource.h in Headers */,
+				A4F6DA7C20CC4B16DF0BBD943991108D /* JSQMessageBubbleImageDataSource.h in Headers */,
+				579F5B08F5D8299F4BB0A9AB44C84FA7 /* JSQMessageData.h in Headers */,
+				C65DCBDD4FAF45D8BDDB686C7453083E /* JSQMessageMediaData.h in Headers */,
+				768F1DE7CA5E754BE0F06A52066B3544 /* JSQMessages.h in Headers */,
+				EC0993DEAE73EDFA1E42B92454D53096 /* JSQMessagesAvatarImage.h in Headers */,
+				FDD63C5749F1E20C7AA2E2D079282117 /* JSQMessagesAvatarImageFactory.h in Headers */,
+				2367C9536DABA06DEAA798CC180ED67C /* JSQMessagesBubbleImage.h in Headers */,
+				9CC971CE0EA48027B893A8AA5F2C452C /* JSQMessagesBubbleImageFactory.h in Headers */,
+				B9C946F65F417847AFF6D5C24587E091 /* JSQMessagesBubbleSizeCalculating.h in Headers */,
+				78BA75223D5CBFB27AC98092DA67839B /* JSQMessagesBubblesSizeCalculator.h in Headers */,
+				D789A642D4D8D3E2E99D2143408C2FDE /* JSQMessagesCellTextView.h in Headers */,
+				23B31DAECE298E56760B53206971C6E0 /* JSQMessagesCollectionView.h in Headers */,
+				F28CEFF02311DDB81E5DB68B295E067D /* JSQMessagesCollectionViewCell.h in Headers */,
+				81480EB7934E94B4BE172527B6EC8F79 /* JSQMessagesCollectionViewCellIncoming.h in Headers */,
+				F4E9E5BF69FAFDCDA5E2F60C2523220F /* JSQMessagesCollectionViewCellOutgoing.h in Headers */,
+				B7F1D9E14737FA7269D75A6D01BBB5A9 /* JSQMessagesCollectionViewDataSource.h in Headers */,
+				BB6FF60A541DD5C3E58F806470690041 /* JSQMessagesCollectionViewDelegateFlowLayout.h in Headers */,
+				5E7C46E9368070A9FE5150F7CFAE82D1 /* JSQMessagesCollectionViewFlowLayout.h in Headers */,
+				5E3CD934B1911134558C5CB7FF0BA1B4 /* JSQMessagesCollectionViewFlowLayoutInvalidationContext.h in Headers */,
+				2C9F7C1DABBFB9CB281783A5DB445C44 /* JSQMessagesCollectionViewLayoutAttributes.h in Headers */,
+				0FC068A6DD03CACA24535E284B60FD71 /* JSQMessagesComposerTextView.h in Headers */,
+				1EA2E6DFBE4AC13642F05FDAA29C2C50 /* JSQMessagesInputToolbar.h in Headers */,
+				74EAADDADC835AE371509AF4BC19EED7 /* JSQMessagesKeyboardController.h in Headers */,
+				6CCE35C0E52AD7C8175B08C75B325049 /* JSQMessagesLabel.h in Headers */,
+				C72B319F3B855F71D31C0ABF4EC7C543 /* JSQMessagesLoadEarlierHeaderView.h in Headers */,
+				EAC4E8296D47BC3806FAFCA254D9B02B /* JSQMessagesMediaPlaceholderView.h in Headers */,
+				FC82748F1DB8B5C127C9D94C9EE10323 /* JSQMessagesMediaViewBubbleImageMasker.h in Headers */,
+				867CA269771C0C2939021BAED4A96C39 /* JSQMessagesTimestampFormatter.h in Headers */,
+				200AE7D9FF81A5659D02E515B85D4B23 /* JSQMessagesToolbarButtonFactory.h in Headers */,
+				B87FE02FA7A0A8F226501245ADC88D3D /* JSQMessagesToolbarContentView.h in Headers */,
+				87A792E3DD909716060338A8D718681F /* JSQMessagesTypingIndicatorFooterView.h in Headers */,
+				6B3E1EF3C0A0280C1E99603DFC2966F0 /* JSQMessagesViewController-umbrella.h in Headers */,
+				B4E2F424298D517511F47AFBCE7877D1 /* JSQMessagesViewController.h in Headers */,
+				1D175A520B3D6B2B3134593270CF4C3B /* JSQPhotoMediaItem.h in Headers */,
+				45BBCE2ECEC4891384F0F0D45BD2499A /* JSQSystemSoundPlayer+JSQMessages.h in Headers */,
+				523985DCBCFF0F95DA244BA5BD0C3780 /* JSQVideoMediaItem.h in Headers */,
+				319E1BA9E6B38CE41234EDABD73C4C38 /* NSBundle+JSQMessages.h in Headers */,
+				9C847E9CB58D21A0D6CA6E1E6EF45114 /* NSString+JSQMessages.h in Headers */,
+				49FBC73695AB31538136416D8C16E401 /* UIColor+JSQMessages.h in Headers */,
+				39D7C670879E236D85F82657BB4DAD2A /* UIDevice+JSQMessages.h in Headers */,
+				6CFA0C1B6E580D5EC5F8B4E36ACDE892 /* UIImage+JSQMessages.h in Headers */,
+				9F80FD930EFABE333171E6812AFFFF89 /* UIView+JSQMessages.h in Headers */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		C8363D983C2C0C2CEDE62EA44B0B9A74 /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				5E7C3EBEDD021CD5B54E9D40EC2B0AA2 /* Pods-WhiskBot-umbrella.h in Headers */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		D023226FC7EB14DAD84B6AA568BACC98 /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				98175010AA1363461D0DBD6A8F79C6F6 /* Pods-WhiskBotUITests-umbrella.h in Headers */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		EC65D8E83A23BCCF40CC62DD7CC4912E /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				F0AAAFE8E84ECF9A6CBCCBBA96B16A29 /* JSQSystemSoundPlayer-umbrella.h in Headers */,
+				597DCDBBC3F2A87D7BE4BBAB00D90385 /* JSQSystemSoundPlayer.h in Headers */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F305ADAE2F5491E71117D81407E2A7A1 /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				04C9F27D8BD6D02BCD9A4A4086C2ED41 /* SwiftyJSON-umbrella.h in Headers */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		FF30ED0926A2850D7C2EF9C90EC95504 /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				FD83ACAE9094227EE3F99B6D50FA37DE /* Pods-WhiskBotTests-umbrella.h in Headers */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+		195C014CC3B115DE2418CA949281BEAB /* Pods-WhiskBot */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 1E786F92562B1C24C69679B20EDB3B6C /* Build configuration list for PBXNativeTarget "Pods-WhiskBot" */;
+			buildPhases = (
+				FCD0B847CD05A8A7B304545CB93A9F70 /* Sources */,
+				277B91F16F533170BC66571D168A14BB /* Frameworks */,
+				C8363D983C2C0C2CEDE62EA44B0B9A74 /* Headers */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				F59EEEBE5DBD49ECBF40C5F1CF249292 /* PBXTargetDependency */,
+				EE06669717853F43CBB2D6287C355FE5 /* PBXTargetDependency */,
+				09CAC31735F8B424E4FA5F1E02112CEC /* PBXTargetDependency */,
+				275F7758E35A9C215AFAE109528EA667 /* PBXTargetDependency */,
+			);
+			name = "Pods-WhiskBot";
+			productName = "Pods-WhiskBot";
+			productReference = 78C2F6C14B4C102ECD25D29DD8B71F07 /* Pods_WhiskBot.framework */;
+			productType = "com.apple.product-type.framework";
+		};
+		511405A82CBE553D0A18DB2A59E9F9ED /* Pods-WhiskBotTests */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 044F2CF7A655D9419C2DDE17026FF849 /* Build configuration list for PBXNativeTarget "Pods-WhiskBotTests" */;
+			buildPhases = (
+				75F1F83B72420815F4C83542779C2C20 /* Sources */,
+				11CB2C2CE1C75B2DE57CDD8F41264112 /* Frameworks */,
+				FF30ED0926A2850D7C2EF9C90EC95504 /* Headers */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = "Pods-WhiskBotTests";
+			productName = "Pods-WhiskBotTests";
+			productReference = 6E2487F53A3F4E2E57ACE0A8726037F2 /* Pods_WhiskBotTests.framework */;
+			productType = "com.apple.product-type.framework";
+		};
+		54D9E87F2717881BD1F94F4A65434708 /* SwiftyJSON */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = CC69E587A3C23CD9E60E5D19627ED3F7 /* Build configuration list for PBXNativeTarget "SwiftyJSON" */;
+			buildPhases = (
+				C6B63BB1E56B2EAE93A4027DB9B838A2 /* Sources */,
+				9382450C8A42AC3528F8F2E841E880D4 /* Frameworks */,
+				F305ADAE2F5491E71117D81407E2A7A1 /* Headers */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = SwiftyJSON;
+			productName = SwiftyJSON;
+			productReference = FA368FEB97439C24E38850A7DF5CBCAA /* SwiftyJSON.framework */;
+			productType = "com.apple.product-type.framework";
+		};
+		C7DCF2B547F7871B9BFD74DE93B0E173 /* JSQSystemSoundPlayer */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 1F667698FA6F084AEB077EB13AC4DDE7 /* Build configuration list for PBXNativeTarget "JSQSystemSoundPlayer" */;
+			buildPhases = (
+				21C764C8D4A3161C696419572944578A /* Sources */,
+				040C2507C3340E681F3CBA134A3B988C /* Frameworks */,
+				EC65D8E83A23BCCF40CC62DD7CC4912E /* Headers */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = JSQSystemSoundPlayer;
+			productName = JSQSystemSoundPlayer;
+			productReference = E814D96AD1A17F06CE577C508B3F0548 /* JSQSystemSoundPlayer.framework */;
+			productType = "com.apple.product-type.framework";
+		};
+		D0581AF7BF4A6DA140D280B19ECC7BFF /* JSQMessagesViewController */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = EF4840F49250B389B9C61B64707D6C6B /* Build configuration list for PBXNativeTarget "JSQMessagesViewController" */;
+			buildPhases = (
+				59B981C022D1C459FC04B2999E3C2D61 /* Sources */,
+				D2F108FFB11F430009AB0413A1436E45 /* Frameworks */,
+				ADD676BFE689D3BB1C5A34AA26A95BA8 /* Headers */,
+				1B8078A19ECA99C9B9678B95F440C3E6 /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				B355035F5C4F2981379FBD36B7FED189 /* PBXTargetDependency */,
+			);
+			name = JSQMessagesViewController;
+			productName = JSQMessagesViewController;
+			productReference = BD1734D5878E207B7E20F9F6ED1000A3 /* JSQMessagesViewController.framework */;
+			productType = "com.apple.product-type.framework";
+		};
+		D2B7EFCD4A44E5CF56785242F9632123 /* Pods-WhiskBotUITests */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 78217554A79251977908CD048B2EEA16 /* Build configuration list for PBXNativeTarget "Pods-WhiskBotUITests" */;
+			buildPhases = (
+				77CE9A25427060FD30FF3DB2D78BE4EB /* Sources */,
+				04AA5AA42986F232B48554D8B61218D6 /* Frameworks */,
+				D023226FC7EB14DAD84B6AA568BACC98 /* Headers */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = "Pods-WhiskBotUITests";
+			productName = "Pods-WhiskBotUITests";
+			productReference = 0F6CA7B1E7A7E55AB93AE91F93CC8581 /* Pods_WhiskBotUITests.framework */;
+			productType = "com.apple.product-type.framework";
+		};
+		DAF887453904739967DA9E16B68AD96E /* OpenWhisk */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 8BCE1F1469AE142E766C22E3823AC508 /* Build configuration list for PBXNativeTarget "OpenWhisk" */;
+			buildPhases = (
+				028625AE1C7B2B7425509D3A42472249 /* Sources */,
+				F0020D3F2D7CCEBAD802161C1AB507EB /* Frameworks */,
+				156C29BF70E41FCBE8ACB5001427E990 /* Resources */,
+				56D54E97E2747AA591F16066AE673C02 /* Headers */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				9EBB742FB30C90AA9232EE3F1D3210BE /* PBXTargetDependency */,
+			);
+			name = OpenWhisk;
+			productName = OpenWhisk;
+			productReference = D491E264123B228014D36E70F7B76EC7 /* OpenWhisk.framework */;
+			productType = "com.apple.product-type.framework";
+		};
+		E9F7495D838404B103ADD79427CA9320 /* OpenWhisk-OpenWhiskResources */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 9A471A7A29CA2DB2680A023F34B2A67B /* Build configuration list for PBXNativeTarget "OpenWhisk-OpenWhiskResources" */;
+			buildPhases = (
+				692A77191587F891E298B3B4FC286FD4 /* Sources */,
+				4E84ECB59116333EA452CC15E3772FD1 /* Frameworks */,
+				1D3A08B755F5684965B9B36D5411DD70 /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = "OpenWhisk-OpenWhiskResources";
+			productName = "OpenWhisk-OpenWhiskResources";
+			productReference = 5439BCE9F884F5B855E14A1106428F65 /* OpenWhiskResources.bundle */;
+			productType = "com.apple.product-type.bundle";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		D41D8CD98F00B204E9800998ECF8427E /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				LastSwiftUpdateCheck = 0730;
+				LastUpgradeCheck = 0700;
+			};
+			buildConfigurationList = 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */;
+			compatibilityVersion = "Xcode 3.2";
+			developmentRegion = English;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+			);
+			mainGroup = 7DB346D0F39D3F0E887471402A8071AB;
+			productRefGroup = C5E1BC056907A259F09535120921F915 /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				D0581AF7BF4A6DA140D280B19ECC7BFF /* JSQMessagesViewController */,
+				C7DCF2B547F7871B9BFD74DE93B0E173 /* JSQSystemSoundPlayer */,
+				DAF887453904739967DA9E16B68AD96E /* OpenWhisk */,
+				E9F7495D838404B103ADD79427CA9320 /* OpenWhisk-OpenWhiskResources */,
+				195C014CC3B115DE2418CA949281BEAB /* Pods-WhiskBot */,
+				511405A82CBE553D0A18DB2A59E9F9ED /* Pods-WhiskBotTests */,
+				D2B7EFCD4A44E5CF56785242F9632123 /* Pods-WhiskBotUITests */,
+				54D9E87F2717881BD1F94F4A65434708 /* SwiftyJSON */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+		156C29BF70E41FCBE8ACB5001427E990 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				28F54EA3F7D44B2EB87871CCF142BF9A /* OpenWhiskResources.bundle in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		1B8078A19ECA99C9B9678B95F440C3E6 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				41D50BBEA635DAD4E95FF71D4DD1D8AA /* JSQMessagesAssets.bundle in Resources */,
+				18E6DE6A5C5196F931759B4D545DE975 /* JSQMessagesCollectionViewCellIncoming.xib in Resources */,
+				048D02CBD0A8636E6830140C4D48CA32 /* JSQMessagesCollectionViewCellOutgoing.xib in Resources */,
+				8DBCD01CAC80EABF1EB242ACE7787C8A /* JSQMessagesLoadEarlierHeaderView.xib in Resources */,
+				E205C0F77B94CAD08E1191486CFA314E /* JSQMessagesToolbarContentView.xib in Resources */,
+				F3D3406B798B94A35C7F26504C44ADC9 /* JSQMessagesTypingIndicatorFooterView.xib in Resources */,
+				DD2A2BCB72C62F2F32B3D2DA324636FE /* JSQMessagesViewController.xib in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		1D3A08B755F5684965B9B36D5411DD70 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				002CFBE7E95979BE7DC143EF5A3817A6 /* OpenWhiskConfig.plist in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		028625AE1C7B2B7425509D3A42472249 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				F38E75F1F613396092B4083EF8F80A15 /* Config.swift in Sources */,
+				97566BA16346218BCCD0F0E38EB70E0C /* OpenWhisk-dummy.m in Sources */,
+				4DA12AA1089FFF8B526DE898A9B8DC39 /* OpenWhiskButton.swift in Sources */,
+				2D1D88CBBF20C68BAC3D0904888B9DB8 /* OpenWhiskSDK.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		21C764C8D4A3161C696419572944578A /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				D5EDF701474637548017366D85DC162B /* JSQSystemSoundPlayer-dummy.m in Sources */,
+				33BB9AD3741F3ECF75411A4E3C82B74D /* JSQSystemSoundPlayer.m in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		59B981C022D1C459FC04B2999E3C2D61 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				8FF808C38E2A1978A476C0C1D72C9F97 /* JSQAudioMediaItem.m in Sources */,
+				BFC12801804825AE4228285DC2FC11DF /* JSQAudioMediaViewAttributes.m in Sources */,
+				4BB4FDF8AC4FC772F11D5E20A6F50CCA /* JSQLocationMediaItem.m in Sources */,
+				D3606896B42830A11DDCD11445D58346 /* JSQMediaItem.m in Sources */,
+				C9A7BF29CFB2EB284506526C409DCE56 /* JSQMessage.m in Sources */,
+				B29D907250856963C8C41CEC8336CF3B /* JSQMessagesAvatarImage.m in Sources */,
+				DDC94334FF57682689F2BFEBCB52597E /* JSQMessagesAvatarImageFactory.m in Sources */,
+				80AC20A5B7B098AEB98604C320BAD232 /* JSQMessagesBubbleImage.m in Sources */,
+				54B4C7E82F92DD998C63F9EC869C20C9 /* JSQMessagesBubbleImageFactory.m in Sources */,
+				FC1DFCD7AE1E5A781EB5E43CA6AABDA4 /* JSQMessagesBubblesSizeCalculator.m in Sources */,
+				561D081EAB6F263BD3FA0B444C395030 /* JSQMessagesCellTextView.m in Sources */,
+				D687858C00D384EE419E0AD92032CE67 /* JSQMessagesCollectionView.m in Sources */,
+				FD435B4361EA18F8CFD1FD2C237F47A2 /* JSQMessagesCollectionViewCell.m in Sources */,
+				B74724F4DE7AF477390ABC79AAD35BAE /* JSQMessagesCollectionViewCellIncoming.m in Sources */,
+				843166B023307AD37F03434FAC558E4F /* JSQMessagesCollectionViewCellOutgoing.m in Sources */,
+				E3A1194D92818EA1B4A6F05836E04256 /* JSQMessagesCollectionViewFlowLayout.m in Sources */,
+				64812729D8DE634B9524C5319F72E932 /* JSQMessagesCollectionViewFlowLayoutInvalidationContext.m in Sources */,
+				9022B43E902DFE27B8107A37AC8B3726 /* JSQMessagesCollectionViewLayoutAttributes.m in Sources */,
+				6E68CD04C09B3F0359FF672A2AE6F90D /* JSQMessagesComposerTextView.m in Sources */,
+				733E8CA810F0F437C9C7FDE6DA60B9E9 /* JSQMessagesInputToolbar.m in Sources */,
+				06B20D9837A06A4D524D3F66E029D468 /* JSQMessagesKeyboardController.m in Sources */,
+				6D5671FAD658E09E2E03A7B935F50010 /* JSQMessagesLabel.m in Sources */,
+				FEAE161C5872A47553E1F76AB1C33F93 /* JSQMessagesLoadEarlierHeaderView.m in Sources */,
+				7A16F2A86CB1A5D66DDBCFEE7B6BAA20 /* JSQMessagesMediaPlaceholderView.m in Sources */,
+				8CF27DDD56556F901EA411AF3261639E /* JSQMessagesMediaViewBubbleImageMasker.m in Sources */,
+				C1AC507D95B47716673A6E2C8C115ECD /* JSQMessagesTimestampFormatter.m in Sources */,
+				0258A1B465E4F0F23E354076BDAA6361 /* JSQMessagesToolbarButtonFactory.m in Sources */,
+				29B73968F1BA2987FEF099C812351349 /* JSQMessagesToolbarContentView.m in Sources */,
+				4CCBF4DC98798CF31A907A6271104368 /* JSQMessagesTypingIndicatorFooterView.m in Sources */,
+				B01BCEA53EAD2B9D468DA470ACE25399 /* JSQMessagesViewController-dummy.m in Sources */,
+				980C43DE877CCD4131F0D6EFB68249F5 /* JSQMessagesViewController.m in Sources */,
+				E529FEE5379F6E8CA6B442FE25F59AB1 /* JSQPhotoMediaItem.m in Sources */,
+				A159C0A3164478623E459164250E45C4 /* JSQSystemSoundPlayer+JSQMessages.m in Sources */,
+				04113425D6044E3BB06BEC9D4C631EAF /* JSQVideoMediaItem.m in Sources */,
+				2219255BCD9D285E7B23E2DBA4D7B9C1 /* NSBundle+JSQMessages.m in Sources */,
+				712931D97B07F23295FABC8FAA89505D /* NSString+JSQMessages.m in Sources */,
+				56EE115614D32FF57180D7683412D915 /* UIColor+JSQMessages.m in Sources */,
+				4A0B511C1EE50388FD1640B3A4F3C27D /* UIDevice+JSQMessages.m in Sources */,
+				89D842477092AE8F70A518FB11893B8E /* UIImage+JSQMessages.m in Sources */,
+				104E8110FE9622F86FC8BB1E3075ED21 /* UIView+JSQMessages.m in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		692A77191587F891E298B3B4FC286FD4 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		75F1F83B72420815F4C83542779C2C20 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				D41B237B5DBDA6D59088BE1ABA4596D3 /* Pods-WhiskBotTests-dummy.m in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		77CE9A25427060FD30FF3DB2D78BE4EB /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				3BB813F15A688BB4041390038DFCAE9C /* Pods-WhiskBotUITests-dummy.m in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		C6B63BB1E56B2EAE93A4027DB9B838A2 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				6923138460C4EEDB05974A333D3976D8 /* SwiftyJSON-dummy.m in Sources */,
+				D98DE2E729D20CA6B3B8A65BF804DE1C /* SwiftyJSON.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		FCD0B847CD05A8A7B304545CB93A9F70 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				67AF387C8C6EBB766FD33141E8E072E6 /* Pods-WhiskBot-dummy.m in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+		09CAC31735F8B424E4FA5F1E02112CEC /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			name = OpenWhisk;
+			target = DAF887453904739967DA9E16B68AD96E /* OpenWhisk */;
+			targetProxy = BF03284A54D288F18C8C95E8229C78CA /* PBXContainerItemProxy */;
+		};
+		275F7758E35A9C215AFAE109528EA667 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			name = SwiftyJSON;
+			target = 54D9E87F2717881BD1F94F4A65434708 /* SwiftyJSON */;
+			targetProxy = FB4D609DB85C1E7E009DFFC2F8FEA1FE /* PBXContainerItemProxy */;
+		};
+		9EBB742FB30C90AA9232EE3F1D3210BE /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			name = "OpenWhisk-OpenWhiskResources";
+			target = E9F7495D838404B103ADD79427CA9320 /* OpenWhisk-OpenWhiskResources */;
+			targetProxy = 61164EA705E7F0300CF5C3E57AD1321D /* PBXContainerItemProxy */;
+		};
+		B355035F5C4F2981379FBD36B7FED189 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			name = JSQSystemSoundPlayer;
+			target = C7DCF2B547F7871B9BFD74DE93B0E173 /* JSQSystemSoundPlayer */;
+			targetProxy = C10A60E444C404E0967413316E725A2F /* PBXContainerItemProxy */;
+		};
+		EE06669717853F43CBB2D6287C355FE5 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			name = JSQSystemSoundPlayer;
+			target = C7DCF2B547F7871B9BFD74DE93B0E173 /* JSQSystemSoundPlayer */;
+			targetProxy = C202DFB61C4E1CF8A6D812B2F242EDAE /* PBXContainerItemProxy */;
+		};
+		F59EEEBE5DBD49ECBF40C5F1CF249292 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			name = JSQMessagesViewController;
+			target = D0581AF7BF4A6DA140D280B19ECC7BFF /* JSQMessagesViewController */;
+			targetProxy = E5F485F562A6E6626A53F7C045B56853 /* PBXContainerItemProxy */;
+		};
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+		029AE7B7112D7A646F4A766D63D4E75A /* Release */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = A20FA82DA1AA5214F869ACD683D8E4F8 /* JSQMessagesViewController.xcconfig */;
+			buildSettings = {
+				"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
+				"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
+				CURRENT_PROJECT_VERSION = 1;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				DEFINES_MODULE = YES;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_PREFIX_HEADER = "Target Support Files/JSQMessagesViewController/JSQMessagesViewController-prefix.pch";
+				INFOPLIST_FILE = "Target Support Files/JSQMessagesViewController/Info.plist";
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MODULEMAP_FILE = "Target Support Files/JSQMessagesViewController/JSQMessagesViewController.modulemap";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				PRODUCT_NAME = JSQMessagesViewController;
+				SDKROOT = iphoneos;
+				SKIP_INSTALL = YES;
+				SWIFT_VERSION = 3.0;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VERSIONING_SYSTEM = "apple-generic";
+				VERSION_INFO_PREFIX = "";
+			};
+			name = Release;
+		};
+		1A47B18C4B76FADFE563380E1B4F5A21 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 1A509411156D95A98D50167105B77EAE /* OpenWhisk.xcconfig */;
+			buildSettings = {
+				"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
+				"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
+				CURRENT_PROJECT_VERSION = 1;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				DEFINES_MODULE = YES;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_PREFIX_HEADER = "Target Support Files/OpenWhisk/OpenWhisk-prefix.pch";
+				INFOPLIST_FILE = "Target Support Files/OpenWhisk/Info.plist";
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MODULEMAP_FILE = "Target Support Files/OpenWhisk/OpenWhisk.modulemap";
+				MTL_ENABLE_DEBUG_INFO = YES;
+				PRODUCT_NAME = OpenWhisk;
+				SDKROOT = iphoneos;
+				SKIP_INSTALL = YES;
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+				SWIFT_VERSION = 3.0;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VERSIONING_SYSTEM = "apple-generic";
+				VERSION_INFO_PREFIX = "";
+			};
+			name = Debug;
+		};
+		28A34E51C6EDFC63B045D3248A317B97 /* Release */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 0CD22AE59F55893A567B5EFF54022481 /* Pods-WhiskBotTests.release.xcconfig */;
+			buildSettings = {
+				"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
+				"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
+				CURRENT_PROJECT_VERSION = 1;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				DEFINES_MODULE = YES;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_NO_COMMON_BLOCKS = YES;
+				INFOPLIST_FILE = "Target Support Files/Pods-WhiskBotTests/Info.plist";
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				IPHONEOS_DEPLOYMENT_TARGET = 10.2;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MACH_O_TYPE = staticlib;
+				MODULEMAP_FILE = "Target Support Files/Pods-WhiskBotTests/Pods-WhiskBotTests.modulemap";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				OTHER_LDFLAGS = "";
+				OTHER_LIBTOOLFLAGS = "";
+				PODS_ROOT = "$(SRCROOT)";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}";
+				PRODUCT_NAME = Pods_WhiskBotTests;
+				SDKROOT = iphoneos;
+				SKIP_INSTALL = YES;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VERSIONING_SYSTEM = "apple-generic";
+				VERSION_INFO_PREFIX = "";
+			};
+			name = Release;
+		};
+		3B8BDD35AB9FAEDDA5D574A79131A513 /* Release */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 62D801F74C63E4AF2AC31300AC59517D /* Pods-WhiskBot.release.xcconfig */;
+			buildSettings = {
+				"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
+				"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
+				CURRENT_PROJECT_VERSION = 1;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				DEFINES_MODULE = YES;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_NO_COMMON_BLOCKS = YES;
+				INFOPLIST_FILE = "Target Support Files/Pods-WhiskBot/Info.plist";
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				IPHONEOS_DEPLOYMENT_TARGET = 10.2;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MACH_O_TYPE = staticlib;
+				MODULEMAP_FILE = "Target Support Files/Pods-WhiskBot/Pods-WhiskBot.modulemap";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				OTHER_LDFLAGS = "";
+				OTHER_LIBTOOLFLAGS = "";
+				PODS_ROOT = "$(SRCROOT)";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}";
+				PRODUCT_NAME = Pods_WhiskBot;
+				SDKROOT = iphoneos;
+				SKIP_INSTALL = YES;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VERSIONING_SYSTEM = "apple-generic";
+				VERSION_INFO_PREFIX = "";
+			};
+			name = Release;
+		};
+		400D365DBB62B3690E20E7C2034AE69C /* Release */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 7D920E76A0AE87F8142333C9B1BC3BB8 /* Pods-WhiskBotUITests.release.xcconfig */;
+			buildSettings = {
+				"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
+				"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
+				CURRENT_PROJECT_VERSION = 1;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				DEFINES_MODULE = YES;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_NO_COMMON_BLOCKS = YES;
+				INFOPLIST_FILE = "Target Support Files/Pods-WhiskBotUITests/Info.plist";
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				IPHONEOS_DEPLOYMENT_TARGET = 10.2;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MACH_O_TYPE = staticlib;
+				MODULEMAP_FILE = "Target Support Files/Pods-WhiskBotUITests/Pods-WhiskBotUITests.modulemap";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				OTHER_LDFLAGS = "";
+				OTHER_LIBTOOLFLAGS = "";
+				PODS_ROOT = "$(SRCROOT)";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}";
+				PRODUCT_NAME = Pods_WhiskBotUITests;
+				SDKROOT = iphoneos;
+				SKIP_INSTALL = YES;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VERSIONING_SYSTEM = "apple-generic";
+				VERSION_INFO_PREFIX = "";
+			};
+			name = Release;
+		};
+		4140EE26F961CE36B6AB7340059D761C /* Debug */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 36105D6BFA5F5AB6ABE70E71EE8228C4 /* Pods-WhiskBot.debug.xcconfig */;
+			buildSettings = {
+				"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
+				"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
+				CURRENT_PROJECT_VERSION = 1;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				DEFINES_MODULE = YES;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_NO_COMMON_BLOCKS = YES;
+				INFOPLIST_FILE = "Target Support Files/Pods-WhiskBot/Info.plist";
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				IPHONEOS_DEPLOYMENT_TARGET = 10.2;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MACH_O_TYPE = staticlib;
+				MODULEMAP_FILE = "Target Support Files/Pods-WhiskBot/Pods-WhiskBot.modulemap";
+				MTL_ENABLE_DEBUG_INFO = YES;
+				OTHER_LDFLAGS = "";
+				OTHER_LIBTOOLFLAGS = "";
+				PODS_ROOT = "$(SRCROOT)";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}";
+				PRODUCT_NAME = Pods_WhiskBot;
+				SDKROOT = iphoneos;
+				SKIP_INSTALL = YES;
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VERSIONING_SYSTEM = "apple-generic";
+				VERSION_INFO_PREFIX = "";
+			};
+			name = Debug;
+		};
+		4EBE6F6BFA1FA02C5ABE1C7F220F24E2 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 591893BD9779F8D04A28A2FDE5C20562 /* JSQSystemSoundPlayer.xcconfig */;
+			buildSettings = {
+				"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
+				"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
+				CURRENT_PROJECT_VERSION = 1;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				DEFINES_MODULE = YES;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_PREFIX_HEADER = "Target Support Files/JSQSystemSoundPlayer/JSQSystemSoundPlayer-prefix.pch";
+				INFOPLIST_FILE = "Target Support Files/JSQSystemSoundPlayer/Info.plist";
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MODULEMAP_FILE = "Target Support Files/JSQSystemSoundPlayer/JSQSystemSoundPlayer.modulemap";
+				MTL_ENABLE_DEBUG_INFO = YES;
+				PRODUCT_NAME = JSQSystemSoundPlayer;
+				SDKROOT = iphoneos;
+				SKIP_INSTALL = YES;
+				SWIFT_VERSION = 3.0;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VERSIONING_SYSTEM = "apple-generic";
+				VERSION_INFO_PREFIX = "";
+			};
+			name = Debug;
+		};
+		55543C73CCF525C542B0353BFABFBCA7 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = A20FA82DA1AA5214F869ACD683D8E4F8 /* JSQMessagesViewController.xcconfig */;
+			buildSettings = {
+				"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
+				"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
+				CURRENT_PROJECT_VERSION = 1;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				DEFINES_MODULE = YES;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_PREFIX_HEADER = "Target Support Files/JSQMessagesViewController/JSQMessagesViewController-prefix.pch";
+				INFOPLIST_FILE = "Target Support Files/JSQMessagesViewController/Info.plist";
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MODULEMAP_FILE = "Target Support Files/JSQMessagesViewController/JSQMessagesViewController.modulemap";
+				MTL_ENABLE_DEBUG_INFO = YES;
+				PRODUCT_NAME = JSQMessagesViewController;
+				SDKROOT = iphoneos;
+				SKIP_INSTALL = YES;
+				SWIFT_VERSION = 3.0;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VERSIONING_SYSTEM = "apple-generic";
+				VERSION_INFO_PREFIX = "";
+			};
+			name = Debug;
+		};
+		673254EEAF0B5BF4596080C749645884 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				CODE_SIGNING_REQUIRED = NO;
+				COPY_PHASE_STRIP = YES;
+				ENABLE_NS_ASSERTIONS = NO;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"POD_CONFIGURATION_RELEASE=1",
+					"$(inherited)",
+				);
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 10.2;
+				PROVISIONING_PROFILE_SPECIFIER = NO_SIGNING/;
+				STRIP_INSTALLED_PRODUCT = NO;
+				SYMROOT = "${SRCROOT}/../build";
+				VALIDATE_PRODUCT = YES;
+			};
+			name = Release;
+		};
+		6F22BEEACA7189111A535D3776222863 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = DBFDAA0565A3919568B2B69EE389CC1C /* Pods-WhiskBotUITests.debug.xcconfig */;
+			buildSettings = {
+				"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
+				"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
+				CURRENT_PROJECT_VERSION = 1;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				DEFINES_MODULE = YES;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_NO_COMMON_BLOCKS = YES;
+				INFOPLIST_FILE = "Target Support Files/Pods-WhiskBotUITests/Info.plist";
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				IPHONEOS_DEPLOYMENT_TARGET = 10.2;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MACH_O_TYPE = staticlib;
+				MODULEMAP_FILE = "Target Support Files/Pods-WhiskBotUITests/Pods-WhiskBotUITests.modulemap";
+				MTL_ENABLE_DEBUG_INFO = YES;
+				OTHER_LDFLAGS = "";
+				OTHER_LIBTOOLFLAGS = "";
+				PODS_ROOT = "$(SRCROOT)";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}";
+				PRODUCT_NAME = Pods_WhiskBotUITests;
+				SDKROOT = iphoneos;
+				SKIP_INSTALL = YES;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VERSIONING_SYSTEM = "apple-generic";
+				VERSION_INFO_PREFIX = "";
+			};
+			name = Debug;
+		};
+		85CB941970266E196F27ADE185C5CD06 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 5393EAF83B4BC397AA0E38197BEFFEA2 /* Pods-WhiskBotTests.debug.xcconfig */;
+			buildSettings = {
+				"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
+				"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
+				CURRENT_PROJECT_VERSION = 1;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				DEFINES_MODULE = YES;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_NO_COMMON_BLOCKS = YES;
+				INFOPLIST_FILE = "Target Support Files/Pods-WhiskBotTests/Info.plist";
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				IPHONEOS_DEPLOYMENT_TARGET = 10.2;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MACH_O_TYPE = staticlib;
+				MODULEMAP_FILE = "Target Support Files/Pods-WhiskBotTests/Pods-WhiskBotTests.modulemap";
+				MTL_ENABLE_DEBUG_INFO = YES;
+				OTHER_LDFLAGS = "";
+				OTHER_LIBTOOLFLAGS = "";
+				PODS_ROOT = "$(SRCROOT)";
+				PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}";
+				PRODUCT_NAME = Pods_WhiskBotTests;
+				SDKROOT = iphoneos;
+				SKIP_INSTALL = YES;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VERSIONING_SYSTEM = "apple-generic";
+				VERSION_INFO_PREFIX = "";
+			};
+			name = Debug;
+		};
+		9A98FCC68669E11E489A325EE4658DDD /* Debug */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = EF3BE07AAAE2B939C8A40C336C06670A /* SwiftyJSON.xcconfig */;
+			buildSettings = {
+				"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
+				"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
+				CURRENT_PROJECT_VERSION = 1;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				DEFINES_MODULE = YES;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_PREFIX_HEADER = "Target Support Files/SwiftyJSON/SwiftyJSON-prefix.pch";
+				INFOPLIST_FILE = "Target Support Files/SwiftyJSON/Info.plist";
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MODULEMAP_FILE = "Target Support Files/SwiftyJSON/SwiftyJSON.modulemap";
+				MTL_ENABLE_DEBUG_INFO = YES;
+				PRODUCT_NAME = SwiftyJSON;
+				SDKROOT = iphoneos;
+				SKIP_INSTALL = YES;
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+				SWIFT_VERSION = 3.0;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VERSIONING_SYSTEM = "apple-generic";
+				VERSION_INFO_PREFIX = "";
+			};
+			name = Debug;
+		};
+		C02CFC46D1E5CA37AB3F72068114918C /* Release */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 591893BD9779F8D04A28A2FDE5C20562 /* JSQSystemSoundPlayer.xcconfig */;
+			buildSettings = {
+				"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
+				"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
+				CURRENT_PROJECT_VERSION = 1;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				DEFINES_MODULE = YES;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_PREFIX_HEADER = "Target Support Files/JSQSystemSoundPlayer/JSQSystemSoundPlayer-prefix.pch";
+				INFOPLIST_FILE = "Target Support Files/JSQSystemSoundPlayer/Info.plist";
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MODULEMAP_FILE = "Target Support Files/JSQSystemSoundPlayer/JSQSystemSoundPlayer.modulemap";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				PRODUCT_NAME = JSQSystemSoundPlayer;
+				SDKROOT = iphoneos;
+				SKIP_INSTALL = YES;
+				SWIFT_VERSION = 3.0;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VERSIONING_SYSTEM = "apple-generic";
+				VERSION_INFO_PREFIX = "";
+			};
+			name = Release;
+		};
+		C3B6CD6B7125CB4608914470B4BB4BEF /* Release */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 1A509411156D95A98D50167105B77EAE /* OpenWhisk.xcconfig */;
+			buildSettings = {
+				"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
+				"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
+				CURRENT_PROJECT_VERSION = 1;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				DEFINES_MODULE = YES;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_PREFIX_HEADER = "Target Support Files/OpenWhisk/OpenWhisk-prefix.pch";
+				INFOPLIST_FILE = "Target Support Files/OpenWhisk/Info.plist";
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MODULEMAP_FILE = "Target Support Files/OpenWhisk/OpenWhisk.modulemap";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				PRODUCT_NAME = OpenWhisk;
+				SDKROOT = iphoneos;
+				SKIP_INSTALL = YES;
+				SWIFT_VERSION = 3.0;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VERSIONING_SYSTEM = "apple-generic";
+				VERSION_INFO_PREFIX = "";
+			};
+			name = Release;
+		};
+		E21124538DA33D74F69885FFDA597AEA /* Release */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 1A509411156D95A98D50167105B77EAE /* OpenWhisk.xcconfig */;
+			buildSettings = {
+				CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/OpenWhisk";
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_NO_COMMON_BLOCKS = YES;
+				INFOPLIST_FILE = "Target Support Files/OpenWhisk/ResourceBundle-OpenWhiskResources-Info.plist";
+				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+				PRODUCT_NAME = OpenWhiskResources;
+				SDKROOT = iphoneos;
+				SKIP_INSTALL = YES;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				WRAPPER_EXTENSION = bundle;
+			};
+			name = Release;
+		};
+		E2E6B1F2FADF1628BB5A5CABC2F8ACA4 /* Release */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = EF3BE07AAAE2B939C8A40C336C06670A /* SwiftyJSON.xcconfig */;
+			buildSettings = {
+				"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
+				"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
+				CURRENT_PROJECT_VERSION = 1;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				DEFINES_MODULE = YES;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_PREFIX_HEADER = "Target Support Files/SwiftyJSON/SwiftyJSON-prefix.pch";
+				INFOPLIST_FILE = "Target Support Files/SwiftyJSON/Info.plist";
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				MODULEMAP_FILE = "Target Support Files/SwiftyJSON/SwiftyJSON.modulemap";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				PRODUCT_NAME = SwiftyJSON;
+				SDKROOT = iphoneos;
+				SKIP_INSTALL = YES;
+				SWIFT_VERSION = 3.0;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VERSIONING_SYSTEM = "apple-generic";
+				VERSION_INFO_PREFIX = "";
+			};
+			name = Release;
+		};
+		E4F26E6EB105713A6A7E7E2E283AC2DF /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				CODE_SIGNING_REQUIRED = NO;
+				COPY_PHASE_STRIP = NO;
+				ENABLE_TESTABILITY = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"POD_CONFIGURATION_DEBUG=1",
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 10.2;
+				ONLY_ACTIVE_ARCH = YES;
+				PROVISIONING_PROFILE_SPECIFIER = NO_SIGNING/;
+				STRIP_INSTALLED_PRODUCT = NO;
+				SYMROOT = "${SRCROOT}/../build";
+			};
+			name = Debug;
+		};
+		F36592F6FF01F5E1BF75F178D165FD5E /* Debug */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 1A509411156D95A98D50167105B77EAE /* OpenWhisk.xcconfig */;
+			buildSettings = {
+				CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/OpenWhisk";
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_NO_COMMON_BLOCKS = YES;
+				INFOPLIST_FILE = "Target Support Files/OpenWhisk/ResourceBundle-OpenWhiskResources-Info.plist";
+				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+				PRODUCT_NAME = OpenWhiskResources;
+				SDKROOT = iphoneos;
+				SKIP_INSTALL = YES;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				WRAPPER_EXTENSION = bundle;
+			};
+			name = Debug;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		044F2CF7A655D9419C2DDE17026FF849 /* Build configuration list for PBXNativeTarget "Pods-WhiskBotTests" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				85CB941970266E196F27ADE185C5CD06 /* Debug */,
+				28A34E51C6EDFC63B045D3248A317B97 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		1E786F92562B1C24C69679B20EDB3B6C /* Build configuration list for PBXNativeTarget "Pods-WhiskBot" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				4140EE26F961CE36B6AB7340059D761C /* Debug */,
+				3B8BDD35AB9FAEDDA5D574A79131A513 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		1F667698FA6F084AEB077EB13AC4DDE7 /* Build configuration list for PBXNativeTarget "JSQSystemSoundPlayer" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				4EBE6F6BFA1FA02C5ABE1C7F220F24E2 /* Debug */,
+				C02CFC46D1E5CA37AB3F72068114918C /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				E4F26E6EB105713A6A7E7E2E283AC2DF /* Debug */,
+				673254EEAF0B5BF4596080C749645884 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		78217554A79251977908CD048B2EEA16 /* Build configuration list for PBXNativeTarget "Pods-WhiskBotUITests" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				6F22BEEACA7189111A535D3776222863 /* Debug */,
+				400D365DBB62B3690E20E7C2034AE69C /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		8BCE1F1469AE142E766C22E3823AC508 /* Build configuration list for PBXNativeTarget "OpenWhisk" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				1A47B18C4B76FADFE563380E1B4F5A21 /* Debug */,
+				C3B6CD6B7125CB4608914470B4BB4BEF /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		9A471A7A29CA2DB2680A023F34B2A67B /* Build configuration list for PBXNativeTarget "OpenWhisk-OpenWhiskResources" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				F36592F6FF01F5E1BF75F178D165FD5E /* Debug */,
+				E21124538DA33D74F69885FFDA597AEA /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		CC69E587A3C23CD9E60E5D19627ED3F7 /* Build configuration list for PBXNativeTarget "SwiftyJSON" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				9A98FCC68669E11E489A325EE4658DDD /* Debug */,
+				E2E6B1F2FADF1628BB5A5CABC2F8ACA4 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		EF4840F49250B389B9C61B64707D6C6B /* Build configuration list for PBXNativeTarget "JSQMessagesViewController" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				55543C73CCF525C542B0353BFABFBCA7 /* Debug */,
+				029AE7B7112D7A646F4A766D63D4E75A /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = D41D8CD98F00B204E9800998ECF8427E /* Project object */;
+}
diff --git a/whiskbot-demo-app/Pods/SwiftyJSON/LICENSE b/whiskbot-demo-app/Pods/SwiftyJSON/LICENSE
new file mode 100644
index 0000000..916a0ac
--- /dev/null
+++ b/whiskbot-demo-app/Pods/SwiftyJSON/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Ruoyu Fu
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/whiskbot-demo-app/Pods/SwiftyJSON/README.md b/whiskbot-demo-app/Pods/SwiftyJSON/README.md
new file mode 100644
index 0000000..6256c84
--- /dev/null
+++ b/whiskbot-demo-app/Pods/SwiftyJSON/README.md
@@ -0,0 +1,519 @@
+# SwiftyJSON
+
+[![Travis CI](https://travis-ci.org/SwiftyJSON/SwiftyJSON.svg?branch=master)](https://travis-ci.org/SwiftyJSON/SwiftyJSON) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) ![CocoaPods](https://img.shields.io/cocoapods/v/SwiftyJSON.svg) ![Platform](https://img.shields.io/badge/platforms-iOS%208.0+%20%7C%20macOS%2010.10+%20%7C%20tvOS%209.0+%20%7C%20watchOS%202.0+-333333.svg)
+
+SwiftyJSON makes it easy to deal with JSON data in Swift.
+
+1. [Why is the typical JSON handling in Swift NOT good](#why-is-the-typical-json-handling-in-swift-not-good)
+2. [Requirements](#requirements)
+3. [Integration](#integration)
+4. [Usage](#usage)
+   - [Initialization](#initialization)
+   - [Subscript](#subscript)
+   - [Loop](#loop)
+   - [Error](#error)
+   - [Optional getter](#optional-getter)
+   - [Non-optional getter](#non-optional-getter)
+   - [Setter](#setter)
+   - [Raw object](#raw-object)
+   - [Literal convertibles](#literal-convertibles)
+   - [Merging](#merging)
+5. [Work with Alamofire](#work-with-alamofire)
+
+> For Legacy Swift support, take a look at the [swift2 branch](https://github.com/SwiftyJSON/SwiftyJSON/tree/swift2)
+
+> [中文介绍](http://tangplin.github.io/swiftyjson/)
+
+
+## Why is the typical JSON handling in Swift NOT good?
+
+Swift is very strict about types. But although explicit typing is good for saving us from mistakes, it becomes painful when dealing with JSON and other areas that are, by nature, implicit about types.
+
+Take the Twitter API for example. Say we want to retrieve a user's "name" value of some tweet in Swift (according to Twitter's API https://dev.twitter.com/docs/api/1.1/get/statuses/home_timeline).
+
+The code would look like this:
+
+```swift
+if let statusesArray = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [[String: Any]],
+    let user = statusesArray[0]["user"] as? [String: Any],
+    let username = user["name"] as? String {
+    // Finally we got the username
+}
+```
+
+It's not good.
+
+Even if we use optional chaining, it would be messy:
+
+```swift
+if let JSONObject = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [[String: Any]],
+    let username = (JSONObject[0]["user"] as? [String: Any])?["name"] as? String {
+        // There's our username
+}
+```
+
+An unreadable mess--for something that should really be simple!
+
+With SwiftyJSON all you have to do is:
+
+```swift
+let json = JSON(data: dataFromNetworking)
+if let userName = json[0]["user"]["name"].string {
+  //Now you got your value
+}
+```
+
+And don't worry about the Optional Wrapping thing. It's done for you automatically.
+
+```swift
+let json = JSON(data: dataFromNetworking)
+if let userName = json[999999]["wrong_key"]["wrong_name"].string {
+    //Calm down, take it easy, the ".string" property still produces the correct Optional String type with safety
+} else {
+    //Print the error
+    print(json[999999]["wrong_key"]["wrong_name"])
+}
+```
+
+## Requirements
+
+- iOS 8.0+ | macOS 10.10+ | tvOS 9.0+ | watchOS 2.0+
+- Xcode 8
+
+## Integration
+
+#### CocoaPods (iOS 8+, OS X 10.9+)
+
+You can use [CocoaPods](http://cocoapods.org/) to install `SwiftyJSON`by adding it to your `Podfile`:
+
+```ruby
+platform :ios, '8.0'
+use_frameworks!
+
+target 'MyApp' do
+	pod 'SwiftyJSON'
+end
+```
+
+Note that this requires CocoaPods version 36, and your iOS deployment target to be at least 8.0:
+
+
+#### Carthage (iOS 8+, OS X 10.9+)
+
+You can use [Carthage](https://github.com/Carthage/Carthage) to install `SwiftyJSON` by adding it to your `Cartfile`:
+
+```
+github "SwiftyJSON/SwiftyJSON"
+```
+
+#### Swift Package Manager
+
+You can use [The Swift Package Manager](https://swift.org/package-manager) to install `SwiftyJSON` by adding the proper description to your `Package.swift` file:
+
+```swift
+import PackageDescription
+
+let package = Package(
+    name: "YOUR_PROJECT_NAME",
+    targets: [],
+    dependencies: [
+        .Package(url: "https://github.com/SwiftyJSON/SwiftyJSON.git", versions: Version(1,0,0)..<Version(3, .max, .max)),
+    ]
+)
+```
+
+Note that the [Swift Package Manager](https://swift.org/package-manager) is still in early design and development, for more information checkout its [GitHub Page](https://github.com/apple/swift-package-manager)
+
+#### Manually (iOS 7+, OS X 10.9+)
+
+To use this library in your project manually you may:  
+
+1. for Projects, just drag SwiftyJSON.swift to the project tree
+2. for Workspaces, include the whole SwiftyJSON.xcodeproj
+
+## Usage
+
+#### Initialization
+
+```swift
+import SwiftyJSON
+```
+
+```swift
+let json = JSON(data: dataFromNetworking)
+```
+
+```swift
+let json = JSON(jsonObject)
+```
+
+```swift
+if let dataFromString = jsonString.data(using: .utf8, allowLossyConversion: false) {
+    let json = JSON(data: dataFromString)
+}
+```
+
+#### Subscript
+
+```swift
+//Getting a double from a JSON Array
+let name = json[0].double
+```
+
+```swift
+//Getting an array of string from a JSON Array
+let arrayNames =  json["users"].arrayValue.map({$0["name"].stringValue})
+```
+
+```swift
+//Getting a string from a JSON Dictionary
+let name = json["name"].stringValue
+```
+
+```swift
+//Getting a string using a path to the element
+let path: [JSONSubscriptType] = [1,"list",2,"name"]
+let name = json[path].string
+//Just the same
+let name = json[1]["list"][2]["name"].string
+//Alternatively
+let name = json[1,"list",2,"name"].string
+```
+
+```swift
+//With a hard way
+let name = json[].string
+```
+
+```swift
+//With a custom way
+let keys:[SubscriptType] = [1,"list",2,"name"]
+let name = json[keys].string
+```
+
+#### Loop
+
+```swift
+//If json is .Dictionary
+for (key,subJson):(String, JSON) in json {
+   //Do something you want
+}
+```
+
+*The first element is always a String, even if the JSON is an Array*
+
+```swift
+//If json is .Array
+//The `index` is 0..<json.count's string value
+for (index,subJson):(String, JSON) in json {
+    //Do something you want
+}
+```
+
+#### Error
+
+Use a subscript to get/set a value in an Array or Dictionary
+
+If the JSON is:
+*  an array, the app may crash with "index out-of-bounds."
+*  a dictionary, it will be assigned `nil` without a reason.
+*  not an array or a dictionary, the app may crash with an "unrecognised selector" exception.
+
+This will never happen in SwiftyJSON.
+
+```swift
+let json = JSON(["name", "age"])
+if let name = json[999].string {
+    //Do something you want
+} else {
+    print(json[999].error) // "Array[999] is out of bounds"
+}
+```
+
+```swift
+let json = JSON(["name":"Jack", "age": 25])
+if let name = json["address"].string {
+    //Do something you want
+} else {
+    print(json["address"].error) // "Dictionary["address"] does not exist"
+}
+```
+
+```swift
+let json = JSON(12345)
+if let age = json[0].string {
+    //Do something you want
+} else {
+    print(json[0])       // "Array[0] failure, It is not an array"
+    print(json[0].error) // "Array[0] failure, It is not an array"
+}
+
+if let name = json["name"].string {
+    //Do something you want
+} else {
+    print(json["name"])       // "Dictionary[\"name"] failure, It is not an dictionary"
+    print(json["name"].error) // "Dictionary[\"name"] failure, It is not an dictionary"
+}
+```
+
+#### Optional getter
+
+```swift
+//NSNumber
+if let id = json["user"]["favourites_count"].number {
+   //Do something you want
+} else {
+   //Print the error
+   print(json["user"]["favourites_count"].error)
+}
+```
+
+```swift
+//String
+if let id = json["user"]["name"].string {
+   //Do something you want
+} else {
+   //Print the error
+   print(json["user"]["name"])
+}
+```
+
+```swift
+//Bool
+if let id = json["user"]["is_translator"].bool {
+   //Do something you want
+} else {
+   //Print the error
+   print(json["user"]["is_translator"])
+}
+```
+
+```swift
+//Int
+if let id = json["user"]["id"].int {
+   //Do something you want
+} else {
+   //Print the error
+   print(json["user"]["id"])
+}
+...
+```
+
+#### Non-optional getter
+
+Non-optional getter is named `xxxValue`
+
+```swift
+//If not a Number or nil, return 0
+let id: Int = json["id"].intValue
+```
+
+```swift
+//If not a String or nil, return ""
+let name: String = json["name"].stringValue
+```
+
+```swift
+//If not an Array or nil, return []
+let list: Array<JSON> = json["list"].arrayValue
+```
+
+```swift
+//If not a Dictionary or nil, return [:]
+let user: Dictionary<String, JSON> = json["user"].dictionaryValue
+```
+
+#### Setter
+
+```swift
+json["name"] = JSON("new-name")
+json[0] = JSON(1)
+```
+
+```swift
+json["id"].int =  1234567890
+json["coordinate"].double =  8766.766
+json["name"].string =  "Jack"
+json.arrayObject = [1,2,3,4]
+json.dictionaryObject = ["name":"Jack", "age":25]
+```
+
+#### Raw object
+
+```swift
+let jsonObject: Any = json.object
+```
+
+```swift
+if let jsonObject: Any = json.rawValue
+```
+
+```swift
+//convert the JSON to raw NSData
+if let data = json.rawData() {
+    //Do something you want
+}
+```
+
+```swift
+//convert the JSON to a raw String
+if let string = json.rawString() {
+    //Do something you want
+}
+```
+
+#### Existence
+
+```swift
+//shows you whether value specified in JSON or not
+if json["name"].exists()
+```
+
+#### Literal convertibles
+
+For more info about literal convertibles: [Swift Literal Convertibles](http://nshipster.com/swift-literal-convertible/)
+
+```swift
+//StringLiteralConvertible
+let json: JSON = "I'm a json"
+```
+
+```swift
+//IntegerLiteralConvertible
+let json: JSON =  12345
+```
+
+```swift
+//BooleanLiteralConvertible
+let json: JSON =  true
+```
+
+```swift
+//FloatLiteralConvertible
+let json: JSON =  2.8765
+```
+
+```swift
+//DictionaryLiteralConvertible
+let json: JSON =  ["I":"am", "a":"json"]
+```
+
+```swift
+//ArrayLiteralConvertible
+let json: JSON =  ["I", "am", "a", "json"]
+```
+
+```swift
+//NilLiteralConvertible
+let json: JSON =  nil
+```
+
+```swift
+//With subscript in array
+var json: JSON =  [1,2,3]
+json[0] = 100
+json[1] = 200
+json[2] = 300
+json[999] = 300 //Don't worry, nothing will happen
+```
+
+```swift
+//With subscript in dictionary
+var json: JSON =  ["name": "Jack", "age": 25]
+json["name"] = "Mike"
+json["age"] = "25" //It's OK to set String
+json["address"] = "L.A." // Add the "address": "L.A." in json
+```
+
+```swift
+//Array & Dictionary
+var json: JSON =  ["name": "Jack", "age": 25, "list": ["a", "b", "c", ["what": "this"]]]
+json["list"][3]["what"] = "that"
+json["list",3,"what"] = "that"
+let path: [JSONSubscriptType] = ["list",3,"what"]
+json[path] = "that"
+```
+
+```swift
+//With other JSON objects
+let user: JSON = ["username" : "Steve", "password": "supersecurepassword"]
+let auth: JSON = [
+  "user": user.object //use user.object instead of just user
+  "apikey": "supersecretapitoken"
+]
+```
+
+#### Merging
+
+It is possible to merge one JSON into another JSON. Merging a JSON into another JSON adds all non existing values to the original JSON which are only present in the `other` JSON.
+
+If both JSONs contain a value for the same key, _mostly_ this value gets overwritten in the original JSON, but there are two cases where it provides some special treatment:
+
+- In case of both values being a `JSON.Type.array` the values form the array found in the `other` JSON getting appended to the original JSON's array value. 
+- In case of both values being a `JSON.Type.dictionary` both JSON-values are getting merged the same way the encapsulating JSON is merged.
+
+In case, where two fields in a JSON have a different types, the value will get always overwritten.
+
+There are two different fashions for merging: `merge` modifies the original JSON, whereas `merged` works non-destructively on a copy.
+
+```swift
+let original: JSON = [
+    "first_name": "John",
+    "age": 20,
+    "skills": ["Coding", "Reading"],
+    "address": [
+        "street": "Front St",
+        "zip": "12345",
+    ]
+]
+
+let update: JSON = [
+    "last_name": "Doe",
+    "age": 21,
+    "skills": ["Writing"],
+    "address": [
+        "zip": "12342",
+        "city": "New York City"
+    ]
+]
+
+let updated = original.merge(with: update)
+// [
+//     "first_name": "John",
+//     "last_name": "Doe",
+//     "age": 21,
+//     "skills": ["Coding", "Reading", "Writing"],
+//     "address": [
+//         "street": "Front St",
+//         "zip": "12342",
+//         "city": "New York City"
+//     ]
+// ]
+```
+
+## String representation
+There are two options available:
+- use the default Swift one
+- use a custom one that will handle optionals well and represent `nil` as `"null"`:
+```swift
+let dict = ["1":2, "2":"two", "3": nil] as [String: Any?]
+let json = JSON(dict)
+let representation = json.rawString(options: [.castNilToNSNull: true])
+// representation is "{\"1\":2,\"2\":\"two\",\"3\":null}", which represents {"1":2,"2":"two","3":null}
+```
+
+## Work with Alamofire
+
+SwiftyJSON nicely wraps the result of the Alamofire JSON response handler:
+
+```swift
+Alamofire.request(url, method: .get).validate().responseJSON { response in
+    switch response.result {
+    case .success(let value):
+        let json = JSON(value)
+        print("JSON: \(json)")
+    case .failure(let error):
+        print(error)
+    }
+}
+```
diff --git a/whiskbot-demo-app/Pods/SwiftyJSON/Source/SwiftyJSON.swift b/whiskbot-demo-app/Pods/SwiftyJSON/Source/SwiftyJSON.swift
new file mode 100644
index 0000000..e79c10d
--- /dev/null
+++ b/whiskbot-demo-app/Pods/SwiftyJSON/Source/SwiftyJSON.swift
@@ -0,0 +1,1485 @@
+//  SwiftyJSON.swift
+//
+//  Copyright (c) 2014 - 2017 Ruoyu Fu, Pinglin Tang
+//
+//  Permission is hereby granted, free of charge, to any person obtaining a copy
+//  of this software and associated documentation files (the "Software"), to deal
+//  in the Software without restriction, including without limitation the rights
+//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+//  copies of the Software, and to permit persons to whom the Software is
+//  furnished to do so, subject to the following conditions:
+//
+//  The above copyright notice and this permission notice shall be included in
+//  all copies or substantial portions of the Software.
+//
+//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+//  THE SOFTWARE.
+
+import Foundation
+
+// MARK: - Error
+
+///Error domain
+public let ErrorDomain: String = "SwiftyJSONErrorDomain"
+
+///Error code
+public let ErrorUnsupportedType: Int = 999
+public let ErrorIndexOutOfBounds: Int = 900
+public let ErrorWrongType: Int = 901
+public let ErrorNotExist: Int = 500
+public let ErrorInvalidJSON: Int = 490
+
+// MARK: - JSON Type
+
+/**
+ JSON's type definitions.
+
+ See http://www.json.org
+ */
+public enum Type :Int{
+
+    case number
+    case string
+    case bool
+    case array
+    case dictionary
+    case null
+    case unknown
+}
+
+// MARK: - JSON Base
+public struct JSON {
+
+    /**
+     Creates a JSON using the data.
+
+     - parameter data:  The NSData used to convert to json.Top level object in data is an NSArray or NSDictionary
+     - parameter opt:   The JSON serialization reading options. `.AllowFragments` by default.
+     - parameter error: The NSErrorPointer used to return the error. `nil` by default.
+
+     - returns: The created JSON
+     */
+    public init(data: Data, options opt: JSONSerialization.ReadingOptions = .allowFragments, error: NSErrorPointer = nil) {
+        do {
+            let object: Any = try JSONSerialization.jsonObject(with: data, options: opt)
+            self.init(jsonObject: object)
+        } catch let aError as NSError {
+            if error != nil {
+                error?.pointee = aError
+            }
+            self.init(jsonObject: NSNull())
+        }
+    }
+
+    /**
+     Creates a JSON object
+     - parameter object: the object
+     - note: this does not parse a `String` into JSON, instead use `init(parseJSON: String)`
+     - returns: the created JSON object
+     */
+    public init(_ object: Any) {
+        switch object {
+        case let object as [JSON] where object.count > 0:
+            self.init(array: object)
+        case let object as [String: JSON] where object.count > 0:
+            self.init(dictionary: object)
+        case let object as Data:
+            self.init(data: object)
+        default:
+            self.init(jsonObject: object)
+        }
+    }
+
+    /**
+     Parses the JSON string into a JSON object
+     - parameter json: the JSON string
+     - returns: the created JSON object
+     */
+    public init(parseJSON jsonString: String) {
+        if let data = jsonString.data(using: .utf8) {
+            self.init(data)
+        } else {
+            self.init(NSNull())
+        }
+    }
+
+    /**
+     Creates a JSON from JSON string
+     - parameter string: Normal json string like '{"a":"b"}'
+
+     - returns: The created JSON
+     */
+    @available(*, deprecated: 3.2, message: "Use instead `init(parseJSON: )`")
+    public static func parse(_ json: String) -> JSON {
+        return json.data(using: String.Encoding.utf8)
+            .flatMap{ JSON(data: $0) } ?? JSON(NSNull())
+    }
+
+    /**
+     Creates a JSON using the object.
+
+     - parameter object:  The object must have the following properties: All objects are NSString/String, NSNumber/Int/Float/Double/Bool, NSArray/Array, NSDictionary/Dictionary, or NSNull; All dictionary keys are NSStrings/String; NSNumbers are not NaN or infinity.
+
+     - returns: The created JSON
+     */
+    fileprivate init(jsonObject: Any) {
+        self.object = jsonObject
+    }
+
+    /**
+     Creates a JSON from a [JSON]
+
+     - parameter jsonArray: A Swift array of JSON objects
+
+     - returns: The created JSON
+     */
+    fileprivate init(array: [JSON]) {
+        self.init(array.map { $0.object })
+    }
+
+    /**
+     Creates a JSON from a [String: JSON]
+
+     - parameter jsonDictionary: A Swift dictionary of JSON objects
+
+     - returns: The created JSON
+     */
+    fileprivate init(dictionary: [String: JSON]) {
+        var newDictionary = [String: Any](minimumCapacity: dictionary.count)
+        for (key, json) in dictionary {
+            newDictionary[key] = json.object
+        }
+
+        self.init(newDictionary)
+    }
+    
+    /**
+     Merges another JSON into this JSON, whereas primitive values which are not present in this JSON are getting added, 
+     present values getting overwritten, array values getting appended and nested JSONs getting merged the same way.
+ 
+     - parameter other: The JSON which gets merged into this JSON
+     - throws `ErrorWrongType` if the other JSONs differs in type on the top level.
+     */
+    public mutating func merge(with other: JSON) throws {
+        try self.merge(with: other, typecheck: true)
+    }
+    
+    /**
+     Merges another JSON into this JSON and returns a new JSON, whereas primitive values which are not present in this JSON are getting added,
+     present values getting overwritten, array values getting appended and nested JSONS getting merged the same way.
+     
+     - parameter other: The JSON which gets merged into this JSON
+     - returns: New merged JSON
+     - throws `ErrorWrongType` if the other JSONs differs in type on the top level.
+     */
+    public func merged(with other: JSON) throws -> JSON {
+        var merged = self
+        try merged.merge(with: other, typecheck: true)
+        return merged
+    }
+    
+    // Private woker function which does the actual merging
+    // Typecheck is set to true for the first recursion level to prevent total override of the source JSON
+    fileprivate mutating func merge(with other: JSON, typecheck: Bool) throws {
+        if self.type == other.type {
+            switch self.type {
+            case .dictionary:
+                for (key, _) in other {
+                    try self[key].merge(with: other[key], typecheck: false)
+                }
+            case .array:
+                self = JSON(self.arrayValue + other.arrayValue)
+            default:
+                self = other
+            }
+        } else {
+            if typecheck {
+                throw NSError(domain: ErrorDomain, code: ErrorWrongType, userInfo: [NSLocalizedDescriptionKey: "Couldn't merge, because the JSONs differ in type on top level."])
+            } else {
+                self = other
+            }
+        }
+    }
+
+    /// Private object
+    fileprivate var rawArray: [Any] = []
+    fileprivate var rawDictionary: [String : Any] = [:]
+    fileprivate var rawString: String = ""
+    fileprivate var rawNumber: NSNumber = 0
+    fileprivate var rawNull: NSNull = NSNull()
+    fileprivate var rawBool: Bool = false
+    /// Private type
+    fileprivate var _type: Type = .null
+    /// prviate error
+    fileprivate var _error: NSError? = nil
+
+    /// Object in JSON
+    public var object: Any {
+        get {
+            switch self.type {
+            case .array:
+                return self.rawArray
+            case .dictionary:
+                return self.rawDictionary
+            case .string:
+                return self.rawString
+            case .number:
+                return self.rawNumber
+            case .bool:
+                return self.rawBool
+            default:
+                return self.rawNull
+            }
+        }
+        set {
+            _error = nil
+            switch newValue {
+            case let number as NSNumber:
+                if number.isBool {
+                    _type = .bool
+                    self.rawBool = number.boolValue
+                } else {
+                    _type = .number
+                    self.rawNumber = number
+                }
+            case let string as String:
+                _type = .string
+                self.rawString = string
+            case _ as NSNull:
+                _type = .null
+            case _ as [JSON]:
+				_type = .array
+			case nil:
+				_type = .null
+            case let array as [Any]:
+                _type = .array
+                self.rawArray = array
+            case let dictionary as [String : Any]:
+                _type = .dictionary
+                self.rawDictionary = dictionary
+            default:
+                _type = .unknown
+                _error = NSError(domain: ErrorDomain, code: ErrorUnsupportedType, userInfo: [NSLocalizedDescriptionKey: "It is a unsupported type"])
+            }
+        }
+    }
+
+    /// JSON type
+    public var type: Type { get { return _type } }
+
+    /// Error in JSON
+    public var error: NSError? { get { return self._error } }
+
+    /// The static null JSON
+    @available(*, unavailable, renamed:"null")
+    public static var nullJSON: JSON { get { return null } }
+    public static var null: JSON { get { return JSON(NSNull()) } }
+}
+
+public enum Index<T: Any>: Comparable
+{
+    case array(Int)
+    case dictionary(DictionaryIndex<String, T>)
+    case null
+
+    static public func ==(lhs: Index, rhs: Index) -> Bool {
+        switch (lhs, rhs) {
+        case (.array(let left), .array(let right)):
+            return left == right
+        case (.dictionary(let left), .dictionary(let right)):
+            return left == right
+        case (.null, .null): return true
+        default:
+            return false
+        }
+    }
+
+    static public func <(lhs: Index, rhs: Index) -> Bool {
+        switch (lhs, rhs) {
+        case (.array(let left), .array(let right)):
+            return left < right
+        case (.dictionary(let left), .dictionary(let right)):
+            return left < right
+        default:
+            return false
+        }
+    }
+}
+
+public typealias JSONIndex = Index<JSON>
+public typealias JSONRawIndex = Index<Any>
+
+
+extension JSON: Collection
+{
+
+    public typealias Index = JSONRawIndex
+
+    public var startIndex: Index
+    {
+        switch type
+        {
+        case .array:
+            return .array(rawArray.startIndex)
+        case .dictionary:
+            return .dictionary(rawDictionary.startIndex)
+        default:
+            return .null
+        }
+    }
+
+    public var endIndex: Index
+    {
+        switch type
+        {
+        case .array:
+            return .array(rawArray.endIndex)
+        case .dictionary:
+            return .dictionary(rawDictionary.endIndex)
+        default:
+            return .null
+        }
+    }
+
+    public func index(after i: Index) -> Index
+    {
+        switch i
+        {
+        case .array(let idx):
+            return .array(rawArray.index(after: idx))
+        case .dictionary(let idx):
+            return .dictionary(rawDictionary.index(after: idx))
+        default:
+            return .null
+        }
+
+    }
+
+    public subscript (position: Index) -> (String, JSON)
+    {
+        switch position
+        {
+        case .array(let idx):
+            return (String(idx), JSON(self.rawArray[idx]))
+        case .dictionary(let idx):
+            let (key, value) = self.rawDictionary[idx]
+            return (key, JSON(value))
+        default:
+            return ("", JSON.null)
+        }
+    }
+
+
+}
+
+// MARK: - Subscript
+
+/**
+ *  To mark both String and Int can be used in subscript.
+ */
+public enum JSONKey
+{
+    case index(Int)
+    case key(String)
+}
+
+public protocol JSONSubscriptType {
+    var jsonKey:JSONKey { get }
+}
+
+extension Int: JSONSubscriptType {
+    public var jsonKey:JSONKey {
+        return JSONKey.index(self)
+    }
+}
+
+extension String: JSONSubscriptType {
+    public var jsonKey:JSONKey {
+        return JSONKey.key(self)
+    }
+}
+
+extension JSON {
+
+    /// If `type` is `.Array`, return json whose object is `array[index]`, otherwise return null json with error.
+    fileprivate subscript(index index: Int) -> JSON {
+        get {
+            if self.type != .array {
+                var r = JSON.null
+                r._error = self._error ?? NSError(domain: ErrorDomain, code: ErrorWrongType, userInfo: [NSLocalizedDescriptionKey: "Array[\(index)] failure, It is not an array"])
+                return r
+            } else if index >= 0 && index < self.rawArray.count {
+                return JSON(self.rawArray[index])
+            } else {
+                var r = JSON.null
+                r._error = NSError(domain: ErrorDomain, code:ErrorIndexOutOfBounds , userInfo: [NSLocalizedDescriptionKey: "Array[\(index)] is out of bounds"])
+                return r
+            }
+        }
+        set {
+            if self.type == .array {
+                if self.rawArray.count > index && newValue.error == nil {
+                    self.rawArray[index] = newValue.object
+                }
+            }
+        }
+    }
+
+    /// If `type` is `.Dictionary`, return json whose object is `dictionary[key]` , otherwise return null json with error.
+    fileprivate subscript(key key: String) -> JSON {
+        get {
+            var r = JSON.null
+            if self.type == .dictionary {
+                if let o = self.rawDictionary[key] {
+                    r = JSON(o)
+                } else {
+                    r._error = NSError(domain: ErrorDomain, code: ErrorNotExist, userInfo: [NSLocalizedDescriptionKey: "Dictionary[\"\(key)\"] does not exist"])
+                }
+            } else {
+                r._error = self._error ?? NSError(domain: ErrorDomain, code: ErrorWrongType, userInfo: [NSLocalizedDescriptionKey: "Dictionary[\"\(key)\"] failure, It is not an dictionary"])
+            }
+            return r
+        }
+        set {
+            if self.type == .dictionary && newValue.error == nil {
+                self.rawDictionary[key] = newValue.object
+            }
+        }
+    }
+
+    /// If `sub` is `Int`, return `subscript(index:)`; If `sub` is `String`,  return `subscript(key:)`.
+    fileprivate subscript(sub sub: JSONSubscriptType) -> JSON {
+        get {
+            switch sub.jsonKey {
+            case .index(let index): return self[index: index]
+            case .key(let key): return self[key: key]
+            }
+        }
+        set {
+            switch sub.jsonKey {
+            case .index(let index): self[index: index] = newValue
+            case .key(let key): self[key: key] = newValue
+            }
+        }
+    }
+
+    /**
+     Find a json in the complex data structures by using array of Int and/or String as path.
+
+     - parameter path: The target json's path. Example:
+
+     let json = JSON[data]
+     let path = [9,"list","person","name"]
+     let name = json[path]
+
+     The same as: let name = json[9]["list"]["person"]["name"]
+
+     - returns: Return a json found by the path or a null json with error
+     */
+    public subscript(path: [JSONSubscriptType]) -> JSON {
+        get {
+            return path.reduce(self) { $0[sub: $1] }
+        }
+        set {
+            switch path.count {
+            case 0:
+                return
+            case 1:
+                self[sub:path[0]].object = newValue.object
+            default:
+                var aPath = path; aPath.remove(at: 0)
+                var nextJSON = self[sub: path[0]]
+                nextJSON[aPath] = newValue
+                self[sub: path[0]] = nextJSON
+            }
+        }
+    }
+
+    /**
+     Find a json in the complex data structures by using array of Int and/or String as path.
+
+     - parameter path: The target json's path. Example:
+
+     let name = json[9,"list","person","name"]
+
+     The same as: let name = json[9]["list"]["person"]["name"]
+
+     - returns: Return a json found by the path or a null json with error
+     */
+    public subscript(path: JSONSubscriptType...) -> JSON {
+        get {
+            return self[path]
+        }
+        set {
+            self[path] = newValue
+        }
+    }
+}
+
+// MARK: - LiteralConvertible
+
+extension JSON: Swift.ExpressibleByStringLiteral {
+
+    public init(stringLiteral value: StringLiteralType) {
+        self.init(value as Any)
+    }
+
+    public init(extendedGraphemeClusterLiteral value: StringLiteralType) {
+        self.init(value as Any)
+    }
+
+    public init(unicodeScalarLiteral value: StringLiteralType) {
+        self.init(value as Any)
+    }
+}
+
+extension JSON: Swift.ExpressibleByIntegerLiteral {
+
+    public init(integerLiteral value: IntegerLiteralType) {
+        self.init(value as Any)
+    }
+}
+
+extension JSON: Swift.ExpressibleByBooleanLiteral {
+
+    public init(booleanLiteral value: BooleanLiteralType) {
+        self.init(value as Any)
+    }
+}
+
+extension JSON: Swift.ExpressibleByFloatLiteral {
+
+    public init(floatLiteral value: FloatLiteralType) {
+        self.init(value as Any)
+    }
+}
+
+extension JSON: Swift.ExpressibleByDictionaryLiteral {
+    public init(dictionaryLiteral elements: (String, Any)...) {
+        let array = elements
+        self.init(dictionaryLiteral: array)
+    }
+
+    public init(dictionaryLiteral elements: [(String, Any)]) {
+        let jsonFromDictionaryLiteral: ([String : Any]) -> JSON = { dictionary in
+            let initializeElement = Array(dictionary.keys).flatMap { key -> (String, Any)? in
+                if let value = dictionary[key] {
+                    return (key, value)
+                }
+                return nil
+            }
+            return JSON(dictionaryLiteral: initializeElement)
+        }
+
+        var dict = [String : Any](minimumCapacity: elements.count)
+
+        for element in elements {
+            let elementToSet: Any
+            if let json = element.1 as? JSON {
+                elementToSet = json.object
+            } else if let jsonArray = element.1 as? [JSON] {
+                elementToSet = JSON(jsonArray).object
+            } else if let dictionary = element.1 as? [String : Any] {
+                elementToSet = jsonFromDictionaryLiteral(dictionary).object
+            } else if let dictArray = element.1 as? [[String : Any]] {
+                let jsonArray = dictArray.map { jsonFromDictionaryLiteral($0) }
+                elementToSet = JSON(jsonArray).object
+            } else {
+                elementToSet = element.1
+            }
+            dict[element.0] = elementToSet
+        }
+
+        self.init(dict)
+    }
+}
+
+extension JSON: Swift.ExpressibleByArrayLiteral {
+
+    public init(arrayLiteral elements: Any...) {
+        self.init(elements as Any)
+    }
+}
+
+extension JSON: Swift.ExpressibleByNilLiteral {
+
+    @available(*, deprecated, message: "use JSON.null instead. Will be removed in future versions")
+    public init(nilLiteral: ()) {
+        self.init(NSNull() as Any)
+    }
+}
+
+// MARK: - Raw
+
+extension JSON: Swift.RawRepresentable {
+
+    public init?(rawValue: Any) {
+        if JSON(rawValue).type == .unknown {
+            return nil
+        } else {
+            self.init(rawValue)
+        }
+    }
+
+    public var rawValue: Any {
+        return self.object
+    }
+
+    public func rawData(options opt: JSONSerialization.WritingOptions = JSONSerialization.WritingOptions(rawValue: 0)) throws -> Data {
+        guard JSONSerialization.isValidJSONObject(self.object) else {
+            throw NSError(domain: ErrorDomain, code: ErrorInvalidJSON, userInfo: [NSLocalizedDescriptionKey: "JSON is invalid"])
+        }
+
+        return try JSONSerialization.data(withJSONObject: self.object, options: opt)
+	}
+	
+	public func rawString(_ encoding: String.Encoding = .utf8, options opt: JSONSerialization.WritingOptions = .prettyPrinted) -> String? {
+		do {
+			return try _rawString(encoding, options: [.jsonSerialization: opt])
+		} catch {
+			print("Could not serialize object to JSON because:", error.localizedDescription)
+			return nil
+		}
+	}
+
+	public func rawString(_ options: [writtingOptionsKeys: Any]) -> String? {
+		let encoding = options[.encoding] as? String.Encoding ?? String.Encoding.utf8
+		let maxObjectDepth = options[.maxObjextDepth] as? Int ?? 10
+		do {
+			return try _rawString(encoding, options: options, maxObjectDepth: maxObjectDepth)
+		} catch {
+			print("Could not serialize object to JSON because:", error.localizedDescription)
+			return nil
+		}
+	}
+
+	fileprivate func _rawString(
+		_ encoding: String.Encoding = .utf8,
+		options: [writtingOptionsKeys: Any],
+		maxObjectDepth: Int = 10
+	) throws -> String? {
+        if (maxObjectDepth < 0) {
+            throw NSError(domain: ErrorDomain, code: ErrorInvalidJSON, userInfo: [NSLocalizedDescriptionKey: "Element too deep. Increase maxObjectDepth and make sure there is no reference loop"])
+        }
+        switch self.type {
+		case .dictionary:
+			do {
+				if !(options[.castNilToNSNull] as? Bool ?? false) {
+					let jsonOption = options[.jsonSerialization] as? JSONSerialization.WritingOptions ?? JSONSerialization.WritingOptions.prettyPrinted
+					let data = try self.rawData(options: jsonOption)
+					return String(data: data, encoding: encoding)
+				}
+
+				guard let dict = self.object as? [String: Any?] else {
+					return nil
+				}
+				let body = try dict.keys.map { key throws -> String in
+					guard let value = dict[key] else {
+						return "\"\(key)\": null"
+					}
+					guard let unwrappedValue = value else {
+						return "\"\(key)\": null"
+					}
+
+					let nestedValue = JSON(unwrappedValue)
+					guard let nestedString = try nestedValue._rawString(encoding, options: options, maxObjectDepth: maxObjectDepth - 1) else {
+						throw NSError(domain: ErrorDomain, code: ErrorInvalidJSON, userInfo: [NSLocalizedDescriptionKey: "Could not serialize nested JSON"])
+					}
+					if nestedValue.type == .string {
+						return "\"\(key)\": \"\(nestedString.replacingOccurrences(of: "\\", with: "\\\\").replacingOccurrences(of: "\"", with: "\\\""))\""
+					} else {
+						return "\"\(key)\": \(nestedString)"
+					}
+				}
+
+				return "{\(body.joined(separator: ","))}"
+			} catch _ {
+				return nil
+			}
+		case .array:
+            do {
+				if !(options[.castNilToNSNull] as? Bool ?? false) {
+					let jsonOption = options[.jsonSerialization] as? JSONSerialization.WritingOptions ?? JSONSerialization.WritingOptions.prettyPrinted
+					let data = try self.rawData(options: jsonOption)
+					return String(data: data, encoding: encoding)
+				}
+
+                guard let array = self.object as? [Any?] else {
+                    return nil
+                }
+                let body = try array.map { value throws -> String in
+                    guard let unwrappedValue = value else {
+                        return "null"
+                    }
+
+                    let nestedValue = JSON(unwrappedValue)
+                    guard let nestedString = try nestedValue._rawString(encoding, options: options, maxObjectDepth: maxObjectDepth - 1) else {
+                        throw NSError(domain: ErrorDomain, code: ErrorInvalidJSON, userInfo: [NSLocalizedDescriptionKey: "Could not serialize nested JSON"])
+                    }
+                    if nestedValue.type == .string {
+                        return "\"\(nestedString.replacingOccurrences(of: "\\", with: "\\\\").replacingOccurrences(of: "\"", with: "\\\""))\""
+                    } else {
+                        return nestedString
+                    }
+                }
+
+                return "[\(body.joined(separator: ","))]"
+            } catch _ {
+                return nil
+            }
+        case .string:
+            return self.rawString
+        case .number:
+            return self.rawNumber.stringValue
+        case .bool:
+            return self.rawBool.description
+        case .null:
+            return "null"
+        default:
+            return nil
+        }
+    }
+}
+
+// MARK: - Printable, DebugPrintable
+
+extension JSON: Swift.CustomStringConvertible, Swift.CustomDebugStringConvertible {
+
+    public var description: String {
+        if let string = self.rawString(options:.prettyPrinted) {
+            return string
+        } else {
+            return "unknown"
+        }
+    }
+
+    public var debugDescription: String {
+        return description
+    }
+}
+
+// MARK: - Array
+
+extension JSON {
+
+    //Optional [JSON]
+    public var array: [JSON]? {
+        get {
+            if self.type == .array {
+                return self.rawArray.map{ JSON($0) }
+            } else {
+                return nil
+            }
+        }
+    }
+
+    //Non-optional [JSON]
+    public var arrayValue: [JSON] {
+        get {
+            return self.array ?? []
+        }
+    }
+
+    //Optional [Any]
+    public var arrayObject: [Any]? {
+        get {
+            switch self.type {
+            case .array:
+                return self.rawArray
+            default:
+                return nil
+            }
+        }
+        set {
+            if let array = newValue {
+                self.object = array as Any
+            } else {
+                self.object = NSNull()
+            }
+        }
+    }
+}
+
+// MARK: - Dictionary
+
+extension JSON {
+
+    //Optional [String : JSON]
+    public var dictionary: [String : JSON]? {
+        if self.type == .dictionary {
+            var d = [String : JSON](minimumCapacity: rawDictionary.count)
+            for (key, value) in rawDictionary {
+                d[key] = JSON(value)
+            }
+            return d
+        } else {
+            return nil
+        }
+    }
+
+    //Non-optional [String : JSON]
+    public var dictionaryValue: [String : JSON] {
+        return self.dictionary ?? [:]
+    }
+
+    //Optional [String : Any]
+
+    public var dictionaryObject: [String : Any]? {
+        get {
+            switch self.type {
+            case .dictionary:
+                return self.rawDictionary
+            default:
+                return nil
+            }
+        }
+        set {
+            if let v = newValue {
+                self.object = v as Any
+            } else {
+                self.object = NSNull()
+            }
+        }
+    }
+}
+
+// MARK: - Bool
+
+extension JSON { // : Swift.Bool
+
+    //Optional bool
+    public var bool: Bool? {
+        get {
+            switch self.type {
+            case .bool:
+                return self.rawBool
+            default:
+                return nil
+            }
+        }
+        set {
+            if let newValue = newValue {
+                self.object = newValue as Bool
+            } else {
+                self.object = NSNull()
+            }
+        }
+    }
+
+    //Non-optional bool
+    public var boolValue: Bool {
+        get {
+            switch self.type {
+            case .bool:
+                return self.rawBool
+            case .number:
+                return self.rawNumber.boolValue
+            case .string:
+                return ["true", "y", "t"].contains() { (truthyString) in
+                    return self.rawString.caseInsensitiveCompare(truthyString) == .orderedSame
+                }
+            default:
+                return false
+            }
+        }
+        set {
+            self.object = newValue
+        }
+    }
+}
+
+// MARK: - String
+
+extension JSON {
+
+    //Optional string
+    public var string: String? {
+        get {
+            switch self.type {
+            case .string:
+                return self.object as? String
+            default:
+                return nil
+            }
+        }
+        set {
+            if let newValue = newValue {
+                self.object = NSString(string:newValue)
+            } else {
+                self.object = NSNull()
+            }
+        }
+    }
+
+    //Non-optional string
+    public var stringValue: String {
+        get {
+            switch self.type {
+            case .string:
+                return self.object as? String ?? ""
+            case .number:
+                return self.rawNumber.stringValue
+            case .bool:
+                return (self.object as? Bool).map { String($0) } ?? ""
+            default:
+                return ""
+            }
+        }
+        set {
+            self.object = NSString(string:newValue)
+        }
+    }
+}
+
+// MARK: - Number
+extension JSON {
+
+    //Optional number
+    public var number: NSNumber? {
+        get {
+            switch self.type {
+            case .number:
+                return self.rawNumber
+            case .bool:
+                return NSNumber(value: self.rawBool ? 1 : 0)
+            default:
+                return nil
+            }
+        }
+        set {
+            self.object = newValue ?? NSNull()
+        }
+    }
+
+    //Non-optional number
+    public var numberValue: NSNumber {
+        get {
+            switch self.type {
+            case .string:
+                let decimal = NSDecimalNumber(string: self.object as? String)
+                if decimal == NSDecimalNumber.notANumber {  // indicates parse error
+                    return NSDecimalNumber.zero
+                }
+                return decimal
+            case .number:
+                return self.object as? NSNumber ?? NSNumber(value: 0)
+            case .bool:
+                return NSNumber(value: self.rawBool ? 1 : 0)
+            default:
+                return NSNumber(value: 0.0)
+            }
+        }
+        set {
+            self.object = newValue
+        }
+    }
+}
+
+//MARK: - Null
+extension JSON {
+
+    public var null: NSNull? {
+        get {
+            switch self.type {
+            case .null:
+                return self.rawNull
+            default:
+                return nil
+            }
+        }
+        set {
+            self.object = NSNull()
+        }
+    }
+    public func exists() -> Bool{
+        if let errorValue = error, errorValue.code == ErrorNotExist ||
+            errorValue.code == ErrorIndexOutOfBounds ||
+            errorValue.code == ErrorWrongType {
+                return false
+        }
+        return true
+    }
+}
+
+//MARK: - URL
+extension JSON {
+
+    //Optional URL
+    public var url: URL? {
+        get {
+            switch self.type {
+            case .string:
+                // Check for existing percent escapes first to prevent double-escaping of % character
+                if let _ = self.rawString.range(of: "%[0-9A-Fa-f]{2}", options: .regularExpression, range: nil, locale: nil) {
+                    return Foundation.URL(string: self.rawString)
+                } else if let encodedString_ = self.rawString.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) {
+                    // We have to use `Foundation.URL` otherwise it conflicts with the variable name.
+                    return Foundation.URL(string: encodedString_)
+                } else {
+                    return nil
+                }
+            default:
+                return nil
+            }
+        }
+        set {
+            self.object = newValue?.absoluteString ?? NSNull()
+        }
+    }
+}
+
+// MARK: - Int, Double, Float, Int8, Int16, Int32, Int64
+
+extension JSON {
+
+    public var double: Double? {
+        get {
+            return self.number?.doubleValue
+        }
+        set {
+            if let newValue = newValue {
+                self.object = NSNumber(value: newValue)
+            } else {
+                self.object = NSNull()
+            }
+        }
+    }
+
+    public var doubleValue: Double {
+        get {
+            return self.numberValue.doubleValue
+        }
+        set {
+            self.object = NSNumber(value: newValue)
+        }
+    }
+
+    public var float: Float? {
+        get {
+            return self.number?.floatValue
+        }
+        set {
+            if let newValue = newValue {
+                self.object = NSNumber(value: newValue)
+            } else {
+                self.object = NSNull()
+            }
+        }
+    }
+
+    public var floatValue: Float {
+        get {
+            return self.numberValue.floatValue
+        }
+        set {
+            self.object = NSNumber(value: newValue)
+        }
+    }
+
+    public var int: Int?
+    {
+        get
+        {
+            return self.number?.intValue
+        }
+        set
+        {
+            if let newValue = newValue
+            {
+                self.object = NSNumber(value: newValue)
+            } else
+            {
+                self.object = NSNull()
+            }
+        }
+    }
+
+    public var intValue: Int {
+        get {
+            return self.numberValue.intValue
+        }
+        set {
+            self.object = NSNumber(value: newValue)
+        }
+    }
+
+    public var uInt: UInt? {
+        get {
+            return self.number?.uintValue
+        }
+        set {
+            if let newValue = newValue {
+                self.object = NSNumber(value: newValue)
+            } else {
+                self.object = NSNull()
+            }
+        }
+    }
+
+    public var uIntValue: UInt {
+        get {
+            return self.numberValue.uintValue
+        }
+        set {
+            self.object = NSNumber(value: newValue)
+        }
+    }
+
+    public var int8: Int8? {
+        get {
+            return self.number?.int8Value
+        }
+        set {
+            if let newValue = newValue {
+                self.object = NSNumber(value: Int(newValue))
+            } else {
+                self.object =  NSNull()
+            }
+        }
+    }
+
+    public var int8Value: Int8 {
+        get {
+            return self.numberValue.int8Value
+        }
+        set {
+            self.object = NSNumber(value: Int(newValue))
+        }
+    }
+
+    public var uInt8: UInt8? {
+        get {
+            return self.number?.uint8Value
+        }
+        set {
+            if let newValue = newValue {
+                self.object = NSNumber(value: newValue)
+            } else {
+                self.object =  NSNull()
+            }
+        }
+    }
+
+    public var uInt8Value: UInt8 {
+        get {
+            return self.numberValue.uint8Value
+        }
+        set {
+            self.object = NSNumber(value: newValue)
+        }
+    }
+
+    public var int16: Int16? {
+        get {
+            return self.number?.int16Value
+        }
+        set {
+            if let newValue = newValue {
+                self.object = NSNumber(value: newValue)
+            } else {
+                self.object =  NSNull()
+            }
+        }
+    }
+
+    public var int16Value: Int16 {
+        get {
+            return self.numberValue.int16Value
+        }
+        set {
+            self.object = NSNumber(value: newValue)
+        }
+    }
+
+    public var uInt16: UInt16? {
+        get {
+            return self.number?.uint16Value
+        }
+        set {
+            if let newValue = newValue {
+                self.object = NSNumber(value: newValue)
+            } else {
+                self.object =  NSNull()
+            }
+        }
+    }
+
+    public var uInt16Value: UInt16 {
+        get {
+            return self.numberValue.uint16Value
+        }
+        set {
+            self.object = NSNumber(value: newValue)
+        }
+    }
+
+    public var int32: Int32? {
+        get {
+            return self.number?.int32Value
+        }
+        set {
+            if let newValue = newValue {
+                self.object = NSNumber(value: newValue)
+            } else {
+                self.object =  NSNull()
+            }
+        }
+    }
+
+    public var int32Value: Int32 {
+        get {
+            return self.numberValue.int32Value
+        }
+        set {
+            self.object = NSNumber(value: newValue)
+        }
+    }
+
+    public var uInt32: UInt32? {
+        get {
+            return self.number?.uint32Value
+        }
+        set {
+            if let newValue = newValue {
+                self.object = NSNumber(value: newValue)
+            } else {
+                self.object =  NSNull()
+            }
+        }
+    }
+
+    public var uInt32Value: UInt32 {
+        get {
+            return self.numberValue.uint32Value
+        }
+        set {
+            self.object = NSNumber(value: newValue)
+        }
+    }
+
+    public var int64: Int64? {
+        get {
+            return self.number?.int64Value
+        }
+        set {
+            if let newValue = newValue {
+                self.object = NSNumber(value: newValue)
+            } else {
+                self.object =  NSNull()
+            }
+        }
+    }
+
+    public var int64Value: Int64 {
+        get {
+            return self.numberValue.int64Value
+        }
+        set {
+            self.object = NSNumber(value: newValue)
+        }
+    }
+
+    public var uInt64: UInt64? {
+        get {
+            return self.number?.uint64Value
+        }
+        set {
+            if let newValue = newValue {
+                self.object = NSNumber(value: newValue)
+            } else {
+                self.object =  NSNull()
+            }
+        }
+    }
+
+    public var uInt64Value: UInt64 {
+        get {
+            return self.numberValue.uint64Value
+        }
+        set {
+            self.object = NSNumber(value: newValue)
+        }
+    }
+}
+
+//MARK: - Comparable
+extension JSON : Swift.Comparable {}
+
+public func ==(lhs: JSON, rhs: JSON) -> Bool {
+
+    switch (lhs.type, rhs.type) {
+    case (.number, .number):
+        return lhs.rawNumber == rhs.rawNumber
+    case (.string, .string):
+        return lhs.rawString == rhs.rawString
+    case (.bool, .bool):
+        return lhs.rawBool == rhs.rawBool
+    case (.array, .array):
+        return lhs.rawArray as NSArray == rhs.rawArray as NSArray
+    case (.dictionary, .dictionary):
+        return lhs.rawDictionary as NSDictionary == rhs.rawDictionary as NSDictionary
+    case (.null, .null):
+        return true
+    default:
+        return false
+    }
+}
+
+public func <=(lhs: JSON, rhs: JSON) -> Bool {
+
+    switch (lhs.type, rhs.type) {
+    case (.number, .number):
+        return lhs.rawNumber <= rhs.rawNumber
+    case (.string, .string):
+        return lhs.rawString <= rhs.rawString
+    case (.bool, .bool):
+        return lhs.rawBool == rhs.rawBool
+    case (.array, .array):
+        return lhs.rawArray as NSArray == rhs.rawArray as NSArray
+    case (.dictionary, .dictionary):
+        return lhs.rawDictionary as NSDictionary == rhs.rawDictionary as NSDictionary
+    case (.null, .null):
+        return true
+    default:
+        return false
+    }
+}
+
+public func >=(lhs: JSON, rhs: JSON) -> Bool {
+
+    switch (lhs.type, rhs.type) {
+    case (.number, .number):
+        return lhs.rawNumber >= rhs.rawNumber
+    case (.string, .string):
+        return lhs.rawString >= rhs.rawString
+    case (.bool, .bool):
+        return lhs.rawBool == rhs.rawBool
+    case (.array, .array):
+        return lhs.rawArray as NSArray == rhs.rawArray as NSArray
+    case (.dictionary, .dictionary):
+        return lhs.rawDictionary as NSDictionary == rhs.rawDictionary as NSDictionary
+    case (.null, .null):
+        return true
+    default:
+        return false
+    }
+}
+
+public func >(lhs: JSON, rhs: JSON) -> Bool {
+
+    switch (lhs.type, rhs.type) {
+    case (.number, .number):
+        return lhs.rawNumber > rhs.rawNumber
+    case (.string, .string):
+        return lhs.rawString > rhs.rawString
+    default:
+        return false
+    }
+}
+
+public func <(lhs: JSON, rhs: JSON) -> Bool {
+
+    switch (lhs.type, rhs.type) {
+    case (.number, .number):
+        return lhs.rawNumber < rhs.rawNumber
+    case (.string, .string):
+        return lhs.rawString < rhs.rawString
+    default:
+        return false
+    }
+}
+
+private let trueNumber = NSNumber(value: true)
+private let falseNumber = NSNumber(value: false)
+private let trueObjCType = String(cString: trueNumber.objCType)
+private let falseObjCType = String(cString: falseNumber.objCType)
+
+// MARK: - NSNumber: Comparable
+
+extension NSNumber {
+    var isBool:Bool {
+        get {
+            let objCType = String(cString: self.objCType)
+            if (self.compare(trueNumber) == .orderedSame && objCType == trueObjCType) || (self.compare(falseNumber) == .orderedSame && objCType == falseObjCType){
+                return true
+            } else {
+                return false
+            }
+        }
+    }
+}
+
+func ==(lhs: NSNumber, rhs: NSNumber) -> Bool {
+    switch (lhs.isBool, rhs.isBool) {
+    case (false, true):
+        return false
+    case (true, false):
+        return false
+    default:
+        return lhs.compare(rhs) == .orderedSame
+    }
+}
+
+func !=(lhs: NSNumber, rhs: NSNumber) -> Bool {
+    return !(lhs == rhs)
+}
+
+func <(lhs: NSNumber, rhs: NSNumber) -> Bool {
+
+    switch (lhs.isBool, rhs.isBool) {
+    case (false, true):
+        return false
+    case (true, false):
+        return false
+    default:
+        return lhs.compare(rhs) == .orderedAscending
+    }
+}
+
+func >(lhs: NSNumber, rhs: NSNumber) -> Bool {
+
+    switch (lhs.isBool, rhs.isBool) {
+    case (false, true):
+        return false
+    case (true, false):
+        return false
+    default:
+        return lhs.compare(rhs) == ComparisonResult.orderedDescending
+    }
+}
+
+func <=(lhs: NSNumber, rhs: NSNumber) -> Bool {
+
+    switch (lhs.isBool, rhs.isBool) {
+    case (false, true):
+        return false
+    case (true, false):
+        return false
+    default:
+        return lhs.compare(rhs) != .orderedDescending
+    }
+}
+
+func >=(lhs: NSNumber, rhs: NSNumber) -> Bool {
+
+    switch (lhs.isBool, rhs.isBool) {
+    case (false, true):
+        return false
+    case (true, false):
+        return false
+    default:
+        return lhs.compare(rhs) != .orderedAscending
+    }
+}
+
+public enum writtingOptionsKeys {
+	case jsonSerialization
+	case castNilToNSNull
+	case maxObjextDepth
+	case encoding
+}
diff --git a/whiskbot-demo-app/Pods/Target Support Files/JSQMessagesViewController/Info.plist b/whiskbot-demo-app/Pods/Target Support Files/JSQMessagesViewController/Info.plist
new file mode 100644
index 0000000..5e150f8
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/JSQMessagesViewController/Info.plist
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+  <key>CFBundleDevelopmentRegion</key>
+  <string>en</string>
+  <key>CFBundleExecutable</key>
+  <string>${EXECUTABLE_NAME}</string>
+  <key>CFBundleIdentifier</key>
+  <string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
+  <key>CFBundleInfoDictionaryVersion</key>
+  <string>6.0</string>
+  <key>CFBundleName</key>
+  <string>${PRODUCT_NAME}</string>
+  <key>CFBundlePackageType</key>
+  <string>FMWK</string>
+  <key>CFBundleShortVersionString</key>
+  <string>7.3.4</string>
+  <key>CFBundleSignature</key>
+  <string>????</string>
+  <key>CFBundleVersion</key>
+  <string>${CURRENT_PROJECT_VERSION}</string>
+  <key>NSPrincipalClass</key>
+  <string></string>
+</dict>
+</plist>
diff --git a/whiskbot-demo-app/Pods/Target Support Files/JSQMessagesViewController/JSQMessagesViewController-dummy.m b/whiskbot-demo-app/Pods/Target Support Files/JSQMessagesViewController/JSQMessagesViewController-dummy.m
new file mode 100644
index 0000000..363ff34
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/JSQMessagesViewController/JSQMessagesViewController-dummy.m
@@ -0,0 +1,5 @@
+#import <Foundation/Foundation.h>
+@interface PodsDummy_JSQMessagesViewController : NSObject
+@end
+@implementation PodsDummy_JSQMessagesViewController
+@end
diff --git a/whiskbot-demo-app/Pods/Target Support Files/JSQMessagesViewController/JSQMessagesViewController-prefix.pch b/whiskbot-demo-app/Pods/Target Support Files/JSQMessagesViewController/JSQMessagesViewController-prefix.pch
new file mode 100644
index 0000000..aa992a4
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/JSQMessagesViewController/JSQMessagesViewController-prefix.pch
@@ -0,0 +1,4 @@
+#ifdef __OBJC__
+#import <UIKit/UIKit.h>
+#endif
+
diff --git a/whiskbot-demo-app/Pods/Target Support Files/JSQMessagesViewController/JSQMessagesViewController-umbrella.h b/whiskbot-demo-app/Pods/Target Support Files/JSQMessagesViewController/JSQMessagesViewController-umbrella.h
new file mode 100644
index 0000000..bd4f28c
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/JSQMessagesViewController/JSQMessagesViewController-umbrella.h
@@ -0,0 +1,55 @@
+#ifdef __OBJC__
+#import <UIKit/UIKit.h>
+#endif
+
+#import "JSQSystemSoundPlayer+JSQMessages.h"
+#import "NSBundle+JSQMessages.h"
+#import "NSString+JSQMessages.h"
+#import "UIColor+JSQMessages.h"
+#import "UIDevice+JSQMessages.h"
+#import "UIImage+JSQMessages.h"
+#import "UIView+JSQMessages.h"
+#import "JSQMessagesKeyboardController.h"
+#import "JSQMessagesViewController.h"
+#import "JSQMessagesAvatarImageFactory.h"
+#import "JSQMessagesBubbleImageFactory.h"
+#import "JSQMessagesMediaViewBubbleImageMasker.h"
+#import "JSQMessagesTimestampFormatter.h"
+#import "JSQMessagesToolbarButtonFactory.h"
+#import "JSQMessages.h"
+#import "JSQAudioMediaViewAttributes.h"
+#import "JSQMessagesBubbleSizeCalculating.h"
+#import "JSQMessagesBubblesSizeCalculator.h"
+#import "JSQMessagesCollectionViewFlowLayout.h"
+#import "JSQMessagesCollectionViewFlowLayoutInvalidationContext.h"
+#import "JSQMessagesCollectionViewLayoutAttributes.h"
+#import "JSQAudioMediaItem.h"
+#import "JSQLocationMediaItem.h"
+#import "JSQMediaItem.h"
+#import "JSQMessage.h"
+#import "JSQMessageAvatarImageDataSource.h"
+#import "JSQMessageBubbleImageDataSource.h"
+#import "JSQMessageData.h"
+#import "JSQMessageMediaData.h"
+#import "JSQMessagesAvatarImage.h"
+#import "JSQMessagesBubbleImage.h"
+#import "JSQMessagesCollectionViewDataSource.h"
+#import "JSQMessagesCollectionViewDelegateFlowLayout.h"
+#import "JSQPhotoMediaItem.h"
+#import "JSQVideoMediaItem.h"
+#import "JSQMessagesCellTextView.h"
+#import "JSQMessagesCollectionView.h"
+#import "JSQMessagesCollectionViewCell.h"
+#import "JSQMessagesCollectionViewCellIncoming.h"
+#import "JSQMessagesCollectionViewCellOutgoing.h"
+#import "JSQMessagesComposerTextView.h"
+#import "JSQMessagesInputToolbar.h"
+#import "JSQMessagesLabel.h"
+#import "JSQMessagesLoadEarlierHeaderView.h"
+#import "JSQMessagesMediaPlaceholderView.h"
+#import "JSQMessagesToolbarContentView.h"
+#import "JSQMessagesTypingIndicatorFooterView.h"
+
+FOUNDATION_EXPORT double JSQMessagesViewControllerVersionNumber;
+FOUNDATION_EXPORT const unsigned char JSQMessagesViewControllerVersionString[];
+
diff --git a/whiskbot-demo-app/Pods/Target Support Files/JSQMessagesViewController/JSQMessagesViewController.modulemap b/whiskbot-demo-app/Pods/Target Support Files/JSQMessagesViewController/JSQMessagesViewController.modulemap
new file mode 100644
index 0000000..4b4a90f
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/JSQMessagesViewController/JSQMessagesViewController.modulemap
@@ -0,0 +1,6 @@
+framework module JSQMessagesViewController {
+  umbrella header "JSQMessagesViewController-umbrella.h"
+
+  export *
+  module * { export * }
+}
diff --git a/whiskbot-demo-app/Pods/Target Support Files/JSQMessagesViewController/JSQMessagesViewController.xcconfig b/whiskbot-demo-app/Pods/Target Support Files/JSQMessagesViewController/JSQMessagesViewController.xcconfig
new file mode 100644
index 0000000..1d10cd9
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/JSQMessagesViewController/JSQMessagesViewController.xcconfig
@@ -0,0 +1,10 @@
+CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/JSQMessagesViewController
+FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/JSQSystemSoundPlayer"
+GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
+HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public"
+OTHER_LDFLAGS = -framework "AVFoundation" -framework "CoreGraphics" -framework "CoreLocation" -framework "MapKit" -framework "QuartzCore"
+PODS_BUILD_DIR = $BUILD_DIR
+PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
+PODS_ROOT = ${SRCROOT}
+PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
+SKIP_INSTALL = YES
diff --git a/whiskbot-demo-app/Pods/Target Support Files/JSQSystemSoundPlayer/Info.plist b/whiskbot-demo-app/Pods/Target Support Files/JSQSystemSoundPlayer/Info.plist
new file mode 100644
index 0000000..bdac57c
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/JSQSystemSoundPlayer/Info.plist
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+  <key>CFBundleDevelopmentRegion</key>
+  <string>en</string>
+  <key>CFBundleExecutable</key>
+  <string>${EXECUTABLE_NAME}</string>
+  <key>CFBundleIdentifier</key>
+  <string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
+  <key>CFBundleInfoDictionaryVersion</key>
+  <string>6.0</string>
+  <key>CFBundleName</key>
+  <string>${PRODUCT_NAME}</string>
+  <key>CFBundlePackageType</key>
+  <string>FMWK</string>
+  <key>CFBundleShortVersionString</key>
+  <string>2.0.1</string>
+  <key>CFBundleSignature</key>
+  <string>????</string>
+  <key>CFBundleVersion</key>
+  <string>${CURRENT_PROJECT_VERSION}</string>
+  <key>NSPrincipalClass</key>
+  <string></string>
+</dict>
+</plist>
diff --git a/whiskbot-demo-app/Pods/Target Support Files/JSQSystemSoundPlayer/JSQSystemSoundPlayer-dummy.m b/whiskbot-demo-app/Pods/Target Support Files/JSQSystemSoundPlayer/JSQSystemSoundPlayer-dummy.m
new file mode 100644
index 0000000..f1343c7
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/JSQSystemSoundPlayer/JSQSystemSoundPlayer-dummy.m
@@ -0,0 +1,5 @@
+#import <Foundation/Foundation.h>
+@interface PodsDummy_JSQSystemSoundPlayer : NSObject
+@end
+@implementation PodsDummy_JSQSystemSoundPlayer
+@end
diff --git a/whiskbot-demo-app/Pods/Target Support Files/JSQSystemSoundPlayer/JSQSystemSoundPlayer-prefix.pch b/whiskbot-demo-app/Pods/Target Support Files/JSQSystemSoundPlayer/JSQSystemSoundPlayer-prefix.pch
new file mode 100644
index 0000000..aa992a4
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/JSQSystemSoundPlayer/JSQSystemSoundPlayer-prefix.pch
@@ -0,0 +1,4 @@
+#ifdef __OBJC__
+#import <UIKit/UIKit.h>
+#endif
+
diff --git a/whiskbot-demo-app/Pods/Target Support Files/JSQSystemSoundPlayer/JSQSystemSoundPlayer-umbrella.h b/whiskbot-demo-app/Pods/Target Support Files/JSQSystemSoundPlayer/JSQSystemSoundPlayer-umbrella.h
new file mode 100644
index 0000000..359a93f
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/JSQSystemSoundPlayer/JSQSystemSoundPlayer-umbrella.h
@@ -0,0 +1,9 @@
+#ifdef __OBJC__
+#import <UIKit/UIKit.h>
+#endif
+
+#import "JSQSystemSoundPlayer.h"
+
+FOUNDATION_EXPORT double JSQSystemSoundPlayerVersionNumber;
+FOUNDATION_EXPORT const unsigned char JSQSystemSoundPlayerVersionString[];
+
diff --git a/whiskbot-demo-app/Pods/Target Support Files/JSQSystemSoundPlayer/JSQSystemSoundPlayer.modulemap b/whiskbot-demo-app/Pods/Target Support Files/JSQSystemSoundPlayer/JSQSystemSoundPlayer.modulemap
new file mode 100644
index 0000000..2bc2cc9
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/JSQSystemSoundPlayer/JSQSystemSoundPlayer.modulemap
@@ -0,0 +1,6 @@
+framework module JSQSystemSoundPlayer {
+  umbrella header "JSQSystemSoundPlayer-umbrella.h"
+
+  export *
+  module * { export * }
+}
diff --git a/whiskbot-demo-app/Pods/Target Support Files/JSQSystemSoundPlayer/JSQSystemSoundPlayer.xcconfig b/whiskbot-demo-app/Pods/Target Support Files/JSQSystemSoundPlayer/JSQSystemSoundPlayer.xcconfig
new file mode 100644
index 0000000..13465b0
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/JSQSystemSoundPlayer/JSQSystemSoundPlayer.xcconfig
@@ -0,0 +1,9 @@
+CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/JSQSystemSoundPlayer
+GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
+HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public"
+OTHER_LDFLAGS = -framework "AudioToolbox" -framework "Foundation" -framework "UIKit"
+PODS_BUILD_DIR = $BUILD_DIR
+PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
+PODS_ROOT = ${SRCROOT}
+PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
+SKIP_INSTALL = YES
diff --git a/whiskbot-demo-app/Pods/Target Support Files/OpenWhisk/Info.plist b/whiskbot-demo-app/Pods/Target Support Files/OpenWhisk/Info.plist
new file mode 100644
index 0000000..3f68a24
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/OpenWhisk/Info.plist
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+  <key>CFBundleDevelopmentRegion</key>
+  <string>en</string>
+  <key>CFBundleExecutable</key>
+  <string>${EXECUTABLE_NAME}</string>
+  <key>CFBundleIdentifier</key>
+  <string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
+  <key>CFBundleInfoDictionaryVersion</key>
+  <string>6.0</string>
+  <key>CFBundleName</key>
+  <string>${PRODUCT_NAME}</string>
+  <key>CFBundlePackageType</key>
+  <string>FMWK</string>
+  <key>CFBundleShortVersionString</key>
+  <string>0.2.2</string>
+  <key>CFBundleSignature</key>
+  <string>????</string>
+  <key>CFBundleVersion</key>
+  <string>${CURRENT_PROJECT_VERSION}</string>
+  <key>NSPrincipalClass</key>
+  <string></string>
+</dict>
+</plist>
diff --git a/whiskbot-demo-app/Pods/Target Support Files/OpenWhisk/OpenWhisk-dummy.m b/whiskbot-demo-app/Pods/Target Support Files/OpenWhisk/OpenWhisk-dummy.m
new file mode 100644
index 0000000..b39a81b
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/OpenWhisk/OpenWhisk-dummy.m
@@ -0,0 +1,5 @@
+#import <Foundation/Foundation.h>
+@interface PodsDummy_OpenWhisk : NSObject
+@end
+@implementation PodsDummy_OpenWhisk
+@end
diff --git a/whiskbot-demo-app/Pods/Target Support Files/OpenWhisk/OpenWhisk-prefix.pch b/whiskbot-demo-app/Pods/Target Support Files/OpenWhisk/OpenWhisk-prefix.pch
new file mode 100644
index 0000000..aa992a4
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/OpenWhisk/OpenWhisk-prefix.pch
@@ -0,0 +1,4 @@
+#ifdef __OBJC__
+#import <UIKit/UIKit.h>
+#endif
+
diff --git a/whiskbot-demo-app/Pods/Target Support Files/OpenWhisk/OpenWhisk-umbrella.h b/whiskbot-demo-app/Pods/Target Support Files/OpenWhisk/OpenWhisk-umbrella.h
new file mode 100644
index 0000000..c11f781
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/OpenWhisk/OpenWhisk-umbrella.h
@@ -0,0 +1,9 @@
+#ifdef __OBJC__
+#import <UIKit/UIKit.h>
+#endif
+
+#import "OpenWhisk.h"
+
+FOUNDATION_EXPORT double OpenWhiskVersionNumber;
+FOUNDATION_EXPORT const unsigned char OpenWhiskVersionString[];
+
diff --git a/whiskbot-demo-app/Pods/Target Support Files/OpenWhisk/OpenWhisk.modulemap b/whiskbot-demo-app/Pods/Target Support Files/OpenWhisk/OpenWhisk.modulemap
new file mode 100644
index 0000000..18131e1
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/OpenWhisk/OpenWhisk.modulemap
@@ -0,0 +1,6 @@
+framework module OpenWhisk {
+  umbrella header "OpenWhisk-umbrella.h"
+
+  export *
+  module * { export * }
+}
diff --git a/whiskbot-demo-app/Pods/Target Support Files/OpenWhisk/OpenWhisk.xcconfig b/whiskbot-demo-app/Pods/Target Support Files/OpenWhisk/OpenWhisk.xcconfig
new file mode 100644
index 0000000..994f8ef
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/OpenWhisk/OpenWhisk.xcconfig
@@ -0,0 +1,10 @@
+CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/OpenWhisk
+GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
+HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public"
+OTHER_LDFLAGS = -framework "Foundation" -framework "WatchConnectivity"
+OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
+PODS_BUILD_DIR = $BUILD_DIR
+PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
+PODS_ROOT = ${SRCROOT}
+PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
+SKIP_INSTALL = YES
diff --git a/whiskbot-demo-app/Pods/Target Support Files/OpenWhisk/ResourceBundle-OpenWhiskResources-Info.plist b/whiskbot-demo-app/Pods/Target Support Files/OpenWhisk/ResourceBundle-OpenWhiskResources-Info.plist
new file mode 100644
index 0000000..cc0a0d6
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/OpenWhisk/ResourceBundle-OpenWhiskResources-Info.plist
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+  <key>CFBundleDevelopmentRegion</key>
+  <string>en</string>
+  <key>CFBundleIdentifier</key>
+  <string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
+  <key>CFBundleInfoDictionaryVersion</key>
+  <string>6.0</string>
+  <key>CFBundleName</key>
+  <string>${PRODUCT_NAME}</string>
+  <key>CFBundlePackageType</key>
+  <string>BNDL</string>
+  <key>CFBundleShortVersionString</key>
+  <string>0.2.2</string>
+  <key>CFBundleSignature</key>
+  <string>????</string>
+  <key>CFBundleVersion</key>
+  <string>1</string>
+  <key>NSPrincipalClass</key>
+  <string></string>
+</dict>
+</plist>
diff --git a/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBot/Info.plist b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBot/Info.plist
new file mode 100644
index 0000000..2243fe6
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBot/Info.plist
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+  <key>CFBundleDevelopmentRegion</key>
+  <string>en</string>
+  <key>CFBundleExecutable</key>
+  <string>${EXECUTABLE_NAME}</string>
+  <key>CFBundleIdentifier</key>
+  <string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
+  <key>CFBundleInfoDictionaryVersion</key>
+  <string>6.0</string>
+  <key>CFBundleName</key>
+  <string>${PRODUCT_NAME}</string>
+  <key>CFBundlePackageType</key>
+  <string>FMWK</string>
+  <key>CFBundleShortVersionString</key>
+  <string>1.0.0</string>
+  <key>CFBundleSignature</key>
+  <string>????</string>
+  <key>CFBundleVersion</key>
+  <string>${CURRENT_PROJECT_VERSION}</string>
+  <key>NSPrincipalClass</key>
+  <string></string>
+</dict>
+</plist>
diff --git a/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBot/Pods-WhiskBot-acknowledgements.markdown b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBot/Pods-WhiskBot-acknowledgements.markdown
new file mode 100644
index 0000000..f704ad5
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBot/Pods-WhiskBot-acknowledgements.markdown
@@ -0,0 +1,94 @@
+# Acknowledgements
+This application makes use of the following third party libraries:
+
+## JSQMessagesViewController
+
+
+MIT License
+Copyright (c) 2013-present Jesse Squires
+
+http://www.jessesquires.com
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
+following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
+LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+## JSQSystemSoundPlayer
+
+
+MIT License
+Copyright (c) 2013 Jesse Squires
+
+http://www.hexedbits.com
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
+following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
+LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+## OpenWhisk
+
+
+Copyright 2015-2016 IBM Corporation
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+
+## SwiftyJSON
+
+The MIT License (MIT)
+
+Copyright (c) 2016 Ruoyu Fu
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+Generated by CocoaPods - https://cocoapods.org
diff --git a/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBot/Pods-WhiskBot-acknowledgements.plist b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBot/Pods-WhiskBot-acknowledgements.plist
new file mode 100644
index 0000000..4cccc77
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBot/Pods-WhiskBot-acknowledgements.plist
@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>PreferenceSpecifiers</key>
+	<array>
+		<dict>
+			<key>FooterText</key>
+			<string>This application makes use of the following third party libraries:</string>
+			<key>Title</key>
+			<string>Acknowledgements</string>
+			<key>Type</key>
+			<string>PSGroupSpecifier</string>
+		</dict>
+		<dict>
+			<key>FooterText</key>
+			<string>
+MIT License
+Copyright (c) 2013-present Jesse Squires
+
+http://www.jessesquires.com
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
+following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
+LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+</string>
+			<key>License</key>
+			<string>MIT</string>
+			<key>Title</key>
+			<string>JSQMessagesViewController</string>
+			<key>Type</key>
+			<string>PSGroupSpecifier</string>
+		</dict>
+		<dict>
+			<key>FooterText</key>
+			<string>
+MIT License
+Copyright (c) 2013 Jesse Squires
+
+http://www.hexedbits.com
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
+following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
+LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+</string>
+			<key>License</key>
+			<string>MIT</string>
+			<key>Title</key>
+			<string>JSQSystemSoundPlayer</string>
+			<key>Type</key>
+			<string>PSGroupSpecifier</string>
+		</dict>
+		<dict>
+			<key>FooterText</key>
+			<string>
+Copyright 2015-2016 IBM Corporation
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+</string>
+			<key>License</key>
+			<string>Apache License, Version 2.0</string>
+			<key>Title</key>
+			<string>OpenWhisk</string>
+			<key>Type</key>
+			<string>PSGroupSpecifier</string>
+		</dict>
+		<dict>
+			<key>FooterText</key>
+			<string>The MIT License (MIT)
+
+Copyright (c) 2016 Ruoyu Fu
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+</string>
+			<key>License</key>
+			<string>MIT</string>
+			<key>Title</key>
+			<string>SwiftyJSON</string>
+			<key>Type</key>
+			<string>PSGroupSpecifier</string>
+		</dict>
+		<dict>
+			<key>FooterText</key>
+			<string>Generated by CocoaPods - https://cocoapods.org</string>
+			<key>Title</key>
+			<string></string>
+			<key>Type</key>
+			<string>PSGroupSpecifier</string>
+		</dict>
+	</array>
+	<key>StringsTable</key>
+	<string>Acknowledgements</string>
+	<key>Title</key>
+	<string>Acknowledgements</string>
+</dict>
+</plist>
diff --git a/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBot/Pods-WhiskBot-dummy.m b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBot/Pods-WhiskBot-dummy.m
new file mode 100644
index 0000000..a0e1aaf
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBot/Pods-WhiskBot-dummy.m
@@ -0,0 +1,5 @@
+#import <Foundation/Foundation.h>
+@interface PodsDummy_Pods_WhiskBot : NSObject
+@end
+@implementation PodsDummy_Pods_WhiskBot
+@end
diff --git a/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBot/Pods-WhiskBot-frameworks.sh b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBot/Pods-WhiskBot-frameworks.sh
new file mode 100755
index 0000000..6defb06
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBot/Pods-WhiskBot-frameworks.sh
@@ -0,0 +1,97 @@
+#!/bin/sh
+set -e
+
+echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
+mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
+
+SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
+
+install_framework()
+{
+  if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
+    local source="${BUILT_PRODUCTS_DIR}/$1"
+  elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
+    local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
+  elif [ -r "$1" ]; then
+    local source="$1"
+  fi
+
+  local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
+
+  if [ -L "${source}" ]; then
+      echo "Symlinked..."
+      source="$(readlink "${source}")"
+  fi
+
+  # use filter instead of exclude so missing patterns dont' throw errors
+  echo "rsync -av --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
+  rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
+
+  local basename
+  basename="$(basename -s .framework "$1")"
+  binary="${destination}/${basename}.framework/${basename}"
+  if ! [ -r "$binary" ]; then
+    binary="${destination}/${basename}"
+  fi
+
+  # Strip invalid architectures so "fat" simulator / device frameworks work on device
+  if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
+    strip_invalid_archs "$binary"
+  fi
+
+  # Resign the code if required by the build settings to avoid unstable apps
+  code_sign_if_enabled "${destination}/$(basename "$1")"
+
+  # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
+  if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
+    local swift_runtime_libs
+    swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u  && exit ${PIPESTATUS[0]})
+    for lib in $swift_runtime_libs; do
+      echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
+      rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
+      code_sign_if_enabled "${destination}/${lib}"
+    done
+  fi
+}
+
+# Signs a framework with the provided identity
+code_sign_if_enabled() {
+  if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
+    # Use the current code_sign_identitiy
+    echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
+    echo "/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements \"$1\""
+    /usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements "$1"
+  fi
+}
+
+# Strip invalid architectures
+strip_invalid_archs() {
+  binary="$1"
+  # Get architectures for current file
+  archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)"
+  stripped=""
+  for arch in $archs; do
+    if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then
+      # Strip non-valid architectures in-place
+      lipo -remove "$arch" -output "$binary" "$binary" || exit 1
+      stripped="$stripped $arch"
+    fi
+  done
+  if [[ "$stripped" ]]; then
+    echo "Stripped $binary of architectures:$stripped"
+  fi
+}
+
+
+if [[ "$CONFIGURATION" == "Debug" ]]; then
+  install_framework "$BUILT_PRODUCTS_DIR/JSQMessagesViewController/JSQMessagesViewController.framework"
+  install_framework "$BUILT_PRODUCTS_DIR/JSQSystemSoundPlayer/JSQSystemSoundPlayer.framework"
+  install_framework "$BUILT_PRODUCTS_DIR/OpenWhisk/OpenWhisk.framework"
+  install_framework "$BUILT_PRODUCTS_DIR/SwiftyJSON/SwiftyJSON.framework"
+fi
+if [[ "$CONFIGURATION" == "Release" ]]; then
+  install_framework "$BUILT_PRODUCTS_DIR/JSQMessagesViewController/JSQMessagesViewController.framework"
+  install_framework "$BUILT_PRODUCTS_DIR/JSQSystemSoundPlayer/JSQSystemSoundPlayer.framework"
+  install_framework "$BUILT_PRODUCTS_DIR/OpenWhisk/OpenWhisk.framework"
+  install_framework "$BUILT_PRODUCTS_DIR/SwiftyJSON/SwiftyJSON.framework"
+fi
diff --git a/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBot/Pods-WhiskBot-resources.sh b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBot/Pods-WhiskBot-resources.sh
new file mode 100755
index 0000000..25e9d37
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBot/Pods-WhiskBot-resources.sh
@@ -0,0 +1,96 @@
+#!/bin/sh
+set -e
+
+mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
+
+RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt
+> "$RESOURCES_TO_COPY"
+
+XCASSET_FILES=()
+
+case "${TARGETED_DEVICE_FAMILY}" in
+  1,2)
+    TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone"
+    ;;
+  1)
+    TARGET_DEVICE_ARGS="--target-device iphone"
+    ;;
+  2)
+    TARGET_DEVICE_ARGS="--target-device ipad"
+    ;;
+  *)
+    TARGET_DEVICE_ARGS="--target-device mac"
+    ;;
+esac
+
+install_resource()
+{
+  if [[ "$1" = /* ]] ; then
+    RESOURCE_PATH="$1"
+  else
+    RESOURCE_PATH="${PODS_ROOT}/$1"
+  fi
+  if [[ ! -e "$RESOURCE_PATH" ]] ; then
+    cat << EOM
+error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script.
+EOM
+    exit 1
+  fi
+  case $RESOURCE_PATH in
+    *.storyboard)
+      echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}"
+      ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
+      ;;
+    *.xib)
+      echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}"
+      ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
+      ;;
+    *.framework)
+      echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
+      mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
+      echo "rsync -av $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
+      rsync -av "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
+      ;;
+    *.xcdatamodel)
+      echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\""
+      xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom"
+      ;;
+    *.xcdatamodeld)
+      echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\""
+      xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd"
+      ;;
+    *.xcmappingmodel)
+      echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\""
+      xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm"
+      ;;
+    *.xcassets)
+      ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH"
+      XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE")
+      ;;
+    *)
+      echo "$RESOURCE_PATH"
+      echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY"
+      ;;
+  esac
+}
+
+mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
+rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
+if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then
+  mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
+  rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
+fi
+rm -f "$RESOURCES_TO_COPY"
+
+if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ]
+then
+  # Find all other xcassets (this unfortunately includes those of path pods and other targets).
+  OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d)
+  while read line; do
+    if [[ $line != "${PODS_ROOT}*" ]]; then
+      XCASSET_FILES+=("$line")
+    fi
+  done <<<"$OTHER_XCASSETS"
+
+  printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
+fi
diff --git a/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBot/Pods-WhiskBot-umbrella.h b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBot/Pods-WhiskBot-umbrella.h
new file mode 100644
index 0000000..79253e8
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBot/Pods-WhiskBot-umbrella.h
@@ -0,0 +1,8 @@
+#ifdef __OBJC__
+#import <UIKit/UIKit.h>
+#endif
+
+
+FOUNDATION_EXPORT double Pods_WhiskBotVersionNumber;
+FOUNDATION_EXPORT const unsigned char Pods_WhiskBotVersionString[];
+
diff --git a/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBot/Pods-WhiskBot.debug.xcconfig b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBot/Pods-WhiskBot.debug.xcconfig
new file mode 100644
index 0000000..2c79b77
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBot/Pods-WhiskBot.debug.xcconfig
@@ -0,0 +1,11 @@
+ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
+EMBEDDED_CONTENT_CONTAINS_SWIFT = YES
+FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/JSQMessagesViewController" "$PODS_CONFIGURATION_BUILD_DIR/JSQSystemSoundPlayer" "$PODS_CONFIGURATION_BUILD_DIR/OpenWhisk" "$PODS_CONFIGURATION_BUILD_DIR/SwiftyJSON"
+GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
+LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
+OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/JSQMessagesViewController/JSQMessagesViewController.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/JSQSystemSoundPlayer/JSQSystemSoundPlayer.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/OpenWhisk/OpenWhisk.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/SwiftyJSON/SwiftyJSON.framework/Headers"
+OTHER_LDFLAGS = $(inherited) -framework "JSQMessagesViewController" -framework "JSQSystemSoundPlayer" -framework "OpenWhisk" -framework "SwiftyJSON"
+OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
+PODS_BUILD_DIR = $BUILD_DIR
+PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
+PODS_ROOT = ${SRCROOT}/Pods
diff --git a/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBot/Pods-WhiskBot.modulemap b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBot/Pods-WhiskBot.modulemap
new file mode 100644
index 0000000..61f84b0
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBot/Pods-WhiskBot.modulemap
@@ -0,0 +1,6 @@
+framework module Pods_WhiskBot {
+  umbrella header "Pods-WhiskBot-umbrella.h"
+
+  export *
+  module * { export * }
+}
diff --git a/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBot/Pods-WhiskBot.release.xcconfig b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBot/Pods-WhiskBot.release.xcconfig
new file mode 100644
index 0000000..2c79b77
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBot/Pods-WhiskBot.release.xcconfig
@@ -0,0 +1,11 @@
+ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
+EMBEDDED_CONTENT_CONTAINS_SWIFT = YES
+FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/JSQMessagesViewController" "$PODS_CONFIGURATION_BUILD_DIR/JSQSystemSoundPlayer" "$PODS_CONFIGURATION_BUILD_DIR/OpenWhisk" "$PODS_CONFIGURATION_BUILD_DIR/SwiftyJSON"
+GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
+LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
+OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/JSQMessagesViewController/JSQMessagesViewController.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/JSQSystemSoundPlayer/JSQSystemSoundPlayer.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/OpenWhisk/OpenWhisk.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/SwiftyJSON/SwiftyJSON.framework/Headers"
+OTHER_LDFLAGS = $(inherited) -framework "JSQMessagesViewController" -framework "JSQSystemSoundPlayer" -framework "OpenWhisk" -framework "SwiftyJSON"
+OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
+PODS_BUILD_DIR = $BUILD_DIR
+PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
+PODS_ROOT = ${SRCROOT}/Pods
diff --git a/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotTests/Info.plist b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotTests/Info.plist
new file mode 100644
index 0000000..2243fe6
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotTests/Info.plist
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+  <key>CFBundleDevelopmentRegion</key>
+  <string>en</string>
+  <key>CFBundleExecutable</key>
+  <string>${EXECUTABLE_NAME}</string>
+  <key>CFBundleIdentifier</key>
+  <string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
+  <key>CFBundleInfoDictionaryVersion</key>
+  <string>6.0</string>
+  <key>CFBundleName</key>
+  <string>${PRODUCT_NAME}</string>
+  <key>CFBundlePackageType</key>
+  <string>FMWK</string>
+  <key>CFBundleShortVersionString</key>
+  <string>1.0.0</string>
+  <key>CFBundleSignature</key>
+  <string>????</string>
+  <key>CFBundleVersion</key>
+  <string>${CURRENT_PROJECT_VERSION}</string>
+  <key>NSPrincipalClass</key>
+  <string></string>
+</dict>
+</plist>
diff --git a/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotTests/Pods-WhiskBotTests-acknowledgements.markdown b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotTests/Pods-WhiskBotTests-acknowledgements.markdown
new file mode 100644
index 0000000..102af75
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotTests/Pods-WhiskBotTests-acknowledgements.markdown
@@ -0,0 +1,3 @@
+# Acknowledgements
+This application makes use of the following third party libraries:
+Generated by CocoaPods - https://cocoapods.org
diff --git a/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotTests/Pods-WhiskBotTests-acknowledgements.plist b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotTests/Pods-WhiskBotTests-acknowledgements.plist
new file mode 100644
index 0000000..7acbad1
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotTests/Pods-WhiskBotTests-acknowledgements.plist
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>PreferenceSpecifiers</key>
+	<array>
+		<dict>
+			<key>FooterText</key>
+			<string>This application makes use of the following third party libraries:</string>
+			<key>Title</key>
+			<string>Acknowledgements</string>
+			<key>Type</key>
+			<string>PSGroupSpecifier</string>
+		</dict>
+		<dict>
+			<key>FooterText</key>
+			<string>Generated by CocoaPods - https://cocoapods.org</string>
+			<key>Title</key>
+			<string></string>
+			<key>Type</key>
+			<string>PSGroupSpecifier</string>
+		</dict>
+	</array>
+	<key>StringsTable</key>
+	<string>Acknowledgements</string>
+	<key>Title</key>
+	<string>Acknowledgements</string>
+</dict>
+</plist>
diff --git a/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotTests/Pods-WhiskBotTests-dummy.m b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotTests/Pods-WhiskBotTests-dummy.m
new file mode 100644
index 0000000..2b4971c
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotTests/Pods-WhiskBotTests-dummy.m
@@ -0,0 +1,5 @@
+#import <Foundation/Foundation.h>
+@interface PodsDummy_Pods_WhiskBotTests : NSObject
+@end
+@implementation PodsDummy_Pods_WhiskBotTests
+@end
diff --git a/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotTests/Pods-WhiskBotTests-frameworks.sh b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotTests/Pods-WhiskBotTests-frameworks.sh
new file mode 100755
index 0000000..893c16a
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotTests/Pods-WhiskBotTests-frameworks.sh
@@ -0,0 +1,84 @@
+#!/bin/sh
+set -e
+
+echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
+mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
+
+SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
+
+install_framework()
+{
+  if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
+    local source="${BUILT_PRODUCTS_DIR}/$1"
+  elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
+    local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
+  elif [ -r "$1" ]; then
+    local source="$1"
+  fi
+
+  local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
+
+  if [ -L "${source}" ]; then
+      echo "Symlinked..."
+      source="$(readlink "${source}")"
+  fi
+
+  # use filter instead of exclude so missing patterns dont' throw errors
+  echo "rsync -av --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
+  rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
+
+  local basename
+  basename="$(basename -s .framework "$1")"
+  binary="${destination}/${basename}.framework/${basename}"
+  if ! [ -r "$binary" ]; then
+    binary="${destination}/${basename}"
+  fi
+
+  # Strip invalid architectures so "fat" simulator / device frameworks work on device
+  if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
+    strip_invalid_archs "$binary"
+  fi
+
+  # Resign the code if required by the build settings to avoid unstable apps
+  code_sign_if_enabled "${destination}/$(basename "$1")"
+
+  # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
+  if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
+    local swift_runtime_libs
+    swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u  && exit ${PIPESTATUS[0]})
+    for lib in $swift_runtime_libs; do
+      echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
+      rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
+      code_sign_if_enabled "${destination}/${lib}"
+    done
+  fi
+}
+
+# Signs a framework with the provided identity
+code_sign_if_enabled() {
+  if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
+    # Use the current code_sign_identitiy
+    echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
+    echo "/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements \"$1\""
+    /usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements "$1"
+  fi
+}
+
+# Strip invalid architectures
+strip_invalid_archs() {
+  binary="$1"
+  # Get architectures for current file
+  archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)"
+  stripped=""
+  for arch in $archs; do
+    if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then
+      # Strip non-valid architectures in-place
+      lipo -remove "$arch" -output "$binary" "$binary" || exit 1
+      stripped="$stripped $arch"
+    fi
+  done
+  if [[ "$stripped" ]]; then
+    echo "Stripped $binary of architectures:$stripped"
+  fi
+}
+
diff --git a/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotTests/Pods-WhiskBotTests-resources.sh b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotTests/Pods-WhiskBotTests-resources.sh
new file mode 100755
index 0000000..25e9d37
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotTests/Pods-WhiskBotTests-resources.sh
@@ -0,0 +1,96 @@
+#!/bin/sh
+set -e
+
+mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
+
+RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt
+> "$RESOURCES_TO_COPY"
+
+XCASSET_FILES=()
+
+case "${TARGETED_DEVICE_FAMILY}" in
+  1,2)
+    TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone"
+    ;;
+  1)
+    TARGET_DEVICE_ARGS="--target-device iphone"
+    ;;
+  2)
+    TARGET_DEVICE_ARGS="--target-device ipad"
+    ;;
+  *)
+    TARGET_DEVICE_ARGS="--target-device mac"
+    ;;
+esac
+
+install_resource()
+{
+  if [[ "$1" = /* ]] ; then
+    RESOURCE_PATH="$1"
+  else
+    RESOURCE_PATH="${PODS_ROOT}/$1"
+  fi
+  if [[ ! -e "$RESOURCE_PATH" ]] ; then
+    cat << EOM
+error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script.
+EOM
+    exit 1
+  fi
+  case $RESOURCE_PATH in
+    *.storyboard)
+      echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}"
+      ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
+      ;;
+    *.xib)
+      echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}"
+      ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
+      ;;
+    *.framework)
+      echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
+      mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
+      echo "rsync -av $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
+      rsync -av "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
+      ;;
+    *.xcdatamodel)
+      echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\""
+      xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom"
+      ;;
+    *.xcdatamodeld)
+      echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\""
+      xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd"
+      ;;
+    *.xcmappingmodel)
+      echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\""
+      xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm"
+      ;;
+    *.xcassets)
+      ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH"
+      XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE")
+      ;;
+    *)
+      echo "$RESOURCE_PATH"
+      echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY"
+      ;;
+  esac
+}
+
+mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
+rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
+if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then
+  mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
+  rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
+fi
+rm -f "$RESOURCES_TO_COPY"
+
+if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ]
+then
+  # Find all other xcassets (this unfortunately includes those of path pods and other targets).
+  OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d)
+  while read line; do
+    if [[ $line != "${PODS_ROOT}*" ]]; then
+      XCASSET_FILES+=("$line")
+    fi
+  done <<<"$OTHER_XCASSETS"
+
+  printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
+fi
diff --git a/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotTests/Pods-WhiskBotTests-umbrella.h b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotTests/Pods-WhiskBotTests-umbrella.h
new file mode 100644
index 0000000..f260b8c
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotTests/Pods-WhiskBotTests-umbrella.h
@@ -0,0 +1,8 @@
+#ifdef __OBJC__
+#import <UIKit/UIKit.h>
+#endif
+
+
+FOUNDATION_EXPORT double Pods_WhiskBotTestsVersionNumber;
+FOUNDATION_EXPORT const unsigned char Pods_WhiskBotTestsVersionString[];
+
diff --git a/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotTests/Pods-WhiskBotTests.debug.xcconfig b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotTests/Pods-WhiskBotTests.debug.xcconfig
new file mode 100644
index 0000000..945ad0d
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotTests/Pods-WhiskBotTests.debug.xcconfig
@@ -0,0 +1,8 @@
+ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO
+FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/JSQMessagesViewController" "$PODS_CONFIGURATION_BUILD_DIR/JSQSystemSoundPlayer" "$PODS_CONFIGURATION_BUILD_DIR/OpenWhisk" "$PODS_CONFIGURATION_BUILD_DIR/SwiftyJSON"
+GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
+LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
+OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/JSQMessagesViewController/JSQMessagesViewController.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/JSQSystemSoundPlayer/JSQSystemSoundPlayer.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/OpenWhisk/OpenWhisk.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/SwiftyJSON/SwiftyJSON.framework/Headers"
+PODS_BUILD_DIR = $BUILD_DIR
+PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
+PODS_ROOT = ${SRCROOT}/Pods
diff --git a/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotTests/Pods-WhiskBotTests.modulemap b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotTests/Pods-WhiskBotTests.modulemap
new file mode 100644
index 0000000..cac3082
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotTests/Pods-WhiskBotTests.modulemap
@@ -0,0 +1,6 @@
+framework module Pods_WhiskBotTests {
+  umbrella header "Pods-WhiskBotTests-umbrella.h"
+
+  export *
+  module * { export * }
+}
diff --git a/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotTests/Pods-WhiskBotTests.release.xcconfig b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotTests/Pods-WhiskBotTests.release.xcconfig
new file mode 100644
index 0000000..945ad0d
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotTests/Pods-WhiskBotTests.release.xcconfig
@@ -0,0 +1,8 @@
+ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO
+FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/JSQMessagesViewController" "$PODS_CONFIGURATION_BUILD_DIR/JSQSystemSoundPlayer" "$PODS_CONFIGURATION_BUILD_DIR/OpenWhisk" "$PODS_CONFIGURATION_BUILD_DIR/SwiftyJSON"
+GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
+LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
+OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/JSQMessagesViewController/JSQMessagesViewController.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/JSQSystemSoundPlayer/JSQSystemSoundPlayer.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/OpenWhisk/OpenWhisk.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/SwiftyJSON/SwiftyJSON.framework/Headers"
+PODS_BUILD_DIR = $BUILD_DIR
+PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
+PODS_ROOT = ${SRCROOT}/Pods
diff --git a/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotUITests/Info.plist b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotUITests/Info.plist
new file mode 100644
index 0000000..2243fe6
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotUITests/Info.plist
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+  <key>CFBundleDevelopmentRegion</key>
+  <string>en</string>
+  <key>CFBundleExecutable</key>
+  <string>${EXECUTABLE_NAME}</string>
+  <key>CFBundleIdentifier</key>
+  <string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
+  <key>CFBundleInfoDictionaryVersion</key>
+  <string>6.0</string>
+  <key>CFBundleName</key>
+  <string>${PRODUCT_NAME}</string>
+  <key>CFBundlePackageType</key>
+  <string>FMWK</string>
+  <key>CFBundleShortVersionString</key>
+  <string>1.0.0</string>
+  <key>CFBundleSignature</key>
+  <string>????</string>
+  <key>CFBundleVersion</key>
+  <string>${CURRENT_PROJECT_VERSION}</string>
+  <key>NSPrincipalClass</key>
+  <string></string>
+</dict>
+</plist>
diff --git a/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotUITests/Pods-WhiskBotUITests-acknowledgements.markdown b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotUITests/Pods-WhiskBotUITests-acknowledgements.markdown
new file mode 100644
index 0000000..102af75
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotUITests/Pods-WhiskBotUITests-acknowledgements.markdown
@@ -0,0 +1,3 @@
+# Acknowledgements
+This application makes use of the following third party libraries:
+Generated by CocoaPods - https://cocoapods.org
diff --git a/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotUITests/Pods-WhiskBotUITests-acknowledgements.plist b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotUITests/Pods-WhiskBotUITests-acknowledgements.plist
new file mode 100644
index 0000000..7acbad1
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotUITests/Pods-WhiskBotUITests-acknowledgements.plist
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>PreferenceSpecifiers</key>
+	<array>
+		<dict>
+			<key>FooterText</key>
+			<string>This application makes use of the following third party libraries:</string>
+			<key>Title</key>
+			<string>Acknowledgements</string>
+			<key>Type</key>
+			<string>PSGroupSpecifier</string>
+		</dict>
+		<dict>
+			<key>FooterText</key>
+			<string>Generated by CocoaPods - https://cocoapods.org</string>
+			<key>Title</key>
+			<string></string>
+			<key>Type</key>
+			<string>PSGroupSpecifier</string>
+		</dict>
+	</array>
+	<key>StringsTable</key>
+	<string>Acknowledgements</string>
+	<key>Title</key>
+	<string>Acknowledgements</string>
+</dict>
+</plist>
diff --git a/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotUITests/Pods-WhiskBotUITests-dummy.m b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotUITests/Pods-WhiskBotUITests-dummy.m
new file mode 100644
index 0000000..402c8d4
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotUITests/Pods-WhiskBotUITests-dummy.m
@@ -0,0 +1,5 @@
+#import <Foundation/Foundation.h>
+@interface PodsDummy_Pods_WhiskBotUITests : NSObject
+@end
+@implementation PodsDummy_Pods_WhiskBotUITests
+@end
diff --git a/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotUITests/Pods-WhiskBotUITests-frameworks.sh b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotUITests/Pods-WhiskBotUITests-frameworks.sh
new file mode 100755
index 0000000..893c16a
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotUITests/Pods-WhiskBotUITests-frameworks.sh
@@ -0,0 +1,84 @@
+#!/bin/sh
+set -e
+
+echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
+mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
+
+SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
+
+install_framework()
+{
+  if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
+    local source="${BUILT_PRODUCTS_DIR}/$1"
+  elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
+    local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
+  elif [ -r "$1" ]; then
+    local source="$1"
+  fi
+
+  local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
+
+  if [ -L "${source}" ]; then
+      echo "Symlinked..."
+      source="$(readlink "${source}")"
+  fi
+
+  # use filter instead of exclude so missing patterns dont' throw errors
+  echo "rsync -av --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
+  rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
+
+  local basename
+  basename="$(basename -s .framework "$1")"
+  binary="${destination}/${basename}.framework/${basename}"
+  if ! [ -r "$binary" ]; then
+    binary="${destination}/${basename}"
+  fi
+
+  # Strip invalid architectures so "fat" simulator / device frameworks work on device
+  if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
+    strip_invalid_archs "$binary"
+  fi
+
+  # Resign the code if required by the build settings to avoid unstable apps
+  code_sign_if_enabled "${destination}/$(basename "$1")"
+
+  # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
+  if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
+    local swift_runtime_libs
+    swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u  && exit ${PIPESTATUS[0]})
+    for lib in $swift_runtime_libs; do
+      echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
+      rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
+      code_sign_if_enabled "${destination}/${lib}"
+    done
+  fi
+}
+
+# Signs a framework with the provided identity
+code_sign_if_enabled() {
+  if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
+    # Use the current code_sign_identitiy
+    echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
+    echo "/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements \"$1\""
+    /usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements "$1"
+  fi
+}
+
+# Strip invalid architectures
+strip_invalid_archs() {
+  binary="$1"
+  # Get architectures for current file
+  archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)"
+  stripped=""
+  for arch in $archs; do
+    if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then
+      # Strip non-valid architectures in-place
+      lipo -remove "$arch" -output "$binary" "$binary" || exit 1
+      stripped="$stripped $arch"
+    fi
+  done
+  if [[ "$stripped" ]]; then
+    echo "Stripped $binary of architectures:$stripped"
+  fi
+}
+
diff --git a/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotUITests/Pods-WhiskBotUITests-resources.sh b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotUITests/Pods-WhiskBotUITests-resources.sh
new file mode 100755
index 0000000..25e9d37
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotUITests/Pods-WhiskBotUITests-resources.sh
@@ -0,0 +1,96 @@
+#!/bin/sh
+set -e
+
+mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
+
+RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt
+> "$RESOURCES_TO_COPY"
+
+XCASSET_FILES=()
+
+case "${TARGETED_DEVICE_FAMILY}" in
+  1,2)
+    TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone"
+    ;;
+  1)
+    TARGET_DEVICE_ARGS="--target-device iphone"
+    ;;
+  2)
+    TARGET_DEVICE_ARGS="--target-device ipad"
+    ;;
+  *)
+    TARGET_DEVICE_ARGS="--target-device mac"
+    ;;
+esac
+
+install_resource()
+{
+  if [[ "$1" = /* ]] ; then
+    RESOURCE_PATH="$1"
+  else
+    RESOURCE_PATH="${PODS_ROOT}/$1"
+  fi
+  if [[ ! -e "$RESOURCE_PATH" ]] ; then
+    cat << EOM
+error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script.
+EOM
+    exit 1
+  fi
+  case $RESOURCE_PATH in
+    *.storyboard)
+      echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}"
+      ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
+      ;;
+    *.xib)
+      echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}"
+      ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
+      ;;
+    *.framework)
+      echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
+      mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
+      echo "rsync -av $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
+      rsync -av "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
+      ;;
+    *.xcdatamodel)
+      echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\""
+      xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom"
+      ;;
+    *.xcdatamodeld)
+      echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\""
+      xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd"
+      ;;
+    *.xcmappingmodel)
+      echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\""
+      xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm"
+      ;;
+    *.xcassets)
+      ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH"
+      XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE")
+      ;;
+    *)
+      echo "$RESOURCE_PATH"
+      echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY"
+      ;;
+  esac
+}
+
+mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
+rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
+if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then
+  mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
+  rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
+fi
+rm -f "$RESOURCES_TO_COPY"
+
+if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ]
+then
+  # Find all other xcassets (this unfortunately includes those of path pods and other targets).
+  OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d)
+  while read line; do
+    if [[ $line != "${PODS_ROOT}*" ]]; then
+      XCASSET_FILES+=("$line")
+    fi
+  done <<<"$OTHER_XCASSETS"
+
+  printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
+fi
diff --git a/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotUITests/Pods-WhiskBotUITests-umbrella.h b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotUITests/Pods-WhiskBotUITests-umbrella.h
new file mode 100644
index 0000000..4ab1cd3
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotUITests/Pods-WhiskBotUITests-umbrella.h
@@ -0,0 +1,8 @@
+#ifdef __OBJC__
+#import <UIKit/UIKit.h>
+#endif
+
+
+FOUNDATION_EXPORT double Pods_WhiskBotUITestsVersionNumber;
+FOUNDATION_EXPORT const unsigned char Pods_WhiskBotUITestsVersionString[];
+
diff --git a/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotUITests/Pods-WhiskBotUITests.debug.xcconfig b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotUITests/Pods-WhiskBotUITests.debug.xcconfig
new file mode 100644
index 0000000..945ad0d
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotUITests/Pods-WhiskBotUITests.debug.xcconfig
@@ -0,0 +1,8 @@
+ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO
+FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/JSQMessagesViewController" "$PODS_CONFIGURATION_BUILD_DIR/JSQSystemSoundPlayer" "$PODS_CONFIGURATION_BUILD_DIR/OpenWhisk" "$PODS_CONFIGURATION_BUILD_DIR/SwiftyJSON"
+GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
+LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
+OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/JSQMessagesViewController/JSQMessagesViewController.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/JSQSystemSoundPlayer/JSQSystemSoundPlayer.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/OpenWhisk/OpenWhisk.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/SwiftyJSON/SwiftyJSON.framework/Headers"
+PODS_BUILD_DIR = $BUILD_DIR
+PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
+PODS_ROOT = ${SRCROOT}/Pods
diff --git a/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotUITests/Pods-WhiskBotUITests.modulemap b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotUITests/Pods-WhiskBotUITests.modulemap
new file mode 100644
index 0000000..2993f16
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotUITests/Pods-WhiskBotUITests.modulemap
@@ -0,0 +1,6 @@
+framework module Pods_WhiskBotUITests {
+  umbrella header "Pods-WhiskBotUITests-umbrella.h"
+
+  export *
+  module * { export * }
+}
diff --git a/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotUITests/Pods-WhiskBotUITests.release.xcconfig b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotUITests/Pods-WhiskBotUITests.release.xcconfig
new file mode 100644
index 0000000..945ad0d
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/Pods-WhiskBotUITests/Pods-WhiskBotUITests.release.xcconfig
@@ -0,0 +1,8 @@
+ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO
+FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/JSQMessagesViewController" "$PODS_CONFIGURATION_BUILD_DIR/JSQSystemSoundPlayer" "$PODS_CONFIGURATION_BUILD_DIR/OpenWhisk" "$PODS_CONFIGURATION_BUILD_DIR/SwiftyJSON"
+GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
+LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
+OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/JSQMessagesViewController/JSQMessagesViewController.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/JSQSystemSoundPlayer/JSQSystemSoundPlayer.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/OpenWhisk/OpenWhisk.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/SwiftyJSON/SwiftyJSON.framework/Headers"
+PODS_BUILD_DIR = $BUILD_DIR
+PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
+PODS_ROOT = ${SRCROOT}/Pods
diff --git a/whiskbot-demo-app/Pods/Target Support Files/SwiftyJSON/Info.plist b/whiskbot-demo-app/Pods/Target Support Files/SwiftyJSON/Info.plist
new file mode 100644
index 0000000..36f2c7e
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/SwiftyJSON/Info.plist
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+  <key>CFBundleDevelopmentRegion</key>
+  <string>en</string>
+  <key>CFBundleExecutable</key>
+  <string>${EXECUTABLE_NAME}</string>
+  <key>CFBundleIdentifier</key>
+  <string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
+  <key>CFBundleInfoDictionaryVersion</key>
+  <string>6.0</string>
+  <key>CFBundleName</key>
+  <string>${PRODUCT_NAME}</string>
+  <key>CFBundlePackageType</key>
+  <string>FMWK</string>
+  <key>CFBundleShortVersionString</key>
+  <string>3.1.4</string>
+  <key>CFBundleSignature</key>
+  <string>????</string>
+  <key>CFBundleVersion</key>
+  <string>${CURRENT_PROJECT_VERSION}</string>
+  <key>NSPrincipalClass</key>
+  <string></string>
+</dict>
+</plist>
diff --git a/whiskbot-demo-app/Pods/Target Support Files/SwiftyJSON/SwiftyJSON-dummy.m b/whiskbot-demo-app/Pods/Target Support Files/SwiftyJSON/SwiftyJSON-dummy.m
new file mode 100644
index 0000000..3159bec
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/SwiftyJSON/SwiftyJSON-dummy.m
@@ -0,0 +1,5 @@
+#import <Foundation/Foundation.h>
+@interface PodsDummy_SwiftyJSON : NSObject
+@end
+@implementation PodsDummy_SwiftyJSON
+@end
diff --git a/whiskbot-demo-app/Pods/Target Support Files/SwiftyJSON/SwiftyJSON-prefix.pch b/whiskbot-demo-app/Pods/Target Support Files/SwiftyJSON/SwiftyJSON-prefix.pch
new file mode 100644
index 0000000..aa992a4
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/SwiftyJSON/SwiftyJSON-prefix.pch
@@ -0,0 +1,4 @@
+#ifdef __OBJC__
+#import <UIKit/UIKit.h>
+#endif
+
diff --git a/whiskbot-demo-app/Pods/Target Support Files/SwiftyJSON/SwiftyJSON-umbrella.h b/whiskbot-demo-app/Pods/Target Support Files/SwiftyJSON/SwiftyJSON-umbrella.h
new file mode 100644
index 0000000..e0b0f40
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/SwiftyJSON/SwiftyJSON-umbrella.h
@@ -0,0 +1,8 @@
+#ifdef __OBJC__
+#import <UIKit/UIKit.h>
+#endif
+
+
+FOUNDATION_EXPORT double SwiftyJSONVersionNumber;
+FOUNDATION_EXPORT const unsigned char SwiftyJSONVersionString[];
+
diff --git a/whiskbot-demo-app/Pods/Target Support Files/SwiftyJSON/SwiftyJSON.modulemap b/whiskbot-demo-app/Pods/Target Support Files/SwiftyJSON/SwiftyJSON.modulemap
new file mode 100644
index 0000000..6f41751
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/SwiftyJSON/SwiftyJSON.modulemap
@@ -0,0 +1,6 @@
+framework module SwiftyJSON {
+  umbrella header "SwiftyJSON-umbrella.h"
+
+  export *
+  module * { export * }
+}
diff --git a/whiskbot-demo-app/Pods/Target Support Files/SwiftyJSON/SwiftyJSON.xcconfig b/whiskbot-demo-app/Pods/Target Support Files/SwiftyJSON/SwiftyJSON.xcconfig
new file mode 100644
index 0000000..7fbe960
--- /dev/null
+++ b/whiskbot-demo-app/Pods/Target Support Files/SwiftyJSON/SwiftyJSON.xcconfig
@@ -0,0 +1,10 @@
+CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/SwiftyJSON
+GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
+HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public"
+OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
+PODS_BUILD_DIR = $BUILD_DIR
+PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
+PODS_ROOT = ${SRCROOT}
+PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
+SKIP_INSTALL = YES
+SWIFT_VERSION = 3.0
diff --git a/whiskbot-demo-app/README.md b/whiskbot-demo-app/README.md
new file mode 100644
index 0000000..dba5035
--- /dev/null
+++ b/whiskbot-demo-app/README.md
@@ -0,0 +1,66 @@
+#WhiskBot Demo App
+>A Chatbot iOS application that uses OpenWhisk Swift Actions
+
+## Installation
+
+In order to install and setup WhiskBot there are a lot of things to get set up.  
+
+#### Installing OpenWhisk and setting up the actions
+
+The backend of WhiskBot is built with OpenWhisk actions.  There is a main Conversation Action, which is what the app directly interfaces with.  The Conversation Action communicates with the IBM Watson Conversation API in order to get responses to user inputs.  Based on the response and node visited inside the IBM Watson Conversation Service, the conversation Action will invoke other actions (Slack Post, Translation).  In order to set up WhiskBot, the Actions must be uploaded to the Cloud.
+
+`The Actions to be uploaded to OpenWhisk can be found in the folder /WhiskBot/OpenWhiskActions`
+
+To upload the Actions to OpenWhisk, you can either use the Command Line Interface or the Web Browser. [Get set up with OpenWhisk](https://console.ng.bluemix.net/openwhisk/getting-started)
+
+
+#### Setting up the OpenWhisk Swift Client SDK
+
+After all of the Actions are uploaded to IBM Bluemix, they are invoked with the app by using the [OpenWhisk Swift Client SDK](https://github.com/openwhisk/openwhisk-client-swift).  To install the Swift Client SDK, simply run `pod install` from the directory of the demo app.  
+
+Along with the installation, the SDK has two credentials needed.  OpenWhisk has an Access Token and an Access Key that need to be updated inside the `IBMConstants.plist` file found in the main directory.  
+
+
+In order to find the tokens, you can either use the CLI as documented in the [OpenWhisk Swift Client SDK](https://github.com/openwhisk/openwhisk-client-swift) README.
+
+Or you can go to the [OpenWhisk Bluemix website](https://console.ng.bluemix.net/openwhisk/learn/cli) and under Step 2. copy the Authorization Key and Token.  Found in the command `wsk property set --apihost openwhisk.ng.bluemix.net --auth key:token`
+
+
+#### Setting up the Watson Conversation Service
+
+In order to set up the Watson Conversation Service, there are a lot of steps that are very similar to Setting up the Conversation service for the IBM Demo [Cognative Concierge](https://www.ibm.com/blogs/bluemix/2016/12/mobile-chatbot-cognitive-concierge/).  To start, go to the [Watson Conversation Page](https://www.ibm.com/watson/developercloud/conversation.html) and create a conversation instance.  In the creation of the conversation service, the `Service name` and `Credential name` do not matter.  Your conversation service should now appear in the [Watson Services page](https://console.ng.bluemix.net/dashboard/services).  Click on it, and launch it.  
+
+Instead of creating a Workspace, `Import a workspace`.  
+The WhiskBot Workspace is saved as a json in app directory, named `ConversationWorkspace.json`.
+
+After the Workspace is imported, you should be able to test the conversation with the Demo Side bar.
+
+
+To complete the connections between the Conversation Workspace and the actions, there are three keys that are necessary to find.  The `conversation_workspace_id`, `conversation_username`, and `conversation_password`.  All three keys should be input into the `getConstants` function, found in the OpenWhisk ConversationAction.Swift file.
+
+To find the `conversation_workspace_id`, follow the instructions [here](https://www.ibm.com/blogs/bluemix/2016/12/mobile-chatbot-cognitive-concierge/).
+
+To find the `conversation_username` and `conversation_password`, use the following link,  [Obtaining Credentials for Watson Services](https://www.ibm.com/watson/developercloud/doc/getting_started/gs-credentials.shtml)
+
+#### Setting up the Watson Translation Service
+
+To set up the Watson Language Translator Service, it is quite straightforward.  Simply go yo the [Watson Language Translator Website](https://www.ibm.com/watson/developercloud/language-translator.html) and click start free in Bluemix.  Name the service with whatever name you want.  
+
+
+There are two keys that are necessary to use the Watson Language Translator Service, `translation_username` and `translation_password`.  The same link above used to find the Watson Conversation Service Authentication keys will get you to the Translator keys.  [Obtaining Credentials for Watson Services](https://www.ibm.com/watson/developercloud/doc/getting_started/gs-credentials.shtml)
+
+#### Setting up Slack Webhooks
+
+In order to give WhiskBot the ability to post to Slack, your Slack group needs webhook integration.  In order to setup URL Hooks for slack use the following [setup link](https://api.slack.com/custom-integrations).  You can setup webhook urls for different channels.  To add the channels to the OpenWhisk Action, under `getConstants` in `ConversationAction.swift`, there are `slack_channel_url_channelName` keys.  Add your own channelName and URL and modify the Conversation Workspace entity @slack_channels, to allow WhiskBot to pick up different channel names.
+
+
+
+
+
+License
+
+Copyright 2015-2016 IBM Corporation
+
+Licensed under the Apache License, Version 2.0 (the "License").
+
+Unless required by applicable law or agreed to in writing, software distributed under the license is distributed on an "as is" basis, without warranties or conditions of any kind, either express or implied. See the license for the specific language governing permissions and limitations under the license.
diff --git a/whiskbot-demo-app/WhiskBot.xcodeproj/project.pbxproj b/whiskbot-demo-app/WhiskBot.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..0c317f9
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot.xcodeproj/project.pbxproj
@@ -0,0 +1,789 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 46;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		4A803C1101B4B47DEB480A56 /* Pods_WhiskBot.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D2178B8DCD3FA3ED7852EC98 /* Pods_WhiskBot.framework */; };
+		7F0044F61E2FF88E002A4B05 /* ChatBotViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F0044F51E2FF88E002A4B05 /* ChatBotViewController.swift */; };
+		7F08F8831E43B8D400A2C875 /* IBMConstants.plist in Resources */ = {isa = PBXBuildFile; fileRef = 7F08F8821E43B8D400A2C875 /* IBMConstants.plist */; };
+		7F61C9AF1E3009EA00AF3443 /* SpeechRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F61C9AE1E3009EA00AF3443 /* SpeechRecognizer.swift */; };
+		7F6E27BC1E2E73C50002E80B /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F6E27BB1E2E73C50002E80B /* AppDelegate.swift */; };
+		7F6E27BE1E2E73C50002E80B /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F6E27BD1E2E73C50002E80B /* ViewController.swift */; };
+		7F6E27C11E2E73C50002E80B /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7F6E27BF1E2E73C50002E80B /* Main.storyboard */; };
+		7F6E27C31E2E73C50002E80B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7F6E27C21E2E73C50002E80B /* Assets.xcassets */; };
+		7F6E27C61E2E73C50002E80B /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7F6E27C41E2E73C50002E80B /* LaunchScreen.storyboard */; };
+		7F6E27D11E2E73C50002E80B /* WhiskBotTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F6E27D01E2E73C50002E80B /* WhiskBotTests.swift */; };
+		7F6E27DC1E2E73C50002E80B /* WhiskBotUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F6E27DB1E2E73C50002E80B /* WhiskBotUITests.swift */; };
+		7F6E27EA1E2EA9940002E80B /* SplashViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F6E27E91E2EA9940002E80B /* SplashViewController.swift */; };
+		7F6E27EC1E2EA9E40002E80B /* ChatViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F6E27EB1E2EA9E40002E80B /* ChatViewController.swift */; };
+		85DC49E165A8387295BD8BE6 /* Pods_WhiskBotUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53C614C16CF1D65C6B0416B9 /* Pods_WhiskBotUITests.framework */; };
+		B1BA3598E0AD211BFB984469 /* Pods_WhiskBotTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A00927178E4BF4CD67E73AA1 /* Pods_WhiskBotTests.framework */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+		7F6E27CD1E2E73C50002E80B /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 7F6E27B01E2E73C50002E80B /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 7F6E27B71E2E73C50002E80B;
+			remoteInfo = WhiskBot;
+		};
+		7F6E27D81E2E73C50002E80B /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 7F6E27B01E2E73C50002E80B /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 7F6E27B71E2E73C50002E80B;
+			remoteInfo = WhiskBot;
+		};
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+		7F254E4F1E2FCA4F0029B772 /* Embed Frameworks */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 12;
+			dstPath = "";
+			dstSubfolderSpec = 10;
+			files = (
+			);
+			name = "Embed Frameworks";
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+		10D90A899043788B2F68746A /* Pods-WhiskBot.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WhiskBot.release.xcconfig"; path = "Pods/Target Support Files/Pods-WhiskBot/Pods-WhiskBot.release.xcconfig"; sourceTree = "<group>"; };
+		2945C1CEF44B524E77D0E7DA /* Pods-WhiskBotTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WhiskBotTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-WhiskBotTests/Pods-WhiskBotTests.release.xcconfig"; sourceTree = "<group>"; };
+		53C614C16CF1D65C6B0416B9 /* Pods_WhiskBotUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_WhiskBotUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+		607D45ACE515D6A5F008D842 /* Pods-WhiskBot.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WhiskBot.debug.xcconfig"; path = "Pods/Target Support Files/Pods-WhiskBot/Pods-WhiskBot.debug.xcconfig"; sourceTree = "<group>"; };
+		61F3AE277EAA256CEBA7BD62 /* Pods-WhiskBotUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WhiskBotUITests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-WhiskBotUITests/Pods-WhiskBotUITests.debug.xcconfig"; sourceTree = "<group>"; };
+		7F0044F51E2FF88E002A4B05 /* ChatBotViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatBotViewController.swift; sourceTree = "<group>"; };
+		7F08F8821E43B8D400A2C875 /* IBMConstants.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = IBMConstants.plist; sourceTree = "<group>"; };
+		7F0DDB211E3669EF00A7F99E /* ConversationAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ConversationAction.swift; path = OpenWhiskActions/ConversationAction.swift; sourceTree = "<group>"; };
+		7F254E411E2FC9AB0029B772 /* Build */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Build; path = Carthage/Build; sourceTree = "<group>"; };
+		7F254E431E2FC9B70029B772 /* ConversationV1.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ConversationV1.framework; path = Carthage/Build/iOS/ConversationV1.framework; sourceTree = "<group>"; };
+		7F254E551E2FD67C0029B772 /* ConversationV1.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ConversationV1.framework; path = "../../CognitiveConciergeTest/CognitiveConciergeTest/CognitiveConcierge-iOS/Carthage/Build/iOS/ConversationV1.framework"; sourceTree = "<group>"; };
+		7F254E591E2FD79D0029B772 /* RestKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RestKit.framework; path = Carthage/Build/iOS/RestKit.framework; sourceTree = "<group>"; };
+		7F61C9AE1E3009EA00AF3443 /* SpeechRecognizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpeechRecognizer.swift; sourceTree = "<group>"; };
+		7F6E27B81E2E73C50002E80B /* WhiskBot.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WhiskBot.app; sourceTree = BUILT_PRODUCTS_DIR; };
+		7F6E27BB1E2E73C50002E80B /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
+		7F6E27BD1E2E73C50002E80B /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
+		7F6E27C01E2E73C50002E80B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
+		7F6E27C21E2E73C50002E80B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
+		7F6E27C51E2E73C50002E80B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
+		7F6E27C71E2E73C50002E80B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		7F6E27CC1E2E73C50002E80B /* WhiskBotTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = WhiskBotTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+		7F6E27D01E2E73C50002E80B /* WhiskBotTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WhiskBotTests.swift; sourceTree = "<group>"; };
+		7F6E27D21E2E73C50002E80B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		7F6E27D71E2E73C50002E80B /* WhiskBotUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = WhiskBotUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+		7F6E27DB1E2E73C50002E80B /* WhiskBotUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WhiskBotUITests.swift; sourceTree = "<group>"; };
+		7F6E27DD1E2E73C50002E80B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		7F6E27E91E2EA9940002E80B /* SplashViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SplashViewController.swift; sourceTree = "<group>"; };
+		7F6E27EB1E2EA9E40002E80B /* ChatViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatViewController.swift; sourceTree = "<group>"; };
+		7FA3161B1E438AD50018E364 /* PostToSlack.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = PostToSlack.js; path = OpenWhiskActions/PostToSlack.js; sourceTree = "<group>"; };
+		7FA3161C1E438AD50018E364 /* TranslatorAction.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = TranslatorAction.js; path = OpenWhiskActions/TranslatorAction.js; sourceTree = "<group>"; };
+		8F521B1C934121C1C296CCF8 /* Pods-WhiskBotUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WhiskBotUITests.release.xcconfig"; path = "Pods/Target Support Files/Pods-WhiskBotUITests/Pods-WhiskBotUITests.release.xcconfig"; sourceTree = "<group>"; };
+		A00927178E4BF4CD67E73AA1 /* Pods_WhiskBotTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_WhiskBotTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+		D2178B8DCD3FA3ED7852EC98 /* Pods_WhiskBot.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_WhiskBot.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+		ED94B5A49FAF65F34AF6C43D /* Pods-WhiskBotTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WhiskBotTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-WhiskBotTests/Pods-WhiskBotTests.debug.xcconfig"; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		7F6E27B51E2E73C50002E80B /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				4A803C1101B4B47DEB480A56 /* Pods_WhiskBot.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		7F6E27C91E2E73C50002E80B /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				B1BA3598E0AD211BFB984469 /* Pods_WhiskBotTests.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		7F6E27D41E2E73C50002E80B /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				85DC49E165A8387295BD8BE6 /* Pods_WhiskBotUITests.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		205F0F5297F3FBC7E78CFCFD /* Pods */ = {
+			isa = PBXGroup;
+			children = (
+				607D45ACE515D6A5F008D842 /* Pods-WhiskBot.debug.xcconfig */,
+				10D90A899043788B2F68746A /* Pods-WhiskBot.release.xcconfig */,
+				ED94B5A49FAF65F34AF6C43D /* Pods-WhiskBotTests.debug.xcconfig */,
+				2945C1CEF44B524E77D0E7DA /* Pods-WhiskBotTests.release.xcconfig */,
+				61F3AE277EAA256CEBA7BD62 /* Pods-WhiskBotUITests.debug.xcconfig */,
+				8F521B1C934121C1C296CCF8 /* Pods-WhiskBotUITests.release.xcconfig */,
+			);
+			name = Pods;
+			sourceTree = "<group>";
+		};
+		7F254E401E2FC9A90029B772 /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				7F254E591E2FD79D0029B772 /* RestKit.framework */,
+				7F254E551E2FD67C0029B772 /* ConversationV1.framework */,
+				7F254E431E2FC9B70029B772 /* ConversationV1.framework */,
+				7F254E411E2FC9AB0029B772 /* Build */,
+				D2178B8DCD3FA3ED7852EC98 /* Pods_WhiskBot.framework */,
+				A00927178E4BF4CD67E73AA1 /* Pods_WhiskBotTests.framework */,
+				53C614C16CF1D65C6B0416B9 /* Pods_WhiskBotUITests.framework */,
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
+		7F641C931E3145CA0004BEDF /* OpenWhisk Actions */ = {
+			isa = PBXGroup;
+			children = (
+				7FA3161B1E438AD50018E364 /* PostToSlack.js */,
+				7FA3161C1E438AD50018E364 /* TranslatorAction.js */,
+				7F0DDB211E3669EF00A7F99E /* ConversationAction.swift */,
+			);
+			name = "OpenWhisk Actions";
+			sourceTree = "<group>";
+		};
+		7F6E27AF1E2E73C50002E80B = {
+			isa = PBXGroup;
+			children = (
+				7F6E27BA1E2E73C50002E80B /* WhiskBot */,
+				7F6E27CF1E2E73C50002E80B /* WhiskBotTests */,
+				7F6E27DA1E2E73C50002E80B /* WhiskBotUITests */,
+				7F6E27B91E2E73C50002E80B /* Products */,
+				7F254E401E2FC9A90029B772 /* Frameworks */,
+				205F0F5297F3FBC7E78CFCFD /* Pods */,
+			);
+			sourceTree = "<group>";
+		};
+		7F6E27B91E2E73C50002E80B /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				7F6E27B81E2E73C50002E80B /* WhiskBot.app */,
+				7F6E27CC1E2E73C50002E80B /* WhiskBotTests.xctest */,
+				7F6E27D71E2E73C50002E80B /* WhiskBotUITests.xctest */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		7F6E27BA1E2E73C50002E80B /* WhiskBot */ = {
+			isa = PBXGroup;
+			children = (
+				7F6E27BB1E2E73C50002E80B /* AppDelegate.swift */,
+				7F6E27BD1E2E73C50002E80B /* ViewController.swift */,
+				7F6E27E91E2EA9940002E80B /* SplashViewController.swift */,
+				7F6E27BF1E2E73C50002E80B /* Main.storyboard */,
+				7F6E27EB1E2EA9E40002E80B /* ChatViewController.swift */,
+				7F0044F51E2FF88E002A4B05 /* ChatBotViewController.swift */,
+				7F08F8821E43B8D400A2C875 /* IBMConstants.plist */,
+				7F61C9AE1E3009EA00AF3443 /* SpeechRecognizer.swift */,
+				7F641C931E3145CA0004BEDF /* OpenWhisk Actions */,
+				7F6E27C21E2E73C50002E80B /* Assets.xcassets */,
+				7F6E27C41E2E73C50002E80B /* LaunchScreen.storyboard */,
+				7F6E27C71E2E73C50002E80B /* Info.plist */,
+			);
+			path = WhiskBot;
+			sourceTree = "<group>";
+		};
+		7F6E27CF1E2E73C50002E80B /* WhiskBotTests */ = {
+			isa = PBXGroup;
+			children = (
+				7F6E27D01E2E73C50002E80B /* WhiskBotTests.swift */,
+				7F6E27D21E2E73C50002E80B /* Info.plist */,
+			);
+			path = WhiskBotTests;
+			sourceTree = "<group>";
+		};
+		7F6E27DA1E2E73C50002E80B /* WhiskBotUITests */ = {
+			isa = PBXGroup;
+			children = (
+				7F6E27DB1E2E73C50002E80B /* WhiskBotUITests.swift */,
+				7F6E27DD1E2E73C50002E80B /* Info.plist */,
+			);
+			path = WhiskBotUITests;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+		7F6E27B71E2E73C50002E80B /* WhiskBot */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 7F6E27E01E2E73C50002E80B /* Build configuration list for PBXNativeTarget "WhiskBot" */;
+			buildPhases = (
+				6946A633B00338DB9F586232 /* [CP] Check Pods Manifest.lock */,
+				7F6E27B41E2E73C50002E80B /* Sources */,
+				7F6E27B51E2E73C50002E80B /* Frameworks */,
+				7F6E27B61E2E73C50002E80B /* Resources */,
+				7F254E4F1E2FCA4F0029B772 /* Embed Frameworks */,
+				0EE5E942EB14E2A6A3036DA7 /* [CP] Embed Pods Frameworks */,
+				D9E43EAB6653C21A448C2DE0 /* [CP] Copy Pods Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = WhiskBot;
+			productName = WhiskBot;
+			productReference = 7F6E27B81E2E73C50002E80B /* WhiskBot.app */;
+			productType = "com.apple.product-type.application";
+		};
+		7F6E27CB1E2E73C50002E80B /* WhiskBotTests */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 7F6E27E31E2E73C50002E80B /* Build configuration list for PBXNativeTarget "WhiskBotTests" */;
+			buildPhases = (
+				D06E1DE8E4D183B5236BD422 /* [CP] Check Pods Manifest.lock */,
+				7F6E27C81E2E73C50002E80B /* Sources */,
+				7F6E27C91E2E73C50002E80B /* Frameworks */,
+				7F6E27CA1E2E73C50002E80B /* Resources */,
+				66B4729EE868BC56B83B4518 /* [CP] Embed Pods Frameworks */,
+				D8CFB8DF973640C14DDA9C71 /* [CP] Copy Pods Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				7F6E27CE1E2E73C50002E80B /* PBXTargetDependency */,
+			);
+			name = WhiskBotTests;
+			productName = WhiskBotTests;
+			productReference = 7F6E27CC1E2E73C50002E80B /* WhiskBotTests.xctest */;
+			productType = "com.apple.product-type.bundle.unit-test";
+		};
+		7F6E27D61E2E73C50002E80B /* WhiskBotUITests */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 7F6E27E61E2E73C50002E80B /* Build configuration list for PBXNativeTarget "WhiskBotUITests" */;
+			buildPhases = (
+				F741D44D50DB185CDFFB8003 /* [CP] Check Pods Manifest.lock */,
+				7F6E27D31E2E73C50002E80B /* Sources */,
+				7F6E27D41E2E73C50002E80B /* Frameworks */,
+				7F6E27D51E2E73C50002E80B /* Resources */,
+				E0607CEF3BDE1BF4E3876F2C /* [CP] Embed Pods Frameworks */,
+				85628A6BD4F65CA247CADE61 /* [CP] Copy Pods Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				7F6E27D91E2E73C50002E80B /* PBXTargetDependency */,
+			);
+			name = WhiskBotUITests;
+			productName = WhiskBotUITests;
+			productReference = 7F6E27D71E2E73C50002E80B /* WhiskBotUITests.xctest */;
+			productType = "com.apple.product-type.bundle.ui-testing";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		7F6E27B01E2E73C50002E80B /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				LastSwiftUpdateCheck = 0820;
+				LastUpgradeCheck = 0820;
+				ORGANIZATIONNAME = "Avery Lamp";
+				TargetAttributes = {
+					7F6E27B71E2E73C50002E80B = {
+						CreatedOnToolsVersion = 8.2.1;
+						DevelopmentTeam = 9XWYL3K4YT;
+						ProvisioningStyle = Automatic;
+					};
+					7F6E27CB1E2E73C50002E80B = {
+						CreatedOnToolsVersion = 8.2.1;
+						ProvisioningStyle = Automatic;
+						TestTargetID = 7F6E27B71E2E73C50002E80B;
+					};
+					7F6E27D61E2E73C50002E80B = {
+						CreatedOnToolsVersion = 8.2.1;
+						ProvisioningStyle = Automatic;
+						TestTargetID = 7F6E27B71E2E73C50002E80B;
+					};
+				};
+			};
+			buildConfigurationList = 7F6E27B31E2E73C50002E80B /* Build configuration list for PBXProject "WhiskBot" */;
+			compatibilityVersion = "Xcode 3.2";
+			developmentRegion = English;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+				Base,
+			);
+			mainGroup = 7F6E27AF1E2E73C50002E80B;
+			productRefGroup = 7F6E27B91E2E73C50002E80B /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				7F6E27B71E2E73C50002E80B /* WhiskBot */,
+				7F6E27CB1E2E73C50002E80B /* WhiskBotTests */,
+				7F6E27D61E2E73C50002E80B /* WhiskBotUITests */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+		7F6E27B61E2E73C50002E80B /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				7F6E27C61E2E73C50002E80B /* LaunchScreen.storyboard in Resources */,
+				7F08F8831E43B8D400A2C875 /* IBMConstants.plist in Resources */,
+				7F6E27C31E2E73C50002E80B /* Assets.xcassets in Resources */,
+				7F6E27C11E2E73C50002E80B /* Main.storyboard in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		7F6E27CA1E2E73C50002E80B /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		7F6E27D51E2E73C50002E80B /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+		0EE5E942EB14E2A6A3036DA7 /* [CP] Embed Pods Frameworks */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			name = "[CP] Embed Pods Frameworks";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-WhiskBot/Pods-WhiskBot-frameworks.sh\"\n";
+			showEnvVarsInLog = 0;
+		};
+		66B4729EE868BC56B83B4518 /* [CP] Embed Pods Frameworks */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			name = "[CP] Embed Pods Frameworks";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-WhiskBotTests/Pods-WhiskBotTests-frameworks.sh\"\n";
+			showEnvVarsInLog = 0;
+		};
+		6946A633B00338DB9F586232 /* [CP] Check Pods Manifest.lock */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			name = "[CP] Check Pods Manifest.lock";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n";
+			showEnvVarsInLog = 0;
+		};
+		85628A6BD4F65CA247CADE61 /* [CP] Copy Pods Resources */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			name = "[CP] Copy Pods Resources";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-WhiskBotUITests/Pods-WhiskBotUITests-resources.sh\"\n";
+			showEnvVarsInLog = 0;
+		};
+		D06E1DE8E4D183B5236BD422 /* [CP] Check Pods Manifest.lock */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			name = "[CP] Check Pods Manifest.lock";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n";
+			showEnvVarsInLog = 0;
+		};
+		D8CFB8DF973640C14DDA9C71 /* [CP] Copy Pods Resources */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			name = "[CP] Copy Pods Resources";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-WhiskBotTests/Pods-WhiskBotTests-resources.sh\"\n";
+			showEnvVarsInLog = 0;
+		};
+		D9E43EAB6653C21A448C2DE0 /* [CP] Copy Pods Resources */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			name = "[CP] Copy Pods Resources";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-WhiskBot/Pods-WhiskBot-resources.sh\"\n";
+			showEnvVarsInLog = 0;
+		};
+		E0607CEF3BDE1BF4E3876F2C /* [CP] Embed Pods Frameworks */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			name = "[CP] Embed Pods Frameworks";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-WhiskBotUITests/Pods-WhiskBotUITests-frameworks.sh\"\n";
+			showEnvVarsInLog = 0;
+		};
+		F741D44D50DB185CDFFB8003 /* [CP] Check Pods Manifest.lock */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			name = "[CP] Check Pods Manifest.lock";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n";
+			showEnvVarsInLog = 0;
+		};
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		7F6E27B41E2E73C50002E80B /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				7F6E27EA1E2EA9940002E80B /* SplashViewController.swift in Sources */,
+				7F6E27BE1E2E73C50002E80B /* ViewController.swift in Sources */,
+				7F0044F61E2FF88E002A4B05 /* ChatBotViewController.swift in Sources */,
+				7F6E27EC1E2EA9E40002E80B /* ChatViewController.swift in Sources */,
+				7F6E27BC1E2E73C50002E80B /* AppDelegate.swift in Sources */,
+				7F61C9AF1E3009EA00AF3443 /* SpeechRecognizer.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		7F6E27C81E2E73C50002E80B /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				7F6E27D11E2E73C50002E80B /* WhiskBotTests.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		7F6E27D31E2E73C50002E80B /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				7F6E27DC1E2E73C50002E80B /* WhiskBotUITests.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+		7F6E27CE1E2E73C50002E80B /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 7F6E27B71E2E73C50002E80B /* WhiskBot */;
+			targetProxy = 7F6E27CD1E2E73C50002E80B /* PBXContainerItemProxy */;
+		};
+		7F6E27D91E2E73C50002E80B /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 7F6E27B71E2E73C50002E80B /* WhiskBot */;
+			targetProxy = 7F6E27D81E2E73C50002E80B /* PBXContainerItemProxy */;
+		};
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+		7F6E27BF1E2E73C50002E80B /* Main.storyboard */ = {
+			isa = PBXVariantGroup;
+			children = (
+				7F6E27C01E2E73C50002E80B /* Base */,
+			);
+			name = Main.storyboard;
+			sourceTree = "<group>";
+		};
+		7F6E27C41E2E73C50002E80B /* LaunchScreen.storyboard */ = {
+			isa = PBXVariantGroup;
+			children = (
+				7F6E27C51E2E73C50002E80B /* Base */,
+			);
+			name = LaunchScreen.storyboard;
+			sourceTree = "<group>";
+		};
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+		7F6E27DE1E2E73C50002E80B /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 10.2;
+				MTL_ENABLE_DEBUG_INFO = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				SDKROOT = iphoneos;
+				SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+			};
+			name = Debug;
+		};
+		7F6E27DF1E2E73C50002E80B /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 10.2;
+				MTL_ENABLE_DEBUG_INFO = NO;
+				SDKROOT = iphoneos;
+				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
+				VALIDATE_PRODUCT = YES;
+			};
+			name = Release;
+		};
+		7F6E27E11E2E73C50002E80B /* Debug */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 607D45ACE515D6A5F008D842 /* Pods-WhiskBot.debug.xcconfig */;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				DEVELOPMENT_TEAM = 9XWYL3K4YT;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+				);
+				INFOPLIST_FILE = WhiskBot/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = IBM.WhiskBot;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_VERSION = 3.0;
+			};
+			name = Debug;
+		};
+		7F6E27E21E2E73C50002E80B /* Release */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 10D90A899043788B2F68746A /* Pods-WhiskBot.release.xcconfig */;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				DEVELOPMENT_TEAM = 9XWYL3K4YT;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Carthage/Build/iOS",
+				);
+				INFOPLIST_FILE = WhiskBot/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = IBM.WhiskBot;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_VERSION = 3.0;
+			};
+			name = Release;
+		};
+		7F6E27E41E2E73C50002E80B /* Debug */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = ED94B5A49FAF65F34AF6C43D /* Pods-WhiskBotTests.debug.xcconfig */;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
+				BUNDLE_LOADER = "$(TEST_HOST)";
+				INFOPLIST_FILE = WhiskBotTests/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = IBM.WhiskBotTests;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/WhiskBot.app/WhiskBot";
+			};
+			name = Debug;
+		};
+		7F6E27E51E2E73C50002E80B /* Release */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 2945C1CEF44B524E77D0E7DA /* Pods-WhiskBotTests.release.xcconfig */;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
+				BUNDLE_LOADER = "$(TEST_HOST)";
+				INFOPLIST_FILE = WhiskBotTests/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = IBM.WhiskBotTests;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_VERSION = 3.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/WhiskBot.app/WhiskBot";
+			};
+			name = Release;
+		};
+		7F6E27E71E2E73C50002E80B /* Debug */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 61F3AE277EAA256CEBA7BD62 /* Pods-WhiskBotUITests.debug.xcconfig */;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
+				INFOPLIST_FILE = WhiskBotUITests/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = IBM.WhiskBotUITests;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_VERSION = 3.0;
+				TEST_TARGET_NAME = WhiskBot;
+			};
+			name = Debug;
+		};
+		7F6E27E81E2E73C50002E80B /* Release */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 8F521B1C934121C1C296CCF8 /* Pods-WhiskBotUITests.release.xcconfig */;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
+				INFOPLIST_FILE = WhiskBotUITests/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = IBM.WhiskBotUITests;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_VERSION = 3.0;
+				TEST_TARGET_NAME = WhiskBot;
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		7F6E27B31E2E73C50002E80B /* Build configuration list for PBXProject "WhiskBot" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				7F6E27DE1E2E73C50002E80B /* Debug */,
+				7F6E27DF1E2E73C50002E80B /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		7F6E27E01E2E73C50002E80B /* Build configuration list for PBXNativeTarget "WhiskBot" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				7F6E27E11E2E73C50002E80B /* Debug */,
+				7F6E27E21E2E73C50002E80B /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		7F6E27E31E2E73C50002E80B /* Build configuration list for PBXNativeTarget "WhiskBotTests" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				7F6E27E41E2E73C50002E80B /* Debug */,
+				7F6E27E51E2E73C50002E80B /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		7F6E27E61E2E73C50002E80B /* Build configuration list for PBXNativeTarget "WhiskBotUITests" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				7F6E27E71E2E73C50002E80B /* Debug */,
+				7F6E27E81E2E73C50002E80B /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = 7F6E27B01E2E73C50002E80B /* Project object */;
+}
diff --git a/whiskbot-demo-app/WhiskBot.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/whiskbot-demo-app/WhiskBot.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..348cd77
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+   version = "1.0">
+   <FileRef
+      location = "self:WhiskBot.xcodeproj">
+   </FileRef>
+</Workspace>
diff --git a/whiskbot-demo-app/WhiskBot.xcodeproj/project.xcworkspace/xcshareddata/WhiskBot.xcscmblueprint b/whiskbot-demo-app/WhiskBot.xcodeproj/project.xcworkspace/xcshareddata/WhiskBot.xcscmblueprint
new file mode 100644
index 0000000..b5ce819
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot.xcodeproj/project.xcworkspace/xcshareddata/WhiskBot.xcscmblueprint
@@ -0,0 +1,30 @@
+{
+  "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "356C0FA35D959FB8A0A4A9AFE0E4B13D2C073E83",
+  "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
+
+  },
+  "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
+    "356C0FA35D959FB8A0A4A9AFE0E4B13D2C073E83" : 9223372036854775807,
+    "A8701B03A3B0BD7AB86119B23218B394663BB517" : 9223372036854775807
+  },
+  "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "4B04F5CE-9B5F-4C11-89AD-955B0FF77890",
+  "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
+    "356C0FA35D959FB8A0A4A9AFE0E4B13D2C073E83" : "WhiskBot\/",
+    "A8701B03A3B0BD7AB86119B23218B394663BB517" : "..\/CognitiveConciergeTest\/CognitiveConciergeTest"
+  },
+  "DVTSourceControlWorkspaceBlueprintNameKey" : "WhiskBot",
+  "DVTSourceControlWorkspaceBlueprintVersion" : 204,
+  "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "WhiskBot.xcodeproj",
+  "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
+    {
+      "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/Averylamp\/WhiskBot.git",
+      "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
+      "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "356C0FA35D959FB8A0A4A9AFE0E4B13D2C073E83"
+    },
+    {
+      "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/IBM-MIL\/CognitiveConcierge",
+      "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
+      "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "A8701B03A3B0BD7AB86119B23218B394663BB517"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/whiskbot-demo-app/WhiskBot.xcworkspace/contents.xcworkspacedata b/whiskbot-demo-app/WhiskBot.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..9ac1226
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+   version = "1.0">
+   <FileRef
+      location = "group:WhiskBot.xcodeproj">
+   </FileRef>
+   <FileRef
+      location = "group:Pods/Pods.xcodeproj">
+   </FileRef>
+</Workspace>
diff --git a/whiskbot-demo-app/WhiskBot.xcworkspace/xcshareddata/WhiskBot.xcscmblueprint b/whiskbot-demo-app/WhiskBot.xcworkspace/xcshareddata/WhiskBot.xcscmblueprint
new file mode 100644
index 0000000..e0e20be
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot.xcworkspace/xcshareddata/WhiskBot.xcscmblueprint
@@ -0,0 +1,37 @@
+{
+  "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "356C0FA35D959FB8A0A4A9AFE0E4B13D2C073E83",
+  "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
+
+  },
+  "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
+    "356C0FA35D959FB8A0A4A9AFE0E4B13D2C073E83" : 9223372036854775807,
+    "E9057848A6186DD9CAE5574816428252CA2E16CD" : 9223372036854775807,
+    "A8701B03A3B0BD7AB86119B23218B394663BB517" : 9223372036854775807
+  },
+  "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "020A60EC-934E-4F29-990C-53079B48766E",
+  "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
+    "356C0FA35D959FB8A0A4A9AFE0E4B13D2C073E83" : "WhiskBot\/",
+    "E9057848A6186DD9CAE5574816428252CA2E16CD" : "..",
+    "A8701B03A3B0BD7AB86119B23218B394663BB517" : "..\/CognitiveConciergeTest\/CognitiveConciergeTest"
+  },
+  "DVTSourceControlWorkspaceBlueprintNameKey" : "WhiskBot",
+  "DVTSourceControlWorkspaceBlueprintVersion" : 204,
+  "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "WhiskBot.xcworkspace",
+  "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
+    {
+      "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/Averylamp\/WhiskBot.git",
+      "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
+      "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "356C0FA35D959FB8A0A4A9AFE0E4B13D2C073E83"
+    },
+    {
+      "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/IBM-MIL\/CognitiveConcierge",
+      "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
+      "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "A8701B03A3B0BD7AB86119B23218B394663BB517"
+    },
+    {
+      "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/Averylamp\/openwhisk-xcode.git",
+      "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
+      "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "E9057848A6186DD9CAE5574816428252CA2E16CD"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/whiskbot-demo-app/WhiskBot/AppDelegate.swift b/whiskbot-demo-app/WhiskBot/AppDelegate.swift
new file mode 100644
index 0000000..dc2783e
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/AppDelegate.swift
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2015-2016 IBM Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+//
+//  AppDelegate.swift
+//  WhiskBot
+//
+//  Created by whisk on 1/17/17.
+//  Copyright © 2017 Avery Lamp. All rights reserved.
+//
+
+import UIKit
+
+@UIApplicationMain
+class AppDelegate: UIResponder, UIApplicationDelegate {
+
+    var window: UIWindow?
+
+
+    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
+        // Override point for customization after application launch.
+        return true
+    }
+
+    func applicationWillResignActive(_ application: UIApplication) {
+        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
+        // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
+    }
+
+    func applicationDidEnterBackground(_ application: UIApplication) {
+        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
+        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
+    }
+
+    func applicationWillEnterForeground(_ application: UIApplication) {
+        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
+    }
+
+    func applicationDidBecomeActive(_ application: UIApplication) {
+        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
+    }
+
+    func applicationWillTerminate(_ application: UIApplication) {
+        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
+    }
+
+
+}
+
diff --git a/whiskbot-demo-app/WhiskBot/Assets.xcassets/AppIcon.appiconset/Contents.json b/whiskbot-demo-app/WhiskBot/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..c47d6d4
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,56 @@
+{
+  "images" : [
+    {
+      "size" : "20x20",
+      "idiom" : "iphone",
+      "filename" : "openwhisk_logo_large-7.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "20x20",
+      "idiom" : "iphone",
+      "filename" : "openwhisk_logo_large-5.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "iphone",
+      "filename" : "openwhisk_logo_large-6.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "iphone",
+      "filename" : "openwhisk_logo_large-3.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "iphone",
+      "filename" : "openwhisk_logo_large-4.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "iphone",
+      "filename" : "openwhisk_logo_large-2.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "60x60",
+      "idiom" : "iphone",
+      "filename" : "openwhisk_logo_large-1.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "60x60",
+      "idiom" : "iphone",
+      "filename" : "openwhisk_logo_large.png",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
\ No newline at end of file
diff --git a/whiskbot-demo-app/WhiskBot/Assets.xcassets/AppIcon.appiconset/openwhisk_logo_large-1.png b/whiskbot-demo-app/WhiskBot/Assets.xcassets/AppIcon.appiconset/openwhisk_logo_large-1.png
new file mode 100644
index 0000000..045ab5c
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/Assets.xcassets/AppIcon.appiconset/openwhisk_logo_large-1.png
Binary files differ
diff --git a/whiskbot-demo-app/WhiskBot/Assets.xcassets/AppIcon.appiconset/openwhisk_logo_large-2.png b/whiskbot-demo-app/WhiskBot/Assets.xcassets/AppIcon.appiconset/openwhisk_logo_large-2.png
new file mode 100644
index 0000000..045ab5c
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/Assets.xcassets/AppIcon.appiconset/openwhisk_logo_large-2.png
Binary files differ
diff --git a/whiskbot-demo-app/WhiskBot/Assets.xcassets/AppIcon.appiconset/openwhisk_logo_large-3.png b/whiskbot-demo-app/WhiskBot/Assets.xcassets/AppIcon.appiconset/openwhisk_logo_large-3.png
new file mode 100644
index 0000000..5fe8495
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/Assets.xcassets/AppIcon.appiconset/openwhisk_logo_large-3.png
Binary files differ
diff --git a/whiskbot-demo-app/WhiskBot/Assets.xcassets/AppIcon.appiconset/openwhisk_logo_large-4.png b/whiskbot-demo-app/WhiskBot/Assets.xcassets/AppIcon.appiconset/openwhisk_logo_large-4.png
new file mode 100644
index 0000000..b0030af
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/Assets.xcassets/AppIcon.appiconset/openwhisk_logo_large-4.png
Binary files differ
diff --git a/whiskbot-demo-app/WhiskBot/Assets.xcassets/AppIcon.appiconset/openwhisk_logo_large-5.png b/whiskbot-demo-app/WhiskBot/Assets.xcassets/AppIcon.appiconset/openwhisk_logo_large-5.png
new file mode 100644
index 0000000..be25eb0
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/Assets.xcassets/AppIcon.appiconset/openwhisk_logo_large-5.png
Binary files differ
diff --git a/whiskbot-demo-app/WhiskBot/Assets.xcassets/AppIcon.appiconset/openwhisk_logo_large-6.png b/whiskbot-demo-app/WhiskBot/Assets.xcassets/AppIcon.appiconset/openwhisk_logo_large-6.png
new file mode 100644
index 0000000..67227ab
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/Assets.xcassets/AppIcon.appiconset/openwhisk_logo_large-6.png
Binary files differ
diff --git a/whiskbot-demo-app/WhiskBot/Assets.xcassets/AppIcon.appiconset/openwhisk_logo_large-7.png b/whiskbot-demo-app/WhiskBot/Assets.xcassets/AppIcon.appiconset/openwhisk_logo_large-7.png
new file mode 100644
index 0000000..5a5e254
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/Assets.xcassets/AppIcon.appiconset/openwhisk_logo_large-7.png
Binary files differ
diff --git a/whiskbot-demo-app/WhiskBot/Assets.xcassets/AppIcon.appiconset/openwhisk_logo_large.png b/whiskbot-demo-app/WhiskBot/Assets.xcassets/AppIcon.appiconset/openwhisk_logo_large.png
new file mode 100644
index 0000000..7eaef4d
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/Assets.xcassets/AppIcon.appiconset/openwhisk_logo_large.png
Binary files differ
diff --git a/whiskbot-demo-app/WhiskBot/Assets.xcassets/Contents.json b/whiskbot-demo-app/WhiskBot/Assets.xcassets/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
\ No newline at end of file
diff --git a/whiskbot-demo-app/WhiskBot/Assets.xcassets/IBMLogo.imageset/2000px-IBM_logo.svg.png b/whiskbot-demo-app/WhiskBot/Assets.xcassets/IBMLogo.imageset/2000px-IBM_logo.svg.png
new file mode 100644
index 0000000..ef61ec8
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/Assets.xcassets/IBMLogo.imageset/2000px-IBM_logo.svg.png
Binary files differ
diff --git a/whiskbot-demo-app/WhiskBot/Assets.xcassets/IBMLogo.imageset/Contents.json b/whiskbot-demo-app/WhiskBot/Assets.xcassets/IBMLogo.imageset/Contents.json
new file mode 100644
index 0000000..9fe9c94
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/Assets.xcassets/IBMLogo.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "filename" : "2000px-IBM_logo.svg.png",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
\ No newline at end of file
diff --git a/whiskbot-demo-app/WhiskBot/Assets.xcassets/bluemixLogo.imageset/Contents.json b/whiskbot-demo-app/WhiskBot/Assets.xcassets/bluemixLogo.imageset/Contents.json
new file mode 100644
index 0000000..6e39cf0
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/Assets.xcassets/bluemixLogo.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "filename" : "IBM_Bluemix_logo.svg.png",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
\ No newline at end of file
diff --git a/whiskbot-demo-app/WhiskBot/Assets.xcassets/bluemixLogo.imageset/IBM_Bluemix_logo.svg.png b/whiskbot-demo-app/WhiskBot/Assets.xcassets/bluemixLogo.imageset/IBM_Bluemix_logo.svg.png
new file mode 100644
index 0000000..712054a
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/Assets.xcassets/bluemixLogo.imageset/IBM_Bluemix_logo.svg.png
Binary files differ
diff --git a/whiskbot-demo-app/WhiskBot/Assets.xcassets/helpIcon.imageset/Contents.json b/whiskbot-demo-app/WhiskBot/Assets.xcassets/helpIcon.imageset/Contents.json
new file mode 100644
index 0000000..129895b
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/Assets.xcassets/helpIcon.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "filename" : "Help-100 (1).png",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
\ No newline at end of file
diff --git "a/whiskbot-demo-app/WhiskBot/Assets.xcassets/helpIcon.imageset/Help-100 \0501\051.png" "b/whiskbot-demo-app/WhiskBot/Assets.xcassets/helpIcon.imageset/Help-100 \0501\051.png"
new file mode 100644
index 0000000..d1d6c2b
--- /dev/null
+++ "b/whiskbot-demo-app/WhiskBot/Assets.xcassets/helpIcon.imageset/Help-100 \0501\051.png"
Binary files differ
diff --git a/whiskbot-demo-app/WhiskBot/Assets.xcassets/microphone.imageset/Contents.json b/whiskbot-demo-app/WhiskBot/Assets.xcassets/microphone.imageset/Contents.json
new file mode 100644
index 0000000..dbaab77
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/Assets.xcassets/microphone.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "filename" : "Microphone-100.png",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
\ No newline at end of file
diff --git a/whiskbot-demo-app/WhiskBot/Assets.xcassets/microphone.imageset/Microphone-100.png b/whiskbot-demo-app/WhiskBot/Assets.xcassets/microphone.imageset/Microphone-100.png
new file mode 100644
index 0000000..f142cee
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/Assets.xcassets/microphone.imageset/Microphone-100.png
Binary files differ
diff --git a/whiskbot-demo-app/WhiskBot/Assets.xcassets/microphone2.imageset/Contents.json b/whiskbot-demo-app/WhiskBot/Assets.xcassets/microphone2.imageset/Contents.json
new file mode 100644
index 0000000..d84759c
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/Assets.xcassets/microphone2.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "filename" : "Microphone-96.png",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
\ No newline at end of file
diff --git a/whiskbot-demo-app/WhiskBot/Assets.xcassets/microphone2.imageset/Microphone-96.png b/whiskbot-demo-app/WhiskBot/Assets.xcassets/microphone2.imageset/Microphone-96.png
new file mode 100644
index 0000000..d238579
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/Assets.xcassets/microphone2.imageset/Microphone-96.png
Binary files differ
diff --git a/whiskbot-demo-app/WhiskBot/Assets.xcassets/openwhiskLogo.imageset/Contents.json b/whiskbot-demo-app/WhiskBot/Assets.xcassets/openwhiskLogo.imageset/Contents.json
new file mode 100644
index 0000000..bc0a2fb
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/Assets.xcassets/openwhiskLogo.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "filename" : "openwhisk_hero_medium.png",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
\ No newline at end of file
diff --git a/whiskbot-demo-app/WhiskBot/Assets.xcassets/openwhiskLogo.imageset/openwhisk_hero_medium.png b/whiskbot-demo-app/WhiskBot/Assets.xcassets/openwhiskLogo.imageset/openwhisk_hero_medium.png
new file mode 100644
index 0000000..f58dfc1
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/Assets.xcassets/openwhiskLogo.imageset/openwhisk_hero_medium.png
Binary files differ
diff --git a/whiskbot-demo-app/WhiskBot/Assets.xcassets/splashbg.imageset/Contents.json b/whiskbot-demo-app/WhiskBot/Assets.xcassets/splashbg.imageset/Contents.json
new file mode 100644
index 0000000..bc78f1d
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/Assets.xcassets/splashbg.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "filename" : "profileBackground.png",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
\ No newline at end of file
diff --git a/whiskbot-demo-app/WhiskBot/Assets.xcassets/splashbg.imageset/profileBackground.png b/whiskbot-demo-app/WhiskBot/Assets.xcassets/splashbg.imageset/profileBackground.png
new file mode 100644
index 0000000..bbbbcb3
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/Assets.xcassets/splashbg.imageset/profileBackground.png
Binary files differ
diff --git a/whiskbot-demo-app/WhiskBot/Base.lproj/LaunchScreen.storyboard b/whiskbot-demo-app/WhiskBot/Base.lproj/LaunchScreen.storyboard
new file mode 100644
index 0000000..e35a8e1
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/Base.lproj/LaunchScreen.storyboard
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11762" systemVersion="16C68" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
+    <device id="retina4_7" orientation="portrait">
+        <adaptation id="fullscreen"/>
+    </device>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
+        <capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <scenes>
+        <!--View Controller-->
+        <scene sceneID="EHf-IW-A2E">
+            <objects>
+                <viewController id="01J-lp-oVM" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
+                        <viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <imageView userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="splashbg" translatesAutoresizingMaskIntoConstraints="NO" id="LoI-vf-I2K">
+                                <rect key="frame" x="0.0" y="0.0" width="1125" height="667"/>
+                            </imageView>
+                        </subviews>
+                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <constraints>
+                            <constraint firstItem="LoI-vf-I2K" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leading" id="fuv-kY-V04"/>
+                            <constraint firstItem="LoI-vf-I2K" firstAttribute="height" secondItem="Ze5-6b-2t3" secondAttribute="height" id="iIo-Ca-ICO"/>
+                            <constraint firstItem="LoI-vf-I2K" firstAttribute="width" secondItem="Ze5-6b-2t3" secondAttribute="width" multiplier="3" id="m3o-E7-SlX"/>
+                            <constraint firstItem="LoI-vf-I2K" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="zup-dg-M7g"/>
+                        </constraints>
+                    </view>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="53" y="375"/>
+        </scene>
+    </scenes>
+    <resources>
+        <image name="splashbg" width="3000" height="1688"/>
+    </resources>
+</document>
diff --git a/whiskbot-demo-app/WhiskBot/Base.lproj/Main.storyboard b/whiskbot-demo-app/WhiskBot/Base.lproj/Main.storyboard
new file mode 100644
index 0000000..06ddaee
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/Base.lproj/Main.storyboard
@@ -0,0 +1,422 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="AiM-Wz-Nbc">
+    <device id="retina4_7" orientation="portrait">
+        <adaptation id="fullscreen"/>
+    </device>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
+        <capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
+        <capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <scenes>
+        <!--Splash View Controller-->
+        <scene sceneID="tne-QT-ifu">
+            <objects>
+                <viewController storyboardIdentifier="splashVC" id="BYZ-38-t0r" customClass="SplashViewController" customModule="WhiskBot" customModuleProvider="target" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
+                        <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <imageView userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="splashbg" translatesAutoresizingMaskIntoConstraints="NO" id="K4p-aG-nhN">
+                                <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+                                <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                            </imageView>
+                            <view alpha="0.12" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="k6Y-5N-os7">
+                                <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+                                <color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
+                            </view>
+                            <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" bounces="NO" pagingEnabled="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" translatesAutoresizingMaskIntoConstraints="NO" id="VgN-h6-yjc">
+                                <rect key="frame" x="-0.5" y="-0.5" width="375" height="667"/>
+                                <subviews>
+                                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="HqY-J9-S7l" userLabel="contentView">
+                                        <rect key="frame" x="0.0" y="0.0" width="1500" height="667"/>
+                                        <subviews>
+                                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="yvx-RP-Ney" userLabel="First Page">
+                                                <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+                                                <subviews>
+                                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="WhiskBot" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6FA-ht-ry1">
+                                                        <rect key="frame" x="0.5" y="80" width="375" height="40"/>
+                                                        <constraints>
+                                                            <constraint firstAttribute="height" constant="40" id="YSi-C4-rG1"/>
+                                                        </constraints>
+                                                        <fontDescription key="fontDescription" name="AvenirNext-Medium" family="Avenir Next" pointSize="27"/>
+                                                        <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                                        <nil key="highlightedColor"/>
+                                                    </label>
+                                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="JVe-MU-sXA">
+                                                        <rect key="frame" x="47.5" y="160" width="280" height="290"/>
+                                                        <constraints>
+                                                            <constraint firstAttribute="width" constant="280" id="8nM-7t-hXc"/>
+                                                            <constraint firstAttribute="height" constant="290" id="DkC-Hu-qiT"/>
+                                                        </constraints>
+                                                        <string key="text">WhiskBot is made with OpenWhisk Swift Actions and the IBM Watson Conversation service.
+
+It was built by using a single OpenWhisk action as the middleware for the features built into WhiskBot.  If a Slack Post or Translation are initiated, secondary actions are called from the conversation action.</string>
+                                                        <fontDescription key="fontDescription" name="AvenirNext-Regular" family="Avenir Next" pointSize="18"/>
+                                                        <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                                        <nil key="highlightedColor"/>
+                                                    </label>
+                                                </subviews>
+                                                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+                                                <constraints>
+                                                    <constraint firstItem="JVe-MU-sXA" firstAttribute="top" secondItem="6FA-ht-ry1" secondAttribute="bottom" constant="40" id="0kR-3k-Irq"/>
+                                                    <constraint firstItem="6FA-ht-ry1" firstAttribute="width" secondItem="yvx-RP-Ney" secondAttribute="width" id="Oyz-I4-t8g"/>
+                                                    <constraint firstItem="6FA-ht-ry1" firstAttribute="top" secondItem="yvx-RP-Ney" secondAttribute="top" constant="80" id="T02-yX-Oai"/>
+                                                    <constraint firstItem="JVe-MU-sXA" firstAttribute="centerX" secondItem="6FA-ht-ry1" secondAttribute="centerX" id="gD2-am-EG3"/>
+                                                    <constraint firstItem="6FA-ht-ry1" firstAttribute="centerX" secondItem="yvx-RP-Ney" secondAttribute="centerX" id="kUC-oq-VcA"/>
+                                                </constraints>
+                                            </view>
+                                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="aSg-Rp-D0h" userLabel="Second Page">
+                                                <rect key="frame" x="375.5" y="0.5" width="375" height="667"/>
+                                                <subviews>
+                                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Slack" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="pyS-EU-kKQ">
+                                                        <rect key="frame" x="0.5" y="80" width="375" height="40"/>
+                                                        <constraints>
+                                                            <constraint firstAttribute="height" constant="40" id="w4h-97-Xnu"/>
+                                                        </constraints>
+                                                        <fontDescription key="fontDescription" name="AvenirNext-Medium" family="Avenir Next" pointSize="27"/>
+                                                        <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                                        <nil key="highlightedColor"/>
+                                                    </label>
+                                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Jai-IM-wfh">
+                                                        <rect key="frame" x="60.5" y="160" width="255" height="260"/>
+                                                        <constraints>
+                                                            <constraint firstAttribute="width" constant="255" id="Cg4-Tf-sRr"/>
+                                                            <constraint firstAttribute="height" constant="260" id="vx6-hn-38Y"/>
+                                                        </constraints>
+                                                        <string key="text">Ask WhiskBot to post to slack for you.  

Whiskbot's Conversation OpenWhisk Action acts as middleware intercepting and sending Slack posts to a Slack action.  Specify the channel to post to and text, and WhiskBot will post for you.</string>
+                                                        <fontDescription key="fontDescription" name="AvenirNext-Regular" family="Avenir Next" pointSize="18"/>
+                                                        <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                                        <nil key="highlightedColor"/>
+                                                    </label>
+                                                </subviews>
+                                                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+                                                <constraints>
+                                                    <constraint firstItem="Jai-IM-wfh" firstAttribute="centerX" secondItem="pyS-EU-kKQ" secondAttribute="centerX" id="0b5-WL-3NK"/>
+                                                    <constraint firstItem="pyS-EU-kKQ" firstAttribute="top" secondItem="aSg-Rp-D0h" secondAttribute="top" constant="80" id="9UW-fP-UTL"/>
+                                                    <constraint firstItem="pyS-EU-kKQ" firstAttribute="width" secondItem="aSg-Rp-D0h" secondAttribute="width" id="e59-q2-KeB"/>
+                                                    <constraint firstItem="Jai-IM-wfh" firstAttribute="top" secondItem="pyS-EU-kKQ" secondAttribute="bottom" constant="40" id="nfV-He-8kw"/>
+                                                    <constraint firstItem="pyS-EU-kKQ" firstAttribute="centerX" secondItem="aSg-Rp-D0h" secondAttribute="centerX" id="skT-ll-kh5"/>
+                                                </constraints>
+                                            </view>
+                                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="E9x-rm-zuy" userLabel="Third Page">
+                                                <rect key="frame" x="750.5" y="0.0" width="375" height="667"/>
+                                                <subviews>
+                                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Translations" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="3EW-Vq-tI4">
+                                                        <rect key="frame" x="0.5" y="80" width="375" height="40"/>
+                                                        <constraints>
+                                                            <constraint firstAttribute="height" constant="40" id="rvI-42-ijh"/>
+                                                        </constraints>
+                                                        <fontDescription key="fontDescription" name="AvenirNext-Medium" family="Avenir Next" pointSize="27"/>
+                                                        <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                                        <nil key="highlightedColor"/>
+                                                    </label>
+                                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="JDK-eJ-yFu">
+                                                        <rect key="frame" x="60.5" y="160" width="255" height="260"/>
+                                                        <constraints>
+                                                            <constraint firstAttribute="height" constant="260" id="arf-hf-lFs"/>
+                                                            <constraint firstAttribute="width" constant="255" id="dSr-bd-EhF"/>
+                                                        </constraints>
+                                                        <string key="text">Ask WhiskBot to translate something for you.  
+
+WhiskBot take in your input text and give you the correct translation in another language directly from Watson Language Translator by invoking a seperate translation action</string>
+                                                        <fontDescription key="fontDescription" name="AvenirNext-Regular" family="Avenir Next" pointSize="18"/>
+                                                        <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                                        <nil key="highlightedColor"/>
+                                                    </label>
+                                                </subviews>
+                                                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+                                                <constraints>
+                                                    <constraint firstItem="3EW-Vq-tI4" firstAttribute="centerX" secondItem="E9x-rm-zuy" secondAttribute="centerX" id="5fx-N2-CsP"/>
+                                                    <constraint firstItem="3EW-Vq-tI4" firstAttribute="width" secondItem="E9x-rm-zuy" secondAttribute="width" id="XSM-ql-czU"/>
+                                                    <constraint firstItem="3EW-Vq-tI4" firstAttribute="top" secondItem="E9x-rm-zuy" secondAttribute="top" constant="80" id="YDx-rO-Bc2"/>
+                                                    <constraint firstItem="JDK-eJ-yFu" firstAttribute="top" secondItem="3EW-Vq-tI4" secondAttribute="bottom" constant="40" id="jEj-Ps-BtG"/>
+                                                    <constraint firstItem="JDK-eJ-yFu" firstAttribute="centerX" secondItem="3EW-Vq-tI4" secondAttribute="centerX" id="s95-1N-GQu"/>
+                                                </constraints>
+                                            </view>
+                                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="FqT-WX-hoY" userLabel="Forth Page">
+                                                <rect key="frame" x="1125.5" y="-0.5" width="375" height="667"/>
+                                                <subviews>
+                                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Reminders" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="f9q-l0-3bp">
+                                                        <rect key="frame" x="0.5" y="80" width="375" height="40"/>
+                                                        <constraints>
+                                                            <constraint firstAttribute="height" constant="40" id="GYG-En-wRu"/>
+                                                        </constraints>
+                                                        <fontDescription key="fontDescription" name="AvenirNext-Medium" family="Avenir Next" pointSize="27"/>
+                                                        <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                                        <nil key="highlightedColor"/>
+                                                    </label>
+                                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="YfK-XJ-VX9">
+                                                        <rect key="frame" x="60.5" y="160" width="255" height="180"/>
+                                                        <constraints>
+                                                            <constraint firstAttribute="height" constant="180" id="8hu-ny-WKI"/>
+                                                            <constraint firstAttribute="width" constant="255" id="9ij-Vo-3im"/>
+                                                        </constraints>
+                                                        <string key="text">Ask WhiskBot to remind you to do something or schedule an event.  
+
+WhiskBot will add the reminder to your reminders or the event to your calendar.</string>
+                                                        <fontDescription key="fontDescription" name="AvenirNext-Regular" family="Avenir Next" pointSize="18"/>
+                                                        <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                                        <nil key="highlightedColor"/>
+                                                    </label>
+                                                </subviews>
+                                                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+                                                <constraints>
+                                                    <constraint firstItem="f9q-l0-3bp" firstAttribute="top" secondItem="FqT-WX-hoY" secondAttribute="top" constant="80" id="7bs-9q-Mz3"/>
+                                                    <constraint firstItem="f9q-l0-3bp" firstAttribute="width" secondItem="FqT-WX-hoY" secondAttribute="width" id="MOR-Xs-x8v"/>
+                                                    <constraint firstItem="YfK-XJ-VX9" firstAttribute="top" secondItem="f9q-l0-3bp" secondAttribute="bottom" constant="40" id="Mcd-xU-LT9"/>
+                                                    <constraint firstItem="YfK-XJ-VX9" firstAttribute="centerX" secondItem="f9q-l0-3bp" secondAttribute="centerX" id="heD-uk-jBH"/>
+                                                    <constraint firstItem="f9q-l0-3bp" firstAttribute="centerX" secondItem="FqT-WX-hoY" secondAttribute="centerX" id="j9U-bW-Eou"/>
+                                                </constraints>
+                                            </view>
+                                        </subviews>
+                                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+                                        <constraints>
+                                            <constraint firstItem="aSg-Rp-D0h" firstAttribute="leading" secondItem="yvx-RP-Ney" secondAttribute="trailing" id="5kD-De-y1m"/>
+                                            <constraint firstItem="yvx-RP-Ney" firstAttribute="leading" secondItem="HqY-J9-S7l" secondAttribute="leading" id="84P-c1-3k3"/>
+                                            <constraint firstItem="yvx-RP-Ney" firstAttribute="height" secondItem="HqY-J9-S7l" secondAttribute="height" id="8j2-Em-pHX"/>
+                                            <constraint firstItem="aSg-Rp-D0h" firstAttribute="centerY" secondItem="yvx-RP-Ney" secondAttribute="centerY" id="BXI-Bi-DoJ"/>
+                                            <constraint firstItem="yvx-RP-Ney" firstAttribute="centerY" secondItem="HqY-J9-S7l" secondAttribute="centerY" id="Hqp-Wh-KBZ"/>
+                                            <constraint firstItem="aSg-Rp-D0h" firstAttribute="height" secondItem="yvx-RP-Ney" secondAttribute="height" id="Q8N-E3-wJN"/>
+                                            <constraint firstItem="aSg-Rp-D0h" firstAttribute="width" secondItem="yvx-RP-Ney" secondAttribute="width" id="RHA-s5-d3N"/>
+                                            <constraint firstItem="FqT-WX-hoY" firstAttribute="height" secondItem="E9x-rm-zuy" secondAttribute="height" id="XoP-fQ-Uru"/>
+                                            <constraint firstItem="FqT-WX-hoY" firstAttribute="width" secondItem="E9x-rm-zuy" secondAttribute="width" id="Ybi-j4-8qx"/>
+                                            <constraint firstItem="FqT-WX-hoY" firstAttribute="leading" secondItem="E9x-rm-zuy" secondAttribute="trailing" id="eJg-gr-Mpj"/>
+                                            <constraint firstItem="E9x-rm-zuy" firstAttribute="centerY" secondItem="aSg-Rp-D0h" secondAttribute="centerY" id="lrm-Ca-Gpr"/>
+                                            <constraint firstItem="FqT-WX-hoY" firstAttribute="centerY" secondItem="E9x-rm-zuy" secondAttribute="centerY" id="rKj-bU-BTZ"/>
+                                            <constraint firstItem="E9x-rm-zuy" firstAttribute="leading" secondItem="aSg-Rp-D0h" secondAttribute="trailing" id="scH-gd-Dw4"/>
+                                        </constraints>
+                                    </view>
+                                </subviews>
+                                <constraints>
+                                    <constraint firstItem="E9x-rm-zuy" firstAttribute="width" secondItem="VgN-h6-yjc" secondAttribute="width" id="48H-Ec-0uG"/>
+                                    <constraint firstAttribute="bottom" secondItem="HqY-J9-S7l" secondAttribute="bottom" id="EdF-qp-bD5"/>
+                                    <constraint firstItem="yvx-RP-Ney" firstAttribute="width" secondItem="VgN-h6-yjc" secondAttribute="width" id="Fcv-1w-Eds"/>
+                                    <constraint firstAttribute="trailing" secondItem="HqY-J9-S7l" secondAttribute="trailing" id="OWO-hN-NZp"/>
+                                    <constraint firstItem="HqY-J9-S7l" firstAttribute="top" secondItem="VgN-h6-yjc" secondAttribute="top" id="gFp-9j-d5x"/>
+                                    <constraint firstItem="E9x-rm-zuy" firstAttribute="height" secondItem="VgN-h6-yjc" secondAttribute="height" id="u4g-Ao-Wq8"/>
+                                    <constraint firstItem="HqY-J9-S7l" firstAttribute="leading" secondItem="VgN-h6-yjc" secondAttribute="leading" id="z9o-PJ-Ytd"/>
+                                </constraints>
+                            </scrollView>
+                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="8hb-ji-SnJ">
+                                <rect key="frame" x="117" y="582" width="140" height="45"/>
+                                <color key="backgroundColor" red="0.30588235294117649" green="0.44313725490196076" blue="0.71372549019607845" alpha="1" colorSpace="calibratedRGB"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="45" id="65B-Hv-ZLe"/>
+                                    <constraint firstAttribute="width" constant="140" id="KEt-7a-fpj"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" name="AvenirNext-Regular" family="Avenir Next" pointSize="17"/>
+                                <state key="normal" title="LETS GO">
+                                    <color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                </state>
+                                <userDefinedRuntimeAttributes>
+                                    <userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
+                                        <integer key="value" value="10"/>
+                                    </userDefinedRuntimeAttribute>
+                                    <userDefinedRuntimeAttribute type="number" keyPath="layer.shadowRadius">
+                                        <integer key="value" value="8"/>
+                                    </userDefinedRuntimeAttribute>
+                                    <userDefinedRuntimeAttribute type="number" keyPath="layer.shadowOpacity">
+                                        <real key="value" value="0.59999999999999998"/>
+                                    </userDefinedRuntimeAttribute>
+                                    <userDefinedRuntimeAttribute type="point" keyPath="layer.shadowOffset">
+                                        <point key="value" x="2" y="2"/>
+                                    </userDefinedRuntimeAttribute>
+                                </userDefinedRuntimeAttributes>
+                                <connections>
+                                    <action selector="continueButtonClicked:" destination="BYZ-38-t0r" eventType="touchUpInside" id="zr5-Hl-qc4"/>
+                                </connections>
+                            </button>
+                        </subviews>
+                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <constraints>
+                            <constraint firstItem="VgN-h6-yjc" firstAttribute="width" secondItem="8bC-Xf-vdC" secondAttribute="width" id="12x-eV-Eii"/>
+                            <constraint firstItem="8hb-ji-SnJ" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="54C-sm-yPR"/>
+                            <constraint firstItem="VgN-h6-yjc" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="FaR-Bc-8RF"/>
+                            <constraint firstItem="k6Y-5N-os7" firstAttribute="centerY" secondItem="8bC-Xf-vdC" secondAttribute="centerY" id="MX3-Mt-03u"/>
+                            <constraint firstItem="VgN-h6-yjc" firstAttribute="width" secondItem="k6Y-5N-os7" secondAttribute="width" id="PQx-ho-HHh"/>
+                            <constraint firstItem="VgN-h6-yjc" firstAttribute="height" secondItem="8bC-Xf-vdC" secondAttribute="height" id="RLE-T6-AX9"/>
+                            <constraint firstItem="wfy-db-euE" firstAttribute="top" secondItem="8hb-ji-SnJ" secondAttribute="bottom" constant="40" id="VDx-WZ-L6v"/>
+                            <constraint firstItem="k6Y-5N-os7" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="ao6-gk-J9B"/>
+                            <constraint firstItem="VgN-h6-yjc" firstAttribute="height" secondItem="k6Y-5N-os7" secondAttribute="height" id="bHh-Eq-2Rt"/>
+                            <constraint firstItem="HqY-J9-S7l" firstAttribute="width" secondItem="8bC-Xf-vdC" secondAttribute="width" multiplier="4" id="eac-oy-sFn"/>
+                            <constraint firstItem="VgN-h6-yjc" firstAttribute="centerY" secondItem="8bC-Xf-vdC" secondAttribute="centerY" id="kAx-cV-0w8"/>
+                            <constraint firstItem="HqY-J9-S7l" firstAttribute="height" secondItem="8bC-Xf-vdC" secondAttribute="height" id="n44-ee-vy9"/>
+                        </constraints>
+                    </view>
+                    <connections>
+                        <outlet property="backgroundImage" destination="K4p-aG-nhN" id="hIS-uf-A8n"/>
+                        <outlet property="scrollView" destination="VgN-h6-yjc" id="bnf-RX-29Z"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="-234.40000000000001" y="115.59220389805098"/>
+        </scene>
+        <!--Chat View Controller-->
+        <scene sceneID="Azf-Vl-a5C">
+            <objects>
+                <viewController storyboardIdentifier="ChatVC" id="AiM-Wz-Nbc" customClass="ChatViewController" customModule="WhiskBot" customModuleProvider="target" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="NB1-kn-Fcd"/>
+                        <viewControllerLayoutGuide type="bottom" id="Bpr-87-BHC"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="vtI-ht-JBE">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="zM4-XI-rpq">
+                                <rect key="frame" x="0.0" y="0.0" width="375" height="80"/>
+                                <subviews>
+                                    <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="IBMLogo" translatesAutoresizingMaskIntoConstraints="NO" id="vIm-X5-lfm">
+                                        <rect key="frame" x="137" y="10" width="100" height="70"/>
+                                        <constraints>
+                                            <constraint firstAttribute="width" constant="100" id="Hrh-Rh-NpY"/>
+                                        </constraints>
+                                    </imageView>
+                                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="bdY-zI-TZJ">
+                                        <rect key="frame" x="0.0" y="79" width="375" height="1"/>
+                                        <color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
+                                        <constraints>
+                                            <constraint firstAttribute="height" constant="1" id="zta-Kz-EC1"/>
+                                        </constraints>
+                                    </view>
+                                    <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="IiW-IZ-kLv">
+                                        <rect key="frame" x="330" y="30" width="30" height="30"/>
+                                        <constraints>
+                                            <constraint firstAttribute="width" secondItem="IiW-IZ-kLv" secondAttribute="height" multiplier="1:1" id="C1Q-2R-uZJ"/>
+                                            <constraint firstAttribute="height" constant="30" id="HxY-pC-l1G"/>
+                                        </constraints>
+                                        <state key="normal" image="helpIcon"/>
+                                        <connections>
+                                            <action selector="infoButtonClicked:" destination="AiM-Wz-Nbc" eventType="touchUpInside" id="pI7-HX-6Ip"/>
+                                        </connections>
+                                    </button>
+                                </subviews>
+                                <color key="backgroundColor" white="0.9172712053571429" alpha="1" colorSpace="calibratedWhite"/>
+                                <constraints>
+                                    <constraint firstItem="bdY-zI-TZJ" firstAttribute="centerX" secondItem="zM4-XI-rpq" secondAttribute="centerX" id="4WE-n4-jUa"/>
+                                    <constraint firstAttribute="bottom" secondItem="bdY-zI-TZJ" secondAttribute="bottom" id="JpR-Da-t4t"/>
+                                    <constraint firstItem="vIm-X5-lfm" firstAttribute="height" secondItem="zM4-XI-rpq" secondAttribute="height" constant="-10" id="N0v-MG-jtz"/>
+                                    <constraint firstItem="vIm-X5-lfm" firstAttribute="centerX" secondItem="zM4-XI-rpq" secondAttribute="centerX" id="bwl-EX-8kn"/>
+                                    <constraint firstAttribute="height" constant="80" id="p7U-to-qu5"/>
+                                    <constraint firstItem="vIm-X5-lfm" firstAttribute="top" secondItem="zM4-XI-rpq" secondAttribute="top" constant="10" id="rMI-ck-J5L"/>
+                                    <constraint firstAttribute="trailing" secondItem="IiW-IZ-kLv" secondAttribute="trailing" constant="15" id="ro2-aG-nEJ"/>
+                                    <constraint firstItem="bdY-zI-TZJ" firstAttribute="width" secondItem="zM4-XI-rpq" secondAttribute="width" id="xbk-eO-152"/>
+                                    <constraint firstItem="IiW-IZ-kLv" firstAttribute="centerY" secondItem="vIm-X5-lfm" secondAttribute="centerY" id="zlb-0L-lnh"/>
+                                </constraints>
+                                <userDefinedRuntimeAttributes>
+                                    <userDefinedRuntimeAttribute type="number" keyPath="layer.shadowOpacity">
+                                        <real key="value" value="0.29999999999999999"/>
+                                    </userDefinedRuntimeAttribute>
+                                    <userDefinedRuntimeAttribute type="number" keyPath="layer.shadowRadius">
+                                        <integer key="value" value="5"/>
+                                    </userDefinedRuntimeAttribute>
+                                    <userDefinedRuntimeAttribute type="size" keyPath="layer.shadowOffset">
+                                        <size key="value" width="0.0" height="2"/>
+                                    </userDefinedRuntimeAttribute>
+                                </userDefinedRuntimeAttributes>
+                            </view>
+                            <button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="hof-ff-lco">
+                                <rect key="frame" x="137.5" y="547" width="100" height="100"/>
+                                <color key="backgroundColor" red="0.14509803921568626" green="0.44705882352941173" blue="0.74509803921568629" alpha="1" colorSpace="calibratedRGB"/>
+                                <constraints>
+                                    <constraint firstAttribute="width" secondItem="hof-ff-lco" secondAttribute="height" id="7uW-Ze-xnn"/>
+                                    <constraint firstAttribute="width" constant="100" id="Tvh-yw-2wc"/>
+                                </constraints>
+                                <userDefinedRuntimeAttributes>
+                                    <userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
+                                        <integer key="value" value="50"/>
+                                    </userDefinedRuntimeAttribute>
+                                </userDefinedRuntimeAttributes>
+                                <connections>
+                                    <action selector="chatButtonDragExit:" destination="AiM-Wz-Nbc" eventType="touchDragExit" id="tzn-Hr-fHx"/>
+                                    <action selector="chatButtonTouchDown:" destination="AiM-Wz-Nbc" eventType="touchDown" id="ix9-Go-pGW"/>
+                                    <action selector="chatButtonTouchUpInside:" destination="AiM-Wz-Nbc" eventType="touchUpInside" id="qnd-Rp-1nE"/>
+                                </connections>
+                            </button>
+                            <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="microphone" translatesAutoresizingMaskIntoConstraints="NO" id="lDX-Ql-z9N">
+                                <rect key="frame" x="155" y="565" width="65" height="65"/>
+                                <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                <constraints>
+                                    <constraint firstAttribute="width" secondItem="lDX-Ql-z9N" secondAttribute="height" multiplier="1:1" id="4Rk-9C-P28"/>
+                                </constraints>
+                            </imageView>
+                            <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="bMZ-yK-qYE">
+                                <rect key="frame" x="160" y="570" width="55" height="55"/>
+                                <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                <userDefinedRuntimeAttributes>
+                                    <userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
+                                        <integer key="value" value="10"/>
+                                    </userDefinedRuntimeAttribute>
+                                </userDefinedRuntimeAttributes>
+                            </imageView>
+                            <containerView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="FG9-wO-NqF">
+                                <rect key="frame" x="0.0" y="80" width="375" height="587"/>
+                                <connections>
+                                    <segue destination="1AA-BR-TlZ" kind="embed" id="HZC-AC-0q9"/>
+                                </connections>
+                            </containerView>
+                        </subviews>
+                        <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                        <constraints>
+                            <constraint firstItem="bMZ-yK-qYE" firstAttribute="centerX" secondItem="lDX-Ql-z9N" secondAttribute="centerX" id="1Mn-7d-V5o"/>
+                            <constraint firstItem="bMZ-yK-qYE" firstAttribute="centerY" secondItem="lDX-Ql-z9N" secondAttribute="centerY" id="750-Aw-AJG"/>
+                            <constraint firstItem="FG9-wO-NqF" firstAttribute="centerX" secondItem="vtI-ht-JBE" secondAttribute="centerX" id="KVs-8L-CGG"/>
+                            <constraint firstItem="FG9-wO-NqF" firstAttribute="top" secondItem="zM4-XI-rpq" secondAttribute="bottom" id="PX7-4j-63e"/>
+                            <constraint firstItem="lDX-Ql-z9N" firstAttribute="centerX" secondItem="hof-ff-lco" secondAttribute="centerX" id="PzF-Wf-J0T"/>
+                            <constraint firstItem="hof-ff-lco" firstAttribute="centerX" secondItem="vtI-ht-JBE" secondAttribute="centerX" id="Sll-IW-YmO"/>
+                            <constraint firstItem="Bpr-87-BHC" firstAttribute="top" secondItem="hof-ff-lco" secondAttribute="bottom" constant="20" id="bKi-CO-tnw"/>
+                            <constraint firstItem="zM4-XI-rpq" firstAttribute="top" secondItem="vtI-ht-JBE" secondAttribute="top" id="dfG-Dx-agC"/>
+                            <constraint firstItem="zM4-XI-rpq" firstAttribute="centerX" secondItem="vtI-ht-JBE" secondAttribute="centerX" id="dpS-q9-JI3"/>
+                            <constraint firstItem="lDX-Ql-z9N" firstAttribute="centerY" secondItem="hof-ff-lco" secondAttribute="centerY" id="hmE-yf-NoP"/>
+                            <constraint firstItem="Bpr-87-BHC" firstAttribute="top" secondItem="FG9-wO-NqF" secondAttribute="bottom" id="k2W-5N-VBR"/>
+                            <constraint firstItem="FG9-wO-NqF" firstAttribute="width" secondItem="vtI-ht-JBE" secondAttribute="width" id="l0V-S1-I31"/>
+                            <constraint firstItem="zM4-XI-rpq" firstAttribute="width" secondItem="vtI-ht-JBE" secondAttribute="width" id="lpC-LT-BMd"/>
+                            <constraint firstItem="bMZ-yK-qYE" firstAttribute="width" secondItem="lDX-Ql-z9N" secondAttribute="width" constant="-10" id="mKh-sR-owK"/>
+                            <constraint firstItem="lDX-Ql-z9N" firstAttribute="height" secondItem="hof-ff-lco" secondAttribute="height" constant="-35" id="x5Z-pn-Rcp"/>
+                            <constraint firstItem="bMZ-yK-qYE" firstAttribute="height" secondItem="lDX-Ql-z9N" secondAttribute="height" constant="-10" id="xcm-IW-mcd"/>
+                        </constraints>
+                    </view>
+                    <connections>
+                        <outlet property="chatButton" destination="hof-ff-lco" id="Ws1-eo-jS9"/>
+                        <outlet property="microphoneImage" destination="lDX-Ql-z9N" id="8V8-cz-gxk"/>
+                        <outlet property="stopImage" destination="bMZ-yK-qYE" id="qlf-Md-jyy"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="nIl-Od-0L1" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="428" y="115.59220389805098"/>
+        </scene>
+        <!--Chat Bot View Controller-->
+        <scene sceneID="383-b2-HOH">
+            <objects>
+                <viewController id="1AA-BR-TlZ" customClass="ChatBotViewController" customModule="WhiskBot" customModuleProvider="target" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="Lwa-ey-ClN"/>
+                        <viewControllerLayoutGuide type="bottom" id="Kcj-5Y-cV5"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="7YH-Nt-Prr">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="587"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                    </view>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="mPR-ub-xCQ" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="534" y="789"/>
+        </scene>
+    </scenes>
+    <resources>
+        <image name="IBMLogo" width="2000" height="800"/>
+        <image name="helpIcon" width="100" height="100"/>
+        <image name="microphone" width="100" height="100"/>
+        <image name="splashbg" width="3000" height="1688"/>
+    </resources>
+</document>
diff --git a/whiskbot-demo-app/WhiskBot/ChatBotViewController.swift b/whiskbot-demo-app/WhiskBot/ChatBotViewController.swift
new file mode 100644
index 0000000..3767308
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/ChatBotViewController.swift
@@ -0,0 +1,285 @@
+/*
+ * Copyright 2015-2016 IBM Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+//
+//  ChatBotViewController.swift
+//  WhiskBot
+//
+//  Created by whisk on 1/18/17.
+//  Copyright © 2017 Avery Lamp. All rights reserved.
+//
+
+import UIKit
+import JSQMessagesViewController
+import OpenWhisk
+import SwiftyJSON
+import EventKit
+
+class ChatBotViewController: JSQMessagesViewController, appleSpeechFeedbackProtocall{
+    
+    var messageData = [JSQMessage]()
+    
+    var context: JSON? // save context to continue conversation
+    var whisk: Whisk?
+    
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        
+        if let path = Bundle.main.path(forResource: "IBMConstants", ofType: "plist"), let dict = NSDictionary(contentsOfFile: path) as? [String: AnyObject], let accessKey = dict["whisk_access_key"] as? String, accessKey != "", let accessToken = dict["whisk_access_token"] as? String, accessToken != "" {
+            let whiskCreds = WhiskCredentials(accessKey: accessKey, accessToken: accessToken)
+            whisk = Whisk(credentials: whiskCreds)
+            
+        }else{
+            print("IBM OpenWhisk Credentials not found")
+        }
+        
+        self.senderId = "User"
+        self.senderDisplayName = "Client"
+        self.finishSendingMessage(animated: true)
+        
+        initialMessageFromConversation()
+        speechRecognizer.setupSpeechRecognition()
+        speechRecognizer.delegate = self
+    }
+    
+    override func viewDidAppear(_ animated: Bool) {
+        super.viewDidAppear(animated)
+        self.eventStore = EKEventStore()
+        self.reminders = [EKReminder]()
+        
+        self.eventStore.requestAccess(to: .reminder) { (granted, error) in
+            if granted{
+                let predicate = self.eventStore.predicateForReminders(in: nil)
+                self.eventStore.fetchReminders(matching: predicate, completion: { (reminders) in
+                    self.reminders = reminders
+                })
+            }else {
+                print("Permission not granted for reminders")
+            }
+        }
+    }
+    
+    func initialMessageFromConversation(){
+        
+        let initialMessageParam = [String:Any]()
+        do{
+            try whisk?.invokeAction(name: "Conversation", package: "", namespace: "", parameters: initialMessageParam as AnyObject?, hasResult: true, callback: { (result, error) in
+                if error == nil{
+                    let jsonResult = JSON(result!)
+                    //print("Result - \(jsonResult["result"]["output"]["text"])")
+                    let incomingString = jsonResult["result"]["output"]["text"].arrayObject?.first as? String
+                    let incomingMessage = JSQMessage(senderId: "Bluemix", displayName: "Bluemix", text: incomingString)
+                    self.messageData.append(incomingMessage!)
+                    DispatchQueue.main.async {
+                        self.finishSendingMessage(animated: true)
+                        self.context = jsonResult["result"]["context"]
+                        self.context?["current_slack_channel"] = "general"
+                        self.context?["last_reminder_text"] = "Reminder text"
+                    }
+                }else{
+                    print("error invoking - \(error)")
+                }
+            })
+        }catch{
+            print("Error thrown invoking whisk action")
+        }
+        
+    }
+    
+    override func didPressSend(_ button: UIButton!, withMessageText text: String!, senderId: String!, senderDisplayName: String!, date: Date!) {
+        
+        print("Send message - \(text)")
+        messageData.append(JSQMessage(senderId: "User", displayName: "Client", text: text))
+        
+        var initialMessageParam = [String:Any]()
+        initialMessageParam["input"] = ["text":text]
+        initialMessageParam["context"] = self.context?.dictionaryObject
+        //print("Context - \(self.context?.dictionaryObject)")
+        do{
+            try whisk?.invokeAction(name: "Conversation", package: "", namespace: "", parameters: initialMessageParam as AnyObject?, hasResult: true, callback: { (result, error) in
+                if error == nil{
+                    
+                    let jsonResult = JSON(result!)
+                    let incomingString = jsonResult["result"]["output"]["text"].arrayObject?.first as? String
+                    if incomingString != nil && incomingString != "" {
+                        let incomingMessage = JSQMessage(senderId: "Bluemix", displayName: "Bluemix", text: incomingString)
+                        self.messageData.append(incomingMessage!)
+                        DispatchQueue.main.async {
+                            self.finishSendingMessage(animated: true)
+                            self.context = jsonResult["result"]["context"]
+                            self.processActions(text: text, jsonResult: jsonResult)
+                            if (incomingString?.contains("Translation -"))! {
+                                let timeAfterOpen = 1.0
+                                DispatchQueue.main.asyncAfter(
+                                    deadline: DispatchTime.now() + Double(Int64(timeAfterOpen * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), execute: {
+                                        print("Followup")
+                                        let followUpMessage = JSQMessage(senderId: "Bluemix", displayName: "Bluemix", text: "Is there anything else you would like me to do?")
+                                        self.messageData.append(followUpMessage!)
+                                        self.finishSendingMessage(animated: true)
+                                })
+
+                            }
+                        }
+                    }
+                    
+                }else{
+                    print("error invoking - \(error)")
+                }
+            })
+        }catch{
+            
+            print("Error thrown invoking whisk action")
+        }
+        self.finishSendingMessage(animated: true)
+    }
+    
+    func processActions(text: String, jsonResult: JSON){
+        let lastNodeVisited = jsonResult["result"]["output"]["nodes_visited"].arrayObject?.first! as? String
+        print("Last Node - \(lastNodeVisited)")
+        
+        if lastNodeVisited == "Reminder Text" {
+            self.context?["last_reminder_text"].string = text
+        }
+        
+        if lastNodeVisited == "Reminder Time" {
+            let entities =  jsonResult["result"]["entities"]
+            var dateString = ""
+            var timeString = ""
+            
+            for entity in entities.arrayObject!{
+                if let dict = entity as? [String:Any]{
+                    if dict["entity"] as? String == "sys-time" {
+                        print("Sys-time - \(dict["value"] as! String)")
+                        timeString = dict["value"] as! String
+                    }
+                    if dict["entity"] as? String == "sys-date" {
+                        print("Sys-date - \(dict["value"] as! String)")
+                        dateString = dict["value"] as! String
+                    }
+                }
+            }
+            let todaysDate = Date()
+            let dateFormatter = DateFormatter()
+            dateFormatter.dateFormat = "yyyy-MM-dd"
+            if dateString == ""{
+                dateString = dateFormatter.string(from: todaysDate)
+            }
+            if timeString == "" {
+                timeString = "18:00:00"
+            }
+            dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
+            if let dateToRemind = dateFormatter.date(from: "\(dateString) \(timeString)"){
+                print("Date to remind - \(dateToRemind)")
+                self.createReminder(text: (self.context?["last_reminder_text"].string)!, date: dateToRemind)
+            }
+        }
+    }
+    
+    var isListening = false
+    var textBeforeSpeech = ""
+    var speechRecognizer = SpeechRecognizer()
+    override func didPressAccessoryButton(_ sender: UIButton!) {
+        print("Accessory button pressed")
+        isListening = true
+        
+        speechRecognizer.startRecording()
+        
+    }
+    
+    //MARK : - UICollectionView Data source
+    
+    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
+        return self.messageData.count
+    }
+    
+    override func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
+        let cell = super.collectionView(collectionView, cellForItemAt: indexPath) as! JSQMessagesCollectionViewCell
+        let message = self.messageData[indexPath.item]
+        if !message.isMediaMessage{
+            cell.textView.textColor = UIColor.black
+        }
+    }
+    
+    override func collectionView(_ collectionView: JSQMessagesCollectionView!, messageDataForItemAt indexPath: IndexPath!) -> JSQMessageData! {
+        return messageData[indexPath.item]
+    }
+    
+    override func collectionView(_ collectionView: JSQMessagesCollectionView!, messageBubbleImageDataForItemAt indexPath: IndexPath!) -> JSQMessageBubbleImageDataSource! {
+        let message = self.messageData[indexPath.item]
+        let bubbleFactory = JSQMessagesBubbleImageFactory()
+        if message.senderId == self.senderId{
+            return bubbleFactory?.outgoingMessagesBubbleImage(with: UIColor.black)
+        }else{
+            return bubbleFactory?.incomingMessagesBubbleImage(with: UIColor.lightGray)
+        }
+    }
+    
+    override func collectionView(_ collectionView: JSQMessagesCollectionView!, avatarImageDataForItemAt indexPath: IndexPath!) -> JSQMessageAvatarImageDataSource! {
+        let message = self.messageData[indexPath.item]
+        
+        let  bluemixAvatar = JSQMessagesAvatarImageFactory.avatarImage(with: #imageLiteral(resourceName: "bluemixLogo"), diameter: 30)
+        let clientAvatar = JSQMessagesAvatarImageFactory.avatarImage(with: #imageLiteral(resourceName: "openwhiskLogo"), diameter: 30)
+        if message.senderId == self.senderId{
+            return clientAvatar
+        }else{
+            return bluemixAvatar
+        }
+    }
+    
+    var eventStore: EKEventStore!
+    var reminders: [EKReminder]!
+    
+    func createReminder(text: String, date: Date){
+        let dateFormatter = DateFormatter()
+        dateFormatter.dateFormat = "E, d, h:mm"
+        let alert  = UIAlertController(title: "Create Reminder?", message: "Would you like to create the reminder: \(text) - at \(dateFormatter.string(from: date))", preferredStyle: .actionSheet)
+        let confirmAction = UIAlertAction(title: "Yes", style: .default) { (action) in
+            let reminder = EKReminder(eventStore: self.eventStore)
+            reminder.title = text
+            reminder.calendar = self.eventStore.defaultCalendarForNewReminders()
+
+            reminder.addAlarm(EKAlarm(absoluteDate: date))
+            //reminder.completionDate = date
+            do {
+                try self.eventStore.save(reminder, commit: true)
+                print("Reminder set - \(text) - at \(dateFormatter.string(from: date))")
+            }catch{
+                print("Error creating and saving reminder - \(error)")
+            }
+        }
+        let cancelAction = UIAlertAction(title: "Cancel", style: .destructive) { (action) in
+            print("Reminder creation canceled")
+        }
+        alert.addAction(confirmAction)
+        alert.addAction(cancelAction)
+        
+        self.present(alert, animated: true, completion: nil)
+    }
+    
+    //MARK : - Speech Recognition Delegates
+    
+    func finalAppleRecognitionRecieved(phrase: String) {
+        print("Final Speech recieved - \(phrase)")
+    }
+    
+    func partialAppleRecognitionRecieved(phrase: String) {
+        print("Partial Speech recieved - \(phrase)")
+    }
+    
+    func errorAppleRecieved(error: String) {
+        print("SPEECH ERROR - \(error)")
+    }
+    
+}
diff --git a/whiskbot-demo-app/WhiskBot/ChatViewController.swift b/whiskbot-demo-app/WhiskBot/ChatViewController.swift
new file mode 100644
index 0000000..1cd1cf2
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/ChatViewController.swift
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2015-2016 IBM Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+//
+//  ChatViewController.swift
+//  WhiskBot
+//
+//  Created by whisk on 1/17/17.
+//  Copyright © 2017 Avery Lamp. All rights reserved.
+//
+
+import UIKit
+
+class ChatViewController: UIViewController {
+    @IBOutlet weak var chatButton: UIButton!
+    @IBOutlet weak var stopImage: UIImageView!
+
+    @IBOutlet weak var microphoneImage: UIImageView!
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        chatButton.tintColor = UIColor.white
+        stopImage.alpha = 0.0
+    }
+    
+    @IBAction func infoButtonClicked(_ sender: Any) {
+        let storyboard = UIStoryboard(name: "Main", bundle: nil)
+        let splashVC = storyboard.instantiateViewController(withIdentifier: "splashVC")
+        self.present(splashVC, animated: true, completion: nil)
+    }
+    
+    
+    
+    var circleLayer: CAShapeLayer? = nil
+    @IBAction func chatButtonTouchDown(_ sender: Any) {
+        if circleLayer == nil {
+            circleLayer = CAShapeLayer()
+            
+            circleLayer?.path = UIBezierPath(roundedRect: CGRect(origin: CGPoint.zero, size: chatButton.frame.size), cornerRadius: chatButton.frame.width / 2).cgPath
+            circleLayer?.lineWidth = 3
+            circleLayer?.fillColor = nil
+            circleLayer?.strokeColor = UIColor.green.cgColor
+            circleLayer?.strokeEnd = 0.0
+            CATransaction.setAnimationDuration(0.0)
+            circleLayer?.strokeEnd = 0.0
+            chatButton.layer.addSublayer(circleLayer!)
+            
+        }
+        CATransaction.setAnimationDuration(1.0)
+        circleLayer?.strokeEnd = 1.0
+        UIView.animate(withDuration: 1.0) { 
+            self.microphoneImage.alpha = 0.0
+            self.stopImage.alpha = 1.0
+        }
+        print("Touch Down")
+    }
+    
+    @IBAction func chatButtonDragExit(_ sender: Any) {
+        CATransaction.setAnimationDuration(1.0)
+        circleLayer?.strokeEnd = 0.0
+        UIView.animate(withDuration: 1.0) {
+            self.microphoneImage.alpha = 1.0
+            self.stopImage.alpha = 0.0
+        }
+        print("Drag Exit")
+    }
+    
+    @IBAction func chatButtonTouchUpInside(_ sender: Any) {
+        CATransaction.setAnimationDuration(1.0)
+        circleLayer?.strokeEnd = 0.0
+        UIView.animate(withDuration: 1.0) {
+            self.microphoneImage.alpha = 1.0
+            self.stopImage.alpha = 0.0
+        }
+        print("Touch Up Inside")
+    }
+    
+}
+
diff --git a/whiskbot-demo-app/WhiskBot/IBMConstants.plist b/whiskbot-demo-app/WhiskBot/IBMConstants.plist
new file mode 100644
index 0000000..5b2178f
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/IBMConstants.plist
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>whisk_access_token</key>
+	<string></string>
+	<key>whisk_access_key</key>
+	<string></string>
+</dict>
+</plist>
diff --git a/whiskbot-demo-app/WhiskBot/Info.plist b/whiskbot-demo-app/WhiskBot/Info.plist
new file mode 100644
index 0000000..68cc577
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/Info.plist
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>en</string>
+	<key>CFBundleExecutable</key>
+	<string>$(EXECUTABLE_NAME)</string>
+	<key>CFBundleIdentifier</key>
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>$(PRODUCT_NAME)</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>1.0</string>
+	<key>CFBundleVersion</key>
+	<string>1</string>
+	<key>LSRequiresIPhoneOS</key>
+	<true/>
+	<key>UILaunchStoryboardName</key>
+	<string>LaunchScreen</string>
+	<key>UIMainStoryboardFile</key>
+	<string>Main</string>
+	<key>UIRequiredDeviceCapabilities</key>
+	<array>
+		<string>armv7</string>
+	</array>
+	<key>UISupportedInterfaceOrientations</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+		<string>UIInterfaceOrientationLandscapeLeft</string>
+		<string>UIInterfaceOrientationLandscapeRight</string>
+	</array>
+	<key>NSAppTransportSecurity</key>
+	<dict>
+		<key>NSExceptionDomains</key>
+		<dict>
+			<key>watsonplatform.net</key>
+			<dict>
+				<key>NSTemporaryExceptionRequiresForwardSecrecy</key>
+				<false/>
+				<key>NSIncludesSubdomains</key>
+				<true/>
+				<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
+				<true/>
+				<key>NSTemporaryExceptionMinimumTLSVersion</key>
+				<string>TLSv1.0</string>
+			</dict>
+		</dict>
+	</dict>
+	<key>NSMicrophoneUsageDescription</key>
+	<string>We use the microphone to do speech to text for message input</string>
+	<key>NSSpeechRecognitionUsageDescription</key>
+	<string>Speech recognition will be used to translate your speech into text to reply to messages</string>
+	<key>NSRemindersUsageDescription</key>
+	<string>Create and save reminders</string>
+</dict>
+</plist>
diff --git a/whiskbot-demo-app/WhiskBot/OpenWhiskActions/ConversationAction.swift b/whiskbot-demo-app/WhiskBot/OpenWhiskActions/ConversationAction.swift
new file mode 100644
index 0000000..0deddd5
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/OpenWhiskActions/ConversationAction.swift
@@ -0,0 +1,279 @@
+/*
+ * Copyright 2015-2016 IBM Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import KituraNet
+import Dispatch
+import Foundation
+import SwiftyJSON
+
+// MARK: - Constants
+private func getConstants(key: String)->String? {
+    var constants = [String:String]()
+    
+    
+    
+    // Conversation
+    constants["conversation_username"] = <#conversation_username#>
+    //Does not require Colon seperating username and password
+    constants["conversation_password"] = <#conversation_password#>
+    constants["conversation_workspace_id"] = <#conversation_workspace_id#>
+
+    // Translation
+    constants["translation_username"] = <#translation_username#>
+    constants["translation_password"] = <#translation_password#>
+    constants["translation_from_language"] = "en"
+    
+    // Translation supportedLanguages
+    // -  In order to add more languages, check if they are supported (https://www.ibm.com/watson/developercloud/language-translator.html)
+    // -  Add the language to the Entity @language, and modify the Dialog to be consistent with the language
+    constants["translation_language_spanish"] = "es"
+    constants["translation_language_french"] = "fr"
+    constants["translation_language_arabic"] = "ar"
+    constants["translation_language_korean"] = "ko"
+    
+    
+    // Modify the URL Hooks in order to post to different teams  (https://api.slack.com/incoming-webhooks)
+    // To add more channels, add them in the IBM Watson Conversation Entities, under @slack_channels.  Then add a response in Dialog for the different channels.
+    constants["slack_channel_url_general"] = <#slack_channel_url#>
+    constants["slack_channel_url_random"] = <#slack_channel_url#>
+    
+    return constants[key]
+}
+
+// MARK: - Main
+
+func main(args:[String:Any])-> [String:Any]{
+    var convoResponse: [String:Any]!
+    
+    print("Input recieved - \(args["input"])")
+    
+    let invokeGroup = DispatchGroup()
+    invokeGroup.enter()
+    
+    let queue = DispatchQueue(label: "PostRequestQueue", qos: DispatchQoS.userInitiated, attributes: .concurrent, autoreleaseFrequency: .inherit, target: nil)
+    
+    queue.async  {
+        
+        post(params:args){ result in
+            print("Post response recieved - \(result["output"])")
+            convoResponse = result
+            invokeGroup.leave()
+        }
+        
+    }
+    
+    switch invokeGroup.wait(timeout:DispatchTime.now() + 15) {
+    case DispatchTimeoutResult.success:
+        break
+    case DispatchTimeoutResult.timedOut:
+        convoResponse = ["Error":"Timeout"]
+        break
+    }
+    convoResponse =  checkForSlackPost(convoResponse: JSON(convoResponse)).dictionaryObject!
+    convoResponse =  checkForTranslation(convoResponse: JSON(convoResponse)).dictionaryObject!
+    return convoResponse
+    
+}
+
+private func checkForTranslation(convoResponse: JSON) -> JSON{
+    if convoResponse["output"]["nodes_visited"].arrayObject?.first! as? String  == "Language Choice"{
+        var editedResponse: JSON?
+        do{
+            editedResponse = try JSON(data: convoResponse.rawData())
+            let entities =  editedResponse?["entities"].arrayObject!
+            for entity in entities!{
+                if let dict = entity as? [String:Any]{
+                    if dict["entity"] as? String == "language" {
+                        let entityValue = dict["value"] as! String
+                        if let language = getConstants(key:"translation_language_\(entityValue.lowercased())") {
+                            editedResponse!["context"]["current_language_translation"].string = language
+                            print("Language detected - \(entityValue)")
+                        }else{
+                            print("Language not detected - Put spanish as default language")
+                            editedResponse!["context"]["current_language_translation"].string = "es"
+                        }
+                    }
+                }
+            }
+        }catch{
+            return convoResponse
+        }
+        return editedResponse!
+    }
+    
+    if convoResponse["output"]["nodes_visited"].arrayObject?.first! as? String  == "Translate Text", let text = convoResponse["input"]["text"].string, let language = convoResponse["context"]["current_language_translation"].string {
+        //print(convoResponse)
+        let translation = translateMessage(text: text, language: language)
+        var editedResponse: JSON?
+        do{
+            editedResponse = try JSON(data: convoResponse.rawData())
+            let currentOutput = editedResponse!["output"]["text"].arrayObject!.first as! String
+            print("Translation - \(translation) - \(currentOutput)")
+            editedResponse!["output"]["text"] = ["\(currentOutput) \(translation)"]
+            return editedResponse!
+        }catch {
+            print("Unable to edit JSON")
+            return convoResponse
+        }
+    }
+    return convoResponse
+}
+
+private func translateMessage(text:String, language: String) -> String{
+    var translatedMessage = ""
+    
+    print("Translating \(text) into - \(language)")
+    var initialParams = [String:Any]()
+    initialParams["payload"] = text
+    initialParams["translateTo"] = language
+    if let translateFrom = getConstants(key:"translation_from_language"), let translationUsername = getConstants(key:"translation_username"), let translationPassword = getConstants(key:"translation_password"){
+        initialParams["translateFrom"] = translateFrom
+        initialParams["username"] = translationUsername
+        initialParams["password"] = translationPassword
+        
+        let translation: JSON = JSON(Whisk.invoke(actionNamed: "TranslatorAction", withParameters: initialParams))
+        
+        if let translatedText =  translation["response"]["result"]["payload"].string {
+            translatedMessage = translatedText
+            print("Translated to - \(translatedText)")
+        }
+    }else{
+        print("Some of the required Translation constants were not found")
+    }
+    
+    return translatedMessage
+}
+
+private func checkForSlackPost(convoResponse: JSON) -> JSON{
+    
+    if convoResponse["output"]["nodes_visited"].arrayObject?.first! as? String  == "Slack Channel"{
+        var editedResponse: JSON?
+        do{
+            editedResponse = try JSON(data: convoResponse.rawData())
+            let entities =  editedResponse?["entities"].arrayObject!
+            for entity in entities!{
+                if let dict = entity as? [String:Any]{
+                    if dict["entity"] as? String == "slack_channels" {
+                        let slackChannel = dict["value"] as! String
+                        editedResponse!["context"]["current_slack_channel"].string = slackChannel
+                        print("Channel detected - \(slackChannel)")
+                    }
+                }
+            }
+        }catch{
+            return convoResponse
+        }
+        return editedResponse!
+    }
+    if convoResponse["output"]["nodes_visited"].arrayObject?.first! as? String  == "Slack Post Text", let text = convoResponse["input"]["text"].string, let channel = convoResponse["context"]["current_slack_channel"].string {
+        postToSlack(text: text, channel: channel)
+    }
+    
+    return convoResponse
+}
+
+private func postToSlack(text: String, channel: String){
+    print("Posting to Slack, channel - \(channel) - \(text)")
+    var initialMessageParam = [String:Any]()
+    initialMessageParam["text"] = text
+    initialMessageParam["channel"] = channel
+    initialMessageParam["username"] = "WhiskBot"
+    
+    if let channelURL = getConstants(key:"slack_channel_url_\(channel.lowercased())"){
+        initialMessageParam["url"] = channelURL
+        
+        if text.contains("to Slack"){
+            initialMessageParam["text"] = text.components(separatedBy: "to Slack").last
+        }
+        
+        Whisk.invoke(actionNamed: "PostToSlack", withParameters: initialMessageParam)
+    }else{
+        print("Slack Channel URL not found in constants")
+    }
+}
+
+private func post(params : [String:Any], callback : @escaping([String:Any]) -> Void) {
+    if let username = getConstants(key:"conversation_username"), let password = getConstants(key:"conversation_password"), let workspaceId = getConstants(key:"conversation_workspace_id"){
+        
+        print("Convo url - \("/conversation/api/v1/workspaces/\(workspaceId)/message?version=2017-01-18")")
+        
+        let authString = "\(username):\(password)"
+        
+        let authData = authString.data(using: String.Encoding.utf8)
+        let authValue = "Basic \(authData!.base64EncodedString())"
+        
+        
+        let headers = ["Content-Type" : "application/json",
+                       "Authorization" : authValue]
+        
+        
+        let requestOptions = [ClientRequest.Options.schema("https://"),
+                              ClientRequest.Options.method("POST"),
+                              ClientRequest.Options.hostname("gateway.watsonplatform.net"),
+                              ClientRequest.Options.port(443),
+                              ClientRequest.Options.path("/conversation/api/v1/workspaces/\(workspaceId)/message?version=2017-01-18"),
+                              ClientRequest.Options.headers(headers),
+                              ClientRequest.Options.disableSSLVerification]
+        
+        let request = HTTP.request(requestOptions) { response in
+            if response != nil {
+                do {
+                    // this is odd, but that's just how KituraNet has you get
+                    // the response as NSData
+                    var jsonData = Data()
+                    try response!.readAllData(into: &jsonData)
+                    
+                    //let resp = try JSONSerialization.jsonObject(with: jsonData, options: [])
+                    //callback(resp as! [String:Any])
+                    
+                    switch WhiskJsonUtils.getJsonType(jsonData: jsonData) {
+                    case .Dictionary:
+                        if let resp = WhiskJsonUtils.jsonDataToDictionary(jsonData: jsonData) {
+                            callback(resp)
+                        } else {
+                            callback(["error": "Could not parse a valid JSON response."])
+                            
+                        }
+                    case .Array:
+                        if let resp = WhiskJsonUtils.jsonDataToArray(jsonData: jsonData) {
+                            callback(["error": "Response is an array, expecting dictionary."])
+                        } else {
+                            callback(["error": "Could not parse a valid JSON response."])
+                            
+                        }
+                    case .Undefined:
+                        callback(["error": "Could not parse a valid JSON response."])
+                    }
+                } catch {
+                    callback(["error": "Could not parse a valid JSON response."])
+                }
+            } else {
+                callback(["error": "Did not receive a response."])
+            }
+        }
+        
+        // turn params into JSON data
+        if let jsonData = WhiskJsonUtils.dictionaryToJsonString(jsonDict: params) {
+            request.write(from: jsonData)
+            request.end()
+        } else {
+            callback(["error": "Could not parse parameters."])
+        }
+    }else{
+        print("You are missing a required constant to access the Conversation API")
+    }
+}
+
diff --git a/whiskbot-demo-app/WhiskBot/OpenWhiskActions/PostToSlack.js b/whiskbot-demo-app/WhiskBot/OpenWhiskActions/PostToSlack.js
new file mode 100644
index 0000000..35baf5a
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/OpenWhiskActions/PostToSlack.js
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2015-2016 IBM Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+var request = require('request');
+
+/**
+ *   Action to post to slack
+ *  @param {string} url - Slack webhook url
+ *  @param {string} channel - Slack channel to post the message to
+ *  @param {string} username - name to post the message as
+ *  @param {string} text - message to post
+ *  @param {string} icon_emoji - (optional) emoji to use as the icon for the message
+ *  @param {boolean} as_user - (optional) when the token belongs to a bot, whether to post as the bot itself
+ *  @param {object} attachments - (optional) message attachments (see Slack documentation for format)
+ *  @return {object} whisk async
+ */
+function main(params) {
+    var promise = new Promise(function (resolve, reject) {
+      checkParams(params, reject);
+
+      var body = {
+        channel: params.channel,
+        username: params.username || 'Simple Message Bot',
+        text: params.text
+      };
+
+      if (params.icon_emoji) {
+        // guard against sending icon_emoji: undefined
+        body.icon_emoji = params.icon_emoji;
+      }
+
+      if (params.token) {
+        //
+        // this allows us to support /api/chat.postMessage
+        // e.g. users can pass params.url = https://slack.com/api/chat.postMessage
+        //                 and params.token = <their auth token>
+        //
+        body.token = params.token;
+      } else {
+        //
+        // the webhook api expects a nested payload
+        //
+        // notice that we need to stringify; this is due to limitations
+        // of the formData npm: it does not handle nested objects
+        //
+        console.log(body);
+        console.log("to: " + params.url);
+
+        body = {
+          payload: JSON.stringify(body)
+        };
+      }
+
+      if (params.as_user === true) {
+          body.as_user = true;
+      }
+
+      if (params.attachments) {
+          body.attachments = params.attachments;
+      }
+
+      request.post({
+        url: params.url,
+        formData: body
+      }, function (err, res, body) {
+        if (err) {
+          console.log('error: ', err, body);
+          reject(err);
+        } else {
+          console.log('success: ', params.text, 'successfully sent');
+          resolve();
+        }
+      });
+    });
+
+    return promise;
+}
+
+/**
+Checks if all required params are set
+*/
+function checkParams(params, reject) {
+  if (params.text === undefined) {
+    reject('No text provided');
+  }
+  if (params.url === undefined) {
+	reject('No Webhook URL provided');
+  }
+  if (params.channel === undefined) {
+	reject('No channel provided');
+  }
+}
diff --git a/whiskbot-demo-app/WhiskBot/OpenWhiskActions/TranslatorAction.js b/whiskbot-demo-app/WhiskBot/OpenWhiskActions/TranslatorAction.js
new file mode 100644
index 0000000..e17ed4e
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/OpenWhiskActions/TranslatorAction.js
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2015-2016 IBM Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+var watson = require('watson-developer-cloud/language-translator/v2');
+
+/**
+ * Translate a string from one language to another.
+ *
+ * @param translateFrom The two digit code of the language to translate from.
+ * @param translateTo The two digit code of the language to translate to.
+ * @param translateParam The input parameter to translate. Defaults to 'payload'.
+ * @param username The Watson service username.
+ * @param password The Watson service password.
+ * @return The translateParam parameter with all values translated, or error if
+ * Watson service returns error
+ */
+function main(params) {
+    console.log('params:', params);
+
+    var from = params.translateFrom || 'en';
+    var to = params.translateTo || 'fr';
+    var translateParam = params.translateParam || 'payload';
+    var url = params.url || 'https://gateway.watsonplatform.net/language-translator/api';
+    var input = {};
+    input[translateParam] = params[translateParam];
+
+    var texts = getTextsToTranslate(input);
+    var promise = new Promise(function(resolve, reject) {
+        doTranslateTexts(texts, from, to, params.username, params.password, url, function (error, translatedTexts) {
+
+            if (error) {
+                reject(error);
+            } else {
+                var output = setTranslatedTexts(input, {translatedTexts: translatedTexts});
+                console.log('output:', JSON.stringify(output));
+                resolve(output);
+            }
+        });
+    });
+
+    return promise;
+}
+
+/**
+ * Return all the string values in an object.
+ *
+ * This will recursively traverse the object.
+ */
+function getTextsToTranslate(obj) {
+    var texts = [];
+    if (typeof obj === 'string') {
+        texts.push(obj);
+    } else if (typeof obj === 'object') {
+        for (var e in obj) {
+            var value = obj[e];
+            if (typeof value === 'string')
+                texts.push(value);
+            else if (typeof value === 'object')
+                texts = texts.concat(getTextsToTranslate(value));
+        }
+    }
+    return texts;
+}
+
+/**
+ * Set the string values in an object to the translated values.
+ *
+ * This will recursively traverse the object.
+ */
+function setTranslatedTexts(obj, translations) {
+    var translatedTexts = translations.translatedTexts || [];
+    var i = translations.start || 0;
+    if (typeof obj === 'string') {
+        obj = translatedTexts[i++];
+    } else if (typeof obj === 'object') {
+        for (var e in obj) {
+            var value = obj[e];
+            if (typeof value === 'string') {
+                obj[e] = translatedTexts[i++];
+            } else if (typeof value === 'object') {
+                var translations = {translatedTexts: translatedTexts, start: i};
+                setTranslatedTexts(value, translations);
+                i = translations.start;
+            }
+        }
+    }
+    translations.start = i;
+    return obj;
+}
+
+/**
+ * Translate an array of strings.
+ */
+function doTranslateTexts(texts, from, to, username, password, url, next) {
+    var translated = [];
+    var language_translation = new watson({
+        username: username,
+        password: password,
+        url: url
+    });
+    var options = { text: texts, source: from, target: to };
+    language_translation.translate(options, function (err, response) {
+        if (err) {
+            console.log('error:', err);
+            if (next) next(err, null)
+        } else {
+            var translation = response.translations[0].translation;
+            //console.log('response:', response);
+            for (var e in response.translations) {
+                translated.push(removeDiacritics(response.translations[e].translation));
+            }
+        }
+        if (next) next(null, translated);
+    });
+}
+
+/**
+ * Return a string with diacritics removed.
+ * From http://web.archive.org/web/20120918093154/http://lehelk.com/2011/05/06/script-to-remove-diacritics
+ */
+function removeDiacritics (str) {
+
+  var defaultDiacriticsRemovalMap = [
+    {'base':'A', 'letters':/[\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F]/g},
+    {'base':'AA','letters':/[\uA732]/g},
+    {'base':'AE','letters':/[\u00C6\u01FC\u01E2]/g},
+    {'base':'AO','letters':/[\uA734]/g},
+    {'base':'AU','letters':/[\uA736]/g},
+    {'base':'AV','letters':/[\uA738\uA73A]/g},
+    {'base':'AY','letters':/[\uA73C]/g},
+    {'base':'B', 'letters':/[\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181]/g},
+    {'base':'C', 'letters':/[\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E]/g},
+    {'base':'D', 'letters':/[\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779]/g},
+    {'base':'DZ','letters':/[\u01F1\u01C4]/g},
+    {'base':'Dz','letters':/[\u01F2\u01C5]/g},
+    {'base':'E', 'letters':/[\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E]/g},
+    {'base':'F', 'letters':/[\u0046\u24BB\uFF26\u1E1E\u0191\uA77B]/g},
+    {'base':'G', 'letters':/[\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E]/g},
+    {'base':'H', 'letters':/[\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D]/g},
+    {'base':'I', 'letters':/[\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197]/g},
+    {'base':'J', 'letters':/[\u004A\u24BF\uFF2A\u0134\u0248]/g},
+    {'base':'K', 'letters':/[\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2]/g},
+    {'base':'L', 'letters':/[\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780]/g},
+    {'base':'LJ','letters':/[\u01C7]/g},
+    {'base':'Lj','letters':/[\u01C8]/g},
+    {'base':'M', 'letters':/[\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C]/g},
+    {'base':'N', 'letters':/[\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4]/g},
+    {'base':'NJ','letters':/[\u01CA]/g},
+    {'base':'Nj','letters':/[\u01CB]/g},
+    {'base':'O', 'letters':/[\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u00D6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C]/g},
+    {'base':'OI','letters':/[\u01A2]/g},
+    {'base':'OO','letters':/[\uA74E]/g},
+    {'base':'OU','letters':/[\u0222]/g},
+    {'base':'P', 'letters':/[\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754]/g},
+    {'base':'Q', 'letters':/[\u0051\u24C6\uFF31\uA756\uA758\u024A]/g},
+    {'base':'R', 'letters':/[\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782]/g},
+    {'base':'S', 'letters':/[\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784]/g},
+    {'base':'T', 'letters':/[\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786]/g},
+    {'base':'TZ','letters':/[\uA728]/g},
+    {'base':'U', 'letters':/[\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u00DC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244]/g},
+    {'base':'V', 'letters':/[\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245]/g},
+    {'base':'VY','letters':/[\uA760]/g},
+    {'base':'W', 'letters':/[\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72]/g},
+    {'base':'X', 'letters':/[\u0058\u24CD\uFF38\u1E8A\u1E8C]/g},
+    {'base':'Y', 'letters':/[\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE]/g},
+    {'base':'Z', 'letters':/[\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762]/g},
+    {'base':'a', 'letters':/[\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250]/g},
+    {'base':'aa','letters':/[\uA733]/g},
+    {'base':'ae','letters':/[\u00E6\u01FD\u01E3]/g},
+    {'base':'ao','letters':/[\uA735]/g},
+    {'base':'au','letters':/[\uA737]/g},
+    {'base':'av','letters':/[\uA739\uA73B]/g},
+    {'base':'ay','letters':/[\uA73D]/g},
+    {'base':'b', 'letters':/[\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253]/g},
+    {'base':'c', 'letters':/[\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184]/g},
+    {'base':'d', 'letters':/[\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A]/g},
+    {'base':'dz','letters':/[\u01F3\u01C6]/g},
+    {'base':'e', 'letters':/[\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD]/g},
+    {'base':'f', 'letters':/[\u0066\u24D5\uFF46\u1E1F\u0192\uA77C]/g},
+    {'base':'g', 'letters':/[\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F]/g},
+    {'base':'h', 'letters':/[\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265]/g},
+    {'base':'hv','letters':/[\u0195]/g},
+    {'base':'i', 'letters':/[\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131]/g},
+    {'base':'j', 'letters':/[\u006A\u24D9\uFF4A\u0135\u01F0\u0249]/g},
+    {'base':'k', 'letters':/[\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3]/g},
+    {'base':'l', 'letters':/[\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747]/g},
+    {'base':'lj','letters':/[\u01C9]/g},
+    {'base':'m', 'letters':/[\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F]/g},
+    {'base':'n', 'letters':/[\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5]/g},
+    {'base':'nj','letters':/[\u01CC]/g},
+    {'base':'o', 'letters':/[\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u00F6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275]/g},
+    {'base':'oi','letters':/[\u01A3]/g},
+    {'base':'ou','letters':/[\u0223]/g},
+    {'base':'oo','letters':/[\uA74F]/g},
+    {'base':'p','letters':/[\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755]/g},
+    {'base':'q','letters':/[\u0071\u24E0\uFF51\u024B\uA757\uA759]/g},
+    {'base':'r','letters':/[\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783]/g},
+    {'base':'s','letters':/[\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B]/g},
+    {'base':'t','letters':/[\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787]/g},
+    {'base':'tz','letters':/[\uA729]/g},
+    {'base':'u','letters':/[\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u00FC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289]/g},
+    {'base':'v','letters':/[\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C]/g},
+    {'base':'vy','letters':/[\uA761]/g},
+    {'base':'w','letters':/[\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73]/g},
+    {'base':'x','letters':/[\u0078\u24E7\uFF58\u1E8B\u1E8D]/g},
+    {'base':'y','letters':/[\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF]/g},
+    {'base':'z','letters':/[\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763]/g}
+  ];
+
+  for(var i=0; i<defaultDiacriticsRemovalMap.length; i++) {
+    str = str.replace(defaultDiacriticsRemovalMap[i].letters, defaultDiacriticsRemovalMap[i].base);
+  }
+
+  return str;
+
+}
diff --git a/whiskbot-demo-app/WhiskBot/SpeechRecognizer.swift b/whiskbot-demo-app/WhiskBot/SpeechRecognizer.swift
new file mode 100644
index 0000000..debd221
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/SpeechRecognizer.swift
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2015-2016 IBM Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+//
+//  SpeechRecognizer.swift
+//  WhiskBot
+//
+//  Created by whisk on 1/18/17.
+//  Copyright © 2017 Avery Lamp. All rights reserved.
+//
+
+import UIKit
+import Speech
+
+protocol appleSpeechFeedbackProtocall: class {
+    func finalAppleRecognitionRecieved( phrase: String)
+    func partialAppleRecognitionRecieved( phrase: String)
+    func errorAppleRecieved(error: String)
+}
+
+
+class SpeechRecognizer: NSObject, SFSpeechRecognizerDelegate  {
+    
+    let speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "en-US"))
+    var recognitionRequest : SFSpeechAudioBufferRecognitionRequest?
+    var recognitionTask : SFSpeechRecognitionTask?
+    let audioEngine = AVAudioEngine()
+    
+    var delegate: appleSpeechFeedbackProtocall?
+    var speechAuthorized = false
+    var isRecording = false
+    
+    func setupSpeechRecognition(){
+        speechRecognizer?.delegate = self
+        
+        SFSpeechRecognizer.requestAuthorization { (authStatus) in
+            
+            OperationQueue.main.addOperation {
+                switch authStatus{
+                case .authorized:
+                    print("Recording Authorized")
+                    self.speechAuthorized = true
+                case .denied:
+                    print("Recording Denied")
+                default:
+                    print("Something went wrong")
+                }
+            }
+        }
+    }
+    
+    func startRecording() {
+        if isRecording{
+            isRecording = false
+            self.audioEngine.stop()
+            audioEngine.inputNode?.removeTap(onBus: 0)
+            self.recognitionRequest = nil
+            self.recognitionTask = nil
+            print("Stopped Recording")
+            return
+        }else{
+            print("Started Recording")
+            isRecording = true
+        }
+        if speechAuthorized == false{
+            setupSpeechRecognition()
+        }
+        if recognitionTask != nil {
+            recognitionTask?.cancel()
+            recognitionTask = nil
+        }
+        
+        let audioSession = AVAudioSession.sharedInstance()
+        do {
+            try audioSession.setCategory(AVAudioSessionCategoryRecord)
+            try audioSession.setMode(AVAudioSessionModeMeasurement)
+            try  audioSession.setActive(true, with: .notifyOthersOnDeactivation)
+        }catch {
+            print("Error creating audio session")
+        }
+        
+        recognitionRequest = SFSpeechAudioBufferRecognitionRequest()
+        
+        guard let input = audioEngine.inputNode else { fatalError("Audio Engine has no input") }
+        guard let recognitionRequest = recognitionRequest else { fatalError("Unable to create SFSpeechAudioBuffer") }
+        
+        recognitionRequest.shouldReportPartialResults = true
+        recognitionTask = speechRecognizer?.recognitionTask(with: recognitionRequest, resultHandler: { (result, error) in
+            if let result = result {
+                for transcription in result.transcriptions {
+                    print(transcription.formattedString)
+                }
+                let partialText = result.bestTranscription.formattedString
+                if result.isFinal == true {
+                    self.audioEngine.stop()
+                    input.removeTap(onBus: 0)
+                    self.recognitionRequest = nil
+                    self.recognitionTask = nil
+                    self.delegate?.finalAppleRecognitionRecieved(phrase: result.bestTranscription.formattedString)
+                }else{
+                    self.delegate?.partialAppleRecognitionRecieved(phrase: partialText)
+                }
+            }
+            
+            if error != nil {
+                print("Error recieved - \(error)")
+                self.delegate?.errorAppleRecieved(error: "\(error)")
+            }
+        })
+        
+        let recordingFormat = input.outputFormat(forBus: 0)
+        input.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { (buffer, time) in
+            self.recognitionRequest?.append(buffer)
+        }
+        
+        audioEngine.prepare()
+        
+        do {
+            try audioEngine.start()
+        }catch{
+            print("Unable to start audio engine")
+        }
+        
+    }
+
+}
diff --git a/whiskbot-demo-app/WhiskBot/SplashViewController.swift b/whiskbot-demo-app/WhiskBot/SplashViewController.swift
new file mode 100644
index 0000000..00b52f0
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/SplashViewController.swift
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2015-2016 IBM Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+//
+//  SplashViewController.swift
+//  WhiskBot
+//
+//  Created by whisk on 1/17/17.
+//  Copyright © 2017 Avery Lamp. All rights reserved.
+//
+
+import UIKit
+
+class SplashViewController: UIViewController, UIScrollViewDelegate {
+
+    @IBOutlet weak var scrollView: UIScrollView!
+    @IBOutlet weak var backgroundImage: UIImageView!
+    
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        scrollView.delegate = self
+        backgroundImage.frame = CGRect(x: 0, y: 0, width: self.view.frame.width * 2, height: self.view.frame.height)
+        backgroundImage.center.x = self.view.center.x + self.view.frame.width
+        
+        // Do any additional setup after loading the view.
+    }
+
+    func scrollViewDidScroll(_ scrollView: UIScrollView) {
+        let positionPercent = scrollView.contentOffset.x / ( scrollView.contentSize.width - self.view.frame.width)
+        backgroundImage.center.x = self.view.center.x + self.view.frame.width - self.view.frame.width * positionPercent
+        
+        
+    }
+    
+    override func didReceiveMemoryWarning() {
+        super.didReceiveMemoryWarning()
+        // Dispose of any resources that can be recreated.
+    }
+    
+    @IBAction func continueButtonClicked(_ sender: Any) {
+        /*
+        let chatVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ChatVC") as! ChatViewController
+        
+        self.present(chatVC, animated: true, completion: nil)
+        */
+        self.dismiss(animated: true, completion: nil)
+    }
+
+    /*
+    // MARK: - Navigation
+
+    // In a storyboard-based application, you will often want to do a little preparation before navigation
+    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
+        // Get the new view controller using segue.destinationViewController.
+        // Pass the selected object to the new view controller.
+    }
+    */
+
+}
diff --git a/whiskbot-demo-app/WhiskBot/ViewController.swift b/whiskbot-demo-app/WhiskBot/ViewController.swift
new file mode 100644
index 0000000..3b07d12
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBot/ViewController.swift
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2015-2016 IBM Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+//
+//  ViewController.swift
+//  WhiskBot
+//
+//  Created by whisk on 1/17/17.
+//  Copyright © 2017 Avery Lamp. All rights reserved.
+//
+
+import UIKit
+
+class ViewController: UIViewController {
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        // Do any additional setup after loading the view, typically from a nib.
+    }
+
+    override func didReceiveMemoryWarning() {
+        super.didReceiveMemoryWarning()
+        // Dispose of any resources that can be recreated.
+    }
+
+
+}
+
diff --git a/whiskbot-demo-app/WhiskBotDemoVideo.mp4 b/whiskbot-demo-app/WhiskBotDemoVideo.mp4
new file mode 100644
index 0000000..063bd50
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBotDemoVideo.mp4
Binary files differ
diff --git a/whiskbot-demo-app/WhiskBotTests/Info.plist b/whiskbot-demo-app/WhiskBotTests/Info.plist
new file mode 100644
index 0000000..6c6c23c
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBotTests/Info.plist
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>en</string>
+	<key>CFBundleExecutable</key>
+	<string>$(EXECUTABLE_NAME)</string>
+	<key>CFBundleIdentifier</key>
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>$(PRODUCT_NAME)</string>
+	<key>CFBundlePackageType</key>
+	<string>BNDL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>1.0</string>
+	<key>CFBundleVersion</key>
+	<string>1</string>
+</dict>
+</plist>
diff --git a/whiskbot-demo-app/WhiskBotTests/WhiskBotTests.swift b/whiskbot-demo-app/WhiskBotTests/WhiskBotTests.swift
new file mode 100644
index 0000000..d12c50f
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBotTests/WhiskBotTests.swift
@@ -0,0 +1,36 @@
+//
+//  WhiskBotTests.swift
+//  WhiskBotTests
+//
+//  Created by whisk on 1/17/17.
+//  Copyright © 2017 Avery Lamp. All rights reserved.
+//
+
+import XCTest
+@testable import WhiskBot
+
+class WhiskBotTests: XCTestCase {
+    
+    override func setUp() {
+        super.setUp()
+        // Put setup code here. This method is called before the invocation of each test method in the class.
+    }
+    
+    override func tearDown() {
+        // Put teardown code here. This method is called after the invocation of each test method in the class.
+        super.tearDown()
+    }
+    
+    func testExample() {
+        // This is an example of a functional test case.
+        // Use XCTAssert and related functions to verify your tests produce the correct results.
+    }
+    
+    func testPerformanceExample() {
+        // This is an example of a performance test case.
+        self.measure {
+            // Put the code you want to measure the time of here.
+        }
+    }
+    
+}
diff --git a/whiskbot-demo-app/WhiskBotUITests/Info.plist b/whiskbot-demo-app/WhiskBotUITests/Info.plist
new file mode 100644
index 0000000..6c6c23c
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBotUITests/Info.plist
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>en</string>
+	<key>CFBundleExecutable</key>
+	<string>$(EXECUTABLE_NAME)</string>
+	<key>CFBundleIdentifier</key>
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>$(PRODUCT_NAME)</string>
+	<key>CFBundlePackageType</key>
+	<string>BNDL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>1.0</string>
+	<key>CFBundleVersion</key>
+	<string>1</string>
+</dict>
+</plist>
diff --git a/whiskbot-demo-app/WhiskBotUITests/WhiskBotUITests.swift b/whiskbot-demo-app/WhiskBotUITests/WhiskBotUITests.swift
new file mode 100644
index 0000000..2327b15
--- /dev/null
+++ b/whiskbot-demo-app/WhiskBotUITests/WhiskBotUITests.swift
@@ -0,0 +1,36 @@
+//
+//  WhiskBotUITests.swift
+//  WhiskBotUITests
+//
+//  Created by whisk on 1/17/17.
+//  Copyright © 2017 Avery Lamp. All rights reserved.
+//
+
+import XCTest
+
+class WhiskBotUITests: XCTestCase {
+        
+    override func setUp() {
+        super.setUp()
+        
+        // Put setup code here. This method is called before the invocation of each test method in the class.
+        
+        // In UI tests it is usually best to stop immediately when a failure occurs.
+        continueAfterFailure = false
+        // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
+        XCUIApplication().launch()
+
+        // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
+    }
+    
+    override func tearDown() {
+        // Put teardown code here. This method is called after the invocation of each test method in the class.
+        super.tearDown()
+    }
+    
+    func testExample() {
+        // Use recording to get started writing UI tests.
+        // Use XCTAssert and related functions to verify your tests produce the correct results.
+    }
+    
+}
diff --git a/wsktools/WhiskSwiftTools/ConsoleIO.swift b/wsktools/WhiskSwiftTools/ConsoleIO.swift
index d9e6146..9f33df7 100644
--- a/wsktools/WhiskSwiftTools/ConsoleIO.swift
+++ b/wsktools/WhiskSwiftTools/ConsoleIO.swift
@@ -49,7 +49,7 @@
             self = .Target
         case "t":
             self = .Target
-
+            
             
         default:
             self = .Undefined
diff --git a/wsktools/WhiskSwiftTools/ProjectManager.swift b/wsktools/WhiskSwiftTools/ProjectManager.swift
index 2b7f728..5a66b3b 100644
--- a/wsktools/WhiskSwiftTools/ProjectManager.swift
+++ b/wsktools/WhiskSwiftTools/ProjectManager.swift
@@ -101,7 +101,7 @@
                         try self.projectReader?.readRootDependencies(false)
                     }
                     try self.projectReader?.readProjectDirectory()
-                   // self.projectReader?.dumpProjectStructure()
+                    // self.projectReader?.dumpProjectStructure()
                     
                     try self.deleteRules()
                     try self.deleteActionsAndSequences()
diff --git a/wsktools/WhiskSwiftTools/WhiskTokenizer.swift b/wsktools/WhiskSwiftTools/WhiskTokenizer.swift
index ecfdf41..a183333 100644
--- a/wsktools/WhiskSwiftTools/WhiskTokenizer.swift
+++ b/wsktools/WhiskSwiftTools/WhiskTokenizer.swift
@@ -161,6 +161,7 @@
         }
 
         
+        
         return (whiskActionArray, whiskTriggerArray, whiskRuleArray, whiskSequenceArray)
     }
     
@@ -328,4 +329,3 @@
     }
     
 }
-
diff --git a/xcode-playgrounds-extension/README.md b/xcode-playgrounds-extension/README.md
index 4576720..649e5ff 100644
--- a/xcode-playgrounds-extension/README.md
+++ b/xcode-playgrounds-extension/README.md
@@ -8,18 +8,25 @@
 
 To invoke the extension, simply select the function header then run the extension.
 
-![Highlighting function](/Readme_Images/SelectFunction.png)
+![Highlighting function](/xcode-playgrounds-extension/Readme_Images/SelectFunction.png)
 
 The extension can be found in the Editor Menu, under OWPlaygrounds.  
-![Run Extension from Editor menu](/Readme_Images/RunExtension.png)
+![Run Extension from Editor menu](/xcode-playgrounds-extension/Readme_Images/RunExtension.png)
 
 The first time the extension is run, it will create documentation for the function to populate the test.  
 
+### Playground
+
+In order to use the extension, the playground must be installed as well.  To install the playground, [go here](https://github.com/openwhisk/openwhisk-playground)
+
+The playground app must also be named openwhisk-playground-osx.app
+
+
 #### Parameters
 To input test values into the playground, the format `- paramName : description of parameter (optional) : param value for playground ` is used.  
 The parser looks only for `- paramName : : value`.  The description is not necessary, but the colons (:) seperating the paramName : Description : and test value are.  
 
-![Placeholders parameter example](/Readme_Images/DocumentationPlaceholders.png)
+![Placeholders parameter example](/xcode-playgrounds-extension/Readme_Images/DocumentationPlaceholders.png)
 
 If the extension does not find all of the  paramaters that are used in the function inside the documentation, it will recreate the documentation header.  
 
@@ -40,3 +47,15 @@
 One way to easily improve the speed of invoking the extension is to create a shortcut for it.  To do this, open Xcode Preferences -> Key Bindings, then search for OWPlaygrounds.  You can create your own shortcut to invoke the action.
 
 
+
+
+
+
+## License
+
+Copyright 2015-2016 IBM Corporation
+
+Licensed under the Apache License, Version 2.0 (the "License").
+
+Unless required by applicable law or agreed to in writing, software distributed under the license is distributed on an "as is" basis, without warranties or conditions of any kind, either express or implied. See the license for the specific language governing permissions and limitations under the license.
+
diff --git a/xcode-playgrounds-extension/Readme_Images/DocumentationFilled.png b/xcode-playgrounds-extension/Readme_Images/DocumentationFilled.png
new file mode 100644
index 0000000..d0423ce
--- /dev/null
+++ b/xcode-playgrounds-extension/Readme_Images/DocumentationFilled.png
Binary files differ