{"version":3,"file":"js/cj-ee4305e3883f65ea2392.js","sources":["webpack:///webpack/bootstrap","webpack:///./app/javascript/channels sync _channel\\.js$","webpack:///./app/javascript/channels/index.js","webpack:///./app/javascript/cj/card.js","webpack:///./app/javascript/cj/firebase/cj.js","webpack:///./app/javascript/cj/firebase/setup.js","webpack:///./app/javascript/cj/friends.js","webpack:///./app/javascript/cj/hellojs.js","webpack:///./app/javascript/cj/message.js","webpack:///./app/javascript/cj/ranking.js","webpack:///./app/javascript/cj/setup.js","webpack:///./app/javascript/cj/tourjs.js","webpack:///./app/javascript/cj/wall.js","webpack:///./app/javascript/cj/watcher.js","webpack:///./app/javascript/packs/cj.js","webpack:///./node_modules/@firebase/analytics/dist/index.esm.js","webpack:///./node_modules/@firebase/app/dist/index.cjs.js","webpack:///./node_modules/@firebase/auth/dist/auth.js","webpack:///./node_modules/@firebase/component/dist/index.cjs.js","webpack:///./node_modules/@firebase/database/dist/index.cjs.js","webpack:///./node_modules/@firebase/firestore/dist/index.cjs.js","webpack:///./node_modules/@firebase/functions/dist/index.cjs.js","webpack:///./node_modules/@firebase/installations/dist/index.esm.js","webpack:///./node_modules/@firebase/logger/dist/index.esm.js","webpack:///./node_modules/@firebase/messaging/dist/index.esm.js","webpack:///./node_modules/@firebase/performance/dist/index.cjs.js","webpack:///./node_modules/@firebase/remote-config/dist/index.cjs.js","webpack:///./node_modules/@firebase/storage/dist/index.esm.js","webpack:///./node_modules/@firebase/util/dist/index.cjs.js","webpack:///./node_modules/@firebase/webchannel-wrapper/dist/index.esm.js","webpack:///./node_modules/@rails/activestorage/app/assets/javascripts/activestorage.esm.js","webpack:///./node_modules/@rails/ujs/lib/assets/compiled/rails-ujs.js","webpack:///./node_modules/firebase/dist/index.cjs.js","webpack:///./node_modules/idb/build/idb.js","webpack:///./node_modules/jquery/dist/jquery.js","webpack:///./node_modules/process/browser.js","webpack:///./node_modules/setimmediate/setImmediate.js","webpack:///./node_modules/timers-browserify/main.js","webpack:///./node_modules/tslib/tslib.es6.js","webpack:///(webpack)/buildin/global.js","webpack:///(webpack)/buildin/module.js","webpack:///./vendor/cj/bootbox.js","webpack:///./vendor/cj/bootstrap.min.js","webpack:///./vendor/cj/moment/locale sync ^\\.\\/.*$","webpack:///./vendor/cj/moment/locale/af.js","webpack:///./vendor/cj/moment/locale/ar-dz.js","webpack:///./vendor/cj/moment/locale/ar-kw.js","webpack:///./vendor/cj/moment/locale/ar-ly.js","webpack:///./vendor/cj/moment/locale/ar-ma.js","webpack:///./vendor/cj/moment/locale/ar-sa.js","webpack:///./vendor/cj/moment/locale/ar-tn.js","webpack:///./vendor/cj/moment/locale/ar.js","webpack:///./vendor/cj/moment/locale/az.js","webpack:///./vendor/cj/moment/locale/be.js","webpack:///./vendor/cj/moment/locale/bg.js","webpack:///./vendor/cj/moment/locale/bn.js","webpack:///./vendor/cj/moment/locale/bo.js","webpack:///./vendor/cj/moment/locale/br.js","webpack:///./vendor/cj/moment/locale/bs.js","webpack:///./vendor/cj/moment/locale/ca.js","webpack:///./vendor/cj/moment/locale/cs.js","webpack:///./vendor/cj/moment/locale/cv.js","webpack:///./vendor/cj/moment/locale/cy.js","webpack:///./vendor/cj/moment/locale/da.js","webpack:///./vendor/cj/moment/locale/de-at.js","webpack:///./vendor/cj/moment/locale/de-ch.js","webpack:///./vendor/cj/moment/locale/de.js","webpack:///./vendor/cj/moment/locale/dv.js","webpack:///./vendor/cj/moment/locale/el.js","webpack:///./vendor/cj/moment/locale/en-au.js","webpack:///./vendor/cj/moment/locale/en-ca.js","webpack:///./vendor/cj/moment/locale/en-gb.js","webpack:///./vendor/cj/moment/locale/en-ie.js","webpack:///./vendor/cj/moment/locale/en-nz.js","webpack:///./vendor/cj/moment/locale/eo.js","webpack:///./vendor/cj/moment/locale/es-do.js","webpack:///./vendor/cj/moment/locale/es.js","webpack:///./vendor/cj/moment/locale/et.js","webpack:///./vendor/cj/moment/locale/eu.js","webpack:///./vendor/cj/moment/locale/fa.js","webpack:///./vendor/cj/moment/locale/fi.js","webpack:///./vendor/cj/moment/locale/fo.js","webpack:///./vendor/cj/moment/locale/fr-ca.js","webpack:///./vendor/cj/moment/locale/fr-ch.js","webpack:///./vendor/cj/moment/locale/fr.js","webpack:///./vendor/cj/moment/locale/fy.js","webpack:///./vendor/cj/moment/locale/gd.js","webpack:///./vendor/cj/moment/locale/gl.js","webpack:///./vendor/cj/moment/locale/gom-latn.js","webpack:///./vendor/cj/moment/locale/he.js","webpack:///./vendor/cj/moment/locale/hi.js","webpack:///./vendor/cj/moment/locale/hr.js","webpack:///./vendor/cj/moment/locale/hu.js","webpack:///./vendor/cj/moment/locale/hy-am.js","webpack:///./vendor/cj/moment/locale/id.js","webpack:///./vendor/cj/moment/locale/is.js","webpack:///./vendor/cj/moment/locale/it.js","webpack:///./vendor/cj/moment/locale/ja.js","webpack:///./vendor/cj/moment/locale/jv.js","webpack:///./vendor/cj/moment/locale/ka.js","webpack:///./vendor/cj/moment/locale/kk.js","webpack:///./vendor/cj/moment/locale/km.js","webpack:///./vendor/cj/moment/locale/kn.js","webpack:///./vendor/cj/moment/locale/ko.js","webpack:///./vendor/cj/moment/locale/ky.js","webpack:///./vendor/cj/moment/locale/lb.js","webpack:///./vendor/cj/moment/locale/lo.js","webpack:///./vendor/cj/moment/locale/lt.js","webpack:///./vendor/cj/moment/locale/lv.js","webpack:///./vendor/cj/moment/locale/me.js","webpack:///./vendor/cj/moment/locale/mi.js","webpack:///./vendor/cj/moment/locale/mk.js","webpack:///./vendor/cj/moment/locale/ml.js","webpack:///./vendor/cj/moment/locale/mr.js","webpack:///./vendor/cj/moment/locale/ms-my.js","webpack:///./vendor/cj/moment/locale/ms.js","webpack:///./vendor/cj/moment/locale/my.js","webpack:///./vendor/cj/moment/locale/nb.js","webpack:///./vendor/cj/moment/locale/ne.js","webpack:///./vendor/cj/moment/locale/nl-be.js","webpack:///./vendor/cj/moment/locale/nl.js","webpack:///./vendor/cj/moment/locale/nn.js","webpack:///./vendor/cj/moment/locale/pa-in.js","webpack:///./vendor/cj/moment/locale/pl.js","webpack:///./vendor/cj/moment/locale/pt-br.js","webpack:///./vendor/cj/moment/locale/pt.js","webpack:///./vendor/cj/moment/locale/ro.js","webpack:///./vendor/cj/moment/locale/ru.js","webpack:///./vendor/cj/moment/locale/sd.js","webpack:///./vendor/cj/moment/locale/se.js","webpack:///./vendor/cj/moment/locale/si.js","webpack:///./vendor/cj/moment/locale/sk.js","webpack:///./vendor/cj/moment/locale/sl.js","webpack:///./vendor/cj/moment/locale/sq.js","webpack:///./vendor/cj/moment/locale/sr-cyrl.js","webpack:///./vendor/cj/moment/locale/sr.js","webpack:///./vendor/cj/moment/locale/ss.js","webpack:///./vendor/cj/moment/locale/sv.js","webpack:///./vendor/cj/moment/locale/sw.js","webpack:///./vendor/cj/moment/locale/ta.js","webpack:///./vendor/cj/moment/locale/te.js","webpack:///./vendor/cj/moment/locale/tet.js","webpack:///./vendor/cj/moment/locale/th.js","webpack:///./vendor/cj/moment/locale/tl-ph.js","webpack:///./vendor/cj/moment/locale/tlh.js","webpack:///./vendor/cj/moment/locale/tr.js","webpack:///./vendor/cj/moment/locale/tzl.js","webpack:///./vendor/cj/moment/locale/tzm-latn.js","webpack:///./vendor/cj/moment/locale/tzm.js","webpack:///./vendor/cj/moment/locale/uk.js","webpack:///./vendor/cj/moment/locale/ur.js","webpack:///./vendor/cj/moment/locale/uz-latn.js","webpack:///./vendor/cj/moment/locale/uz.js","webpack:///./vendor/cj/moment/locale/vi.js","webpack:///./vendor/cj/moment/locale/x-pseudo.js","webpack:///./vendor/cj/moment/locale/yo.js","webpack:///./vendor/cj/moment/locale/zh-cn.js","webpack:///./vendor/cj/moment/locale/zh-hk.js","webpack:///./vendor/cj/moment/locale/zh-tw.js","webpack:///./vendor/cj/moment/moment.js","webpack:///./vendor/cj/nouislider/distribute/nouislider.js"],"sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"/packs/\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = \"./app/javascript/packs/cj.js\");\n","function webpackEmptyContext(req) {\n\tvar e = new Error(\"Cannot find module '\" + req + \"'\");\n\te.code = 'MODULE_NOT_FOUND';\n\tthrow e;\n}\nwebpackEmptyContext.keys = function() { return []; };\nwebpackEmptyContext.resolve = webpackEmptyContext;\nmodule.exports = webpackEmptyContext;\nwebpackEmptyContext.id = \"./app/javascript/channels sync recursive _channel\\\\.js$\";","// Load all the channels within this directory and all subdirectories.\n// Channel files must be named *_channel.js.\n\nconst channels = require.context('.', true, /_channel\\.js$/)\nchannels.keys().forEach(channels)\n","\n\n\nwindow.openCard = function(data) {\n event.preventDefault();\n \n var hidden = 1;\n $('.card').attr('id', data.card_id);\n card_id = '#' + data.card_id\n $('.card .header').css('background-image', 'url(' + data.user.image + ')');\n\n if(currentUser.user_id == data.card_id) {\n $('.remove-card').show();\n // $('.my-crush').hide();\n } else {\n $('.remove-card').hide();\n // $('.my-crush').show();\n\n }\n\n if(tour_id == '77'){\n snapUrl = 'https://images.gigafans.com/snapshot/' + tour_id + '/' + data.card_id + '/'+tour_id+'_'+currentUser.photo_id+'_'+data.card_id+'.png'; \n }\n\n\n // console.log(card_id)\n\n $(card_id + ' .profile').attr('src', data.user.image);\n $(card_id + ' .name').text(data.user.name);\n\n var provider = data.user.provider;\n if(provider == 'twitter.com') {\n \t// twitter\n \t$(card_id + ' .urlProfile').removeClass('facebook google instagram');\n $(card_id + ' .urlProfile').addClass('twitter');\n $(card_id + ' .urlProfile').attr('href', data.user.providerUrl);\n $(card_id + ' .urlProfile').attr('target', '_blank');\n } else if (provider == 'facebook.com') {\n \t// facebook\n \t$(card_id + ' .urlProfile').removeClass('twitter google instagram');\n $(card_id + ' .urlProfile').addClass('facebook');\n $(card_id + ' .urlProfile').attr('href', data.user.providerUrl);\n $(card_id + ' .urlProfile').attr('target', '_blank');\n }\n else if (provider == 'google.com') {\n \t// google\n \t$(card_id + ' .urlProfile').removeClass('facebook twitter instagram');\n $(card_id + ' .urlProfile').addClass('google');\n $(card_id + ' .urlProfile').attr('href', data.user.providerUrl);\n $(card_id + ' .urlProfile').attr('target', '_blank');\n }\n else if (provider == 'instagram.com') {\n \t// instagram\n \t$(card_id + ' .urlProfile').removeClass('facebook twitter google');\n $(card_id + ' .urlProfile').addClass('instagram');\n $(card_id + ' .urlProfile').attr('href', data.user.providerUrl);\n $(card_id + ' .urlProfile').attr('target', '_blank');\n }\n\n //status\n\n $(card_id + \" #total_views\").text(data.status.total_views);\n $(card_id + \" #total_comments\").text(data.status.total_comments);\n $(card_id + \" #total_likes\").text(data.status.total_likes);\n\n // Get Messages\n\n var messages = [];\n \n if (data.messages == null) {\n \t$(card_id + \" .card-message\").html('');\n \t$(card_id +' .card-message').append('
  • Você ainda não possui mensagens!
  • ');\n }\n else {\n\t $.each(data.messages, function (idx, obj) { \n // console.log(obj); \n\t messages += ('
  • ');\n\t messages += ('');\n\t messages += ('' + obj.user.name + '');\n\t messages += ('

    ' + obj.content + '

    ');\n\t messages += ('

    ' + obj.created + '

    ');\n messages += ('
  • ');\n\t });\n\t \t$(card_id +\" .card-message\").html(messages);\n \t}\n\n\n if(data.ilike == true ) {\n $('#like i').addClass('fa-thumbs-up');\n $('#like i').removeClass('fa-thumbs-o-up');\n } else {\n $('#like i').addClass('fa-thumbs-o-up');\n $('#like i').removeClass('fa-thumbs-up');\n }\n} \n \n\nwindow.updateCard = function (data, card_id) {\n card_id = '#' + card_id\n \n // status hotspot\n// console.log(data)\n $(card_id + \" #total_views\").text(data.status.total_views);\n $(card_id + \" #total_comments\").text(data.status.total_comments);\n $(card_id + ' #total_likes').text(data.status.total_likes);\n\n // Get Messages from cards \n\n var messages = '';\n \n if (data.messages == null) {\n $(card_id + \" .card-message\").html('');\n }\n else {\n $.each(data.messages, function (idx, obj) { \n messages += ('
  • ');\n messages += ('');\n messages += ('' + obj.user.name + '');\n messages += ('

    ' + obj.content + '

    ');\n messages += ('

    ' + obj.created + '

    ');\n messages += ('
  • ');\n });\n $(card_id + \" .card-message\").html(messages);\n }\n}\n\n\n\n$('.send-message').click(function(event) {\n event.preventDefault();\n var IDhotspot = $(this).parent().parent().attr('id');\n var content = $('input.message').val();\n if(currentUser.isAnonymous == false) {\n sendMessage(currentUser.user_id, IDhotspot, content);\n }\n else {\n $('.card footer input').attr('placeholder', 'Digite alguma mensagem!');\n $('.card footer i.fa-paper-plane').addClass('animated wobble');\n }\n});\n\n$('#like').click(function(event) {\n event.preventDefault();\n\n var IDhotspot = $(this).parent().parent().parent().parent().parent().attr('id');\n $('#like i').toggleClass('fa-thumbs-o-up fa-thumbs-up');\n\n sendLike(currentUser.user_id, IDhotspot);\n});\n \n// Send Like\n\nwindow.sendLike = function (user, id) {\n\n $.ajax({\n url: '/api/v1//tour/card/cards_like.json?tour_id=' + tour_id + '&user_id=' + user + '&card_id=' + id + '&photo_id=' + photo_id ,\n type: 'POST',\n success: function (data) {\n\n $('#total_likes').text(data)\n return false;\n },\n beforeSend: function () { },\n complete: function () {\n\n }\n });\n\n return false;\n}\n\n\n\n\n// Remove Card \n\n $('.remove-card').click(function(event) {\n\n _cardID = currentUser.user_id\n _cardName = 'brut'+_cardID;\n\n bootbox.confirm({\n message: \"Tem certeza que deseja remover sua marcação?\",\n buttons: {\n confirm: {\n label: 'Sim',\n className: 'btn-success'\n },\n cancel: {\n label: 'Não',\n className: 'btn-danger'\n }\n },\n callback: function (result) {\n if (result == true) {\n // remove card\n $.ajax({\n url: '/api/v1/tour/card.json?tour_id=' + tour_id + '&photo_id=' + currentUser.photo_id + '&card_id=' + _cardID + '&user_id=' + currentUser.user_id,\n type: 'DELETE',\n success: function(data) {\n krpano.call(\"removehotspot(\"+ _cardName + \")\");\n $('.confirm-check').removeClass('loading-animate');\n $('.confirm-check').removeClass('flipOutX');\n $('img.aim').removeClass('animated bounceOut');\n $('.mycheckin').hide();\n $('.my-checkin-faceApp').hide();\n $('.makecheckin').show();\n $('.make-checkin-faceApp').show();\n $('#button-circle').css('background-color', '#005892');\n },\n beforeSend: function() { $('.overlay').show(); $('.loading').addClass('loading-animate'); },\n complete: function() { \n window.currentUser.checkin = null\n window.currentUser.checkin_photo = null\n $('.loading').removeClass('loading-animate');\n\n $('#'+_cardID).hide();\n overlay.hide(); \n } \n });\n \n }\n }\n });\n\n return false;\n });","const firebase = require('firebase');\nvar login_waiting = localStorage.getItem('login_waiting');\nconst is_logged = localStorage.getItem('token');\n\nwindow.krpano = document.getElementById(\"tourId\");\nwindow.photo_id = gon.photo_id;\nif (is_logged) {\n $('#login').hide();\n $('.overlay').hide();\n $('.hamburger').show();\n krpano.set(\"autorotate.enabled\", false);\n}\n\n\nif (login_waiting) {\n krpano.set(\"autorotate.enabled\", false);\n $('#login').hide();\n $('.overlay').show();\n $('.loading').addClass('loading-animate');\n $('.hamburger').hide();\n}\n\n\n\n// current user\n\nconst brut_auth = JSON.parse(localStorage.getItem('brut_auth'));\nwindow.currentUser = {}\nif (brut_auth) {\n \n \n\n window.currentUser = JSON.parse(localStorage.getItem('current_user'));\n if (window.currentUser.checkin === true) {\n window.currentUser.cardUrl = window.origin + '?gigacard='+ window.currentUser.user_id;\n $('.makecheckin').hide();\n $('.make-checkin-faceApp').hide();\n $('#button-circle').css('background-color', '#fff');\n $('.mycheckin').show();\n $('.my-checkin-faceApp').show();\n } else {\n window.currentUser.checkin = false;\n }\n // Instagram \n if (window.currentUser.provider == 'instagram.com') {\n // App.authentication.login(currentUser, tour_id, photo_id); \n\n //window.currentUser.tour_id = tour_id\n window.currentUser.isAnonymous = false\n \n\n\n \n // add token to firebase\n firebase.auth().signInWithCustomToken(window.currentUser.baseToken).catch(function (da) {\n console.log(da, 'custom login')\n // ... \n });\n\n $('.profile-usertitle-name').text(window.currentUser.name);\n $('.urlProfile').attr('href', window.currentUser.providerUrl);\n $('.urlProfile').removeClass('anonymous twitter google');\n $('.urlProfile').addClass('instagram');\n $('.profile').attr('src', window.currentUser.image);\n // $('[data-toggle=\"offcanvas\"]').trigger('click');\n\n\n }\n\n \n // check if user has checked - canarysend\n\n $.ajax({\n url: '/api/v1/user/track/login.json',\n type: 'PUT',\n data: {\n \"current_user\": window.currentUser,\n \"tour_id\": gon.tour_id,\n \"photo_id\": window.photo_id\n },\n success: function(data) {\n if (data.checkin === true) {\n window.currentUser.checkin = true;\n window.currentUser.checkin_photo = data.checkin_photo;\n window.currentUser.cardUrl = window.origin + '?gigacard='+ window.currentUser.user_id;\n $('.makecheckin').hide();\n $('.make-checkin-faceApp').hide();\n $('#button-circle').css('background-color', '#fff');\n $('.mycheckin').show();\n $('.my-checkin-faceApp').show();\n } else {\n window.currentUser.checkin = false;\n }\n \n if(data.modalClient === false){\n $('#clientModal').modal('show')\n }\n }\n });\n\n\n\n\n} else {\n \n\n firebase.auth().onAuthStateChanged(function (user) {\n \n\n if (user && user.isAnonymous == false) {\n krpano.set(\"autorotate.enabled\", false);\n \n\n // console.log(user)\n // currentUser.tour_id = tour_id\n window.currentUser.photo_id = window.photo_id\n\n \n window.currentUser.token = user.refreshToken;\n var provider = user.providerData[0].providerId;\n window.currentUser.provider = user.providerData[0].providerId;\n window.currentUser.providerId = user.providerData[0].uid;\n window.currentUser.user_id = user.uid;\n window.currentUser.name = user.displayName;\n window.currentUser.email = user.email;\n window.currentUser.status = user.status;\n window.currentUser.isAnonymous = false\n\n // check if user has checked - canarysend\n\n \n\n // var hasVote = firebase.database().ref('quiz/' + tour_id + '/' + user.uid);\n\n // hasVote.once('value').then(function (data) {\n\n\n // if (data.val() == null) {\n // currentUser.hasVote = false\n // } else {\n // currentUser.hasVote = data.val().option\n // $('#quiz .answer').hide();\n // $('#quiz .question').show();\n // $(\".funkyradio input[name=\" + currentUser.hasVote + \"]\").attr(\"checked\", 'checked');\n // }\n // });\n\n\n $('.profile-usertitle-name').text(user.displayName);\n\n // Facebook\n if (provider == 'facebook.com') {\n window.currentUser.email = user.providerData[0].email;\n photo = 'https://graph.facebook.com/' + currentUser.providerId + '/picture?width=500&height=500';\n urlProfile = 'https://facebook.com/' + user.providerData[0].uid;\n window.currentUser.image = photo\n $('.urlProfile').attr('href', urlProfile);\n $('.urlProfile').removeClass('anonymous twitter google instagram');\n $('.urlProfile').addClass('facebook');\n $('.profile').attr('src', photo);\n }\n\n // Twitter\n else if (provider == 'twitter.com') {\n window.currentUser.email = user.providerData[0].email;\n \n urlProfile = user.providerData[0].photoURL.replace('_normal', '');\n window.currentUser.image = urlProfile\n $('.urlProfile').attr('href', urlProfile);\n $('.urlProfile').removeClass('anonymous facebook google instagram');\n $('.urlProfile').addClass('twitter');\n $('.profile').attr('src', urlProfile);\n }\n // Google\n else if (provider == 'google.com') {\n photo = user.photoURL\n urlProfile = 'https://plus.google.com/' + user.providerData[0].uid;\n window.currentUser.image = photo\n $('.urlProfile').attr('href', urlProfile);\n $('.urlProfile').removeClass('anonymous facebook twitter instagram');\n $('.urlProfile').addClass('google');\n $('.profile').attr('src', photo);\n }\n\n\n // db.collection(\"users\").doc(user.uid).set({ \n // user_id: user.uid,\n // name: user.displayName,\n // email: currentUser.email,\n\n // // providerId: user.providerData[0].uid,\n // // providerUrl: user.urlProfile\n\n // });\n\n // $('[data-toggle=\"offcanvas\"]').trigger('click');\n // user_data = { \"photo_id\": currentUser.photo_id, \"tour_id\": tour_id, \"user_id\": user.uid, \"name\": user.displayName, \"email\": currentUser.email, \"image\": photo, \"provider\": provider, \"providerId\": user.providerData[0].uid, \"providerUrl\": urlProfile }\n\n\n // $.ajax({\n // url: '/api/v1/user/signup/provider.json',\n // type: 'POST',\n // data: user_data,\n // success: function (data) {\n // // console.log('user update');\n // }\n // });\n\n\n // console.log(currentUser.provider);\n // user.providerData.forEach(function (profile) {\n // console.log(\"Sign-in provider: \"+profile.providerId);\n // console.log(\" Provider-specific UID: \"+profile.uid);\n // console.log(\" Name: \"+profile.displayName);\n // console.log(\" Email: \"+profile.email);\n // console.log(\" Photo URL: \"+profile.photoURL);\n\n // });\n\n\n $.ajax({\n url: '/api/v1/user/track/login.json',\n type: 'PUT',\n data: {\n \"current_user\": window.currentUser,\n \"tour_id\": gon.tour_id,\n \"photo_id\": window.photo_id\n },\n success: function(data) {\n if (data.checkin === true) {\n window.currentUser.checkin = true;\n window.currentUser.checkin_photo = data.checkin_photo;\n window.currentUser.cardUrl = window.origin + '?gigacard='+ window.currentUser.user_id;\n $('.makecheckin').hide();\n $('.make-checkin-faceApp').hide();\n $('#button-circle').css('background-color', '#fff');\n $('.mycheckin').show();\n $('.my-checkin-faceApp').show();\n } else {\n window.currentUser.checkin = false;\n }\n if(data.modalClient === false){\n $('#clientModal').modal('show')\n }\n }\n });\n \n\n // App.authentication.login(currentUser, tour_id, photo_id);\n\n } else {\n $('.overlay').show();\n $('#login').show();\n $('.hamburger').hide();\n \n\n firebase.auth().signInAnonymously().catch(function (error) {\n console.log(error)\n // Handle Errors here.\n var errorCode = error.code;\n var errorMessage = error.message;\n \n // krpano.set(\"autorotate.enabled\", false);\n // ...\n });\n window.currentUser.isAnonymous = true;\n window.currentUser.photo_id = window.photo_id;\n window.currentUser.user_id = user.uid;\n $('.link-pic-profile').addClass('anon-logged');\n // console.log('loguemex') \n\n $('.profile-usertitle-name').text('LOGIN');\n $('.urlProfile').removeClass('facebook google twitter instagram');\n $('.urlProfile').addClass('anonymous');\n $('.profile').attr('src', 'https://images.gigafans.com/assets/player/anonymous.png');\n $('.urlProfile').removeAttr('href');\n $('.urlProfile').removeAttr('target');\n\n\n authdata = null\n\n\n\n }\n \n \n // console.log(currentUser, 'tchau');\n return currentUser;\n });\n}\n\n\n// localStorage.setItem('current_user', currentUser)\n// Create/update user\n\n\nfunction createUser(user) {\n user_data = { \"user_id\": user.uid, \"name\": user.name, \"email\": user.email, \"image\": user.image, \"provider_facebook\": \"true\", \"providerId\": providerData[0].uid }\n\n $.ajax({\n url: '/api/v1/user/signup/provider.json',\n type: 'POST',\n data: user_data,\n success: function (data) {\n // console.log('user Created');\n }\n });\n}\n\n// console.log(currentUser)\n// login facebook\n\nvar facebook_provider = new firebase.auth.FacebookAuthProvider();\nfacebook_provider.addScope('public_profile')\nfacebook_provider.addScope('email')\nfacebook_provider.addScope('user_likes')\n//facebook_provider.addScope('user_friends')\n\n// https://developers.facebook.com/docs/facebook-login/permissions\n\n\n\n\n$(\"#faceLogin\").click(function () {\n krpano.set(\"autorotate.enabled\", false);\n localStorage.setItem('login_waiting', true);\n firebase.auth().signInWithPopup(facebook_provider).then(function (result) {\n // Open Menu\n // $('[data-toggle=\"offcanvas\"]').trigger('click');\n console.log(result)\n // This gives you a Facebook Access Token. You can use it to access the Facebook API.\n var token = result.credential.accessToken;\n // The signed-in user info.\n var user = result.user;\n // ... \n\n\n\n }).catch(function (error) {\n console.log(error)\n // Handle Errors here.\n var errorCode = error.code;\n var errorMessage = error.message;\n // The email of the user's account used.\n var email = error.email;\n // The firebase.auth.AuthCredential type that was used.\n var credential = error.credential;\n // ...\n });\n\n});\n\n\n\n// login Twitter\n\nvar twitter_provider = new firebase.auth.TwitterAuthProvider();\n\n\n$(\"#twitterLogin\").click(function () {\n krpano.set(\"autorotate.enabled\", false);\n localStorage.setItem('login_waiting', true);\n firebase.auth().signInWithPopup(twitter_provider).then(function (result) {\n // Open Menu\n // $('[data-toggle=\"offcanvas\"]').trigger('click');\n // This gives you a Facebook Access Token. You can use it to access the Facebook API.\n var token = result.credential.accessToken;\n var secret = result.credential.secret;\n // The signed-in user info.\n var user = result.user;\n // ...\n \n urlProfile = user.providerData[0].photoURL.replace('_normal', '');\n user.user_id = user.uid;\n user.email = user.providerData[0].email;\n user.image = urlProfile;\n \n console.log(user)\n $('.profile-usertitle-name').text(user.displayName);\n \n $('.urlProfile').attr('href', urlProfile);\n $('.urlProfile').removeClass('anonymous facebook google instagram');\n $('.urlProfile').addClass('twitter');\n $('.profile').attr('src', urlProfile);\n \n \n $('#login').hide();\n $('.overlay').hide();\n $('.hamburger').show();\n krpano.set(\"autorotate.enabled\", false);\n\n $.ajax({\n url: '/api/v1/user/track/login.json',\n type: 'PUT',\n data: {\n \"current_user\": user,\n \"tour_id\": gon.tour_id,\n \"photo_id\": window.photo_id\n },\n success: function(data) {\n \n if(data.modalClient === false){\n $('#clientModal').modal('show')\n }\n }\n });\n\n \n \n }).catch(function (error) {\n // Handle Errors here.\n var errorCode = error.code;\n var errorMessage = error.message;\n // The email of the user's account used.\n var email = error.email;\n // The firebase.auth.AuthCredential type that was used.\n var credential = error.credential;\n // ...\n });\n\n});\n\n// login Google\n\nvar google_provider = new firebase.auth.GoogleAuthProvider();\ngoogle_provider.addScope('profile');\ngoogle_provider.addScope('email');\n$(\"#googleLogin\").click(function () {\n\n krpano.set(\"autorotate.enabled\", false);\n localStorage.setItem('login_waiting', true);\n firebase.auth().signInWithPopup(google_provider).then(function (result) {\n // Open Menu\n // $('[data-toggle=\"offcanvas\"]').trigger('click');\n // This gives you a Google Access Token. You can use it to access the Google API.\n var token = result.credential.accessToken;\n // The signed-in user info.\n var user = result.user;\n console.log('djisj')\n $('#login').hide();\n $('.overlay').hide();\n $('.hamburger').show();\n krpano.set(\"autorotate.enabled\", false);\n // ...\n }).catch(function (error) {\n // Handle Errors here.\n var errorCode = error.code;\n var errorMessage = error.message;\n // The email of the user's account used.\n var email = error.email;\n // The firebase.auth.AuthCredential type that was used.\n var credential = error.credential;\n // ...\n });\n\n});\n\n// login Instagram\n\nvar sessionStart = function () {\n alert('Session has started');\n};\nhello.init({\n instagram: '0c79602e62ca4a0499d5e5e7b9dcae36'\n}, {\n scope: 'basic',\n redirect_uri: '/oauth/redirect',\n display: 'page',\n });\n\n\n$(\"#instaLogin\").click(function () {\n krpano.set(\"autorotate.enabled\", false);\n localStorage.setItem('login_waiting', true);\n localStorage.setItem('tour_id', tour_id);\n\n hello('instagram').login().then(function () {\n hello.on('auth.login', sessionStart);\n // Open Menu\n // $('[data-toggle=\"offcanvas\"]').trigger('click');\n alert('You are signed in to Instagram');\n }, function (e) {\n alert('Signin error: ' + e.error.message);\n });\n\n\n\n});\n\n// Anonymous\n\n$(\"#anonymousLogin\").click(function () {\n krpano.set(\"autorotate.enabled\", false);\n localStorage.setItem('token', 'signInAnonymously');\n window.currentUser.photo_id = window.photo_id;\n window.currentUser.isAnonymous = true\n $('.urlProfile').addClass('logoutButton');\n\n $('.link-pic-profile').addClass('anon-logged');\n\n firebase.auth().signInAnonymously().catch(function (error) {\n // Handle Errors here.\n var errorCode = error.code;\n var errorMessage = error.message;\n\n // krpano.set(\"autorotate.enabled\", false);\n // ...\n });\n\n $('.overlay').css('z-index', '999');\n\n});\n\n\n\n// Logout\n\n$(\".logoutButton\").click(function () {\n\n firebase.auth().signOut().then(function () {\n localStorage.removeItem('token');\n localStorage.removeItem('current_user');\n localStorage.removeItem('brut_auth');\n currentUser = {}\n $('.hamburger').trigger('click');\n $('.overlay').show();\n $('#login').show();\n $('.hamburger').hide();\n\n $('.profile-usertitle-name').text('LOGIN');\n $('.avatar').attr('src', 'assets/player/anonymous.png');\n\n krpano.set(\"autorotate.enabled\", true);\n $('#button-circle').css('background-color', '#005892');\n $('.mycheckin').hide();\n $('.makecheckin').show();\n\n // Sign-out successful.\n }).catch(function (error) {\n // An error happened.\n });\n\n});\n\n\nfirebase.auth().getRedirectResult().then(function (result) {\n krpano.set(\"autorotate.enabled\", false);\n $('.overlay').hide();\n $('.loading').removeClass('loading-animate');\n $('#login').hide();\n $('.hamburger').show();\n if (result.credential) {\n // This gives you a Google Access Token. You can use it to access the Google API.\n var token = result.credential.accessToken;\n localStorage.removeItem('login_waiting');\n localStorage.setItem('token', token);\n // ...\n }\n // The signed-in user info.\n var user = result.user;\n}).catch(function (error) {\n // Handle Errors here.\n localStorage.removeItem('login_waiting');\n $('.loading').removeClass('loading-animate');\n $('#login').show();\n var errorCode = error.code;\n var errorMessage = error.message;\n // The email of the user's account used.\n var email = error.email;\n // The firebase.auth.AuthCredential type that was used.\n var credential = error.credential;\n // ...\n});\n\n\n\n// Modal Client Unilever\n\n\n\n\n$('.close-modal-client').on('click', function(e) {\n\n let name = window.currentUser.name\n let parts = name.split(' ')\n let firstName = parts.shift(); \n let lastName = parts.join(' ');\n\n\n var data = {\n \"profile\": {\n \"header\": {\n \"isoLanguage\": \"pt\",\n \"isoCountry\": \"BR\",\n \"brandCode\": \"BH0432\",\n \"campaignId\": \"PN004388\",\n \"formType\": \"signUp\",\n \"entity\": \"PRM2.6\",\n \"origin\": \"carnavalsedaboom.gigafans.com\"\n },\n \"consumerIdentity\": {\n \"firstName\": firstName,\n \"lastName\": lastName,\n\n },\n \"contactDetail\": {\n \"email\": currentUser.email\n },\n \"optInStatus\": {\n \"unileverEmailConsent\": false,\n \"legalAgeConsent\": false\n }\n }\n }\n\n $.ajax({\n url: 'https://forms-us.unileversolutions.com/v3',\n type: \"POST\",\n headers: {\n 'Origin':'carnavalsedaboom.gigafans.com',\n 'x-api-key':'f43780f1-27ef-4f3e-9bd1-aaea4c2a7646',\n 'Content-Type':'application/json'\n },\n dataType: 'json',\n data: JSON.stringify(data),\n success: function(msg) {\n console.log('eaee', msg)\n $.ajax({\n url: '/api/v1/user/track/modal.json',\n type: 'PUT',\n data: {\n \"tour_id\": gon.tour_id,\n \"user_id\": window.currentUser.user_id\n },\n success: function(data) {\n console.log(data)\n }\n });\n }\n });\n\n});\n \n \n$('.done-modal-client').on('click', function(e) {\n\n let name = window.currentUser.name\n let parts = name.split(' ')\n let firstName = parts.shift(); \n let lastName = parts.join(' ');\n\n\n var data = {\n \"profile\": {\n \"header\": {\n \"isoLanguage\": \"pt\",\n \"isoCountry\": \"BR\",\n \"brandCode\": \"BH0432\",\n \"campaignId\": \"PN004388\",\n \"formType\": \"signUp\",\n \"entity\": \"PRM2.6\",\n \"origin\": \"carnavalsedaboom.gigafans.com\"\n },\n \"consumerIdentity\": {\n \"firstName\": firstName,\n \"lastName\": lastName,\n\n },\n \"contactDetail\": {\n \"email\": currentUser.email\n },\n \"optInStatus\": {\n \"unileverEmailConsent\": true,\n \"legalAgeConsent\": true\n }\n }\n }\n\n $.ajax({\n url: 'https://forms-us.unileversolutions.com/v3',\n type: \"POST\",\n headers: {\n 'Origin':'carnavalsedaboom.gigafans.com',\n 'x-api-key':'f43780f1-27ef-4f3e-9bd1-aaea4c2a7646',\n 'Content-Type':'application/json'\n },\n dataType: 'json',\n data: JSON.stringify(data),\n success: function(msg) {\n console.log('eaee', msg)\n $.ajax({\n url: '/api/v1/user/track/modal.json',\n type: 'PUT',\n data: {\n \"tour_id\": gon.tour_id,\n \"user_id\": window.currentUser.user_id\n },\n success: function(data) {\n console.log(data)\n }\n });\n }\n });\n\n});\n \n\n\n","\n\nconst firebase = require('firebase');\n\n\n// init firebase\n// var config = firebase.initializeApp({\n// apiKey: \"AIzaSyAubv69Kl-qbVmL4Z1ACfvhtpHLW3Rq_4M\",\n// authDomain: \"gigafans-8cd43.firebaseapp.com\",\n// databaseURL: \"https://gigafans-8cd43.firebaseio.com\",\n// projectId: \"gigafans-8cd43\",\n// storageBucket: \"images.gigafans.com\",\n// messagingSenderId: \"950279574805\"\n// });\n\n\nvar config = firebase.initializeApp({\n apiKey: \"AIzaSyAubv69Kl-qbVmL4Z1ACfvhtpHLW3Rq_4M\",\n authDomain: \"gigafans.firebaseapp.com\",\n databaseURL: \"https://gigafans.firebaseio.com\",\n projectId: \"gigafans-8cd43\",\n storageBucket: \"images.gigafans.com\",\n messagingSenderId: \"950279574805\"\n});\n\n\n\n\nfirebase.firestore().settings({\n // Enable offline support\n // persistence: true\n});\n\nvar db = firebase.firestore();\nvar currentUser = {}\n\n\n\n// firebase.database().ref('quiz/'+ tour_id +'/' + user.uid);\n\n// console.log('oi', oi);"," // Call Friends Screen\n $('a.friends').click(function(event) {\n badges.hide();\n ranking.hide();\n share.hide();\n contactus.hide();\n torcidometro.hide();\n tutorial.hide();\n card.hide();\n gigafotos.hide();\n friends.show();\n\n \n user_data = { \"token\": currentUser.token}\n $.ajax({\n url: '/api/v1/friends/instagram.json',\n type: 'GET',\n data: user_data,\n success: function (data) {\n \n updateFriends(data)\n \n }\n });\n\n return false;\n });\n\n\n\nfunction updateFriends(data) {\n\n\n var friends = [];\n \n if (data == null) {\n // $(\".wall-message\").html('');\n // $('.wall-message').append('
  • Você ainda não possui mensagens!
  • ');\n console.log('none')\n }\n else {\n $.each(data, function (obj, user) { \n console.log(user.profile_picture)\n data += ('
    ');\n data += (''); \n data += ('
    ' + user.username + '
    ');\n data += ('

    ' + user.created + '

    ');\n // messages += ('

    Responder

    ');\n // messages += ('
    ');\n data += ('
    ');\n });\n $(\".loadFriend\").html(data);\n // $('.wall-message li:last-child').addClass('animated fadeIn');\n }\n\n\n}\n\n ","/*! hellojs v1.16.1 | (c) 2012-2017 Andrew Dodson | MIT https://adodson.com/hello.js/LICENSE */\n// ES5 Object.create\nif (!Object.create) {\n\n // Shim, Object create\n // A shim for Object.create(), it adds a prototype to a new object\n Object.create = (function () {\n\n function F() { }\n\n return function (o) {\n\n if (arguments.length != 1) {\n throw new Error('Object.create implementation only accepts one parameter.');\n }\n\n F.prototype = o;\n return new F();\n };\n\n })();\n\n}\n\n// ES5 Object.keys\nif (!Object.keys) {\n Object.keys = function (o, k, r) {\n r = [];\n for (k in o) {\n if (r.hasOwnProperty.call(o, k))\n r.push(k);\n }\n\n return r;\n };\n}\n\n// ES5 [].indexOf\nif (!Array.prototype.indexOf) {\n Array.prototype.indexOf = function (s) {\n\n for (var j = 0; j < this.length; j++) {\n if (this[j] === s) {\n return j;\n }\n }\n\n return -1;\n };\n}\n\n// ES5 [].forEach\nif (!Array.prototype.forEach) {\n Array.prototype.forEach = function (fun/*, thisArg*/) {\n\n if (this === void 0 || this === null) {\n throw new TypeError();\n }\n\n var t = Object(this);\n var len = t.length >>> 0;\n if (typeof fun !== 'function') {\n throw new TypeError();\n }\n\n var thisArg = arguments.length >= 2 ? arguments[1] : void 0;\n for (var i = 0; i < len; i++) {\n if (i in t) {\n fun.call(thisArg, t[i], i, t);\n }\n }\n\n return this;\n };\n}\n\n// ES5 [].filter\nif (!Array.prototype.filter) {\n Array.prototype.filter = function (fun, thisArg) {\n\n var a = [];\n this.forEach(function (val, i, t) {\n if (fun.call(thisArg || void 0, val, i, t)) {\n a.push(val);\n }\n });\n\n return a;\n };\n}\n\n// Production steps of ECMA-262, Edition 5, 15.4.4.19\n// Reference: http://es5.github.io/#x15.4.4.19\nif (!Array.prototype.map) {\n\n Array.prototype.map = function (fun, thisArg) {\n\n var a = [];\n this.forEach(function (val, i, t) {\n a.push(fun.call(thisArg || void 0, val, i, t));\n });\n\n return a;\n };\n}\n\n// ES5 isArray\nif (!Array.isArray) {\n\n // Function Array.isArray\n Array.isArray = function (o) {\n return Object.prototype.toString.call(o) === '[object Array]';\n };\n\n}\n\n// Test for location.assign\nif (typeof window === 'object' && typeof window.location === 'object' && !window.location.assign) {\n\n window.location.assign = function (url) {\n window.location = url;\n };\n\n}\n\n// Test for Function.bind\nif (!Function.prototype.bind) {\n\n // MDN\n // Polyfill IE8, does not support native Function.bind\n Function.prototype.bind = function (b) {\n\n if (typeof this !== 'function') {\n throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');\n }\n\n function C() { }\n\n var a = [].slice;\n var f = a.call(arguments, 1);\n var _this = this;\n var D = function () {\n return _this.apply(this instanceof C ? this : b || window, f.concat(a.call(arguments)));\n };\n\n C.prototype = this.prototype;\n D.prototype = new C();\n\n return D;\n };\n\n}\n\n/**\n * @hello.js\n *\n * HelloJS is a client side Javascript SDK for making OAuth2 logins and subsequent REST calls.\n *\n * @author Andrew Dodson\n * @website https://adodson.com/hello.js/\n *\n * @copyright Andrew Dodson, 2012 - 2015\n * @license MIT: You are free to use and modify this code for any use, on the condition that this copyright notice remains.\n */\n\nvar hello = function (name) {\n return hello.use(name);\n};\n\nhello.utils = {\n\n // Extend the first object with the properties and methods of the second\n extend: function (r /*, a[, b[, ...]] */) {\n\n // Get the arguments as an array but ommit the initial item\n Array.prototype.slice.call(arguments, 1).forEach(function (a) {\n if (Array.isArray(r) && Array.isArray(a)) {\n Array.prototype.push.apply(r, a);\n }\n else if (r && (r instanceof Object || typeof r === 'object') && a && (a instanceof Object || typeof a === 'object') && r !== a) {\n for (var x in a) {\n r[x] = hello.utils.extend(r[x], a[x]);\n }\n }\n else {\n\n if (Array.isArray(a)) {\n // Clone it\n a = a.slice(0);\n }\n\n r = a;\n }\n });\n\n return r;\n }\n};\n\n// Core library\nhello.utils.extend(hello, {\n\n settings: {\n\n // OAuth2 authentication defaults\n redirect_uri: window.location.href.split('&')[0],\n response_type: 'token',\n display: 'popup',\n state: '',\n\n // OAuth1 shim\n // The path to the OAuth1 server for signing user requests\n // Want to recreate your own? Checkout https://github.com/MrSwitch/node-oauth-shim\n oauth_proxy: 'https://auth-server.herokuapp.com/proxy',\n\n // API timeout in milliseconds\n timeout: 20000,\n\n // Popup Options\n popup: {\n resizable: 1,\n scrollbars: 1,\n width: 500,\n height: 550\n },\n\n // Default scope\n // Many services require atleast a profile scope,\n // HelloJS automatially includes the value of provider.scope_map.basic\n // If that's not required it can be removed via hello.settings.scope.length = 0;\n scope: ['basic'],\n\n // Scope Maps\n // This is the default module scope, these are the defaults which each service is mapped too.\n // By including them here it prevents the scope from being applied accidentally\n scope_map: {\n basic: ''\n },\n\n // Default service / network\n default_service: null,\n\n // Force authentication\n // When hello.login is fired.\n // (null): ignore current session expiry and continue with login\n // (true): ignore current session expiry and continue with login, ask for user to reauthenticate\n // (false): if the current session looks good for the request scopes return the current session.\n force: null,\n\n // Page URL\n // When 'display=page' this property defines where the users page should end up after redirect_uri\n // Ths could be problematic if the redirect_uri is indeed the final place,\n // Typically this circumvents the problem of the redirect_url being a dumb relay page.\n page_uri: window.location.href\n },\n\n // Service configuration objects\n services: {},\n\n // Use\n // Define a new instance of the HelloJS library with a default service\n use: function (service) {\n\n // Create self, which inherits from its parent\n var self = Object.create(this);\n\n // Inherit the prototype from its parent\n self.settings = Object.create(this.settings);\n\n // Define the default service\n if (service) {\n self.settings.default_service = service;\n }\n\n // Create an instance of Events\n self.utils.Event.call(self);\n\n return self;\n },\n\n // Initialize\n // Define the client_ids for the endpoint services\n // @param object o, contains a key value pair, service => clientId\n // @param object opts, contains a key value pair of options used for defining the authentication defaults\n // @param number timeout, timeout in seconds\n init: function (services, options) {\n\n var utils = this.utils;\n\n if (!services) {\n return this.services;\n }\n\n // Define provider credentials\n // Reformat the ID field\n for (var x in services) {\n if (services.hasOwnProperty(x)) {\n if (typeof (services[x]) !== 'object') {\n services[x] = { id: services[x] };\n }\n }\n }\n\n // Merge services if there already exists some\n utils.extend(this.services, services);\n\n // Update the default settings with this one.\n if (options) {\n utils.extend(this.settings, options);\n\n // Do this immediatly incase the browser changes the current path.\n if ('redirect_uri' in options) {\n this.settings.redirect_uri = utils.url(options.redirect_uri).href;\n }\n }\n\n return this;\n },\n\n // Login\n // Using the endpoint\n // @param network stringify name to connect to\n // @param options object (optional) {display mode, is either none|popup(default)|page, scope: email,birthday,publish, .. }\n // @param callback function (optional) fired on signin\n login: function () {\n\n // Create an object which inherits its parent as the prototype and constructs a new event chain.\n var _this = this;\n var utils = _this.utils;\n var error = utils.error;\n var promise = utils.Promise();\n\n // Get parameters\n var p = utils.args({ network: 's', options: 'o', callback: 'f' }, arguments);\n\n // Local vars\n var url;\n\n // Get all the custom options and store to be appended to the querystring\n var qs = utils.diffKey(p.options, _this.settings);\n\n // Merge/override options with app defaults\n var opts = p.options = utils.merge(_this.settings, p.options || {});\n\n // Merge/override options with app defaults\n opts.popup = utils.merge(_this.settings.popup, p.options.popup || {});\n\n // Network\n p.network = p.network || _this.settings.default_service;\n\n // Bind callback to both reject and fulfill states\n promise.proxy.then(p.callback, p.callback);\n\n // Trigger an event on the global listener\n function emit(s, value) {\n hello.emit(s, value);\n }\n\n promise.proxy.then(emit.bind(this, 'auth.login auth'), emit.bind(this, 'auth.failed auth'));\n\n // Is our service valid?\n if (typeof (p.network) !== 'string' || !(p.network in _this.services)) {\n // Trigger the default login.\n // Ahh we dont have one.\n return promise.reject(error('invalid_network', 'The provided network was not recognized'));\n }\n\n var provider = _this.services[p.network];\n\n // Create a global listener to capture events triggered out of scope\n var callbackId = utils.globalEvent(function (str) {\n\n // The responseHandler returns a string, lets save this locally\n var obj;\n\n if (str) {\n obj = JSON.parse(str);\n }\n else {\n obj = error('cancelled', 'The authentication was not completed');\n }\n\n // Handle these response using the local\n // Trigger on the parent\n if (!obj.error) {\n\n // Save on the parent window the new credentials\n // This fixes an IE10 bug i think... atleast it does for me.\n utils.store(obj.network, obj);\n\n // Fulfill a successful login\n promise.fulfill({\n network: obj.network,\n authResponse: obj\n });\n }\n else {\n // Reject a successful login\n promise.reject(obj);\n }\n });\n\n var redirectUri = utils.url(opts.redirect_uri).href;\n\n // May be a space-delimited list of multiple, complementary types\n var responseType = provider.oauth.response_type || opts.response_type;\n\n // Fallback to token if the module hasn't defined a grant url\n if (/\\bcode\\b/.test(responseType) && !provider.oauth.grant) {\n responseType = responseType.replace(/\\bcode\\b/, 'token');\n }\n\n // Query string parameters, we may pass our own arguments to form the querystring\n p.qs = utils.merge(qs, {\n client_id: encodeURIComponent(provider.id),\n response_type: encodeURIComponent(responseType),\n redirect_uri: encodeURIComponent(redirectUri),\n state: {\n client_id: provider.id,\n network: p.network,\n display: opts.display,\n callback: callbackId,\n state: opts.state,\n redirect_uri: redirectUri\n }\n });\n\n // Get current session for merging scopes, and for quick auth response\n var session = utils.store(p.network);\n\n // Scopes (authentication permisions)\n // Ensure this is a string - IE has a problem moving Arrays between windows\n // Append the setup scope\n var SCOPE_SPLIT = /[,\\s]+/;\n\n // Include default scope settings (cloned).\n var scope = _this.settings.scope ? [_this.settings.scope.toString()] : [];\n\n // Extend the providers scope list with the default\n var scopeMap = utils.merge(_this.settings.scope_map, provider.scope || {});\n\n // Add user defined scopes...\n if (opts.scope) {\n scope.push(opts.scope.toString());\n }\n\n // Append scopes from a previous session.\n // This helps keep app credentials constant,\n // Avoiding having to keep tabs on what scopes are authorized\n if (session && 'scope' in session && session.scope instanceof String) {\n scope.push(session.scope);\n }\n\n // Join and Split again\n scope = scope.join(',').split(SCOPE_SPLIT);\n\n // Format remove duplicates and empty values\n scope = utils.unique(scope).filter(filterEmpty);\n\n // Save the the scopes to the state with the names that they were requested with.\n p.qs.state.scope = scope.join(',');\n\n // Map scopes to the providers naming convention\n scope = scope.map(function (item) {\n // Does this have a mapping?\n return (item in scopeMap) ? scopeMap[item] : item;\n });\n\n // Stringify and Arrayify so that double mapped scopes are given the chance to be formatted\n scope = scope.join(',').split(SCOPE_SPLIT);\n\n // Again...\n // Format remove duplicates and empty values\n scope = utils.unique(scope).filter(filterEmpty);\n\n // Join with the expected scope delimiter into a string\n p.qs.scope = scope.join(provider.scope_delim || ',');\n\n // Is the user already signed in with the appropriate scopes, valid access_token?\n if (opts.force === false) {\n\n if (session && 'access_token' in session && session.access_token && 'expires' in session && session.expires > ((new Date()).getTime() / 1e3)) {\n // What is different about the scopes in the session vs the scopes in the new login?\n var diff = utils.diff((session.scope || '').split(SCOPE_SPLIT), (p.qs.state.scope || '').split(SCOPE_SPLIT));\n if (diff.length === 0) {\n\n // OK trigger the callback\n promise.fulfill({\n unchanged: true,\n network: p.network,\n authResponse: session\n });\n\n // Nothing has changed\n return promise;\n }\n }\n }\n\n // Page URL\n if (opts.display === 'page' && opts.page_uri) {\n // Add a page location, place to endup after session has authenticated\n p.qs.state.page_uri = utils.url(opts.page_uri).href;\n }\n\n // Bespoke\n // Override login querystrings from auth_options\n if ('login' in provider && typeof (provider.login) === 'function') {\n // Format the paramaters according to the providers formatting function\n provider.login(p);\n }\n\n // Add OAuth to state\n // Where the service is going to take advantage of the oauth_proxy\n if (!/\\btoken\\b/.test(responseType) ||\n parseInt(provider.oauth.version, 10) < 2 ||\n (opts.display === 'none' && provider.oauth.grant && session && session.refresh_token)) {\n\n // Add the oauth endpoints\n p.qs.state.oauth = provider.oauth;\n\n // Add the proxy url\n p.qs.state.oauth_proxy = opts.oauth_proxy;\n\n }\n\n // Convert state to a string\n p.qs.state = encodeURIComponent(JSON.stringify(p.qs.state));\n\n // URL\n if (parseInt(provider.oauth.version, 10) === 1) {\n\n // Turn the request to the OAuth Proxy for 3-legged auth\n url = utils.qs(opts.oauth_proxy, p.qs, encodeFunction);\n }\n\n // Refresh token\n else if (opts.display === 'none' && provider.oauth.grant && session && session.refresh_token) {\n\n // Add the refresh_token to the request\n p.qs.refresh_token = session.refresh_token;\n\n // Define the request path\n url = utils.qs(opts.oauth_proxy, p.qs, encodeFunction);\n }\n else {\n url = utils.qs(provider.oauth.auth, p.qs, encodeFunction);\n }\n\n // Broadcast this event as an auth:init\n emit('auth.init', p);\n\n // Execute\n // Trigger how we want self displayed\n if (opts.display === 'none') {\n // Sign-in in the background, iframe\n utils.iframe(url, redirectUri);\n }\n\n // Triggering popup?\n else if (opts.display === 'popup') {\n\n var popup = utils.popup(url, redirectUri, opts.popup);\n\n var timer = setInterval(function () {\n if (!popup || popup.closed) {\n clearInterval(timer);\n if (!promise.state) {\n\n var response = error('cancelled', 'Login has been cancelled');\n\n if (!popup) {\n response = error('blocked', 'Popup was blocked');\n }\n\n response.network = p.network;\n\n promise.reject(response);\n }\n }\n }, 100);\n }\n\n else {\n window.location = url;\n }\n\n return promise.proxy;\n\n function encodeFunction(s) { return s; }\n\n function filterEmpty(s) { return !!s; }\n },\n\n // Remove any data associated with a given service\n // @param string name of the service\n // @param function callback\n logout: function () {\n\n var _this = this;\n var utils = _this.utils;\n var error = utils.error;\n\n // Create a new promise\n var promise = utils.Promise();\n\n var p = utils.args({ name: 's', options: 'o', callback: 'f' }, arguments);\n\n p.options = p.options || {};\n\n // Add callback to events\n promise.proxy.then(p.callback, p.callback);\n\n // Trigger an event on the global listener\n function emit(s, value) {\n hello.emit(s, value);\n }\n\n promise.proxy.then(emit.bind(this, 'auth.logout auth'), emit.bind(this, 'error'));\n\n // Network\n p.name = p.name || this.settings.default_service;\n p.authResponse = utils.store(p.name);\n\n if (p.name && !(p.name in _this.services)) {\n\n promise.reject(error('invalid_network', 'The network was unrecognized'));\n\n }\n else if (p.name && p.authResponse) {\n\n // Define the callback\n var callback = function (opts) {\n\n // Remove from the store\n utils.store(p.name, null);\n\n // Emit events by default\n promise.fulfill(hello.utils.merge({ network: p.name }, opts || {}));\n };\n\n // Run an async operation to remove the users session\n var _opts = {};\n if (p.options.force) {\n var logout = _this.services[p.name].logout;\n if (logout) {\n // Convert logout to URL string,\n // If no string is returned, then this function will handle the logout async style\n if (typeof (logout) === 'function') {\n logout = logout(callback, p);\n }\n\n // If logout is a string then assume URL and open in iframe.\n if (typeof (logout) === 'string') {\n utils.iframe(logout);\n _opts.force = null;\n _opts.message = 'Logout success on providers site was indeterminate';\n }\n else if (logout === undefined) {\n // The callback function will handle the response.\n return promise.proxy;\n }\n }\n }\n\n // Remove local credentials\n callback(_opts);\n }\n else {\n promise.reject(error('invalid_session', 'There was no session to remove'));\n }\n\n return promise.proxy;\n },\n\n // Returns all the sessions that are subscribed too\n // @param string optional, name of the service to get information about.\n getAuthResponse: function (service) {\n\n // If the service doesn't exist\n service = service || this.settings.default_service;\n\n if (!service || !(service in this.services)) {\n return null;\n }\n\n return this.utils.store(service) || null;\n },\n\n // Events: placeholder for the events\n events: {}\n});\n\n// Core utilities\nhello.utils.extend(hello.utils, {\n\n // Error\n error: function (code, message) {\n return {\n error: {\n code: code,\n message: message\n }\n };\n },\n\n // Append the querystring to a url\n // @param string url\n // @param object parameters\n qs: function (url, params, formatFunction) {\n\n if (params) {\n\n // Set default formatting function\n formatFunction = formatFunction || encodeURIComponent;\n\n // Override the items in the URL which already exist\n for (var x in params) {\n var str = '([\\\\?\\\\&])' + x + '=[^\\\\&]*';\n var reg = new RegExp(str);\n if (url.match(reg)) {\n url = url.replace(reg, '$1' + x + '=' + formatFunction(params[x]));\n delete params[x];\n }\n }\n }\n\n if (!this.isEmpty(params)) {\n return url + (url.indexOf('?') > -1 ? '&' : '?') + this.param(params, formatFunction);\n }\n\n return url;\n },\n\n // Param\n // Explode/encode the parameters of an URL string/object\n // @param string s, string to decode\n param: function (s, formatFunction) {\n var b;\n var a = {};\n var m;\n\n if (typeof (s) === 'string') {\n\n formatFunction = formatFunction || decodeURIComponent;\n\n m = s.replace(/^[\\&\\?]/, '').match(/([^=\\/\\&]+)=([^\\&]+)/g);\n if (m) {\n for (var i = 0; i < m.length; i++) {\n b = m[i].match(/([^=]+)=(.*)/);\n a[b[1]] = formatFunction(b[2]);\n }\n }\n\n return a;\n }\n else {\n\n formatFunction = formatFunction || encodeURIComponent;\n\n var o = s;\n\n a = [];\n\n for (var x in o) {\n if (o.hasOwnProperty(x)) {\n if (o.hasOwnProperty(x)) {\n a.push([x, o[x] === '?' ? '?' : formatFunction(o[x])].join('='));\n }\n }\n }\n\n return a.join('&');\n }\n },\n\n // Local storage facade\n store: (function () {\n\n var a = ['localStorage', 'sessionStorage'];\n var i = -1;\n var prefix = 'test';\n\n // Set LocalStorage\n var localStorage;\n\n while (a[++i]) {\n try {\n // In Chrome with cookies blocked, calling localStorage throws an error\n localStorage = window[a[i]];\n localStorage.setItem(prefix + i, i);\n localStorage.removeItem(prefix + i);\n break;\n }\n catch (e) {\n localStorage = null;\n }\n }\n\n if (!localStorage) {\n\n var cache = null;\n\n localStorage = {\n getItem: function (prop) {\n prop = prop + '=';\n var m = document.cookie.split(';');\n for (var i = 0; i < m.length; i++) {\n var _m = m[i].replace(/(^\\s+|\\s+$)/, '');\n if (_m && _m.indexOf(prop) === 0) {\n return _m.substr(prop.length);\n }\n }\n\n return cache;\n },\n\n setItem: function (prop, value) {\n cache = value;\n document.cookie = prop + '=' + value;\n }\n };\n\n // Fill the cache up\n cache = localStorage.getItem('hello');\n }\n\n function get() {\n var json = {};\n try {\n json = JSON.parse(localStorage.getItem('hello')) || {};\n }\n catch (e) { }\n\n return json;\n }\n\n function set(json) {\n localStorage.setItem('hello', JSON.stringify(json));\n }\n\n // Check if the browser support local storage\n return function (name, value, days) {\n\n // Local storage\n var json = get();\n\n if (name && value === undefined) {\n return json[name] || null;\n }\n else if (name && value === null) {\n try {\n delete json[name];\n }\n catch (e) {\n json[name] = null;\n }\n }\n else if (name) {\n json[name] = value;\n }\n else {\n return json;\n }\n\n set(json);\n\n return json || null;\n };\n\n })(),\n\n // Create and Append new DOM elements\n // @param node string\n // @param attr object literal\n // @param dom/string\n append: function (node, attr, target) {\n\n var n = typeof (node) === 'string' ? document.createElement(node) : node;\n\n if (typeof (attr) === 'object') {\n if ('tagName' in attr) {\n target = attr;\n }\n else {\n for (var x in attr) {\n if (attr.hasOwnProperty(x)) {\n if (typeof (attr[x]) === 'object') {\n for (var y in attr[x]) {\n if (attr[x].hasOwnProperty(y)) {\n n[x][y] = attr[x][y];\n }\n }\n }\n else if (x === 'html') {\n n.innerHTML = attr[x];\n }\n\n // IE doesn't like us setting methods with setAttribute\n else if (!/^on/.test(x)) {\n n.setAttribute(x, attr[x]);\n }\n else {\n n[x] = attr[x];\n }\n }\n }\n }\n }\n\n if (target === 'body') {\n (function self() {\n if (document.body) {\n document.body.appendChild(n);\n }\n else {\n setTimeout(self, 16);\n }\n })();\n }\n else if (typeof (target) === 'object') {\n target.appendChild(n);\n }\n else if (typeof (target) === 'string') {\n document.getElementsByTagName(target)[0].appendChild(n);\n }\n\n return n;\n },\n\n // An easy way to create a hidden iframe\n // @param string src\n iframe: function (src) {\n this.append('iframe', { src: src, style: { position: 'absolute', left: '-1000px', bottom: 0, height: '1px', width: '1px' } }, 'body');\n },\n\n // Recursive merge two objects into one, second parameter overides the first\n // @param a array\n merge: function (/* Args: a, b, c, .. n */) {\n var args = Array.prototype.slice.call(arguments);\n args.unshift({});\n return this.extend.apply(null, args);\n },\n\n // Makes it easier to assign parameters, where some are optional\n // @param o object\n // @param a arguments\n args: function (o, args) {\n\n var p = {};\n var i = 0;\n var t = null;\n var x = null;\n\n // 'x' is the first key in the list of object parameters\n for (x in o) {\n if (o.hasOwnProperty(x)) {\n break;\n }\n }\n\n // Passing in hash object of arguments?\n // Where the first argument can't be an object\n if ((args.length === 1) && (typeof (args[0]) === 'object') && o[x] != 'o!') {\n\n // Could this object still belong to a property?\n // Check the object keys if they match any of the property keys\n for (x in args[0]) {\n if (o.hasOwnProperty(x)) {\n // Does this key exist in the property list?\n if (x in o) {\n // Yes this key does exist so its most likely this function has been invoked with an object parameter\n // Return first argument as the hash of all arguments\n return args[0];\n }\n }\n }\n }\n\n // Else loop through and account for the missing ones.\n for (x in o) {\n if (o.hasOwnProperty(x)) {\n\n t = typeof (args[i]);\n\n if ((typeof (o[x]) === 'function' && o[x].test(args[i])) || (typeof (o[x]) === 'string' && (\n (o[x].indexOf('s') > -1 && t === 'string') ||\n (o[x].indexOf('o') > -1 && t === 'object') ||\n (o[x].indexOf('i') > -1 && t === 'number') ||\n (o[x].indexOf('a') > -1 && t === 'object') ||\n (o[x].indexOf('f') > -1 && t === 'function')\n ))\n ) {\n p[x] = args[i++];\n }\n\n else if (typeof (o[x]) === 'string' && o[x].indexOf('!') > -1) {\n return false;\n }\n }\n }\n\n return p;\n },\n\n // Returns a URL instance\n url: function (path) {\n\n // If the path is empty\n if (!path) {\n return window.location;\n }\n\n // Chrome and FireFox support new URL() to extract URL objects\n else if (window.URL && URL instanceof Function && URL.length !== 0) {\n return new URL(path, window.location);\n }\n\n // Ugly shim, it works!\n else {\n var a = document.createElement('a');\n a.href = path;\n return a.cloneNode(false);\n }\n },\n\n diff: function (a, b) {\n return b.filter(function (item) {\n return a.indexOf(item) === -1;\n });\n },\n\n // Get the different hash of properties unique to `a`, and not in `b`\n diffKey: function (a, b) {\n if (a || !b) {\n var r = {};\n for (var x in a) {\n // Does the property not exist?\n if (!(x in b)) {\n r[x] = a[x];\n }\n }\n\n return r;\n }\n\n return a;\n },\n\n // Unique\n // Remove duplicate and null values from an array\n // @param a array\n unique: function (a) {\n if (!Array.isArray(a)) { return []; }\n\n return a.filter(function (item, index) {\n // Is this the first location of item\n return a.indexOf(item) === index;\n });\n },\n\n isEmpty: function (obj) {\n\n // Scalar\n if (!obj)\n return true;\n\n // Array\n if (Array.isArray(obj)) {\n return !obj.length;\n }\n else if (typeof (obj) === 'object') {\n // Object\n for (var key in obj) {\n if (obj.hasOwnProperty(key)) {\n return false;\n }\n }\n }\n\n return true;\n },\n\n //jscs:disable\n\n\t/*!\n\t ** Thenable -- Embeddable Minimum Strictly-Compliant Promises/A+ 1.1.1 Thenable\n\t ** Copyright (c) 2013-2014 Ralf S. Engelschall \n\t ** Licensed under The MIT License \n\t ** Source-Code distributed on \n\t */\n Promise: (function () {\n /* promise states [Promises/A+ 2.1] */\n var STATE_PENDING = 0; /* [Promises/A+ 2.1.1] */\n var STATE_FULFILLED = 1; /* [Promises/A+ 2.1.2] */\n var STATE_REJECTED = 2; /* [Promises/A+ 2.1.3] */\n\n /* promise object constructor */\n var api = function (executor) {\n /* optionally support non-constructor/plain-function call */\n if (!(this instanceof api))\n return new api(executor);\n\n /* initialize object */\n this.id = \"Thenable/1.0.6\";\n this.state = STATE_PENDING; /* initial state */\n this.fulfillValue = undefined; /* initial value */ /* [Promises/A+ 1.3, 2.1.2.2] */\n this.rejectReason = undefined; /* initial reason */ /* [Promises/A+ 1.5, 2.1.3.2] */\n this.onFulfilled = []; /* initial handlers */\n this.onRejected = []; /* initial handlers */\n\n /* provide optional information-hiding proxy */\n this.proxy = {\n then: this.then.bind(this)\n };\n\n /* support optional executor function */\n if (typeof executor === \"function\")\n executor.call(this, this.fulfill.bind(this), this.reject.bind(this));\n };\n\n /* promise API methods */\n api.prototype = {\n /* promise resolving methods */\n fulfill: function (value) { return deliver(this, STATE_FULFILLED, \"fulfillValue\", value); },\n reject: function (value) { return deliver(this, STATE_REJECTED, \"rejectReason\", value); },\n\n /* \"The then Method\" [Promises/A+ 1.1, 1.2, 2.2] */\n then: function (onFulfilled, onRejected) {\n var curr = this;\n var next = new api(); /* [Promises/A+ 2.2.7] */\n curr.onFulfilled.push(\n resolver(onFulfilled, next, \"fulfill\")); /* [Promises/A+ 2.2.2/2.2.6] */\n curr.onRejected.push(\n resolver(onRejected, next, \"reject\")); /* [Promises/A+ 2.2.3/2.2.6] */\n execute(curr);\n return next.proxy; /* [Promises/A+ 2.2.7, 3.3] */\n }\n };\n\n /* deliver an action */\n var deliver = function (curr, state, name, value) {\n if (curr.state === STATE_PENDING) {\n curr.state = state; /* [Promises/A+ 2.1.2.1, 2.1.3.1] */\n curr[name] = value; /* [Promises/A+ 2.1.2.2, 2.1.3.2] */\n execute(curr);\n }\n return curr;\n };\n\n /* execute all handlers */\n var execute = function (curr) {\n if (curr.state === STATE_FULFILLED)\n execute_handlers(curr, \"onFulfilled\", curr.fulfillValue);\n else if (curr.state === STATE_REJECTED)\n execute_handlers(curr, \"onRejected\", curr.rejectReason);\n };\n\n /* execute particular set of handlers */\n var execute_handlers = function (curr, name, value) {\n /* global process: true */\n /* global setImmediate: true */\n /* global setTimeout: true */\n\n /* short-circuit processing */\n if (curr[name].length === 0)\n return;\n\n /* iterate over all handlers, exactly once */\n var handlers = curr[name];\n curr[name] = []; /* [Promises/A+ 2.2.2.3, 2.2.3.3] */\n var func = function () {\n for (var i = 0; i < handlers.length; i++)\n handlers[i](value); /* [Promises/A+ 2.2.5] */\n };\n\n /* execute procedure asynchronously */ /* [Promises/A+ 2.2.4, 3.1] */\n if (typeof process === \"object\" && typeof process.nextTick === \"function\")\n process.nextTick(func);\n else if (typeof setImmediate === \"function\")\n setImmediate(func);\n else\n setTimeout(func, 0);\n };\n\n /* generate a resolver function */\n var resolver = function (cb, next, method) {\n return function (value) {\n if (typeof cb !== \"function\") /* [Promises/A+ 2.2.1, 2.2.7.3, 2.2.7.4] */\n next[method].call(next, value); /* [Promises/A+ 2.2.7.3, 2.2.7.4] */\n else {\n var result;\n try { result = cb(value); } /* [Promises/A+ 2.2.2.1, 2.2.3.1, 2.2.5, 3.2] */\n catch (e) {\n next.reject(e); /* [Promises/A+ 2.2.7.2] */\n return;\n }\n resolve(next, result); /* [Promises/A+ 2.2.7.1] */\n }\n };\n };\n\n /* \"Promise Resolution Procedure\" */ /* [Promises/A+ 2.3] */\n var resolve = function (promise, x) {\n /* sanity check arguments */ /* [Promises/A+ 2.3.1] */\n if (promise === x || promise.proxy === x) {\n promise.reject(new TypeError(\"cannot resolve promise with itself\"));\n return;\n }\n\n\t\t\t/* surgically check for a \"then\" method\n\t\t\t\t(mainly to just call the \"getter\" of \"then\" only once) */\n var then;\n if ((typeof x === \"object\" && x !== null) || typeof x === \"function\") {\n try { then = x.then; } /* [Promises/A+ 2.3.3.1, 3.5] */\n catch (e) {\n promise.reject(e); /* [Promises/A+ 2.3.3.2] */\n return;\n }\n }\n\n\t\t\t/* handle own Thenables [Promises/A+ 2.3.2]\n\t\t\t\tand similar \"thenables\" [Promises/A+ 2.3.3] */\n if (typeof then === \"function\") {\n var resolved = false;\n try {\n /* call retrieved \"then\" method */ /* [Promises/A+ 2.3.3.3] */\n then.call(x,\n /* resolvePromise */ /* [Promises/A+ 2.3.3.3.1] */\n function (y) {\n if (resolved) return; resolved = true; /* [Promises/A+ 2.3.3.3.3] */\n if (y === x) /* [Promises/A+ 3.6] */\n promise.reject(new TypeError(\"circular thenable chain\"));\n else\n resolve(promise, y);\n },\n\n /* rejectPromise */ /* [Promises/A+ 2.3.3.3.2] */\n function (r) {\n if (resolved) return; resolved = true; /* [Promises/A+ 2.3.3.3.3] */\n promise.reject(r);\n }\n );\n }\n catch (e) {\n if (!resolved) /* [Promises/A+ 2.3.3.3.3] */\n promise.reject(e); /* [Promises/A+ 2.3.3.3.4] */\n }\n return;\n }\n\n /* handle other values */\n promise.fulfill(x); /* [Promises/A+ 2.3.4, 2.3.3.4] */\n };\n\n /* export API */\n return api;\n })(),\n\n //jscs:enable\n\n // Event\n // A contructor superclass for adding event menthods, on, off, emit.\n Event: function () {\n\n var separator = /[\\s\\,]+/;\n\n // If this doesn't support getPrototype then we can't get prototype.events of the parent\n // So lets get the current instance events, and add those to a parent property\n this.parent = {\n events: this.events,\n findEvents: this.findEvents,\n parent: this.parent,\n utils: this.utils\n };\n\n this.events = {};\n\n // On, subscribe to events\n // @param evt string\n // @param callback function\n this.on = function (evt, callback) {\n\n if (callback && typeof (callback) === 'function') {\n var a = evt.split(separator);\n for (var i = 0; i < a.length; i++) {\n\n // Has this event already been fired on this instance?\n this.events[a[i]] = [callback].concat(this.events[a[i]] || []);\n }\n }\n\n return this;\n };\n\n // Off, unsubscribe to events\n // @param evt string\n // @param callback function\n this.off = function (evt, callback) {\n\n this.findEvents(evt, function (name, index) {\n if (!callback || this.events[name][index] === callback) {\n this.events[name][index] = null;\n }\n });\n\n return this;\n };\n\n // Emit\n // Triggers any subscribed events\n this.emit = function (evt /*, data, ... */) {\n\n // Get arguments as an Array, knock off the first one\n var args = Array.prototype.slice.call(arguments, 1);\n args.push(evt);\n\n // Handler\n var handler = function (name, index) {\n\n // Replace the last property with the event name\n args[args.length - 1] = (name === '*' ? evt : name);\n\n // Trigger\n this.events[name][index].apply(this, args);\n };\n\n // Find the callbacks which match the condition and call\n var _this = this;\n while (_this && _this.findEvents) {\n\n // Find events which match\n _this.findEvents(evt + ',*', handler);\n _this = _this.parent;\n }\n\n return this;\n };\n\n //\n // Easy functions\n this.emitAfter = function () {\n var _this = this;\n var args = arguments;\n setTimeout(function () {\n _this.emit.apply(_this, args);\n }, 0);\n\n return this;\n };\n\n this.findEvents = function (evt, callback) {\n\n var a = evt.split(separator);\n\n for (var name in this.events) {\n if (this.events.hasOwnProperty(name)) {\n\n if (a.indexOf(name) > -1) {\n\n for (var i = 0; i < this.events[name].length; i++) {\n\n // Does the event handler exist?\n if (this.events[name][i]) {\n // Emit on the local instance of this\n callback.call(this, name, i);\n }\n }\n }\n }\n }\n };\n\n return this;\n },\n\n // Global Events\n // Attach the callback to the window object\n // Return its unique reference\n globalEvent: function (callback, guid) {\n // If the guid has not been supplied then create a new one.\n guid = guid || '_hellojs_' + parseInt(Math.random() * 1e12, 10).toString(36);\n\n // Define the callback function\n window[guid] = function () {\n // Trigger the callback\n try {\n if (callback.apply(this, arguments)) {\n delete window[guid];\n }\n }\n catch (e) {\n console.error(e);\n }\n };\n\n return guid;\n },\n\n // Trigger a clientside popup\n // This has been augmented to support PhoneGap\n popup: function (url, redirectUri, options) {\n\n var documentElement = document.documentElement;\n\n // Multi Screen Popup Positioning (http://stackoverflow.com/a/16861050)\n // Credit: http://www.xtf.dk/2011/08/center-new-popup-window-even-on.html\n // Fixes dual-screen position Most browsers Firefox\n\n if (options.height) {\n var dualScreenTop = window.screenTop !== undefined ? window.screenTop : screen.top;\n var height = screen.height || window.innerHeight || documentElement.clientHeight;\n options.top = (options.top) ? options.top : parseInt((height - options.height) / 2, 10) + dualScreenTop;\n }\n\n if (options.width) {\n var dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : screen.left;\n var width = screen.width || window.innerWidth || documentElement.clientWidth;\n options.left = (options.left) ? options.left : parseInt((width - options.width) / 2, 10) + dualScreenLeft;\n }\n\n // Convert options into an array\n var optionsArray = [];\n Object.keys(options).forEach(function (name) {\n var value = options[name];\n optionsArray.push(name + (value !== null ? '=' + value : ''));\n });\n\n // Call the open() function with the initial path\n //\n // OAuth redirect, fixes URI fragments from being lost in Safari\n // (URI Fragments within 302 Location URI are lost over HTTPS)\n // Loading the redirect.html before triggering the OAuth Flow seems to fix it.\n //\n // Firefox decodes URL fragments when calling location.hash.\n // - This is bad if the value contains break points which are escaped\n // - Hence the url must be encoded twice as it contains breakpoints.\n if (navigator.userAgent.indexOf('Safari') !== -1 && navigator.userAgent.indexOf('Chrome') === -1) {\n url = redirectUri + '&oauth_redirect=' + encodeURIComponent(encodeURIComponent(url));\n }\n\n var popup = window.open(\n url,\n '_blank',\n optionsArray.join(',')\n );\n\n if (popup && popup.focus) {\n popup.focus();\n }\n\n return popup;\n },\n\n // OAuth and API response handler\n responseHandler: function (window, parent) {\n\n var _this = this;\n var p;\n var location = window.location;\n\n // Is this an auth relay message which needs to call the proxy?\n p = _this.param(location.search);\n\n // OAuth2 or OAuth1 server response?\n if (p && p.state && (p.code || p.oauth_token)) {\n\n var state = JSON.parse(p.state);\n\n // Add this path as the redirect_uri\n p.redirect_uri = state.redirect_uri || location.href.replace(/[\\?\\&].*$/, '');\n\n // Redirect to the host\n var path = _this.qs(state.oauth_proxy, p);\n\n location.assign(path);\n\n return;\n }\n\n // Save session, from redirected authentication\n // #access_token has come in?\n //\n // FACEBOOK is returning auth errors within as a query_string... thats a stickler for consistency.\n // SoundCloud is the state in the querystring and the token in the hashtag, so we'll mix the two together\n\n p = _this.merge(_this.param(location.search || ''), _this.param(location.hash || ''));\n\n // If p.state\n if (p && 'state' in p) {\n\n // Remove any addition information\n // E.g. p.state = 'facebook.page';\n try {\n var a = JSON.parse(p.state);\n _this.extend(p, a);\n }\n catch (e) {\n var stateDecoded = decodeURIComponent(p.state);\n try {\n var b = JSON.parse(stateDecoded);\n _this.extend(p, b);\n }\n catch (e) {\n console.error('Could not decode state parameter');\n }\n }\n\n // Access_token?\n if (('access_token' in p && p.access_token) && p.network) {\n\n if (!p.expires_in || parseInt(p.expires_in, 10) === 0) {\n // If p.expires_in is unset, set to 0\n p.expires_in = 0;\n }\n\n p.expires_in = parseInt(p.expires_in, 10);\n p.expires = ((new Date()).getTime() / 1e3) + (p.expires_in || (60 * 60 * 24 * 365));\n\n // Lets use the \"state\" to assign it to one of our networks\n authCallback(p, window, parent);\n }\n\n // Error=?\n // &error_description=?\n // &state=?\n else if (('error' in p && p.error) && p.network) {\n\n p.error = {\n code: p.error,\n message: p.error_message || p.error_description\n };\n\n // Let the state handler handle it\n authCallback(p, window, parent);\n }\n\n // API call, or a cancelled login\n // Result is serialized JSON string\n else if (p.callback && p.callback in parent) {\n\n // Trigger a function in the parent\n var res = 'result' in p && p.result ? JSON.parse(p.result) : false;\n\n // Trigger the callback on the parent\n callback(parent, p.callback)(res);\n closeWindow();\n }\n\n // If this page is still open\n if (p.page_uri) {\n location.assign(p.page_uri);\n }\n }\n\n // OAuth redirect, fixes URI fragments from being lost in Safari\n // (URI Fragments within 302 Location URI are lost over HTTPS)\n // Loading the redirect.html before triggering the OAuth Flow seems to fix it.\n else if ('oauth_redirect' in p) {\n\n location.assign(decodeURIComponent(p.oauth_redirect));\n return;\n }\n\n // Trigger a callback to authenticate\n function authCallback(obj, window, parent) {\n\n var cb = obj.callback;\n var network = obj.network;\n\n // Trigger the callback on the parent\n _this.store(network, obj);\n\n // If this is a page request it has no parent or opener window to handle callbacks\n if (('display' in obj) && obj.display === 'page') {\n return;\n }\n\n // Remove from session object\n if (parent && cb && cb in parent) {\n\n try {\n delete obj.callback;\n }\n catch (e) { }\n\n // Update store\n _this.store(network, obj);\n\n // Call the globalEvent function on the parent\n // It's safer to pass back a string to the parent,\n // Rather than an object/array (better for IE8)\n var str = JSON.stringify(obj);\n\n try {\n callback(parent, cb)(str);\n }\n catch (e) {\n // Error thrown whilst executing parent callback\n }\n }\n\n closeWindow();\n }\n\n function callback(parent, callbackID) {\n if (callbackID.indexOf('_hellojs_') !== 0) {\n return function () {\n throw 'Could not execute callback ' + callbackID;\n };\n }\n\n return parent[callbackID];\n }\n\n function closeWindow() {\n\n if (window.frameElement) {\n // Inside an iframe, remove from parent\n parent.document.body.removeChild(window.frameElement);\n }\n else {\n // Close this current window\n try {\n window.close();\n }\n catch (e) { }\n\n // IOS bug wont let us close a popup if still loading\n if (window.addEventListener) {\n window.addEventListener('load', function () {\n window.close();\n });\n }\n }\n\n }\n }\n});\n\n// Events\n// Extend the hello object with its own event instance\nhello.utils.Event.call(hello);\n\n///////////////////////////////////\n// Monitoring session state\n// Check for session changes\n///////////////////////////////////\n\n(function (hello) {\n\n // Monitor for a change in state and fire\n var oldSessions = {};\n\n // Hash of expired tokens\n var expired = {};\n\n // Listen to other triggers to Auth events, use these to update this\n hello.on('auth.login, auth.logout', function (auth) {\n if (auth && typeof (auth) === 'object' && auth.network) {\n oldSessions[auth.network] = hello.utils.store(auth.network) || {};\n }\n });\n\n (function self() {\n\n var CURRENT_TIME = ((new Date()).getTime() / 1e3);\n var emit = function (eventName) {\n hello.emit('auth.' + eventName, {\n network: name,\n authResponse: session\n });\n };\n\n // Loop through the services\n for (var name in hello.services) {\n if (hello.services.hasOwnProperty(name)) {\n\n if (!hello.services[name].id) {\n // We haven't attached an ID so dont listen.\n continue;\n }\n\n // Get session\n var session = hello.utils.store(name) || {};\n var provider = hello.services[name];\n var oldSess = oldSessions[name] || {};\n\n // Listen for globalEvents that did not get triggered from the child\n if (session && 'callback' in session) {\n\n // To do remove from session object...\n var cb = session.callback;\n try {\n delete session.callback;\n }\n catch (e) { }\n\n // Update store\n // Removing the callback\n hello.utils.store(name, session);\n\n // Emit global events\n try {\n window[cb](session);\n }\n catch (e) { }\n }\n\n // Refresh token\n if (session && ('expires' in session) && session.expires < CURRENT_TIME) {\n\n // If auto refresh is possible\n // Either the browser supports\n var refresh = provider.refresh || session.refresh_token;\n\n // Has the refresh been run recently?\n if (refresh && (!(name in expired) || expired[name] < CURRENT_TIME)) {\n // Try to resignin\n hello.emit('notice', name + ' has expired trying to resignin');\n hello.login(name, { display: 'none', force: false });\n\n // Update expired, every 10 minutes\n expired[name] = CURRENT_TIME + 600;\n }\n\n // Does this provider not support refresh\n else if (!refresh && !(name in expired)) {\n // Label the event\n emit('expired');\n expired[name] = true;\n }\n\n // If session has expired then we dont want to store its value until it can be established that its been updated\n continue;\n }\n\n // Has session changed?\n else if (oldSess.access_token === session.access_token &&\n oldSess.expires === session.expires) {\n continue;\n }\n\n // Access_token has been removed\n else if (!session.access_token && oldSess.access_token) {\n emit('logout');\n }\n\n // Access_token has been created\n else if (session.access_token && !oldSess.access_token) {\n emit('login');\n }\n\n // Access_token has been updated\n else if (session.expires !== oldSess.expires) {\n emit('update');\n }\n\n // Updated stored session\n oldSessions[name] = session;\n\n // Remove the expired flags\n if (name in expired) {\n delete expired[name];\n }\n }\n }\n\n // Check error events\n setTimeout(self, 1000);\n })();\n\n})(hello);\n\n// EOF CORE lib\n//////////////////////////////////\n\n/////////////////////////////////////////\n// API\n// @param path string\n// @param query object (optional)\n// @param method string (optional)\n// @param data object (optional)\n// @param timeout integer (optional)\n// @param callback function (optional)\n\nhello.api = function () {\n\n // Shorthand\n var _this = this;\n var utils = _this.utils;\n var error = utils.error;\n\n // Construct a new Promise object\n var promise = utils.Promise();\n\n // Arguments\n var p = utils.args({ path: 's!', query: 'o', method: 's', data: 'o', timeout: 'i', callback: 'f' }, arguments);\n\n // Method\n p.method = (p.method || 'get').toLowerCase();\n\n // Headers\n p.headers = p.headers || {};\n\n // Query\n p.query = p.query || {};\n\n // If get, put all parameters into query\n if (p.method === 'get' || p.method === 'delete') {\n utils.extend(p.query, p.data);\n p.data = {};\n }\n\n var data = p.data = p.data || {};\n\n // Completed event callback\n promise.then(p.callback, p.callback);\n\n // Remove the network from path, e.g. facebook:/me/friends\n // Results in { network : facebook, path : me/friends }\n if (!p.path) {\n return promise.reject(error('invalid_path', 'Missing the path parameter from the request'));\n }\n\n p.path = p.path.replace(/^\\/+/, '');\n var a = (p.path.split(/[\\/\\:]/, 2) || [])[0].toLowerCase();\n\n if (a in _this.services) {\n p.network = a;\n var reg = new RegExp('^' + a + ':?\\/?');\n p.path = p.path.replace(reg, '');\n }\n\n // Network & Provider\n // Define the network that this request is made for\n p.network = _this.settings.default_service = p.network || _this.settings.default_service;\n var o = _this.services[p.network];\n\n // INVALID\n // Is there no service by the given network name?\n if (!o) {\n return promise.reject(error('invalid_network', 'Could not match the service requested: ' + p.network));\n }\n\n // PATH\n // As long as the path isn't flagged as unavaiable, e.g. path == false\n\n if (!(!(p.method in o) || !(p.path in o[p.method]) || o[p.method][p.path] !== false)) {\n return promise.reject(error('invalid_path', 'The provided path is not available on the selected network'));\n }\n\n // PROXY\n // OAuth1 calls always need a proxy\n\n if (!p.oauth_proxy) {\n p.oauth_proxy = _this.settings.oauth_proxy;\n }\n\n if (!('proxy' in p)) {\n p.proxy = p.oauth_proxy && o.oauth && parseInt(o.oauth.version, 10) === 1;\n }\n\n // TIMEOUT\n // Adopt timeout from global settings by default\n\n if (!('timeout' in p)) {\n p.timeout = _this.settings.timeout;\n }\n\n // Format response\n // Whether to run the raw response through post processing.\n if (!('formatResponse' in p)) {\n p.formatResponse = true;\n }\n\n // Get the current session\n // Append the access_token to the query\n p.authResponse = _this.getAuthResponse(p.network);\n if (p.authResponse && p.authResponse.access_token) {\n p.query.access_token = p.authResponse.access_token;\n }\n\n var url = p.path;\n var m;\n\n // Store the query as options\n // This is used to populate the request object before the data is augmented by the prewrap handlers.\n p.options = utils.clone(p.query);\n\n // Clone the data object\n // Prevent this script overwriting the data of the incoming object.\n // Ensure that everytime we run an iteration the callbacks haven't removed some data\n p.data = utils.clone(data);\n\n // URL Mapping\n // Is there a map for the given URL?\n var actions = o[{ 'delete': 'del' }[p.method] || p.method] || {};\n\n // Extrapolate the QueryString\n // Provide a clean path\n // Move the querystring into the data\n if (p.method === 'get') {\n\n var query = url.split(/[\\?&]/)[1];\n if (query) {\n utils.extend(p.query, utils.param(query));\n\n // Remove the query part from the URL\n url = url.replace(/\\?.*?(&|$)/, '$1');\n }\n }\n\n // Is the hash fragment defined\n if ((m = url.match(/&(.+)/, ''))) {\n url = url.split('&')[0];\n p.path = m[1];\n }\n else if (url in actions) {\n p.path = url;\n url = actions[url];\n }\n else if ('default' in actions) {\n url = actions['default'];\n }\n\n // Redirect Handler\n // This defines for the Form+Iframe+Hash hack where to return the results too.\n p.redirect_uri = _this.settings.redirect_uri;\n\n // Define FormatHandler\n // The request can be procesed in a multitude of ways\n // Here's the options - depending on the browser and endpoint\n p.xhr = o.xhr;\n p.jsonp = o.jsonp;\n p.form = o.form;\n\n // Make request\n if (typeof (url) === 'function') {\n // Does self have its own callback?\n url(p, getPath);\n }\n else {\n // Else the URL is a string\n getPath(url);\n }\n\n return promise.proxy;\n\n // If url needs a base\n // Wrap everything in\n function getPath(url) {\n\n // Format the string if it needs it\n url = url.replace(/\\@\\{([a-z\\_\\-]+)(\\|.*?)?\\}/gi, function (m, key, defaults) {\n var val = defaults ? defaults.replace(/^\\|/, '') : '';\n if (key in p.query) {\n val = p.query[key];\n delete p.query[key];\n }\n else if (p.data && key in p.data) {\n val = p.data[key];\n delete p.data[key];\n }\n else if (!defaults) {\n promise.reject(error('missing_attribute', 'The attribute ' + key + ' is missing from the request'));\n }\n\n return val;\n });\n\n // Add base\n if (!url.match(/^https?:\\/\\//)) {\n url = o.base + url;\n }\n\n // Define the request URL\n p.url = url;\n\n // Make the HTTP request with the curated request object\n // CALLBACK HANDLER\n // @ response object\n // @ statusCode integer if available\n utils.request(p, function (r, headers) {\n\n // Is this a raw response?\n if (!p.formatResponse) {\n // Bad request? error statusCode or otherwise contains an error response vis JSONP?\n if (typeof headers === 'object' ? (headers.statusCode >= 400) : (typeof r === 'object' && 'error' in r)) {\n promise.reject(r);\n }\n else {\n promise.fulfill(r);\n }\n\n return;\n }\n\n // Should this be an object\n if (r === true) {\n r = { success: true };\n }\n else if (!r) {\n r = {};\n }\n\n // The delete callback needs a better response\n if (p.method === 'delete') {\n r = (!r || utils.isEmpty(r)) ? { success: true } : r;\n }\n\n // FORMAT RESPONSE?\n // Does self request have a corresponding formatter\n if (o.wrap && ((p.path in o.wrap) || ('default' in o.wrap))) {\n var wrap = (p.path in o.wrap ? p.path : 'default');\n var time = (new Date()).getTime();\n\n // FORMAT RESPONSE\n var b = o.wrap[wrap](r, headers, p);\n\n // Has the response been utterly overwritten?\n // Typically self augments the existing object.. but for those rare occassions\n if (b) {\n r = b;\n }\n }\n\n // Is there a next_page defined in the response?\n if (r && 'paging' in r && r.paging.next) {\n\n // Add the relative path if it is missing from the paging/next path\n if (r.paging.next[0] === '?') {\n r.paging.next = p.path + r.paging.next;\n }\n\n // The relative path has been defined, lets markup the handler in the HashFragment\n else {\n r.paging.next += '&' + p.path;\n }\n }\n\n // Dispatch to listeners\n // Emit events which pertain to the formatted response\n if (!r || 'error' in r) {\n promise.reject(r);\n }\n else {\n promise.fulfill(r);\n }\n });\n }\n};\n\n// API utilities\nhello.utils.extend(hello.utils, {\n\n // Make an HTTP request\n request: function (p, callback) {\n\n var _this = this;\n var error = _this.error;\n\n // This has to go through a POST request\n if (!_this.isEmpty(p.data) && !('FileList' in window) && _this.hasBinary(p.data)) {\n\n // Disable XHR and JSONP\n p.xhr = false;\n p.jsonp = false;\n }\n\n // Check if the browser and service support CORS\n var cors = this.request_cors(function () {\n // If it does then run this...\n return ((p.xhr === undefined) || (p.xhr && (typeof (p.xhr) !== 'function' || p.xhr(p, p.query))));\n });\n\n if (cors) {\n\n formatUrl(p, function (url) {\n\n var x = _this.xhr(p.method, url, p.headers, p.data, callback);\n x.onprogress = p.onprogress || null;\n\n // Windows Phone does not support xhr.upload, see #74\n // Feature detect\n if (x.upload && p.onuploadprogress) {\n x.upload.onprogress = p.onuploadprogress;\n }\n\n });\n\n return;\n }\n\n // Clone the query object\n // Each request modifies the query object and needs to be tared after each one.\n var _query = p.query;\n\n p.query = _this.clone(p.query);\n\n // Assign a new callbackID\n p.callbackID = _this.globalEvent();\n\n // JSONP\n if (p.jsonp !== false) {\n\n // Clone the query object\n p.query.callback = p.callbackID;\n\n // If the JSONP is a function then run it\n if (typeof (p.jsonp) === 'function') {\n p.jsonp(p, p.query);\n }\n\n // Lets use JSONP if the method is 'get'\n if (p.method === 'get') {\n\n formatUrl(p, function (url) {\n _this.jsonp(url, callback, p.callbackID, p.timeout);\n });\n\n return;\n }\n else {\n // It's not compatible reset query\n p.query = _query;\n }\n\n }\n\n // Otherwise we're on to the old school, iframe hacks and JSONP\n if (p.form !== false) {\n\n // Add some additional query parameters to the URL\n // We're pretty stuffed if the endpoint doesn't like these\n p.query.redirect_uri = p.redirect_uri;\n p.query.state = JSON.stringify({ callback: p.callbackID });\n\n var opts;\n\n if (typeof (p.form) === 'function') {\n\n // Format the request\n opts = p.form(p, p.query);\n }\n\n if (p.method === 'post' && opts !== false) {\n\n formatUrl(p, function (url) {\n _this.post(url, p.data, opts, callback, p.callbackID, p.timeout);\n });\n\n return;\n }\n }\n\n // None of the methods were successful throw an error\n callback(error('invalid_request', 'There was no mechanism for handling this request'));\n\n return;\n\n // Format URL\n // Constructs the request URL, optionally wraps the URL through a call to a proxy server\n // Returns the formatted URL\n function formatUrl(p, callback) {\n\n // Are we signing the request?\n var sign;\n\n // OAuth1\n // Remove the token from the query before signing\n if (p.authResponse && p.authResponse.oauth && parseInt(p.authResponse.oauth.version, 10) === 1) {\n\n // OAUTH SIGNING PROXY\n sign = p.query.access_token;\n\n // Remove the access_token\n delete p.query.access_token;\n\n // Enfore use of Proxy\n p.proxy = true;\n }\n\n // POST body to querystring\n if (p.data && (p.method === 'get' || p.method === 'delete')) {\n // Attach the p.data to the querystring.\n _this.extend(p.query, p.data);\n p.data = null;\n }\n\n // Construct the path\n var path = _this.qs(p.url, p.query);\n\n // Proxy the request through a server\n // Used for signing OAuth1\n // And circumventing services without Access-Control Headers\n if (p.proxy) {\n // Use the proxy as a path\n path = _this.qs(p.oauth_proxy, {\n path: path,\n access_token: sign || '',\n\n // This will prompt the request to be signed as though it is OAuth1\n then: p.proxy_response_type || (p.method.toLowerCase() === 'get' ? 'redirect' : 'proxy'),\n method: p.method.toLowerCase(),\n suppress_response_codes: true\n });\n }\n\n callback(path);\n }\n },\n\n // Test whether the browser supports the CORS response\n request_cors: function (callback) {\n return 'withCredentials' in new XMLHttpRequest() && callback();\n },\n\n // Return the type of DOM object\n domInstance: function (type, data) {\n var test = 'HTML' + (type || '').replace(\n /^[a-z]/,\n function (m) {\n return m.toUpperCase();\n }\n\n ) + 'Element';\n\n if (!data) {\n return false;\n }\n\n if (window[test]) {\n return data instanceof window[test];\n }\n else if (window.Element) {\n return data instanceof window.Element && (!type || (data.tagName && data.tagName.toLowerCase() === type));\n }\n else {\n return (!(data instanceof Object || data instanceof Array || data instanceof String || data instanceof Number) && data.tagName && data.tagName.toLowerCase() === type);\n }\n },\n\n // Create a clone of an object\n clone: function (obj) {\n // Does not clone DOM elements, nor Binary data, e.g. Blobs, Filelists\n if (obj === null || typeof (obj) !== 'object' || obj instanceof Date || 'nodeName' in obj || this.isBinary(obj) || (typeof FormData === 'function' && obj instanceof FormData)) {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n // Clone each item in the array\n return obj.map(this.clone.bind(this));\n }\n\n // But does clone everything else.\n var clone = {};\n for (var x in obj) {\n clone[x] = this.clone(obj[x]);\n }\n\n return clone;\n },\n\n // XHR: uses CORS to make requests\n xhr: function (method, url, headers, data, callback) {\n\n var r = new XMLHttpRequest();\n var error = this.error;\n\n // Binary?\n var binary = false;\n if (method === 'blob') {\n binary = method;\n method = 'GET';\n }\n\n method = method.toUpperCase();\n\n // Xhr.responseType 'json' is not supported in any of the vendors yet.\n r.onload = function (e) {\n var json = r.response;\n try {\n json = JSON.parse(r.responseText);\n }\n catch (_e) {\n if (r.status === 401) {\n json = error('access_denied', r.statusText);\n }\n }\n\n var headers = headersToJSON(r.getAllResponseHeaders());\n headers.statusCode = r.status;\n\n callback(json || (method === 'GET' ? error('empty_response', 'Could not get resource') : {}), headers);\n };\n\n r.onerror = function (e) {\n var json = r.responseText;\n try {\n json = JSON.parse(r.responseText);\n }\n catch (_e) { }\n\n callback(json || error('access_denied', 'Could not get resource'));\n };\n\n var x;\n\n // Should we add the query to the URL?\n if (method === 'GET' || method === 'DELETE') {\n data = null;\n }\n else if (data && typeof (data) !== 'string' && !(data instanceof FormData) && !(data instanceof File) && !(data instanceof Blob)) {\n // Loop through and add formData\n var f = new FormData();\n for (x in data) if (data.hasOwnProperty(x)) {\n if (data[x] instanceof HTMLInputElement) {\n if ('files' in data[x] && data[x].files.length > 0) {\n f.append(x, data[x].files[0]);\n }\n }\n else if (data[x] instanceof Blob) {\n f.append(x, data[x], data.name);\n }\n else {\n f.append(x, data[x]);\n }\n }\n\n data = f;\n }\n\n // Open the path, async\n r.open(method, url, true);\n\n if (binary) {\n if ('responseType' in r) {\n r.responseType = binary;\n }\n else {\n r.overrideMimeType('text/plain; charset=x-user-defined');\n }\n }\n\n // Set any bespoke headers\n if (headers) {\n for (x in headers) {\n r.setRequestHeader(x, headers[x]);\n }\n }\n\n r.send(data);\n\n return r;\n\n // Headers are returned as a string\n function headersToJSON(s) {\n var r = {};\n var reg = /([a-z\\-]+):\\s?(.*);?/gi;\n var m;\n while ((m = reg.exec(s))) {\n r[m[1]] = m[2];\n }\n\n return r;\n }\n },\n\n // JSONP\n // Injects a script tag into the DOM to be executed and appends a callback function to the window object\n // @param string/function pathFunc either a string of the URL or a callback function pathFunc(querystringhash, continueFunc);\n // @param function callback a function to call on completion;\n jsonp: function (url, callback, callbackID, timeout) {\n\n var _this = this;\n var error = _this.error;\n\n // Change the name of the callback\n var bool = 0;\n var head = document.getElementsByTagName('head')[0];\n var operaFix;\n var result = error('server_error', 'server_error');\n var cb = function () {\n if (!(bool++)) {\n window.setTimeout(function () {\n callback(result);\n head.removeChild(script);\n }, 0);\n }\n\n };\n\n // Add callback to the window object\n callbackID = _this.globalEvent(function (json) {\n result = json;\n return true;\n\n // Mark callback as done\n }, callbackID);\n\n // The URL is a function for some cases and as such\n // Determine its value with a callback containing the new parameters of this function.\n url = url.replace(new RegExp('=\\\\?(&|$)'), '=' + callbackID + '$1');\n\n // Build script tag\n var script = _this.append('script', {\n id: callbackID,\n name: callbackID,\n src: url,\n async: true,\n onload: cb,\n onerror: cb,\n onreadystatechange: function () {\n if (/loaded|complete/i.test(this.readyState)) {\n cb();\n }\n }\n });\n\n // Opera fix error\n // Problem: If an error occurs with script loading Opera fails to trigger the script.onerror handler we specified\n //\n // Fix:\n // By setting the request to synchronous we can trigger the error handler when all else fails.\n // This action will be ignored if we've already called the callback handler \"cb\" with a successful onload event\n if (window.navigator.userAgent.toLowerCase().indexOf('opera') > -1) {\n operaFix = _this.append('script', {\n text: 'document.getElementById(\\'' + callbackID + '\\').onerror();'\n });\n script.async = false;\n }\n\n // Add timeout\n if (timeout) {\n window.setTimeout(function () {\n result = error('timeout', 'timeout');\n cb();\n }, timeout);\n }\n\n // TODO: add fix for IE,\n // However: unable recreate the bug of firing off the onreadystatechange before the script content has been executed and the value of \"result\" has been defined.\n // Inject script tag into the head element\n head.appendChild(script);\n\n // Append Opera Fix to run after our script\n if (operaFix) {\n head.appendChild(operaFix);\n }\n },\n\n // Post\n // Send information to a remote location using the post mechanism\n // @param string uri path\n // @param object data, key value data to send\n // @param function callback, function to execute in response\n post: function (url, data, options, callback, callbackID, timeout) {\n\n var _this = this;\n var error = _this.error;\n var doc = document;\n\n // This hack needs a form\n var form = null;\n var reenableAfterSubmit = [];\n var newform;\n var i = 0;\n var x = null;\n var bool = 0;\n var cb = function (r) {\n if (!(bool++)) {\n callback(r);\n }\n };\n\n // What is the name of the callback to contain\n // We'll also use this to name the iframe\n _this.globalEvent(cb, callbackID);\n\n // Build the iframe window\n var win;\n try {\n // IE7 hack, only lets us define the name here, not later.\n win = doc.createElement('