<commit_before>// @flow

const Promise = require("bluebird");
const OpenShiftClient = require('openshift-client');
const sleep = require("es7-sleep");
const AWS = require('aws-sdk');
const uuidv4 = require('uuid/v4');
const R = require('ramda');
const { logger } = require('@lagoon/commons/src/local-logging');
const {
  getOpenShiftInfoForProject,
  getEnvironmentByName,
  updateEnvironment,
  getDeploymentByRemoteId,
  updateDeployment,
  setEnvironmentServices,
} = require('@lagoon/commons/src/api');

const { sendToLagoonLogs, initSendToLagoonLogs } = require('@lagoon/commons/src/logs');
const { consumeTaskMonitor, initSendToLagoonTasks } = require('@lagoon/commons/src/tasks');

class BuildNotCompletedYet extends Error {
  constructor(message: string) {
    super(message);
    this.name = 'BuildNotCompletedYet';
  }
}

const accessKeyId =  process.env.AWS_ACCESS_KEY_ID
const secretAccessKey =  process.env.AWS_SECRET_ACCESS_KEY
const bucket = process.env.AWS_BUCKET
const region = process.env.AWS_REGION || 'us-east-2'

if ( !accessKeyId || !secretAccessKey || !bucket) {
  logger.error('AWS_ACCESS_KEY_ID or AWS_SECRET_ACCESS_KEY or AWS_BUCKET not set.')
}

AWS.config.update({accessKeyId: accessKeyId, secretAccessKey: secretAccessKey, region: region});
const s3 = new AWS.S3();

initSendToLagoonLogs();
initSendToLagoonTasks();

const messageConsumer = async msg => {
  const {
    buildName,
    projectName,
    openshiftProject,
    branchName,
    sha
  } = JSON.parse(msg.content.toString())

  logger.verbose(`Received BuildDeployOpenshift monitoring task for project: ${projectName}, buildName: ${buildName}, openshiftProject: ${openshiftProject}, branch: ${branchName}, sha: ${sha}`);
  const projectResult = await getOpenShiftInfoForProject(projectName);
  const project = projectResult.project

  const environmentResult = await getEnvironmentByName(branchName, project.id)
  const environment = environmentResult.environmentByName

  try {
    var gitSha = sha
    var openshiftConsole = project.openshift.consoleUrl.replace(/\/$/, "");
    var openshiftToken = project.openshift.token || ""
  } catch(error) {
    logger.warn(`Error while loading information for project ${projectName}: ${error}`)
    throw(error)
  }

  // OpenShift API object
  const openshift = new OpenShiftClient.OApi({
    url: openshiftConsole,
    insecureSkipTlsVerify: true,
    auth: {
      bearer: openshiftToken
    },
  });

  // Kubernetes API Object - needed as some API calls are done to the Kubernetes API part of OpenShift and
  // the OpenShift API does not support them.
  const kubernetes = new OpenShiftClient.Core({
    url: openshiftConsole,
    insecureSkipTlsVerify: true,
    auth: {
      bearer: openshiftToken
    },
  });

  // kubernetes-client does not know about the OpenShift Resources, let's teach it.
  openshift.ns.addResource('builds');
  openshift.ns.addResource('deploymentconfigs');

  let projectStatus = {}
  try {
    const projectsGet = Promise.promisify(openshift.projects(openshiftProject).get, { context: openshift.projects(openshiftProject) })
    projectStatus = await projectsGet()
  } catch (err) {
    // a non existing project also throws an error, we check if it's a 404, means it does not exist, so we create it.
    if (err.code == 404) {
      logger.error(`Project ${openshiftProject} does not exist, bailing`)
      return
    } else {
      logger.error(err)
      throw new Error
    }
  }

  try {
    const buildsGet = Promise.promisify(openshift.ns(openshiftProject).builds(buildName).get, { context: openshift.ns(openshiftProject).builds(buildName) })
    buildstatus = await buildsGet()
  } catch (err) {
    if (err.code == 404) {
      logger.error(`Build ${buildName} does not exist, bailing`)
      return
    } else {
      logger.error(err)
      throw new Error
    }
  }

  const buildPhase = buildstatus.status.phase.toLowerCase();
  const buildsLogGet = Promise.promisify(openshift.ns(openshiftProject).builds(`${buildName}/log`).get, { context: openshift.ns(openshiftProject).builds(`${buildName}/log`) })
  const routesGet = Promise.promisify(openshift.ns(openshiftProject).routes.get, { context: openshift.ns(openshiftProject).routes })

  try {
    const deployment = await getDeploymentByRemoteId(buildstatus.metadata.uid);
    if (!deployment.deploymentByRemoteId) {
      throw new Error(`No deployment found with remote id ${buildstatus.metadata.uid}`);
    }

    const convertDateFormat = R.init;
    const dateOrNull = R.unless(R.isNil, convertDateFormat);

    await updateDeployment(deployment.deploymentByRemoteId.id, {
      status: buildstatus.status.phase.toUpperCase(),
      created: convertDateFormat(buildstatus.metadata.creationTimestamp),
      started: dateOrNull(buildstatus.status.startTimestamp),
      completed: dateOrNull(buildstatus.status.completionTimestamp),
    });
  } catch (error) {
    logger.error(`Could not update deployment ${projectName} ${buildName}. Message: ${error}`);
  }

  const meta = JSON.parse(msg.content.toString())
  let logLink = ""
  let logMessage = ''
  if (sha) {
    meta.shortSha = sha.substring(0, 7)
    logMessage = `\`${branchName}\` (${sha.substring(0, 7)})`
  } else {
    logMessage = `\`${branchName}\``
  }
  switch (buildPhase) {
    case "new":
    case "pending":
      sendToLagoonLogs('info', projectName, "", `task:builddeploy-openshift:${buildPhase}`, meta,
        `*[${projectName}]* ${logMessage} Build \`${buildName}\` not yet started`
      )
      throw new BuildNotCompletedYet(`*[${projectName}]* ${logMessage} Build \`${buildName}\` not yet started`)
      break;

    case "running":
      sendToLagoonLogs('info', projectName, "", `task:builddeploy-openshift:${buildPhase}`, meta,
        `*[${projectName}]* ${logMessage} Build \`${buildName}\` running`
      )
      throw new BuildNotCompletedYet(`*[${projectName}]* ${logMessage} Build \`${buildName}\` running`)
      break;

    case "cancelled":
    case "error":
      try {
        const buildLog = await buildsLogGet()
        const s3UploadResult = await saveBuildLog(buildName, projectName, branchName, buildLog, buildstatus)
        logLink = s3UploadResult.Location
        meta.logLink = logLink
      } catch (err) {
        logger.warn(`${openshiftProject} ${buildName}: Error while getting and uploading Logs to S3, Error: ${err}. Continuing without log link in message`)
        meta.logLink = ''
      }
      sendToLagoonLogs('warn', projectName, "", `task:builddeploy-openshift:${buildPhase}`, meta,
        `*[${projectName}]* ${logMessage} Build \`${buildName}\` cancelled. <${logLink}|Logs>`
      )
      break;

    case "failed":
      try {
        const buildLog = await buildsLogGet()
        const s3UploadResult = await saveBuildLog(buildName, projectName, branchName, buildLog, buildstatus)
        logLink = s3UploadResult.Location
        meta.logLink = logLink
      } catch (err) {
        logger.warn(`${openshiftProject} ${buildName}: Error while getting and uploading Logs to S3, Error: ${err}. Continuing without log link in message`)
        meta.logLink = ''
      }

      sendToLagoonLogs('error', projectName, "", `task:builddeploy-openshift:${buildPhase}`, meta,
        `*[${projectName}]* ${logMessage} Build \`${buildName}\` failed. $<${logLink}|Logs>`
      )
      break;

    case "complete":
      try {
        const buildLog = await buildsLogGet()
        const s3UploadResult = await saveBuildLog(buildName, projectName, branchName, buildLog, buildstatus)
        logLink = s3UploadResult.Location
        meta.logLink = logLink
      } catch (err) {
        logger.warn(`${openshiftProject} ${buildName}: Error while getting and uploading Logs to S3, Error: ${err}. Continuing without log link in message`)
        meta.logLink = ''
      }

      try {
        const configMapGet = Promise.promisify(kubernetes.ns(openshiftProject).configmaps('lagoon-env').get, { context: kubernetes.ns(openshiftProject).configmaps('lagoon-env') })
        configMap = await configMapGet()
      } catch (err) {
        if (err.code == 404) {
          logger.error(`configmap lagoon-env does not exist, continuing without routes information`)
        } else {
          logger.error(err)
          throw new Error
        }
      }

      const route = configMap.data.LAGOON_ROUTE
      const routes = configMap.data.LAGOON_ROUTES.split(',').filter(e => e !== route);
      meta.route = route
      meta.routes = routes
      sendToLagoonLogs('info', projectName, "", `task:builddeploy-openshift:${buildPhase}`, meta,
        `*[${projectName}]* ${logMessage} Build \`${buildName}\` complete. <${logLink}|Logs> \n ${route}\n ${routes.join("\n")}`
      )
      try {
        const updateEnvironmentResult = await updateEnvironment(
          environment.id,
          `{
            route: "${configMap.data.LAGOON_ROUTE}",
            routes: "${configMap.data.LAGOON_ROUTES}",
            monitoringUrls: "${configMap.data.LAGOON_MONITORING_URLS}",
            project: ${project.id}
          }`)
        } catch (err) {
          logger.warn(`${openshiftProject} ${buildName}: Error while updating routes in API, Error: ${err}. Continuing without update`)
        }

      // Tell api what services are running in this environment
      try {
        // Get pod template from existing service
        const deploymentConfigsGet = Promise.promisify(
          openshift.ns(openshiftProject).deploymentconfigs.get, { context: openshift.ns(openshiftProject).deploymentconfigs }
        );
        const deploymentConfigs = await deploymentConfigsGet();

        const serviceNames = deploymentConfigs.items.reduce(
          (names, deploymentConfig) => [
            ...names,
            ...deploymentConfig.spec.template.spec.containers.reduce(
              (names, container) => [
                ...names,
                container.name
              ],
              []
            )
          ],
          []
        );

        await setEnvironmentServices(environment.id, serviceNames);
      } catch (err) {
        logger.error(`${openshiftProject} ${buildName}: Error while updating environment services in API, Error: ${err}`)
      }
      break;

    default:
      sendToLagoonLogs('info', projectName, "", `task:builddeploy-openshift:${buildPhase}`, meta,
        `*[${projectName}]* ${logMessage} Build \`${buildName}\` phase ${buildPhase}`
      )
      throw new BuildNotCompletedYet(`*[${projectName}]* ${logMessage} Build \`${buildName}\` phase ${buildPhase}`)
      break;
  }

}

const saveBuildLog = async(buildName, projectName, branchName, buildLog, buildStatus) => {
  const meta = {
    buildName,
    branchName,
    buildPhase: buildStatus.status.phase.toLowerCase(),
    remoteId: buildStatus.metadata.uid
  };

  sendToLagoonLogs('info', projectName, "", `build-logs:builddeploy-openshift:${buildName}`, meta,
    buildLog
  );
  return await uploadLogToS3(buildName, projectName, branchName, buildLog);
}

const uploadLogToS3 = async (buildName, projectName, branchName, buildLog) => {
  const uuid = uuidv4();
  const path = `${projectName}/${branchName}/${uuid}.txt`

  const params = {
    Bucket: bucket,
    Key:    path,
    Body:   buildLog,
    ACL:    'public-read',
    ContentType: 'text/plain',
  };
  const s3Upload = Promise.promisify(s3.upload, { context: s3 })
  return s3Upload(params);

};

const deathHandler = async (msg, lastError) => {
  const {
    buildName,
    projectName,
    openshiftProject,
    branchName,
    sha
  } = JSON.parse(msg.content.toString())

  let logMessage = ''
  if (sha) {
    logMessage = `\`${branchName}\` (${sha.substring(0, 7)})`
  } else {
    logMessage = `\`${branchName}\``
  }

  sendToLagoonLogs('error', projectName, "", "task:builddeploy-openshift:error",  {},
`*[${projectName}]* ${logMessage} Build \`${buildName}\` ERROR:
\`\`\`
${lastError}
\`\`\``
  )

}

consumeTaskMonitor('builddeploy-openshift', messageConsumer, deathHandler)
<commit_msg>Issue #1072: Removed "$" character from slack logs notification link<commit_after>// @flow

const Promise = require("bluebird");
const OpenShiftClient = require('openshift-client');
const sleep = require("es7-sleep");
const AWS = require('aws-sdk');
const uuidv4 = require('uuid/v4');
const R = require('ramda');
const { logger } = require('@lagoon/commons/src/local-logging');
const {
  getOpenShiftInfoForProject,
  getEnvironmentByName,
  updateEnvironment,
  getDeploymentByRemoteId,
  updateDeployment,
  setEnvironmentServices,
} = require('@lagoon/commons/src/api');

const { sendToLagoonLogs, initSendToLagoonLogs } = require('@lagoon/commons/src/logs');
const { consumeTaskMonitor, initSendToLagoonTasks } = require('@lagoon/commons/src/tasks');

class BuildNotCompletedYet extends Error {
  constructor(message: string) {
    super(message);
    this.name = 'BuildNotCompletedYet';
  }
}

const accessKeyId =  process.env.AWS_ACCESS_KEY_ID
const secretAccessKey =  process.env.AWS_SECRET_ACCESS_KEY
const bucket = process.env.AWS_BUCKET
const region = process.env.AWS_REGION || 'us-east-2'

if ( !accessKeyId || !secretAccessKey || !bucket) {
  logger.error('AWS_ACCESS_KEY_ID or AWS_SECRET_ACCESS_KEY or AWS_BUCKET not set.')
}

AWS.config.update({accessKeyId: accessKeyId, secretAccessKey: secretAccessKey, region: region});
const s3 = new AWS.S3();

initSendToLagoonLogs();
initSendToLagoonTasks();

const messageConsumer = async msg => {
  const {
    buildName,
    projectName,
    openshiftProject,
    branchName,
    sha
  } = JSON.parse(msg.content.toString())

  logger.verbose(`Received BuildDeployOpenshift monitoring task for project: ${projectName}, buildName: ${buildName}, openshiftProject: ${openshiftProject}, branch: ${branchName}, sha: ${sha}`);
  const projectResult = await getOpenShiftInfoForProject(projectName);
  const project = projectResult.project

  const environmentResult = await getEnvironmentByName(branchName, project.id)
  const environment = environmentResult.environmentByName

  try {
    var gitSha = sha
    var openshiftConsole = project.openshift.consoleUrl.replace(/\/$/, "");
    var openshiftToken = project.openshift.token || ""
  } catch(error) {
    logger.warn(`Error while loading information for project ${projectName}: ${error}`)
    throw(error)
  }

  // OpenShift API object
  const openshift = new OpenShiftClient.OApi({
    url: openshiftConsole,
    insecureSkipTlsVerify: true,
    auth: {
      bearer: openshiftToken
    },
  });

  // Kubernetes API Object - needed as some API calls are done to the Kubernetes API part of OpenShift and
  // the OpenShift API does not support them.
  const kubernetes = new OpenShiftClient.Core({
    url: openshiftConsole,
    insecureSkipTlsVerify: true,
    auth: {
      bearer: openshiftToken
    },
  });

  // kubernetes-client does not know about the OpenShift Resources, let's teach it.
  openshift.ns.addResource('builds');
  openshift.ns.addResource('deploymentconfigs');

  let projectStatus = {}
  try {
    const projectsGet = Promise.promisify(openshift.projects(openshiftProject).get, { context: openshift.projects(openshiftProject) })
    projectStatus = await projectsGet()
  } catch (err) {
    // a non existing project also throws an error, we check if it's a 404, means it does not exist, so we create it.
    if (err.code == 404) {
      logger.error(`Project ${openshiftProject} does not exist, bailing`)
      return
    } else {
      logger.error(err)
      throw new Error
    }
  }

  try {
    const buildsGet = Promise.promisify(openshift.ns(openshiftProject).builds(buildName).get, { context: openshift.ns(openshiftProject).builds(buildName) })
    buildstatus = await buildsGet()
  } catch (err) {
    if (err.code == 404) {
      logger.error(`Build ${buildName} does not exist, bailing`)
      return
    } else {
      logger.error(err)
      throw new Error
    }
  }

  const buildPhase = buildstatus.status.phase.toLowerCase();
  const buildsLogGet = Promise.promisify(openshift.ns(openshiftProject).builds(`${buildName}/log`).get, { context: openshift.ns(openshiftProject).builds(`${buildName}/log`) })
  const routesGet = Promise.promisify(openshift.ns(openshiftProject).routes.get, { context: openshift.ns(openshiftProject).routes })

  try {
    const deployment = await getDeploymentByRemoteId(buildstatus.metadata.uid);
    if (!deployment.deploymentByRemoteId) {
      throw new Error(`No deployment found with remote id ${buildstatus.metadata.uid}`);
    }

    const convertDateFormat = R.init;
    const dateOrNull = R.unless(R.isNil, convertDateFormat);

    await updateDeployment(deployment.deploymentByRemoteId.id, {
      status: buildstatus.status.phase.toUpperCase(),
      created: convertDateFormat(buildstatus.metadata.creationTimestamp),
      started: dateOrNull(buildstatus.status.startTimestamp),
      completed: dateOrNull(buildstatus.status.completionTimestamp),
    });
  } catch (error) {
    logger.error(`Could not update deployment ${projectName} ${buildName}. Message: ${error}`);
  }

  const meta = JSON.parse(msg.content.toString())
  let logLink = ""
  let logMessage = ''
  if (sha) {
    meta.shortSha = sha.substring(0, 7)
    logMessage = `\`${branchName}\` (${sha.substring(0, 7)})`
  } else {
    logMessage = `\`${branchName}\``
  }
  switch (buildPhase) {
    case "new":
    case "pending":
      sendToLagoonLogs('info', projectName, "", `task:builddeploy-openshift:${buildPhase}`, meta,
        `*[${projectName}]* ${logMessage} Build \`${buildName}\` not yet started`
      )
      throw new BuildNotCompletedYet(`*[${projectName}]* ${logMessage} Build \`${buildName}\` not yet started`)
      break;

    case "running":
      sendToLagoonLogs('info', projectName, "", `task:builddeploy-openshift:${buildPhase}`, meta,
        `*[${projectName}]* ${logMessage} Build \`${buildName}\` running`
      )
      throw new BuildNotCompletedYet(`*[${projectName}]* ${logMessage} Build \`${buildName}\` running`)
      break;

    case "cancelled":
    case "error":
      try {
        const buildLog = await buildsLogGet()
        const s3UploadResult = await saveBuildLog(buildName, projectName, branchName, buildLog, buildstatus)
        logLink = s3UploadResult.Location
        meta.logLink = logLink
      } catch (err) {
        logger.warn(`${openshiftProject} ${buildName}: Error while getting and uploading Logs to S3, Error: ${err}. Continuing without log link in message`)
        meta.logLink = ''
      }
      sendToLagoonLogs('warn', projectName, "", `task:builddeploy-openshift:${buildPhase}`, meta,
        `*[${projectName}]* ${logMessage} Build \`${buildName}\` cancelled. <${logLink}|Logs>`
      )
      break;

    case "failed":
      try {
        const buildLog = await buildsLogGet()
        const s3UploadResult = await saveBuildLog(buildName, projectName, branchName, buildLog, buildstatus)
        logLink = s3UploadResult.Location
        meta.logLink = logLink
      } catch (err) {
        logger.warn(`${openshiftProject} ${buildName}: Error while getting and uploading Logs to S3, Error: ${err}. Continuing without log link in message`)
        meta.logLink = ''
      }

      sendToLagoonLogs('error', projectName, "", `task:builddeploy-openshift:${buildPhase}`, meta,
        `*[${projectName}]* ${logMessage} Build \`${buildName}\` failed. <${logLink}|Logs>`
      )
      break;

    case "complete":
      try {
        const buildLog = await buildsLogGet()
        const s3UploadResult = await saveBuildLog(buildName, projectName, branchName, buildLog, buildstatus)
        logLink = s3UploadResult.Location
        meta.logLink = logLink
      } catch (err) {
        logger.warn(`${openshiftProject} ${buildName}: Error while getting and uploading Logs to S3, Error: ${err}. Continuing without log link in message`)
        meta.logLink = ''
      }

      try {
        const configMapGet = Promise.promisify(kubernetes.ns(openshiftProject).configmaps('lagoon-env').get, { context: kubernetes.ns(openshiftProject).configmaps('lagoon-env') })
        configMap = await configMapGet()
      } catch (err) {
        if (err.code == 404) {
          logger.error(`configmap lagoon-env does not exist, continuing without routes information`)
        } else {
          logger.error(err)
          throw new Error
        }
      }

      const route = configMap.data.LAGOON_ROUTE
      const routes = configMap.data.LAGOON_ROUTES.split(',').filter(e => e !== route);
      meta.route = route
      meta.routes = routes
      sendToLagoonLogs('info', projectName, "", `task:builddeploy-openshift:${buildPhase}`, meta,
        `*[${projectName}]* ${logMessage} Build \`${buildName}\` complete. <${logLink}|Logs> \n ${route}\n ${routes.join("\n")}`
      )
      try {
        const updateEnvironmentResult = await updateEnvironment(
          environment.id,
          `{
            route: "${configMap.data.LAGOON_ROUTE}",
            routes: "${configMap.data.LAGOON_ROUTES}",
            monitoringUrls: "${configMap.data.LAGOON_MONITORING_URLS}",
            project: ${project.id}
          }`)
        } catch (err) {
          logger.warn(`${openshiftProject} ${buildName}: Error while updating routes in API, Error: ${err}. Continuing without update`)
        }

      // Tell api what services are running in this environment
      try {
        // Get pod template from existing service
        const deploymentConfigsGet = Promise.promisify(
          openshift.ns(openshiftProject).deploymentconfigs.get, { context: openshift.ns(openshiftProject).deploymentconfigs }
        );
        const deploymentConfigs = await deploymentConfigsGet();

        const serviceNames = deploymentConfigs.items.reduce(
          (names, deploymentConfig) => [
            ...names,
            ...deploymentConfig.spec.template.spec.containers.reduce(
              (names, container) => [
                ...names,
                container.name
              ],
              []
            )
          ],
          []
        );

        await setEnvironmentServices(environment.id, serviceNames);
      } catch (err) {
        logger.error(`${openshiftProject} ${buildName}: Error while updating environment services in API, Error: ${err}`)
      }
      break;

    default:
      sendToLagoonLogs('info', projectName, "", `task:builddeploy-openshift:${buildPhase}`, meta,
        `*[${projectName}]* ${logMessage} Build \`${buildName}\` phase ${buildPhase}`
      )
      throw new BuildNotCompletedYet(`*[${projectName}]* ${logMessage} Build \`${buildName}\` phase ${buildPhase}`)
      break;
  }

}

const saveBuildLog = async(buildName, projectName, branchName, buildLog, buildStatus) => {
  const meta = {
    buildName,
    branchName,
    buildPhase: buildStatus.status.phase.toLowerCase(),
    remoteId: buildStatus.metadata.uid
  };

  sendToLagoonLogs('info', projectName, "", `build-logs:builddeploy-openshift:${buildName}`, meta,
    buildLog
  );
  return await uploadLogToS3(buildName, projectName, branchName, buildLog);
}

const uploadLogToS3 = async (buildName, projectName, branchName, buildLog) => {
  const uuid = uuidv4();
  const path = `${projectName}/${branchName}/${uuid}.txt`

  const params = {
    Bucket: bucket,
    Key:    path,
    Body:   buildLog,
    ACL:    'public-read',
    ContentType: 'text/plain',
  };
  const s3Upload = Promise.promisify(s3.upload, { context: s3 })
  return s3Upload(params);

};

const deathHandler = async (msg, lastError) => {
  const {
    buildName,
    projectName,
    openshiftProject,
    branchName,
    sha
  } = JSON.parse(msg.content.toString())

  let logMessage = ''
  if (sha) {
    logMessage = `\`${branchName}\` (${sha.substring(0, 7)})`
  } else {
    logMessage = `\`${branchName}\``
  }

  sendToLagoonLogs('error', projectName, "", "task:builddeploy-openshift:error",  {},
`*[${projectName}]* ${logMessage} Build \`${buildName}\` ERROR:
\`\`\`
${lastError}
\`\`\``
  )

}

consumeTaskMonitor('builddeploy-openshift', messageConsumer, deathHandler)
<|endoftext|>


<commit_before>var https = require("https");
var q = require("q");
var request = require('request');
var _ = require('lodash');

module.exports = function (nigel) {
    var projectBuildInfoUrl = "/job/{{project}}/{{buildId}}/api/json";
    var projectBuildStartUrl = "/job/{{project}}/build";
    var projectInfoUrl = "/job/{{project}}/api/json";

    var urlRegex = /\{\{(\w+)\}\}/g;

    function replaceUrlParams(url, params) {
        return url.replace(urlRegex, function(match, p1) {
            return params[p1] || "";
        });
    }

    function doRequest(params, method) {
        var deferred = q.defer();
        request({
            url: params.url,
            method: method || "GET",
            auth: {
                user: params.user,
                pass: params.pass,
                sendImmediately: true
            }
        }, function (error, response, body) {
          if (('' + response.statusCode).match(/^[23]\d\d$/)) {
            deferred.resolve(body);
          } else {
            deferred.reject(error || body);
          }
        });
        return deferred.promise;
    }

    function buildInfo(nigel, params) {
        params = _.extend({}, {
            buildId: "lastBuild",
            project: "bti-svc-integ"
        }, params);
        params.url = replaceUrlParams(params.url + projectBuildInfoUrl, params);
        return doRequest(params).then(function(resp) {
            if (params.format === "plain") {
                var body = JSON.parse(resp);
                var result = "";
                var changeItems = body.changeSet.items;
                for (var i = 0; i < changeItems.length; i++) {
                    var line = changeItems[i].msg + " - " + changeItems[i].author.fullName;
                    result += line + "\n";
                }
                result += "Status: " + body.result + "\n";
                result += "Url: " + body.url;
                return result;
            }
            return resp;
        });
    }

    function getProjectInfoParams(params) {
        var oParams = _.extend({}, params);
        oParams = _.extend({}, {
            project: "bti-svc-integ"
        }, oParams);
        oParams.url = replaceUrlParams(oParams.url + projectInfoUrl, oParams);
        return oParams;
    }

    function projectInfo(nigel, params) {
        return doRequest(getProjectInfoParams(params));
    }

    function startBuild(nigel, params) {
        var deferred = q.defer();
        var oParams = _.extend({}, params);
        params = _.extend({}, {
            project: "bti-svc-integ"
        }, params);
        params.url = replaceUrlParams(params.url + projectBuildStartUrl, params);
        doRequest(params, "POST").then(function() {
            doRequest(getProjectInfoParams(oParams)).then(function (data) {
                var jsonObj = JSON.parse(data);
                deferred.resolve({ build: jsonObj.nextBuildNumber });
            }, deferred.reject);
        }, deferred.reject);
        return deferred.promise;
    }

    nigel.registerTask("info", "Gets a specific builds information", buildInfo);
    nigel.registerTask("start", "Starts a new build", startBuild);
};
<commit_msg>Added a plain version of build start<commit_after>var https = require("https");
var q = require("q");
var request = require('request');
var _ = require('lodash');

module.exports = function (nigel) {
    var projectBuildInfoUrl = "/job/{{project}}/{{buildId}}";
    var projectBuildInfoJsonUrl = projectBuildInfoUrl + "/api/json";
    var projectBuildStartUrl = "/job/{{project}}/build";
    var projectInfoUrl = "/job/{{project}}/api/json";

    var urlRegex = /\{\{(\w+)\}\}/g;

    function replaceUrlParams(url, params) {
        return url.replace(urlRegex, function(match, p1) {
            return params[p1] || "";
        });
    }

    function doRequest(params, method) {
        var deferred = q.defer();
        request({
            url: params.url,
            method: method || "GET",
            auth: {
                user: params.user,
                pass: params.pass,
                sendImmediately: true
            }
        }, function (error, response, body) {
          if (('' + response.statusCode).match(/^[23]\d\d$/)) {
            deferred.resolve(body);
          } else {
            deferred.reject(error || body);
          }
        });
        return deferred.promise;
    }

    function buildInfo(nigel, params) {
        params = _.extend({}, {
            buildId: "lastBuild",
            project: "bti-svc-integ"
        }, params);
        params.url = replaceUrlParams(params.url + projectBuildInfoJsonUrl, params);
        return doRequest(params).then(function(resp) {
            if (params.format === "plain") {
                var body = JSON.parse(resp);
                var result = "";
                var changeItems = body.changeSet.items;
                for (var i = 0; i < changeItems.length; i++) {
                    var line = changeItems[i].msg + " - " + changeItems[i].author.fullName;
                    result += line + "\n";
                }
                result += "Status: " + body.result + "\n";
                result += "Url: " + body.url;
                return result;
            }
            return resp;
        });
    }

    function getProjectInfoParams(params) {
        var oParams = _.extend({}, params);
        oParams = _.extend({}, {
            project: "bti-svc-integ"
        }, oParams);
        oParams.url = replaceUrlParams(oParams.url + projectInfoUrl, oParams);
        return oParams;
    }

    function projectInfo(nigel, params) {
        return doRequest(getProjectInfoParams(params));
    }

    function startBuild(nigel, params) {
        var deferred = q.defer();
        var oParams = _.extend({}, params);
        params = _.extend({}, {
            project: "bti-svc-integ"
        }, params);
        params.url = replaceUrlParams(params.url + projectBuildStartUrl, params);
        doRequest(params, "POST").then(function() {
            doRequest(getProjectInfoParams(oParams)).then(function (data) {
                var jsonObj = JSON.parse(data);
                var result = { build: jsonObj.nextBuildNumber };
                if (params.format === "plain") {
                    result =
                        "Started build " + jsonObj.nextBuildNumber + " - " +
                        replaceUrlParams(oParams.url + projectBuildInfoUrl, {
                            project: oParams.project,
                            buildId: jsonObj.nextBuildNumber
                        });
                }
                deferred.resolve(result);
            }, deferred.reject);
        }, deferred.reject);
        return deferred.promise;
    }

    nigel.registerTask("info", "Gets a specific builds information", buildInfo);
    nigel.registerTask("start", "Starts a new build", startBuild);
};
<|endoftext|>


<commit_before>/*
 * image-test.js: Test that should be common to all providers.
 *
 * (C) 2012 Nodejitsu Inc.
 *
 */

var fs = require('fs'),
    path = require('path'),
    vows = require('vows'),
    assert = require('../../helpers/assert'),
    helpers = require('../../helpers');

var testData    = {},
    testContext = {},
    clients     = {};

function batchOne (providerClient, providerName) {
  var name   = providerName   || 'rackspace',
      client = providerClient || rackspace,
      test   = {};

  test["The pkgcloud " + name + " compute client"] =
    {
      "the getImages() method": {
        "with details": {
          topic: function () {
            client.getImages(this.callback);
          },
          "should return the list of images": function (err, images) {
            assert.isNull(err);
            testContext.images = images;
            images.forEach(function (image) {
              assert.assertImageDetails(image);
            });
          }
        }
      },
      "the getFlavors() method": {
        "with details": {
          topic: function () {
            client.getFlavors(this.callback);
          },
          "should return the list of flavors": function (err, flavors) {
            assert.isNull(err);
            testContext.flavors = flavors;
            flavors.forEach(function (flavor) {
              assert.assertFlavorDetails(flavor);
            });
          }
        }
      }
    };

  return test;
}

function batchTwo (providerClient, providerName) {
  var name   = providerName   || 'rackspace',
      client = providerClient || rackspace,
      test   = {};

  test["The pkgcloud " + name + " compute client"] =
    {
      "the createServer() method": {
        "with image and flavor ids": {
          topic: function () {
            client.createServer({
              name: 'create-test-ids2',
              image: testContext.images[0].id,
              flavor: testContext.flavors[0].id
            }, this.callback);
          },
          "should return a valid server": function (err, server) {
            testContext.servers = [server];
            assert.isNull(err);
            assert.equal(server.name, 'create-test-ids2');
            assert.equal(server.imageId, testContext.images[0].id);
            assert.assertServerDetails(server);
          }
        }
      }
    };

  return test;
}

function batchThree (providerClient, providerName) {
  var name   = providerName   || 'rackspace',
      client = providerClient || rackspace,
      test   = {};

  test["The pkgcloud " + name + " compute client"] =
    {
      "the getServers() method": {
        topic: function () {
          client.getServers(this.callback);
        },
        "should return the list of servers": function (err, servers) {
          assert.isNull(err);
          testContext.servers = servers;
          servers.forEach(function (server) {
            assert.assertServer(server);
          });
        }
      },
      "the getServer() method": {
        topic: function () {
            client.getServer(testContext.servers[0], this.callback);
        },
        "should return a valid server": function (err, server) {
          client.destroyServer(server);
          assert.isNull(err);
          assert.assertServerDetails(server);
        }
      }
    };

  return test;
}

function batchReboot(providerClient, providerName, nock) {
  var name    = providerName   || 'rackspace',
      client  = providerClient || rackspace,
      timeout = process.env.NOCK ? 1 : 10000,
      test    = {};

  test["The pkgcloud " + name + " compute client"] =
    {
      "the rebootServer() method": {
        topic: function () {
          var self = this;
          client.createServer({
              name  : "test-reboot",
              image : testContext.images[0].id,
              flavor: testContext.flavors[0].id
            },
            function(err,server,response) {
              if(err) { return self.callback(err); }

              function waitForReboot(server) {
                return setTimeout(function (){
                  server.refresh(function(err,srv){
                    if(err) { return self.callback(err); }
                    if(srv.status === "RUNNING") {
                      return self.callback(null,srv);
                    }
                    waitForReboot(srv);
                  });
                }, timeout);
              }

            function keepTrying() {
              return setTimeout(function () {
                if(server.status==='RUNNING') {
                  server.reboot(function(err,ok) {
                    if(err) { return self.callback(err); }
                    waitForReboot(server);
                  });
                } else {
                  server.refresh(function(err,srv){
                    if(err) { return self.callback(err); }
                    server=srv;
                    keepTrying();
                  });
                }
              }, timeout);
            }
            keepTrying();
          });
        },
        "should return a server after reboot": function (err, server) {
          assert.isNull(err);
          assert.assertServer(server);
        }
      }
    };

  return test;
}

JSON.parse(fs.readFileSync(__dirname + '/../../configs/providers.json'))
  .forEach(function(provider) {
    clients[provider] = helpers.createClient(provider, 'compute');
    var client = clients[provider],
        nock   = require('nock');
    testData    = {};
    testContext = {};
    if(process.env.NOCK) {
      if(provider === 'joyent') {
        nock('https://' + client.serversUrl)
          .get('/' + client.account + '/machines')
            .reply(200, "[]", {})
          .get('/' + client.account + '/datasets')
            .reply(200, helpers.loadFixture('joyent/images.json'), {})
          .get('/' + client.account + '/packages')
            .reply(200, helpers.loadFixture('joyent/flavors.json'), {})
        .post('/' + client.account + '/machines',
          helpers.loadFixture('joyent/createServer.json'))
        .reply(201, helpers.loadFixture('joyent/createdServer.json'), {})
        ["delete"]('/' + client.account +
         '/machines/14186c17-0fcd-4bb5-ab42-51b848bda7e9')
          .reply(204, "", {})
        .get('/' + client.account + '/machines')
          .reply(200, helpers.loadFixture('joyent/servers.json'), {})
        .post('/' + client.account + '/machines',
            helpers.loadFixture('joyent/rebootServerRequest1.json'))
          .reply(201,
            helpers.loadFixture('joyent/rebootServerResponse1.json'), {})
        .get('/' + client.account +
            '/machines/fe4d8e28-6154-4281-8f0e-dead21585ed5')
          .reply(200,
            helpers.loadFixture('joyent/fe4d8e28.json'), {})
        .post('/' + client.account +
            '/machines/fe4d8e28-6154-4281-8f0e-dead21585ed5?action=reboot')
          .reply(202, "", {})
        .get('/' + client.account +
            '/machines/fe4d8e28-6154-4281-8f0e-dead21585ed5')
          .reply(200,
            helpers.loadFixture('joyent/fe4d8e28.json'), {})
        .get('/' + client.account +
            '/machines/14186c17-0fcd-4bb5-ab42-51b848bda7e9')
          .reply(200,
            helpers.loadFixture('joyent/fe4d8e28.json'), {})
        ["delete"]('/' + client.account +
         '/machines/fe4d8e28-6154-4281-8f0e-dead21585ed5')
          .reply(204, "", {})
        ;
      }
      else if(provider === 'rackspace') {
        nock('https://' + client.authUrl)
          .get('/v1.0')
          .reply(204, "",
            JSON.parse(helpers.loadFixture('rackspace/auth.json')));
        nock('https://' + client.serversUrl)
          .get('/v1.0/537645/flavors/detail.json')
            .reply(200, helpers.loadFixture('rackspace/flavors.json'), {})
          .get('/v1.0/537645/flavors/detail.json')
            .reply(200, helpers.loadFixture('rackspace/flavors.json'), {})
          .get('/v1.0/537645/images/detail.json')
            .reply(200, helpers.loadFixture('rackspace/images.json'), {})
          .get('/v1.0/537645/images/detail.json')
            .reply(200, helpers.loadFixture('rackspace/images.json'), {})
          .post('/v1.0/537645/servers',
              helpers.loadFixture('rackspace/createServer.json'))
            .reply(202,  helpers.loadFixture('rackspace/createdServer.json'),
              {})
          .post('/v1.0/537645/servers',
              helpers.loadFixture('rackspace/createServer.json'))
            .reply(202,  helpers.loadFixture('rackspace/createdServer.json'),
              {})
          .get('/v1.0/537645/servers/detail.json')
            .reply(204, helpers.loadFixture('rackspace/servers.json'), {})
          ["delete"]('/v1.0/537645/servers/20592449')
            .reply(200, '{"ok": 20592449}', {})
          .get('/v1.0/537645/servers/20592449')
              .reply(200, helpers.loadFixture('rackspace/20592449.json'), {})
          .post('/v1.0/537645/servers',
              helpers.loadFixture('rackspace/createReboot.json'))
            .reply(202,
              helpers.loadFixture('rackspace/buildingReboot.json'), {})
          .get('/v1.0/537645/servers/20596929')
            .reply(200,
              helpers.loadFixture('rackspace/activeReboot.json'), {})
          .post('/v1.0/537645/servers/20596929/action',
              '{"reboot":{"type":"SOFT"}}')
            .reply(202, "", {})
          .get('/v1.0/537645/servers/20596929')
            .reply(200,
              helpers.loadFixture('rackspace/activeReboot.json'), {})
          ;
      }
    }
    vows
      .describe('pkgcloud/common/compute/server [' + provider + ']')
      .addBatch(batchOne(client, provider))
      .addBatch(batchTwo(client, provider))
      .addBatch(batchThree(client, provider))
      .addBatch(batchReboot(client, provider, nock))
       ["export"](module);
  });<commit_msg>[compute] reboot added comment<commit_after>/*
 * image-test.js: Test that should be common to all providers.
 *
 * (C) 2012 Nodejitsu Inc.
 *
 */

var fs = require('fs'),
    path = require('path'),
    vows = require('vows'),
    assert = require('../../helpers/assert'),
    helpers = require('../../helpers');

var testData    = {},
    testContext = {},
    clients     = {};

function batchOne (providerClient, providerName) {
  var name   = providerName   || 'rackspace',
      client = providerClient || rackspace,
      test   = {};

  test["The pkgcloud " + name + " compute client"] =
    {
      "the getImages() method": {
        "with details": {
          topic: function () {
            client.getImages(this.callback);
          },
          "should return the list of images": function (err, images) {
            assert.isNull(err);
            testContext.images = images;
            images.forEach(function (image) {
              assert.assertImageDetails(image);
            });
          }
        }
      },
      "the getFlavors() method": {
        "with details": {
          topic: function () {
            client.getFlavors(this.callback);
          },
          "should return the list of flavors": function (err, flavors) {
            assert.isNull(err);
            testContext.flavors = flavors;
            flavors.forEach(function (flavor) {
              assert.assertFlavorDetails(flavor);
            });
          }
        }
      }
    };

  return test;
}

function batchTwo (providerClient, providerName) {
  var name   = providerName   || 'rackspace',
      client = providerClient || rackspace,
      test   = {};

  test["The pkgcloud " + name + " compute client"] =
    {
      "the createServer() method": {
        "with image and flavor ids": {
          topic: function () {
            client.createServer({
              name: 'create-test-ids2',
              image: testContext.images[0].id,
              flavor: testContext.flavors[0].id
            }, this.callback);
          },
          "should return a valid server": function (err, server) {
            testContext.servers = [server];
            assert.isNull(err);
            assert.equal(server.name, 'create-test-ids2');
            assert.equal(server.imageId, testContext.images[0].id);
            assert.assertServerDetails(server);
          }
        }
      }
    };

  return test;
}

function batchThree (providerClient, providerName) {
  var name   = providerName   || 'rackspace',
      client = providerClient || rackspace,
      test   = {};

  test["The pkgcloud " + name + " compute client"] =
    {
      "the getServers() method": {
        topic: function () {
          client.getServers(this.callback);
        },
        "should return the list of servers": function (err, servers) {
          assert.isNull(err);
          testContext.servers = servers;
          servers.forEach(function (server) {
            assert.assertServer(server);
          });
        }
      },
      "the getServer() method": {
        topic: function () {
            client.getServer(testContext.servers[0], this.callback);
        },
        "should return a valid server": function (err, server) {
          client.destroyServer(server);
          assert.isNull(err);
          assert.assertServerDetails(server);
        }
      }
    };

  return test;
}

function batchReboot(providerClient, providerName, nock) {
  var name    = providerName   || 'rackspace',
      client  = providerClient || rackspace,
      timeout = process.env.NOCK ? 1 : 10000,
      test    = {};

  test["The pkgcloud " + name + " compute client"] =
    {
      "the rebootServer() method": {
        topic: function () {
          var self = this;
          client.createServer({
              name  : "test-reboot",
              image : testContext.images[0].id,
              flavor: testContext.flavors[0].id
            },
            function(err,server,response) {
              if(err) { return self.callback(err); }

              function waitForReboot(server) {
                // should have used setWait
                // dont do this in your code
                return setTimeout(function (){
                  server.refresh(function(err,srv){
                    if(err) { return self.callback(err); }
                    if(srv.status === "RUNNING") {
                      return self.callback(null,srv);
                    }
                    waitForReboot(srv);
                  });
                }, timeout);
              }

            function keepTrying() {
              // should have used setWait
              // dont do this in your code
              return setTimeout(function () {
                if(server.status==='RUNNING') {
                  server.reboot(function(err,ok) {
                    if(err) { return self.callback(err); }
                    waitForReboot(server);
                  });
                } else {
                  server.refresh(function(err,srv){
                    if(err) { return self.callback(err); }
                    server=srv;
                    keepTrying();
                  });
                }
              }, timeout);
            }
            keepTrying();
          });
        },
        "should return a server after reboot": function (err, server) {
          assert.isNull(err);
          assert.assertServer(server);
        }
      }
    };

  return test;
}

JSON.parse(fs.readFileSync(__dirname + '/../../configs/providers.json'))
  .forEach(function(provider) {
    clients[provider] = helpers.createClient(provider, 'compute');
    var client = clients[provider],
        nock   = require('nock');
    testData    = {};
    testContext = {};
    if(process.env.NOCK) {
      if(provider === 'joyent') {
        nock('https://' + client.serversUrl)
          .get('/' + client.account + '/machines')
            .reply(200, "[]", {})
          .get('/' + client.account + '/datasets')
            .reply(200, helpers.loadFixture('joyent/images.json'), {})
          .get('/' + client.account + '/packages')
            .reply(200, helpers.loadFixture('joyent/flavors.json'), {})
        .post('/' + client.account + '/machines',
          helpers.loadFixture('joyent/createServer.json'))
        .reply(201, helpers.loadFixture('joyent/createdServer.json'), {})
        ["delete"]('/' + client.account +
         '/machines/14186c17-0fcd-4bb5-ab42-51b848bda7e9')
          .reply(204, "", {})
        .get('/' + client.account + '/machines')
          .reply(200, helpers.loadFixture('joyent/servers.json'), {})
        .post('/' + client.account + '/machines',
            helpers.loadFixture('joyent/rebootServerRequest1.json'))
          .reply(201,
            helpers.loadFixture('joyent/rebootServerResponse1.json'), {})
        .get('/' + client.account +
            '/machines/fe4d8e28-6154-4281-8f0e-dead21585ed5')
          .reply(200,
            helpers.loadFixture('joyent/fe4d8e28.json'), {})
        .post('/' + client.account +
            '/machines/fe4d8e28-6154-4281-8f0e-dead21585ed5?action=reboot')
          .reply(202, "", {})
        .get('/' + client.account +
            '/machines/fe4d8e28-6154-4281-8f0e-dead21585ed5')
          .reply(200,
            helpers.loadFixture('joyent/fe4d8e28.json'), {})
        .get('/' + client.account +
            '/machines/14186c17-0fcd-4bb5-ab42-51b848bda7e9')
          .reply(200,
            helpers.loadFixture('joyent/fe4d8e28.json'), {})
        ["delete"]('/' + client.account +
         '/machines/fe4d8e28-6154-4281-8f0e-dead21585ed5')
          .reply(204, "", {})
        ;
      }
      else if(provider === 'rackspace') {
        nock('https://' + client.authUrl)
          .get('/v1.0')
          .reply(204, "",
            JSON.parse(helpers.loadFixture('rackspace/auth.json')));
        nock('https://' + client.serversUrl)
          .get('/v1.0/537645/flavors/detail.json')
            .reply(200, helpers.loadFixture('rackspace/flavors.json'), {})
          .get('/v1.0/537645/flavors/detail.json')
            .reply(200, helpers.loadFixture('rackspace/flavors.json'), {})
          .get('/v1.0/537645/images/detail.json')
            .reply(200, helpers.loadFixture('rackspace/images.json'), {})
          .get('/v1.0/537645/images/detail.json')
            .reply(200, helpers.loadFixture('rackspace/images.json'), {})
          .post('/v1.0/537645/servers',
              helpers.loadFixture('rackspace/createServer.json'))
            .reply(202,  helpers.loadFixture('rackspace/createdServer.json'),
              {})
          .post('/v1.0/537645/servers',
              helpers.loadFixture('rackspace/createServer.json'))
            .reply(202,  helpers.loadFixture('rackspace/createdServer.json'),
              {})
          .get('/v1.0/537645/servers/detail.json')
            .reply(204, helpers.loadFixture('rackspace/servers.json'), {})
          ["delete"]('/v1.0/537645/servers/20592449')
            .reply(200, '{"ok": 20592449}', {})
          .get('/v1.0/537645/servers/20592449')
              .reply(200, helpers.loadFixture('rackspace/20592449.json'), {})
          .post('/v1.0/537645/servers',
              helpers.loadFixture('rackspace/createReboot.json'))
            .reply(202,
              helpers.loadFixture('rackspace/buildingReboot.json'), {})
          .get('/v1.0/537645/servers/20596929')
            .reply(200,
              helpers.loadFixture('rackspace/activeReboot.json'), {})
          .post('/v1.0/537645/servers/20596929/action',
              '{"reboot":{"type":"SOFT"}}')
            .reply(202, "", {})
          .get('/v1.0/537645/servers/20596929')
            .reply(200,
              helpers.loadFixture('rackspace/activeReboot.json'), {})
          ;
      }
    }
    vows
      .describe('pkgcloud/common/compute/server [' + provider + ']')
      .addBatch(batchOne(client, provider))
      .addBatch(batchTwo(client, provider))
      .addBatch(batchThree(client, provider))
      .addBatch(batchReboot(client, provider, nock))
       ["export"](module);
  });<|endoftext|>


<commit_before>/*
* This randomize function was originally created by David Sutherland.
* You may use or modify it freely as needed. Just notify me in some way, so I tract how useful it is (star it, watch it, fork it... whatever works for you!)
*/

//RANDOMIZE returns a random number between 'min' - 'max', but will not return 'not'.
function randomize(min = 0, max = 1, fixed = 0, not = NaN, identifier = 'none set') {
    var loopBreak = 0;
    var loopStop = 100;
    //throw errors if input is no good
    console.assert(min <= max, 'Please place the greater value in the "max" perameter | min = ' + min + ' | max = ' + max + ' | not =' + not + ' | identifier = ' + identifier)
    console.assert(typeof not === 'number', '3rd Parameter - "not" - must be a number | min = ' + min + ' | max = ' + max + ' | not =' + not + ' | identifier = ' + identifier)
    console.assert(typeof identifier === 'string', '4th Parameter - "identifier" -  must be a string | min = ' + min + ' | max = ' + max + ' | not =' + not + ' | identifier = ' + identifier)
    do {
        //Pick a number
        var randomNumber = Math.random() * (max - min) + min;
        if (randomNumber>max){
            console.log(randomNumber);

            randomNumber=max;};
        loopBreak++;
    } while (loopBreak < loopStop && randomNumber === not);
    //write error if randomNumber still === not
    console.assert(randomNumber !== not, 'Randomized number equals "not" - randomize function | min = ' + min + ' | max = ' + max + ' | not =' + not + ' | identifier = ' + identifier)
    if (randomNumber !== not) {
        return randomNumber.toFixed(fixed);
    } else {
        //Return error if Infinite loop has been prevented
        console.log('Randomization Loop Ended on attempt # ' + loopBreak + ' | min = ' + min + ' | max = ' + max + ' | not =' + not);
        return min
    }
}
<commit_msg>Permissions Update<commit_after>/*
* This randomize function was originally created by David Sutherland.
* You may use or modify it freely as needed. Just notify me in some way, so I can tract how useful it is (star it, watch it, fork it... whatever works for you!)
*/

//RANDOMIZE returns a random number between 'min' - 'max', but will not return 'not'.
function randomize(min = 0, max = 1, fixed = 0, not = NaN, identifier = 'none set') {
    var loopBreak = 0;
    var loopStop = 100;
    //throw errors if input is no good
    console.assert(min <= max, 'Please place the greater value in the "max" perameter | min = ' + min + ' | max = ' + max + ' | not =' + not + ' | identifier = ' + identifier)
    console.assert(typeof not === 'number', '3rd Parameter - "not" - must be a number | min = ' + min + ' | max = ' + max + ' | not =' + not + ' | identifier = ' + identifier)
    console.assert(typeof identifier === 'string', '4th Parameter - "identifier" -  must be a string | min = ' + min + ' | max = ' + max + ' | not =' + not + ' | identifier = ' + identifier)
    do {
        //Pick a number
        var randomNumber = Math.random() * (max - min) + min;
        if (randomNumber>max){
            console.log(randomNumber);

            randomNumber=max;};
        loopBreak++;
    } while (loopBreak < loopStop && randomNumber === not);
    //write error if randomNumber still === not
    console.assert(randomNumber !== not, 'Randomized number equals "not" - randomize function | min = ' + min + ' | max = ' + max + ' | not =' + not + ' | identifier = ' + identifier)
    if (randomNumber !== not) {
        return randomNumber.toFixed(fixed);
    } else {
        //Return error if Infinite loop has been prevented
        console.log('Randomization Loop Ended on attempt # ' + loopBreak + ' | min = ' + min + ' | max = ' + max + ' | not =' + not);
        return min
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright © 2015 Cask Data, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

angular.module(PKG.name + '.services')
  .factory('myPipelineApi', function($resource, myHelpers, GLOBALS) {
    var templatePath = '/templates',
        pipelinePath = '/namespaces/:namespace/apps/:pipeline',

        listPath = '/namespaces/:namespace/apps?artifactName=' + GLOBALS.etlBatch + ',' + GLOBALS.etlRealtime,
        artifactsPath = '/namespaces/:namespace/artifacts?scope=SYSTEM',
        pluginFetchBase = '/namespaces/:namespace/artifacts/:pipelineType/versions/:version/extensions/:extensionType',
        pluginsFetchPath = pluginFetchBase + '?scope=system',
        pluginDetailFetch = pluginFetchBase + '/plugins/:pluginName?scope=system',
        artifactPropertiesPath = '/namespaces/:namespace/artifacts/:artifactName/versions/:artifactVersion/properties';

    return $resource(
      '',
      {

      },
      {
        save: myHelpers.getConfig('PUT', 'REQUEST', pipelinePath, false, {contentType: 'application/json'}),
        fetchArtifacts: myHelpers.getConfig('GET', 'REQUEST', artifactsPath, true),
        fetchTemplates: myHelpers.getConfig('GET', 'REQUEST', templatePath, true),
        fetchSources: myHelpers.getConfig('GET', 'REQUEST', pluginsFetchPath, true),
        fetchSinks: myHelpers.getConfig('GET', 'REQUEST', pluginsFetchPath, true),
        fetchTransforms: myHelpers.getConfig('GET', 'REQUEST', pluginsFetchPath, true),
        fetchPlugins: myHelpers.getConfig('GET', 'REQUEST', pluginsFetchPath, true),
        fetchSourceProperties: myHelpers.getConfig('GET', 'REQUEST', pluginDetailFetch, true),
        fetchSinkProperties: myHelpers.getConfig('GET', 'REQUEST', pluginDetailFetch, true),
        fetchTransformProperties: myHelpers.getConfig('GET', 'REQUEST', pluginDetailFetch, true),

        fetchArtifactProperties: myHelpers.getConfig('GET', 'REQUEST', artifactPropertiesPath),

        // The above three could be replaced by this one.
        fetchPluginProperties: myHelpers.getConfig('GET', 'REQUEST', pluginDetailFetch, true),

        // FIXME: This needs to be replaced with fetching etl-batch & etl-realtime separately.
        list: myHelpers.getConfig('GET', 'REQUEST', listPath, true),
        pollStatus: myHelpers.getConfig('GET', 'POLL', pipelinePath + '/status'),
        stopPollStatus: myHelpers.getConfig('GET', 'POLL-STOP', pipelinePath + '/status'),
        delete: myHelpers.getConfig('DELETE', 'REQUEST', pipelinePath),
        runs: myHelpers.getConfig('GET', 'REQUEST', pipelinePath + '/runs', true),
        get: myHelpers.getConfig('GET', 'REQUEST', pipelinePath),
        datasets: myHelpers.getConfig('GET', 'REQUEST', pipelinePath + '/datasets', true),
        streams: myHelpers.getConfig('GET', 'REQUEST', pipelinePath + '/streams', true),
        action: myHelpers.getConfig('POST', 'REQUEST', pipelinePath + '/:action')
      }
    );
  });
<commit_msg>Modifies my-pipeline-api to add a generic fetchPlugins api<commit_after>/*
 * Copyright © 2015 Cask Data, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

angular.module(PKG.name + '.services')
  .factory('myPipelineApi', function($resource, myHelpers, GLOBALS) {
    var templatePath = '/templates',
        pipelinePath = '/namespaces/:namespace/apps/:pipeline',

        listPath = '/namespaces/:namespace/apps?artifactName=' + GLOBALS.etlBatch + ',' + GLOBALS.etlRealtime,
        artifactsPath = '/namespaces/:namespace/artifacts?scope=SYSTEM',
        extensionsFetchBase = '/namespaces/:namespace/artifacts/:pipelineType/versions/:version/extensions',
        pluginFetchBase = extensionsFetchBase + '/:extensionType',
        pluginsFetchPath = pluginFetchBase + '?scope=system',
        extensionsFetchPath = extensionsFetchBase + '?scope=system',
        pluginDetailFetch = pluginFetchBase + '/plugins/:pluginName?scope=system',
        artifactPropertiesPath = '/namespaces/:namespace/artifacts/:artifactName/versions/:artifactVersion/properties';

    return $resource(
      '',
      {

      },
      {
        save: myHelpers.getConfig('PUT', 'REQUEST', pipelinePath, false, {contentType: 'application/json'}),
        fetchArtifacts: myHelpers.getConfig('GET', 'REQUEST', artifactsPath, true),
        fetchExtensions: myHelpers.getConfig('GET', 'REQUEST', extensionsFetchPath, true),
        fetchSources: myHelpers.getConfig('GET', 'REQUEST', pluginsFetchPath, true),
        fetchSinks: myHelpers.getConfig('GET', 'REQUEST', pluginsFetchPath, true),
        fetchTransforms: myHelpers.getConfig('GET', 'REQUEST', pluginsFetchPath, true),
        fetchTemplates: myHelpers.getConfig('GET', 'REQUEST', templatePath, true),
        fetchPlugins: myHelpers.getConfig('GET', 'REQUEST', pluginsFetchPath, true),
        fetchSourceProperties: myHelpers.getConfig('GET', 'REQUEST', pluginDetailFetch, true),
        fetchSinkProperties: myHelpers.getConfig('GET', 'REQUEST', pluginDetailFetch, true),
        fetchTransformProperties: myHelpers.getConfig('GET', 'REQUEST', pluginDetailFetch, true),

        fetchArtifactProperties: myHelpers.getConfig('GET', 'REQUEST', artifactPropertiesPath),

        // The above three could be replaced by this one.
        fetchPluginProperties: myHelpers.getConfig('GET', 'REQUEST', pluginDetailFetch, true),

        // FIXME: This needs to be replaced with fetching etl-batch & etl-realtime separately.
        list: myHelpers.getConfig('GET', 'REQUEST', listPath, true),
        pollStatus: myHelpers.getConfig('GET', 'POLL', pipelinePath + '/status'),
        stopPollStatus: myHelpers.getConfig('GET', 'POLL-STOP', pipelinePath + '/status'),
        delete: myHelpers.getConfig('DELETE', 'REQUEST', pipelinePath),
        runs: myHelpers.getConfig('GET', 'REQUEST', pipelinePath + '/runs', true),
        get: myHelpers.getConfig('GET', 'REQUEST', pipelinePath),
        datasets: myHelpers.getConfig('GET', 'REQUEST', pipelinePath + '/datasets', true),
        streams: myHelpers.getConfig('GET', 'REQUEST', pipelinePath + '/streams', true),
        action: myHelpers.getConfig('POST', 'REQUEST', pipelinePath + '/:action')
      }
    );
  });
<|endoftext|>


<commit_before>(function (env) {
    "use strict";

    var ID = 'pokemon',
        DESCRIPTION_ENDPOINT = '/js/spice/pokemon/description/{id}',
        POKEAPI_SPRITE_URL = 'http://pokeapi.co/media/img/{id}.png',
        INFOBOX_PROPS = ['hp', 'attack', 'defense', 'height', 'weight', 'speed'];

    /**
     *  [ Pokemon::Data ]
     */
    env.ddg_spice_pokemon_data = function(api_result){
        if (!api_result) {
            return Spice.failed('pokemon');
        }

        Spice.add({
            id: ID,
            name: 'Pokedex',
            data: api_result,
            meta: {
                sourceName: 'pokeapi.co',
                sourceUrl: 'http://pokeapi.co/',
                sourceIconUrl: 'http://pokeapi.co/static/favicon.ico'
            },
            normalize: function(item) {
                return {
                    title: item.name,
                    image: getSprite.call(item),
                    infoboxData: getInfoboxData.call(item),
                    eggGroups: getCollectionNames.call(item, 'egg_groups'),
                    types: getCollectionNames.call(item, 'types')
                };
            },
            onItemShown: function() {
                if( api_result.descriptions.length > 0 ) {
                    fetchDescription(api_result.descriptions).done(function(api_result) {
                        var description = Handlebars.helpers.ellipsis(api_result.description, 140);

                        Spice.getDOM(ID).find('.pokemon__description').html(description);
                    });
                }
            },
            templates: {
                group: 'info',
                options: {
                    content: Spice.pokemon_data.content,
                    moreAt: true
                }
            }
        });
    };

    /**
     * Chooses a random pokemon's description from the available sets
     * and then calls the Pokemon::Description endpoint to fetch its full text
     *
     * @param {Array} descriptions
     * @return {jqXHR} the Promise object
     */
    function fetchDescription(descriptions) {
        var randIndex = Math.floor(Math.random() * descriptions.length),
            id = descriptions[randIndex].resource_uri.match(/(\d+)\/$/)[1];

        return $.getJSON(DESCRIPTION_ENDPOINT.replace('{id}', id));
    }

    /**
     * Returns the list of capitalized names from a collection
     *
     * @context {item}
     * @param {Array} collection
     * @return {Array}
     */
    function getCollectionNames(collection) {
        return $.map(this[collection], function(element) {
            return DDG.capitalize(element.name);
        });
    }

    /**
     * Returns the list of label/value pairs to display in the Info Box
     *
     * @context {item}
     * @return {Array}
     */
    function getInfoboxData() {
        var infoboxData = [{ heading: 'Stats:' }];

        for( var prop in this ) {
            if( INFOBOX_PROPS.indexOf(prop) !== -1 && parseInt(this[prop], 10) ) {
                infoboxData.push({
                    label: DDG.capitalize(prop),
                    value: this[prop]
                });
            }
        }

        return infoboxData;
    }

    /**
     * Returns the url of the pokemon's sprite or null if the API doesn't provide any
     *
     * @context {item}
     * @return {String / null}
     */
    function getSprite() {
        if( this.sprites.length !== 0 ) {
            return POKEAPI_SPRITE_URL.replace('{id}', this.national_id);
        } else {
            return null;
        }
    }
}(this));
<commit_msg>Use onShow instead of onItemShown<commit_after>(function (env) {
    "use strict";

    var ID = 'pokemon',
        DESCRIPTION_ENDPOINT = '/js/spice/pokemon/description/{id}',
        POKEAPI_SPRITE_URL = 'http://pokeapi.co/media/img/{id}.png',
        INFOBOX_PROPS = ['hp', 'attack', 'defense', 'height', 'weight', 'speed'];

    /**
     *  [ Pokemon::Data ]
     */
    env.ddg_spice_pokemon_data = function(api_result){
        if (!api_result) {
            return Spice.failed('pokemon');
        }

        Spice.add({
            id: ID,
            name: 'Pokedex',
            data: api_result,
            meta: {
                sourceName: 'pokeapi.co',
                sourceUrl: 'http://pokeapi.co/',
                sourceIconUrl: 'http://pokeapi.co/static/favicon.ico'
            },
            normalize: function(item) {
                return {
                    title: item.name,
                    image: getSprite.call(item),
                    infoboxData: getInfoboxData.call(item),
                    eggGroups: getCollectionNames.call(item, 'egg_groups'),
                    types: getCollectionNames.call(item, 'types')
                };
            },
            onShow: function() {
                if( api_result.descriptions.length > 0 ) {
                    fetchDescription(api_result.descriptions).done(function(api_result) {
                        var description = Handlebars.helpers.ellipsis(api_result.description, 140);

                        Spice.getDOM(ID).find('.pokemon__description').html(description);
                    });
                }
            },
            templates: {
                group: 'info',
                options: {
                    content: Spice.pokemon_data.content,
                    moreAt: true
                }
            }
        });
    };

    /**
     * Chooses a random pokemon's description from the available sets
     * and then calls the Pokemon::Description endpoint to fetch its full text
     *
     * @param {Array} descriptions
     * @return {jqXHR} the Promise object
     */
    function fetchDescription(descriptions) {
        var randIndex = Math.floor(Math.random() * descriptions.length),
            id = descriptions[randIndex].resource_uri.match(/(\d+)\/$/)[1];

        return $.getJSON(DESCRIPTION_ENDPOINT.replace('{id}', id));
    }

    /**
     * Returns the list of capitalized names from a collection
     *
     * @context {item}
     * @param {Array} collection
     * @return {Array}
     */
    function getCollectionNames(collection) {
        return $.map(this[collection], function(element) {
            return DDG.capitalize(element.name);
        });
    }

    /**
     * Returns the list of label/value pairs to display in the Info Box
     *
     * @context {item}
     * @return {Array}
     */
    function getInfoboxData() {
        var infoboxData = [{ heading: 'Stats:' }];

        for( var prop in this ) {
            if( INFOBOX_PROPS.indexOf(prop) !== -1 && parseInt(this[prop], 10) ) {
                infoboxData.push({
                    label: DDG.capitalize(prop),
                    value: this[prop]
                });
            }
        }

        return infoboxData;
    }

    /**
     * Returns the url of the pokemon's sprite or null if the API doesn't provide any
     *
     * @context {item}
     * @return {String / null}
     */
    function getSprite() {
        if( this.sprites.length !== 0 ) {
            return POKEAPI_SPRITE_URL.replace('{id}', this.national_id);
        } else {
            return null;
        }
    }
}(this));
<|endoftext|>


<commit_before>// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'
// 'starter.services' is found in services.js
// 'starter.controllers' is found in controllers.js
angular.module('starter', ['ionic', 'ng-cordova', 'pascalprecht.translate',
   , 'starter.services', 'starter.controllers', 'starter.controllers.send', 'starter.directives', 'starter.filters'])

.run(function ($ionicPlatform, $translate) {
	$ionicPlatform.ready(function () {
		// Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
		// for form inputs)
	    if (window.cordova && window.cordova.plugins && window.cordova.plugins.Keyboard) {
			cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
		}
		if (window.StatusBar) {
			// org.apache.cordova.statusbar required
			StatusBar.styleDefault();
		}
    });
})

.config(function ($ionicConfigProvider) {
    $ionicConfigProvider.tabs.position('bottom');
    $ionicConfigProvider.navBar.alignTitle('center');
})

.config(function ($stateProvider, $urlRouterProvider, $translateProvider) {

	// Ionic uses AngularUI Router which uses the concept of states
	// Learn more here: https://github.com/angular-ui/ui-router
	// Set up the various states which the app can be in.
	// Each state's controller can be found in controllers.js
	$stateProvider

	// setup an abstract state for the tabs directive
	.state('app', {
	    url: "/app",
		abstract : true,
		templateUrl: "templates/sidemenus.html"
	})

	// Each tab has its own nav history stack:

	.state('app.receive', {
		url : '/receive/',
		views : {
		    'sidemenuContent': {
				templateUrl : 'templates/tab-receive.html',
				controller : 'ReceiveCtrl'
			}
		}
	})

	.state('app.wallet', {
		url : '/wallet/',
		views : {
		    'sidemenuContent': {
				templateUrl : 'templates/tab-wallet.html',
				controller : 'WalletCtrl'
			}
		}
	})

	.state('app.send', {
	    url: '/send/{recipient}',
	    views: {
	        'sidemenuContent': {
	            templateUrl: 'templates/tab-send.html',
	            controller: 'SendCtrl'
	        }
	    }
	})

	.state('app.transactions', {
	    url: '/transactions/',
	    views: {
	        'sidemenuContent': {
	            templateUrl: 'templates/tab-transactions.html',
	            controller: 'TransactionsCtrl'
	        }
	    }
	})

	.state('app.contacts', {
	    url: '/contacts/',
	    views: {
	        'sidemenuContent': {
	            templateUrl: 'templates/view-contacts.html',
	            controller: 'ContactsCtrl'
	        }
	    }
	})

	.state('app.about', {
		url : '/about/',
		views : {
		    'sidemenuContent': {
				templateUrl : 'templates/tab-about.html',
				controller : 'AboutCtrl'
			}
		}
	})

    .state('app.language', {
        url: '/language/',
        views: {
            'sidemenuContent': {
                templateUrl: 'templates/selectLanguage.html',
                controller: 'AboutCtrl'
            }
        }
    });

	// if none of the above states are matched, use this as the fallback
	$urlRouterProvider.otherwise('/app/wallet/');

    ///////////////////////////////////////////////////
    /// translate
	$translateProvider.useStaticFilesLoader({
	    prefix: 'i18n/',
	    suffix: '.json'
	});
	$translateProvider
    .registerAvailableLanguageKeys(['en', 'de', 'fr', 'nl'], {
        'de_*': 'de',
        'fr_*': 'fr',
        'nl_*': 'nl',
        '*': 'en'
    });

	var lang = window.localStorage['language'];
	if (lang)
	    $translateProvider.preferredLanguage(lang);
	else
	    $translateProvider.determinePreferredLanguage();

	$translateProvider.fallbackLanguage("en");
});

angular.module("pascalprecht.translate")
.factory("$translateStaticFilesLoader", ["$q", "$http", function (a, b) {
    return function (c) {
        if (!c || !angular.isString(c.prefix) || !angular.isString(c.suffix))
            throw new Error("Couldn't load static files, no prefix or suffix specified!");
        var d = a.defer();
        return b({ url: [c.prefix, c.key, c.suffix].join(""), method: "GET", params: "" })
            .success(function (a) { d.resolve(a) })
            .error(function () { d.reject(c.key) }), d.promise
    }
}]);<commit_msg>replace tab with sidemenu<commit_after>// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'
// 'starter.services' is found in services.js
// 'starter.controllers' is found in controllers.js
angular.module('starter', ['ionic', 'ng-cordova', 'pascalprecht.translate',
   , 'starter.services', 'starter.controllers', 'starter.controllers.send', 'starter.directives', 'starter.filters'])

.run(function ($ionicPlatform, $translate) {
	$ionicPlatform.ready(function () {
		// Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
		// for form inputs)
	    if (window.cordova && window.cordova.plugins && window.cordova.plugins.Keyboard) {
			cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
		}
		if (window.StatusBar) {
			// org.apache.cordova.statusbar required
			StatusBar.styleDefault();
		}
    });
})

.config(function ($ionicConfigProvider) {
    $ionicConfigProvider.tabs.position('bottom');
    $ionicConfigProvider.navBar.alignTitle('center');
})

.config(function ($stateProvider, $urlRouterProvider, $translateProvider) {

	// Ionic uses AngularUI Router which uses the concept of states
	// Learn more here: https://github.com/angular-ui/ui-router
	// Set up the various states which the app can be in.
	// Each state's controller can be found in controllers.js
	$stateProvider

	// setup an abstract state for the sidemenu directive
	.state('app', {
	    url: "/app",
		abstract : true,
		templateUrl: "templates/sidemenus.html"
	})

	// Each tab has its own nav history stack:

	.state('app.receive', {
		url : '/receive/',
		views : {
		    'sidemenuContent': {
				templateUrl : 'templates/tab-receive.html',
				controller : 'ReceiveCtrl'
			}
		}
	})

	.state('app.wallet', {
		url : '/wallet/',
		views : {
		    'sidemenuContent': {
				templateUrl : 'templates/tab-wallet.html',
				controller : 'WalletCtrl'
			}
		}
	})

	.state('app.send', {
	    url: '/send/{recipient}',
	    views: {
	        'sidemenuContent': {
	            templateUrl: 'templates/tab-send.html',
	            controller: 'SendCtrl'
	        }
	    }
	})

	.state('app.transactions', {
	    url: '/transactions/',
	    views: {
	        'sidemenuContent': {
	            templateUrl: 'templates/tab-transactions.html',
	            controller: 'TransactionsCtrl'
	        }
	    }
	})

	.state('app.contacts', {
	    url: '/contacts/',
	    views: {
	        'sidemenuContent': {
	            templateUrl: 'templates/view-contacts.html',
	            controller: 'ContactsCtrl'
	        }
	    }
	})

	.state('app.about', {
		url : '/about/',
		views : {
		    'sidemenuContent': {
				templateUrl : 'templates/tab-about.html',
				controller : 'AboutCtrl'
			}
		}
	})

    .state('app.language', {
        url: '/language/',
        views: {
            'sidemenuContent': {
                templateUrl: 'templates/selectLanguage.html',
                controller: 'AboutCtrl'
            }
        }
    });

	// if none of the above states are matched, use this as the fallback
	$urlRouterProvider.otherwise('/app/wallet/');

    ///////////////////////////////////////////////////
    /// translate
	$translateProvider.useStaticFilesLoader({
	    prefix: 'i18n/',
	    suffix: '.json'
	});
	$translateProvider
    .registerAvailableLanguageKeys(['en', 'de', 'fr', 'nl'], {
        'de_*': 'de',
        'fr_*': 'fr',
        'nl_*': 'nl',
        '*': 'en'
    });

	var lang = window.localStorage['language'];
	if (lang)
	    $translateProvider.preferredLanguage(lang);
	else
	    $translateProvider.determinePreferredLanguage();

	$translateProvider.fallbackLanguage("en");
});

angular.module("pascalprecht.translate")
.factory("$translateStaticFilesLoader", ["$q", "$http", function (a, b) {
    return function (c) {
        if (!c || !angular.isString(c.prefix) || !angular.isString(c.suffix))
            throw new Error("Couldn't load static files, no prefix or suffix specified!");
        var d = a.defer();
        return b({ url: [c.prefix, c.key, c.suffix].join(""), method: "GET", params: "" })
            .success(function (a) { d.resolve(a) })
            .error(function () { d.reject(c.key) }), d.promise
    }
}]);<|endoftext|>