%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /proc/985914/root/data/old/home/stash/stash/atlassian-stash/static/stash/api/util/
Upload File :
Create Path :
Current File : //proc/985914/root/data/old/home/stash/stash/atlassian-stash/static/stash/api/util/navbuilder.js

/**
 * The basic idea of the nav builder is to support a chain of method calls that roughly map to the structure and categorisation
 * of parts of Stash. This is referred to as the "Builder API" of navbuilder.
 *
 * E.g. `nav.project('foo').repo('bar').permissions()` will return a builder that can build the URL for the permissions page
 * of the repository with slug 'bar' of the project with key 'foo', while just `nav.project('foo')` will return a builder for a URL to
 * the project page for project 'foo'.
 *
 * At each point in the method chain, the returned object will support methods that return a builder
 * that maps to a concept at a lower level.
 * At most points, `.build()` may be called to build the URL to be used. There are a few places where no URL makes sense.
 *
 * The "Classes" listed in this module describe the methods that can be called from each step in the chain. E.g.
 *
 * ```javascript
 * var adminBuilder = navbuilder.admin(); // adminBuilder will be a {@linkcode stash/api/util/navbuilder.AdminBuilder}
 * var groupsBuilder = adminBuilder.groups(); // groupsBuilder will be a {@linkcode stash/api/util/navbuilder.GroupsBuilder}
 * ```
 *
 * **Web Resource:** com.atlassian.stash.stash-web-api:navbuilder
 *
 * @example
 * require([
 *     'stash/api/util/navbuilder',
 *     'stash/api/util/server'
 * ], function (navbuilder, server) {
 *     server.rest({
 *         url: navbuilder.rest().projects().build()
 *     }).then(doSomethingWithProjects);
 * });
 *
 * @namespace stash/api/util/navbuilder
 */
define('stash/api/util/navbuilder', [
    'aui',
    'jquery',
    'lib/jsuri',
    'underscore',
    'util/deprecation',
    'model/page-state',
    'exports'
],
/**
 * @exports stash/api/util/navbuilder
 */
function (
    AJS,
    $,
    Uri,
    _,
    deprecate,
    pageState,
    exports
) {

    'use strict';

    /**
     * Encapsulates a URI path and params that make up a query string.
     * This class is immutable - all mutating operations return a new instance.
     *
     * NOTE: The PathAndQuery constructor is not exposed.
     *
     * @private
     * @class PathAndQuery
     * @memberof stash/api/util/navbuilder
     */
    function PathAndQuery(components, params, anchor) {
        this.components = (_.isString(components) ? [components] : components) || [];
        this.params = params || {};
        this.anchor = anchor || undefined;
    }

    /**
     * Returns the described URL as a string. The returned URL is relative to the Stash application's
     * context path root. E.g. If Stash is running at example.com/stash, the URL example.com/stash/a/b/c
     * will be returned as /a/b/c.
     * In client-side code, this version of the URL is rarely useful. stash/api/util/navbuilder.PathAndQuery.buildRelative is
     * likely to be what you want to use.
     *
     * @name stash/api/util/navbuilder.PathAndQuery#buildRelNoContext
     * @returns {string}
     */
    PathAndQuery.prototype.buildRelNoContext = function() {
        var path = '/' + _.map(this.components, encodeURIComponent).join('/');

        var params = _.reduce(this.params, function(memo, values, key) {
            if (!(_.isArray(values))) {
                values = [values];
            }
            _.forEach(values, function(value) {
                memo.push({ key : key, value : value });
            });
            return memo;
        }, []);
        var query = _.map(params,
            function (param) {
                var encodedValue = encodeURIComponent(param.value);
                return encodeURIComponent(param.key) + (encodedValue ? '=' + encodedValue : '');
            }).join("&");

        return path + (query ? '?' + query : '') + (this.anchor ? '#' + this.anchor : '');
    };

    /**
     * Returns the described URL as a string. The returned URL is relative to the server root. E.g.
     * If Stash is running at example.com/stash, the URL example.com/stash/a/b/c
     * will be returned as /stash/a/b/c.
     *
     * stash/api/util/navbuilder.PathAndQuery.buildRelative
     * @returns {string}
     */
    PathAndQuery.prototype.buildRelative = function () {
        return AJS.contextPath() + this.buildRelNoContext();
    };


    /**
     * Returns the described URL as a string. The returned URL is absolute. E.g.
     * If Stash is running at example.com/stash, the URL example.com/stash/a/b/c
     * will be returned as http://example.com/stash/a/b/c.
     *
     * stash/api/util/navbuilder.PathAndQuery.buildAbsolute
     * @returns {string}
     */
    PathAndQuery.prototype.buildAbsolute = function () {
        return location.protocol + "//" + location.hostname + (location.port ? ':' + location.port : '') + this.buildRelative();
    };

    PathAndQuery.prototype.toString = function() {
        return this.buildRelative();
    };

    /**
     * Adds query parameters. If a map (object) is supplied, its properties are added to the parameters.
     * If a single string is supplied, it is added as a query parameter with no value.
     *
     * @name stash/api/util/navbuilder.PathAndQuery#addParams
     * @returns a new PathAndQuery object with the updated query params
     */
    PathAndQuery.prototype.addParams = function (params) {
        var path = new PathAndQuery(this.components, _.extend({}, this.params));
        if (_.isString(params)) {
            path.params[params] = '';
        } else {
            if (params.hasOwnProperty("queryParams")) {
                path.params = _.extend(path.params, params.queryParams);
            } else if (!params.hasOwnProperty("urlMode")) {
                path.params = _.extend(path.params, params);
            }// todo - implement urlMode
        }
        return path;
    };

    /**
     * Sets the document hash. If a hash has been set previously, it is overwritten
     *
     * @name stash/api/util/navbuilder.PathAndQuery#withFragment
     * @return a new PathAndQuery object with unchanged path and query string params, but with a new anchor
     */
    PathAndQuery.prototype.withFragment = function (anchor) {
        return new PathAndQuery(this.components, this.params, anchor);
    };

    /**
     * Pushes a new path component onto the list of path components.
     *
     * @name stash/api/util/navbuilder.PathAndQuery#pushComponents
     * @returns a new PathAndQuery object with the updated query params
     */
    PathAndQuery.prototype.pushComponents = function() {
        var path = new PathAndQuery(this.components.slice(0), this.params);
        _.each(_.toArray(arguments).slice(0), function (component) {
            if (component !== '') {
                path.components.push(component);
            }
        });
        return path;
    };

    /**
     * A Builder of URLs. All methods in the Builder API will return a subclass of this and will include these methods.
     *
     *
     * NOTE: The Builder constructor is not exposed. A new Builder can be created through
     * {@linkcode stash/api/util/navbuilder.newBuilder}.
     *
     * @class Builder
     * @memberof stash/api/util/navbuilder
     */

    /**
     * Returns a new builder for the current path with the properties supported by otherMethods.
     * Used after each call in the method chain to construct the next object in the chain and specify
     * exactly which calls are acceptable.
     *
     * @name stash/api/util/navbuilder.PathAndQuery#makeBuilder
     * @returns {stash/api/util/navbuilder.Builder} a new builder
     */
    PathAndQuery.prototype.makeBuilder = function (otherMethods) {
        var path = this;
        return _.extend(
            /** @lends stash/api/util/navbuilder.Builder.prototype */
            {
            /**
             * @private
             */
            _path: function() { return path; },
            /**
             * @returns {string} relative URL. See stash/api/util/navbuilder.PathAndQuery.buildRelative
             */
            build: function() { return path.buildRelative(); },
            /**
             * @returns {string} absolute URL. See stash/api/util/navbuilder.PathAndQuery.buildAbsolute
             */
            buildAbsolute: function() { return path.buildAbsolute(); },
            /**
             * @returns {stash/api/util/navbuilder.Uri} URI object formed by the builder.
             */
            parse : function() { return parse(this.build()); },
            /**
             * Sets query string parameters for the output URL of this builder.
             * @param {Object} params - A map of parameter name to value. Previous params with the same names will be overwritten.
             * @returns {stash/api/util/navbuilder.Builder}
             */
            withParams: function(params) {
                //return a new builder with the same methods as the current builder but with added query parameters
                return path.addParams(params).makeBuilder(otherMethods);
            },
            /**
             * Sets the hash (#) portion of the output URL for this builder.
             * @param {string} anchor - The hash portion of the URL.
             * @returns {stash/api/util/navbuilder.Builder}
             */
            withFragment: function (anchor) {
                return path.withFragment(anchor).makeBuilder(otherMethods);
            },
            /**
             * Return a new builder with more path components appended to the URL.
             * @param {...string} component - A path component to append.
             * @returns {stash/api/util/navbuilder.Builder}
             */
            addPathComponents: function() {
                //return a new builder with the same methods as the current builder but with an augmented (new) path
                return path.pushComponents.apply(path, arguments).makeBuilder(otherMethods);
            }
        }, otherMethods);
    };

    // id/slug/key helpers

    // If the input is a string, it's the key/slug/id.
    // Otherwise, if it exists, assume it's a project/repo/PR
    // Otherwise, use this pageState's project/repo/PR.

    /**
     * @private
     */
    function getProjectKey(projectOrKey) {
        if (typeof(projectOrKey) === 'string') {
            return projectOrKey;
        } else if (!projectOrKey) {
            throw new Error(AJS.I18n.getText('stash.web.error.no.project'));
        }
        return projectOrKey.getKey ? projectOrKey.getKey() : projectOrKey.key;
    }

    /**
     * @private
     */
    function getCurrentProject() {
        if (pageState.getProject()) {
            return pageState.getProject();
        }
        throw new Error(AJS.I18n.getText('stash.web.error.no.project.context'));
    }

    /**
     * @private
     */
    function getRepoSlug(repoOrSlug) {
        if (typeof(repoOrSlug) === 'string') {
            return repoOrSlug;
        } else if (!repoOrSlug) {
            throw new Error(AJS.I18n.getText('stash.web.error.no.repo'));
        }
        return repoOrSlug.getSlug ? repoOrSlug.getSlug() : repoOrSlug.slug;
    }

    /**
     * @private
     */
    function getHookKey(hookOrKey) {
        if (typeof(hookOrKey) === 'string') {
            return hookOrKey;
        } else if (!hookOrKey) {
            throw new Error(AJS.I18n.getText('stash.web.error.no.hook.key'));
        }
        return hookOrKey.getDetails().getKey();
    }

    /**
     * @private
     */
    function getCurrentRepository() {
        if (pageState.getRepository()) {
            return pageState.getRepository();
        }
        throw new Error(AJS.I18n.getText('stash.web.error.no.repo.context'));
    }

    /**
     * @private
     */
    function getPullRequestId(prOrId) {
        if (prOrId !== 0 && !prOrId) {
            throw new Error(AJS.I18n.getText('stash.web.error.no.pull-request.id'));
        }

        if (typeof prOrId in {"string":1, "number": 1}) {
            return prOrId;
        }

        return prOrId.getId ? prOrId.getId() : prOrId.id;
    }

    /**
     * @private
     */
    function getCurrentPullRequest() {
        if (pageState.getPullRequest()) {
            return pageState.getPullRequest();
        }
        throw new Error(AJS.I18n.getText('stash.web.error.no.pull-request.context'));
    }


    /**
     * If the project is a personal project, use the /users/slug form otherwise go with /projects/KEY form
     * @private
     */
    function maybeResolveAsUserPath(path) {
        var projectKey = path.components[1];
        var userSlugPattern = /~(.*)/;
        var result = userSlugPattern.exec(projectKey);
        if (result) {
            return new PathAndQuery(['users', result[1].toLowerCase()]);
        } else {
            return path;
        }
    }

    /**
     * pull path components from an arguments object.  We all .path('a', 'b') and .path(['a', 'b']) both.
     * @param {Array<string>} args
     * @private
     */
    function componentsFromArguments(args) {

        //accept multiple args or accept a single arg that's an array to support .path('a', 'b') and .path(['a', 'b'])
        if (args.length === 1) {
            if (args[0] && args[0].getComponents) { // accept a Path object
                return args[0].getComponents();
            } else if (args[0] && args[0].components) { // accept a JSON.PathJSON
                return args[0].components;
            } else if ($.isArray(args[0])) {
                return args[0];
            }
        }
        return _.toArray(args);
    }

    //----------------------------------------
    //Start of Builder API method chains
    //----------------------------------------

    //--- Methods at the root of the chain ---

    /**
     * login-related {@linkcode stash/api/util/navbuilder.Builder}.
     *
     * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
     *
     * @class LoginBuilder
     * @memberof stash/api/util/navbuilder
     */

    /**
     * @memberof stash/api/util/navbuilder
     * @returns {stash/api/util/navbuilder.LoginBuilder}
     */
    function login() {
        return new PathAndQuery('login').makeBuilder(
            /**
             * @lends stash/api/util/navbuilder.LoginBuilder.prototype
             */
            {
            /**
             * @param {string} url - next URL to navigate to after login.
             * @returns {stash/api/util/navbuilder.Builder}
             */
            next : _nextUrl
        });
    }

    /**
     * @private
     */
    function _nextUrl(url) {
        if (typeof url !== 'string') {
            var contextPath = AJS.contextPath();
            var currentPath = location.pathname;
            //Make current path relative if context path exist
            if (contextPath.length > 0) {
                currentPath = currentPath.substring(currentPath.indexOf(contextPath) + contextPath.length);
            }
            url = currentPath + location.search + location.hash;
        }
        return this._path().addParams({ next: url }).makeBuilder();
    }

    /**
     * Temporary resource-related {@linkcode stash/api/util/navbuilder.Builder}.
     *
     * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
     *
     * @class TmpBuilder
     * @memberof stash/api/util/navbuilder
     */

    /**
     * @memberof stash/api/util/navbuilder
     * @returns {stash/api/util/navbuilder.TmpBuilder}
     */
    function tmp() {
        return new PathAndQuery('tmp').makeBuilder(/**
         * @lends stash/api/util/navbuilder.TmpBuilder.prototype
         */
        {
            /**
             * @returns {stash/api/util/navbuilder.Builder}
             */
            avatars: function tmpAvatars(){
                return this._path().pushComponents('avatars').makeBuilder();
            }
        });
    }

    /**
     * Welcome page {@linkcode stash/api/util/navbuilder.Builder}.
     *
     * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
     *
     * @class WelcomeBuilder
     * @memberof stash/api/util/navbuilder
     * @deprecated
     */

    /**
     * @memberof stash/api/util/navbuilder
     * @returns {stash/api/util/navbuilder.WelcomeBuilder}
     */
    function welcome() {
        return gettingStarted();
    }

    /**
     * Getting Started page {@linkcode stash/api/util/navbuilder.Builder}.
     *
     * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
     *
     * @class GettingStartedBuilder
     * @memberof stash/api/util/navbuilder
     */

    /**
     * @memberof stash/api/util/navbuilder
     * @returns {stash/api/util/navbuilder.GettingStartedBuilder}
     */
    function gettingStarted() {
        return new PathAndQuery('getting-started').makeBuilder(/**
             * @lends stash/api/util/navbuilder.GettingStartedBuilder.prototype
             */
            {
                /**
                 * @param {string} url - next URL to navigate to after login.
                 * @returns {stash/api/util/navbuilder.Builder}
                 */
                next : _nextUrl
            });
    }


    /**
     * Admin-related {@linkcode stash/api/util/navbuilder.Builder}.
     *
     * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
     *
     * @class AdminBuilder
     * @memberof stash/api/util/navbuilder
     */

    /**
     * @memberof stash/api/util/navbuilder
     * @returns {stash/api/util/navbuilder.AdminBuilder}
     */
    function admin() {
        return new PathAndQuery('admin').makeBuilder(/**
         * @lends stash/api/util/navbuilder.AdminBuilder.prototype
         */
        {
            /**
             * @method
             * @returns {stash/api/util/navbuilder.PermissionsBuilder}
             */
            permissions: permissions,
            /**
             * @method
             * @returns {stash/api/util/navbuilder.AdminUsersBuilder}
             */
            users: adminUsers,
            /**
             * @method
             * @returns {stash/api/util/navbuilder.GroupsBuilder}
             */
            groups: groups,
            /**
             * @method
             * @returns {stash/api/util/navbuilder.LicenseBuilder}
             */
            licensing: function licensing() {

                /**
                 * License-related {@linkcode stash/api/util/navbuilder.Builder}.
                 *
                 * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
                 *
                 * @class LicenseBuilder
                 * @memberof stash/api/util/navbuilder
                 */

                return this._path().pushComponents('license').makeBuilder(
                /**
                 * @lends stash/api/util/navbuilder.LicenseBuilder.prototype
                 */
                {
                    /**
                     * @returns {stash/api/util/navbuilder.Builder}
                     */
                    edit: function editLicense() {
                        return this._path().addParams({edit: ''}).makeBuilder();
                    }
                });
            },
            /**
             * @returns {stash/api/util/navbuilder.Builder}
             */
            mailServer: function mailServer() {
                return this._path().pushComponents('mail-server').makeBuilder();
            },
            /**
             * @returns {stash/api/util/navbuilder.Builder}
             */
            db : function adminDb() {
                return this._path().pushComponents('db').makeBuilder();
            }
        });
    }

    /**
     * @memberof stash/api/util/navbuilder
     * @returns {stash/api/util/navbuilder.Builder}
     */
    function allProjects() {
        return new PathAndQuery('projects').makeBuilder();
    }


    /**
     * {@linkcode stash/api/util/navbuilder.Builder} for the Stash-wide repository list.
     *
     * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
     *
     * @class GlobalRepoBuilder
     * @memberof stash/api/util/navbuilder
     */

    /**
     * @name allRepos
     * @method
     * @memberof stash/api/util/navbuilder
     * @returns {stash/api/util/navbuilder.GlobalRepoBuilder}
     */
    function globalAllRepos() {
        return new PathAndQuery('repos').makeBuilder(
        /**
         * @lends stash/api/util/navbuilder.GlobalRepoBuilder
         */
        {
            /**
             * @param {string} visibility - A filter to the shown list of repositories: "public" or "private".
             * @returns {stash/api/util/navbuilder.Builder}
             */
            visibility: function allReposWithVisibility(visibility) {
                return this._path().addParams({'visibility': visibility}).makeBuilder();
            }
        });
    }

    /**
     * @memberof stash/api/util/navbuilder
     * @returns {stash/api/util/navbuilder.Builder}
     */
    function captcha() {
        //Add a changing query param to ensure all browsers reload the image when refreshing it - some don't respect the HTTP headers
        return new PathAndQuery('captcha').addParams({'ts' : new Date().getTime().toString()}).makeBuilder();
    }

    /**
     * Project-related {@linkcode stash/api/util/navbuilder.Builder}.
     *
     * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
     *
     * @class ProjectBuilder
     * @memberof stash/api/util/navbuilder
     */

    /**
     * @param {string} projectKey - The key of the project to return a builder for.
     * @returns {stash/api/util/navbuilder.ProjectBuilder}
     */
    function project(projectOrKey) {
        var path = new PathAndQuery(['projects', getProjectKey(projectOrKey)]);

        return maybeResolveAsUserPath(path).makeBuilder(
        /**
         * @lends stash/api/util/navbuilder.ProjectBuilder.prototype
         */
        {
            /**
             * @method
             * @returns {stash/api/util/navbuilder.Builder}
             */
            allRepos: allRepos,
            /**
             * @method
             * @param {string} slug - The slug of the repository to return a builder for.
             * @returns {stash/api/util/navbuilder.RepositoryBuilder}
             */
            repo: repo,
            /**
             * @returns {stash/api/util/navbuilder.Builder}
             */
            createRepo: function createRepo() {
                return maybeResolveAsUserPath(this._path()).pushComponents('repos').addParams('create').makeBuilder();
            },
            /**
             * @returns {stash/api/util/navbuilder.Builder}
             */
            settings: function projSettings() {
                return this._path().pushComponents('settings').makeBuilder();
            },
            /**
             * @method
             * @returns {stash/api/util/navbuilder.PermissionsBuilder}
             */
            permissions: permissions,
            /**
             * @returns {stash/api/util/navbuilder.Builder}
             */
            remove: function projDelete() {
                return this._path().makeBuilder();
            },
            /**
             * @method
             * @returns {stash/api/util/navbuilder.AdminUsersBuilder}
             */
            users: adminUsers,
            /**
             * @method
             * @returns {stash/api/util/navbuilder.GroupsBuilder}
             */
            groups: groups,
            /**
             * @param {number} [size] - A pixel value for the height and width of the avatar. Please use only pixel sizes referenced by the ADG at http://developer.atlassian.com/design.
             * @returns {stash/api/util/navbuilder.Builder}
             */
            avatar: function projAvatar(size) {
                var builder = this._path().pushComponents('avatar.png');
                if (size) {
                    builder = builder.addParams({s: size});
                }
                return builder.makeBuilder();
            }
        });
    }

    /**
     * Returns the project builder for the current page's project, if there is one.
     * @memberof stash/api/util/navbuilder
     * @returns {stash/api/util/navbuilder.ProjectBuilder}
     */
    function currentProject() {
        return project(getCurrentProject());
    }

    /**
     * @memberof stash/api/util/navbuilder
     * @returns {stash/api/util/navbuilder.Builder}
     */
    function createProject() {
        return new PathAndQuery('projects').addParams('create').makeBuilder();
    }

    /**
     * REST URL {@linkcode stash/api/util/navbuilder.Builder}.
     *
     * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
     *
     * @class RestBuilder
     * @memberof stash/api/util/navbuilder
     */

    /**
     * @memberof stash/api/util/navbuilder
     * @returns {stash/api/util/navbuilder.RestBuilder}
     */
    function rest(resourcePath) {
        resourcePath = resourcePath ? resourcePath : 'api';
        return new PathAndQuery(['rest', resourcePath, 'latest']).makeBuilder(
        /**
         * @lends stash/api/util/navbuilder.RestBuilder.prototype
         */
        {
            /**
             * @method
             * @param {string} key - The key of the project to form URLs for.
             * @returns {stash/api/util/navbuilder.RestProjectBuilder}
             */
            project: restProj,
            /**
             * @method
             * @returns {stash/api/util/navbuilder.RestProjectBuilder}
             */
            currentProject : restCurrentProject,
            /**
             * @method
             * @returns {stash/api/util/navbuilder.RestRepositoryBuilder}
             */
            currentRepo: restCurrentRepo,
            /**
             * @method
             * @returns {stash/api/util/navbuilder.RestPullRequestBuilder}
             */
            currentPullRequest: restCurrentPullRequest,
            /**
             * @returns {stash/api/util/navbuilder.RestMarkupBuilder}
             */
            markup: function restMarkup() {
                /**
                 * REST markup URL {@linkcode stash/api/util/navbuilder.Builder}.
                 *
                 * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
                 *
                 * @class RestMarkupBuilder
                 * @memberof stash/api/util/navbuilder
                 */
                return this._path().pushComponents('markup').makeBuilder(
                /**
                 * @lends stash/api/util/navbuilder.RestMarkupBuilder.prototype
                 */
                {
                    /**
                     * @returns {stash/api/util/navbuilder.Builder}
                     */
                    preview: function restMarkupPreview() {
                        return this._path().pushComponents('preview').makeBuilder();
                    }
                });
            },
            /**
             * @returns {stash/api/util/navbuilder.RestProfileBuilder}
             */
            profile: function restProfile() {
                /**
                 * REST profile URL {@linkcode stash/api/util/navbuilder.Builder}.
                 *
                 * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
                 *
                 * @class RestProfileBuilder
                 * @memberof stash/api/util/navbuilder
                 */
                return this._path().pushComponents('profile').makeBuilder(
                /**
                 * @lends stash/api/util/navbuilder.RestProfileBuilder.prototype
                 */
                {
                    /**
                     * REST recently viewed URL {@linkcode stash/api/util/navbuilder.Builder}.
                     *
                     * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
                     *
                     * @class RestRecentlyViewedBuilder
                     * @memberof stash/api/util/navbuilder
                     */
                    /**
                     * @returns {stash/api/util/navbuilder.RestRecentlyViewedBuilder}
                     */
                    recent: function restProfileRecent() {
                        return this._path().pushComponents('recent').makeBuilder(
                        /**
                         * @lends stash/api/util/navbuilder.RestRecentlyViewedBuilder.prototype
                         */
                        {
                            /**
                             * @returns {stash/api/util/navbuilder.Builder}
                             */
                            repos: function restProfileRecentRepos() {
                                return this._path().pushComponents('repos').makeBuilder();
                            }
                        });
                    }
                });
            },
            /**
             * @param {string} [userSlug] - If provided, a RestUserBuilder will be returned. Otherwise, a regular builder is returned.
             * @returns {stash/api/util/navbuilder.Builder|stash/api/util/navbuilder.RestUserBuilder}
             */
            users: function restUsers(userSlug) {
                var builder = this._path().pushComponents('users');
                if (userSlug) {
                    /**
                     * {@linkcode stash/api/util/navbuilder.Builder} for REST user URLs.
                     *
                     * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
                     *
                     * @class RestUserBuilder
                     * @memberof stash/api/util/navbuilder
                     */
                    return builder.pushComponents(userSlug).makeBuilder(
                    /**
                     * @lends stash/api/util/navbuilder.RestUserBuilder.prototype
                     */
                    {
                        /**
                         * @method
                         * @param {number} [size] - A pixel value for the height and width of the avatar. Please use only pixel sizes referenced by the ADG at http://developer.atlassian.com/design.
                         * @returns {stash/api/util/navbuilder.Builder}
                         */
                        avatar: userAvatar
                    });
                }
                return builder.makeBuilder();
            },
            /**
             * @returns {stash/api/util/navbuilder.Builder}
             */
            groups: function restGroups() {
                return this._path().pushComponents('groups').makeBuilder();
            },
            /**
             * @method
             * @returns {stash/api/util/navbuilder.RestHookPluginsBuilder}
             */
            hooks: restHookPlugins,
            /**
             * @method
             * @returns {stash/api/util/navbuilder.Builder}
             */
            allRepos: allRepos,
            /**
             * @returns {stash/api/util/navbuilder.RestAdminBuilder}
             */
            admin: function restAdmin() {
                /**
                 * Admin REST URL {@linkcode stash/api/util/navbuilder.Builder}.
                 *
                 * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
                 *
                 * @class RestAdminBuilder
                 * @memberof stash/api/util/navbuilder
                 */
                return this._path().pushComponents('admin').makeBuilder(
                /**
                 * @lends stash/api/util/navbuilder.RestAdminBuilder.prototype
                 */
                {
                    /**
                     * @returns {stash/api/util/navbuilder.Builder}
                     */
                    users: function restAdminUsers() {
                        return this._path().pushComponents('users').makeBuilder();
                    }
                });
            }
        });
    }

    /**
     * Add-on-related {@linkcode stash/api/util/navbuilder.Builder}.
     *
     * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
     *
     * @class AddonBuilder
     * @memberof stash/api/util/navbuilder
     */

    /**
     * @memberof stash/api/util/navbuilder
     * @returns {stash/api/util/navbuilder.AddonBuilder}
     */
    function addons() {
        return new PathAndQuery(['plugins', 'servlet', 'upm']).makeBuilder(
        /**
         * @lends stash/api/util/navbuilder.AddonBuilder.prototype
         */
        {
            /**
             * Add-on-requests-related {@linkcode stash/api/util/navbuilder.Builder}.
             *
             * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
             *
             * @class AddonRequestsBuilder
             * @memberof stash/api/util/navbuilder
             */

            /**
             * @returns {stash/api/util/navbuilder.AddonRequestsBuilder}
             */
            requests: function addonsRequests() {
                return this._path().pushComponents('requests', 'popular').makeBuilder(
                /**
                 * @lends stash/api/util/navbuilder.AddonRequestsBuilder.prototype
                 */
                {
                    /**
                     * @param {string} category - The category of requests to filter by.
                     * @returns {stash/api/util/navbuilder.Builder}
                     */
                    category: function(category) {
                        return this._path().addParams({category: category}).makeBuilder();
                    }
                });
            }
        });
    }


    /**
     * {@linkcode stash/api/util/navbuilder.Builder} for creating plugin servlet URLs.
     *
     * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
     *
     * @class PluginServletsBuilder
     * @memberof stash/api/util/navbuilder
     */

    /**
     * @memberof stash/api/util/navbuilder
     * @returns {stash/api/util/navbuilder.PluginServletsBuilder}
     */
    function pluginServlets() {
        return new PathAndQuery(['plugins', 'servlet']).makeBuilder(
        /**
         * @lends stash/api/util/navbuilder.PluginServletsBuilder.prototype
         */
        {
            /**
             * @param {...string} component - A path component under the servlet.
             * @returns {stash/api/util/navbuilder.Builder}
             */
            path: function servletPath() {
                var path = this._path();
                return path.pushComponents.apply(path, componentsFromArguments(arguments)).makeBuilder();
            }
        });
    }

    /**
     * permissions-related {@linkcode stash/api/util/navbuilder.Builder}.
     *
     * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
     *
     * @class PermissionsBuilder
     * @memberof stash/api/util/navbuilder
     */

    /**
     * Documented at parent builders
     * @private
     */
    function permissions() {
        return this._path().pushComponents('permissions').makeBuilder(
        /**
         * @lends stash/api/util/navbuilder.PermissionsBuilder.prototype
         */
        {
            /**
             * @method
             * @returns {stash/api/util/navbuilder.PermissionBuilder}
             */
            permission: permission,
            /**
             * @method
             * @returns {stash/api/util/navbuilder.AdminUsersBuilder}
             */
            users: adminUsers,
            /**
             * @method
             * @returns {stash/api/util/navbuilder.GroupsBuilder}
             */
            groups: groups
        });
    }

    /**
     * permission-related {@linkcode stash/api/util/navbuilder.Builder}.
     *
     * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
     *
     * @class PermissionBuilder
     * @memberof stash/api/util/navbuilder
     */

    /**
     * Documented at parent builders
     * @private
     */
    function permission(name) {
        return this._path().pushComponents(name).makeBuilder(
        /**
         * @lends stash/api/util/navbuilder.PermissionBuilder.prototype
         */
        {
            /**
             * @returns stash/api/util/navbuilder.Builder
             */
            users: function usersPerm() {
                return this._path().pushComponents('users').makeBuilder();
            },
            /**
             * @returns stash/api/util/navbuilder.Builder
             */
            groups: function groupsPerm() {
                return this._path().pushComponents('groups').makeBuilder();
            },
            /**
             * @returns stash/api/util/navbuilder.Builder
             */
            all: function allPerm() {
                return this._path().pushComponents('all').makeBuilder();
            }
        });
    }

    /**
     * Admin user-related {@linkcode stash/api/util/navbuilder.Builder}.
     *
     * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
     *
     * @class AdminUsersBuilder
     * @memberof stash/api/util/navbuilder
     */

    /**
     * Documented at parent builders
     * @private
     */
    function adminUsers() {
        return this._path().pushComponents('users').makeBuilder(
        /**
         * @lends stash/api/util/navbuilder.AdminUsersBuilder.prototype
         */
        {
            /**
             * @method
             * @returns stash/api/util/navbuilder.Builder
             */
            create: createEntity,
            /**
             * @method
             * @param {string} name - The username of the user to delete.
             * @returns {stash/api/util/navbuilder.Builder}
             */
            deleteUser: deleteEntity,
            /**
             * @param {string} name - The username of the user to read/write captcha info for.
             * @returns {stash/api/util/navbuilder.Builder}
             */
            captcha: function adminCaptcha(name) {
                return this._path().pushComponents('captcha').addParams({name: name}).makeBuilder();
            },
            /**
             * @method
             * @param {string} name - The username of the user to view.
             * @returns {stash/api/util/navbuilder.Builder}
             */
            view: viewEntity,
            /**
             * @method
             * @param {string} filter - A search string to filter by.
             * @returns {stash/api/util/navbuilder.Builder}
             */
            filter: filterEntity,
            /**
             * @private
             * @param {string} deletedUser - The user who was just deleted.
             * @returns {stash/api/util/navbuilder.Builder}
             */
            deleteSuccess: deleteSuccess,
            /**
             * @method
             * @returns {stash/api/util/navbuilder.PermissionsBuilder}
             */
            permissions: permissions,
            /**
             * @method
             * @returns {stash/api/util/navbuilder.Builder}
             */
            none: nonePerm
        });
    }


    /**
     * Group-related {@linkcode stash/api/util/navbuilder.Builder}.
     *
     * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
     *
     * @class GroupsBuilder
     * @memberof stash/api/util/navbuilder
     */

    /**
     * @private
     */
    function groups() {
        return this._path().pushComponents('groups').makeBuilder(
        /**
         * @lends stash/api/util/navbuilder.GroupsBuilder.prototype
         */
        {
            /**
             * @method
             * @returns stash/api/util/navbuilder.Builder
             */
             create: createEntity,
            /**
             * @method
             * @param {string} name - The name of the group to delete.
             * @returns {stash/api/util/navbuilder.Builder}
             */
            deleteGroup: deleteEntity,
            /**
             * @method
             * @param {string} name - The name of the group to view.
             * @returns {stash/api/util/navbuilder.Builder}
             */
            view: viewEntity,
            /**
             * @method
             * @param {string} filter - A search string to filter by.
             * @returns {stash/api/util/navbuilder.Builder}
             */
            filter: filterEntity,
            /**
             * @private
             * @param {string} deletedUser - The user who was just deleted.
             * @returns {stash/api/util/navbuilder.Builder}
             */
            deleteSuccess: deleteSuccess,
            /**
             * @method
             * @returns {stash/api/util/navbuilder.PermissionsBuilder}
             */
            permissions: permissions,
            /**
             * @method
             * @returns {stash/api/util/navbuilder.Builder}
             */
            none: nonePerm
        });
    }

    //--- Methods further down the chain ---

    /**
     * Documented at parent builders
     * @private
     */
    function nonePerm() {
        return this._path().pushComponents('none').makeBuilder();
    }

    /**
     * Documented at parent builders
     * @private
     */
    function allRepos() {
        return maybeResolveAsUserPath(this._path()).pushComponents('repos').makeBuilder();
    }

    /**
     * User-related {@linkcode stash/api/util/navbuilder.Builder}.
     *
     * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
     *
     * @class UserBuilder
     * @memberof stash/api/util/navbuilder
     */

    /**
     * @memberof stash/api/util/navbuilder
     * @param {string} userSlug - The URL-safe slug for a user.
     * @returns {stash/api/util/navbuilder.UserBuilder}
     */
    function user(userSlug) {
        return new PathAndQuery(['users', userSlug]).makeBuilder(
        /**
         * @lends stash/api/util/navbuilder.UserBuilder.prototype
         */
        {
            /**
             * @method
             * @param {number} [size] - A pixel value for the height and width of the avatar. Please use only pixel sizes referenced by the ADG at http://developer.atlassian.com/design.
             * @returns {stash/api/util/navbuilder.Builder}
             */
            avatar: userAvatar
        });
    }



    /**
     * Documented at parent builders
     * @private
     */
    function createEntity() {
        return this._path().addParams({create: ''}).makeBuilder();
    }

    /**
     * Documented at parent builders
     * @private
     */
    function deleteEntity(name) { // delete is a reserved keyword
        return this._path().addParams({name: name}).makeBuilder();
    }

    /**
     * Documented at parent builds
     * @private
     */
    function viewEntity(name) {
        return this._path().pushComponents('view').addParams({name: name}).makeBuilder();
    }

    /**
     * Documented at parent builds
     * @private
     */
    function filterEntity(filterValue) {
        return this._path().addParams({filter: filterValue}).makeBuilder();
    }

    /**
     * Documented at parent builds
     * @private
     */
    function deleteSuccess(name) {
        return this._path().addParams({deleted: name}).makeBuilder();
    }

    /**
     * Repository-related {@linkcode stash/api/util/navbuilder.Builder}.
     *
     * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
     *
     * @class RepositoryBuilder
     * @memberof stash/api/util/navbuilder
     */

    /**
     * @param {string} slug - The slug of the repository to return a builder for.
     * @returns {stash/api/util/navbuilder.RepositoryBuilder}
     */
    function repo(repoOrSlug) {
        return maybeResolveAsUserPath(this._path()).pushComponents('repos', getRepoSlug(repoOrSlug)).makeBuilder(
        /**
         * @lends stash/api/util/navbuilder.RepositoryBuilder.prototype
         */
        {
            /**
             * @returns {stash/api/util/navbuilder.RepoBrowseBuilder}
             */
            browse: function repoBrowse() {
                return this._path().pushComponents('browse').makeBuilder(RepoBrowseBuilderMethods);
            },
            /**
             * @method
             * @param {string|JSON.FileChangeJSON} pathOrFileChange - A string to use as the file path to diff, or a FileChangeJSON to specify the revisions and paths together.
             * @returns {stash/api/util/navbuilder.RevisionSpecifyingBuilder}
             */
            diff : repoDiff,
            /**
             * @returns {stash/api/util/navbuilder.CommitsBuilder}
             */
            commits: function repoCommits() {
                /**
                 * Commits list-related {@linkcode stash/api/util/navbuilder.Builder}.
                 *
                 * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
                 *
                 * @class CommitsBuilder
                 * @memberof stash/api/util/navbuilder
                 */
                return this._path().pushComponents('commits').makeBuilder(
                /**
                 * @lends stash/api/util/navbuilder.CommitsBuilder.prototype
                 */
                {
                    /**
                     * @param {string} [until] - The ID of the ref to use as the tip of the commit list. Omit to use the default branch's HEAD.
                     * @returns {stash/api/util/navbuilder.Builder}
                     */
                    until: function repoCommitsUntil(until) {
                        var builder = this._path();
                        if (until && !until.isDefault) {
                            if (typeof until !== 'string') {
                                until = until.displayId || until;
                            }
                            builder = builder.addParams({ until: until });
                        }

                        return builder.makeBuilder();
                    }
                });
            },
            /**
             * @param {string} [baseRef] - The ID of the ref to use as the base branch for comparisons.
             * @returns {stash/api/util/navbuilder.Builder}
             */
            branches: function repoBranches(baseRef) {
                var builder = this._path().pushComponents('branches');
                if (baseRef && !baseRef.isDefault) {
                    if (typeof baseRef !== 'string') {
                        baseRef = baseRef.displayId || baseRef.id || baseRef;
                    }
                    builder = builder.addParams({ base: baseRef });
                }
                return builder.makeBuilder();
            },
            /**
             * @method
             * @param {string} commitId - The ID of the commit to form URLs for.
             * @returns {stash/api/util/navbuilder.CommitBuilder}
             */
            changeset: repoCommit,
            /**
             * @method
             * @param {string} commitId - The ID of the commit to form URLs for.
             * @returns {stash/api/util/navbuilder.CommitBuilder}
             */
            commit: repoCommit,
            /**
             * {@linkcode stash/api/util/navbuilder.Builder} for branch comparison URLs.
             *
             * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
             *
             * @class BranchCompareBuilder
             * @extends stash/api/util/navbuilder.SourceTargetBuilder
             * @memberof stash/api/util/navbuilder
             */
            /**
             * @returns {stash/api/util/navbuilder.BranchCompareBuilder}
             */
            compare: function repoCompare() {
                function comparePath(path) {
                    return function() {
                        //noinspection JSPotentiallyInvalidUsageOfThis
                        return this._path().pushComponents(path).makeBuilder(secondBranchParamBuilders);
                    };
                }
                return this._path().pushComponents('compare').makeBuilder(_.extend(
                /**
                 * @lends stash/api/util/navbuilder.BranchCompareBuilder.prototype
                 */
                {
                    /**
                     * @method
                     * @returns {stash/api/util/navbuilder.SourceTargetBuilder}
                     */
                    commits : comparePath('commits'),
                    /**
                     * @method
                     * @returns {stash/api/util/navbuilder.SourceTargetBuilder}
                     */
                    diff: comparePath('diff')
                }, compareDefaultBranchParamBuilders));
            },
            /**
             * @returns {stash/api/util/navbuilder.Builder}
             */
            settings: function repoSettings() {
                return this._path().pushComponents('settings').makeBuilder();
            },
            /**
             * @method
             * @returns {stash/api/util/navbuilder.PermissionsBuilder}
             */
            permissions: permissions,
            /**
             * @method
             * @returns {stash/api/util/navbuilder.Builder}
             */
            hooks: repoHooks,
            /**
             * @param {string} scm - The kind of SCM (e.g. git) for this repo.
             * @returns {stash/api/util/navbuilder.Builder}
             */
            clone: function repoClone(scm) {
                var path = this._path(),
                    projectKey = path.components[1].toLowerCase(),
                    repoSlug = path.components[3].toLowerCase();

                if (path.components[0] === 'users') {
                    projectKey = "~" + projectKey;
                }

                return new PathAndQuery(['scm', projectKey, repoSlug + '.' + scm], path.params).makeBuilder();
            },
            /**
             * @returns {stash/api/util/navbuilder.Builder}
             */
            fork: function repoFork() {
                return this._path().addParams('fork').makeBuilder();
            },
            /**
             * @returns {stash/api/util/navbuilder.Builder}
             */
            allPullRequests: function allPullRequests() {
                return this._path().pushComponents('pull-requests').makeBuilder();
            },
            /**
             * @returns {stash/api/util/navbuilder.SourceTargetBuilder}
             */
            createPullRequest: function createPullRequest() {
                return this._path().pushComponents('pull-requests').addParams('create').makeBuilder(secondBranchParamBuilders);
            },
            /**
             * @method
             * @param {number} pullRequestId - The ID of a pull request to build URLs for.
             * @returns {stash/api/util/navbuilder.PullRequestBuilder}
             */
            pullRequest: pullRequest,
            /**
             * @returns {stash/api/util/navbuilder.Builder}
             */
            attachments: function repoAttachments() {
                return this._path().pushComponents('attachments').makeBuilder();
            },
            /**
             * @returns {stash/api/util/navbuilder.Builder}
             */
            sizes : function repoSizes() {
                return this._path().pushComponents('sizes').makeBuilder();
            },
            /**
             * Documented under Builder
             * @private
             */
            build: function () {
                return this._path().pushComponents('browse').toString(); //the stem /projects/PROJ/repos is different to the path needed if build() is called
            }
        });
    }


    /**
     * Returns the builder for the current page's repository, if there is one.
     * @memberof stash/api/util/navbuilder
     * @returns {stash/api/util/navbuilder.RepositoryBuilder}
     */
    function currentRepo() {
        return currentProject().repo(pageState.getRepository());
    }


    /**
     * {@linkcode stash/api/util/navbuilder.Builder} to select which commits are involved and whether to retrieve the
     * "raw" version when browsing files within Stash.
     *
     * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
     *
     * @class RevisionSpecifyingBuilder
     * @memberof stash/api/util/navbuilder
     */

    var RevisionRangeSpecifyingBuilderMethods =
        /**
         * @lends stash/api/util/navbuilder.RevisionSpecifyingBuilder.prototype
         */
         {
            /**
             * Set the "at" revision for browsing. This revision describes the branch head whose history is being viewed.
             * This is _not_ the actual revision at which to view the file (but it is used as fallback for that purpose).
             * The main purpose of this parameter is to determine which branch to use as "current" in the page layout.
             *
             * @param {string} refId - The ID of a ref or commit in the SCM whose history to browse.
             * @returns {stash/api/util/navbuilder.RevisionSpecifyingBuilder}
             */
            at : function repoBrowsePathAt(refId) {
                var builder = this._path();
                if (refId) {
                    if (typeof refId !== 'string') {
                        refId = refId.displayId || refId;
                    }
                    builder = builder.addParams({ at: refId });
                }
                return builder.makeBuilder(RevisionRangeSpecifyingBuilderMethods);
            },
            /**
             * Set the "until" commit for browsing. This commit describes the actual revision at which you want to view file content.
             * @param {string} commitId - The ID of a commit in the SCM at which to browse.
             * @returns {stash/api/util/navbuilder.RevisionSpecifyingBuilder}
             */
            until : function repoBrowsePathUntil(commitId) {
                return this._path().addParams({until: commitId}).makeBuilder(RevisionRangeSpecifyingBuilderMethods);
            },
            /**
             * Describes that you want to view the "raw"/downloadable version of the file, not the HTML version
             * @returns {stash/api/util/navbuilder.RevisionSpecifyingBuilder}
             */
            raw : function repoBrowsePathRaw() {
                return this._path().addParams({raw: ''}).makeBuilder(RevisionRangeSpecifyingBuilderMethods);
            }
        };

    /**
     * {@linkcode stash/api/util/navbuilder.Builder} to select where to browse files.
     *
     * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
     *
     * @class RepoBrowseBuilder
     * @memberof stash/api/util/navbuilder
     */

    var RepoBrowseBuilderMethods =
        /**
         * @lends stash/api/util/navbuilder.RepoBrowseBuilder.prototype
         */
        {
            /**
             * @param {...string} components - path components for the file/directory at which to browse.
             * @returns {stash/api/util/navbuilder.RevisionSpecifyingBuilder}
             */
            path : function repoBrowsePath() {
                var path = this._path();
                return path.pushComponents.apply(path, componentsFromArguments(arguments)).makeBuilder(RevisionRangeSpecifyingBuilderMethods);
            },
            /**
             * Set the "at" revision for browsing. This revision describes the branch head whose history is being viewed.
             * This is _not_ the actual revision at which to view the file (but it is used as fallback for that purpose).
             * The main purpose of this parameter is to determine which branch to use as "current" in the page layout.
             *
             * @method
             * @param {string} refId - The ID of a ref or commit in the SCM whose history to browse.
             * @returns {stash/api/util/navbuilder.RevisionSpecifyingBuilder}
             */
            at : RevisionRangeSpecifyingBuilderMethods.at
        };



    /**
     * Documented at parent builders
     * @private
     */
    function repoDiff(fileChangeOrPath) {
        var builder = this._path(),
            path;

        // Duck-type as adding FileChange as a dependency on navbuilder causes too much recursion in dependency stack
        var isFileChange = (
                fileChangeOrPath.getCommitRange &&
                fileChangeOrPath.getPath &&
                fileChangeOrPath.getSrcPath
            );
        var isFileChangeJSON = (
                fileChangeOrPath.commitRange &&
                fileChangeOrPath.path &&
                fileChangeOrPath.srcPath
            );
        var fileChangeJSON;
        if (isFileChange || isFileChangeJSON) {
            fileChangeJSON = fileChangeOrPath.toJSON ? fileChangeOrPath.toJSON() : fileChangeOrPath;
        }

        if (fileChangeJSON) {
            var commitRangeJSON = fileChangeJSON.commitRange;
            path = fileChangeJSON.path;
            if (commitRangeJSON.pullRequest) {
                builder = builder.pushComponents('pull-requests', commitRangeJSON.pullRequest.id);
            } else {
                // Use of extend will root out undefined props
                builder = builder.addParams($.extend({}, {
                    until: commitRangeJSON.untilRevision && commitRangeJSON.untilRevision.id || undefined,
                    since: commitRangeJSON.sinceRevision && commitRangeJSON.sinceRevision.id || undefined
                }));
            }
        } else {
            path = fileChangeOrPath;
        }

        builder = builder.pushComponents('diff'); // need to do this separately otherwise we don't have the correct context for the next apply invocation.
        builder = builder.pushComponents.apply(builder, path && componentsFromArguments([path]));
        builder = builder.addParams($.extend({}, { // extend removes undefined properties
            srcPath: fileChangeJSON && fileChangeJSON.srcPath || undefined
        }));

        return builder.makeBuilder(RevisionRangeSpecifyingBuilderMethods);
    }


    /**
     * {@linkcode stash/api/util/navbuilder.Builder} for commit-related URLs.
     *
     * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
     *
     * @class CommitBuilder
     * @memberof stash/api/util/navbuilder
     */

    /**
     * Documented at parent builders
     * @private
     */
    function repoCommit(commitId) {
        // commitId must be SHA1 hash
        return this._path().pushComponents('commits', commitId).makeBuilder(
        /**
         * @lends stash/api/util/navbuilder.CommitBuilder.prototype
         */
        {
            /**
             * @param {number} commentId - The commit comment to form URLs for.
             * @returns {stash/api/util/navbuilder.Builder}
             */
            comment: function repoCommitComment(commentId) {
                return this._path().addParams({
                    commentId: commentId
                }).makeBuilder();
            }
        });
    }


    /**
     * Documented at parent builders
     * @private
     */
    function repoHooks() {
        return this._path().pushComponents('settings', 'hooks').makeBuilder();
    }

    //--- Pull Request Methods ---


    /**
     * {@linkcode stash/api/util/navbuilder.Builder} for URLs that have a source and target branch.
     *
     * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
     *
     * @class SourceTargetBuilder
     * @memberof stash/api/util/navbuilder
     */

    var secondBranchParamBuilders =
    /**
     * @lends stash/api/util/navbuilder.SourceTargetBuilder.prototype
     */
    {
        /**
         * The builder that will be returned from branch setter methods
         * @private
         */
        _builder: null,
        /**
         * @param {string} sourceBranchRefId - The refId for the source branch.
         * @returns {stash/api/util/navbuilder.SourceTargetBuilder}
         */
        sourceBranch: function sourceBranch(sourceBranchRefId) {
            return this._path().addParams({sourceBranch: sourceBranchRefId}).makeBuilder(this._builder);
        },
        /**
         * @param {string} targetBranchRefId - The refId for the target branch.
         * @returns {stash/api/util/navbuilder.SourceTargetBuilder}
         */
        targetBranch: function targetBranch(targetBranchRefId) {
            return this._path().addParams({targetBranch: targetBranchRefId}).makeBuilder(this._builder);
        },
        /**
         * @param {string} id - The ID (not slug) for the target repository (containing the target branch).
         * @returns {stash/api/util/navbuilder.SourceTargetBuilder}
         */
        targetRepo: function targetRepo(id) {
            return this._path().addParams({targetRepoId: id}).makeBuilder(this._builder);
        }
    };
    // set the builder
    secondBranchParamBuilders._builder = secondBranchParamBuilders;

    var compareDefaultBranchParamBuilders = _.extend({
        /**
         * Documented under Builder
         * @private
         */
        build: function () {
            return this._path().pushComponents('commits').toString(); //the stem /projects/PROJ/repos is different to the path needed if build() is called
        }
    }, secondBranchParamBuilders);
    // set the builder
    compareDefaultBranchParamBuilders._builder = compareDefaultBranchParamBuilders;


    /**
     * Pull request-related {@linkcode stash/api/util/navbuilder.Builder}.
     *
     * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
     *
     * @class PullRequestBuilder
     * @memberof stash/api/util/navbuilder
     */

    /**
     * Documented at parent builder
     * @private
     */
    function pullRequest(prOrId) {
        return this._path().pushComponents('pull-requests', getPullRequestId(prOrId)).makeBuilder(
        /**
         * @lends stash/api/util/navbuilder.PullRequestBuilder.prototype
         */
        {
            /**
             * @returns {stash/api/util/navbuilder.Builder}
             */
            unwatch: function pullRequestUnwatch() {
                return this._path().pushComponents('unwatch').makeBuilder();
            },
            /**
             * @param {string} [commitId] - The ID of a commit in the pull request.
             * @returns {stash/api/util/navbuilder.Builder}
             */
            changeset: function pullRequestChangeset(commitId) {
                //Unlike repository changesets, ref names like "master" are not supported here. As a result, there is
                //no need to do all the path gyrations repoChangeset does
                return this._path().pushComponents('commits', commitId).makeBuilder();
            },
            /**
             * @returns {stash/api/util/navbuilder.PullRequestOverviewBuilder}
             */
            overview: function pullRequestOverview() {
                /**
                 * Pull request overview URL {@linkcode stash/api/util/navbuilder.Builder}.
                 *
                 * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
                 *
                 * @class PullRequestOverviewBuilder
                 * @memberof stash/api/util/navbuilder
                 */
                return this._path().pushComponents('overview').makeBuilder(
                /**
                 * @lends stash/api/util/navbuilder.PullRequestOverviewBuilder.prototype
                 */
                {
                    /**
                     * @param {number} commentId - The ID of a comment to view within the overview activity.
                     * @returns {stash/api/util/navbuilder.Builder}
                     */
                    comment: function pullRequestComment(commentId){
                        return this._path().addParams({commentId: commentId}).makeBuilder();
                    }
                });
            },
            /**
             * @returns {stash/api/util/navbuilder.PullRequestDiffBuilder}
             */
            diff: function pullRequestDiff() {
                /**
                 * Pull request diff-related {@linkcode stash/api/util/navbuilder.Builder}.
                 *
                 * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
                 *
                 * @class PullRequestDiffBuilder
                 * @memberof stash/api/util/navbuilder
                 */
                return this._path().pushComponents('diff').makeBuilder(
                /**
                 * @lends stash/api/util/navbuilder.PullRequestDiffBuilder.prototype
                 */
                {
                    /**
                     * @param {string} diffChangePath - The filepath to view the change of, within the PR.
                     * @returns {stash/api/util/navbuilder.Builder}
                     */
                    change: function (diffChangePath) {
                        return this._path().withFragment(diffChangePath).makeBuilder();
                    }
                });
            },
            /**
             * @returns {stash/api/util/navbuilder.Builder}
             */
            commits: function pullRequestCommits(){
                return this._path().pushComponents('commits').makeBuilder();
            },
            /**
             * Documented on Builder
             * @private
             */
            build: function () {
                return this._path().pushComponents('overview').toString(); //Default to overview view
            }
        });
    }


    /**
     * Returns the builder for the current page's pull request, if there is one.
     * @memberof stash/api/util/navbuilder
     * @returns {stash/api/util/navbuilder.PullRequestBuilder}
     */
    function currentPullRequest() {
        return currentRepo.call(this).pullRequest(getCurrentPullRequest());
    }


    /**
     * REST project-related {@linkcode stash/api/util/navbuilder.Builder}.
     *
     * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
     *
     * @class RestProjectBuilder
     * @memberof stash/api/util/navbuilder
     */

    /**
     * Documented at parent builder
     * @private
     */
    function restProj(projectOrKey) {
        var key = getProjectKey(projectOrKey);
        return this._path().pushComponents('projects', key).makeBuilder(
        /**
         * @lends stash/api/util/navbuilder.RestProjectBuilder.prototype
         */
        {
            /**
             * @returns {stash/api/util/navbuilder.Builder}
             */
            allRepos: function restAllRepos() {
                return this._path().pushComponents('repos').makeBuilder();
            },
            /**
             * @method
             * @param {string} slug - The slug of the repo to form URLs for.
             * @returns {stash/api/util/navbuilder.RestRepositoryBuilder}
             */
            repo: restRepo,
            /**
             * @method
             * @returns {stash/api/util/navbuilder.RestProjectPermissionsBuilder}
             */
            permissions: restProjPermissions
        });
    }

    /**
     * Documented at parent builder
     * @private
     */
    function restCurrentProject() {
        return restProj.call(this, getCurrentProject());
    }

    /**
     * Documented at parent builder
     * @private
     */
    function restCurrentRepo() {
        return restCurrentProject.call(this).repo(getCurrentRepository());
    }


    /**
     * REST repository hook-related {@linkcode stash/api/util/navbuilder.Builder}.
     *
     * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
     *
     * @class RestHookBuilder
     * @memberof stash/api/util/navbuilder
     */

    /**
     * @param {string} hookKey - The key of the hook you want to build URLs for.
     * @returns {stash/api/util/navbuilder.RestHookBuilder}
     */
    function restHook(hookOrKey) {
        var hookKey = getHookKey(hookOrKey);
        return this._path().pushComponents('settings').pushComponents('hooks', hookKey).makeBuilder(
        /**
         * @lends stash/api/util/navbuilder.RestHookBuilder.prototype
         */
        {
            /**
             * @returns {stash/api/util/navbuilder.Builder}
             */
            enabled: function hookEnabled() {
                return this._path().pushComponents('enabled').makeBuilder();
            },
            /**
             * @returns {stash/api/util/navbuilder.Builder}
             */
            settings: function hookSettings() {
                return this._path().pushComponents('settings').makeBuilder();
            }
        });
    }


    /**
     * REST repository-related {@linkcode stash/api/util/navbuilder.Builder}.
     *
     * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
     *
     * @class RestRepositoryBuilder
     * @memberof stash/api/util/navbuilder
     */

    /**
     * Documented at parent builders
     * @private
     */
    function restRepo(repoOrSlug) {
        var slug = getRepoSlug(repoOrSlug);
        return this._path().pushComponents('repos', slug).makeBuilder(
        /**
         * @lends stash/api/util/navbuilder.RestRepositoryBuilder.prototype
         */
        {
            /**
             * @returns {stash/api/util/navbuilder.Builder}
             */
            tags: function restRepoTags() {
                return this._path().pushComponents('tags').makeBuilder();
            },
            /**
             * @returns {stash/api/util/navbuilder.Builder}
             */
            branches: function restRepoBranches() {
                return this._path().pushComponents('branches').makeBuilder();
            },
            /**
             * @returns {stash/api/util/navbuilder.Builder}
             */
            commits : function restRepoAllCommits() {
                return this._path().pushComponents('commits').makeBuilder();
            },
            /**
             * @method
             * @param {string|JSON.CommitRangeJSON} commitIdOrCommitRange
             * @returns {stash/api/util/navbuilder.RestCommitBuilder}
             */
            commit: restRepoCommit,
            /**
             * @returns {stash/api/util/navbuilder.RestRepoCompareBuilder}
             */
            compare : function restRepoCompare() {
                /**
                 * REST ref comparison-related {@linkcode stash/api/util/navbuilder.Builder}.
                 *
                 * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
                 *
                 * @class RestRepoCompareBuilder
                 * @memberof stash/api/util/navbuilder
                 */

                var compareParam = function(name, value) {
                    var params = {};
                    params[name] = value;
                    return this._path().addParams(params).makeBuilder(paramsBuilder);
                };
                var comparePath = function(path) {
                    return function() {
                        return this._path().pushComponents(path).makeBuilder(paramsBuilder);
                    };
                };

                /**
                 * {@linkcode stash/api/util/navbuilder.Builder} for REST ref comparison-related params.
                 *
                 * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
                 *
                 * @class RestRepoCompareParamBuilder
                 * @memberof stash/api/util/navbuilder
                 */

                var paramsBuilder =
                /**
                 * @lends stash/api/util/navbuilder.RestRepoCompareParamBuilder.prototype
                 */
                {
                    /**
                     * @method
                     * @param {string} refId - The from/until ref's ID for comparison.
                     * @returns {stash/api/util/navbuilder.RestRepoCompareParamBuilder}
                     */
                    from: _.partial(compareParam, 'from'),
                    /**
                     * @method
                     * @param {string} refId - The to/since ref's ID for comparison.
                     * @returns {stash/api/util/navbuilder.RestRepoCompareParamBuilder}
                     */
                    to: _.partial(compareParam, 'to'),
                    /**
                     * @method
                     * @param {string} repoId - The ID of the repository containing the from/until ref.
                     * @returns {stash/api/util/navbuilder.RestRepoCompareParamBuilder}
                     */
                    fromRepo:  _.partial(compareParam, 'fromRepo')
                };
                return this._path().pushComponents('compare').makeBuilder(
                /**
                 * @lends stash/api/util/navbuilder.RestRepoCompareBuilder.prototype
                 */
                {
                    /**
                     * @method
                     * @returns {stash/api/util/navbuilder.RestRepoCompareParamBuilder}
                     */
                    changes : comparePath('changes'),
                    /**
                     * @method
                     * @returns {stash/api/util/navbuilder.RestRepoCompareParamBuilder}
                     */
                    commits : comparePath('commits'),
                    /**
                     * @method
                     * @param {JSON.FileChangeJSON} fileChange - The fileChange object describing the files to be compared.
                     * @returns {stash/api/util/navbuilder.RestRepoCompareParamBuilder}
                     */
                    diff : function(fileChange) {
                        return restDiffInternal.call(this, fileChange, paramsBuilder);
                    }
                });
            },
            /**
             * @method
             * @param {string|JSON.CommitRangeJSON} commitIdOrCommitRange
             * @returns {stash/api/util/navbuilder.RestCommitBuilder}
             */
            changeset: restRepoCommit,
            /**
             * @param {JSON.CommitRangeJSON} commitRange - describe the range of commits to get changes between.
             * @returns {stash/api/util/navbuilder.RestCommitPathBuilder|stash/api/util/navbuilder.Builder}
             */
            changes: function routeChangesRequest (commitRange) {
                commitRange = commitRange.toJSON ? commitRange.toJSON() : commitRange;
                if (commitRange.pullRequest) {
                    return this.pullRequest(commitRange.pullRequest).changes();
                } else if (commitRange.untilRevision) {
                    return this.changeset(commitRange).changes();
                } else {
                    throw new Error("A valid commit-range is required to retrieve changes");
                }
            },
            /**
             * @returns {stash/api/util/navbuilder.RepoBrowseBuilder}
             */
            browse: function restRepoBrowse() {
                return this._path().pushComponents('browse').makeBuilder(RepoBrowseBuilderMethods);
            },
            /**
             * @method
             * @returns {stash/api/util/navbuilder.RestRepoFilesListBuilder}
             */
            files: restRepoFind,
            /**
             * @returns {stash/api/util/navbuilder.Builder}
             */
            related : function restRepoRelated() {
                return this._path().pushComponents('related').makeBuilder();
            },
            /**
             * @method
             * @param {number} id - The ID of a pull request.
             * @returns {stash/api/util/navbuilder.RestPullRequestBuilder}
             */
            pullRequest : restPullRequest,
            /**
             * @returns {stash/api/util/navbuilder.Builder}
             */
            allPullRequests : function restAllPullRequests() {
                return this._path().pushComponents('pull-requests').makeBuilder();
            },
            /**
             * @method
             * @returns {stash/api/util/navbuilder.Builder}
             */
            hooks : repoHooks,
            /**
             * @method
             * @param {string} hookKey - The key of the hook to form URLs about.
             * @returns {stash/api/util/navbuilder.RestHookBuilder}
             */
            hook : restHook
        });
    }



    /**
     * {@linkcode stash/api/util/navbuilder.Builder} for REST pull request info.
     *
     * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
     *
     * @class RestPullRequestBuilder
     * @memberof stash/api/util/navbuilder
     */

    /**
     * Documented at parent builders
     * @private
     */
    function restPullRequest(prOrId) {
        var id = getPullRequestId(prOrId);
        return this._path().pushComponents('pull-requests', id).makeBuilder(
        /**
         * @lends stash/api/util/navbuilder.RestPullRequestBuilder.prototype
         */
        {
            /**
             * @returns {stash/api/util/navbuilder.Builder}
             */
            activities : function() {
                return this._path().pushComponents('activities').makeBuilder();
            },
            /**
             * @returns {stash/api/util/navbuilder.Builder}
             */
            approve: function restApprove() {
                return this._path().pushComponents('approve').makeBuilder();
            },
            /**
             * @param {number} id - The ID of the comment to generate URLs for.
             * @returns {stash/api/util/navbuilder.Builder}
             */
            comment : function restComment(id) {
                return this._path().pushComponents('comments', id).makeBuilder({
                    comment : restComment /* TODO is this legit?!?!?! Not documenting it for now... */
                });
            },
            /**
             * @returns {stash/api/util/navbuilder.Builder}
             */
            comments : function() {
                return this._path().pushComponents('comments').makeBuilder();
            },
            /**
             * @returns {stash/api/util/navbuilder.Builder}
             */
            changes: function restPullRequestChanges(){
                return this._path().pushComponents('changes').makeBuilder();
            },
            /**
             * @method
             * @param {JSON.FileChangeJSON} fileChange
             * @returns {stash/api/util/navbuilder.Builder}
             */
            diff: restDiff,
            /**
             * @returns {stash/api/util/navbuilder.Builder}
             */
            watch: function restPullRequestWatch() {
                return this._path().pushComponents('watch').makeBuilder();
            },
            /**
             * @returns {stash/api/util/navbuilder.Builder}
             */
            merge: function restMerge() {
                return this._path().pushComponents('merge').makeBuilder();
            },
            /**
             * @returns {stash/api/util/navbuilder.Builder}
             */
            reopen: function restReopen() {
                return this._path().pushComponents('reopen').makeBuilder();
            },
            /**
             * @returns {stash/api/util/navbuilder.Builder}
             */
            decline: function restDecline() {
                return this._path().pushComponents('decline').makeBuilder();
            }
        });
    }

    /**
     * Documented at parent builders
     * @private
     */
    function restCurrentPullRequest() {
        return restCurrentRepo.call(this).pullRequest(getCurrentPullRequest());
    }


    /**
     * {@linkcode stash/api/util/navbuilder.Builder} for REST commit URLs.
     *
     * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
     *
     * @class RestCommitBuilder
     * @memberof stash/api/util/navbuilder
     */

    /**
     * Documented at parent builders
     * @private
     */
    function restRepoCommit(commitIdOrCommitRange) {
        commitIdOrCommitRange = commitIdOrCommitRange.toJSON ?commitIdOrCommitRange.toJSON() : commitIdOrCommitRange;

        var path = this._path().pushComponents('commits');
        if (typeof commitIdOrCommitRange === 'string') {
            path = path.pushComponents(commitIdOrCommitRange);
        } else if (commitIdOrCommitRange.untilRevision) {
            path = path.pushComponents(commitIdOrCommitRange.untilRevision.id);

            var sinceId = commitIdOrCommitRange.sinceRevision && commitIdOrCommitRange.sinceRevision.id;
            if (sinceId) {
                path = path.addParams({ since: sinceId });
            }
        } else {
            throw new Error(AJS.I18n.getText('stash.web.error.no.commit.or.commitRange'));
        }

        return path.makeBuilder(
        /**
         * @lends stash/api/util/navbuilder.RestCommitBuilder.prototype
         */
        {
            /**
             * @method
             * @param {JSON.FileChangeJSON} fileChange
             * @returns {stash/api/util/navbuilder.Builder}
             */
            diff: restDiff,
            /**
             * @returns {stash/api/util/navbuilder.RestCommitPathBuilder}
             */
            changes: function restChangesetChanges() {
                return this._path().pushComponents('changes').makeBuilder(restCommitPathBuilderMethods);
            },
            /**
             * @returns {stash/api/util/navbuilder.RestCommitPathBuilder}
             */
            comments: function restChangesetComment() {
                return this._path().pushComponents('comments').makeBuilder(restCommitPathBuilderMethods);
            },
            /**
             * @returns {stash/api/util/navbuilder.RepoBrowseBuilder}
             */
            watch: function restCommitWatch() {
                return this._path().pushComponents('watch').makeBuilder();
            }
        });
    }

    /**
     * {@linkcode stash/api/util/navbuilder.Builder} for REST commit path URLs.
     *
     * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
     *
     * @class RestCommitPathBuilder
     * @memberof stash/api/util/navbuilder
     */
    var restCommitPathBuilderMethods =
        /**
         * @lends stash/api/util/navbuilder.RestCommitPathBuilder.prototype
         */
        {
            /**
             * @param {string} path - A file path.
             * @returns {stash/api/util/navbuilder.Builder}
             */
            path : function restChangesetPath(path) {
                return this._path().addParams({
                    path: path.toString()
                }).makeBuilder();
            }
         };

    /**
     * @private
     */
    function restDiffInternal(fileChange, builderMethods) {
        var fileChangeJSON = fileChange.toJSON ? fileChange.toJSON() : fileChange;

        var builder = this._path();

        builder = builder.pushComponents('diff');
        builder = builder.pushComponents.apply(builder, componentsFromArguments([fileChangeJSON.path]));

        if (fileChangeJSON.srcPath) {
            builder = builder.addParams({ srcPath: fileChangeJSON.srcPath.toString() });
        }

        return builder.makeBuilder(builderMethods);

    }

    /**
     * Documented at parent builders
     * @private
     */
    function restDiff(fileChange) {
        return restDiffInternal.call(this, fileChange);
    }

    /**
     * @returns {stash/api/util/navbuilder.RepoBrowseBuilder}
     */
    function restRepoBrowse() {
        return this._path().pushComponents('browse').makeBuilder(RepoBrowseBuilderMethods);
    }


    /**
     * {@linkcode stash/api/util/navbuilder.Builder} for specifying revisions in REST repository files list URLs.
     *
     * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
     *
     * @class RestRepoFilesListAtBuilder
     * @memberof stash/api/util/navbuilder
     */
    var restRepoFilesListAtBuilderMethods =
        /**
         * @lends stash/api/util/navbuilder.RestRepoFilesListAtBuilder.prototype
         */
        {
            /**
             * Set the "at" revision at which to obtain a file list from the repo.
             *
             * @method
             * @param {string} refId - The ID of a ref or commit in the SCM whose history to browse.
             * @returns {stash/api/util/navbuilder.Builder}
             */
            at: RevisionRangeSpecifyingBuilderMethods.at
        };


    /**
     * {@linkcode stash/api/util/navbuilder.Builder} for REST repository files list URLs.
     *
     * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
     *
     * @class RestRepoFilesListBuilder
     * @extends stash/api/util/navbuilder.RestRepoFilesListAtBuilder
     * @memberof stash/api/util/navbuilder
     */
    var restRepoFilesListBuilderMethods =
        /**
         * @lends stash/api/util/navbuilder.RestRepoFilesListBuilder.prototype
         */
        {
            /**
             * @param {...string} component - A path component within which to obtain a list of files.
             * @returns {stash/api/util/navbuilder.RestRepoFilesListAtBuilder}
             */
            path: function restRepoFilesInPath() {
                var path = this._path();
                return path.pushComponents.apply(path, componentsFromArguments(arguments)).makeBuilder(restRepoFilesListAtBuilderMethods);
            },
            at : restRepoFilesListAtBuilderMethods.at
        };

    /**
     * Documented at parent builder
     * @private
     */
    function restRepoFind() {
        return this._path().pushComponents('files').makeBuilder($.extend({
            /**
             * @private
             */
            all: deprecate.fn(restRepoAllFiles, 'nav.rest().{currentRepo()|project().repo()}.files().all()', null, '3.0', '4.0')
        }, restRepoFilesListBuilderMethods));
    }

    /**
     * Undocumented
     * @deprecated
     * @private
     */
    function restRepoAllFiles() {
        return this._path().addParams({limit: 100000}).makeBuilder(restRepoFilesListBuilderMethods);
    }

    /**
     * {@linkcode stash/api/util/navbuilder.Builder} for REST project permissions URLs.
     *
     * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
     *
     * @class RestProjectPermissionsBuilder
     * @memberof stash/api/util/navbuilder
     */

    /**
     * Documented at parent builder
     * @private
     */
    function restProjPermissions() {
        return this._path().pushComponents('permissions').makeBuilder(
        /**
         * @lends stash/api/util/navbuilder.RestProjectPermissionsBuilder.prototype
         */
        {
            /**
             * {@linkcode stash/api/util/navbuilder.Builder} for REST project read permissions URLs.
             *
             * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
             *
             * @class RestProjectReadPermissionsBuilder
             * @memberof stash/api/util/navbuilder
             */
            /**
             * @returns {stash/api/util/navbuilder.RestProjectReadPermissionsBuilder}
             */
            projectRead: function restProjReadPerms() {
                return this._path().pushComponents('project-read').makeBuilder(
                /**
                 * @lends stash/api/util/navbuilder.RestProjectReadPermissionsBuilder.prototype
                 */
                {
                    /**
                     * @method
                     * @returns {stash/api/util/navbuilder.RestPermissionAllowBuilder}
                     */
                    all: restAllProjPerms,
                    /**
                     * @returns {stash/api/util/navbuilder.RestPermissionAllowBuilder}
                     */
                    anon: function restAnonProReadPerms() {
                        return this._path().pushComponents('anon').makeBuilder(allowBuilderMethods);
                    }
                });
            },
            /**
             * {@linkcode stash/api/util/navbuilder.Builder} for REST project read permissions URLs.
             *
             * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
             *
             * @class RestProjectWritePermissionsBuilder
             * @memberof stash/api/util/navbuilder
             */
            /**
             * @returns {stash/api/util/navbuilder.RestProjectWritePermissionsBuilder}
             */
            projectWrite: function restProjWritePerms() {
                return this._path().pushComponents('project-write').makeBuilder(
                /**
                 * @lends stash/api/util/navbuilder.RestProjectWritePermissionsBuilder.prototype
                 */
                {
                    /**
                     * @method
                     * @returns {stash/api/util/navbuilder.RestPermissionAllowBuilder}
                     */
                    all: restAllProjPerms
                });
            }
        });
    }

    /**
     * {@linkcode stash/api/util/navbuilder.Builder} to grant permissions.
     *
     * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
     *
     * @class RestPermissionAllowBuilder
     * @memberof stash/api/util/navbuilder
     */
    var allowBuilderMethods =
    /**
     * @lends stash/api/util/navbuilder.RestPermissionAllowBuilder.prototype
     */
    {
        /**
         * @method
         * @returns {stash/api/util/navbuilder.Builder}
         */
        allow : restAllowProjPerms
    };

    /**
     * Documented at parent builders
     * @private
     */
    function restAllProjPerms() {
        return this._path().pushComponents('all').makeBuilder(allowBuilderMethods);
    }

    /**
     * Documented at parent builders
     * @private
     */
    function restAllowProjPerms(allow) {
        return this._path().addParams({'allow': allow}).makeBuilder();
    }

    /**
     * {@linkcode stash/api/util/navbuilder.Builder} for info about repository hook plugins.
     *
     * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
     *
     * @class RestHookPluginsBuilder
     * @memberof stash/api/util/navbuilder
     */

    /**
     * Documented at parent builders
     * @private
     */
    function restHookPlugins() {
        return this._path().pushComponents('hooks').makeBuilder(
        /**
         * @lends stash/api/util/navbuilder.RestHookPluginsBuilder.prototype
         */
        {
            /**
             * {@linkcode stash/api/util/navbuilder.Builder} for info about a repository hook plugin.
             *
             * NOTE: The constructor is not exposed. A new instance can be created through the Builder API.
             *
             * @class RestHookPluginBuilder
             * @memberof stash/api/util/navbuilder
             */

            /**
             * @param {string} hookKey - The key of the hook.
             * @returns {stash/api/util/navbuilder.RestHookPluginBuilder}
             */
            hook: function restHookPlugin(hookKey) {
                return this._path().pushComponents(hookKey).makeBuilder(
                /**
                 * @lends stash/api/util/navbuilder.RestHookPluginBuilder.prototype
                 */
                {
                    /**
                     * @param {string} [version] - A string identifying the version of the hook plugin.
                     *                             Used only to invalidate browser caches when the plugin updates.
                     * @returns {stash/api/util/navbuilder.Builder}
                     */
                    avatar: function restHookAvatar(version) {
                        return this._path().pushComponents('avatar').addParams({'version': version}).makeBuilder();
                    }
                });
            }
        });
    }

    /**
     * Documented at parent builders.
     * @private
     */
    function userAvatar(size) {
        var builder = this._path().pushComponents('avatar.png');
        if (size) {
            builder = builder.addParams({s: size});
        }
        return builder.makeBuilder();
    }

    // HACKY CODE CHECK: off
    var fallbackUrlPattern = /(default-avatar-)\d+(\.png)/;

    /**
     * @private
     */
    function _avatarUrl(person, size) {
        return {
            build : function() {
                var uri = parse(person.avatarUrl);
                if (uri.getQueryParamValue("s")) {
                    uri.replaceQueryParam("s", size);
                }
                // If what we're looking at is the default avatar, its size is set differently,
                // so use a regex in the filename, rather than a query string param, to insert the correct size.
                return uri.toString().replace(fallbackUrlPattern, "$1" + size + "$2");
            }
        };
    }

    // HACKY CODE CHECK: on

    /**
     * An object representation of a URI with methods allowing you to read and modify the URI.
     *
     * NOTE: The Uri constructor is not exposed. Use {@linkcode stash/api/util/navbuilder.parse} to create an instance.
     *
     * @class Uri
     * @memberof stash/api/util/navbuilder
     */

    /**
     * Serialize the Uri instance.
     *
     * @function toString
     * @name stash/api/util/navbuilder.Uri#toString
     * @returns {string}
     */

    /**
     * Get just the path portion of the URI.
     *
     * @function path
     * @name stash/api/util/navbuilder.Uri#path
     * @returns {string}
     */


    /**
     * Get just the query string portion of the URI, as an object.
     *
     * @function query
     * @name stash/api/util/navbuilder.Uri#query
     * @returns {stash/api/util/navbuilder.Query}
     */

    /**
     * Get just the anchor/hash portion of the URI.
     *
     * @function anchor
     * @name stash/api/util/navbuilder.Uri#anchor
     * @returns {string}
     */

    /**
     * Add a query parameter value. If the key is already present in the URI, the key will be repeated.
     *
     * @function addQueryParam
     * @name stash/api/util/navbuilder.Uri#addQueryParam
     * @param {string} paramKey - The key/name of the parameter.
     * @param {string} paramValue - The value for the parameter.
     * @returns {stash/api/util/navbuilder.Uri}
     */

    /**
     * Add a query parameter value. If the key is already present in the URI, it will be replaced.
     *
     * @function replaceQueryParam
     * @name stash/api/util/navbuilder.Uri#replaceQueryParam
     * @param {string} paramKey - The key/name of the parameter.
     * @param {string} paramValue - The value for the parameter.
     * @returns {stash/api/util/navbuilder.Uri}
     */

    /**
     * Remove a query parameter from the URI.
     *
     * @function deleteQueryParam
     * @name stash/api/util/navbuilder.Uri#deleteQueryParam
     * @param {string} paramKey - The key/name of the parameter.
     * @returns {stash/api/util/navbuilder.Uri}
     */

    /**
     * Get a query parameter value. If the key is repeated in the URI, the first instance will be returned.
     *
     * @function getQueryParamValue
     * @name stash/api/util/navbuilder.Uri#getQueryParamValue
     * @param {string} paramKey - The key/name of the parameter.
     * @returns {string}
     */

    /**
     * Get an array of query parameter values for a key.
     *
     * @function getQueryParamValues
     * @name stash/api/util/navbuilder.Uri#getQueryParamValues
     * @param {string} paramKey - The key/name of the parameter.
     * @returns {Array<string>}
     */

    /**
     * Parse an absolute string URI in to a mutable Uri object.
     * @memberof stash/api/util/navbuilder
     * @param {string} uri - An absolute URI to be parsed.
     * @returns {stash/api/util/navbuilder.Uri}
     */
    function parse(uri) {
        return new Uri(uri);
    }

    /**
     * An object representation of a query string with methods allowing you to read and modify the string.
     *
     * NOTE: The Query constructor is not exposed. Use {@linkcode stash/api/util/navbuilder.parseQuery} to create an instance.
     *
     * @class Query
     * @memberof stash/api/util/navbuilder
     */

    /**
     * Serialize the Query instance.
     *
     * @function toString
     * @name stash/api/util/navbuilder.Query#toString
     * @returns {string}
     */

    /**
     * Add a query parameter value. If the key is already present in the Query, the key will be repeated.
     *
     * @function addParam
     * @name stash/api/util/navbuilder.Query#addParam
     * @param {string} paramKey - The key/name of the parameter.
     * @param {string} paramValue - The value for the parameter.
     * @returns {stash/api/util/navbuilder.Query}
     */

    /**
     * Add a query parameter value. If the key is already present in the Query, it will be replaced.
     *
     * @function replaceParam
     * @name stash/api/util/navbuilder.Query#replaceParam
     * @param {string} paramKey - The key/name of the parameter.
     * @param {string} paramValue - The value for the parameter.
     * @returns {stash/api/util/navbuilder.Query}
     */

    /**
     * Remove a query parameter from the URI.
     *
     * @function deleteParam
     * @name stash/api/util/navbuilder.Query#deleteParam
     * @param {string} paramKey - The key/name of the parameter.
     * @returns {stash/api/util/navbuilder.Query}
     */

    /**
     * Get a query parameter value. If the key is repeated in the Query, the first instance will be returned.
     *
     * @function getParamValue
     * @name stash/api/util/navbuilder.Query#getParamValue
     * @param {string} paramKey - The key/name of the parameter.
     * @returns {string}
     */

    /**
     * Get an array of query parameter values for a key.
     *
     * @function getParamValues
     * @name stash/api/util/navbuilder.Query#getParamValues
     * @param {string} paramKey - The key/name of the parameter.
     * @returns {Array<string>}
     */

    /**
     * Parse a URI's query string into a mutable object.
     * @memberof stash/api/util/navbuilder
     * @param {string} queryString - A query string to be parsed.
     * @returns {stash/api/util/navbuilder.Query}
     */
    function parseQuery(queryString) {
        return new Query(queryString);
    }

    /**
     * Get a raw builder instance to form your own URLs.
     *
     * @memberof stash/api/util/navbuilder
     * @param {Array<string>} components - An array of path components that will be URI encoded and joined by forward slashes when the URL is formed.
     * @param {Object} params - A map of parameter names to values that will form the query string.
     * @returns {stash/api/util/navbuilder.Builder}
     */
    function newBuilder(components, params) {
        return new PathAndQuery(components, params).makeBuilder();
    }

    exports._avatarUrl = _avatarUrl;
    exports.addons = addons;
    exports.admin = admin;
    exports.allProjects = allProjects;
    exports.allRepos = globalAllRepos;
    exports.captcha = captcha;
    exports.createProject = createProject;
    exports.currentProject = currentProject;
    exports.currentPullRequest = currentPullRequest;
    exports.currentRepo = currentRepo;
    exports.login = login;
    exports.newBuilder = newBuilder;
    exports.parse = parse;
    exports.parseQuery = parseQuery;
    exports.pluginServlets = pluginServlets;
    exports.project = project;
    exports.rest = rest;
    exports.tmp = tmp;
    exports.user = user;
    exports.welcome = welcome;
    exports.gettingStarted = gettingStarted;
});

Zerion Mini Shell 1.0