(function (context, $) {

  /**
   * Javascript wrappers for the REST API
   */

  "use strict";

  context.JK = context.JK || {};
  context.JK.Rest = function () {

    var self = this;
    var logger = context.JK.logger;

    function createJoinRequest(joinRequest) {
      return $.ajax({
        type: "POST",
        dataType: "json",
        url: '/api/join_requests',
        contentType: 'application/json',
        processData: false,
        data: JSON.stringify(joinRequest)
      });
    }

    function updateJoinRequest(joinRequestId, isApproved) {
      return $.ajax({
        type: "PUT",
        dataType: "json",
        url: '/api/join_requests/' + joinRequestId,
        contentType: 'application/json',
        processData: false,
        data: JSON.stringify({"approved": isApproved})
      });
    }

    function legacyCreateSession(options) {
      return $.ajax({
        type: "POST",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/sessions/legacy",
        processData: false,
        data: JSON.stringify(options)
      });
    }

    function createScheduledSession(options) {
      return $.ajax({
        type: "POST",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/sessions",
        processData: false,
        data: JSON.stringify(options)
      });
    }

    function getBroadcastNotification(options) {
      var userId = getId(options);
      return $.ajax({
        type: "GET",
        url: "/api/users/" + userId + "/broadcast_notification"
      });
    }

    function quietBroadcastNotification(options) {
      var userId = getId(options);
      var broadcast_id = options.broadcast_id;
      return $.ajax({
        type: "POST",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/users/" + userId + "/broadcast_notification/" + broadcast_id + '/quiet',
        data: JSON.stringify({}),
      });
    }

    function uploadMusicNotations(formData) {
      return $.ajax({
        type: "POST",
        processData: false,
        contentType: false,
        dataType: "json",
        cache: false,
        url: "/api/music_notations",
        data: formData
      });
    }

    function getMusicNotation(query) {
      return $.ajax({
        type: "GET",
        url: "/api/music_notations/" + query
      });
    }


    function deleteMusicNotation(options) {
      return $.ajax({
        type: "DELETE",
        url: "/api/music_notations/" + options.id
      });
    }

    function legacyJoinSession(options) {
      var sessionId = options["session_id"];
      delete options["session_id"];

      return $.ajax({
        type: "POST",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/sessions/" + sessionId + "/participants/legacy",
        data: JSON.stringify(options),
        processData: false
      });
    }

    function joinSession(options) {
      var sessionId = options["session_id"];
      delete options["session_id"];

      return $.ajax({
        type: "POST",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/sessions/" + sessionId + "/participants",
        data: JSON.stringify(options),
        processData: false
      });
    }

    function cancelSession(options) {
      var sessionId = options["session_id"];
      delete options["session_id"];

      return $.ajax({
        type: "DELETE",
        dataType: "JSON",
        contentType: 'application/json',
        url: "/api/sessions/" + sessionId,
        data: JSON.stringify(options),
        processData: false
      });
    }

    function findFriendSessions(query) {
      return $.ajax({
        type: "GET",
        url: "/api/sessions/friends?" + $.param(query)
      });
    }

    function findPublicSessions(query) {
      return $.ajax({
        type: "GET",
        url: "/api/sessions/public?" + $.param(query)
      });
    }

    function findActiveSessions(query) {
      return $.ajax({
        type: "GET",
        url: "/api/sessions/active?" + $.param(query)
      });
    }

    function findInactiveSessions(query) {
      return $.ajax({
        type: "GET",
        url: "/api/sessions/inactive?" + $.param(query)
      });
    }

    function findScheduledSessions(query) {
      return $.ajax({
        type: "GET",
        url: "/api/sessions/scheduled?" + $.param(query)
      });
    }

    function findScheduledRsvpSessions(query) {
      return $.ajax({
        type: "GET",
        url: "/api/sessions/scheduled_rsvp?" + $.param(query)
      });
    }

    function updateSession(id, newSession) {
      return $.ajax({
        url: '/api/sessions/' + id,
        type: "PUT",
        data: newSession,
        dataType: 'json'
      });
    }

    function updateScheduledSession(id, newSession) {
      return $.ajax({
        url: '/api/sessions/' + id,
        type: "POST",
        data: newSession,
        dataType: 'json'
      });
    }

    function getSessionHistory(id, includePending) {
      var includeFlag = 'false';
      if (includePending) {
        includeFlag = 'true';
      }

      return $.ajax({
        type: "GET",
        dataType: "json",
        url: '/api/sessions/' + id + '/history?includePending=' + includeFlag,
        contentType: 'application/json',
        processData: false
      });
    }

    function addSessionInfoComment(sessionId, comment) {
      return $.ajax({
        url: '/api/sessions/' + sessionId + "/details/comments",
        type: "POST",
        data: JSON.stringify({"comment": comment}),
        dataType: 'json',
        contentType: 'application/json'
      });
    }

    function addSessionComment(sessionId, userId, comment) {
      return $.ajax({
        url: '/api/sessions/' + sessionId + "/comments",
        type: "POST",
        data: JSON.stringify({"comment": comment, "user_id": userId}),
        dataType: 'json',
        contentType: 'application/json'
      });
    }

    function addSessionLike(sessionId, userId) {
      return $.ajax({
        url: '/api/sessions/' + sessionId + "/likes",
        type: "POST",
        data: JSON.stringify({"user_id": userId}),
        dataType: 'json',
        contentType: 'application/json'
      });
    }

    function getRsvpRequests(sessionId) {
      return $.ajax({
        url: '/api/rsvp_requests?session_id=' + sessionId,
        type: "GET",
        dataType: 'json',
        contentType: 'application/json'
      });
    }

    function submitRsvpRequest(sessionId, slotIds) {
      return $.ajax({
        url: '/api/rsvp_requests',
        type: "POST",
        data: JSON.stringify({"session_id": sessionId, "rsvp_slots": slotIds}),
        dataType: 'json',
        contentType: 'application/json'
      });
    }

    function updateRsvpRequest(rsvpRequestId, responses) {
      return $.ajax({
        url: '/api/rsvp_requests/' + rsvpRequestId,
        type: "POST",
        data: JSON.stringify(responses),
        dataType: 'json',
        contentType: 'application/json'
      });
    }

    function cancelRsvpRequest(sessionId, rsvpRequestId, cancelAll) {
      var cancel = "yes";
      if (cancelAll) {
        cancel = "all";
      }
      return $.ajax({
        url: '/api/rsvp_requests/' + rsvpRequestId,
        type: "DELETE",
        data: JSON.stringify({"session_id": sessionId, "cancelled": cancelAll}),
        dataType: 'json',
        contentType: 'application/json'
      });
    }

    function getOpenSessionSlots(sessionId, openOnly) {
      var url = '/api/rsvp_slots?session_id=' + sessionId;

      if (openOnly) {
        url += '&open_only=true';
      }
      return $.ajax({
        type: "GET",
        dataType: "json",
        url: url,
        contentType: 'application/json',
        processData: false
      });
    }

    function addRecordingComment(recordingId, userId, comment) {
      return $.ajax({
        url: '/api/recordings/' + recordingId + "/comments",
        type: "POST",
        data: JSON.stringify({"comment": comment, "user_id": userId}),
        dataType: 'json',
        contentType: 'application/json'
      });
    }

    function addRecordingLike(recordingId, claimedRecordingId, userId) {
      return $.ajax({
        url: '/api/recordings/' + recordingId + "/likes",
        type: "POST",
        data: JSON.stringify({"user_id": userId, claimed_recording_id: claimedRecordingId}),
        dataType: 'json',
        contentType: 'application/json'
      });
    }

    function addPlayablePlay(playableId, playableType, claimedRecordingId, userId) {
      return $.ajax({
        url: '/api/users/' + playableId + "/plays",
        type: "POST",
        data: JSON.stringify({user_id: userId, claimed_recording_id: claimedRecordingId, playable_type: playableType}),
        dataType: 'json',
        contentType: 'application/json'
      });
    }

    function updateFavorite(claimedRecordingId, favorite) {
      return $.ajax({
        url: '/api/favorites/' + claimedRecordingId,
        type: "POST",
        data: JSON.stringify({favorite: favorite}),
        dataType: 'json',
        contentType: 'application/json'
      });
    }

    function validateBand(band) {
      return $.ajax({
        type: "POST",
        dataType: "json",
        url: '/api/bands/validate',
        contentType: 'application/json',
        processData: false,
        data: JSON.stringify(band)
      });
    }

    function getBand(bandId) {
      return $.ajax({
        type: "GET",
        dataType: "json",
        url: '/api/bands/' + bandId,
        contentType: 'application/json',
        processData: false
      });
    }

    function createBand(band) {
      var deferred = $.ajax({
        type: "POST",
        dataType: "json",
        url: '/api/bands',
        contentType: 'application/json',
        processData: false,
        data: JSON.stringify(band)
      });

      deferred.done(function () {
        context.JK.GA.trackBand(context.JK.GA.BandActions.create);
        context.JK.GA.trackBand(context.JK.GA.BandActions.join);
      });

      return deferred;
    }

    function deleteBand(bandId) {
      var url = "/api/bands/" + bandId;
      return $.ajax({
        type: "DELETE",
        dataType: "json",
        url: url,
        contentType: 'application/json',
        processData: false
      });
    }

    function updateBand(band) {
      return $.ajax({
        type: "POST",
        dataType: "json",
        url: '/api/bands/' + band.id,
        contentType: 'application/json',
        processData: false,
        data: JSON.stringify(band)
      });
    }

    function createBandInvitation(bandId, userId) {
      var bandInvitation = {
        band_id: bandId,
        user_id: userId
      };

      return $.ajax({
        type: "POST",
        dataType: "json",
        url: '/api/bands/' + bandId + "/invitations",
        contentType: 'application/json',
        processData: false,
        data: JSON.stringify(bandInvitation)
      });
    }

    function updateBandInvitation(bandId, invitationId, isAccepted) {
      var deferred = $.ajax({
        type: "POST",
        dataType: "json",
        url: '/api/bands/' + bandId + "/invitations/" + invitationId,
        contentType: 'application/json',
        processData: false,
        data: JSON.stringify({"accepted": isAccepted})
      })

      if (isAccepted) {
        deferred.done(function () {
          context.JK.GA.trackBand(context.JK.GA.BandActions.join);
        })
      }

      return deferred;
    }

    function resendBandInvitation(bandId, invitationId) {
      return $.ajax({
        type: "POST",
        dataType: "json",
        url: '/api/bands/' + bandId + "/invitations/" + invitationId,
        contentType: 'application/json',
        processData: false,
        data: JSON.stringify({"resend": true})
      })
    }

    function removeBandMember(bandId, userId) {
      var url = "/api/bands/" + bandId + "/musicians/" + userId;
      return $.ajax({
        type: "DELETE",
        dataType: "json",
        url: url,
        processData: false
      });
    }

    function getBandMembers(bandId, hasPendingInvitation) {
      var url = "/api/bands/" + bandId + "/musicians";

      if (hasPendingInvitation) {
        url += "?pending=true";
      }

      return $.ajax({
        type: "GET",
        dataType: "json",
        url: url,
        processData: false
      });
    }

    function getBands(userId) {
      var url = "/api/users/" + userId + "/bands";
      return $.ajax({
        type: "GET",
        dataType: "json",
        url: url,
        processData: false
      });
    }


    function getTeacher(options) {
      return $.ajax({
        type: "GET",
        dataType: "json",
        url: '/api/teachers/detail?' + $.param(options),
        contentType: 'application/json',
        processData: false
      });
    }

    function deleteTeacher(teacherId) {
      var url = "/api/teachers/" + teacherId;
      return $.ajax({
        type: "DELETE",
        dataType: "json",
        url: url,
        contentType: 'application/json',
        processData: false
      });
    }

    function updateTeacher(teacher) {
      console.log("Updating teacher", teacher)
      var id = teacher && teacher["id"]
      var url
      if (id != null && typeof(id) != 'undefined') {
        url = '/api/teachers/' + teacher.id
      } else {
        url = '/api/teachers'
      }

      var deferred = $.ajax({
        type: "POST",
        dataType: "json",
        url: url,
        contentType: 'application/json',
        processData: false,
        data: JSON.stringify(teacher)
      })

      return deferred
    }

    function getSession(id) {
      var url = "/api/sessions/" + id;
      return $.ajax({
        type: "GET",
        dataType: "json",
        url: url,
        processData: false
      });
    }

    function deleteParticipant(clientId) {
      var url = "/api/participants/" + clientId;
      return $.ajax({
        type: "DELETE",
        url: url
      });
    }

    function login(options) {
      var url = '/api/auths/login';

      return $.ajax({
        type: "POST",
        dataType: "json",
        url: url,
        processData: false,
        contentType: 'application/json',
        data: JSON.stringify(options)
      })
    }

    function getUserAuthorizations(options) {
      var id = getId(options);

      return $.ajax({
        type: "GET",
        dataType: "json",
        url: "/api/users/" + id + '/authorizations',
        processData: false
      });
    }

    function getGoogleAuth(options) {
      var id = getId(options);

      return $.ajax({
        type: "GET",
        dataType: "json",
        url: "/api/users/authorizations/google",
        processData: false
      });
    }

    function getUserDetail(options) {
      if (!options) {
        options = {}
      }
      var id = getId(options);
      var detail = null;
      if (id != null && typeof(id) != 'undefined') {
        detail = $.ajax({
          type: "GET",
          dataType: "json",
          url: "/api/users/" + id + '?' + $.param(options),
          processData: false
        });
      }
      if (detail && context.JK.currentUserId == id) {
        detail.done(function (user) {
          window.UserActions.loaded(user)
        })
      }
      return detail;
    }

    function getUserJamBlasters(options) {
      if (!options) {
        options = {}
      }
      var id = getId(options);
      return $.ajax({
        type: "GET",
        dataType: "json",
        url: "/api/users/" + id + '/jamblasters?' + $.param(options),
        processData: false
      });
    }

    function getUserProfile(options) {
      if (!options) {
        options = {}
      }
      var id = getId(options);
      return $.ajax({
        type: "GET",
        dataType: "json",
        url: "/api/users/" + id + "/profile" + '?' + $.param(options),
        processData: false
      });
    }

    function createAffiliatePartner(options) {
      return $.ajax({
        type: "POST",
        url: '/api/affiliate_partners',
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(options)
      })
    }

    function getAffiliatePartnerData(userId) {
      return $.ajax({
        type: "GET",
        dataType: "json",
        url: "/api/users/" + userId + "/affiliate_partner"
      });
    }

    function postAffiliatePartnerData(userId, data) {
      return $.ajax({
        type: "POST",
        dataType: "json",
        url: "/api/users/" + userId + "/affiliate_partner",
        contentType: 'application/json',
        processData: false,
        data: JSON.stringify(data)
      });
    }

    function getLinks(type, partner_id) {
      var url = "/api/links/" + type;

      if (partner_id) {
        url += '?affiliate_id=' + partner_id;
      }
      return $.ajax({
        type: "GET",
        dataType: "json",
        url: url
      });
    }

    function getAffiliateSignups() {
      return $.ajax({
        type: "GET",
        dataType: "json",
        url: "/api/affiliate_partners/signups"
      });
    }

    function getAffiliateMonthly() {
      return $.ajax({
        type: "GET",
        dataType: "json",
        url: "/api/affiliate_partners/monthly_earnings"
      });
    }

    function getAffiliateQuarterly() {
      return $.ajax({
        type: "GET",
        dataType: "json",
        url: "/api/affiliate_partners/quarterly_earnings"
      });
    }

    function getAffiliatePayments() {
      return $.ajax({
        type: "GET",
        dataType: "json",
        url: "/api/affiliate_partners/payments"
      });
    }

    function getCities(options) {
      var country = options['country']
      var region = options['region']

      return $.ajax('/api/cities', {
        data: {country: country, region: region},
        dataType: 'json'
      });
    }

    function getRegions(options) {
      var country = options["country"]

      return $.ajax('/api/regions', {
        data: {country: country},
        dataType: 'json'
      });
    }

    function getCountries() {
      return $.ajax('/api/countries', {
        dataType: 'json'
      });
    }

    function getResolvedLocation() {
      return $.ajax('/api/resolved_location', {
        dataType: 'json'
      });
    }

    function getInstruments(options) {
      return $.ajax('/api/instruments', {
        data: {},
        dataType: 'json'
      });
    }

    function getGenres(options) {
      return $.ajax('/api/genres', {
        data: {},
        dataType: 'json'
      });
    }

    function getSubjects(options) {
      return $.ajax('/api/subjects', {
        data: {},
        dataType: 'json'
      });
    }

    function getLanguages(options) {
      return $.ajax('/api/languages', {
        data: {},
        dataType: 'json'
      });
    }

    function updateUdpReachable(options) {
      var id = getId(options);

      return $.ajax({
        type: "POST",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/users/" + id + "/udp_reachable",
        data: JSON.stringify(options),
        processData: false
      });
    }

    function updateNetworkTesting(options) {
      var id = getId(options);

      return $.ajax({
        type: "POST",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/users/" + id + "/is_network_testing",
        data: JSON.stringify(options),
        processData: false
      });
    }

    function updateAvatar(options) {
      var id = getId(options);

      var original_fpfile = options['original_fpfile'];
      var cropped_fpfile = options['cropped_fpfile'];
      var cropped_large_fpfile = options['cropped_large_fpfile'];
      var crop_selection = options['crop_selection'];

      logger.debug(JSON.stringify({
        original_fpfile: original_fpfile,
        cropped_fpfile: cropped_fpfile,
        cropped_large_fpfile: cropped_large_fpfile,
        crop_selection: crop_selection
      }));

      var url = "/api/users/" + id + "/avatar";
      return $.ajax({
        type: "POST",
        dataType: "json",
        url: url,
        contentType: 'application/json',
        processData: false,
        data: JSON.stringify({
          original_fpfile: original_fpfile,
          cropped_fpfile: cropped_fpfile,
          cropped_large_fpfile: cropped_large_fpfile,
          crop_selection: crop_selection
        })
      });
    }

    function deleteAvatar(options) {
      var id = getId(options);

      var url = "/api/users/" + id + "/avatar";
      return $.ajax({
        type: "DELETE",
        dataType: "json",
        url: url,
        contentType: 'application/json',
        processData: false
      });
    }

    function getFilepickerPolicy(options) {
      var id = getId(options);
      var handle = options && options["handle"];
      var convert = options && options["convert"]

      var url = "/api/users/" + id + "/filepicker_policy";

      return $.ajax(url, {
        data: {handle: handle, convert: convert},
        dataType: 'json'
      });
    }

    function updateBandPhoto(options) {
      var id = getId(options);

      var original_fpfile = options['original_fpfile'];
      var cropped_fpfile = options['cropped_fpfile'];
      var cropped_large_fpfile = options['cropped_large_fpfile'];
      var crop_selection = options['crop_selection'];

      logger.debug(JSON.stringify({
        original_fpfile: original_fpfile,
        cropped_fpfile: cropped_fpfile,
        cropped_large_fpfile: cropped_large_fpfile,
        crop_selection: crop_selection
      }));

      var url = "/api/bands/" + id + "/photo";
      return $.ajax({
        type: "POST",
        dataType: "json",
        url: url,
        contentType: 'application/json',
        processData: false,
        data: JSON.stringify({
          original_fpfile: original_fpfile,
          cropped_fpfile: cropped_fpfile,
          cropped_large_fpfile: cropped_large_fpfile,
          crop_selection: crop_selection
        })
      });
    }

    function deleteBandPhoto(options) {
      var id = getId(options);

      var url = "/api/bands/" + id + "/photo";
      return $.ajax({
        type: "DELETE",
        dataType: "json",
        url: url,
        contentType: 'application/json',
        processData: false
      });
    }

    function getBandPhotoFilepickerPolicy(options) {
      var id = getId(options);
      var handle = options && options["handle"];
      var convert = options && options["convert"]

      var url = "/api/bands/" + id + "/filepicker_policy";

      return $.ajax(url, {
        data: {handle: handle, convert: convert},
        dataType: 'json'
      });
    }

    function getFriends(options) {
      var id = getId(options);
      return $.ajax({
        type: "GET",
        url: '/api/users/' + id + '/friends',
        dataType: 'json'
      });
    }

    function removeFriend(options) {
      var id = getId(options);
      var friendId = options["friend_id"];

      return $.ajax({
        type: "DELETE",
        dataType: "json",
        url: "/api/users/" + id + "/friends/" + friendId,
        processData: false
      });
    }

    /** NOTE: This is only for Musician, Fan, and Band Likes. Recording and
     Session Likes have their own section below since unauthenticated users
     are allowed to Like these entities.
     */
    function addLike(options) {
      var id = getId(options);
      return $.ajax({
        type: "POST",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/users/" + id + "/likings",
        data: JSON.stringify(options),
        processData: false
      });
    }

    function removeLike(likableId, options) {
      var id = getId(options);
      return $.ajax({
        type: "DELETE",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/users/" + id + "/likings",
        data: JSON.stringify(options),
        processData: false
      });
    }

    function addFollowing(options) {
      var id = getId(options);

      return $.ajax({
        type: "POST",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/users/" + id + "/followings",
        data: JSON.stringify(options),
        processData: false
      });
    }

    function removeFollowing(followableId, options) {
      var id = getId(options);
      return $.ajax({
        type: "DELETE",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/users/" + id + "/followings/" + followableId,
        processData: false
      });
    }

    function getFollowings(options) {
      var userId = getId(options);

      // FOLLOWINGS (USERS)
      return $.ajax({
        type: "GET",
        dataType: "json",
        url: "/api/users/" + userId + "/followings",
        processData: false
      });
    }

    function getFollowers(options) {
      var userId = getId(options);
      return $.ajax({
        type: "GET",
        dataType: "json",
        url: "/api/users/" + userId + "/followers",
        processData: false
      });
    }

    function getBands(options) {
      var userId = getId(options);

      return $.ajax({
        type: "GET",
        dataType: "json",
        url: "/api/users/" + userId + "/bands",
        processData: false
      });
    }

    function getBandFollowers(bandId) {
      return $.ajax({
        type: "GET",
        dataType: "json",
        url: "/api/bands/" + bandId + "/followers",
        processData: false
      });
    }

    function getClientDownloads(options) {

      return $.ajax({
        type: "GET",
        url: '/api/artifacts/clients',
        dataType: 'json'
      });
    }

    /** check if the server is alive */
    function serverHealthCheck(options) {
      return $.ajax({
        type: "GET",
        url: "/api/healthcheck"
      });
    }

    function getId(options) {
      var id = options && options["id"]

      if (!id) {
        id = context.JK.currentUserId;
      }
      else {
        delete options["id"];
      }

      return id;
    }

    function createEmailInvitations(emails, message) {
      return $.ajax({
        type: "POST",
        dataType: "json",
        url: '/api/invited_users',
        contentType: 'application/json',
        processData: false,
        data: JSON.stringify({
          emails: emails,
          note: message
        })
      });
    }

    function getMusicianInvites(options) {
      return $.ajax({
        type: "GET",
        dataType: "json",
        data: options,
        url: '/api/invitations'
      })
    }

    function createMusicianInvite(options) {
      return $.ajax({
        type: "POST",
        dataType: "json",
        url: '/api/invitations',
        contentType: 'application/json',
        processData: false,
        data: JSON.stringify(options)
      })
    }

    function postFeedback(email, body) {
      return $.ajax({
        type: "POST",
        dataType: "json",
        url: '/api/feedback',
        contentType: 'application/json',
        processData: false,
        data: JSON.stringify({
          email: email,
          body: body
        })
      });
    }

    function getFeeds(options) {
      if (!options) {
        options = {};
      }
      return $.ajax({
        type: 'GET',
        dataType: "json",
        url: "/api/feeds?" + $.param(options),
        processData: false
      })
    }

    function getUserSyncs(options) {
      if (!options) {
        options = {};
      }
      var userId = getId(options)
      return $.ajax({
        type: 'GET',
        dataType: "json",
        url: "/api/users/" + userId + "/syncs?" + $.param(options),
        processData: false
      })
    }

    function getUserSync(options) {
      if (!options) {
        options = {};
      }
      var userId = getId(options)
      var userSyncId = options['user_sync_id']

      return $.ajax({
        type: 'GET',
        dataType: "json",
        url: "/api/users/" + userId + "/syncs/" + userSyncId,
        processData: false
      })
    }

    function sendFriendRequest(app, userId, callback) {
      var url = "/api/users/" + context.JK.currentUserId + "/friend_requests";
      return $.ajax({
        type: "POST",
        dataType: "json",
        contentType: 'application/json',
        url: url,
        data: '{"friend_id":"' + userId + '"}',
        processData: false,
        success: function (response) {
          if (callback) {
            callback(userId);
          }
          context.JK.GA.trackFriendConnect(context.JK.GA.FriendConnectTypes.request);
        },
        error: app.ajaxError
      });
    }

    function getFriendRequest(options) {
      var id = getId(options);
      var friendRequestId = options["friend_request_id"];

      var deferred = $.ajax({
        type: "GET",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/users/" + id + "/friend_requests/" + friendRequestId,
        processData: false
      });

      return deferred;
    }

    function acceptFriendRequest(options) {
      var id = getId(options);
      var friendRequestId = options["friend_request_id"];
      var status = options["status"];

      var friend_request = {status: status};

      var deferred = $.ajax({
        type: "POST",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/users/" + id + "/friend_requests/" + friendRequestId,
        data: JSON.stringify(friend_request),
        processData: false
      });

      deferred.done(function () {
        context.JK.GA.trackFriendConnect(context.JK.GA.FriendConnectTypes.accept);
      });

      return deferred;
    }

    function userDownloadedClient(options) {

      return $.ajax({
        type: "POST",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/users/progression/downloaded_client",
        processData: false
      });
    }

    function userCertifiedGear(options) {

      return $.ajax({
        type: "POST",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/users/progression/certified_gear",
        processData: false,
        data: JSON.stringify({
          success: options.success,
          reason: options.reason
        })
      });
    }

    function userSocialPromoted(options) {
      var id = getId(options);

      return $.ajax({
        type: "POST",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/users/progression/social_promoted",
        processData: false
      });
    }

    function userOpenedJamTrackWebPlayer(options) {
      var id = getId(options);

      return $.ajax({
        type: "POST",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/users/progression/opened_jamtrack_web_player",
        processData: false
      });
    }

    function postUserEvent(options) {
      return $.ajax({
        type: "POST",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/users/event/record",
        data: JSON.stringify(options),
        processData: false
      });
    }

    function signout() {
      return $.ajax({
        type: "DELETE",
        dataType: "json",
        url: '/signout',
        contentType: 'application/json'
      });
    }

    function updateUser(options) {
      options = options || {};
      var id = getId(options);

      delete options['id'];

      var deferred = $.ajax({
        type: "POST",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/users/" + id,
        data: JSON.stringify(options),
        processData: false
      });

      deferred.done(function (user) {
        context.JK.currentUserFreeJamTrack = user.show_free_jamtrack
        window.UserActions.loaded(user)
      })

      return deferred;

    }

    function startRecording(options) {
      return $.ajax({
        type: "POST",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/recordings/start",
        data: JSON.stringify(options)
      })
    }

    function stopRecording(options) {
      var recordingId = options["id"]

      return $.ajax({
        type: "POST",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/recordings/" + recordingId + "/stop",
        data: JSON.stringify(options)
      })
    }

    function markRecordedBackingTrackSilent(options) {
      var recordingId = options["recording_id"];
      var trackId = options["backing_track_id"];

      return $.ajax({
        type: "POST",
        dataType: "json",
        contentType: 'application/json',
        data: {},
        url: "/api/recordings/" + recordingId + "/backing_tracks/" + trackId + '/silent'
      });
    }

    function getRecordedTrack(options) {
      var recordingId = options["recording_id"];
      var trackId = options["track_id"];

      return $.ajax({
        type: "GET",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/recordings/" + recordingId + "/tracks/" + trackId
      });
    }

    function getRecordedBackingTrack(options) {
      var recordingId = options["recording_id"];
      var trackId = options["track_id"];

      return $.ajax({
        type: "GET",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/recordings/" + recordingId + "/backing_tracks/" + trackId
      });
    }

    function getRecording(options) {
      var recordingId = options["id"];

      return $.ajax({
        type: "GET",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/recordings/" + recordingId
      });
    }

    function getClaimedRecordings(options) {
      return $.ajax({
        type: "GET",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/claimed_recordings",
        data: options
      });
    }

    function getClaimedRecording(id) {
      return $.ajax({
        type: "GET",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/claimed_recordings/" + id
      });
    }

    function updateClaimedRecording(options) {
      var claimedRecordingId = options["id"];
      return $.ajax({
        type: "PUT",
        dataType: "json",
        url: '/api/claimed_recordings/' + claimedRecordingId,
        contentType: 'application/json',
        processData: false,
        data: JSON.stringify(options)
      });
    }

    function deleteClaimedRecording(id) {
      return $.ajax({
        type: "DELETE",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/claimed_recordings/" + id
      });
    }

    function deleteRecordingClaim(id) {
      return $.ajax({
        type: "DELETE",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/recordings/" + id + "/claim"
      });
    }

    function claimRecording(options) {
      var recordingId = options["id"];

      return $.ajax({
        type: "POST",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/recordings/" + recordingId + "/claim",
        data: JSON.stringify(options)
      })
    }

    function startPlayClaimedRecording(options) {
      var musicSessionId = options["id"];
      var claimedRecordingId = options["claimed_recording_id"];
      delete options["id"];
      delete options["claimed_recording_id"];

      return $.ajax({
        type: "POST",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/sessions/" + musicSessionId + "/claimed_recording/" + claimedRecordingId + "/start",
        data: JSON.stringify(options)
      })
    }

    function stopPlayClaimedRecording(options) {
      var musicSessionId = options["id"];
      var claimedRecordingId = options["claimed_recording_id"];
      delete options["id"];
      delete options["claimed_recording_id"];

      return $.ajax({
        type: "POST",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/sessions/" + musicSessionId + "/claimed_recording/" + claimedRecordingId + "/stop",
        data: JSON.stringify(options)
      })
    }

    function openBackingTrack(options) {
      var musicSessionId = options["id"];
      delete options["id"];

      return $.ajax({
        type: "POST",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/sessions/" + musicSessionId + "/backing_tracks/open",
        data: JSON.stringify(options)
      })
    }

    function closeBackingTrack(options) {
      var musicSessionId = options["id"];
      delete options["id"];

      return $.ajax({
        type: "POST",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/sessions/" + musicSessionId + "/backing_tracks/close",
        data: JSON.stringify(options)
      })
    }

    function markMixdownActive(options) {
      var id = options["id"];

      return $.ajax({
        type: "POST",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/jamtracks/" + id + "/mixdowns/active",
        data: JSON.stringify(options)
      })
    }

    function createMixdown(options) {
      return $.ajax({
        type: "POST",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/mixdowns/",
        data: JSON.stringify(options)
      })
    }

    function editMixdown(options) {
      var id = options["id"];

      return $.ajax({
        type: "POST",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/mixdowns/" + id,
        data: JSON.stringify(options)
      })
    }

    function deleteMixdown(options) {
      var id = options["id"];

      return $.ajax({
        type: "DELETE",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/mixdowns/" + id
      })
    }

    function getMixdown(options) {
      var id = options["id"];

      return $.ajax({
        type: "GET",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/mixdowns/" + id
      })
    }

    function getMixdownPackage(options) {
      var id = options["id"];

      return $.ajax({
        type: "GET",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/mixdown_packages/" + id
      })
    }

    function enqueueMixdown(options) {
      var id = options["id"];

      return $.ajax({
        type: "POST",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/mixdowns/" + id + '/enqueue',
        data: JSON.stringify(options)
      })
    }

    function openJamTrack(options) {
      var musicSessionId = options["id"];
      var jamTrackId = options["jam_track_id"];
      delete options["id"];
      delete options["jam_track_id"];

      return $.ajax({
        type: "POST",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/sessions/" + musicSessionId + "/jam_tracks/" + jamTrackId + "/open",
        data: JSON.stringify(options)
      })
    }

    function playJamTrack(jamTrackId) {
      return $.ajax({
        type: "POST",
        url: '/api/jamtracks/played/' + jamTrackId,
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function closeJamTrack(options) {
      var musicSessionId = options["id"];
      delete options["id"];

      return $.ajax({
        type: "POST",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/sessions/" + musicSessionId + "/jam_tracks/close",
        data: JSON.stringify(options)
      })
    }

    function openMetronome(options) {
      var musicSessionId = options["id"];
      delete options["id"];

      return $.ajax({
        type: "POST",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/sessions/" + musicSessionId + "/metronome/open",
        data: JSON.stringify(options)
      })
    }

    function closeMetronome(options) {
      var musicSessionId = options["id"];
      delete options["id"];

      return $.ajax({
        type: "POST",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/sessions/" + musicSessionId + "/metronome/close",
        data: JSON.stringify(options)
      })
    }

    function discardRecording(options) {
      var recordingId = options["id"];

      return $.ajax({
        type: "POST",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/recordings/" + recordingId + "/discard",
        data: JSON.stringify(options)
      })
    }

    function putTrackSyncChange(options) {
      var musicSessionId = options["id"]
      delete options["id"];

      return $.ajax({
        type: "PUT",
        dataType: "json",
        url: '/api/sessions/' + musicSessionId + '/tracks',
        contentType: 'application/json',
        processData: false,
        data: JSON.stringify(options)
      });
    }

    function getShareSession(options) {
      var id = getId(options);
      var provider = options['provider'];
      delete options['provider']

      return $.ajax({
        type: "GET",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/users/" + id + "/share/session/" + provider,
        data: options
      })
    }

    function getShareRecording(options) {
      var id = getId(options);
      var provider = options['provider'];
      delete options['provider']

      return $.ajax({
        type: "GET",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/users/" + id + "/share/recording/" + provider,
        data: options
      })
    }

    function tweet(options) {
      return $.ajax({
        type: "POST",
        dataType: "json",
        contentType: 'application/json',
        url: "/api/twitter/tweet",
        data: JSON.stringify(options)
      })
    }

    function createFbInviteUrl() {
      return $.ajax({
        type: "GET",
        url: '/api/invited_users/facebook',
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function createTextMessage(options) {
      var id = getId(options);
      return $.ajax({
        type: "POST",
        url: '/api/text_messages',
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(options)
      });
    }

    function getTextMessages(options) {
      if (!options) options = {};
      var id = getId(options);
      return $.ajax({
        type: "GET",
        url: '/api/text_messages?' + $.param(options),
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function getNotifications(options) {
      if (!options) options = {};
      var id = getId(options);
      return $.ajax({
        type: "GET",
        url: '/api/users/' + id + '/notifications?' + $.param(options),
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function createChatMessage(data) {
      return $.ajax({
        type: "POST",
        url: '/api/chat',
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(data)
      });
    }

    function getChatMessages(options) {
      return $.ajax({
        type: "GET",
        url: '/api/chat?' + $.param(options),
        dataType: "json",
        contentType: 'application/json'
      })
    };

    function createDiagnostic(options) {
      var data = null;
      try {
        data = JSON.stringify(options)
      }
      catch (e) {
        data = JSON.stringify({data_error: "unable to JSON.stringify debug data:" + e.toString()})
      }
      return $.ajax({
        type: "POST",
        url: '/api/diagnostics',
        dataType: "json",
        contentType: 'application/json',
        data: data,
      });
    }

    function getLatencyTester(options) {
      return $.ajax({
        type: "GET",
        url: '/api/latency_testers',
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(options)
      });
    }

    function updateAudioLatency(options) {
      var id = getId(options);
      return $.ajax({
        type: "POST",
        url: '/api/users/' + id + '/audio_latency',
        dataType: "json",
        contentType: 'application/json',
        data: options,
      });
    }

    function getJamTrack(options) {
      return $.ajax({
        type: "GET",
        url: '/api/jamtracks/' + options['plan_code'] + '?' + $.param(options),
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function getJamTrackWithArtistInfo(options) {
      return $.ajax({
        type: "GET",
        url: '/api/jamtracks/band/' + options['plan_code'] + '?' + $.param(options),
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function getJamTracks(options) {
      return $.ajax({
        type: "GET",
        url: '/api/jamtracks?' + $.param(options),
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function autocompleteJamTracks(options) {
      return $.ajax({
        type: "GET",
        url: '/api/jamtracks/autocomplete?' + $.param(options),
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function getJamTrackArtists(options) {
      return $.ajax({
        type: "GET",
        url: '/api/jamtracks/artists?' + $.param(options),
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function getJamTrackRight(options) {
      var jamTrackId = options['id'];

      return $.ajax({
        type: "GET",
        url: '/api/jamtracks/rights/' + jamTrackId + '?' + $.param(options),
        dataType: "json",
        contentType: 'application/json'
      })
    }

    function enqueueJamTrack(options) {
      var jamTrackId = options['id'];
      delete options['id']

      return $.ajax({
        type: "POST",
        url: '/api/jamtracks/enqueue/' + jamTrackId,
        dataType: "json",
        data: options
      });
    }

    function getPurchasedJamTracks(options) {
      return $.ajax({
        type: "GET",
        url: '/api/jamtracks/purchased?' + $.param(options),
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function getPaymentHistory(options) {
      return $.ajax({
        type: "GET",
        url: '/api/recurly/payment_history',
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function getSalesHistory(options) {
      return $.ajax({
        type: "GET",
        url: '/api/payment_histories?' + $.param(options),
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function getBackingTracks(options) {
      return $.ajax({
        type: "GET",
        url: '/api/backing_tracks?' + $.param(options),
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function addJamtrackToShoppingCart(options) {
      var deferred = $.ajax({
        type: "POST",
        url: '/api/shopping_carts/add_jamtrack?' + $.param(options),
        dataType: "json",
        contentType: 'application/json'
      });

      deferred.done(function (response) {
        window.UserActions.modify(response)
      })
      return deferred
    }

    function addGiftCardToShoppingCart(options) {
      var deferred = $.ajax({
        type: "POST",
        url: '/api/shopping_carts/add_gift_card?' + $.param(options),
        dataType: "json",
        contentType: 'application/json'
      });

      return deferred
    }

    function getShoppingCarts() {
      // the need for the time de-duplicator indicates we are doing something wrong on the server
      return $.ajax({
        type: "GET",
        url: '/api/shopping_carts?time=' + new Date().getTime(),
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function removeShoppingCart(options) {
      var deferred = $.ajax({
        type: "DELETE",
        url: '/api/shopping_carts?' + $.param(options),
        dataType: "json",
        contentType: 'application/json'
      })

      deferred.done(function (response) {
        window.UserActions.modify(response)
      })
      return deferred
    }

    function clearShoppingCart(options) {
      return $.ajax({
        type: "DELETE",
        url: '/api/shopping_carts/clear_all',
        dataType: "json",
        contentType: 'application/json'
      })
    }

    function getRecurlyAccount() {
      return $.ajax({
        type: "GET",
        url: '/api/recurly/get_account',
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function createRecurlyAccount(options) {
      return $.ajax({
        type: "POST",
        url: '/api/recurly/create_account?' + $.param(options),
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function getBillingInfo() {
      return $.ajax({
        type: "GET",
        url: '/api/recurly/billing_info',
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function updateBillingInfo(options) {
      return $.ajax({
        type: "PUT",
        url: '/api/recurly/update_billing_info?' + $.param({billing_info: options}),
        dataType: "json",
        //data: JSON.stringify({"billing_info": $.param(options)}),
        contentType: 'application/json'
      });
    }

    function placeOrder() {
      return $.ajax({
        type: "POST",
        url: '/api/recurly/place_order',
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function searchMusicians(query) {
      return $.ajax({
        type: "GET",
        url: "/api/search.json?" + $.param(query)
      });
    }

    function searchTeachers(query) {
      return $.ajax({
        type: "GET",
        url: "/api/teachers?" + $.param(query),
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function getMusicianSearchFilter(query) {
      var qarg = query === undefined ? '' : query;
      return $.get("/api/search/musicians.json?" + qarg);
    }

    function postMusicianSearchFilter(query) {
      return $.ajax({
        type: "POST",
        url: "/api/search/musicians.json",
        data: query
      });
    }

    function getBandSearchFilter(query) {
      var qarg = query === undefined ? '' : query;
      return $.get("/api/search/bands.json?" + qarg);
    }

    function postBandSearchFilter(query) {
      return $.ajax({
        type: "POST",
        url: "/api/search/bands.json",
        data: query
      });
    }

    function getMount(options) {
      var id = getId(options);
      return $.ajax({
        type: "GET",
        url: '/api/icecast/mount/' + id,
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function createSourceChange(options) {
      var mountId = options['mount_id'];

      return $.ajax({
        type: "POST",
        url: '/api/icecast/mount/' + mountId + '/source_change',
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(options),
      });
    }

    function validateUrlSite(url, sitetype) {
      return $.ajax({
        type: "GET",
        url: '/api/data_validation?sitetype=' + sitetype + '&data=' + encodeURIComponent(url),
        contentType: 'application/json'
      });
    }

    function addRecordingTimeline(recordingId, data) {
      return $.ajax({
        type: "POST",
        url: '/api/recordings/' + recordingId + '/timeline',
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(data),
      });
    }


    function addRecordingVideoData(recordingId, data) {
      return $.ajax({
        type: "POST",
        url: '/api/recordings/' + recordingId + '/video_data',
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(data),
      });
    }

    function deleteRecordingVideoData(recordingId) {
      return $.ajax({
        type: "DELETE",
        url: '/api/recordings/' + recordingId + '/video_data',
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function createSignupHint(data) {
      return $.ajax({
        type: "POST",
        url: '/api/signup_hints',
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(data),
      });
    }

    function createRedirectHint(data) {
      return $.ajax({
        type: "POST",
        url: '/api/redirect_hints',
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(data),
      });
    }

    function signup(data) {
      return $.ajax({
        type: "POST",
        url: '/api/users',
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(data),
      });
    }

    function redeemGiftCard(data) {
      var id = getId(data);
      return $.ajax({
        type: "POST",
        url: '/api/users/' + id + '/gift_cards',
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(data),
      });
    }

    function portOverCarts() {
      return $.ajax({
        type: "POST",
        url: '/api/shopping_carts/port',
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(data)
      })
    }


    function attachRecordingToLesson(data) {
      return $.ajax({
        type: "POST",
        url: '/api/lesson_sessions/' + data.id + '/attach_recording',
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(data)
      })
    }

    function attachRecordingToSession(data) {
      return $.ajax({
        type: "POST",
        url: '/api/sessions/' + data.id + '/attach_recording',
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(data)
      })
    }


    function bookLesson(data) {
      return $.ajax({
        type: "POST",
        url: '/api/lesson_bookings',
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(data)
      })
    }

    function getTestDrivePackageChoice(options) {
      options = options || {}
      return $.ajax({
        type: "GET",
        url: '/api/test_drive_package_choice/' + options.id,
        dataType: "json",
        contentType: 'application/json'
      })
    }

    function getLessonBooking(options) {
      options = options || {}
      return $.ajax({
        type: "GET",
        url: '/api/lesson_bookings/' + options.id,
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(options)
      })
    }


    function getUnprocessedLesson(options) {
      options = options || {}
      return $.ajax({
        type: "GET",
        url: '/api/lesson_bookings/unprocessed',
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(options)
      })
    }

    function getUnprocessedLessonOrIntent(options) {
      options = options || {}
      return $.ajax({
        type: "GET",
        url: '/api/lesson_bookings/unprocessed_or_intent',
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(options)
      })
    }

    function acceptLessonBooking(options) {
      return $.ajax({
        type: "POST",
        url: '/api/lesson_bookings/' + options.id + '/accept',
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(options)
      })
    }

    function counterLessonBooking(options) {
      return $.ajax({
        type: "POST",
        url: '/api/lesson_bookings/' + options.id + '/counter',
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(options)
      })
    }


    function cancelLessonBooking(options) {
      return $.ajax({
        type: "POST",
        url: '/api/lesson_bookings/' + options.id + '/cancel',
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(options)
      })
    }

    function createAlert(subject, data) {
      var message = {subject: subject};
      $.extend(message, data);
      console.log("message", message)
      return $.ajax({
        type: "POST",
        url: '/api/alerts',
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(message),
      });
    }

    function submitStripe(options) {
      return $.ajax({
        type: "POST",
        url: '/api/stripe',
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(options)
      })
    }

    function getLessonSessions(options) {
      options = options || {}
      return $.ajax({
        type: "GET",
        url: "/api/lesson_sessions?" + $.param(options),
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function getUncollectables(options) {
      options = options || {}
      return $.ajax({
        type: "GET",
        url: "/api/lesson_sessions/uncollectable",
        dataType: "json",
        contentType: 'application/json'
      });
    }


    function getLesson(options) {
      options = options || {}
      return $.ajax({
        type: "GET",
        url: "/api/lesson_sessions/" + options.id,
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function getLessonAnalysis(options) {
      options = options || {}
      return $.ajax({
        type: "GET",
        url: "/api/lesson_sessions/" + options.id + "/analysis",
        dataType: "json",
        contentType: 'application/json'
      });
    }


    function updateLessonSessionUnreadMessages(options) {
      return $.ajax({
        type: "POST",
        url: '/api/lesson_sessions/' + options.id + "/update_unread_messages",
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(options)
      })
    }

    function checkLessonReschedule(options) {
      return $.ajax({
        type: "POST",
        url: '/api/lesson_sessions/' + options.id + "/reschedule_check",
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(options)
      })
    }


    function checkLessonCancel(options) {
      return $.ajax({
        type: "POST",
        url: '/api/lesson_sessions/' + options.id + "/cancel_check",
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(options)
      })
    }

    function lessonStartTime(options) {
      return $.ajax({
        type: "POST",
        url: '/api/lesson_sessions/' + options.id + "/start_time",
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(options)
      })
    }

    function getTestDriveStatus(options) {
      return $.ajax({
        type: "GET",
        url: "/api/users/" + options.id + "/test_drive/" + options.teacher_id,
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function createTeacherIntent(options) {
      return $.ajax({
        type: "POST",
        url: '/api/teachers/' + options.id + "/intent",
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(options)
      })
    }

    function getSchool(options) {

      var id = getId(options);
      return $.ajax({
        type: "GET",
        url: "/api/schools/" + id,
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function updateSchool(options) {
      var id = getId(options);
      return $.ajax({
        type: "POST",
        url: '/api/schools/' + id,
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(options)
      })
    }

    function updateSchoolAvatar(options) {
      var id = getId(options);

      var original_fpfile = options['original_fpfile'];
      var cropped_fpfile = options['cropped_fpfile'];
      var cropped_large_fpfile = options['cropped_large_fpfile'];
      var crop_selection = options['crop_selection'];

      logger.debug(JSON.stringify({
        original_fpfile: original_fpfile,
        cropped_fpfile: cropped_fpfile,
        cropped_large_fpfile: cropped_large_fpfile,
        crop_selection: crop_selection
      }));

      var url = "/api/schools/" + id + "/avatar";
      return $.ajax({
        type: "POST",
        dataType: "json",
        url: url,
        contentType: 'application/json',
        processData: false,
        data: JSON.stringify({
          original_fpfile: original_fpfile,
          cropped_fpfile: cropped_fpfile,
          cropped_large_fpfile: cropped_large_fpfile,
          crop_selection: crop_selection
        })
      });
    }

    function deleteSchoolAvatar(options) {
      var id = getId(options);

      var url = "/api/schools/" + id + "/avatar";
      return $.ajax({
        type: "DELETE",
        dataType: "json",
        url: url,
        contentType: 'application/json',
        processData: false
      });
    }

    function generateSchoolFilePickerPolicy(options) {
      var id = getId(options);
      var handle = options && options["handle"];
      var convert = options && options["convert"]

      var url = "/api/schools/" + id + "/filepicker_policy";

      return $.ajax(url, {
        data: {handle: handle, convert: convert},
        dataType: 'json'
      });
    }

    function listSchoolInvitations(options) {

      var id = getId(options);

      return $.ajax({
        type: "GET",
        url: "/api/schools/" + id + '/invitations?' + $.param(options),
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function createSchoolInvitation(options) {

      var id = getId(options);

      return $.ajax({
        type: "POST",
        url: "/api/schools/" + id + '/invitations?' + $.param(options),
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(options)
      });
    }

    function deleteSchoolInvitation(options) {

      var id = getId(options);

      return $.ajax({
        type: "DELETE",
        url: "/api/schools/" + id + '/invitations/' + options.invitation_id,
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function resendSchoolInvitation(options) {

      var id = getId(options);

      return $.ajax({
        type: "POST",
        url: "/api/schools/" + id + '/invitations/' + options.invitation_id + '/resend',
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(options)
      });
    }

    function deleteSchoolStudent(options) {

      var id = getId(options);

      return $.ajax({
        type: "DELETE",
        url: "/api/schools/" + id + '/students/' + options.student_id,
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function deleteSchoolTeacher(options) {

      var id = getId(options);

      return $.ajax({
        type: "DELETE",
        url: "/api/schools/" + id + '/teachers/' + options.teacher_id,
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function getRetailer(options) {

      var id = getId(options);
      return $.ajax({
        type: "GET",
        url: "/api/retailers/" + id,
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function updateRetailer(options) {
      var id = getId(options);
      return $.ajax({
        type: "POST",
        url: '/api/retailers/' + id,
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(options)
      })
    }

    function updateRetailerAvatar(options) {
      var id = getId(options);

      var original_fpfile = options['original_fpfile'];
      var cropped_fpfile = options['cropped_fpfile'];
      var cropped_large_fpfile = options['cropped_large_fpfile'];
      var crop_selection = options['crop_selection'];

      logger.debug(JSON.stringify({
        original_fpfile: original_fpfile,
        cropped_fpfile: cropped_fpfile,
        cropped_large_fpfile: cropped_large_fpfile,
        crop_selection: crop_selection
      }));

      var url = "/api/retailers/" + id + "/avatar";
      return $.ajax({
        type: "POST",
        dataType: "json",
        url: url,
        contentType: 'application/json',
        processData: false,
        data: JSON.stringify({
          original_fpfile: original_fpfile,
          cropped_fpfile: cropped_fpfile,
          cropped_large_fpfile: cropped_large_fpfile,
          crop_selection: crop_selection
        })
      });
    }

    function deleteRetailerAvatar(options) {
      var id = getId(options);

      var url = "/api/retailers/" + id + "/avatar";
      return $.ajax({
        type: "DELETE",
        dataType: "json",
        url: url,
        contentType: 'application/json',
        processData: false
      });
    }

    function generateRetailerFilePickerPolicy(options) {
      var id = getId(options);
      var handle = options && options["handle"];
      var convert = options && options["convert"]

      var url = "/api/retailers/" + id + "/filepicker_policy";

      return $.ajax(url, {
        data: {handle: handle, convert: convert},
        dataType: 'json'
      });
    }

    function listRetailerInvitations(options) {

      var id = getId(options);

      return $.ajax({
        type: "GET",
        url: "/api/retailers/" + id + '/invitations?' + $.param(options),
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function createRetailerInvitation(options) {

      var id = getId(options);

      return $.ajax({
        type: "POST",
        url: "/api/retailers/" + id + '/invitations?' + $.param(options),
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(options)
      });
    }

    function deleteRetailerInvitation(options) {

      var id = getId(options);

      return $.ajax({
        type: "DELETE",
        url: "/api/retailers/" + id + '/invitations/' + options.invitation_id,
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function resendRetailerInvitation(options) {

      var id = getId(options);

      return $.ajax({
        type: "POST",
        url: "/api/retaiers/" + id + '/invitations/' + options.invitation_id + '/resend',
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(options)
      });
    }

    function deleteRetailerStudent(options) {

      var id = getId(options);

      return $.ajax({
        type: "DELETE",
        url: "/api/retailers/" + id + '/students/' + options.student_id,
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function deleteRetailerTeacher(options) {

      var id = getId(options);

      return $.ajax({
        type: "DELETE",
        url: "/api/retailers/" + id + '/teachers/' + options.teacher_id,
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function listTeacherDistributions(options) {

      if (!options) {
        options = {}
      }

      return $.ajax({
        type: "GET",
        url: "/api/teacher_distributions?" + $.param(options),
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function getConfigClient(options) {

      if (!options) {
        options = {}
      }

      return $.ajax({
        type: "GET",
        url: "/api/config/client?" + $.param(options),
        dataType: "json",
        contentType: 'application/json'
      });
    }

    function createReview(options) {

      return $.ajax({
        type: "POST",
        url: '/api/reviews',
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(options),
      });
    }

    function askSearchHelp(options) {

      return $.ajax({
        type: "POST",
        url: '/api/teachers/search_help',
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(options),
      })
    }

    function ratingDecision(options) {
      return $.ajax({
        type: "GET",
        url: '/api/lesson_sessions/rating_decision?' + $.param(options),
        dataType: "json",
        contentType: 'application/json'
      })
    }

    function posaActivate(options) {
      var slug = options.slug
      delete options.slug

      return $.ajax({
        type: "POST",
        url: '/api/posa/' + slug + '/activate',
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(options),
      })
    }

    function posaClaim(options) {

      return $.ajax({
        type: "POST",
        url: '/api/posa/claim',
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(options),
      })
    }

    function sendRetailerCustomerEmail(options) {
      options = options || {}
      var retailerId = options.retailer
      delete options.retailer

      return $.ajax({
        type: 'POST',
        url: '/api/retailers/' + retailerId + '/customer_email',
        dataType: 'json',
        contentType: 'application/json',
        data: JSON.stringify(options)
      })
    }

    function paypalDetail(options) {
      options = options || {}
      return $.ajax({
        type: 'POST',
        url: '/api/paypal/checkout/detail',
        dataType: 'json',
        contentType: 'application/json',
        data: JSON.stringify(options)
      })
    }

    function paypalPlaceOrder(options) {
      options = options || {}
      return $.ajax({
        type: 'POST',
        url: '/api/paypal/checkout/confirm',
        dataType: 'json',
        contentType: 'application/json',
        data: JSON.stringify(options)
      })
    }

    function createSubscription(options) {
      options = options || {}
      return $.ajax({
        type: "POST",
        url: '/api/recurly/create_subscription',
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(options)
      })
    }

    function updatePayment(options) {
      options = options || {}
      return $.ajax({
        type: "POST",
        url: '/api/recurly/update_payment',
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(options)
      })
    }

    function getSubscription() {
      return $.ajax({
        type: "GET",
        url: '/api/recurly/get_subscription',
        dataType: "json",
        contentType: 'application/json'
      })
    }

    function changeSubscription(plan_code) {
      var options = {plan_code: plan_code}
      return $.ajax({
        type: "POST",
        url: '/api/recurly/change_subscription',
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(options)
      })
    }

    function cancelSubscription(options) {
      options = options || {}
      return $.ajax({
        type: "POST",
        url: '/api/recurly/cancel_subscription',
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify(options)
      })
    }

    function listInvoices(options) {
      return $.ajax({
        type: "GET",
        url: '/api/recurly/invoice_history',
        dataType: "json",
        contentType: 'application/json'
      })
    }

    function createLiveStream(musicSessionId) {
      return $.ajax({
        type: "POST",
        url: '/api/sessions/' + musicSessionId + '/livestream',
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify({})
      })
    }

    function liveStreamTransition(musicSessionId, broadcastStatus) {
      return $.ajax({
        type: "POST",
        url: '/api/sessions/' + musicSessionId + '/livestream/transition',
        dataType: "json",
        contentType: 'application/json',
        data: JSON.stringify({broadcastStatus: broadcastStatus})
      })
    }

    function getLiveStream(musicSessionId) {
      return $.ajax({
        type: "GET",
        url: '/api/sessions/' + musicSessionId + '/livestream',
        dataType: "json",
        contentType: 'application/json'
      })
    }

    function getBroadcast(musicSessionId) {
      return $.ajax({
        type: "GET",
        url: '/api/sessions/' + musicSessionId + '/broadcast',
        dataType: "json",
        contentType: 'application/json'
      })
    }

    function listOnboardings(id) {
      return $.ajax({
        type: "GET",
        url: '/api/users/' + id + '/onboardings',
        dataType: "json",
        contentType: 'application/json'
      })
    }

    function getOnboarding(id) {
      return $.ajax({
        type: "GET",
        url: '/api/users/' + id + '/onboardings',
        dataType: "json",
        contentType: 'application/json'
      })
    }
    function updateOnboarding(options) {
      options = options || {}
      var id = options.id
      delete options.id

      return $.ajax({
        type: 'POST',
        url: '/api/users/' + id + '/onboardings',
        dataType: 'json',
        contentType: 'application/json',
        data: JSON.stringify(options)
      })
    }



    function initialize() {
      return self;
    }

    // Expose publics
    this.initialize = initialize;
    this.legacyCreateSession = legacyCreateSession;
    this.createScheduledSession = createScheduledSession;
    this.uploadMusicNotations = uploadMusicNotations;
    this.getMusicNotation = getMusicNotation;
    this.deleteMusicNotation = deleteMusicNotation;
    this.getBroadcastNotification = getBroadcastNotification;
    this.quietBroadcastNotification = quietBroadcastNotification;
    this.legacyJoinSession = legacyJoinSession;
    this.joinSession = joinSession;
    this.cancelSession = cancelSession;
    this.updateScheduledSession = updateScheduledSession;
    this.getUserDetail = getUserDetail;
    this.getUserJamBlasters = getUserJamBlasters;
    this.getUserAuthorizations = getUserAuthorizations;
    this.getGoogleAuth = getGoogleAuth;
    this.getUserProfile = getUserProfile;
    this.getAffiliatePartnerData = getAffiliatePartnerData;
    this.postAffiliatePartnerData = postAffiliatePartnerData;
    this.createAffiliatePartner = createAffiliatePartner;
    this.getLinks = getLinks;
    this.getAffiliateSignups = getAffiliateSignups;
    this.getAffiliateMonthly = getAffiliateMonthly;
    this.getAffiliateQuarterly = getAffiliateQuarterly;
    this.getAffiliatePayments = getAffiliatePayments;
    this.getCities = getCities;
    this.getRegions = getRegions;
    this.getCountries = getCountries;
    this.getResolvedLocation = getResolvedLocation;
    this.getInstruments = getInstruments;
    this.getGenres = getGenres;
    this.getSubjects = getSubjects;
    this.getLanguages = getLanguages;
    this.updateUdpReachable = updateUdpReachable;
    this.updateNetworkTesting = updateNetworkTesting;
    this.updateAvatar = updateAvatar;
    this.deleteAvatar = deleteAvatar;
    this.getFilepickerPolicy = getFilepickerPolicy;
    this.getFriends = getFriends;
    this.removeFriend = removeFriend;
    this.addLike = addLike;
    this.removeLike = removeLike;
    this.addFollowing = addFollowing;
    this.removeFollowing = removeFollowing;
    this.getFollowings = getFollowings;
    this.getFollowers = getFollowers;
    this.getBands = getBands;
    this.getBandFollowers = getBandFollowers;
    this.findActiveSessions = findActiveSessions;
    this.findInactiveSessions = findInactiveSessions;
    this.findScheduledSessions = findScheduledSessions;
    this.findScheduledRsvpSessions = findScheduledRsvpSessions;
    this.updateSession = updateSession;
    this.getSessionHistory = getSessionHistory;
    this.addSessionComment = addSessionComment;
    this.addSessionInfoComment = addSessionInfoComment;
    this.addSessionLike = addSessionLike;
    this.getRsvpRequests = getRsvpRequests;
    this.submitRsvpRequest = submitRsvpRequest;
    this.updateRsvpRequest = updateRsvpRequest;
    this.cancelRsvpRequest = cancelRsvpRequest;
    this.getOpenSessionSlots = getOpenSessionSlots;
    this.addRecordingComment = addRecordingComment;
    this.addRecordingLike = addRecordingLike;
    this.addPlayablePlay = addPlayablePlay;
    this.getSession = getSession;
    this.deleteParticipant = deleteParticipant;
    this.getClientDownloads = getClientDownloads;
    this.createEmailInvitations = createEmailInvitations;
    this.createMusicianInvite = createMusicianInvite;
    this.getMusicianInvites = getMusicianInvites;
    this.postFeedback = postFeedback;
    this.getFeeds = getFeeds;
    this.getUserSyncs = getUserSyncs;
    this.getUserSync = getUserSync;
    this.serverHealthCheck = serverHealthCheck;
    this.sendFriendRequest = sendFriendRequest;
    this.getFriendRequest = getFriendRequest;
    this.acceptFriendRequest = acceptFriendRequest;
    this.signout = signout;
    this.userDownloadedClient = userDownloadedClient;
    this.userCertifiedGear = userCertifiedGear;
    this.userSocialPromoted = userSocialPromoted;
    this.userOpenedJamTrackWebPlayer = userOpenedJamTrackWebPlayer;
    this.postUserEvent = postUserEvent;
    this.createJoinRequest = createJoinRequest;
    this.updateJoinRequest = updateJoinRequest;
    this.updateUser = updateUser;
    this.startRecording = startRecording;
    this.stopRecording = stopRecording;
    this.getRecording = getRecording;
    this.getRecordedTrack = getRecordedTrack;
    this.getRecordedBackingTrack = getRecordedBackingTrack;
    this.getClaimedRecordings = getClaimedRecordings;
    this.getClaimedRecording = getClaimedRecording;
    this.updateClaimedRecording = updateClaimedRecording;
    this.deleteClaimedRecording = deleteClaimedRecording;
    this.deleteRecordingClaim = deleteRecordingClaim;
    this.claimRecording = claimRecording;
    this.startPlayClaimedRecording = startPlayClaimedRecording;
    this.stopPlayClaimedRecording = stopPlayClaimedRecording;
    this.markMixdownActive = markMixdownActive;
    this.createMixdown = createMixdown;
    this.editMixdown = editMixdown;
    this.deleteMixdown = deleteMixdown;
    this.enqueueMixdown = enqueueMixdown;
    this.getMixdown = getMixdown;
    this.getMixdownPackage = getMixdownPackage;
    this.openJamTrack = openJamTrack
    this.openBackingTrack = openBackingTrack
    this.closeBackingTrack = closeBackingTrack
    this.closeMetronome = closeMetronome;
    this.closeJamTrack = closeJamTrack;
    this.openMetronome = openMetronome;
    this.closeMetronome = closeMetronome;
    this.discardRecording = discardRecording;
    this.putTrackSyncChange = putTrackSyncChange;
    this.createBand = createBand;
    this.updateBand = updateBand;
    this.updateBandPhoto = updateBandPhoto;
    this.deleteBandPhoto = deleteBandPhoto;
    this.deleteBand = deleteBand;
    this.getBandPhotoFilepickerPolicy = getBandPhotoFilepickerPolicy;
    this.getBand = getBand;
    this.validateBand = validateBand;
    this.getTeacher = getTeacher;
    this.updateTeacher = updateTeacher;
    this.deleteTeacher = deleteTeacher;
    this.updateFavorite = updateFavorite;
    this.createBandInvitation = createBandInvitation;
    this.updateBandInvitation = updateBandInvitation;
    this.removeBandMember = removeBandMember;
    this.getBandMembers = getBandMembers;
    this.login = login;
    this.getShareSession = getShareSession;
    this.getShareRecording = getShareRecording;
    this.tweet = tweet;
    this.createFbInviteUrl = createFbInviteUrl;
    this.createTextMessage = createTextMessage;
    this.getTextMessages = getTextMessages;
    this.getNotifications = getNotifications;
    this.createChatMessage = createChatMessage;
    this.getChatMessages = getChatMessages;
    this.createDiagnostic = createDiagnostic;
    this.getLatencyTester = getLatencyTester;
    this.updateAudioLatency = updateAudioLatency;
    this.getJamTrack = getJamTrack;
    this.getJamTrackWithArtistInfo = getJamTrackWithArtistInfo;
    this.getJamTracks = getJamTracks;
    this.autocompleteJamTracks = autocompleteJamTracks;
    this.getJamTrackArtists = getJamTrackArtists;
    this.getPurchasedJamTracks = getPurchasedJamTracks;
    this.getPaymentHistory = getPaymentHistory;
    this.getSalesHistory = getSalesHistory;
    this.getJamTrackRight = getJamTrackRight;
    this.enqueueJamTrack = enqueueJamTrack;
    this.getBackingTracks = getBackingTracks;
    this.addJamtrackToShoppingCart = addJamtrackToShoppingCart;
    this.addGiftCardToShoppingCart = addGiftCardToShoppingCart;
    this.getShoppingCarts = getShoppingCarts;
    this.removeShoppingCart = removeShoppingCart;
    this.clearShoppingCart = clearShoppingCart;
    this.getRecurlyAccount = getRecurlyAccount;
    this.createRecurlyAccount = createRecurlyAccount;
    this.getBillingInfo = getBillingInfo;
    this.updateBillingInfo = updateBillingInfo;
    this.placeOrder = placeOrder;
    this.searchMusicians = searchMusicians;
    this.searchTeachers = searchTeachers;
    this.resendBandInvitation = resendBandInvitation;
    this.getMount = getMount;
    this.createSourceChange = createSourceChange;
    this.validateUrlSite = validateUrlSite;
    this.markRecordedBackingTrackSilent = markRecordedBackingTrackSilent;
    this.addRecordingTimeline = addRecordingTimeline;
    this.addRecordingVideoData = addRecordingVideoData;
    this.deleteRecordingVideoData = deleteRecordingVideoData;
    this.getMusicianSearchFilter = getMusicianSearchFilter;
    this.postMusicianSearchFilter = postMusicianSearchFilter;
    this.getBandSearchFilter = getBandSearchFilter;
    this.postBandSearchFilter = postBandSearchFilter;
    this.playJamTrack = playJamTrack;
    this.createSignupHint = createSignupHint;
    this.createRedirectHint = createRedirectHint;
    this.createAlert = createAlert;
    this.redeemGiftCard = redeemGiftCard;
    this.signup = signup;
    this.portOverCarts = portOverCarts;
    this.bookLesson = bookLesson;
    this.attachRecordingToLesson = attachRecordingToLesson;
    this.attachRecordingToSession = attachRecordingToSession;
    this.getTestDrivePackageChoice = getTestDrivePackageChoice;
    this.getLessonBooking = getLessonBooking;
    this.getUnprocessedLesson = getUnprocessedLesson;
    this.getUnprocessedLessonOrIntent = getUnprocessedLessonOrIntent;
    this.acceptLessonBooking = acceptLessonBooking;
    this.cancelLessonBooking = cancelLessonBooking;
    this.counterLessonBooking = counterLessonBooking;
    this.submitStripe = submitStripe;
    this.getLessonSessions = getLessonSessions;
    this.getUncollectables = getUncollectables;
    this.getLesson = getLesson;
    this.getLessonAnalysis = getLessonAnalysis;
    this.updateLessonSessionUnreadMessages = updateLessonSessionUnreadMessages;
    this.checkLessonCancel = checkLessonCancel;
    this.checkLessonReschedule = checkLessonReschedule;
    this.getTestDriveStatus = getTestDriveStatus;
    this.createTeacherIntent = createTeacherIntent;
    this.getSchool = getSchool;
    this.updateSchool = updateSchool;
    this.updateSchoolAvatar = updateSchoolAvatar;
    this.deleteSchoolAvatar = deleteSchoolAvatar;
    this.generateSchoolFilePickerPolicy = generateSchoolFilePickerPolicy;
    this.listSchoolInvitations = listSchoolInvitations;
    this.createSchoolInvitation = createSchoolInvitation;
    this.deleteSchoolInvitation = deleteSchoolInvitation;
    this.resendSchoolInvitation = resendSchoolInvitation;
    this.deleteSchoolTeacher = deleteSchoolTeacher;
    this.deleteSchoolStudent = deleteSchoolStudent;
    this.getRetailer = getRetailer;
    this.updateRetailer = updateRetailer;
    this.updateRetailerAvatar = updateRetailerAvatar;
    this.deleteRetailerAvatar = deleteRetailerAvatar;
    this.generateRetailerFilePickerPolicy = generateRetailerFilePickerPolicy;
    this.listRetailerInvitations = listRetailerInvitations;
    this.createRetailerInvitation = createRetailerInvitation;
    this.deleteRetailerInvitation = deleteRetailerInvitation;
    this.resendRetailerInvitation = resendRetailerInvitation;
    this.deleteRetailerTeacher = deleteRetailerTeacher;
    this.deleteRetailerStudent = deleteRetailerStudent;
    this.listTeacherDistributions = listTeacherDistributions;
    this.lessonStartTime = lessonStartTime;
    this.createReview = createReview;
    this.askSearchHelp = askSearchHelp;
    this.ratingDecision = ratingDecision;
    this.posaActivate = posaActivate;
    this.posaClaim = posaClaim;
    this.sendRetailerCustomerEmail = sendRetailerCustomerEmail;
    this.paypalDetail = paypalDetail;
    this.paypalPlaceOrder = paypalPlaceOrder;
    this.createLiveStream = createLiveStream;
    this.liveStreamTransition = liveStreamTransition;
    this.getLiveStream = getLiveStream;
    this.getBroadcast = getBroadcast;
    this.listOnboardings = listOnboardings;
    this.getOnboarding = getOnboarding;
    this.updateOnboarding = updateOnboarding;
    this.findFriendSessions = findFriendSessions;
    this.findPublicSessions = findPublicSessions;
    this.getConfigClient = getConfigClient;
    this.createSubscription = createSubscription;
    this.updatePayment = updatePayment;
    this.getSubscription = getSubscription;
    this.changeSubscription = changeSubscription;
    this.cancelSubscription= cancelSubscription;
    this.listInvoices = listInvoices;
    return this;
  };
})(window, jQuery);
