{"action":"created","comment":{"url":"https://api.github.com/repos/HiP-App/HiPCMS/pulls/comments/56748983","id":56748983,"diff_hunk":"@@ -0,0 +1,856 @@\n+/**\n+ * Satellizer 0.10.1\n+ * (c) 2015 Sahat Yalkabov\n+ * License: MIT\n+ */\n+(function(window, angular, undefined) {\n+  'use strict';\n+\n+  angular.module('satellizer', [])\n+    .constant('satellizer.config', {\n+      httpInterceptor: true,\n+      loginOnSignup: true,\n+      baseUrl: '/',\n+      loginRedirect: '/',\n+      logoutRedirect: '/',\n+      signupRedirect: '/login',\n+      loginUrl: '/auth/login',\n+      signupUrl: '/auth/signup',\n+      loginRoute: '/login',\n+      signupRoute: '/signup',\n+      tokenRoot: false,\n+      tokenName: 'token',\n+      tokenPrefix: 'satellizer',\n+      unlinkUrl: '/auth/unlink/',\n+      unlinkMethod: 'get',\n+      authHeader: 'Authorization',\n+      authToken: 'Bearer',\n+      withCredentials: true,\n+      platform: 'browser',\n+      storage: 'localStorage',\n+      providers: {\n+        google: {\n+          name: 'google',\n+          url: '/auth/google',\n+          authorizationEndpoint: 'https://accounts.google.com/o/oauth2/auth',\n+          redirectUri: window.location.origin || window.location.protocol + '//' + window.location.host,\n+          scope: ['profile', 'email'],\n+          scopePrefix: 'openid',\n+          scopeDelimiter: ' ',\n+          requiredUrlParams: ['scope'],\n+          optionalUrlParams: ['display'],\n+          display: 'popup',\n+          type: '2.0',\n+          popupOptions: { width: 452, height: 633 }\n+        },\n+        facebook: {\n+          name: 'facebook',\n+          url: '/auth/facebook',\n+          authorizationEndpoint: 'https://www.facebook.com/v2.3/dialog/oauth',\n+          redirectUri: window.location.origin + '/' || window.location.protocol + '//' + window.location.host + '/',\n+          scope: ['email'],\n+          scopeDelimiter: ',',\n+          requiredUrlParams: ['display', 'scope'],\n+          display: 'popup',\n+          type: '2.0',\n+          popupOptions: { width: 580, height: 400 }\n+        },\n+        linkedin: {\n+          name: 'linkedin',\n+          url: '/auth/linkedin',\n+          authorizationEndpoint: 'https://www.linkedin.com/uas/oauth2/authorization',\n+          redirectUri: window.location.origin || window.location.protocol + '//' + window.location.host,\n+          requiredUrlParams: ['state'],\n+          scope: ['r_emailaddress'],\n+          scopeDelimiter: ' ',\n+          state: 'STATE',\n+          type: '2.0',\n+          popupOptions: { width: 527, height: 582 }\n+        },\n+        github: {\n+          name: 'github',\n+          url: '/auth/github',\n+          authorizationEndpoint: 'https://github.com/login/oauth/authorize',\n+          redirectUri: window.location.origin || window.location.protocol + '//' + window.location.host,\n+          optionalUrlParams: ['scope'],\n+          scope: ['user:email'],\n+          scopeDelimiter: ' ',\n+          type: '2.0',\n+          popupOptions: { width: 1020, height: 618 }\n+        },\n+        yahoo: {\n+          name: 'yahoo',\n+          url: '/auth/yahoo',\n+          authorizationEndpoint: 'https://api.login.yahoo.com/oauth2/request_auth',\n+          redirectUri: window.location.origin || window.location.protocol + '//' + window.location.host,\n+          scope: [],\n+          scopeDelimiter: ',',\n+          type: '2.0',\n+          popupOptions: { width: 559, height: 519 }\n+        },\n+        twitter: {\n+          name: 'twitter',\n+          url: '/auth/twitter',\n+          type: '1.0',\n+          popupOptions: { width: 495, height: 645 }\n+        },\n+        live: {\n+          name: 'live',\n+          url: '/auth/live',\n+          authorizationEndpoint: 'https://login.live.com/oauth20_authorize.srf',\n+          redirectUri: window.location.origin || window.location.protocol + '//' + window.location.host,\n+          scope: ['wl.emails'],\n+          scopeDelimiter: ' ',\n+          requiredUrlParams: ['display', 'scope'],\n+          display: 'popup',\n+          type: '2.0',\n+          popupOptions: { width: 500, height: 560 }\n+        }\n+      }\n+    })\n+    .provider('$auth', ['satellizer.config', function(config) {\n+      Object.defineProperties(this, {\n+        baseUrl: {\n+          get: function() { return config.baseUrl; },\n+          set: function(value) { config.baseUrl = value; }\n+        },\n+        httpInterceptor: {\n+          get: function() { return config.httpInterceptor; },\n+          set: function(value) { config.httpInterceptor = value; }\n+        },\n+        loginOnSignup: {\n+          get: function() { return config.loginOnSignup; },\n+          set: function(value) { config.loginOnSignup = value; }\n+        },\n+\n+        logoutRedirect: {\n+          get: function() { return config.logoutRedirect; },\n+          set: function(value) { config.logoutRedirect = value; }\n+        },\n+        loginRedirect: {\n+          set: function(value) { config.loginRedirect = value; },\n+          get: function() { return config.loginRedirect; }\n+        },\n+        signupRedirect: {\n+          get: function() { return config.signupRedirect; },\n+          set: function(value) { config.signupRedirect = value; }\n+        },\n+        loginUrl: {\n+          get: function() { return config.loginUrl; },\n+          set: function(value) { config.loginUrl = value; }\n+        },\n+        signupUrl: {\n+          get: function() { return config.signupUrl; },\n+          set: function(value) { config.signupUrl = value; }\n+        },\n+        loginRoute: {\n+          get: function() { return config.loginRoute; },\n+          set: function(value) { config.loginRoute = value; }\n+        },\n+        signupRoute: {\n+          get: function() { return config.signupRoute; },\n+          set: function(value) { config.signupRoute = value; }\n+        },\n+        tokenRoot: {\n+          get: function() { return config.tokenRoot; },\n+          set: function(value) { config.tokenRoot = value; }\n+        },\n+        tokenName: {\n+          get: function() { return config.tokenName; },\n+          set: function(value) { config.tokenName = value; }\n+        },\n+        tokenPrefix: {\n+          get: function() { return config.tokenPrefix; },\n+          set: function(value) { config.tokenPrefix = value; }\n+        },\n+        unlinkUrl: {\n+          get: function() { return config.unlinkUrl; },\n+          set: function(value) { config.unlinkUrl = value; }\n+        },\n+        authHeader: {\n+          get: function() { return config.authHeader; },\n+          set: function(value) { config.authHeader = value; }\n+        },\n+        authToken: {\n+          get: function() { return config.authToken; },\n+          set: function(value) { config.authToken = value; }\n+        },\n+        withCredentials: {\n+          get: function() { return config.withCredentials; },\n+          set: function(value) { config.withCredentials = value; }\n+        },\n+        unlinkMethod: {\n+          get: function() { return config.unlinkMethod; },\n+          set: function(value) { config.unlinkMethod = value; }\n+        },\n+        platform: {\n+          get: function() { return config.platform; },\n+          set: function(value) { config.platform = value; }\n+        },\n+        storage: {\n+          get: function() { return config.storage; },\n+          set: function(value) { config.storage = value; }\n+        }\n+      });\n+\n+      angular.forEach(Object.keys(config.providers), function(provider) {\n+        this[provider] = function(params) {\n+          return angular.extend(config.providers[provider], params);\n+        };\n+      }, this);\n+\n+      var oauth = function(params) {\n+        config.providers[params.name] = config.providers[params.name] || {};\n+        angular.extend(config.providers[params.name], params);\n+      };\n+\n+      this.oauth1 = function(params) {\n+        oauth(params);\n+        config.providers[params.name].type = '1.0';\n+      };\n+\n+      this.oauth2 = function(params) {\n+        oauth(params);\n+        config.providers[params.name].type = '2.0';\n+      };\n+\n+      this.$get = [\n+        '$q',\n+        'satellizer.shared',\n+        'satellizer.local',\n+        'satellizer.oauth',\n+        function($q, shared, local, oauth) {\n+          var $auth = {};\n+\n+          $auth.authenticate = function(name, userData) {\n+            return oauth.authenticate(name, false, userData);\n+          };\n+\n+          $auth.login = function(user, redirect) {\n+            return local.login(user, redirect);\n+          };\n+\n+          $auth.signup = function(user) {\n+            return local.signup(user);\n+          };\n+\n+          $auth.logout = function(redirect) {\n+            return shared.logout(redirect);\n+          };\n+\n+          $auth.isAuthenticated = function() {\n+            return shared.isAuthenticated();\n+          };\n+\n+          $auth.link = function(name, userData) {\n+            return oauth.authenticate(name, true, userData);\n+          };\n+\n+          $auth.unlink = function(provider) {\n+            return oauth.unlink(provider);\n+          };\n+\n+          $auth.getToken = function() {\n+            return shared.getToken();\n+          };\n+\n+          $auth.setToken = function(token, redirect) {\n+            shared.setToken({ access_token: token }, redirect);\n+          };\n+\n+          $auth.removeToken = function() {\n+            return shared.removeToken();\n+          };\n+\n+          $auth.getPayload = function() {\n+            return shared.getPayload();\n+          };\n+\n+          $auth.setStorage = function(type) {\n+            return shared.setStorage(type);\n+          };\n+\n+          return $auth;\n+        }];\n+\n+    }])\n+    .factory('satellizer.shared', [\n+      '$q',\n+      '$window',\n+      '$location',\n+      'satellizer.config',\n+      'satellizer.storage',\n+      function($q, $window, $location, config, storage) {\n+        var shared = {};\n+        var tokenName = config.tokenPrefix ? config.tokenPrefix + '_' + config.tokenName : config.tokenName;\n+\n+        shared.getToken = function() {\n+          return storage.get(tokenName);\n+        };\n+\n+        shared.getPayload = function() {\n+          var token = storage.get(tokenName);\n+\n+          if (token && token.split('.').length === 3) {\n+            var base64Url = token.split('.')[1];\n+            var base64 = base64Url.replace('-', '+').replace('_', '/');\n+            return JSON.parse($window.atob(base64));\n+          }\n+        };\n+\n+        shared.setToken = function(response, redirect) {\n+          var accessToken = response && response.access_token;\n+          var token;\n+\n+          if (accessToken) {\n+            if (angular.isObject(accessToken) && angular.isObject(accessToken.data)) {\n+              response = accessToken;\n+            } else if (angular.isString(accessToken)) {\n+              token = accessToken;\n+            }\n+          }\n+\n+          if (!token && response) {\n+            token = config.tokenRoot && response.data[config.tokenRoot] ?\n+              response.data[config.tokenRoot][config.tokenName] : response.data[config.tokenName];\n+          }\n+\n+          if (!token) {\n+            var tokenPath = config.tokenRoot ? config.tokenRoot + '.' + config.tokenName : config.tokenName;\n+            throw new Error('Expecting a token named \"' + tokenPath + '\" but instead got: ' + JSON.stringify(response.data));\n+          }\n+\n+          storage.set(tokenName, token);\n+\n+          if (config.loginRedirect && !redirect) {\n+            $location.path(config.loginRedirect);\n+          }  else if (redirect && angular.isString(redirect)) {\n+            $location.path(encodeURI(redirect));\n+          }\n+        };\n+\n+        shared.removeToken = function() {\n+          storage.remove(tokenName);\n+        };\n+\n+        shared.isAuthenticated = function() {\n+          var token = storage.get(tokenName);\n+\n+          if (token) {\n+            if (token.split('.').length === 3) {\n+              var base64Url = token.split('.')[1];\n+              var base64 = base64Url.replace('-', '+').replace('_', '/');\n+              var exp = JSON.parse($window.atob(base64)).exp;\n+              if (exp) {\n+                return Math.round(new Date().getTime() / 1000) <= exp;\n+              }\n+            }\n+            return true;\n+          }\n+          return false;\n+        };\n+\n+        shared.logout = function(redirect) {\n+          storage.remove(tokenName);\n+\n+          if (config.logoutRedirect && !redirect) {\n+            $location.url(config.logoutRedirect);\n+          }\n+          else if (angular.isString(redirect)) {\n+            $location.url(redirect);\n+          }\n+\n+          return $q.when();\n+        };\n+\n+        shared.setStorage = function(type){\n+          config.storage = type;\n+        };\n+\n+        return shared;\n+      }])\n+    .factory('satellizer.oauth', [\n+      '$q',\n+      '$http',\n+      'satellizer.config',\n+      'satellizer.shared',\n+      'satellizer.Oauth1',\n+      'satellizer.Oauth2',\n+      function($q, $http, config, shared, Oauth1, Oauth2) {\n+        var oauth = {};\n+\n+        oauth.authenticate = function(name, redirect, userData) {\n+          var provider = config.providers[name].type === '1.0' ? new Oauth1() : new Oauth2();\n+          var deferred = $q.defer();\n+\n+          provider.open(config.providers[name], userData || {})\n+            .then(function(response) {\n+              shared.setToken(response, redirect);\n+              deferred.resolve(response);\n+            })\n+            .catch(function(error) {\n+              deferred.reject(error);\n+            });\n+\n+          return deferred.promise;\n+        };\n+\n+        oauth.unlink = function(provider) {\n+          if (config.unlinkMethod === 'get') {\n+            return $http.get(config.unlinkUrl + provider);\n+          } else if (config.unlinkMethod === 'post') {\n+            return $http.post(config.unlinkUrl, provider);\n+          }\n+        };\n+\n+        return oauth;\n+      }])\n+    .factory('satellizer.local', [\n+      '$q',\n+      '$http',\n+      '$location',\n+      'satellizer.utils',\n+      'satellizer.shared',\n+      'satellizer.config',\n+      function($q, $http, $location, utils, shared, config) {\n+        var local = {};\n+\n+        local.login = function(user, redirect) {\n+          var loginUrl = config.baseUrl ? utils.joinUrl(config.baseUrl, config.loginUrl) : config.loginUrl;\n+          return $http.post(loginUrl, user)\n+            .then(function(response) {\n+              shared.setToken(response, redirect);\n+              return response;\n+            });\n+        };\n+\n+        local.signup = function(user) {\n+          var signupUrl = config.baseUrl ? utils.joinUrl(config.baseUrl, config.signupUrl) : config.signupUrl;\n+          return $http.post(signupUrl, user)\n+            .then(function(response) {\n+              if (config.loginOnSignup) {\n+                shared.setToken(response);\n+              } else if (config.signupRedirect) {\n+                $location.path(config.signupRedirect);\n+              }\n+              return response;\n+            });\n+        };\n+\n+        return local;\n+      }])\n+    .factory('satellizer.Oauth2', [\n+      '$q',\n+      '$http',\n+      '$window',\n+      'satellizer.popup',\n+      'satellizer.utils',\n+      'satellizer.config',\n+      'satellizer.storage',\n+      function($q, $http, $window, popup, utils, config, storage) {\n+        return function() {\n+\n+          var defaults = {\n+            url: null,\n+            name: null,\n+            state: null,\n+            scope: null,\n+            scopeDelimiter: null,\n+            clientId: null,\n+            redirectUri: null,\n+            popupOptions: null,\n+            authorizationEndpoint: null,\n+            responseParams: null,\n+            requiredUrlParams: null,\n+            optionalUrlParams: null,\n+            defaultUrlParams: ['response_type', 'client_id', 'redirect_uri'],\n+            responseType: 'code'\n+          };\n+\n+          var oauth2 = {};\n+\n+          oauth2.open = function(options, userData) {\n+            angular.extend(defaults, options);\n+\n+            var stateName = defaults.name + '_state';\n+\n+            if (angular.isFunction(defaults.state)) {\n+              storage.set(stateName, defaults.state());\n+            } else if (angular.isString(defaults.state)) {\n+              storage.set(stateName, defaults.state);\n+            }\n+\n+            var url = defaults.authorizationEndpoint + '?' + oauth2.buildQueryString();\n+\n+            return popup.open(url, defaults.popupOptions, defaults.redirectUri)\n+              .then(function(oauthData) {\n+                if (defaults.responseType === 'token') {\n+                  return oauthData;\n+                }\n+                if (oauthData.state && oauthData.state !== storage.get(stateName)) {\n+                  return $q.reject('OAuth 2.0 state parameter mismatch.');\n+                }\n+                return oauth2.exchangeForToken(oauthData, userData);\n+              });\n+\n+          };\n+\n+          oauth2.exchangeForToken = function(oauthData, userData) {\n+            var data = angular.extend({}, userData, {\n+              code: oauthData.code,\n+              clientId: defaults.clientId,\n+              redirectUri: defaults.redirectUri\n+            });\n+\n+            if (oauthData.state) {\n+              data.state = oauthData.state;\n+            }\n+\n+            angular.forEach(defaults.responseParams, function(param) {\n+              data[param] = oauthData[param];\n+            });\n+\n+            var exchangeForTokenUrl = config.baseUrl ? utils.joinUrl(config.baseUrl, defaults.url) : defaults.url;\n+            return $http.post(exchangeForTokenUrl, data, { withCredentials: config.withCredentials });\n+          };\n+\n+          oauth2.buildQueryString = function() {\n+            var keyValuePairs = [];\n+            var urlParams = ['defaultUrlParams', 'requiredUrlParams', 'optionalUrlParams'];\n+\n+            angular.forEach(urlParams, function(params) {\n+              angular.forEach(defaults[params], function(paramName) {\n+                var camelizedName = utils.camelCase(paramName);\n+                var paramValue = defaults[camelizedName];\n+\n+                if (paramName === 'state') {\n+                  var stateName = defaults.name + '_state';\n+                  paramValue = encodeURIComponent(storage.get(stateName));\n+                }\n+\n+                if (paramName === 'scope' && Array.isArray(paramValue)) {\n+                  paramValue = paramValue.join(defaults.scopeDelimiter);\n+\n+                  if (defaults.scopePrefix) {\n+                    paramValue = [defaults.scopePrefix, paramValue].join(defaults.scopeDelimiter);\n+                  }\n+                }\n+\n+                keyValuePairs.push([paramName, paramValue]);\n+              });\n+            });\n+\n+            return keyValuePairs.map(function(pair) {\n+              return pair.join('=');\n+            }).join('&');\n+          };\n+\n+          return oauth2;\n+        };\n+      }])\n+    .factory('satellizer.Oauth1', [\n+      '$q',\n+      '$http',\n+      'satellizer.popup',\n+      'satellizer.config',\n+      'satellizer.utils',\n+      function($q, $http, popup, config, utils) {\n+        return function() {\n+\n+          var defaults = {\n+            url: null,\n+            name: null,\n+            popupOptions: null,\n+            redirectUri: null\n+          };\n+\n+          var oauth1 = {};\n+\n+          oauth1.open = function(options, userData) {\n+            angular.extend(defaults, options);\n+            var popupUrl = config.baseUrl ? utils.joinUrl(config.baseUrl, defaults.url) : defaults.url;\n+            return popup.open(popupUrl, defaults.popupOptions, defaults.redirectUri)\n+              .then(function(response) {\n+                return oauth1.exchangeForToken(response, userData);\n+              });\n+          };\n+\n+          oauth1.exchangeForToken = function(oauthData, userData) {\n+            var data = angular.extend({}, userData, oauthData);\n+            var qs = oauth1.buildQueryString(data);\n+            var exchangeForTokenUrl = config.baseUrl ? utils.joinUrl(config.baseUrl, defaults.url) : defaults.url;\n+            return $http.get(exchangeForTokenUrl + '?' + qs);\n+          };\n+\n+          oauth1.buildQueryString = function(obj) {\n+            var str = [];\n+\n+            angular.forEach(obj, function(value, key) {\n+              str.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));\n+            });\n+\n+            return str.join('&');\n+          };\n+\n+          return oauth1;\n+        };\n+      }])\n+    .factory('satellizer.popup', [\n+      '$q',\n+      '$interval',\n+      '$window',\n+      '$location',\n+      'satellizer.config',\n+      'satellizer.utils',\n+      function($q, $interval, $window, $location, config, utils) {\n+        var popupWindow = null;\n+        var polling = null;\n+\n+        var popup = {};\n+\n+        popup.popupWindow = popupWindow;\n+\n+        popup.open = function(url, options, redirectUri) {\n+          var optionsString = popup.stringifyOptions(popup.prepareOptions(options || {}));\n+\n+          popupWindow = window.open(url, '_blank', optionsString);\n+\n+          if (popupWindow && popupWindow.focus) {\n+            popupWindow.focus();\n+          }\n+\n+          if (config.platform === 'mobile') {\n+            return popup.eventListener(redirectUri);\n+          }\n+\n+          return popup.pollPopup();\n+        };\n+\n+        popup.eventListener = function(redirectUri) {\n+          var deferred = $q.defer();\n+\n+          popupWindow.addEventListener('loadstart', function(event) {\n+            if (event.url.indexOf(redirectUri) !== 0) {\n+              return;\n+            }\n+\n+            var parser = document.createElement('a');\n+            parser.href = event.url;\n+\n+            if (parser.search || parser.hash) {\n+              var queryParams = parser.search.substring(1).replace(/\\/$/, '');\n+              var hashParams = parser.hash.substring(1).replace(/\\/$/, '');\n+              var hash = utils.parseQueryString(hashParams);\n+              var qs = utils.parseQueryString(queryParams);\n+\n+              angular.extend(qs, hash);\n+\n+              if (qs.error) {\n+                deferred.reject({ error: qs.error });\n+              } else {\n+                deferred.resolve(qs);\n+              }\n+\n+              popupWindow.close();\n+            }\n+          });\n+\n+          popupWindow.addEventListener('exit', function() {\n+            deferred.reject({ data: 'Provider Popup was closed' });\n+          });\n+\n+          popupWindow.addEventListener('loaderror', function() {\n+            deferred.reject({ data: 'Authorization Failed' });\n+          });\n+\n+          return deferred.promise;\n+        };\n+\n+        popup.pollPopup = function() {\n+          var deferred = $q.defer();\n+          polling = $interval(function() {\n+            try {\n+\n+              var documentOrigin = document.location.host + ':' + document.location.port,\n+                  popupWindowOrigin = popupWindow.location.host + ':' + popupWindow.location.port;\n+\n+              if (popupWindowOrigin === documentOrigin && (popupWindow.location.search || popupWindow.location.hash)) {\n+                var queryParams = popupWindow.location.search.substring(1).replace(/\\/$/, '');\n+                var hashParams = popupWindow.location.hash.substring(1).replace(/\\/$/, '');\n+                var hash = utils.parseQueryString(hashParams);\n+                var qs = utils.parseQueryString(queryParams);\n+\n+                angular.extend(qs, hash);\n+\n+                if (qs.error) {\n+                  deferred.reject({ error: qs.error });\n+                } else {\n+                  deferred.resolve(qs);\n+                }\n+\n+                popupWindow.close();\n+                $interval.cancel(polling);\n+              }\n+            } catch (error) {\n+            }\n+\n+            if (!popupWindow) {\n+              $interval.cancel(polling);\n+              deferred.reject({ data: 'Provider Popup Blocked' });\n+            } else if (popupWindow.closed || popupWindow.closed === undefined) {\n+              $interval.cancel(polling);\n+              deferred.reject({ data: 'Authorization Failed' });\n+            }\n+          }, 35);\n+          return deferred.promise;\n+        };\n+\n+        popup.prepareOptions = function(options) {\n+          var width = options.width || 500;\n+          var height = options.height || 500;\n+          return angular.extend({\n+            width: width,\n+            height: height,\n+            left: $window.screenX + (($window.outerWidth - width) / 2),\n+            top: $window.screenY + (($window.outerHeight - height) / 2.5)\n+          }, options);\n+        };\n+\n+        popup.stringifyOptions = function(options) {\n+          var parts = [];\n+          angular.forEach(options, function(value, key) {\n+            parts.push(key + '=' + value);\n+          });\n+          return parts.join(',');\n+        };\n+\n+        return popup;\n+      }])\n+    .service('satellizer.utils', function() {\n+      this.camelCase = function(name) {\n+        return name.replace(/([\\:\\-\\_]+(.))/g, function(_, separator, letter, offset) {\n+          return offset ? letter.toUpperCase() : letter;\n+        });\n+      };\n+\n+      this.parseQueryString = function(keyValue) {\n+        var obj = {}, key, value;\n+        angular.forEach((keyValue || '').split('&'), function(keyValue) {\n+          if (keyValue) {\n+            value = keyValue.split('=');\n+            key = decodeURIComponent(value[0]);\n+            obj[key] = angular.isDefined(value[1]) ? decodeURIComponent(value[1]) : true;\n+          }\n+        });\n+        return obj;\n+      };\n+\n+      this.joinUrl = function() {\n+        var joined = Array.prototype.slice.call(arguments, 0).join('/');\n+\n+        var normalize = function(str) {\n+          return str\n+            .replace(/[\\/]+/g, '/')\n+            .replace(/\\/\\?/g, '?')\n+            .replace(/\\/\\#/g, '#')\n+            .replace(/\\:\\//g, '://');\n+        };\n+\n+        return normalize(joined);\n+      };\n+    })\n+    .factory('satellizer.storage', ['satellizer.config', function(config) {\n+      var storage = function(type) {\n+        var stub = {\n+          getItem: function(key) { return undefined; },\n+          setItem: function(key, value) { return undefined; },\n+          removeItem: function(key) { return undefined; }\n+        };\n+\n+        switch (type) {\n+          case 'localStorage':\n+          case 'sessionStorage':\n+            if (type in window && window[type] !== null) {\n+              return window[type];\n+            } else {\n+              console.warn('Warning: Storage type `' + type + '` is disabled or unavailable. Satellizer will not work correctly.');\n+              return stub;\n+            }\n+\n+          default:\n+            console.error('Error: Unexpected storage type `' + type + '`');\n+            return stub;\n+        }\n+      };\n+\n+      return {\n+        get: function(key) { return storage(config.storage).getItem(key); },\n+        set: function(key, value) { return storage(config.storage).setItem(key, value); },\n+        remove: function(key) { return storage(config.storage).removeItem(key); }\n+      };\n+    }])\n+    .factory('satellizer.interceptor', [\n+      '$q',\n+      'satellizer.config',\n+      'satellizer.storage',\n+      function($q, config, storage) {\n+        var tokenName = config.tokenPrefix ? config.tokenPrefix + '_' + config.tokenName : config.tokenName;\n+        return {\n+          request: function(httpConfig) {\n+            var token = storage.get(tokenName);\n+            if (token && config.httpInterceptor) {\n+              if (config.authHeader && config.authToken) {\n+                token = config.authToken + ' ' + token;\n+              }\n+              httpConfig.headers[config.authHeader] = token;\n+            }\n+            return httpConfig;\n+          },\n+          responseError: function(response) {\n+            return $q.reject(response);\n+          }\n+        };\n+      }])\n+    .config(['$httpProvider', function($httpProvider) {\n+      $httpProvider.interceptors.push('satellizer.interceptor');\n+    }]);\n+\n+})(window, window.angular);\n+\n+// Base64.js Polyfill (@davidchambers)\n+(function() {\n+  var object = typeof exports != 'undefined' ? exports : this;\n+  var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';\n+\n+  function InvalidCharacterError(message) {\n+    this.message = message;\n+  }\n+\n+  InvalidCharacterError.prototype = new Error;\n+  InvalidCharacterError.prototype.name = 'InvalidCharacterError';\n+\n+  object.btoa || (\n+    object.btoa = function(input) {\n+      var str = String(input);\n+      for (var block, charCode, idx = 0, map = chars, output = ''; str.charAt(idx | 0) || (map = '=', idx % 1); output += map.charAt(63 & block >> 8 - idx % 1 * 8)) {\n+        charCode = str.charCodeAt(idx += 3 / 4);\n+        if (charCode > 0xFF) {\n+          throw new InvalidCharacterError(\"'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.\");\n+        }\n+        block = block << 8 | charCode;","path":"ui/app/lib/satellizer.js","position":840,"original_position":840,"commit_id":"6eb7287f96b881dba764dca8450884356da9699d","original_commit_id":"6eb7287f96b881dba764dca8450884356da9699d","user":{"login":"ironjan","id":1698836,"avatar_url":"https://avatars.githubusercontent.com/u/1698836?v=3","gravatar_id":"","url":"https://api.github.com/users/ironjan","html_url":"https://github.com/ironjan","followers_url":"https://api.github.com/users/ironjan/followers","following_url":"https://api.github.com/users/ironjan/following{/other_user}","gists_url":"https://api.github.com/users/ironjan/gists{/gist_id}","starred_url":"https://api.github.com/users/ironjan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ironjan/subscriptions","organizations_url":"https://api.github.com/users/ironjan/orgs","repos_url":"https://api.github.com/users/ironjan/repos","events_url":"https://api.github.com/users/ironjan/events{/privacy}","received_events_url":"https://api.github.com/users/ironjan/received_events","type":"User","site_admin":false},"body":"![Codacy](https://www.codacy.com/assets/images/favicon.png) Issue found: [Unexpected use of '|'.](https://www.codacy.com/app/HiP-App/HiPCMS/file/2279397488/issues/source?bid=3144114&fileBranchId=3144125#l840)","created_at":"2016-03-19T13:18:11Z","updated_at":"2016-03-19T13:18:11Z","html_url":"https://github.com/HiP-App/HiPCMS/pull/1#discussion_r56748983","pull_request_url":"https://api.github.com/repos/HiP-App/HiPCMS/pulls/1","_links":{"self":{"href":"https://api.github.com/repos/HiP-App/HiPCMS/pulls/comments/56748983"},"html":{"href":"https://github.com/HiP-App/HiPCMS/pull/1#discussion_r56748983"},"pull_request":{"href":"https://api.github.com/repos/HiP-App/HiPCMS/pulls/1"}}},"pull_request":{"url":"https://api.github.com/repos/HiP-App/HiPCMS/pulls/1","id":60499221,"html_url":"https://github.com/HiP-App/HiPCMS/pull/1","diff_url":"https://github.com/HiP-App/HiPCMS/pull/1.diff","patch_url":"https://github.com/HiP-App/HiPCMS/pull/1.patch","issue_url":"https://api.github.com/repos/HiP-App/HiPCMS/issues/1","number":1,"state":"open","locked":false,"title":"Merge back to master","user":{"login":"ironjan","id":1698836,"avatar_url":"https://avatars.githubusercontent.com/u/1698836?v=3","gravatar_id":"","url":"https://api.github.com/users/ironjan","html_url":"https://github.com/ironjan","followers_url":"https://api.github.com/users/ironjan/followers","following_url":"https://api.github.com/users/ironjan/following{/other_user}","gists_url":"https://api.github.com/users/ironjan/gists{/gist_id}","starred_url":"https://api.github.com/users/ironjan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ironjan/subscriptions","organizations_url":"https://api.github.com/users/ironjan/orgs","repos_url":"https://api.github.com/users/ironjan/repos","events_url":"https://api.github.com/users/ironjan/events{/privacy}","received_events_url":"https://api.github.com/users/ironjan/received_events","type":"User","site_admin":false},"body":"","created_at":"2016-02-24T12:10:56Z","updated_at":"2016-03-19T13:18:12Z","closed_at":null,"merged_at":null,"merge_commit_sha":"9cb02b4dc42731e0dee6cc8a304f5f103223af99","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/HiP-App/HiPCMS/pulls/1/commits","review_comments_url":"https://api.github.com/repos/HiP-App/HiPCMS/pulls/1/comments","review_comment_url":"https://api.github.com/repos/HiP-App/HiPCMS/pulls/comments{/number}","comments_url":"https://api.github.com/repos/HiP-App/HiPCMS/issues/1/comments","statuses_url":"https://api.github.com/repos/HiP-App/HiPCMS/statuses/6eb7287f96b881dba764dca8450884356da9699d","head":{"label":"HiP-App:develop","ref":"develop","sha":"6eb7287f96b881dba764dca8450884356da9699d","user":{"login":"HiP-App","id":11423128,"avatar_url":"https://avatars.githubusercontent.com/u/11423128?v=3","gravatar_id":"","url":"https://api.github.com/users/HiP-App","html_url":"https://github.com/HiP-App","followers_url":"https://api.github.com/users/HiP-App/followers","following_url":"https://api.github.com/users/HiP-App/following{/other_user}","gists_url":"https://api.github.com/users/HiP-App/gists{/gist_id}","starred_url":"https://api.github.com/users/HiP-App/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/HiP-App/subscriptions","organizations_url":"https://api.github.com/users/HiP-App/orgs","repos_url":"https://api.github.com/users/HiP-App/repos","events_url":"https://api.github.com/users/HiP-App/events{/privacy}","received_events_url":"https://api.github.com/users/HiP-App/received_events","type":"Organization","site_admin":false},"repo":{"id":52438852,"name":"HiPCMS","full_name":"HiP-App/HiPCMS","owner":{"login":"HiP-App","id":11423128,"avatar_url":"https://avatars.githubusercontent.com/u/11423128?v=3","gravatar_id":"","url":"https://api.github.com/users/HiP-App","html_url":"https://github.com/HiP-App","followers_url":"https://api.github.com/users/HiP-App/followers","following_url":"https://api.github.com/users/HiP-App/following{/other_user}","gists_url":"https://api.github.com/users/HiP-App/gists{/gist_id}","starred_url":"https://api.github.com/users/HiP-App/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/HiP-App/subscriptions","organizations_url":"https://api.github.com/users/HiP-App/orgs","repos_url":"https://api.github.com/users/HiP-App/repos","events_url":"https://api.github.com/users/HiP-App/events{/privacy}","received_events_url":"https://api.github.com/users/HiP-App/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/HiP-App/HiPCMS","description":"","fork":false,"url":"https://api.github.com/repos/HiP-App/HiPCMS","forks_url":"https://api.github.com/repos/HiP-App/HiPCMS/forks","keys_url":"https://api.github.com/repos/HiP-App/HiPCMS/keys{/key_id}","collaborators_url":"https://api.github.com/repos/HiP-App/HiPCMS/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/HiP-App/HiPCMS/teams","hooks_url":"https://api.github.com/repos/HiP-App/HiPCMS/hooks","issue_events_url":"https://api.github.com/repos/HiP-App/HiPCMS/issues/events{/number}","events_url":"https://api.github.com/repos/HiP-App/HiPCMS/events","assignees_url":"https://api.github.com/repos/HiP-App/HiPCMS/assignees{/user}","branches_url":"https://api.github.com/repos/HiP-App/HiPCMS/branches{/branch}","tags_url":"https://api.github.com/repos/HiP-App/HiPCMS/tags","blobs_url":"https://api.github.com/repos/HiP-App/HiPCMS/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/HiP-App/HiPCMS/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/HiP-App/HiPCMS/git/refs{/sha}","trees_url":"https://api.github.com/repos/HiP-App/HiPCMS/git/trees{/sha}","statuses_url":"https://api.github.com/repos/HiP-App/HiPCMS/statuses/{sha}","languages_url":"https://api.github.com/repos/HiP-App/HiPCMS/languages","stargazers_url":"https://api.github.com/repos/HiP-App/HiPCMS/stargazers","contributors_url":"https://api.github.com/repos/HiP-App/HiPCMS/contributors","subscribers_url":"https://api.github.com/repos/HiP-App/HiPCMS/subscribers","subscription_url":"https://api.github.com/repos/HiP-App/HiPCMS/subscription","commits_url":"https://api.github.com/repos/HiP-App/HiPCMS/commits{/sha}","git_commits_url":"https://api.github.com/repos/HiP-App/HiPCMS/git/commits{/sha}","comments_url":"https://api.github.com/repos/HiP-App/HiPCMS/comments{/number}","issue_comment_url":"https://api.github.com/repos/HiP-App/HiPCMS/issues/comments{/number}","contents_url":"https://api.github.com/repos/HiP-App/HiPCMS/contents/{+path}","compare_url":"https://api.github.com/repos/HiP-App/HiPCMS/compare/{base}...{head}","merges_url":"https://api.github.com/repos/HiP-App/HiPCMS/merges","archive_url":"https://api.github.com/repos/HiP-App/HiPCMS/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/HiP-App/HiPCMS/downloads","issues_url":"https://api.github.com/repos/HiP-App/HiPCMS/issues{/number}","pulls_url":"https://api.github.com/repos/HiP-App/HiPCMS/pulls{/number}","milestones_url":"https://api.github.com/repos/HiP-App/HiPCMS/milestones{/number}","notifications_url":"https://api.github.com/repos/HiP-App/HiPCMS/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/HiP-App/HiPCMS/labels{/name}","releases_url":"https://api.github.com/repos/HiP-App/HiPCMS/releases{/id}","deployments_url":"https://api.github.com/repos/HiP-App/HiPCMS/deployments","created_at":"2016-02-24T11:58:23Z","updated_at":"2016-03-04T13:07:16Z","pushed_at":"2016-03-18T18:22:00Z","git_url":"git://github.com/HiP-App/HiPCMS.git","ssh_url":"git@github.com:HiP-App/HiPCMS.git","clone_url":"https://github.com/HiP-App/HiPCMS.git","svn_url":"https://github.com/HiP-App/HiPCMS","homepage":null,"size":21759,"stargazers_count":0,"watchers_count":0,"language":"CSS","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":5,"forks":0,"open_issues":5,"watchers":0,"default_branch":"develop"}},"base":{"label":"HiP-App:master","ref":"master","sha":"dfd1103fa40513c20fefebb13b1dc12ad14398ab","user":{"login":"HiP-App","id":11423128,"avatar_url":"https://avatars.githubusercontent.com/u/11423128?v=3","gravatar_id":"","url":"https://api.github.com/users/HiP-App","html_url":"https://github.com/HiP-App","followers_url":"https://api.github.com/users/HiP-App/followers","following_url":"https://api.github.com/users/HiP-App/following{/other_user}","gists_url":"https://api.github.com/users/HiP-App/gists{/gist_id}","starred_url":"https://api.github.com/users/HiP-App/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/HiP-App/subscriptions","organizations_url":"https://api.github.com/users/HiP-App/orgs","repos_url":"https://api.github.com/users/HiP-App/repos","events_url":"https://api.github.com/users/HiP-App/events{/privacy}","received_events_url":"https://api.github.com/users/HiP-App/received_events","type":"Organization","site_admin":false},"repo":{"id":52438852,"name":"HiPCMS","full_name":"HiP-App/HiPCMS","owner":{"login":"HiP-App","id":11423128,"avatar_url":"https://avatars.githubusercontent.com/u/11423128?v=3","gravatar_id":"","url":"https://api.github.com/users/HiP-App","html_url":"https://github.com/HiP-App","followers_url":"https://api.github.com/users/HiP-App/followers","following_url":"https://api.github.com/users/HiP-App/following{/other_user}","gists_url":"https://api.github.com/users/HiP-App/gists{/gist_id}","starred_url":"https://api.github.com/users/HiP-App/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/HiP-App/subscriptions","organizations_url":"https://api.github.com/users/HiP-App/orgs","repos_url":"https://api.github.com/users/HiP-App/repos","events_url":"https://api.github.com/users/HiP-App/events{/privacy}","received_events_url":"https://api.github.com/users/HiP-App/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/HiP-App/HiPCMS","description":"","fork":false,"url":"https://api.github.com/repos/HiP-App/HiPCMS","forks_url":"https://api.github.com/repos/HiP-App/HiPCMS/forks","keys_url":"https://api.github.com/repos/HiP-App/HiPCMS/keys{/key_id}","collaborators_url":"https://api.github.com/repos/HiP-App/HiPCMS/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/HiP-App/HiPCMS/teams","hooks_url":"https://api.github.com/repos/HiP-App/HiPCMS/hooks","issue_events_url":"https://api.github.com/repos/HiP-App/HiPCMS/issues/events{/number}","events_url":"https://api.github.com/repos/HiP-App/HiPCMS/events","assignees_url":"https://api.github.com/repos/HiP-App/HiPCMS/assignees{/user}","branches_url":"https://api.github.com/repos/HiP-App/HiPCMS/branches{/branch}","tags_url":"https://api.github.com/repos/HiP-App/HiPCMS/tags","blobs_url":"https://api.github.com/repos/HiP-App/HiPCMS/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/HiP-App/HiPCMS/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/HiP-App/HiPCMS/git/refs{/sha}","trees_url":"https://api.github.com/repos/HiP-App/HiPCMS/git/trees{/sha}","statuses_url":"https://api.github.com/repos/HiP-App/HiPCMS/statuses/{sha}","languages_url":"https://api.github.com/repos/HiP-App/HiPCMS/languages","stargazers_url":"https://api.github.com/repos/HiP-App/HiPCMS/stargazers","contributors_url":"https://api.github.com/repos/HiP-App/HiPCMS/contributors","subscribers_url":"https://api.github.com/repos/HiP-App/HiPCMS/subscribers","subscription_url":"https://api.github.com/repos/HiP-App/HiPCMS/subscription","commits_url":"https://api.github.com/repos/HiP-App/HiPCMS/commits{/sha}","git_commits_url":"https://api.github.com/repos/HiP-App/HiPCMS/git/commits{/sha}","comments_url":"https://api.github.com/repos/HiP-App/HiPCMS/comments{/number}","issue_comment_url":"https://api.github.com/repos/HiP-App/HiPCMS/issues/comments{/number}","contents_url":"https://api.github.com/repos/HiP-App/HiPCMS/contents/{+path}","compare_url":"https://api.github.com/repos/HiP-App/HiPCMS/compare/{base}...{head}","merges_url":"https://api.github.com/repos/HiP-App/HiPCMS/merges","archive_url":"https://api.github.com/repos/HiP-App/HiPCMS/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/HiP-App/HiPCMS/downloads","issues_url":"https://api.github.com/repos/HiP-App/HiPCMS/issues{/number}","pulls_url":"https://api.github.com/repos/HiP-App/HiPCMS/pulls{/number}","milestones_url":"https://api.github.com/repos/HiP-App/HiPCMS/milestones{/number}","notifications_url":"https://api.github.com/repos/HiP-App/HiPCMS/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/HiP-App/HiPCMS/labels{/name}","releases_url":"https://api.github.com/repos/HiP-App/HiPCMS/releases{/id}","deployments_url":"https://api.github.com/repos/HiP-App/HiPCMS/deployments","created_at":"2016-02-24T11:58:23Z","updated_at":"2016-03-04T13:07:16Z","pushed_at":"2016-03-18T18:22:00Z","git_url":"git://github.com/HiP-App/HiPCMS.git","ssh_url":"git@github.com:HiP-App/HiPCMS.git","clone_url":"https://github.com/HiP-App/HiPCMS.git","svn_url":"https://github.com/HiP-App/HiPCMS","homepage":null,"size":21759,"stargazers_count":0,"watchers_count":0,"language":"CSS","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":5,"forks":0,"open_issues":5,"watchers":0,"default_branch":"develop"}},"_links":{"self":{"href":"https://api.github.com/repos/HiP-App/HiPCMS/pulls/1"},"html":{"href":"https://github.com/HiP-App/HiPCMS/pull/1"},"issue":{"href":"https://api.github.com/repos/HiP-App/HiPCMS/issues/1"},"comments":{"href":"https://api.github.com/repos/HiP-App/HiPCMS/issues/1/comments"},"review_comments":{"href":"https://api.github.com/repos/HiP-App/HiPCMS/pulls/1/comments"},"review_comment":{"href":"https://api.github.com/repos/HiP-App/HiPCMS/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/HiP-App/HiPCMS/pulls/1/commits"},"statuses":{"href":"https://api.github.com/repos/HiP-App/HiPCMS/statuses/6eb7287f96b881dba764dca8450884356da9699d"}}}}